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