d69b2ced288a7e77e2311390e197b2c20c90545e
[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.cachecrls)
122 {
123 arg[argc++] = "--cachecrls";
124 }
125 if (cfg->setup.crlcheckinterval > 0)
126 {
127 snprintf(buffer1, BUF_LEN, "%u", cfg->setup.crlcheckinterval);
128 arg[argc++] = "--crlcheckinterval";
129 arg[argc++] = buffer1;
130 }
131
132 { /* parse debug string */
133 char *pos, *level, *buf_pos, type[4];
134 pos = cfg->setup.charondebug;
135 buf_pos = buffer;
136 while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
137 {
138 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
139 arg[argc++] = buf_pos;
140 buf_pos += strlen(buf_pos) + 1;
141 if (buf_pos >= buffer + sizeof(buffer))
142 {
143 break;
144 }
145 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
146 arg[argc++] = buf_pos;
147 buf_pos += strlen(buf_pos) + 1;
148 if (buf_pos >= buffer + sizeof(buffer))
149 {
150 break;
151 }
152
153 /* get next */
154 pos = strchr(pos, ',');
155 if (pos)
156 {
157 pos++;
158 }
159 }
160 }
161
162 if (_charon_pid)
163 {
164 plog("starter_start_charon(): charon already started...");
165 return -1;
166 }
167 else
168 {
169 unlink(CHARON_CTL_FILE);
170 _stop_requested = 0;
171
172 /* if ipsec.secrets file is missing then generate RSA default key pair */
173 if (stat(SECRETS_FILE, &stb) != 0)
174 {
175 mode_t oldmask;
176 FILE *f;
177
178 plog("no %s file, generating RSA key", SECRETS_FILE);
179 seteuid(IPSEC_UID);
180 setegid(IPSEC_GID);
181 system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
182 seteuid(0);
183 setegid(0);
184
185 /* ipsec.secrets is root readable only */
186 oldmask = umask(0066);
187
188 f = fopen(SECRETS_FILE, "w");
189 if (f)
190 {
191 fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
192 fprintf(f, "\n");
193 fprintf(f, ": RSA myKey.der\n");
194 fclose(f);
195 }
196 chown(SECRETS_FILE, IPSEC_UID, IPSEC_GID);
197 umask(oldmask);
198 }
199
200 pid = fork();
201 switch (pid)
202 {
203 case -1:
204 plog("can't fork(): %s", strerror(errno));
205 return -1;
206 case 0:
207 /* child */
208 setsid();
209 sigprocmask(SIG_SETMASK, 0, NULL);
210 /* disable glibc's malloc checker, conflicts with leak detective */
211 setenv("MALLOC_CHECK_", "0", 1);
212 execv(arg[0], arg);
213 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
214 exit(1);
215 default:
216 /* father */
217 _charon_pid = pid;
218 for (i = 0; i < 50 && _charon_pid; i++)
219 {
220 /* wait for charon */
221 usleep(20000);
222 if (stat(CHARON_PID_FILE, &stb) == 0)
223 {
224 DBG(DBG_CONTROL,
225 DBG_log("charon (%d) started", _charon_pid)
226 )
227 return 0;
228 }
229 }
230 if (_charon_pid)
231 {
232 /* If charon is started but with no ctl file, stop it */
233 plog("charon too long to start... - kill kill");
234 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
235 {
236 if (i == 0)
237 kill(pid, SIGINT);
238 else if (i < 10)
239 kill(pid, SIGTERM);
240 else
241 kill(pid, SIGKILL);
242 usleep(20000);
243 }
244 }
245 else
246 {
247 plog("charon refused to be started");
248 }
249 return -1;
250 }
251 }
252 return -1;
253 }