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