be less agressive, but more verbose in killing charon
[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 * RCSID $Id$
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27
28 #include <freeswan.h>
29
30 #include "../pluto/constants.h"
31 #include "../pluto/defs.h"
32 #include "../pluto/log.h"
33
34 #include "confread.h"
35 #include "invokecharon.h"
36 #include "files.h"
37
38 static int _charon_pid = 0;
39 static int _stop_requested;
40
41 pid_t
42 starter_charon_pid(void)
43 {
44 return _charon_pid;
45 }
46
47 void
48 starter_charon_sigchild(pid_t pid)
49 {
50 if (pid == _charon_pid)
51 {
52 _charon_pid = 0;
53 if (!_stop_requested)
54 {
55 plog("charon has died -- restart scheduled (%dsec)"
56 , CHARON_RESTART_DELAY);
57 alarm(CHARON_RESTART_DELAY); // restart in 5 sec
58 }
59 unlink(CHARON_PID_FILE);
60 }
61 }
62
63 int
64 starter_stop_charon (void)
65 {
66 pid_t pid;
67 int i;
68
69 pid = _charon_pid;
70 if (pid)
71 {
72 _stop_requested = 1;
73
74 /* be more and more aggressive */
75 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
76 {
77 if (i == 0)
78 kill(pid, SIGINT);
79 else if (i < 10)
80 kill(pid, SIGTERM);
81 else if (i == 10)
82 {
83 kill(pid, SIGKILL);
84 plog("starter_stop_charon(): charon does not respond, sending KILL");
85 }
86 else
87 kill(pid, SIGKILL);
88 usleep(200000);
89 }
90 if (_charon_pid == 0)
91 return 0;
92 plog("starter_stop_charon(): can't stop charon !!!");
93 return -1;
94 }
95 else
96 {
97 plog("stater_stop_charon(): charon is not started...");
98 }
99 return -1;
100 }
101
102
103 int
104 starter_start_charon (starter_config_t *cfg, bool debug)
105 {
106 int pid, i;
107 struct stat stb;
108 char buffer[BUF_LEN], buffer1[BUF_LEN];
109 int argc = 1;
110 char *arg[] = {
111 CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
112 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
113 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
115 };
116
117 if (!debug)
118 {
119 arg[argc++] = "--use-syslog";
120 }
121 if (cfg->setup.strictcrlpolicy)
122 {
123 arg[argc++] = "--strictcrlpolicy";
124 arg[argc++] = cfg->setup.strictcrlpolicy == STRICT_IFURI ? "2":"1";
125 }
126 if (cfg->setup.cachecrls)
127 {
128 arg[argc++] = "--cachecrls";
129 }
130 if (cfg->setup.crlcheckinterval > 0)
131 {
132 snprintf(buffer1, BUF_LEN, "%u", cfg->setup.crlcheckinterval);
133 arg[argc++] = "--crlcheckinterval";
134 arg[argc++] = buffer1;
135 }
136 if (cfg->setup.eapdir)
137 {
138 arg[argc++] = "--eapdir";
139 arg[argc++] = cfg->setup.eapdir;
140 }
141
142 { /* parse debug string */
143 char *pos, *level, *buf_pos, type[4];
144 pos = cfg->setup.charondebug;
145 buf_pos = buffer;
146 while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
147 {
148 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
149 arg[argc++] = buf_pos;
150 buf_pos += strlen(buf_pos) + 1;
151 if (buf_pos >= buffer + sizeof(buffer))
152 {
153 break;
154 }
155 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
156 arg[argc++] = buf_pos;
157 buf_pos += strlen(buf_pos) + 1;
158 if (buf_pos >= buffer + sizeof(buffer))
159 {
160 break;
161 }
162
163 /* get next */
164 pos = strchr(pos, ',');
165 if (pos)
166 {
167 pos++;
168 }
169 }
170 }
171
172 if (_charon_pid)
173 {
174 plog("starter_start_charon(): charon already started...");
175 return -1;
176 }
177 else
178 {
179 unlink(CHARON_CTL_FILE);
180 _stop_requested = 0;
181
182 /* if ipsec.secrets file is missing then generate RSA default key pair */
183 if (stat(SECRETS_FILE, &stb) != 0)
184 {
185 mode_t oldmask;
186 FILE *f;
187
188 plog("no %s file, generating RSA key", SECRETS_FILE);
189 seteuid(IPSEC_UID);
190 setegid(IPSEC_GID);
191 system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
192 seteuid(0);
193 setegid(0);
194
195 /* ipsec.secrets is root readable only */
196 oldmask = umask(0066);
197
198 f = fopen(SECRETS_FILE, "w");
199 if (f)
200 {
201 fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
202 fprintf(f, "\n");
203 fprintf(f, ": RSA myKey.der\n");
204 fclose(f);
205 }
206 chown(SECRETS_FILE, IPSEC_UID, IPSEC_GID);
207 umask(oldmask);
208 }
209
210 pid = fork();
211 switch (pid)
212 {
213 case -1:
214 plog("can't fork(): %s", strerror(errno));
215 return -1;
216 case 0:
217 /* child */
218 setsid();
219 sigprocmask(SIG_SETMASK, 0, NULL);
220 /* disable glibc's malloc checker, conflicts with leak detective */
221 setenv("MALLOC_CHECK_", "0", 1);
222 execv(arg[0], arg);
223 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
224 exit(1);
225 default:
226 /* father */
227 _charon_pid = pid;
228 for (i = 0; i < 50 && _charon_pid; i++)
229 {
230 /* wait for charon */
231 usleep(20000);
232 if (stat(CHARON_PID_FILE, &stb) == 0)
233 {
234 DBG(DBG_CONTROL,
235 DBG_log("charon (%d) started", _charon_pid)
236 )
237 return 0;
238 }
239 }
240 if (_charon_pid)
241 {
242 /* If charon is started but with no ctl file, stop it */
243 plog("charon too long to start... - kill kill");
244 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
245 {
246 if (i == 0)
247 kill(pid, SIGINT);
248 else if (i < 10)
249 kill(pid, SIGTERM);
250 else
251 kill(pid, SIGKILL);
252 usleep(20000);
253 }
254 }
255 else
256 {
257 plog("charon refused to be started");
258 }
259 return -1;
260 }
261 }
262 return -1;
263 }