added missing equals() method assignment for ID_ANY identities
[strongswan.git] / src / starter / invokecharon.c
1 /* strongSwan charon launcher
2 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
3 * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
4 *
5 * Ported from invokepluto.c to fit charons needs.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25
26 #include <freeswan.h>
27
28 #include "../pluto/constants.h"
29 #include "../pluto/defs.h"
30 #include "../pluto/log.h"
31
32 #include "confread.h"
33 #include "invokecharon.h"
34 #include "files.h"
35
36 static int _charon_pid = 0;
37 static int _stop_requested;
38
39 pid_t
40 starter_charon_pid(void)
41 {
42 return _charon_pid;
43 }
44
45 void
46 starter_charon_sigchild(pid_t pid)
47 {
48 if (pid == _charon_pid)
49 {
50 _charon_pid = 0;
51 if (!_stop_requested)
52 {
53 plog("charon has died -- restart scheduled (%dsec)"
54 , CHARON_RESTART_DELAY);
55 alarm(CHARON_RESTART_DELAY); // restart in 5 sec
56 }
57 unlink(CHARON_PID_FILE);
58 }
59 }
60
61 int
62 starter_stop_charon (void)
63 {
64 int i;
65 pid_t pid = _charon_pid;
66
67 if (pid)
68 {
69 _stop_requested = 1;
70
71 /* be more and more aggressive */
72 for (i = 0; i < 50 && (pid = _charon_pid) != 0; i++)
73 {
74 if (i == 0)
75 {
76 kill(pid, SIGINT);
77 }
78 else if (i < 40)
79 {
80 kill(pid, SIGTERM);
81 }
82 else if (i == 40)
83 {
84 kill(pid, SIGKILL);
85 plog("starter_stop_charon(): charon does not respond, sending KILL");
86 }
87 else
88 {
89 kill(pid, SIGKILL);
90 }
91 usleep(200000); /* sleep for 200 ms */
92 }
93 if (_charon_pid == 0)
94 {
95 plog("charon stopped after %d ms", 200*i);
96 return 0;
97 }
98 plog("starter_stop_charon(): can't stop charon !!!");
99 return -1;
100 }
101 else
102 {
103 plog("stater_stop_charon(): charon was not started...");
104 }
105 return -1;
106 }
107
108
109 int
110 starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
111 {
112 struct stat stb;
113 int pid, i;
114 char buffer[BUF_LEN];
115 int argc = 1;
116 char *arg[] = {
117 CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
118 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
119 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
120 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
121 };
122
123 if (attach_gdb)
124 {
125 argc = 0;
126 arg[argc++] = "/usr/bin/gdb";
127 arg[argc++] = "--args";
128 arg[argc++] = CHARON_CMD;
129 }
130 if (!no_fork)
131 {
132 arg[argc++] = "--use-syslog";
133 }
134
135 /* parse debug string */
136 {
137 int level;
138 char type[4];
139 char *pos = cfg->setup.charondebug;
140 char *buf_pos = buffer;
141
142 while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
143 {
144 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
145 arg[argc++] = buf_pos;
146 buf_pos += strlen(buf_pos) + 1;
147 if (buf_pos >= buffer + sizeof(buffer))
148 {
149 break;
150 }
151 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
152 arg[argc++] = buf_pos;
153 buf_pos += strlen(buf_pos) + 1;
154 if (buf_pos >= buffer + sizeof(buffer))
155 {
156 break;
157 }
158
159 /* get next */
160 pos = strchr(pos, ',');
161 if (pos)
162 {
163 pos++;
164 }
165 }
166 }
167
168 if (_charon_pid)
169 {
170 plog("starter_start_charon(): charon already started...");
171 return -1;
172 }
173 else
174 {
175 unlink(CHARON_CTL_FILE);
176 _stop_requested = 0;
177
178 pid = fork();
179 switch (pid)
180 {
181 case -1:
182 plog("can't fork(): %s", strerror(errno));
183 return -1;
184 case 0:
185 /* child */
186 setsid();
187 sigprocmask(SIG_SETMASK, 0, NULL);
188 /* disable glibc's malloc checker, conflicts with leak detective */
189 setenv("MALLOC_CHECK_", "0", 1);
190 execv(arg[0], arg);
191 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
192 exit(1);
193 default:
194 /* father */
195 _charon_pid = pid;
196 for (i = 0; i < 500 && _charon_pid; i++)
197 {
198 /* wait for charon for a maximum of 500 x 20 ms = 10 s */
199 usleep(20000);
200 if (stat(CHARON_PID_FILE, &stb) == 0)
201 {
202 plog("charon (%d) started after %d ms", _charon_pid, 20*(i+1));
203 return 0;
204 }
205 }
206 if (_charon_pid)
207 {
208 /* If charon is started but with no ctl file, stop it */
209 plog("charon too long to start... - kill kill");
210 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
211 {
212 if (i == 0)
213 {
214 kill(pid, SIGINT);
215 }
216 else if (i < 10)
217 {
218 kill(pid, SIGTERM);
219 }
220 else
221 {
222 kill(pid, SIGKILL);
223 }
224 usleep(20000); /* sleep for 20 ms */
225 }
226 }
227 else
228 {
229 plog("charon refused to be started");
230 }
231 return -1;
232 }
233 }
234 return -1;
235 }