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