starter: Remove all ties to pluto/libfreeswan.
[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 <library.h>
27 #include <debug.h>
28
29 #include "confread.h"
30 #include "invokecharon.h"
31 #include "files.h"
32
33 static int _charon_pid = 0;
34 static int _stop_requested;
35
36 pid_t starter_charon_pid(void)
37 {
38 return _charon_pid;
39 }
40
41 void starter_charon_sigchild(pid_t pid, int status)
42 {
43 if (pid == _charon_pid)
44 {
45 _charon_pid = 0;
46 if (status == SS_RC_LIBSTRONGSWAN_INTEGRITY ||
47 status == SS_RC_DAEMON_INTEGRITY)
48 {
49 DBG1(DBG_APP, "charon has quit: integrity test of %s failed",
50 (status == 64) ? "libstrongswan" : "charon");
51 _stop_requested = 1;
52 }
53 else if (status == SS_RC_INITIALIZATION_FAILED)
54 {
55 DBG1(DBG_APP, "charon has quit: initialization failed");
56 _stop_requested = 1;
57 }
58 if (!_stop_requested)
59 {
60 DBG1(DBG_APP, "charon has died -- restart scheduled (%dsec)",
61 CHARON_RESTART_DELAY);
62 alarm(CHARON_RESTART_DELAY); // restart in 5 sec
63 }
64 unlink(CHARON_PID_FILE);
65 }
66 }
67
68 int starter_stop_charon (void)
69 {
70 int i;
71 pid_t pid = _charon_pid;
72
73 if (pid)
74 {
75 _stop_requested = 1;
76
77 /* be more and more aggressive */
78 for (i = 0; i < 50 && (pid = _charon_pid) != 0; i++)
79 {
80 if (i == 0)
81 {
82 kill(pid, SIGINT);
83 }
84 else if (i < 40)
85 {
86 kill(pid, SIGTERM);
87 }
88 else if (i == 40)
89 {
90 kill(pid, SIGKILL);
91 DBG1(DBG_APP, "starter_stop_charon(): charon does not respond, sending KILL");
92 }
93 else
94 {
95 kill(pid, SIGKILL);
96 }
97 usleep(200000); /* sleep for 200 ms */
98 }
99 if (_charon_pid == 0)
100 {
101 DBG1(DBG_APP, "charon stopped after %d ms", 200*i);
102 return 0;
103 }
104 DBG1(DBG_APP, "starter_stop_charon(): can't stop charon !!!");
105 return -1;
106 }
107 else
108 {
109 DBG1(DBG_APP, "stater_stop_charon(): charon was not started...");
110 }
111 return -1;
112 }
113
114
115 int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
116 {
117 struct stat stb;
118 int pid, i;
119 char buffer[BUF_LEN];
120 int argc = 1;
121 char *arg[] = {
122 CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
123 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
124 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
125 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
126 };
127
128 if (attach_gdb)
129 {
130 argc = 0;
131 arg[argc++] = "/usr/bin/gdb";
132 arg[argc++] = "--args";
133 arg[argc++] = CHARON_CMD;
134 }
135 if (!no_fork)
136 {
137 arg[argc++] = "--use-syslog";
138 }
139
140 /* parse debug string */
141 {
142 int level;
143 char type[4];
144 char *pos = cfg->setup.charondebug;
145 char *buf_pos = buffer;
146
147 while (pos && sscanf(pos, "%3s %d,", type, &level) == 2)
148 {
149 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
150 arg[argc++] = buf_pos;
151 buf_pos += strlen(buf_pos) + 1;
152 if (buf_pos >= buffer + sizeof(buffer))
153 {
154 break;
155 }
156 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
157 arg[argc++] = buf_pos;
158 buf_pos += strlen(buf_pos) + 1;
159 if (buf_pos >= buffer + sizeof(buffer))
160 {
161 break;
162 }
163
164 /* get next */
165 pos = strchr(pos, ',');
166 if (pos)
167 {
168 pos++;
169 }
170 }
171 }
172
173 if (_charon_pid)
174 {
175 DBG1(DBG_APP, "starter_start_charon(): charon already started...");
176 return -1;
177 }
178 else
179 {
180 unlink(CHARON_CTL_FILE);
181 _stop_requested = 0;
182
183 pid = fork();
184 switch (pid)
185 {
186 case -1:
187 DBG1(DBG_APP, "can't fork(): %s", strerror(errno));
188 return -1;
189 case 0:
190 /* child */
191 setsid();
192 closefrom(3);
193 sigprocmask(SIG_SETMASK, 0, NULL);
194 /* disable glibc's malloc checker, conflicts with leak detective */
195 setenv("MALLOC_CHECK_", "0", 1);
196 execv(arg[0], arg);
197 DBG1(DBG_APP, "can't execv(%s,...): %s", arg[0], strerror(errno));
198 exit(1);
199 default:
200 /* father */
201 _charon_pid = pid;
202 for (i = 0; i < 500 && _charon_pid; i++)
203 {
204 /* wait for charon for a maximum of 500 x 20 ms = 10 s */
205 usleep(20000);
206 if (stat(CHARON_PID_FILE, &stb) == 0)
207 {
208 DBG1(DBG_APP, "charon (%d) started after %d ms",
209 _charon_pid, 20*(i+1));
210 return 0;
211 }
212 }
213 if (_charon_pid)
214 {
215 /* If charon is started but with no ctl file, stop it */
216 DBG1(DBG_APP, "charon too long to start... - kill kill");
217 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
218 {
219 if (i == 0)
220 {
221 kill(pid, SIGINT);
222 }
223 else if (i < 10)
224 {
225 kill(pid, SIGTERM);
226 }
227 else
228 {
229 kill(pid, SIGKILL);
230 }
231 usleep(20000); /* sleep for 20 ms */
232 }
233 }
234 else
235 {
236 DBG1(DBG_APP, "charon refused to be started");
237 }
238 return -1;
239 }
240 }
241 return -1;
242 }