e97c8388ba32ea95399bfdf228d58b1b950c6f9f
[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 int argc = 1;
104 char *arg[] = {
105 CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
106 NULL, NULL, 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 };
110
111 if (!debug)
112 {
113 arg[argc++] = "--use-syslog";
114 }
115 if (cfg->setup.strictcrlpolicy)
116 {
117 arg[argc++] = "--strictcrlpolicy";
118 }
119 if (cfg->setup.cachecrls)
120 {
121 arg[argc++] = "--cachecrls";
122 }
123 if (cfg->setup.crlcheckinterval > 0)
124 {
125 char buffer[BUF_LEN];
126
127 snprintf(buffer, BUF_LEN, "%u", cfg->setup.crlcheckinterval);
128 arg[argc++] = "--crlcheckinterval";
129 arg[argc++] = buffer;
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], buffer[BUF_LEN];
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 system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
185
186 /* ipsec.secrets is root readable only */
187 oldmask = umask(0066);
188
189 f = fopen(SECRETS_FILE, "w");
190 if (f)
191 {
192 fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
193 fprintf(f, "\n");
194 fprintf(f, ": RSA myKey.der\n");
195 fclose(f);
196 }
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 execv(arg[0], arg);
211 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
212 exit(1);
213 default:
214 /* father */
215 _charon_pid = pid;
216 for (i = 0; i < 50 && _charon_pid; i++)
217 {
218 /* wait for charon */
219 usleep(20000);
220 if (stat(CHARON_PID_FILE, &stb) == 0)
221 {
222 DBG(DBG_CONTROL,
223 DBG_log("charon (%d) started", _charon_pid)
224 )
225 return 0;
226 }
227 }
228 if (_charon_pid)
229 {
230 /* If charon is started but with no ctl file, stop it */
231 plog("charon too long to start... - kill kill");
232 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
233 {
234 if (i == 0)
235 kill(pid, SIGINT);
236 else if (i < 10)
237 kill(pid, SIGTERM);
238 else
239 kill(pid, SIGKILL);
240 usleep(20000);
241 }
242 }
243 else
244 {
245 plog("charon refused to be started");
246 }
247 return -1;
248 }
249 }
250 return -1;
251 }