Annotation of embedaddon/dhcp/server/dhcpd.c, revision 1.1

1.1     ! misho       1: /* dhcpd.c
        !             2: 
        !             3:    DHCP Server Daemon. */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 1996-2003 by Internet Software Consortium
        !             8:  *
        !             9:  * Permission to use, copy, modify, and distribute this software for any
        !            10:  * purpose with or without fee is hereby granted, provided that the above
        !            11:  * copyright notice and this permission notice appear in all copies.
        !            12:  *
        !            13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            20:  *
        !            21:  *   Internet Systems Consortium, Inc.
        !            22:  *   950 Charter Street
        !            23:  *   Redwood City, CA 94063
        !            24:  *   <info@isc.org>
        !            25:  *   https://www.isc.org/
        !            26:  *
        !            27:  * This software has been written for Internet Systems Consortium
        !            28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
        !            29:  * To learn more about Internet Systems Consortium, see
        !            30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
        !            31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
        !            32:  * ``http://www.nominum.com''.
        !            33:  */
        !            34: 
        !            35: static const char copyright[] =
        !            36: "Copyright 2004-2011 Internet Systems Consortium.";
        !            37: static const char arr [] = "All rights reserved.";
        !            38: static const char message [] = "Internet Systems Consortium DHCP Server";
        !            39: static const char url [] =
        !            40: "For info, please visit https://www.isc.org/software/dhcp/";
        !            41: 
        !            42: #include "dhcpd.h"
        !            43: #include <omapip/omapip_p.h>
        !            44: #include <syslog.h>
        !            45: #include <errno.h>
        !            46: #include <limits.h>
        !            47: #include <sys/types.h>
        !            48: #include <sys/time.h>
        !            49: #include <signal.h>
        !            50: 
        !            51: #if defined (PARANOIA)
        !            52: #  include <sys/types.h>
        !            53: #  include <unistd.h>
        !            54: #  include <pwd.h>
        !            55: /* get around the ISC declaration of group */
        !            56: #  define group real_group 
        !            57: #    include <grp.h>
        !            58: #  undef group
        !            59: #endif /* PARANOIA */
        !            60: 
        !            61: static void usage(void);
        !            62: 
        !            63: struct iaddr server_identifier;
        !            64: int server_identifier_matched;
        !            65: 
        !            66: #if defined (NSUPDATE)
        !            67: 
        !            68: /* This stuff is always executed to figure the default values for certain
        !            69:    ddns variables. */
        !            70: 
        !            71: char std_nsupdate [] = "                                                   \n\
        !            72: option server.ddns-hostname =                                              \n\
        !            73:   pick (option fqdn.hostname, option host-name);                           \n\
        !            74: option server.ddns-domainname =        config-option domain-name;                  \n\
        !            75: option server.ddns-ttl = encode-int(lease-time / 2, 32);                   \n\
        !            76: option server.ddns-rev-domainname = \"in-addr.arpa.\";";
        !            77: 
        !            78: /* This is the old-style name service updater that is executed
        !            79:    whenever a lease is committed.  It does not follow the DHCP-DNS
        !            80:    draft at all. */
        !            81: 
        !            82: char old_nsupdate [] = "                                                   \n\
        !            83: on commit {                                                                \n\
        !            84:   if (not static and                                                       \n\
        !            85:       ((config-option server.ddns-updates = null) or                       \n\
        !            86:        (config-option server.ddns-updates != 0))) {                        \n\
        !            87:     set new-ddns-fwd-name =                                                \n\
        !            88:       concat (pick (config-option server.ddns-hostname,                            \n\
        !            89:                    option host-name), \".\",                               \n\
        !            90:              pick (config-option server.ddns-domainname,                   \n\
        !            91:                    config-option domain-name));                            \n\
        !            92:     if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) {   \n\
        !            93:       switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) {  \n\
        !            94:       case NOERROR:                                                        \n\
        !            95:        unset ddns-fwd-name;                                                \n\
        !            96:        on expiry or release {                                              \n\
        !            97:        }                                                                   \n\
        !            98:       }                                                                            \n\
        !            99:     }                                                                      \n\
        !           100:                                                                            \n\
        !           101:     if (not defined (ddns-fwd-name)) {                                     \n\
        !           102:       set ddns-fwd-name = new-ddns-fwd-name;                               \n\
        !           103:       if defined (ddns-fwd-name) {                                         \n\
        !           104:        switch (ns-update (not exists (IN, A, ddns-fwd-name, null),         \n\
        !           105:                           add (IN, A, ddns-fwd-name, leased-address,       \n\
        !           106:                                lease-time / 2))) {                         \n\
        !           107:        default:                                                            \n\
        !           108:          unset ddns-fwd-name;                                              \n\
        !           109:          break;                                                            \n\
        !           110:                                                                            \n\
        !           111:        case NOERROR:                                                       \n\
        !           112:          set ddns-rev-name =                                               \n\
        !           113:            concat (binary-to-ascii (10, 8, \".\",                          \n\
        !           114:                                     reverse (1,                            \n\
        !           115:                                              leased-address)), \".\",      \n\
        !           116:                    pick (config-option server.ddns-rev-domainname,         \n\
        !           117:                          \"in-addr.arpa.\"));                              \n\
        !           118:          switch (ns-update (delete (IN, PTR, ddns-rev-name, null),         \n\
        !           119:                             add (IN, PTR, ddns-rev-name, ddns-fwd-name,    \n\
        !           120:                                  lease-time / 2)))                         \n\
        !           121:            {                                                               \n\
        !           122:            default:                                                        \n\
        !           123:              unset ddns-rev-name;                                          \n\
        !           124:              on release or expiry {                                        \n\
        !           125:                switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
        !           126:                                           leased-address))) {              \n\
        !           127:                case NOERROR:                                               \n\
        !           128:                  unset ddns-fwd-name;                                      \n\
        !           129:                  break;                                                    \n\
        !           130:                }                                                           \n\
        !           131:                on release or expiry;                                       \n\
        !           132:              }                                                             \n\
        !           133:              break;                                                        \n\
        !           134:                                                                            \n\
        !           135:            case NOERROR:                                                   \n\
        !           136:              on release or expiry {                                        \n\
        !           137:                switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
        !           138:                case NOERROR:                                               \n\
        !           139:                  unset ddns-rev-name;                                      \n\
        !           140:                  break;                                                    \n\
        !           141:                }                                                           \n\
        !           142:                switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
        !           143:                                           leased-address))) {              \n\
        !           144:                case NOERROR:                                               \n\
        !           145:                  unset ddns-fwd-name;                                      \n\
        !           146:                  break;                                                    \n\
        !           147:                }                                                           \n\
        !           148:                on release or expiry;                                       \n\
        !           149:              }                                                             \n\
        !           150:            }                                                               \n\
        !           151:        }                                                                   \n\
        !           152:       }                                                                            \n\
        !           153:     }                                                                      \n\
        !           154:     unset new-ddns-fwd-name;                                               \n\
        !           155:   }                                                                        \n\
        !           156: }";
        !           157: 
        !           158: int ddns_update_style;
        !           159: #endif /* NSUPDATE */
        !           160: 
        !           161: const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
        !           162: const char *path_dhcpd_db = _PATH_DHCPD_DB;
        !           163: const char *path_dhcpd_pid = _PATH_DHCPD_PID;
        !           164: /* False (default) => we write and use a pid file */
        !           165: isc_boolean_t no_pid_file = ISC_FALSE;
        !           166: 
        !           167: int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
        !           168: 
        !           169: static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
        !           170: int omapi_port;
        !           171: 
        !           172: #if defined (TRACING)
        !           173: trace_type_t *trace_srandom;
        !           174: #endif
        !           175: 
        !           176: static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
        !           177:        return ISC_R_SUCCESS;
        !           178: }
        !           179: 
        !           180: static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
        !           181:        if (a != omapi_key)
        !           182:                return ISC_R_INVALIDKEY;
        !           183:        return ISC_R_SUCCESS;
        !           184: }
        !           185: 
        !           186: static void omapi_listener_start (void *foo)
        !           187: {
        !           188:        omapi_object_t *listener;
        !           189:        isc_result_t result;
        !           190:        struct timeval tv;
        !           191: 
        !           192:        listener = (omapi_object_t *)0;
        !           193:        result = omapi_generic_new (&listener, MDL);
        !           194:        if (result != ISC_R_SUCCESS)
        !           195:                log_fatal ("Can't allocate new generic object: %s",
        !           196:                           isc_result_totext (result));
        !           197:        result = omapi_protocol_listen (listener,
        !           198:                                        (unsigned)omapi_port, 1);
        !           199:        if (result == ISC_R_SUCCESS && omapi_key)
        !           200:                result = omapi_protocol_configure_security
        !           201:                        (listener, verify_addr, verify_auth);
        !           202:        if (result != ISC_R_SUCCESS) {
        !           203:                log_error ("Can't start OMAPI protocol: %s",
        !           204:                           isc_result_totext (result));
        !           205:                tv.tv_sec = cur_tv.tv_sec + 5;
        !           206:                tv.tv_usec = cur_tv.tv_usec;
        !           207:                add_timeout (&tv, omapi_listener_start, 0, 0, 0);
        !           208:        }
        !           209:        omapi_object_dereference (&listener, MDL);
        !           210: }
        !           211: 
        !           212: #if defined (PARANOIA)
        !           213: /* to be used in one of two possible scenarios */
        !           214: static void setup_chroot (char *chroot_dir) {
        !           215:   if (geteuid())
        !           216:     log_fatal ("you must be root to use chroot");
        !           217: 
        !           218:   if (chroot(chroot_dir)) {
        !           219:     log_fatal ("chroot(\"%s\"): %m", chroot_dir);
        !           220:   }
        !           221:   if (chdir ("/")) {
        !           222:     /* probably permission denied */
        !           223:     log_fatal ("chdir(\"/\"): %m");
        !           224:   }
        !           225: }
        !           226: #endif /* PARANOIA */
        !           227: 
        !           228: #ifndef UNIT_TEST
        !           229: int 
        !           230: main(int argc, char **argv) {
        !           231:        int fd;
        !           232:        int i, status;
        !           233:        struct servent *ent;
        !           234:        char *s;
        !           235:        int cftest = 0;
        !           236:        int lftest = 0;
        !           237: #ifndef DEBUG
        !           238:        int pid;
        !           239:        char pbuf [20];
        !           240:        int daemon = 1;
        !           241: #endif
        !           242:        int quiet = 0;
        !           243:        char *server = (char *)0;
        !           244:        isc_result_t result;
        !           245:        unsigned seed;
        !           246:        struct interface_info *ip;
        !           247:        struct parse *parse;
        !           248:        int lose;
        !           249:        int no_dhcpd_conf = 0;
        !           250:        int no_dhcpd_db = 0;
        !           251:        int no_dhcpd_pid = 0;
        !           252: #ifdef DHCPv6
        !           253:        int local_family_set = 0;
        !           254: #endif /* DHCPv6 */
        !           255: #if defined (TRACING)
        !           256:        char *traceinfile = (char *)0;
        !           257:        char *traceoutfile = (char *)0;
        !           258: #endif
        !           259: 
        !           260: #if defined (PARANOIA)
        !           261:        char *set_user   = 0;
        !           262:        char *set_group  = 0;
        !           263:        char *set_chroot = 0;
        !           264: 
        !           265:        uid_t set_uid = 0;
        !           266:        gid_t set_gid = 0;
        !           267: #endif /* PARANOIA */
        !           268: 
        !           269:         /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
        !           270:            2 (stderr) are open. To do this, we assume that when we
        !           271:            open a file the lowest available file descriptor is used. */
        !           272:         fd = open("/dev/null", O_RDWR);
        !           273:         if (fd == 0)
        !           274:                 fd = open("/dev/null", O_RDWR);
        !           275:         if (fd == 1)
        !           276:                 fd = open("/dev/null", O_RDWR);
        !           277:         if (fd == 2)
        !           278:                 log_perror = 0; /* No sense logging to /dev/null. */
        !           279:         else if (fd != -1)
        !           280:                 close(fd);
        !           281: 
        !           282:        /* Set up the client classification system. */
        !           283:        classification_setup ();
        !           284: 
        !           285:        /*
        !           286:         * Set up the signal handlers, currently we only
        !           287:         * have one to ignore sigpipe.
        !           288:         */
        !           289:        if (dhcp_handle_signal(SIGPIPE, SIG_IGN) != ISC_R_SUCCESS) {
        !           290:                log_fatal("Can't set up signal handler");
        !           291:        }
        !           292: 
        !           293:        /* Initialize the omapi system. */
        !           294:        result = omapi_init ();
        !           295:        if (result != ISC_R_SUCCESS)
        !           296:                log_fatal ("Can't initialize OMAPI: %s",
        !           297:                           isc_result_totext (result));
        !           298: 
        !           299:        /* Set up the OMAPI wrappers for common objects. */
        !           300:        dhcp_db_objects_setup ();
        !           301:        /* Set up the OMAPI wrappers for various server database internal
        !           302:           objects. */
        !           303:        dhcp_common_objects_setup ();
        !           304: 
        !           305:        /* Initially, log errors to stderr as well as to syslogd. */
        !           306:        openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
        !           307: 
        !           308:        for (i = 1; i < argc; i++) {
        !           309:                if (!strcmp (argv [i], "-p")) {
        !           310:                        if (++i == argc)
        !           311:                                usage ();
        !           312:                        local_port = validate_port (argv [i]);
        !           313:                        log_debug ("binding to user-specified port %d",
        !           314:                               ntohs (local_port));
        !           315:                } else if (!strcmp (argv [i], "-f")) {
        !           316: #ifndef DEBUG
        !           317:                        daemon = 0;
        !           318: #endif
        !           319:                } else if (!strcmp (argv [i], "-d")) {
        !           320: #ifndef DEBUG
        !           321:                        daemon = 0;
        !           322: #endif
        !           323:                        log_perror = -1;
        !           324:                } else if (!strcmp (argv [i], "-s")) {
        !           325:                        if (++i == argc)
        !           326:                                usage ();
        !           327:                        server = argv [i];
        !           328: #if defined (PARANOIA)
        !           329:                } else if (!strcmp (argv [i], "-user")) {
        !           330:                        if (++i == argc)
        !           331:                                usage ();
        !           332:                        set_user = argv [i];
        !           333:                } else if (!strcmp (argv [i], "-group")) {
        !           334:                        if (++i == argc)
        !           335:                                usage ();
        !           336:                        set_group = argv [i];
        !           337:                } else if (!strcmp (argv [i], "-chroot")) {
        !           338:                        if (++i == argc)
        !           339:                                usage ();
        !           340:                        set_chroot = argv [i];
        !           341: #endif /* PARANOIA */
        !           342:                } else if (!strcmp (argv [i], "-cf")) {
        !           343:                        if (++i == argc)
        !           344:                                usage ();
        !           345:                        path_dhcpd_conf = argv [i];
        !           346:                        no_dhcpd_conf = 1;
        !           347:                } else if (!strcmp (argv [i], "-lf")) {
        !           348:                        if (++i == argc)
        !           349:                                usage ();
        !           350:                        path_dhcpd_db = argv [i];
        !           351:                        no_dhcpd_db = 1;
        !           352:                } else if (!strcmp (argv [i], "-pf")) {
        !           353:                        if (++i == argc)
        !           354:                                usage ();
        !           355:                        path_dhcpd_pid = argv [i];
        !           356:                        no_dhcpd_pid = 1;
        !           357:                } else if (!strcmp(argv[i], "--no-pid")) {
        !           358:                        no_pid_file = ISC_TRUE;
        !           359:                 } else if (!strcmp (argv [i], "-t")) {
        !           360:                        /* test configurations only */
        !           361: #ifndef DEBUG
        !           362:                        daemon = 0;
        !           363: #endif
        !           364:                        cftest = 1;
        !           365:                        log_perror = -1;
        !           366:                 } else if (!strcmp (argv [i], "-T")) {
        !           367:                        /* test configurations and lease file only */
        !           368: #ifndef DEBUG
        !           369:                        daemon = 0;
        !           370: #endif
        !           371:                        cftest = 1;
        !           372:                        lftest = 1;
        !           373:                        log_perror = -1;
        !           374:                } else if (!strcmp (argv [i], "-q")) {
        !           375:                        quiet = 1;
        !           376:                        quiet_interface_discovery = 1;
        !           377: #ifdef DHCPv6
        !           378:                } else if (!strcmp(argv[i], "-4")) {
        !           379:                        if (local_family_set && (local_family != AF_INET)) {
        !           380:                                log_fatal("Server cannot run in both IPv4 and "
        !           381:                                          "IPv6 mode at the same time.");
        !           382:                        }
        !           383:                        local_family = AF_INET;
        !           384:                        local_family_set = 1;
        !           385:                } else if (!strcmp(argv[i], "-6")) {
        !           386:                        if (local_family_set && (local_family != AF_INET6)) {
        !           387:                                log_fatal("Server cannot run in both IPv4 and "
        !           388:                                          "IPv6 mode at the same time.");
        !           389:                        }
        !           390:                        local_family = AF_INET6;
        !           391:                        local_family_set = 1;
        !           392: #endif /* DHCPv6 */
        !           393:                } else if (!strcmp (argv [i], "--version")) {
        !           394:                        log_info("isc-dhcpd-%s", PACKAGE_VERSION);
        !           395:                        exit (0);
        !           396: #if defined (TRACING)
        !           397:                } else if (!strcmp (argv [i], "-tf")) {
        !           398:                        if (++i == argc)
        !           399:                                usage ();
        !           400:                        traceoutfile = argv [i];
        !           401:                } else if (!strcmp (argv [i], "-play")) {
        !           402:                        if (++i == argc)
        !           403:                                usage ();
        !           404:                        traceinfile = argv [i];
        !           405:                        trace_replay_init ();
        !           406: #endif /* TRACING */
        !           407:                } else if (argv [i][0] == '-') {
        !           408:                        usage ();
        !           409:                } else {
        !           410:                        struct interface_info *tmp =
        !           411:                                (struct interface_info *)0;
        !           412:                        if (strlen(argv[i]) >= sizeof(tmp->name))
        !           413:                                log_fatal("%s: interface name too long "
        !           414:                                          "(is %ld)",
        !           415:                                          argv[i], (long)strlen(argv[i]));
        !           416:                        result = interface_allocate (&tmp, MDL);
        !           417:                        if (result != ISC_R_SUCCESS)
        !           418:                                log_fatal ("Insufficient memory to %s %s: %s",
        !           419:                                           "record interface", argv [i],
        !           420:                                           isc_result_totext (result));
        !           421:                        strcpy (tmp -> name, argv [i]);
        !           422:                        if (interfaces) {
        !           423:                                interface_reference (&tmp -> next,
        !           424:                                                     interfaces, MDL);
        !           425:                                interface_dereference (&interfaces, MDL);
        !           426:                        }
        !           427:                        interface_reference (&interfaces, tmp, MDL);
        !           428:                        tmp -> flags = INTERFACE_REQUESTED;
        !           429:                }
        !           430:        }
        !           431: 
        !           432:        if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
        !           433:                path_dhcpd_conf = s;
        !           434:        }
        !           435: 
        !           436: #ifdef DHCPv6
        !           437:         if (local_family == AF_INET6) {
        !           438:                 /* DHCPv6: override DHCPv4 lease and pid filenames */
        !           439:                if (!no_dhcpd_db) {
        !           440:                         if ((s = getenv ("PATH_DHCPD6_DB")))
        !           441:                                path_dhcpd_db = s;
        !           442:                         else
        !           443:                                path_dhcpd_db = _PATH_DHCPD6_DB;
        !           444:                }
        !           445:                if (!no_dhcpd_pid) {
        !           446:                         if ((s = getenv ("PATH_DHCPD6_PID")))
        !           447:                                path_dhcpd_pid = s;
        !           448:                         else
        !           449:                                path_dhcpd_pid = _PATH_DHCPD6_PID;
        !           450:                }
        !           451:         } else
        !           452: #else /* !DHCPv6 */
        !           453:         {
        !           454:                if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
        !           455:                        path_dhcpd_db = s;
        !           456:                }
        !           457:                if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
        !           458:                        path_dhcpd_pid = s;
        !           459:                }
        !           460:         }
        !           461: #endif /* DHCPv6 */
        !           462: 
        !           463:         /*
        !           464:          * convert relative path names to absolute, for files that need
        !           465:          * to be reopened after chdir() has been called
        !           466:          */
        !           467:         if (path_dhcpd_db[0] != '/') {
        !           468:                 char *path = dmalloc(PATH_MAX, MDL);
        !           469:                 if (path == NULL)
        !           470:                         log_fatal("No memory for filename\n");
        !           471:                 path_dhcpd_db = realpath(path_dhcpd_db,  path);
        !           472:                 if (path_dhcpd_db == NULL)
        !           473:                         log_fatal("%s: %s", path, strerror(errno));
        !           474:         }
        !           475: 
        !           476:        if (!quiet) {
        !           477:                log_info("%s %s", message, PACKAGE_VERSION);
        !           478:                log_info (copyright);
        !           479:                log_info (arr);
        !           480:                log_info (url);
        !           481:        } else {
        !           482:                quiet = 0;
        !           483:                log_perror = 0;
        !           484:        }
        !           485: 
        !           486: #if defined (TRACING)
        !           487:        trace_init (set_time, MDL);
        !           488:        if (traceoutfile) {
        !           489:                result = trace_begin (traceoutfile, MDL);
        !           490:                if (result != ISC_R_SUCCESS)
        !           491:                        log_fatal ("Unable to begin trace: %s",
        !           492:                                isc_result_totext (result));
        !           493:        }
        !           494:        interface_trace_setup ();
        !           495:        parse_trace_setup ();
        !           496:        trace_srandom = trace_type_register ("random-seed", (void *)0,
        !           497:                                             trace_seed_input,
        !           498:                                             trace_seed_stop, MDL);
        !           499: #endif
        !           500: 
        !           501: #if defined (PARANOIA)
        !           502:        /* get user and group info if those options were given */
        !           503:        if (set_user) {
        !           504:                struct passwd *tmp_pwd;
        !           505: 
        !           506:                if (geteuid())
        !           507:                        log_fatal ("you must be root to set user");
        !           508: 
        !           509:                if (!(tmp_pwd = getpwnam(set_user)))
        !           510:                        log_fatal ("no such user: %s", set_user);
        !           511: 
        !           512:                set_uid = tmp_pwd->pw_uid;
        !           513: 
        !           514:                /* use the user's group as the default gid */
        !           515:                if (!set_group)
        !           516:                        set_gid = tmp_pwd->pw_gid;
        !           517:        }
        !           518: 
        !           519:        if (set_group) {
        !           520: /* get around the ISC declaration of group */
        !           521: #define group real_group
        !           522:                struct group *tmp_grp;
        !           523: 
        !           524:                if (geteuid())
        !           525:                        log_fatal ("you must be root to set group");
        !           526: 
        !           527:                if (!(tmp_grp = getgrnam(set_group)))
        !           528:                        log_fatal ("no such group: %s", set_group);
        !           529: 
        !           530:                set_gid = tmp_grp->gr_gid;
        !           531: #undef group
        !           532:        }
        !           533: 
        !           534: #  if defined (EARLY_CHROOT)
        !           535:        if (set_chroot) setup_chroot (set_chroot);
        !           536: #  endif /* EARLY_CHROOT */
        !           537: #endif /* PARANOIA */
        !           538: 
        !           539:        /* Default to the DHCP/BOOTP port. */
        !           540:        if (!local_port)
        !           541:        {
        !           542:                if ((s = getenv ("DHCPD_PORT"))) {
        !           543:                        local_port = validate_port (s);
        !           544:                        log_debug ("binding to environment-specified port %d",
        !           545:                                   ntohs (local_port));
        !           546:                } else {
        !           547:                        if (local_family == AF_INET) {
        !           548:                                ent = getservbyname("dhcp", "udp");
        !           549:                                if (ent == NULL) {
        !           550:                                        local_port = htons(67);
        !           551:                                } else {
        !           552:                                        local_port = ent->s_port;
        !           553:                                }
        !           554:                        } else {
        !           555:                                /* INSIST(local_family == AF_INET6); */
        !           556:                                ent = getservbyname("dhcpv6-server", "udp");
        !           557:                                if (ent == NULL) {
        !           558:                                        local_port = htons(547);
        !           559:                                } else {
        !           560:                                        local_port = ent->s_port;
        !           561:                                }
        !           562:                        }
        !           563: #ifndef __CYGWIN32__ /* XXX */
        !           564:                        endservent ();
        !           565: #endif
        !           566:                }
        !           567:        }
        !           568:   
        !           569:        if (local_family == AF_INET) {
        !           570:                remote_port = htons(ntohs(local_port) + 1);
        !           571:        } else {
        !           572:                /* INSIST(local_family == AF_INET6); */
        !           573:                ent = getservbyname("dhcpv6-client", "udp");
        !           574:                if (ent == NULL) {
        !           575:                        remote_port = htons(546);
        !           576:                } else {
        !           577:                        remote_port = ent->s_port;
        !           578:                }
        !           579:        }
        !           580: 
        !           581:        if (server) {
        !           582:                if (local_family != AF_INET) {
        !           583:                        log_fatal("You can only specify address to send "
        !           584:                                  "replies to when running an IPv4 server.");
        !           585:                }
        !           586:                if (!inet_aton (server, &limited_broadcast)) {
        !           587:                        struct hostent *he;
        !           588:                        he = gethostbyname (server);
        !           589:                        if (he) {
        !           590:                                memcpy (&limited_broadcast,
        !           591:                                        he -> h_addr_list [0],
        !           592:                                        sizeof limited_broadcast);
        !           593:                        } else
        !           594:                                limited_broadcast.s_addr = INADDR_BROADCAST;
        !           595:                }
        !           596:        } else {
        !           597:                limited_broadcast.s_addr = INADDR_BROADCAST;
        !           598:        }
        !           599: 
        !           600:        /* Get the current time... */
        !           601:        gettimeofday(&cur_tv, NULL);
        !           602: 
        !           603:        /* Set up the initial dhcp option universe. */
        !           604:        initialize_common_option_spaces ();
        !           605:        initialize_server_option_spaces ();
        !           606: 
        !           607:        /* Add the ddns update style enumeration prior to parsing. */
        !           608:        add_enumeration (&ddns_styles);
        !           609:        add_enumeration (&syslog_enum);
        !           610: 
        !           611:        if (!group_allocate (&root_group, MDL))
        !           612:                log_fatal ("Can't allocate root group!");
        !           613:        root_group -> authoritative = 0;
        !           614: 
        !           615:        /* Set up various hooks. */
        !           616:        dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
        !           617:        bootp_packet_handler = do_packet;
        !           618: #ifdef DHCPv6
        !           619:        dhcpv6_packet_handler = do_packet6;
        !           620: #endif /* DHCPv6 */
        !           621: 
        !           622: #if defined (NSUPDATE)
        !           623:        /* Set up the standard name service updater routine. */
        !           624:        parse = NULL;
        !           625:        status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
        !           626:                            "standard name service update routine", 0);
        !           627:        if (status != ISC_R_SUCCESS)
        !           628:                log_fatal ("can't begin parsing name service updater!");
        !           629: 
        !           630:        if (parse != NULL) {
        !           631:                lose = 0;
        !           632:                if (!(parse_executable_statements(&root_group->statements,
        !           633:                                                  parse, &lose, context_any))) {
        !           634:                        end_parse(&parse);
        !           635:                        log_fatal("can't parse standard name service updater!");
        !           636:                }
        !           637:                end_parse(&parse);
        !           638:        }
        !           639: #endif
        !           640: 
        !           641:        /* Initialize icmp support... */
        !           642:        if (!cftest && !lftest)
        !           643:                icmp_startup (1, lease_pinged);
        !           644: 
        !           645: #if defined (TRACING)
        !           646:        if (traceinfile) {
        !           647:            if (!no_dhcpd_db) {
        !           648:                    log_error ("%s", "");
        !           649:                    log_error ("** You must specify a lease file with -lf.");
        !           650:                    log_error ("   Dhcpd will not overwrite your default");
        !           651:                    log_fatal ("   lease file when playing back a trace. **");
        !           652:            }           
        !           653:            trace_file_replay (traceinfile);
        !           654: 
        !           655: #if defined (DEBUG_MEMORY_LEAKAGE) && \
        !           656:                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !           657:             free_everything ();
        !           658:             omapi_print_dmalloc_usage_by_caller (); 
        !           659: #endif
        !           660: 
        !           661:            exit (0);
        !           662:        }
        !           663: #endif
        !           664: 
        !           665: #ifdef DHCPv6
        !           666:        /* set up DHCPv6 hashes */
        !           667:        if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
        !           668:                log_fatal("Out of memory creating hash for active IA_NA.");
        !           669:        }
        !           670:        if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
        !           671:                log_fatal("Out of memory creating hash for active IA_TA.");
        !           672:        }
        !           673:        if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
        !           674:                log_fatal("Out of memory creating hash for active IA_PD.");
        !           675:        }
        !           676: #endif /* DHCPv6 */
        !           677: 
        !           678:        /* Read the dhcpd.conf file... */
        !           679:        if (readconf () != ISC_R_SUCCESS)
        !           680:                log_fatal ("Configuration file errors encountered -- exiting");
        !           681: 
        !           682:        postconf_initialization (quiet);
        !           683:  
        !           684: #if defined (PARANOIA) && !defined (EARLY_CHROOT)
        !           685:        if (set_chroot) setup_chroot (set_chroot);
        !           686: #endif /* PARANOIA && !EARLY_CHROOT */
        !           687: 
        !           688:         /* test option should cause an early exit */
        !           689:        if (cftest && !lftest) 
        !           690:                exit(0);
        !           691: 
        !           692:        group_write_hook = group_writer;
        !           693: 
        !           694:        /* Start up the database... */
        !           695:        db_startup (lftest);
        !           696: 
        !           697:        if (lftest)
        !           698:                exit (0);
        !           699: 
        !           700:        /* Discover all the network interfaces and initialize them. */
        !           701:        discover_interfaces(DISCOVER_SERVER);
        !           702: 
        !           703: #ifdef DHCPv6
        !           704:        /*
        !           705:         * Remove addresses from our pools that we should not issue
        !           706:         * to clients.
        !           707:         *
        !           708:         * We currently have no support for this in IPv4. It is not 
        !           709:         * as important in IPv4, as making pools with ranges that 
        !           710:         * leave out interfaces and hosts is fairly straightforward
        !           711:         * using range notation, but not so handy with CIDR notation.
        !           712:         */
        !           713:        if (local_family == AF_INET6) {
        !           714:                mark_hosts_unavailable();
        !           715:                mark_phosts_unavailable();
        !           716:                mark_interfaces_unavailable();
        !           717:        }
        !           718: #endif /* DHCPv6 */
        !           719: 
        !           720: 
        !           721:        /* Make up a seed for the random number generator from current
        !           722:           time plus the sum of the last four bytes of each
        !           723:           interface's hardware address interpreted as an integer.
        !           724:           Not much entropy, but we're booting, so we're not likely to
        !           725:           find anything better. */
        !           726:        seed = 0;
        !           727:        for (ip = interfaces; ip; ip = ip -> next) {
        !           728:                int junk;
        !           729:                memcpy (&junk,
        !           730:                        &ip -> hw_address.hbuf [ip -> hw_address.hlen -
        !           731:                                               sizeof seed], sizeof seed);
        !           732:                seed += junk;
        !           733:        }
        !           734:        srandom (seed + cur_time);
        !           735: #if defined (TRACING)
        !           736:        trace_seed_stash (trace_srandom, seed + cur_time);
        !           737: #endif
        !           738:        postdb_startup ();
        !           739: 
        !           740: #ifdef DHCPv6
        !           741:        /*
        !           742:         * Set server DHCPv6 identifier.
        !           743:         * See dhcpv6.c for discussion of setting DUID.
        !           744:         */
        !           745:        if (set_server_duid_from_option() == ISC_R_SUCCESS) {
        !           746:                write_server_duid();
        !           747:        } else {
        !           748:                if (!server_duid_isset()) {
        !           749:                        if (generate_new_server_duid() != ISC_R_SUCCESS) {
        !           750:                                log_fatal("Unable to set server identifier.");
        !           751:                        }
        !           752:                        write_server_duid();
        !           753:                }
        !           754:        }
        !           755: #endif /* DHCPv6 */
        !           756: 
        !           757: #ifndef DEBUG
        !           758:        if (daemon) {
        !           759:                /* First part of becoming a daemon... */
        !           760:                if ((pid = fork ()) < 0)
        !           761:                        log_fatal ("Can't fork daemon: %m");
        !           762:                else if (pid)
        !           763:                        exit (0);
        !           764:        }
        !           765:  
        !           766: #if defined (PARANOIA)
        !           767:        /* change uid to the specified one */
        !           768: 
        !           769:        if (set_gid) {
        !           770:                if (setgroups (0, (void *)0))
        !           771:                        log_fatal ("setgroups: %m");
        !           772:                if (setgid (set_gid))
        !           773:                        log_fatal ("setgid(%d): %m", (int) set_gid);
        !           774:        }       
        !           775: 
        !           776:        if (set_uid) {
        !           777:                if (setuid (set_uid))
        !           778:                        log_fatal ("setuid(%d): %m", (int) set_uid);
        !           779:        }
        !           780: #endif /* PARANOIA */
        !           781: 
        !           782:        /*
        !           783:         * Deal with pid files.  If the user told us
        !           784:         * not to write a file we don't read one either
        !           785:         */
        !           786:        if (no_pid_file == ISC_FALSE) {
        !           787:                /*Read previous pid file. */
        !           788:                if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
        !           789:                        status = read(i, pbuf, (sizeof pbuf) - 1);
        !           790:                        close (i);
        !           791:                        if (status > 0) {
        !           792:                                pbuf[status] = 0;
        !           793:                                pid = atoi(pbuf);
        !           794: 
        !           795:                                /*
        !           796:                                 * If there was a previous server process and
        !           797:                                 * it is still running, abort
        !           798:                                 */
        !           799:                                if (!pid ||
        !           800:                                    (pid != getpid() && kill(pid, 0) == 0))
        !           801:                                        log_fatal("There's already a "
        !           802:                                                  "DHCP server running.");
        !           803:                        }
        !           804:                }
        !           805: 
        !           806:                /* Write new pid file. */
        !           807:                i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
        !           808:                if (i >= 0) {
        !           809:                        sprintf(pbuf, "%d\n", (int) getpid());
        !           810:                        IGNORE_RET (write(i, pbuf, strlen(pbuf)));
        !           811:                        close(i);
        !           812:                } else {
        !           813:                        log_error("Can't create PID file %s: %m.",
        !           814:                                  path_dhcpd_pid);
        !           815:                }
        !           816:        }
        !           817: 
        !           818:        /* If we were requested to log to stdout on the command line,
        !           819:           keep doing so; otherwise, stop. */
        !           820:        if (log_perror == -1)
        !           821:                log_perror = 1;
        !           822:        else
        !           823:                log_perror = 0;
        !           824: 
        !           825:        if (daemon) {
        !           826:                /* Become session leader and get pid... */
        !           827:                pid = setsid();
        !           828: 
        !           829:                 /* Close standard I/O descriptors. */
        !           830:                 close(0);
        !           831:                 close(1);
        !           832:                 close(2);
        !           833: 
        !           834:                 /* Reopen them on /dev/null. */
        !           835:                 open("/dev/null", O_RDWR);
        !           836:                 open("/dev/null", O_RDWR);
        !           837:                 open("/dev/null", O_RDWR);
        !           838:                 log_perror = 0; /* No sense logging to /dev/null. */
        !           839: 
        !           840:                        IGNORE_RET (chdir("/"));
        !           841:        }
        !           842: #endif /* !DEBUG */
        !           843: 
        !           844: #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
        !           845:                defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !           846:        dmalloc_cutoff_generation = dmalloc_generation;
        !           847:        dmalloc_longterm = dmalloc_outstanding;
        !           848:        dmalloc_outstanding = 0;
        !           849: #endif
        !           850: 
        !           851:        omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
        !           852:                             (omapi_object_t *)0, "state", server_running);
        !           853: 
        !           854:        register_eventhandler(&rw_queue_empty,commit_leases_readerdry);
        !           855:        
        !           856:        /* Receive packets and dispatch them... */
        !           857:        dispatch ();
        !           858: 
        !           859:        /* Not reached */
        !           860:        return 0;
        !           861: }
        !           862: #endif /* !UNIT_TEST */
        !           863: 
        !           864: void postconf_initialization (int quiet)
        !           865: {
        !           866:        struct option_state *options = (struct option_state *)0;
        !           867:        struct data_string db;
        !           868:        struct option_cache *oc;
        !           869:        char *s;
        !           870:        isc_result_t result;
        !           871:        struct parse *parse;
        !           872:        int tmp;
        !           873: 
        !           874:        /* Now try to get the lease file name. */
        !           875:        option_state_allocate (&options, MDL);
        !           876: 
        !           877:        execute_statements_in_scope ((struct binding_value **)0,
        !           878:                                     (struct packet *)0,
        !           879:                                     (struct lease *)0,
        !           880:                                     (struct client_state *)0,
        !           881:                                     (struct option_state *)0,
        !           882:                                     options, &global_scope,
        !           883:                                     root_group,
        !           884:                                     (struct group *)0);
        !           885:        memset (&db, 0, sizeof db);
        !           886:        oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
        !           887:        if (oc &&
        !           888:            evaluate_option_cache (&db, (struct packet *)0,
        !           889:                                   (struct lease *)0, (struct client_state *)0,
        !           890:                                   options, (struct option_state *)0,
        !           891:                                   &global_scope, oc, MDL)) {
        !           892:                s = dmalloc (db.len + 1, MDL);
        !           893:                if (!s)
        !           894:                        log_fatal ("no memory for lease db filename.");
        !           895:                memcpy (s, db.data, db.len);
        !           896:                s [db.len] = 0;
        !           897:                data_string_forget (&db, MDL);
        !           898:                path_dhcpd_db = s;
        !           899:        }
        !           900: 
        !           901:        oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
        !           902:        if (oc &&
        !           903:            evaluate_option_cache (&db, (struct packet *)0,
        !           904:                                   (struct lease *)0, (struct client_state *)0,
        !           905:                                   options, (struct option_state *)0,
        !           906:                                   &global_scope, oc, MDL)) {
        !           907:                s = dmalloc (db.len + 1, MDL);
        !           908:                if (!s)
        !           909:                        log_fatal ("no memory for pid filename.");
        !           910:                memcpy (s, db.data, db.len);
        !           911:                s [db.len] = 0;
        !           912:                data_string_forget (&db, MDL);
        !           913:                path_dhcpd_pid = s;
        !           914:        }
        !           915: 
        !           916: #ifdef DHCPv6
        !           917:         if (local_family == AF_INET6) {
        !           918:                 /*
        !           919:                  * Override lease file name with dhcpv6 lease file name,
        !           920:                  * if it was set; then, do the same with the pid file name
        !           921:                  */
        !           922:                 oc = lookup_option(&server_universe, options,
        !           923:                                    SV_DHCPV6_LEASE_FILE_NAME);
        !           924:                 if (oc &&
        !           925:                     evaluate_option_cache(&db, NULL, NULL, NULL,
        !           926:                                          options, NULL, &global_scope,
        !           927:                                           oc, MDL)) {
        !           928:                         s = dmalloc (db.len + 1, MDL);
        !           929:                         if (!s)
        !           930:                                 log_fatal ("no memory for lease db filename.");
        !           931:                         memcpy (s, db.data, db.len);
        !           932:                         s [db.len] = 0;
        !           933:                         data_string_forget (&db, MDL);
        !           934:                         path_dhcpd_db = s;
        !           935:                 }
        !           936: 
        !           937:                 oc = lookup_option(&server_universe, options,
        !           938:                                    SV_DHCPV6_PID_FILE_NAME);
        !           939:                 if (oc &&
        !           940:                     evaluate_option_cache(&db, NULL, NULL, NULL,
        !           941:                                          options, NULL, &global_scope,
        !           942:                                           oc, MDL)) {
        !           943:                         s = dmalloc (db.len + 1, MDL);
        !           944:                         if (!s)
        !           945:                                 log_fatal ("no memory for pid filename.");
        !           946:                         memcpy (s, db.data, db.len);
        !           947:                         s [db.len] = 0;
        !           948:                         data_string_forget (&db, MDL);
        !           949:                         path_dhcpd_pid = s;
        !           950:                 }
        !           951:         }
        !           952: #endif /* DHCPv6 */
        !           953: 
        !           954:        omapi_port = -1;
        !           955:        oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
        !           956:        if (oc &&
        !           957:            evaluate_option_cache (&db, (struct packet *)0,
        !           958:                                   (struct lease *)0, (struct client_state *)0,
        !           959:                                   options, (struct option_state *)0,
        !           960:                                   &global_scope, oc, MDL)) {
        !           961:                if (db.len == 2) {
        !           962:                        omapi_port = getUShort (db.data);
        !           963:                } else
        !           964:                        log_fatal ("invalid omapi port data length");
        !           965:                data_string_forget (&db, MDL);
        !           966:        }
        !           967: 
        !           968:        oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
        !           969:        if (oc &&
        !           970:            evaluate_option_cache (&db, (struct packet *)0,
        !           971:                                   (struct lease *)0, (struct client_state *)0,
        !           972:                                   options,
        !           973:                                   (struct option_state *)0,
        !           974:                                   &global_scope, oc, MDL)) {
        !           975:                s = dmalloc (db.len + 1, MDL);
        !           976:                if (!s)
        !           977:                        log_fatal ("no memory for OMAPI key filename.");
        !           978:                memcpy (s, db.data, db.len);
        !           979:                s [db.len] = 0;
        !           980:                data_string_forget (&db, MDL);
        !           981:                result = omapi_auth_key_lookup_name (&omapi_key, s);
        !           982:                dfree (s, MDL);
        !           983:                if (result != ISC_R_SUCCESS)
        !           984:                        log_fatal ("OMAPI key %s: %s",
        !           985:                                   s, isc_result_totext (result));
        !           986:        }
        !           987: 
        !           988:        oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
        !           989:        if (oc &&
        !           990:            evaluate_option_cache (&db, (struct packet *)0,
        !           991:                                   (struct lease *)0, (struct client_state *)0,
        !           992:                                   options,
        !           993:                                   (struct option_state *)0,
        !           994:                                   &global_scope, oc, MDL)) {
        !           995:                if (db.len == 2) {
        !           996:                        local_port = htons (getUShort (db.data));
        !           997:                } else
        !           998:                        log_fatal ("invalid local port data length");
        !           999:                data_string_forget (&db, MDL);
        !          1000:        }
        !          1001: 
        !          1002:        oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
        !          1003:        if (oc &&
        !          1004:            evaluate_option_cache (&db, (struct packet *)0,
        !          1005:                                   (struct lease *)0, (struct client_state *)0,
        !          1006:                                   options, (struct option_state *)0,
        !          1007:                                   &global_scope, oc, MDL)) {
        !          1008:                if (db.len == 2) {
        !          1009:                        remote_port = htons (getUShort (db.data));
        !          1010:                } else
        !          1011:                        log_fatal ("invalid remote port data length");
        !          1012:                data_string_forget (&db, MDL);
        !          1013:        }
        !          1014: 
        !          1015:        oc = lookup_option (&server_universe, options,
        !          1016:                            SV_LIMITED_BROADCAST_ADDRESS);
        !          1017:        if (oc &&
        !          1018:            evaluate_option_cache (&db, (struct packet *)0,
        !          1019:                                   (struct lease *)0, (struct client_state *)0,
        !          1020:                                   options, (struct option_state *)0,
        !          1021:                                   &global_scope, oc, MDL)) {
        !          1022:                if (db.len == 4) {
        !          1023:                        memcpy (&limited_broadcast, db.data, 4);
        !          1024:                } else
        !          1025:                        log_fatal ("invalid broadcast address data length");
        !          1026:                data_string_forget (&db, MDL);
        !          1027:        }
        !          1028: 
        !          1029:        oc = lookup_option (&server_universe, options,
        !          1030:                            SV_LOCAL_ADDRESS);
        !          1031:        if (oc &&
        !          1032:            evaluate_option_cache (&db, (struct packet *)0,
        !          1033:                                   (struct lease *)0, (struct client_state *)0,
        !          1034:                                   options, (struct option_state *)0,
        !          1035:                                   &global_scope, oc, MDL)) {
        !          1036:                if (db.len == 4) {
        !          1037:                        memcpy (&local_address, db.data, 4);
        !          1038:                } else
        !          1039:                        log_fatal ("invalid local address data length");
        !          1040:                data_string_forget (&db, MDL);
        !          1041:        }
        !          1042: 
        !          1043:        oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
        !          1044:        if (oc) {
        !          1045:                if (evaluate_option_cache (&db, (struct packet *)0,
        !          1046:                                           (struct lease *)0,
        !          1047:                                           (struct client_state *)0,
        !          1048:                                           options,
        !          1049:                                           (struct option_state *)0,
        !          1050:                                           &global_scope, oc, MDL)) {
        !          1051:                        if (db.len == 1) {
        !          1052:                                ddns_update_style = db.data [0];
        !          1053:                        } else
        !          1054:                                log_fatal ("invalid dns update type");
        !          1055:                        data_string_forget (&db, MDL);
        !          1056:                }
        !          1057:        } else {
        !          1058:                ddns_update_style = DDNS_UPDATE_STYLE_NONE;
        !          1059:        }
        !          1060: 
        !          1061:        oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
        !          1062:        if (oc) {
        !          1063:                if (evaluate_option_cache (&db, (struct packet *)0,
        !          1064:                                           (struct lease *)0,
        !          1065:                                           (struct client_state *)0,
        !          1066:                                           options,
        !          1067:                                           (struct option_state *)0,
        !          1068:                                           &global_scope, oc, MDL)) {
        !          1069:                        if (db.len == 1) {
        !          1070:                                closelog ();
        !          1071:                                openlog ("dhcpd", LOG_NDELAY, db.data[0]);
        !          1072:                                /* Log the startup banner into the new
        !          1073:                                   log file. */
        !          1074:                                if (!quiet) {
        !          1075:                                        /* Don't log to stderr twice. */
        !          1076:                                        tmp = log_perror;
        !          1077:                                        log_perror = 0;
        !          1078:                                        log_info("%s %s",
        !          1079:                                                 message, PACKAGE_VERSION);
        !          1080:                                        log_info (copyright);
        !          1081:                                        log_info (arr);
        !          1082:                                        log_info (url);
        !          1083:                                        log_perror = tmp;
        !          1084:                                }
        !          1085:                        } else
        !          1086:                                log_fatal ("invalid log facility");
        !          1087:                        data_string_forget (&db, MDL);
        !          1088:                }
        !          1089:        }
        !          1090:        
        !          1091:        oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
        !          1092:        if (oc &&
        !          1093:            evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
        !          1094:                                  &global_scope, oc, MDL)) {
        !          1095:                if (db.len == 2) {
        !          1096:                        max_outstanding_acks = htons(getUShort(db.data));
        !          1097:                } else {
        !          1098:                        log_fatal("invalid max delayed ACK count ");
        !          1099:                }
        !          1100:                data_string_forget(&db, MDL);
        !          1101:        }
        !          1102: 
        !          1103:        oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY);
        !          1104:        if (oc &&
        !          1105:            evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
        !          1106:                                  &global_scope, oc, MDL)) {
        !          1107:                u_int32_t timeval;
        !          1108: 
        !          1109:                if (db.len != 4)
        !          1110:                        log_fatal("invalid max ack delay configuration");
        !          1111: 
        !          1112:                timeval = getULong(db.data);
        !          1113:                max_ack_delay_secs  = timeval / 1000000;
        !          1114:                max_ack_delay_usecs = timeval % 1000000;
        !          1115: 
        !          1116:                data_string_forget(&db, MDL);
        !          1117:        }
        !          1118: 
        !          1119:        /* Don't need the options anymore. */
        !          1120:        option_state_dereference (&options, MDL);
        !          1121:        
        !          1122: #if defined (NSUPDATE)
        !          1123:        /* If old-style ddns updates have been requested, parse the
        !          1124:           old-style ddns updater. */
        !          1125:        if (ddns_update_style == 1) {
        !          1126:                struct executable_statement **e, *s;
        !          1127: 
        !          1128:                if (root_group -> statements) {
        !          1129:                        s = (struct executable_statement *)0;
        !          1130:                        if (!executable_statement_allocate (&s, MDL))
        !          1131:                                log_fatal ("no memory for ddns updater");
        !          1132:                        executable_statement_reference
        !          1133:                                (&s -> next, root_group -> statements, MDL);
        !          1134:                        executable_statement_dereference
        !          1135:                                (&root_group -> statements, MDL);
        !          1136:                        executable_statement_reference
        !          1137:                                (&root_group -> statements, s, MDL);
        !          1138:                        s -> op = statements_statement;
        !          1139:                        e = &s -> data.statements;
        !          1140:                        executable_statement_dereference (&s, MDL);
        !          1141:                } else {
        !          1142:                        e = &root_group -> statements;
        !          1143:                }
        !          1144: 
        !          1145:                /* Set up the standard name service updater routine. */
        !          1146:                parse = NULL;
        !          1147:                result = new_parse(&parse, -1, old_nsupdate,
        !          1148:                                   sizeof(old_nsupdate) - 1,
        !          1149:                                   "old name service update routine", 0);
        !          1150:                if (result != ISC_R_SUCCESS)
        !          1151:                        log_fatal ("can't begin parsing old ddns updater!");
        !          1152: 
        !          1153:                if (parse != NULL) {
        !          1154:                        tmp = 0;
        !          1155:                        if (!(parse_executable_statements(e, parse, &tmp,
        !          1156:                                                          context_any))) {
        !          1157:                                end_parse(&parse);
        !          1158:                                log_fatal("can't parse standard ddns updater!");
        !          1159:                        }
        !          1160:                }
        !          1161:                end_parse(&parse);
        !          1162:        }
        !          1163: #endif
        !          1164: }
        !          1165: 
        !          1166: void postdb_startup (void)
        !          1167: {
        !          1168:        /* Initialize the omapi listener state. */
        !          1169:        if (omapi_port != -1) {
        !          1170:                omapi_listener_start (0);
        !          1171:        }
        !          1172: 
        !          1173: #if defined (FAILOVER_PROTOCOL)
        !          1174:        /* Initialize the failover listener state. */
        !          1175:        dhcp_failover_startup ();
        !          1176: #endif
        !          1177: 
        !          1178:        /*
        !          1179:         * Begin our lease timeout background task.
        !          1180:         */
        !          1181:        schedule_all_ipv6_lease_timeouts();
        !          1182: }
        !          1183: 
        !          1184: /* Print usage message. */
        !          1185: 
        !          1186: static void
        !          1187: usage(void) {
        !          1188:        log_info("%s %s", message, PACKAGE_VERSION);
        !          1189:        log_info(copyright);
        !          1190:        log_info(arr);
        !          1191: 
        !          1192:        log_fatal("Usage: dhcpd [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
        !          1193: #ifdef DHCPv6
        !          1194:                  "             [-4|-6] [-cf config-file] [-lf lease-file]\n"
        !          1195: #else /* !DHCPv6 */
        !          1196:                  "             [-cf config-file] [-lf lease-file]\n"
        !          1197: #endif /* DHCPv6 */
        !          1198: #if defined (PARANOIA)
        !          1199:                   /* meld into the following string */
        !          1200:                  "             [-user user] [-group group] [-chroot dir]\n"
        !          1201: #endif /* PARANOIA */
        !          1202: #if defined (TRACING)
        !          1203:                  "             [-tf trace-output-file]\n"
        !          1204:                  "             [-play trace-input-file]\n"
        !          1205: #endif /* TRACING */
        !          1206:                  "             [-pf pid-file] [--no-pid] [-s server]\n"
        !          1207:                  "             [if0 [...ifN]]");
        !          1208: }
        !          1209: 
        !          1210: void lease_pinged (from, packet, length)
        !          1211:        struct iaddr from;
        !          1212:        u_int8_t *packet;
        !          1213:        int length;
        !          1214: {
        !          1215:        struct lease *lp;
        !          1216: 
        !          1217:        /* Don't try to look up a pinged lease if we aren't trying to
        !          1218:           ping one - otherwise somebody could easily make us churn by
        !          1219:           just forging repeated ICMP EchoReply packets for us to look
        !          1220:           up. */
        !          1221:        if (!outstanding_pings)
        !          1222:                return;
        !          1223: 
        !          1224:        lp = (struct lease *)0;
        !          1225:        if (!find_lease_by_ip_addr (&lp, from, MDL)) {
        !          1226:                log_debug ("unexpected ICMP Echo Reply from %s",
        !          1227:                           piaddr (from));
        !          1228:                return;
        !          1229:        }
        !          1230: 
        !          1231:        if (!lp -> state) {
        !          1232: #if defined (FAILOVER_PROTOCOL)
        !          1233:                if (!lp -> pool ||
        !          1234:                    !lp -> pool -> failover_peer)
        !          1235: #endif
        !          1236:                        log_debug ("ICMP Echo Reply for %s late or spurious.",
        !          1237:                                   piaddr (from));
        !          1238:                goto out;
        !          1239:        }
        !          1240: 
        !          1241:        if (lp -> ends > cur_time) {
        !          1242:                log_debug ("ICMP Echo reply while lease %s valid.",
        !          1243:                           piaddr (from));
        !          1244:        }
        !          1245: 
        !          1246:        /* At this point it looks like we pinged a lease and got a
        !          1247:           response, which shouldn't have happened. */
        !          1248:        data_string_forget (&lp -> state -> parameter_request_list, MDL);
        !          1249:        free_lease_state (lp -> state, MDL);
        !          1250:        lp -> state = (struct lease_state *)0;
        !          1251: 
        !          1252:        abandon_lease (lp, "pinged before offer");
        !          1253:        cancel_timeout (lease_ping_timeout, lp);
        !          1254:        --outstanding_pings;
        !          1255:       out:
        !          1256:        lease_dereference (&lp, MDL);
        !          1257: }
        !          1258: 
        !          1259: void lease_ping_timeout (vlp)
        !          1260:        void *vlp;
        !          1261: {
        !          1262:        struct lease *lp = vlp;
        !          1263: 
        !          1264: #if defined (DEBUG_MEMORY_LEAKAGE)
        !          1265:        unsigned long previous_outstanding = dmalloc_outstanding;
        !          1266: #endif
        !          1267: 
        !          1268:        --outstanding_pings;
        !          1269:        dhcp_reply (lp);
        !          1270: 
        !          1271: #if defined (DEBUG_MEMORY_LEAKAGE)
        !          1272:        log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
        !          1273:                  dmalloc_generation,
        !          1274:                  dmalloc_outstanding - previous_outstanding,
        !          1275:                  dmalloc_outstanding, dmalloc_longterm);
        !          1276: #endif
        !          1277: #if defined (DEBUG_MEMORY_LEAKAGE)
        !          1278:        dmalloc_dump_outstanding ();
        !          1279: #endif
        !          1280: }
        !          1281: 
        !          1282: int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
        !          1283: {
        !          1284:        struct subnet *subnet;
        !          1285:        struct shared_network *share;
        !          1286:        isc_result_t status;
        !          1287: 
        !          1288:        /* Special case for fallback network - not sure why this is
        !          1289:           necessary. */
        !          1290:        if (!ia) {
        !          1291:                const char *fnn = "fallback-net";
        !          1292:                status = shared_network_allocate (&ip -> shared_network, MDL);
        !          1293:                if (status != ISC_R_SUCCESS)
        !          1294:                        log_fatal ("No memory for shared subnet: %s",
        !          1295:                                   isc_result_totext (status));
        !          1296:                ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
        !          1297:                strcpy (ip -> shared_network -> name, fnn);
        !          1298:                return 1;
        !          1299:        }
        !          1300: 
        !          1301:        /* If there's a registered subnet for this address,
        !          1302:           connect it together... */
        !          1303:        subnet = (struct subnet *)0;
        !          1304:        if (find_subnet (&subnet, *ia, MDL)) {
        !          1305:                /* If this interface has multiple aliases on the same
        !          1306:                   subnet, ignore all but the first we encounter. */
        !          1307:                if (!subnet -> interface) {
        !          1308:                        interface_reference (&subnet -> interface, ip, MDL);
        !          1309:                        subnet -> interface_address = *ia;
        !          1310:                } else if (subnet -> interface != ip) {
        !          1311:                        log_error ("Multiple interfaces match the %s: %s %s", 
        !          1312:                                   "same subnet",
        !          1313:                                   subnet -> interface -> name, ip -> name);
        !          1314:                }
        !          1315:                share = subnet -> shared_network;
        !          1316:                if (ip -> shared_network &&
        !          1317:                    ip -> shared_network != share) {
        !          1318:                        log_fatal ("Interface %s matches multiple shared %s",
        !          1319:                                   ip -> name, "networks");
        !          1320:                } else {
        !          1321:                        if (!ip -> shared_network)
        !          1322:                                shared_network_reference
        !          1323:                                        (&ip -> shared_network, share, MDL);
        !          1324:                }
        !          1325:                
        !          1326:                if (!share -> interface) {
        !          1327:                        interface_reference (&share -> interface, ip, MDL);
        !          1328:                } else if (share -> interface != ip) {
        !          1329:                        log_error ("Multiple interfaces match the %s: %s %s", 
        !          1330:                                   "same shared network",
        !          1331:                                   share -> interface -> name, ip -> name);
        !          1332:                }
        !          1333:                subnet_dereference (&subnet, MDL);
        !          1334:        }
        !          1335:        return 1;
        !          1336: }
        !          1337: 
        !          1338: static TIME shutdown_time;
        !          1339: static int omapi_connection_count;
        !          1340: enum dhcp_shutdown_state shutdown_state;
        !          1341: 
        !          1342: isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
        !          1343: {
        !          1344:        /* Shut down all listeners. */
        !          1345:        if (shutdown_state == shutdown_listeners &&
        !          1346:            obj -> type == omapi_type_listener &&
        !          1347:            obj -> inner &&
        !          1348:            obj -> inner -> type == omapi_type_protocol_listener) {
        !          1349:                omapi_listener_destroy (obj, MDL);
        !          1350:                return ISC_R_SUCCESS;
        !          1351:        }
        !          1352: 
        !          1353:        /* Shut down all existing omapi connections. */
        !          1354:        if (obj -> type == omapi_type_connection &&
        !          1355:            obj -> inner &&
        !          1356:            obj -> inner -> type == omapi_type_protocol) {
        !          1357:                if (shutdown_state == shutdown_drop_omapi_connections) {
        !          1358:                        omapi_disconnect (obj, 1);
        !          1359:                }
        !          1360:                omapi_connection_count++;
        !          1361:                if (shutdown_state == shutdown_omapi_connections) {
        !          1362:                        omapi_disconnect (obj, 0);
        !          1363:                        return ISC_R_SUCCESS;
        !          1364:                }
        !          1365:        }
        !          1366: 
        !          1367:        /* Shutdown all DHCP interfaces. */
        !          1368:        if (obj -> type == dhcp_type_interface &&
        !          1369:            shutdown_state == shutdown_dhcp) {
        !          1370:                dhcp_interface_remove (obj, (omapi_object_t *)0);
        !          1371:                return ISC_R_SUCCESS;
        !          1372:        }
        !          1373:        return ISC_R_SUCCESS;
        !          1374: }
        !          1375: 
        !          1376: static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
        !          1377: {
        !          1378: #if defined (FAILOVER_PROTOCOL)
        !          1379:        dhcp_failover_state_t *state;
        !          1380:        int failover_connection_count = 0;
        !          1381: #endif
        !          1382:        struct timeval tv;
        !          1383: 
        !          1384:       oncemore:
        !          1385:        if (shutdown_state == shutdown_listeners ||
        !          1386:            shutdown_state == shutdown_omapi_connections ||
        !          1387:            shutdown_state == shutdown_drop_omapi_connections ||
        !          1388:            shutdown_state == shutdown_dhcp) {
        !          1389:                omapi_connection_count = 0;
        !          1390:                omapi_io_state_foreach (dhcp_io_shutdown, 0);
        !          1391:        }
        !          1392: 
        !          1393:        if ((shutdown_state == shutdown_listeners ||
        !          1394:             shutdown_state == shutdown_omapi_connections ||
        !          1395:             shutdown_state == shutdown_drop_omapi_connections) &&
        !          1396:            omapi_connection_count == 0) {
        !          1397:                shutdown_state = shutdown_dhcp;
        !          1398:                shutdown_time = cur_time;
        !          1399:                goto oncemore;
        !          1400:        } else if (shutdown_state == shutdown_listeners &&
        !          1401:                   cur_time - shutdown_time > 4) {
        !          1402:                shutdown_state = shutdown_omapi_connections;
        !          1403:                shutdown_time = cur_time;
        !          1404:        } else if (shutdown_state == shutdown_omapi_connections &&
        !          1405:                   cur_time - shutdown_time > 4) {
        !          1406:                shutdown_state = shutdown_drop_omapi_connections;
        !          1407:                shutdown_time = cur_time;
        !          1408:        } else if (shutdown_state == shutdown_drop_omapi_connections &&
        !          1409:                   cur_time - shutdown_time > 4) {
        !          1410:                shutdown_state = shutdown_dhcp;
        !          1411:                shutdown_time = cur_time;
        !          1412:                goto oncemore;
        !          1413:        } else if (shutdown_state == shutdown_dhcp &&
        !          1414:                   cur_time - shutdown_time > 4) {
        !          1415:                shutdown_state = shutdown_done;
        !          1416:                shutdown_time = cur_time;
        !          1417:        }
        !          1418: 
        !          1419: #if defined (FAILOVER_PROTOCOL)
        !          1420:        /* Set all failover peers into the shutdown state. */
        !          1421:        if (shutdown_state == shutdown_dhcp) {
        !          1422:            for (state = failover_states; state; state = state -> next) {
        !          1423:                if (state -> me.state == normal) {
        !          1424:                    dhcp_failover_set_state (state, shut_down);
        !          1425:                    failover_connection_count++;
        !          1426:                }
        !          1427:                if (state -> me.state == shut_down &&
        !          1428:                    state -> partner.state != partner_down)
        !          1429:                        failover_connection_count++;
        !          1430:            }
        !          1431:        }
        !          1432: 
        !          1433:        if (shutdown_state == shutdown_done) {
        !          1434:            for (state = failover_states; state; state = state -> next) {
        !          1435:                if (state -> me.state == shut_down) {
        !          1436:                    if (state -> link_to_peer)
        !          1437:                        dhcp_failover_link_dereference (&state -> link_to_peer,
        !          1438:                                                        MDL);
        !          1439:                    dhcp_failover_set_state (state, recover);
        !          1440:                }
        !          1441:            }
        !          1442: #if defined (DEBUG_MEMORY_LEAKAGE) && \
        !          1443:                defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !          1444:            free_everything ();
        !          1445:            omapi_print_dmalloc_usage_by_caller ();
        !          1446: #endif
        !          1447:            exit (0);
        !          1448:        }               
        !          1449: #else
        !          1450:        if (shutdown_state == shutdown_done) {
        !          1451: #if defined (DEBUG_MEMORY_LEAKAGE) && \
        !          1452:                defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !          1453:                free_everything ();
        !          1454:                omapi_print_dmalloc_usage_by_caller (); 
        !          1455: #endif
        !          1456:                exit (0);
        !          1457:        }
        !          1458: #endif
        !          1459:        if (shutdown_state == shutdown_dhcp &&
        !          1460: #if defined(FAILOVER_PROTOCOL)
        !          1461:            !failover_connection_count &&
        !          1462: #endif
        !          1463:            ISC_TRUE) {
        !          1464:                shutdown_state = shutdown_done;
        !          1465:                shutdown_time = cur_time;
        !          1466:                goto oncemore;
        !          1467:        }
        !          1468:        tv.tv_sec = cur_tv.tv_sec + 1;
        !          1469:        tv.tv_usec = cur_tv.tv_usec;
        !          1470:        add_timeout (&tv,
        !          1471:                     (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
        !          1472:        return ISC_R_SUCCESS;
        !          1473: }
        !          1474: 
        !          1475: isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
        !          1476:                                     control_object_state_t newstate)
        !          1477: {
        !          1478:        if (newstate == server_shutdown) {
        !          1479:                shutdown_time = cur_time;
        !          1480:                shutdown_state = shutdown_listeners;
        !          1481:                dhcp_io_shutdown_countdown (0);
        !          1482:                return ISC_R_SUCCESS;
        !          1483:        }
        !          1484:        return ISC_R_INVALIDARG;
        !          1485: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>