ade71fc565345763398bf59a2c2664cd29663b95
[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 struct stat stb;
107 int pid, i;
108 char buffer[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 pid = fork();
163 switch (pid)
164 {
165 case -1:
166 plog("can't fork(): %s", strerror(errno));
167 return -1;
168 case 0:
169 /* child */
170 setsid();
171 sigprocmask(SIG_SETMASK, 0, NULL);
172 /* disable glibc's malloc checker, conflicts with leak detective */
173 setenv("MALLOC_CHECK_", "0", 1);
174 execv(arg[0], arg);
175 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
176 exit(1);
177 default:
178 /* father */
179 _charon_pid = pid;
180 for (i = 0; i < 50 && _charon_pid; i++)
181 {
182 /* wait for charon */
183 usleep(20000);
184 if (stat(CHARON_PID_FILE, &stb) == 0)
185 {
186 DBG(DBG_CONTROL,
187 DBG_log("charon (%d) started", _charon_pid)
188 )
189 return 0;
190 }
191 }
192 if (_charon_pid)
193 {
194 /* If charon is started but with no ctl file, stop it */
195 plog("charon too long to start... - kill kill");
196 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
197 {
198 if (i == 0)
199 kill(pid, SIGINT);
200 else if (i < 10)
201 kill(pid, SIGTERM);
202 else
203 kill(pid, SIGKILL);
204 usleep(20000);
205 }
206 }
207 else
208 {
209 plog("charon refused to be started");
210 }
211 return -1;
212 }
213 }
214 return -1;
215 }