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

5-freebsd-12
Last change on this file since 484186e was 484186e, checked in by Christian Mauderer <christian.mauderer@…>, on 05/22/23 at 07:36:46

ipsec-tools: Fix copying fd_set prior to select

The racoon session code copies an fd_set from one variable into another
prior to calling select. That works well for simple structures.

In libbsd we have to allocate fd_sets instead of using fixed structures
to avoid a problem with file numbers bigger than FD_SETSIZE. The simple
assignment didn't work in that case.

This patch makes sure that a memcpy is used instead.

Close #4914

  • Property mode set to 100644
File size: 13.5 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        size_t allocated_mask_size = sizeof(fd_set) *
213            howmany(rtems_libio_number_iops, sizeof(fd_set) * 8);
214        allocated_preset_mask = calloc(sizeof(fd_set),
215            howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
216        if (allocated_preset_mask == NULL)
217                errx(1, "failed to allocate preset_mask");
218        allocated_active_mask = calloc(sizeof(fd_set),
219            howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
220        if (allocated_active_mask == NULL)
221                errx(1, "failed to allocate active_mask");
222        allocated_fd_monitors = calloc(
223            rtems_libio_number_iops, sizeof(struct fd_monitor));
224        if (allocated_fd_monitors == NULL)
225                errx(1, "failed to allocate fd_monitors");
226#endif /* __rtems__ */
227
228        for (i = 0; i < NUM_PRIORITIES; i++)
229                TAILQ_INIT(&fd_monitor_tree[i]);
230
231        /* initialize schedular */
232        sched_init();
233        init_signal();
234
235        if (pfkey_init() < 0)
236                errx(1, "failed to initialize pfkey socket");
237
238        if (isakmp_init() < 0)
239                errx(1, "failed to initialize ISAKMP structures");
240
241#ifdef ENABLE_HYBRID
242        if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD))
243                errx(1, "could not initialize ISAKMP mode config structures");
244#endif
245
246#ifdef HAVE_LIBLDAP
247        if (xauth_ldap_init_conf() != 0)
248                errx(1, "could not initialize ldap config");
249#endif
250
251#ifdef HAVE_LIBRADIUS
252        if (xauth_radius_init_conf(0) != 0)
253                errx(1, "could not initialize radius config");
254#endif
255
256        myaddr_init_lists();
257
258        /*
259         * in order to prefer the parameters by command line,
260         * saving some parameters before parsing configuration file.
261         */
262        save_params();
263        if (cfparse() != 0)
264                errx(1, "failed to parse configuration file.");
265        restore_params();
266
267#ifdef ENABLE_ADMINPORT
268        if (admin_init() < 0)
269                errx(1, "failed to initialize admin port socket");
270#endif
271
272
273#ifdef ENABLE_HYBRID
274        if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0)
275                if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
276                        return error;
277#endif
278
279        if (dump_config)
280                dumprmconf();
281
282#ifdef HAVE_LIBRADIUS
283        if (xauth_radius_init() != 0)
284                errx(1, "could not initialize libradius");
285#endif
286
287        if (myaddr_init() != 0)
288                errx(1, "failed to listen to configured addresses");
289        myaddr_sync();
290
291#ifdef ENABLE_NATT
292        natt_keepalive_init ();
293#endif
294
295#ifndef __rtems__
296        /* write .pid file */
297        if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
298                strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
299        else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
300                strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
301        else {
302                strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
303                strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
304        }
305        fp = fopen(pid_file, "w");
306        if (fp) {
307                if (fchmod(fileno(fp),
308                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
309                        syslog(LOG_ERR, "%s", strerror(errno));
310                        fclose(fp);
311                        exit(1);
312                }
313        } else {
314                plog(LLV_ERROR, LOCATION, NULL,
315                        "cannot open %s", pid_file);
316        }
317#endif /* __rtems__ */
318
319        if (privsep_init() != 0)
320                exit(1);
321
322#ifndef __rtems__
323        /*
324         * The fork()'ed privileged side will close its copy of fp.  We wait
325         * until here to get the correct child pid.
326         */
327        racoon_pid = getpid();
328        fprintf(fp, "%ld\n", (long)racoon_pid);
329        fclose(fp);
330#endif /* __rtems__ */
331
332        for (i = 0; i <= NSIG; i++)
333                sigreq[i] = 0;
334
335        while (1) {
336                /*
337                 * asynchronous requests via signal.
338                 * make sure to reset sigreq to 0.
339                 */
340                check_sigreq();
341
342                /* scheduling */
343                timeout = schedular();
344
345                /* schedular can change select() mask, so we reset
346                 * the working copy here */
347#ifndef __rtems__
348                active_mask = preset_mask;
349#else /* __rtems__ */
350                memcpy(allocated_active_mask, allocated_preset_mask,
351                    allocated_mask_size);
352#endif /* __rtems__ */
353
354                error = select(nfds + 1, &active_mask, NULL, NULL, timeout);
355                if (error < 0) {
356                        switch (errno) {
357                        case EINTR:
358                                continue;
359                        default:
360                                plog(LLV_ERROR, LOCATION, NULL,
361                                        "failed to select (%s)\n",
362                                        strerror(errno));
363                                return -1;
364                        }
365                        /*NOTREACHED*/
366                }
367
368                count = 0;
369                for (i = 0; i < NUM_PRIORITIES; i++) {
370                        TAILQ_FOREACH(fdm, &fd_monitor_tree[i], chain) {
371                                if (!FD_ISSET(fdm->fd, &active_mask))
372                                        continue;
373
374                                FD_CLR(fdm->fd, &active_mask);
375                                if (fdm->callback != NULL) {
376                                        fdm->callback(fdm->ctx, fdm->fd);
377                                        count++;
378                                } else
379                                        plog(LLV_ERROR, LOCATION, NULL,
380                                        "fd %d set, but no active callback\n", i);
381                        }
382                        if (count != 0)
383                                break;
384                }
385
386        }
387}
388
389/* clear all status and exit program. */
390static void
391close_session()
392{
393        evt_generic(EVT_RACOON_QUIT, NULL);
394        pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
395        flushph2();
396        flushph1();
397        flushrmconf();
398        flushsainfo();
399        close_sockets();
400        backupsa_clean();
401#ifdef __rtems__
402        free(allocated_preset_mask); allocated_preset_mask = NULL;
403        free(allocated_active_mask); allocated_active_mask = NULL;
404        free(allocated_fd_monitors); allocated_fd_monitors = NULL;
405#endif /* __rtems__ */
406
407        plog(LLV_INFO, LOCATION, NULL, "racoon process %d shutdown\n", getpid());
408
409        exit(0);
410}
411
412static int signals[] = {
413        SIGHUP,
414        SIGINT,
415        SIGTERM,
416        SIGUSR1,
417        SIGUSR2,
418        SIGCHLD,
419        0
420};
421
422/*
423 * asynchronous requests will actually dispatched in the
424 * main loop in session().
425 */
426RETSIGTYPE
427signal_handler(sig)
428        int sig;
429{
430        sigreq[sig] = 1;
431}
432
433
434/* XXX possible mem leaks and no way to go back for now !!!
435 */
436static void reload_conf(){
437        int error;
438
439#ifdef ENABLE_HYBRID
440        if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
441                plog(LLV_ERROR, LOCATION, NULL,
442                    "ISAKMP mode config structure reset failed, "
443                    "not reloading\n");
444                return;
445        }
446#endif
447
448        sainfo_start_reload();
449
450        /* TODO: save / restore / flush old lcconf (?) / rmtree
451         */
452        rmconf_start_reload();
453
454#ifdef HAVE_LIBRADIUS
455        /* free and init radius configuration */
456        xauth_radius_init_conf(1);
457#endif
458
459        pfkey_reload();
460
461        save_params();
462        flushlcconf();
463        error = cfparse();
464        if (error != 0){
465                plog(LLV_ERROR, LOCATION, NULL, "config reload failed\n");
466                /* We are probably in an inconsistant state... */
467                return;
468        }
469        restore_params();
470
471#if 0
472        if (dump_config)
473                dumprmconf ();
474#endif
475
476        myaddr_sync();
477
478#ifdef HAVE_LIBRADIUS
479        /* re-initialize radius state */
480        xauth_radius_init();
481#endif
482
483        /* Revalidate ph1 / ph2tree !!!
484         * update ctdtree if removing some ph1 !
485         */
486        revalidate_ph12();
487        /* Update ctdtree ?
488         */
489
490        sainfo_finish_reload();
491        rmconf_finish_reload();
492}
493
494static void
495check_sigreq()
496{
497        int sig, s;
498
499        for (sig = 0; sig <= NSIG; sig++) {
500                if (sigreq[sig] == 0)
501                        continue;
502                sigreq[sig] = 0;
503
504                switch(sig) {
505                case 0:
506                        return;
507
508                case SIGCHLD:
509                        /* Reap all pending children */
510                        while (waitpid(-1, &s, WNOHANG) > 0)
511                                ;
512                        break;
513
514#ifdef DEBUG_RECORD_MALLOCATION
515                /*
516                 * XXX This operation is signal handler unsafe and may lead to
517                 * crashes and security breaches: See Henning Brauer talk at
518                 * EuroBSDCon 2005. Do not run in production with this option
519                 * enabled.
520                 */
521                case SIGUSR2:
522                        DRM_dump();
523                        break;
524#endif
525
526                case SIGHUP:
527                        /* Save old configuration, load new one...  */
528                        reload_conf();
529                        break;
530
531                case SIGINT:
532                case SIGTERM:
533                        plog(LLV_INFO, LOCATION, NULL,
534                            "caught signal %d\n", sig);
535                        close_session();
536                        break;
537
538                default:
539                        plog(LLV_INFO, LOCATION, NULL,
540                            "caught signal %d\n", sig);
541                        break;
542                }
543        }
544}
545
546static void
547init_signal()
548{
549        int i;
550
551        /*
552         * Ignore SIGPIPE as we check the return value of system calls
553         * that write to pipe-like fds.
554         */
555        signal(SIGPIPE, SIG_IGN);
556
557        for (i = 0; signals[i] != 0; i++)
558                if (set_signal(signals[i], signal_handler) < 0) {
559                        plog(LLV_ERROR, LOCATION, NULL,
560                                "failed to set_signal (%s)\n",
561                                strerror(errno));
562                        exit(1);
563                }
564}
565
566static int
567set_signal(sig, func)
568        int sig;
569        RETSIGTYPE (*func) __P((int));
570{
571        struct sigaction sa;
572
573        memset((caddr_t)&sa, 0, sizeof(sa));
574        sa.sa_handler = func;
575#ifndef __rtems__
576        sa.sa_flags = SA_RESTART;
577#else /* __rtems__ */
578        sa.sa_flags = 0;
579#endif /* __rtems__ */
580
581        if (sigemptyset(&sa.sa_mask) < 0)
582                return -1;
583
584        if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
585                return(-1);
586
587        return 0;
588}
589
590static int
591close_sockets()
592{
593        myaddr_close();
594        pfkey_close(lcconf->sock_pfkey);
595#ifdef ENABLE_ADMINPORT
596        (void)admin_close();
597#endif
598        return 0;
599}
600
601#ifdef __rtems__
602#include "rtems-bsd-racoon-session-data.h"
603#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.