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