source: rtems-libbsd/ipsec-tools/src/racoon/session.c @ c385e86

5-freebsd-12
Last change on this file since c385e86 was c385e86, checked in by Christian Mauderer <christian.mauderer@…>, on 02/23/21 at 13:18:26

racoon/session: Honor file descriptor maximum

Dynamically allocate a big enough file descriptor set for select(). A
better solution would be to use kqueue() instead of select().

Update #4361

  • Property mode set to 100644
File size: 13.2 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2#ifdef __rtems__
3#include <machine/rtems-bsd-program.h>
4#include "rtems-bsd-racoon-namespace.h"
5#endif /* __rtems__ */
6/*      $NetBSD: session.c,v 1.32 2011/03/02 15:09:16 vanhu Exp $       */
7
8/*      $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $        */
9
10/*
11 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the project nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include "config.h"
40
41#include <sys/types.h>
42#include <sys/param.h>
43#include <sys/time.h>
44#include <sys/socket.h>
45#if HAVE_SYS_WAIT_H
46# include <sys/wait.h>
47#endif
48#ifndef WEXITSTATUS
49# define WEXITSTATUS(s) ((unsigned)(s) >> 8)
50#endif
51#ifndef WIFEXITED
52# define WIFEXITED(s)   (((s) & 255) == 0)
53#endif
54
55#include PATH_IPSEC_H
56
57#include <stdlib.h>
58#include <stdio.h>
59#include <string.h>
60#include <errno.h>
61#ifdef HAVE_UNISTD_H
62#include <unistd.h>
63#endif
64#include <signal.h>
65#include <sys/stat.h>
66#include <paths.h>
67#include <err.h>
68#ifdef __rtems__
69#include <sys/param.h>
70#include <rtems/libio_.h>
71#endif /* __rtems__ */
72
73#include <netinet/in.h>
74#include <resolv.h>
75
76#include "libpfkey.h"
77
78#include "var.h"
79#include "misc.h"
80#include "vmbuf.h"
81#include "plog.h"
82#include "debug.h"
83
84#include "schedule.h"
85#include "session.h"
86#include "grabmyaddr.h"
87#include "evt.h"
88#include "cfparse_proto.h"
89#include "isakmp_var.h"
90#include "isakmp.h"
91#include "isakmp_var.h"
92#include "isakmp_xauth.h"
93#include "isakmp_cfg.h"
94#include "admin_var.h"
95#include "admin.h"
96#include "privsep.h"
97#include "oakley.h"
98#include "pfkey.h"
99#include "handler.h"
100#include "localconf.h"
101#include "remoteconf.h"
102#include "backupsa.h"
103#include "remoteconf.h"
104#ifdef ENABLE_NATT
105#include "nattraversal.h"
106#endif
107
108#include "algorithm.h" /* XXX ??? */
109
110#include "sainfo.h"
111
112struct fd_monitor {
113        int (*callback)(void *ctx, int fd);
114        void *ctx;
115        int prio;
116        int fd;
117        TAILQ_ENTRY(fd_monitor) chain;
118};
119
120#define NUM_PRIORITIES 2
121
122static void close_session __P((void));
123static void initfds __P((void));
124static void init_signal __P((void));
125static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int))));
126static void check_sigreq __P((void));
127static void check_flushsa __P((void));
128static int close_sockets __P((void));
129
130#ifndef __rtems__
131static fd_set preset_mask, active_mask;
132static struct fd_monitor fd_monitors[FD_SETSIZE];
133#else /* __rtems__ */
134static fd_set *allocated_preset_mask, *allocated_active_mask;
135static struct fd_monitor *allocated_fd_monitors;
136#define preset_mask (*allocated_preset_mask)
137#define active_mask (*allocated_active_mask)
138#define fd_monitors (allocated_fd_monitors)
139#endif /* __rtems__ */
140static TAILQ_HEAD(fd_monitor_list, fd_monitor) fd_monitor_tree[NUM_PRIORITIES];
141static int nfds = 0;
142
143static volatile sig_atomic_t sigreq[NSIG + 1];
144static struct sched scflushsa = SCHED_INITIALIZER();
145
146void
147monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority)
148{
149#ifndef __rtems__
150        if (fd < 0 || fd >= FD_SETSIZE) {
151#else /* __rtems__ */
152        if (fd < 0 || fd >= rtems_libio_number_iops) {
153#endif /* __rtems__ */
154                plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun");
155                exit(1);
156        }
157
158        FD_SET(fd, &preset_mask);
159        if (fd > nfds)
160                nfds = fd;
161        if (priority <= 0)
162                priority = 0;
163        if (priority >= NUM_PRIORITIES)
164                priority = NUM_PRIORITIES - 1;
165
166        fd_monitors[fd].callback = callback;
167        fd_monitors[fd].ctx = ctx;
168        fd_monitors[fd].prio = priority;
169        fd_monitors[fd].fd = fd;
170        TAILQ_INSERT_TAIL(&fd_monitor_tree[priority],
171                          &fd_monitors[fd], chain);
172}
173
174void
175unmonitor_fd(int fd)
176{
177#ifndef __rtems__
178        if (fd < 0 || fd >= FD_SETSIZE) {
179#else /* __rtems__ */
180        if (fd < 0 || fd >= rtems_libio_number_iops) {
181#endif /* __rtems__ */
182                plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun");
183                exit(1);
184        }
185
186        if (fd_monitors[fd].callback == NULL)
187                return;
188
189        FD_CLR(fd, &preset_mask);
190        FD_CLR(fd, &active_mask);
191        fd_monitors[fd].callback = NULL;
192        fd_monitors[fd].ctx = NULL;
193        TAILQ_REMOVE(&fd_monitor_tree[fd_monitors[fd].prio],
194                     &fd_monitors[fd], chain);
195}
196
197int
198session(void)
199{
200        struct timeval *timeout;
201        int error;
202        char pid_file[MAXPATHLEN];
203        FILE *fp;
204        pid_t racoon_pid = 0;
205        int i, count;
206        struct fd_monitor *fdm;
207
208        nfds = 0;
209#ifndef __rtems__
210        FD_ZERO(&preset_mask);
211#else /* __rtems__ */
212        allocated_preset_mask = calloc(sizeof(fd_set),
213            howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
214        if (allocated_preset_mask == NULL)
215                errx(1, "failed to allocate preset_mask");
216        allocated_active_mask = calloc(sizeof(fd_set),
217            howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
218        if (allocated_active_mask == NULL)
219                errx(1, "failed to allocate active_mask");
220        allocated_fd_monitors = calloc(
221            rtems_libio_number_iops, sizeof(struct fd_monitor));
222        if (allocated_fd_monitors == NULL)
223                errx(1, "failed to allocate fd_monitors");
224#endif /* __rtems__ */
225
226        for (i = 0; i < NUM_PRIORITIES; i++)
227                TAILQ_INIT(&fd_monitor_tree[i]);
228
229        /* initialize schedular */
230        sched_init();
231        init_signal();
232
233        if (pfkey_init() < 0)
234                errx(1, "failed to initialize pfkey socket");
235
236        if (isakmp_init() < 0)
237                errx(1, "failed to initialize ISAKMP structures");
238
239#ifdef ENABLE_HYBRID
240        if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD))
241                errx(1, "could not initialize ISAKMP mode config structures");
242#endif
243
244#ifdef HAVE_LIBLDAP
245        if (xauth_ldap_init_conf() != 0)
246                errx(1, "could not initialize ldap config");
247#endif
248
249#ifdef HAVE_LIBRADIUS
250        if (xauth_radius_init_conf(0) != 0)
251                errx(1, "could not initialize radius config");
252#endif
253
254        myaddr_init_lists();
255
256        /*
257         * in order to prefer the parameters by command line,
258         * saving some parameters before parsing configuration file.
259         */
260        save_params();
261        if (cfparse() != 0)
262                errx(1, "failed to parse configuration file.");
263        restore_params();
264
265#ifdef ENABLE_ADMINPORT
266        if (admin_init() < 0)
267                errx(1, "failed to initialize admin port socket");
268#endif
269
270
271#ifdef ENABLE_HYBRID
272        if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0)
273                if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
274                        return error;
275#endif
276
277        if (dump_config)
278                dumprmconf();
279
280#ifdef HAVE_LIBRADIUS
281        if (xauth_radius_init() != 0)
282                errx(1, "could not initialize libradius");
283#endif
284
285        if (myaddr_init() != 0)
286                errx(1, "failed to listen to configured addresses");
287        myaddr_sync();
288
289#ifdef ENABLE_NATT
290        natt_keepalive_init ();
291#endif
292
293#ifndef __rtems__
294        /* write .pid file */
295        if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
296                strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
297        else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
298                strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
299        else {
300                strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
301                strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
302        }
303        fp = fopen(pid_file, "w");
304        if (fp) {
305                if (fchmod(fileno(fp),
306                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
307                        syslog(LOG_ERR, "%s", strerror(errno));
308                        fclose(fp);
309                        exit(1);
310                }
311        } else {
312                plog(LLV_ERROR, LOCATION, NULL,
313                        "cannot open %s", pid_file);
314        }
315#endif /* __rtems__ */
316
317        if (privsep_init() != 0)
318                exit(1);
319
320#ifndef __rtems__
321        /*
322         * The fork()'ed privileged side will close its copy of fp.  We wait
323         * until here to get the correct child pid.
324         */
325        racoon_pid = getpid();
326        fprintf(fp, "%ld\n", (long)racoon_pid);
327        fclose(fp);
328#endif /* __rtems__ */
329
330        for (i = 0; i <= NSIG; i++)
331                sigreq[i] = 0;
332
333        while (1) {
334                /*
335                 * asynchronous requests via signal.
336                 * make sure to reset sigreq to 0.
337                 */
338                check_sigreq();
339
340                /* scheduling */
341                timeout = schedular();
342
343                /* schedular can change select() mask, so we reset
344                 * the working copy here */
345                active_mask = preset_mask;
346
347                error = select(nfds + 1, &active_mask, NULL, NULL, timeout);
348                if (error < 0) {
349                        switch (errno) {
350                        case EINTR:
351                                continue;
352                        default:
353                                plog(LLV_ERROR, LOCATION, NULL,
354                                        "failed to select (%s)\n",
355                                        strerror(errno));
356                                return -1;
357                        }
358                        /*NOTREACHED*/
359                }
360
361                count = 0;
362                for (i = 0; i < NUM_PRIORITIES; i++) {
363                        TAILQ_FOREACH(fdm, &fd_monitor_tree[i], chain) {
364                                if (!FD_ISSET(fdm->fd, &active_mask))
365                                        continue;
366
367                                FD_CLR(fdm->fd, &active_mask);
368                                if (fdm->callback != NULL) {
369                                        fdm->callback(fdm->ctx, fdm->fd);
370                                        count++;
371                                } else
372                                        plog(LLV_ERROR, LOCATION, NULL,
373                                        "fd %d set, but no active callback\n", i);
374                        }
375                        if (count != 0)
376                                break;
377                }
378
379        }
380}
381
382/* clear all status and exit program. */
383static void
384close_session()
385{
386        evt_generic(EVT_RACOON_QUIT, NULL);
387        pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
388        flushph2();
389        flushph1();
390        flushrmconf();
391        flushsainfo();
392        close_sockets();
393        backupsa_clean();
394#ifdef __rtems__
395        free(allocated_preset_mask); allocated_preset_mask = NULL;
396        free(allocated_active_mask); allocated_active_mask = NULL;
397        free(allocated_fd_monitors); allocated_fd_monitors = NULL;
398#endif /* __rtems__ */
399
400        plog(LLV_INFO, LOCATION, NULL, "racoon process %d shutdown\n", getpid());
401
402        exit(0);
403}
404
405static int signals[] = {
406        SIGHUP,
407        SIGINT,
408        SIGTERM,
409        SIGUSR1,
410        SIGUSR2,
411        SIGCHLD,
412        0
413};
414
415/*
416 * asynchronous requests will actually dispatched in the
417 * main loop in session().
418 */
419RETSIGTYPE
420signal_handler(sig)
421        int sig;
422{
423        sigreq[sig] = 1;
424}
425
426
427/* XXX possible mem leaks and no way to go back for now !!!
428 */
429static void reload_conf(){
430        int error;
431
432#ifdef ENABLE_HYBRID
433        if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
434                plog(LLV_ERROR, LOCATION, NULL,
435                    "ISAKMP mode config structure reset failed, "
436                    "not reloading\n");
437                return;
438        }
439#endif
440
441        sainfo_start_reload();
442
443        /* TODO: save / restore / flush old lcconf (?) / rmtree
444         */
445        rmconf_start_reload();
446
447#ifdef HAVE_LIBRADIUS
448        /* free and init radius configuration */
449        xauth_radius_init_conf(1);
450#endif
451
452        pfkey_reload();
453
454        save_params();
455        flushlcconf();
456        error = cfparse();
457        if (error != 0){
458                plog(LLV_ERROR, LOCATION, NULL, "config reload failed\n");
459                /* We are probably in an inconsistant state... */
460                return;
461        }
462        restore_params();
463
464#if 0
465        if (dump_config)
466                dumprmconf ();
467#endif
468
469        myaddr_sync();
470
471#ifdef HAVE_LIBRADIUS
472        /* re-initialize radius state */
473        xauth_radius_init();
474#endif
475
476        /* Revalidate ph1 / ph2tree !!!
477         * update ctdtree if removing some ph1 !
478         */
479        revalidate_ph12();
480        /* Update ctdtree ?
481         */
482
483        sainfo_finish_reload();
484        rmconf_finish_reload();
485}
486
487static void
488check_sigreq()
489{
490        int sig, s;
491
492        for (sig = 0; sig <= NSIG; sig++) {
493                if (sigreq[sig] == 0)
494                        continue;
495                sigreq[sig] = 0;
496
497                switch(sig) {
498                case 0:
499                        return;
500
501                case SIGCHLD:
502                        /* Reap all pending children */
503                        while (waitpid(-1, &s, WNOHANG) > 0)
504                                ;
505                        break;
506
507#ifdef DEBUG_RECORD_MALLOCATION
508                /*
509                 * XXX This operation is signal handler unsafe and may lead to
510                 * crashes and security breaches: See Henning Brauer talk at
511                 * EuroBSDCon 2005. Do not run in production with this option
512                 * enabled.
513                 */
514                case SIGUSR2:
515                        DRM_dump();
516                        break;
517#endif
518
519                case SIGHUP:
520                        /* Save old configuration, load new one...  */
521                        reload_conf();
522                        break;
523
524                case SIGINT:
525                case SIGTERM:
526                        plog(LLV_INFO, LOCATION, NULL,
527                            "caught signal %d\n", sig);
528                        close_session();
529                        break;
530
531                default:
532                        plog(LLV_INFO, LOCATION, NULL,
533                            "caught signal %d\n", sig);
534                        break;
535                }
536        }
537}
538
539static void
540init_signal()
541{
542        int i;
543
544        /*
545         * Ignore SIGPIPE as we check the return value of system calls
546         * that write to pipe-like fds.
547         */
548        signal(SIGPIPE, SIG_IGN);
549
550        for (i = 0; signals[i] != 0; i++)
551                if (set_signal(signals[i], signal_handler) < 0) {
552                        plog(LLV_ERROR, LOCATION, NULL,
553                                "failed to set_signal (%s)\n",
554                                strerror(errno));
555                        exit(1);
556                }
557}
558
559static int
560set_signal(sig, func)
561        int sig;
562        RETSIGTYPE (*func) __P((int));
563{
564        struct sigaction sa;
565
566        memset((caddr_t)&sa, 0, sizeof(sa));
567        sa.sa_handler = func;
568#ifndef __rtems__
569        sa.sa_flags = SA_RESTART;
570#else /* __rtems__ */
571        sa.sa_flags = 0;
572#endif /* __rtems__ */
573
574        if (sigemptyset(&sa.sa_mask) < 0)
575                return -1;
576
577        if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
578                return(-1);
579
580        return 0;
581}
582
583static int
584close_sockets()
585{
586        myaddr_close();
587        pfkey_close(lcconf->sock_pfkey);
588#ifdef ENABLE_ADMINPORT
589        (void)admin_close();
590#endif
591        return 0;
592}
593
594#ifdef __rtems__
595#include "rtems-bsd-racoon-session-data.h"
596#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.