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