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

Last change on this file since dfb2144 was dfb2144, 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.

Update #4913

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