]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
1 | /* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */ |
2 | ||
52b7d2ce A |
3 | /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */ |
4 | ||
5 | /* | |
6 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. Neither the name of the project nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include "config.h" | |
35 | ||
36 | #include <sys/types.h> | |
37 | #include <sys/param.h> | |
38 | #include <sys/time.h> | |
39 | #include <sys/socket.h> | |
40 | #if HAVE_SYS_WAIT_H | |
41 | # include <sys/wait.h> | |
42 | #endif | |
43 | #ifndef WEXITSTATUS | |
44 | # define WEXITSTATUS(s) ((unsigned)(s) >> 8) | |
45 | #endif | |
46 | #ifndef WIFEXITED | |
47 | # define WIFEXITED(s) (((s) & 255) == 0) | |
48 | #endif | |
49 | ||
50 | #ifndef HAVE_NETINET6_IPSEC | |
51 | #include <netinet/ipsec.h> | |
52 | #else | |
53 | #include <netinet6/ipsec.h> | |
54 | #endif | |
55 | ||
56 | #include <stdlib.h> | |
57 | #include <stdio.h> | |
58 | #include <string.h> | |
59 | #include <errno.h> | |
60 | #ifdef HAVE_UNISTD_H | |
61 | #include <unistd.h> | |
62 | #endif | |
63 | #include <signal.h> | |
64 | #include <sys/stat.h> | |
65 | #include <paths.h> | |
66 | ||
d1e348cf A |
67 | #include <netinet/in.h> |
68 | #include <netinet/ip.h> | |
69 | #include <netinet/ip_icmp.h> | |
70 | ||
71 | #include <resolv.h> | |
72 | #include <TargetConditionals.h> | |
e97d2cf9 | 73 | #include <vproc_priv.h> |
d1e348cf | 74 | |
52b7d2ce A |
75 | #include "libpfkey.h" |
76 | ||
77 | #include "var.h" | |
78 | #include "misc.h" | |
79 | #include "vmbuf.h" | |
80 | #include "plog.h" | |
81 | #include "debug.h" | |
82 | ||
83 | #include "schedule.h" | |
84 | #include "session.h" | |
85 | #include "grabmyaddr.h" | |
86 | #include "evt.h" | |
87 | #include "cfparse_proto.h" | |
88 | #include "isakmp_var.h" | |
d1e348cf A |
89 | #include "isakmp_xauth.h" |
90 | #include "isakmp_cfg.h" | |
52b7d2ce A |
91 | #include "admin_var.h" |
92 | #include "admin.h" | |
93 | #include "privsep.h" | |
94 | #include "oakley.h" | |
95 | #include "pfkey.h" | |
96 | #include "handler.h" | |
97 | #include "localconf.h" | |
98 | #include "remoteconf.h" | |
99 | #include "backupsa.h" | |
100 | #ifdef ENABLE_NATT | |
101 | #include "nattraversal.h" | |
102 | #endif | |
103 | #include "vpn_control_var.h" | |
104 | #include "policy.h" | |
d1e348cf A |
105 | #include "algorithm.h" /* XXX ??? */ |
106 | ||
107 | #include "sainfo.h" | |
e8d9021d | 108 | #include "power_mgmt.h" |
d1e348cf A |
109 | |
110 | ||
52b7d2ce A |
111 | |
112 | extern pid_t racoon_pid; | |
e8d9021d | 113 | extern char logFileStr[]; |
e97d2cf9 | 114 | extern int launchedbylaunchd(void); |
52b7d2ce A |
115 | static void close_session __P((void)); |
116 | static void check_rtsock __P((void *)); | |
117 | static void initfds __P((void)); | |
118 | static void init_signal __P((void)); | |
e8d9021d | 119 | static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int, siginfo_t *, void *)))); |
52b7d2ce A |
120 | static void check_sigreq __P((void)); |
121 | static void check_flushsa_stub __P((void *)); | |
122 | static void check_flushsa __P((void)); | |
123 | static void auto_exit_do __P((void *)); | |
124 | static int close_sockets __P((void)); | |
125 | ||
126 | static fd_set mask0; | |
127 | static fd_set maskdying; | |
128 | static int nfds = 0; | |
129 | static volatile sig_atomic_t sigreq[NSIG + 1]; | |
130 | static int dying = 0; | |
131 | static struct sched *check_rtsock_sched = NULL; | |
d1e348cf | 132 | int terminated = 0; |
52b7d2ce | 133 | |
e8d9021d A |
134 | #define HANDLE_TENTATIVE_INTF_FAILURES() do { \ |
135 | if (tentative_failures) { \ | |
136 | plog(LLV_ERROR, LOCATION, NULL, \ | |
137 | "detected tentative interface/address issues: will retry later.\n"); \ | |
138 | if (check_rtsock_sched == NULL) { \ | |
139 | /* only schedule if not already done */ \ | |
140 | check_rtsock_sched = sched_new(5, check_rtsock, NULL); \ | |
141 | } \ | |
142 | } \ | |
143 | } while(0) | |
144 | ||
93762ec7 A |
145 | static void |
146 | reinit_socks (void) | |
147 | { | |
e8d9021d A |
148 | int tentative_failures; |
149 | ||
93762ec7 A |
150 | isakmp_close(); |
151 | close(lcconf->rtsock); | |
152 | initmyaddr(); | |
e8d9021d | 153 | if (isakmp_open(&tentative_failures) < 0) { |
93762ec7 A |
154 | plog(LLV_ERROR2, LOCATION, NULL, |
155 | "failed to reopen isakmp sockets\n"); | |
156 | } | |
157 | initfds(); | |
e8d9021d | 158 | HANDLE_TENTATIVE_INTF_FAILURES(); |
93762ec7 A |
159 | } |
160 | ||
e97d2cf9 A |
161 | static int64_t racoon_keepalive = -1; |
162 | ||
163 | /* | |
164 | * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly) | |
e8d9021d | 165 | * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits. |
e97d2cf9 A |
166 | * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit. |
167 | */ | |
168 | int64_t | |
169 | launchd_update_racoon_keepalive (Boolean enabled) | |
170 | { | |
171 | if (launchedbylaunchd()) { | |
172 | vproc_t vp = vprocmgr_lookup_vproc("com.apple.racoon"); | |
173 | if (vp) { | |
174 | int64_t val = (__typeof__(val))enabled; | |
175 | if (vproc_swap_integer(vp, | |
176 | VPROC_GSK_BASIC_KEEPALIVE, | |
177 | &val, | |
178 | &racoon_keepalive)) { | |
179 | plog(LLV_ERROR2, LOCATION, NULL, | |
180 | "failed to swap launchd keepalive integer %d\n", enabled); | |
181 | } | |
182 | vproc_release(vp); | |
183 | } | |
184 | } | |
185 | return racoon_keepalive; | |
186 | } | |
e97d2cf9 | 187 | |
52b7d2ce A |
188 | int |
189 | session(void) | |
190 | { | |
191 | fd_set rfds; | |
192 | struct timeval *timeout; | |
193 | int error; | |
194 | struct myaddrs *p; | |
195 | char pid_file[MAXPATHLEN]; | |
196 | FILE *fp; | |
197 | int i, update_fds; | |
e8d9021d | 198 | int tentative_failures; |
52b7d2ce A |
199 | |
200 | /* initialize schedular */ | |
201 | sched_init(); | |
202 | ||
e8d9021d A |
203 | /* needs to be called after schedular */ |
204 | if (init_power_mgmt() < 0) { | |
205 | errx(1, "failed to initialize power-mgmt."); | |
206 | } | |
207 | ||
52b7d2ce A |
208 | initmyaddr(); |
209 | ||
e8d9021d | 210 | if (isakmp_init(false, &tentative_failures) < 0) { |
52b7d2ce A |
211 | plog(LLV_ERROR2, LOCATION, NULL, |
212 | "failed to initialize isakmp"); | |
213 | exit(1); | |
214 | } | |
e8d9021d A |
215 | HANDLE_TENTATIVE_INTF_FAILURES(); |
216 | ||
52b7d2ce A |
217 | #ifdef ENABLE_ADMINPORT |
218 | if (admin_init() < 0) { | |
219 | plog(LLV_ERROR2, LOCATION, NULL, | |
220 | "failed to initialize admin port"); | |
221 | exit(1); | |
222 | } | |
223 | #endif | |
224 | #ifdef ENABLE_VPNCONTROL_PORT | |
225 | if (vpncontrol_init() < 0) { | |
226 | plog(LLV_ERROR2, LOCATION, NULL, | |
227 | "failed to initialize vpn control port"); | |
228 | exit(1); | |
229 | } | |
d1e348cf | 230 | |
52b7d2ce A |
231 | #endif |
232 | ||
233 | init_signal(); | |
234 | initfds(); | |
235 | ||
e8d9021d | 236 | #ifdef HAVE_OPENSSL |
52b7d2ce A |
237 | if (privsep_init() != 0) { |
238 | plog(LLV_ERROR2, LOCATION, NULL, | |
239 | "failed to initialize privsep"); | |
240 | exit(1); | |
241 | } | |
e8d9021d A |
242 | #endif |
243 | ||
52b7d2ce A |
244 | for (i = 0; i <= NSIG; i++) |
245 | sigreq[i] = 0; | |
246 | ||
247 | /* write .pid file */ | |
248 | if (!f_foreground) { | |
249 | racoon_pid = getpid(); | |
250 | if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) | |
d1e348cf | 251 | strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); |
52b7d2ce | 252 | else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') |
d1e348cf | 253 | strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); |
52b7d2ce | 254 | else { |
d1e348cf A |
255 | strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); |
256 | strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); | |
52b7d2ce A |
257 | } |
258 | fp = fopen(pid_file, "w"); | |
259 | if (fp) { | |
260 | if (fchmod(fileno(fp), | |
261 | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { | |
262 | syslog(LOG_ERR, "%s", strerror(errno)); | |
263 | fclose(fp); | |
264 | exit(1); | |
265 | } | |
266 | fprintf(fp, "%ld\n", (long)racoon_pid); | |
267 | fclose(fp); | |
268 | } else { | |
269 | plog(LLV_ERROR, LOCATION, NULL, | |
270 | "cannot open %s", pid_file); | |
271 | } | |
272 | } | |
e97d2cf9 | 273 | |
e97d2cf9 A |
274 | #if !TARGET_OS_EMBEDDED |
275 | // enable keepalive for recovery (from crashes and bad exits... after init) | |
276 | (void)launchd_update_racoon_keepalive(true); | |
277 | #endif // !TARGET_OS_EMBEDDED | |
e97d2cf9 | 278 | |
52b7d2ce | 279 | while (1) { |
fd507379 A |
280 | if (!TAILQ_EMPTY(&lcconf->saved_msg_queue)) |
281 | pfkey_post_handler(); | |
52b7d2ce A |
282 | update_fds = 0; |
283 | /* | |
284 | * asynchronous requests via signal. | |
285 | * make sure to reset sigreq to 0. | |
286 | */ | |
287 | check_sigreq(); | |
288 | ||
e8d9021d A |
289 | check_power_mgmt(); |
290 | ||
52b7d2ce A |
291 | /* scheduling */ |
292 | timeout = schedular(); | |
93762ec7 A |
293 | // <rdar://problem/7650111> Workaround: make sure timeout is playing nice |
294 | if (timeout) { | |
295 | if (timeout->tv_usec < 0 || timeout->tv_usec > SELECT_USEC_MAX ) { | |
296 | timeout->tv_sec += ((__typeof__(timeout->tv_sec))timeout->tv_usec)/SELECT_USEC_MAX; | |
297 | timeout->tv_usec %= SELECT_USEC_MAX; | |
298 | } | |
299 | if (timeout->tv_sec > SELECT_SEC_MAX /* tv_sec is unsigned */) { | |
300 | timeout->tv_sec = SELECT_SEC_MAX; | |
301 | } | |
302 | if (!timeout->tv_sec && !timeout->tv_usec) { | |
303 | timeout->tv_sec = 1; | |
304 | } | |
305 | } | |
e8d9021d | 306 | |
52b7d2ce A |
307 | if (dying) |
308 | rfds = maskdying; | |
309 | else | |
310 | rfds = mask0; | |
311 | error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); | |
312 | if (error < 0) { | |
313 | switch (errno) { | |
314 | case EINTR: | |
315 | continue; | |
316 | default: | |
317 | plog(LLV_ERROR2, LOCATION, NULL, | |
e8d9021d A |
318 | "failed select (%s) nfds %d\n", |
319 | strerror(errno), nfds); | |
93762ec7 A |
320 | reinit_socks(); |
321 | update_fds = 0; | |
d1e348cf | 322 | continue; |
52b7d2ce A |
323 | } |
324 | /*NOTREACHED*/ | |
325 | } | |
326 | ||
327 | #ifdef ENABLE_ADMINPORT | |
328 | if ((lcconf->sock_admin != -1) && | |
329 | (FD_ISSET(lcconf->sock_admin, &rfds))) | |
330 | admin_handler(); | |
331 | #endif | |
332 | #ifdef ENABLE_VPNCONTROL_PORT | |
333 | { | |
334 | struct vpnctl_socket_elem *elem; | |
335 | struct vpnctl_socket_elem *t_elem; | |
336 | ||
337 | if ((lcconf->sock_vpncontrol != -1) && | |
338 | (FD_ISSET(lcconf->sock_vpncontrol, &rfds))) { | |
339 | vpncontrol_handler(); | |
340 | update_fds = 1; // in case new socket created - update mask | |
341 | } | |
342 | /* The handler may close and remove the list element | |
343 | * so we can't rely on it being valid after calling | |
344 | * the handler. | |
345 | */ | |
346 | LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) { | |
347 | if ((elem->sock != -1) && | |
348 | (FD_ISSET(elem->sock, &rfds))) | |
349 | if (vpncontrol_comm_handler(elem)) | |
350 | update_fds = 1; // socket closed by peer - update mask | |
351 | } | |
352 | } | |
d1e348cf | 353 | #endif |
52b7d2ce A |
354 | |
355 | for (p = lcconf->myaddrs; p; p = p->next) { | |
356 | if (!p->addr) | |
357 | continue; | |
e8d9021d A |
358 | if ((p->sock != -1) && |
359 | (FD_ISSET(p->sock, &rfds))) | |
52b7d2ce A |
360 | if ((error = isakmp_handler(p->sock)) == -2) |
361 | break; | |
362 | } | |
363 | if (error == -2) { | |
e8d9021d A |
364 | plog(LLV_ERROR2, LOCATION, NULL, |
365 | "failed to process isakmp port\n"); | |
93762ec7 A |
366 | reinit_socks(); |
367 | update_fds = 0; | |
e8d9021d | 368 | continue; |
52b7d2ce A |
369 | } |
370 | ||
371 | if (FD_ISSET(lcconf->sock_pfkey, &rfds)) | |
372 | pfkey_handler(); | |
373 | ||
374 | if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) { | |
375 | if (update_myaddrs() && lcconf->autograbaddr) | |
376 | if (check_rtsock_sched == NULL) /* only schedule if not already done */ | |
e8d9021d | 377 | check_rtsock_sched = sched_new(1, check_rtsock, NULL); |
869d26af A |
378 | else { |
379 | // force reinit if schedule is too far off (3 seconds or more) | |
380 | time_t too_far = current_time() + 3; | |
381 | if (check_rtsock_sched->dead || | |
382 | check_rtsock_sched->xtime >= too_far) { | |
383 | plog(LLV_DEBUG, LOCATION, NULL, | |
384 | "forced reinit of addrs\n"); | |
385 | update_fds = 0; | |
386 | check_rtsock(NULL); | |
387 | } | |
388 | } | |
52b7d2ce A |
389 | // initfds(); //%%% BUG FIX - not needed here |
390 | } | |
391 | if (update_fds) { | |
392 | initfds(); | |
393 | update_fds = 0; | |
394 | } | |
395 | } | |
396 | } | |
397 | ||
398 | ||
399 | /* clear all status and exit program. */ | |
400 | static void | |
401 | close_session() | |
402 | { | |
d1e348cf A |
403 | if ( terminated ) |
404 | flushph2(false); | |
405 | flushph1(false); | |
52b7d2ce A |
406 | close_sockets(); |
407 | backupsa_clean(); | |
408 | ||
e97d2cf9 A |
409 | #if !TARGET_OS_EMBEDDED |
410 | // a clean exit, so disable launchd keepalive | |
411 | (void)launchd_update_racoon_keepalive(false); | |
412 | #endif // !TARGET_OS_EMBEDDED | |
e97d2cf9 | 413 | |
52b7d2ce A |
414 | plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); |
415 | exit(0); | |
416 | } | |
417 | ||
418 | static void | |
419 | check_rtsock(p) | |
420 | void *p; | |
421 | { | |
e8d9021d | 422 | int tentative_failures; |
52b7d2ce A |
423 | |
424 | check_rtsock_sched = NULL; | |
425 | grab_myaddrs(); | |
426 | isakmp_close_unused(); | |
427 | ||
428 | autoconf_myaddrsport(); | |
e8d9021d | 429 | isakmp_open(&tentative_failures); |
52b7d2ce A |
430 | |
431 | /* initialize socket list again */ | |
432 | initfds(); | |
e8d9021d | 433 | HANDLE_TENTATIVE_INTF_FAILURES(); |
52b7d2ce A |
434 | } |
435 | ||
436 | static void | |
437 | initfds() | |
438 | { | |
439 | struct myaddrs *p; | |
440 | ||
441 | nfds = 0; | |
442 | ||
443 | FD_ZERO(&mask0); | |
444 | FD_ZERO(&maskdying); | |
445 | ||
446 | #ifdef ENABLE_ADMINPORT | |
447 | if (lcconf->sock_admin != -1) { | |
448 | if (lcconf->sock_admin >= FD_SETSIZE) { | |
449 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - admin socket\n"); | |
450 | exit(1); | |
451 | } | |
452 | FD_SET(lcconf->sock_admin, &mask0); | |
453 | /* XXX should we listen on admin socket when dying ? | |
454 | */ | |
455 | #if 0 | |
456 | FD_SET(lcconf->sock_admin, &maskdying); | |
457 | #endif | |
458 | nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin); | |
459 | } | |
460 | #endif | |
461 | #ifdef ENABLE_VPNCONTROL_PORT | |
462 | { | |
463 | struct vpnctl_socket_elem *elem; | |
464 | ||
465 | if (lcconf->sock_vpncontrol != -1) { | |
466 | if (lcconf->sock_vpncontrol >= FD_SETSIZE) { | |
467 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - vpncontrol socket\n"); | |
468 | exit(1); | |
469 | } | |
470 | FD_SET(lcconf->sock_vpncontrol, &mask0); | |
471 | nfds = (nfds > lcconf->sock_vpncontrol ? nfds : lcconf->sock_vpncontrol); | |
472 | } | |
473 | ||
474 | LIST_FOREACH(elem, &lcconf->vpnctl_comm_socks, chain) { | |
475 | if (elem->sock != -1) { | |
476 | if (elem->sock >= FD_SETSIZE) { | |
477 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun vpnctl_comm socket\n"); | |
478 | exit(1); | |
479 | } | |
480 | FD_SET(elem->sock, &mask0); | |
481 | nfds = (nfds > elem->sock ? nfds : elem->sock); | |
482 | } | |
483 | } | |
484 | } | |
52b7d2ce A |
485 | #endif |
486 | ||
487 | if (lcconf->sock_pfkey >= FD_SETSIZE) { | |
488 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - pfkey socket\n"); | |
489 | exit(1); | |
490 | } | |
491 | FD_SET(lcconf->sock_pfkey, &mask0); | |
492 | FD_SET(lcconf->sock_pfkey, &maskdying); | |
493 | nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey); | |
494 | if (lcconf->rtsock >= 0) { | |
495 | if (lcconf->rtsock >= FD_SETSIZE) { | |
496 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - rt socket\n"); | |
497 | exit(1); | |
498 | } | |
499 | FD_SET(lcconf->rtsock, &mask0); | |
500 | nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock); | |
501 | } | |
d1e348cf | 502 | |
52b7d2ce A |
503 | for (p = lcconf->myaddrs; p; p = p->next) { |
504 | if (!p->addr) | |
505 | continue; | |
506 | if (p->sock < 0) | |
507 | continue; | |
508 | if (p->sock >= FD_SETSIZE) { | |
509 | plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - isakmp socket\n"); | |
510 | exit(1); | |
511 | } | |
512 | FD_SET(p->sock, &mask0); | |
513 | nfds = (nfds > p->sock ? nfds : p->sock); | |
514 | } | |
515 | nfds++; | |
516 | } | |
517 | ||
d1e348cf | 518 | |
52b7d2ce A |
519 | static int signals[] = { |
520 | SIGHUP, | |
521 | SIGINT, | |
522 | SIGTERM, | |
523 | SIGUSR1, | |
524 | SIGUSR2, | |
525 | SIGCHLD, | |
526 | SIGPIPE, | |
527 | 0 | |
528 | }; | |
529 | ||
530 | /* | |
531 | * asynchronous requests will actually dispatched in the | |
532 | * main loop in session(). | |
533 | */ | |
534 | RETSIGTYPE | |
e8d9021d | 535 | signal_handler(sig, sigi, ctx) |
52b7d2ce | 536 | int sig; |
e8d9021d A |
537 | siginfo_t *sigi; |
538 | void *ctx; | |
52b7d2ce | 539 | { |
e8d9021d A |
540 | #if 0 |
541 | plog(LLV_DEBUG, LOCATION, NULL, | |
542 | "%s received signal %d from pid %d uid %d\n\n", | |
543 | __FUNCTION__, sig, sigi->si_pid, sigi->si_uid); | |
544 | #endif | |
545 | ||
52b7d2ce A |
546 | /* Do not just set it to 1, because we may miss some signals by just setting |
547 | * values to 0/1 | |
548 | */ | |
549 | sigreq[sig]++; | |
d1e348cf A |
550 | if ( sig == SIGTERM ){ |
551 | terminated = 1; | |
552 | } | |
52b7d2ce A |
553 | } |
554 | ||
555 | static void | |
556 | check_sigreq() | |
557 | { | |
558 | int sig; | |
e8d9021d | 559 | int tentative_failures; |
52b7d2ce A |
560 | |
561 | /* | |
562 | * XXX We are not able to tell if we got | |
563 | * several time the same signal. This is | |
564 | * not a problem for the current code, | |
565 | * but we shall remember this limitation. | |
566 | */ | |
567 | for (sig = 0; sig <= NSIG; sig++) { | |
568 | if (sigreq[sig] == 0) | |
569 | continue; | |
570 | ||
571 | sigreq[sig]--; | |
572 | switch(sig) { | |
573 | case 0: | |
574 | return; | |
575 | ||
576 | /* Catch up childs, mainly scripts. | |
577 | */ | |
578 | case SIGCHLD: | |
579 | { | |
580 | pid_t pid; | |
581 | int s; | |
582 | ||
583 | pid = wait(&s); | |
584 | } | |
585 | break; | |
586 | ||
587 | #ifdef DEBUG_RECORD_MALLOCATION | |
588 | /* | |
589 | * XXX This operation is signal handler unsafe and may lead to | |
590 | * crashes and security breaches: See Henning Brauer talk at | |
591 | * EuroBSDCon 2005. Do not run in production with this option | |
592 | * enabled. | |
593 | */ | |
594 | case SIGUSR2: | |
595 | DRM_dump(); | |
596 | break; | |
597 | #endif | |
598 | ||
d1e348cf | 599 | case SIGUSR1: |
52b7d2ce | 600 | case SIGHUP: |
d1e348cf A |
601 | #ifdef ENABLE_HYBRID |
602 | if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { | |
603 | plog(LLV_ERROR, LOCATION, NULL, | |
604 | "ISAKMP mode config structure reset failed, " | |
605 | "not reloading\n"); | |
606 | return; | |
607 | } | |
608 | #endif | |
609 | if ( terminated ) | |
610 | break; | |
611 | ||
e8d9021d A |
612 | /* |
613 | * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets... | |
614 | * so that info-deletes notifications can make it to the peer. | |
615 | */ | |
616 | if (sig == SIGHUP) { | |
617 | flushph2(true); | |
618 | flushph1(true); | |
619 | } | |
52b7d2ce A |
620 | /* Save old configuration, load new one... */ |
621 | isakmp_close(); | |
622 | close(lcconf->rtsock); | |
d1e348cf | 623 | if (cfreparse(sig)) { |
52b7d2ce A |
624 | plog(LLV_ERROR2, LOCATION, NULL, |
625 | "configuration read failed\n"); | |
626 | exit(1); | |
627 | } | |
e8d9021d | 628 | if (lcconf->logfile_param == NULL && logFileStr[0] == 0) |
52b7d2ce A |
629 | plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); |
630 | ||
631 | initmyaddr(); | |
632 | isakmp_cleanup(); | |
e8d9021d A |
633 | isakmp_init(true, &tentative_failures); |
634 | HANDLE_TENTATIVE_INTF_FAILURES(); | |
52b7d2ce | 635 | initfds(); |
d1e348cf | 636 | #if TARGET_OS_EMBEDDED |
93762ec7 | 637 | if (no_remote_configs(TRUE)) { |
d1e348cf A |
638 | EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); |
639 | pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); | |
640 | #ifdef ENABLE_FASTQUIT | |
641 | close_session(); | |
642 | #else | |
643 | sched_new(1, check_flushsa_stub, NULL); | |
644 | #endif | |
645 | dying = 1; | |
646 | } | |
647 | #endif | |
52b7d2ce A |
648 | break; |
649 | ||
650 | case SIGINT: | |
651 | case SIGTERM: | |
652 | plog(LLV_INFO, LOCATION, NULL, | |
653 | "caught signal %d\n", sig); | |
654 | EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); | |
655 | pfkey_send_flush(lcconf->sock_pfkey, | |
656 | SADB_SATYPE_UNSPEC); | |
d1e348cf A |
657 | if ( sig == SIGTERM ){ |
658 | terminated = 1; /* in case if it hasn't been set yet */ | |
659 | close_session(); | |
660 | } | |
661 | else | |
662 | sched_new(1, check_flushsa_stub, NULL); | |
663 | ||
664 | dying = 1; | |
52b7d2ce A |
665 | break; |
666 | ||
667 | default: | |
668 | plog(LLV_INFO, LOCATION, NULL, | |
669 | "caught signal %d\n", sig); | |
670 | break; | |
671 | } | |
672 | } | |
673 | } | |
674 | ||
675 | /* | |
676 | * waiting the termination of processing until sending DELETE message | |
677 | * for all inbound SA will complete. | |
678 | */ | |
679 | static void | |
680 | check_flushsa_stub(p) | |
681 | void *p; | |
682 | { | |
683 | ||
684 | check_flushsa(); | |
685 | } | |
686 | ||
687 | static void | |
688 | check_flushsa() | |
689 | { | |
690 | vchar_t *buf; | |
691 | struct sadb_msg *msg, *end, *next; | |
692 | struct sadb_sa *sa; | |
693 | caddr_t mhp[SADB_EXT_MAX + 1]; | |
694 | int n; | |
695 | ||
696 | buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); | |
697 | if (buf == NULL) { | |
698 | plog(LLV_DEBUG, LOCATION, NULL, | |
699 | "pfkey_dump_sadb: returned nothing.\n"); | |
700 | return; | |
701 | } | |
702 | ||
703 | msg = (struct sadb_msg *)buf->v; | |
704 | end = (struct sadb_msg *)(buf->v + buf->l); | |
705 | ||
706 | /* counting SA except of dead one. */ | |
707 | n = 0; | |
708 | while (msg < end) { | |
709 | if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) | |
710 | break; | |
711 | next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); | |
712 | if (msg->sadb_msg_type != SADB_DUMP) { | |
713 | msg = next; | |
714 | continue; | |
715 | } | |
716 | ||
717 | if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { | |
718 | plog(LLV_ERROR, LOCATION, NULL, | |
719 | "pfkey_check (%s)\n", ipsec_strerror()); | |
720 | msg = next; | |
721 | continue; | |
722 | } | |
723 | ||
724 | sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); | |
725 | if (!sa) { | |
726 | msg = next; | |
727 | continue; | |
728 | } | |
729 | ||
730 | if (sa->sadb_sa_state != SADB_SASTATE_DEAD) { | |
731 | n++; | |
732 | msg = next; | |
733 | continue; | |
734 | } | |
735 | ||
736 | msg = next; | |
737 | } | |
738 | ||
739 | if (buf != NULL) | |
740 | vfree(buf); | |
741 | ||
742 | if (n) { | |
743 | sched_new(1, check_flushsa_stub, NULL); | |
744 | return; | |
745 | } | |
746 | ||
747 | close_session(); | |
d1e348cf A |
748 | #if !TARGET_OS_EMBEDDED |
749 | if (lcconf->vt) | |
750 | vproc_transaction_end(NULL, lcconf->vt); | |
751 | #endif | |
52b7d2ce A |
752 | } |
753 | ||
754 | void | |
755 | auto_exit_do(void *p) | |
756 | { | |
757 | EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); | |
d1e348cf A |
758 | plog(LLV_DEBUG, LOCATION, NULL, |
759 | "performing auto exit\n"); | |
52b7d2ce A |
760 | pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); |
761 | sched_new(1, check_flushsa_stub, NULL); | |
762 | dying = 1; | |
763 | } | |
764 | ||
765 | void | |
766 | check_auto_exit(void) | |
767 | { | |
52b7d2ce A |
768 | if (lcconf->auto_exit_sched != NULL) { /* exit scheduled? */ |
769 | if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED | |
770 | || vpn_control_connected() /* vpn control connected */ | |
93762ec7 A |
771 | || policies_installed() /* policies installed in kernel */ |
772 | || !no_remote_configs(FALSE)) /* remote or anonymous configs */ | |
52b7d2ce A |
773 | SCHED_KILL(lcconf->auto_exit_sched); |
774 | } else { /* exit not scheduled */ | |
775 | if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED | |
d1e348cf | 776 | && !vpn_control_connected() |
93762ec7 A |
777 | && !policies_installed() |
778 | && no_remote_configs(FALSE)) | |
52b7d2ce A |
779 | if (lcconf->auto_exit_delay == 0) |
780 | auto_exit_do(NULL); /* immediate exit */ | |
781 | else | |
782 | lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); | |
783 | } | |
784 | } | |
785 | ||
786 | ||
787 | static void | |
788 | init_signal() | |
789 | { | |
790 | int i; | |
791 | ||
792 | for (i = 0; signals[i] != 0; i++) | |
793 | if (set_signal(signals[i], signal_handler) < 0) { | |
794 | plog(LLV_ERROR2, LOCATION, NULL, | |
795 | "failed to set_signal (%s)\n", | |
796 | strerror(errno)); | |
797 | exit(1); | |
798 | } | |
799 | } | |
800 | ||
801 | static int | |
802 | set_signal(sig, func) | |
803 | int sig; | |
e8d9021d | 804 | RETSIGTYPE (*func) __P((int, siginfo_t *, void *)); |
52b7d2ce A |
805 | { |
806 | struct sigaction sa; | |
807 | ||
808 | memset((caddr_t)&sa, 0, sizeof(sa)); | |
809 | sa.sa_handler = func; | |
e8d9021d | 810 | sa.sa_flags = SA_RESTART | SA_SIGINFO; |
52b7d2ce A |
811 | |
812 | if (sigemptyset(&sa.sa_mask) < 0) | |
813 | return -1; | |
814 | ||
815 | if (sigaction(sig, &sa, (struct sigaction *)0) < 0) | |
816 | return(-1); | |
817 | ||
818 | return 0; | |
819 | } | |
820 | ||
821 | static int | |
822 | close_sockets() | |
823 | { | |
824 | isakmp_close(); | |
825 | pfkey_close(lcconf->sock_pfkey); | |
826 | #ifdef ENABLE_ADMINPORT | |
827 | (void)admin_close(); | |
828 | #endif | |
829 | #ifdef ENABLE_VPNCONTROL_PORT | |
830 | vpncontrol_close(); | |
831 | #endif | |
832 | return 0; | |
833 | } | |
834 | ||
d1e348cf | 835 |