Annotation of embedaddon/dhcp/client/dhclient.c, revision 1.1

1.1     ! misho       1: /* dhclient.c
        !             2: 
        !             3:    DHCP Client. */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 1995-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 code is based on the original client state machine that was
        !            28:  * written by Elliot Poger.  The code has been extensively hacked on
        !            29:  * by Ted Lemon since then, so any mistakes you find are probably his
        !            30:  * fault and not Elliot's.
        !            31:  */
        !            32: 
        !            33: #include "dhcpd.h"
        !            34: #include <syslog.h>
        !            35: #include <signal.h>
        !            36: #include <errno.h>
        !            37: #include <sys/time.h>
        !            38: #include <sys/wait.h>
        !            39: #include <limits.h>
        !            40: 
        !            41: TIME default_lease_time = 43200; /* 12 hours... */
        !            42: TIME max_lease_time = 86400; /* 24 hours... */
        !            43: 
        !            44: const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
        !            45: const char *path_dhclient_db = NULL;
        !            46: const char *path_dhclient_pid = NULL;
        !            47: static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
        !            48: char *path_dhclient_script = path_dhclient_script_array;
        !            49: 
        !            50: /* False (default) => we write and use a pid file */
        !            51: isc_boolean_t no_pid_file = ISC_FALSE;
        !            52: 
        !            53: int dhcp_max_agent_option_packet_length = 0;
        !            54: 
        !            55: int interfaces_requested = 0;
        !            56: 
        !            57: struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
        !            58: struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
        !            59: struct in_addr inaddr_any;
        !            60: struct sockaddr_in sockaddr_broadcast;
        !            61: struct in_addr giaddr;
        !            62: struct data_string default_duid;
        !            63: 
        !            64: /* ASSERT_STATE() does nothing now; it used to be
        !            65:    assert (state_is == state_shouldbe). */
        !            66: #define ASSERT_STATE(state_is, state_shouldbe) {}
        !            67: 
        !            68: static const char copyright[] = 
        !            69: "Copyright 2004-2011 Internet Systems Consortium.";
        !            70: static const char arr [] = "All rights reserved.";
        !            71: static const char message [] = "Internet Systems Consortium DHCP Client";
        !            72: static const char url [] = 
        !            73: "For info, please visit https://www.isc.org/software/dhcp/";
        !            74: 
        !            75: u_int16_t local_port = 0;
        !            76: u_int16_t remote_port = 0;
        !            77: int no_daemon = 0;
        !            78: struct string_list *client_env = NULL;
        !            79: int client_env_count = 0;
        !            80: int onetry = 0;
        !            81: int quiet = 1;
        !            82: int nowait = 0;
        !            83: int stateless = 0;
        !            84: int wanted_ia_na = -1;         /* the absolute value is the real one. */
        !            85: int wanted_ia_ta = 0;
        !            86: int wanted_ia_pd = 0;
        !            87: char *mockup_relay = NULL;
        !            88: 
        !            89: void run_stateless(int exit_mode);
        !            90: 
        !            91: static void usage(void);
        !            92: 
        !            93: static isc_result_t write_duid(struct data_string *duid);
        !            94: static void add_reject(struct packet *packet);
        !            95: 
        !            96: static int check_domain_name(const char *ptr, size_t len, int dots);
        !            97: static int check_domain_name_list(const char *ptr, size_t len, int dots);
        !            98: static int check_option_values(struct universe *universe, unsigned int opt,
        !            99:                               const char *ptr, size_t len);
        !           100: 
        !           101: int
        !           102: main(int argc, char **argv) {
        !           103:        int fd;
        !           104:        int i;
        !           105:        struct interface_info *ip;
        !           106:        struct client_state *client;
        !           107:        unsigned seed;
        !           108:        char *server = NULL;
        !           109:        isc_result_t status;
        !           110:        int exit_mode = 0;
        !           111:        int release_mode = 0;
        !           112:        struct timeval tv;
        !           113:        omapi_object_t *listener;
        !           114:        isc_result_t result;
        !           115:        int persist = 0;
        !           116:        int no_dhclient_conf = 0;
        !           117:        int no_dhclient_db = 0;
        !           118:        int no_dhclient_pid = 0;
        !           119:        int no_dhclient_script = 0;
        !           120: #ifdef DHCPv6
        !           121:        int local_family_set = 0;
        !           122: #endif /* DHCPv6 */
        !           123:        char *s;
        !           124: 
        !           125:        /* Initialize client globals. */
        !           126:        memset(&default_duid, 0, sizeof(default_duid));
        !           127: 
        !           128:        /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
        !           129:           2 (stderr) are open. To do this, we assume that when we
        !           130:           open a file the lowest available file descriptor is used. */
        !           131:        fd = open("/dev/null", O_RDWR);
        !           132:        if (fd == 0)
        !           133:                fd = open("/dev/null", O_RDWR);
        !           134:        if (fd == 1)
        !           135:                fd = open("/dev/null", O_RDWR);
        !           136:        if (fd == 2)
        !           137:                log_perror = 0; /* No sense logging to /dev/null. */
        !           138:        else if (fd != -1)
        !           139:                close(fd);
        !           140: 
        !           141:        openlog("dhclient", LOG_NDELAY, LOG_DAEMON);
        !           142: 
        !           143: #if !(defined(DEBUG) || defined(__CYGWIN32__))
        !           144:        setlogmask(LOG_UPTO(LOG_INFO));
        !           145: #endif
        !           146: 
        !           147:        /*
        !           148:         * Set up the signal handlers, currently we only
        !           149:         * have one to ignore sigpipe.
        !           150:         */
        !           151:        if (dhcp_handle_signal(SIGPIPE, SIG_IGN) != ISC_R_SUCCESS) {
        !           152:                log_fatal("Can't set up signal handler");
        !           153:        }
        !           154: 
        !           155:        /* Set up the OMAPI. */
        !           156:        status = omapi_init();
        !           157:        if (status != ISC_R_SUCCESS)
        !           158:                log_fatal("Can't initialize OMAPI: %s",
        !           159:                          isc_result_totext(status));
        !           160: 
        !           161:        /* Set up the OMAPI wrappers for various server database internal
        !           162:           objects. */
        !           163:        dhcp_common_objects_setup();
        !           164: 
        !           165:        dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
        !           166:        dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
        !           167:        dhcp_interface_startup_hook = dhclient_interface_startup_hook;
        !           168: 
        !           169:        for (i = 1; i < argc; i++) {
        !           170:                if (!strcmp(argv[i], "-r")) {
        !           171:                        release_mode = 1;
        !           172:                        no_daemon = 1;
        !           173: #ifdef DHCPv6
        !           174:                } else if (!strcmp(argv[i], "-4")) {
        !           175:                        if (local_family_set && local_family != AF_INET)
        !           176:                                log_fatal("Client can only do v4 or v6, not "
        !           177:                                          "both.");
        !           178:                        local_family_set = 1;
        !           179:                        local_family = AF_INET;
        !           180:                } else if (!strcmp(argv[i], "-6")) {
        !           181:                        if (local_family_set && local_family != AF_INET6)
        !           182:                                log_fatal("Client can only do v4 or v6, not "
        !           183:                                          "both.");
        !           184:                        local_family_set = 1;
        !           185:                        local_family = AF_INET6;
        !           186: #endif /* DHCPv6 */
        !           187:                } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */
        !           188:                        release_mode = 0;
        !           189:                        no_daemon = 0;
        !           190:                        exit_mode = 1;
        !           191:                } else if (!strcmp(argv[i], "-p")) {
        !           192:                        if (++i == argc)
        !           193:                                usage();
        !           194:                        local_port = validate_port(argv[i]);
        !           195:                        log_debug("binding to user-specified port %d",
        !           196:                                  ntohs(local_port));
        !           197:                } else if (!strcmp(argv[i], "-d")) {
        !           198:                        no_daemon = 1;
        !           199:                        quiet = 0;
        !           200:                } else if (!strcmp(argv[i], "-pf")) {
        !           201:                        if (++i == argc)
        !           202:                                usage();
        !           203:                        path_dhclient_pid = argv[i];
        !           204:                        no_dhclient_pid = 1;
        !           205:                } else if (!strcmp(argv[i], "--no-pid")) {
        !           206:                        no_pid_file = ISC_TRUE;
        !           207:                } else if (!strcmp(argv[i], "-cf")) {
        !           208:                        if (++i == argc)
        !           209:                                usage();
        !           210:                        path_dhclient_conf = argv[i];
        !           211:                        no_dhclient_conf = 1;
        !           212:                } else if (!strcmp(argv[i], "-lf")) {
        !           213:                        if (++i == argc)
        !           214:                                usage();
        !           215:                        path_dhclient_db = argv[i];
        !           216:                        no_dhclient_db = 1;
        !           217:                } else if (!strcmp(argv[i], "-sf")) {
        !           218:                        if (++i == argc)
        !           219:                                usage();
        !           220:                        path_dhclient_script = argv[i];
        !           221:                        no_dhclient_script = 1;
        !           222:                } else if (!strcmp(argv[i], "-1")) {
        !           223:                        onetry = 1;
        !           224:                } else if (!strcmp(argv[i], "-q")) {
        !           225:                        quiet = 1;
        !           226:                } else if (!strcmp(argv[i], "-s")) {
        !           227:                        if (++i == argc)
        !           228:                                usage();
        !           229:                        server = argv[i];
        !           230:                } else if (!strcmp(argv[i], "-g")) {
        !           231:                        if (++i == argc)
        !           232:                                usage();
        !           233:                        mockup_relay = argv[i];
        !           234:                } else if (!strcmp(argv[i], "-nw")) {
        !           235:                        nowait = 1;
        !           236:                } else if (!strcmp(argv[i], "-n")) {
        !           237:                        /* do not start up any interfaces */
        !           238:                        interfaces_requested = -1;
        !           239:                } else if (!strcmp(argv[i], "-w")) {
        !           240:                        /* do not exit if there are no broadcast interfaces. */
        !           241:                        persist = 1;
        !           242:                } else if (!strcmp(argv[i], "-e")) {
        !           243:                        struct string_list *tmp;
        !           244:                        if (++i == argc)
        !           245:                                usage();
        !           246:                        tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL);
        !           247:                        if (!tmp)
        !           248:                                log_fatal("No memory for %s", argv[i]);
        !           249:                        strcpy(tmp->string, argv[i]);
        !           250:                        tmp->next = client_env;
        !           251:                        client_env = tmp;
        !           252:                        client_env_count++;
        !           253: #ifdef DHCPv6
        !           254:                } else if (!strcmp(argv[i], "-S")) {
        !           255:                        if (local_family_set && (local_family == AF_INET)) {
        !           256:                                usage();
        !           257:                        }
        !           258:                        local_family_set = 1;
        !           259:                        local_family = AF_INET6;
        !           260:                        wanted_ia_na = 0;
        !           261:                        stateless = 1;
        !           262:                } else if (!strcmp(argv[i], "-N")) {
        !           263:                        if (local_family_set && (local_family == AF_INET)) {
        !           264:                                usage();
        !           265:                        }
        !           266:                        local_family_set = 1;
        !           267:                        local_family = AF_INET6;
        !           268:                        if (wanted_ia_na < 0) {
        !           269:                                wanted_ia_na = 0;
        !           270:                        }
        !           271:                        wanted_ia_na++;
        !           272:                } else if (!strcmp(argv[i], "-T")) {
        !           273:                        if (local_family_set && (local_family == AF_INET)) {
        !           274:                                usage();
        !           275:                        }
        !           276:                        local_family_set = 1;
        !           277:                        local_family = AF_INET6;
        !           278:                        if (wanted_ia_na < 0) {
        !           279:                                wanted_ia_na = 0;
        !           280:                        }
        !           281:                        wanted_ia_ta++;
        !           282:                } else if (!strcmp(argv[i], "-P")) {
        !           283:                        if (local_family_set && (local_family == AF_INET)) {
        !           284:                                usage();
        !           285:                        }
        !           286:                        local_family_set = 1;
        !           287:                        local_family = AF_INET6;
        !           288:                        if (wanted_ia_na < 0) {
        !           289:                                wanted_ia_na = 0;
        !           290:                        }
        !           291:                        wanted_ia_pd++;
        !           292: #endif /* DHCPv6 */
        !           293:                } else if (!strcmp(argv[i], "-v")) {
        !           294:                        quiet = 0;
        !           295:                } else if (!strcmp(argv[i], "--version")) {
        !           296:                        log_info("isc-dhclient-%s", PACKAGE_VERSION);
        !           297:                        exit(0);
        !           298:                } else if (argv[i][0] == '-') {
        !           299:                    usage();
        !           300:                } else if (interfaces_requested < 0) {
        !           301:                    usage();
        !           302:                } else {
        !           303:                    struct interface_info *tmp = NULL;
        !           304: 
        !           305:                    status = interface_allocate(&tmp, MDL);
        !           306:                    if (status != ISC_R_SUCCESS)
        !           307:                        log_fatal("Can't record interface %s:%s",
        !           308:                                  argv[i], isc_result_totext(status));
        !           309:                    if (strlen(argv[i]) >= sizeof(tmp->name))
        !           310:                            log_fatal("%s: interface name too long (is %ld)",
        !           311:                                      argv[i], (long)strlen(argv[i]));
        !           312:                    strcpy(tmp->name, argv[i]);
        !           313:                    if (interfaces) {
        !           314:                            interface_reference(&tmp->next,
        !           315:                                                interfaces, MDL);
        !           316:                            interface_dereference(&interfaces, MDL);
        !           317:                    }
        !           318:                    interface_reference(&interfaces, tmp, MDL);
        !           319:                    tmp->flags = INTERFACE_REQUESTED;
        !           320:                    interfaces_requested++;
        !           321:                }
        !           322:        }
        !           323: 
        !           324:        if (wanted_ia_na < 0) {
        !           325:                wanted_ia_na = 1;
        !           326:        }
        !           327: 
        !           328:        /* Support only one (requested) interface for Prefix Delegation. */
        !           329:        if (wanted_ia_pd && (interfaces_requested != 1)) {
        !           330:                usage();
        !           331:        }
        !           332: 
        !           333:        if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
        !           334:                path_dhclient_conf = s;
        !           335:        }
        !           336:        if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) {
        !           337:                path_dhclient_db = s;
        !           338:        }
        !           339:        if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) {
        !           340:                path_dhclient_pid = s;
        !           341:        }
        !           342:        if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) {
        !           343:                path_dhclient_script = s;
        !           344:        }
        !           345: 
        !           346:        /* Set up the initial dhcp option universe. */
        !           347:        initialize_common_option_spaces();
        !           348: 
        !           349:        /* Assign v4 or v6 specific running parameters. */
        !           350:        if (local_family == AF_INET)
        !           351:                dhcpv4_client_assignments();
        !           352: #ifdef DHCPv6
        !           353:        else if (local_family == AF_INET6)
        !           354:                dhcpv6_client_assignments();
        !           355: #endif /* DHCPv6 */
        !           356:        else
        !           357:                log_fatal("Impossible condition at %s:%d.", MDL);
        !           358: 
        !           359:        /*
        !           360:         * convert relative path names to absolute, for files that need
        !           361:         * to be reopened after chdir() has been called
        !           362:         */
        !           363:        if (path_dhclient_db[0] != '/') {
        !           364:                char *path = dmalloc(PATH_MAX, MDL);
        !           365:                if (path == NULL)
        !           366:                        log_fatal("No memory for filename\n");
        !           367:                path_dhclient_db = realpath(path_dhclient_db, path);
        !           368:                if (path_dhclient_db == NULL)
        !           369:                        log_fatal("%s: %s", path, strerror(errno));
        !           370:        }
        !           371: 
        !           372:        if (path_dhclient_script[0] != '/') {
        !           373:                char *path = dmalloc(PATH_MAX, MDL);
        !           374:                if (path == NULL)
        !           375:                        log_fatal("No memory for filename\n");
        !           376:                path_dhclient_script = realpath(path_dhclient_script, path);
        !           377:                if (path_dhclient_script == NULL)
        !           378:                        log_fatal("%s: %s", path, strerror(errno));
        !           379:        }
        !           380: 
        !           381:        /*
        !           382:         * See if we should  kill off any currently running client
        !           383:         * we don't try to kill it off if the user told us not
        !           384:         * to write a pid file - we assume they are controlling
        !           385:         * the process in some other fashion.
        !           386:         */
        !           387:        if ((release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) {
        !           388:                FILE *pidfd;
        !           389:                pid_t oldpid;
        !           390:                long temp;
        !           391:                int e;
        !           392: 
        !           393:                oldpid = 0;
        !           394:                if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
        !           395:                        e = fscanf(pidfd, "%ld\n", &temp);
        !           396:                        oldpid = (pid_t)temp;
        !           397: 
        !           398:                        if (e != 0 && e != EOF) {
        !           399:                                if (oldpid)
        !           400:                                        kill(oldpid, SIGTERM);
        !           401:                        }
        !           402:                        fclose(pidfd);
        !           403:                }
        !           404:        }
        !           405: 
        !           406:        if (!quiet) {
        !           407:                log_info("%s %s", message, PACKAGE_VERSION);
        !           408:                log_info(copyright);
        !           409:                log_info(arr);
        !           410:                log_info(url);
        !           411:                log_info("%s", "");
        !           412:        } else {
        !           413:                log_perror = 0;
        !           414:                quiet_interface_discovery = 1;
        !           415:        }
        !           416: 
        !           417:        /* If we're given a relay agent address to insert, for testing
        !           418:           purposes, figure out what it is. */
        !           419:        if (mockup_relay) {
        !           420:                if (!inet_aton(mockup_relay, &giaddr)) {
        !           421:                        struct hostent *he;
        !           422:                        he = gethostbyname(mockup_relay);
        !           423:                        if (he) {
        !           424:                                memcpy(&giaddr, he->h_addr_list[0],
        !           425:                                       sizeof giaddr);
        !           426:                        } else {
        !           427:                                log_fatal("%s: no such host", mockup_relay);
        !           428:                        }
        !           429:                }
        !           430:        }
        !           431: 
        !           432:        /* Get the current time... */
        !           433:        gettimeofday(&cur_tv, NULL);
        !           434: 
        !           435:        sockaddr_broadcast.sin_family = AF_INET;
        !           436:        sockaddr_broadcast.sin_port = remote_port;
        !           437:        if (server) {
        !           438:                if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) {
        !           439:                        struct hostent *he;
        !           440:                        he = gethostbyname(server);
        !           441:                        if (he) {
        !           442:                                memcpy(&sockaddr_broadcast.sin_addr,
        !           443:                                       he->h_addr_list[0],
        !           444:                                       sizeof sockaddr_broadcast.sin_addr);
        !           445:                        } else
        !           446:                                sockaddr_broadcast.sin_addr.s_addr =
        !           447:                                        INADDR_BROADCAST;
        !           448:                }
        !           449:        } else {
        !           450:                sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
        !           451:        }
        !           452: 
        !           453:        inaddr_any.s_addr = INADDR_ANY;
        !           454: 
        !           455:        /* Stateless special case. */
        !           456:        if (stateless) {
        !           457:                if (release_mode || (wanted_ia_na > 0) ||
        !           458:                    wanted_ia_ta || wanted_ia_pd ||
        !           459:                    (interfaces_requested != 1)) {
        !           460:                        usage();
        !           461:                }
        !           462:                run_stateless(exit_mode);
        !           463:                return 0;
        !           464:        }
        !           465: 
        !           466:        /* Discover all the network interfaces. */
        !           467:        discover_interfaces(DISCOVER_UNCONFIGURED);
        !           468: 
        !           469:        /* Parse the dhclient.conf file. */
        !           470:        read_client_conf();
        !           471: 
        !           472:        /* Parse the lease database. */
        !           473:        read_client_leases();
        !           474: 
        !           475:        /* Rewrite the lease database... */
        !           476:        rewrite_client_leases();
        !           477: 
        !           478:        /* XXX */
        !           479: /*     config_counter(&snd_counter, &rcv_counter); */
        !           480: 
        !           481:        /*
        !           482:         * If no broadcast interfaces were discovered, call the script
        !           483:         * and tell it so.
        !           484:         */
        !           485:        if (!interfaces) {
        !           486:                /*
        !           487:                 * Call dhclient-script with the NBI flag,
        !           488:                 * in case somebody cares.
        !           489:                 */
        !           490:                script_init(NULL, "NBI", NULL);
        !           491:                script_go(NULL);
        !           492: 
        !           493:                /*
        !           494:                 * If we haven't been asked to persist, waiting for new
        !           495:                 * interfaces, then just exit.
        !           496:                 */
        !           497:                if (!persist) {
        !           498:                        /* Nothing more to do. */
        !           499:                        log_info("No broadcast interfaces found - exiting.");
        !           500:                        exit(0);
        !           501:                }
        !           502:        } else if (!release_mode && !exit_mode) {
        !           503:                /* Call the script with the list of interfaces. */
        !           504:                for (ip = interfaces; ip; ip = ip->next) {
        !           505:                        /*
        !           506:                         * If interfaces were specified, don't configure
        !           507:                         * interfaces that weren't specified!
        !           508:                         */
        !           509:                        if ((interfaces_requested > 0) &&
        !           510:                            ((ip->flags & (INTERFACE_REQUESTED |
        !           511:                                           INTERFACE_AUTOMATIC)) !=
        !           512:                             INTERFACE_REQUESTED))
        !           513:                                continue;
        !           514: 
        !           515:                        if (local_family == AF_INET6) {
        !           516:                                script_init(ip->client, "PREINIT6", NULL);
        !           517:                        } else {
        !           518:                                script_init(ip->client, "PREINIT", NULL);
        !           519:                                if (ip->client->alias != NULL)
        !           520:                                        script_write_params(ip->client,
        !           521:                                                            "alias_",
        !           522:                                                            ip->client->alias);
        !           523:                        }
        !           524:                        script_go(ip->client);
        !           525:                }
        !           526:        }
        !           527: 
        !           528:        /* At this point, all the interfaces that the script thinks
        !           529:           are relevant should be running, so now we once again call
        !           530:           discover_interfaces(), and this time ask it to actually set
        !           531:           up the interfaces. */
        !           532:        discover_interfaces(interfaces_requested != 0
        !           533:                            ? DISCOVER_REQUESTED
        !           534:                            : DISCOVER_RUNNING);
        !           535: 
        !           536:        /* Make up a seed for the random number generator from current
        !           537:           time plus the sum of the last four bytes of each
        !           538:           interface's hardware address interpreted as an integer.
        !           539:           Not much entropy, but we're booting, so we're not likely to
        !           540:           find anything better. */
        !           541:        seed = 0;
        !           542:        for (ip = interfaces; ip; ip = ip->next) {
        !           543:                int junk;
        !           544:                memcpy(&junk,
        !           545:                       &ip->hw_address.hbuf[ip->hw_address.hlen -
        !           546:                                            sizeof seed], sizeof seed);
        !           547:                seed += junk;
        !           548:        }
        !           549:        srandom(seed + cur_time + (unsigned)getpid());
        !           550: 
        !           551:        /* Start a configuration state machine for each interface. */
        !           552: #ifdef DHCPv6
        !           553:        if (local_family == AF_INET6) {
        !           554:                /* Establish a default DUID.  This may be moved to the
        !           555:                 * DHCPv4 area later.
        !           556:                 */
        !           557:                if (default_duid.len == 0) {
        !           558:                        if (default_duid.buffer != NULL)
        !           559:                                data_string_forget(&default_duid, MDL);
        !           560: 
        !           561:                        form_duid(&default_duid, MDL);
        !           562:                        write_duid(&default_duid);
        !           563:                }
        !           564: 
        !           565:                for (ip = interfaces ; ip != NULL ; ip = ip->next) {
        !           566:                        for (client = ip->client ; client != NULL ;
        !           567:                             client = client->next) {
        !           568:                                if (release_mode) {
        !           569:                                        start_release6(client);
        !           570:                                        continue;
        !           571:                                } else if (exit_mode) {
        !           572:                                        unconfigure6(client, "STOP6");
        !           573:                                        continue;
        !           574:                                }
        !           575: 
        !           576:                                /* If we have a previous binding, Confirm
        !           577:                                 * that we can (or can't) still use it.
        !           578:                                 */
        !           579:                                if ((client->active_lease != NULL) &&
        !           580:                                    !client->active_lease->released)
        !           581:                                        start_confirm6(client);
        !           582:                                else
        !           583:                                        start_init6(client);
        !           584:                        }
        !           585:                }
        !           586:        } else
        !           587: #endif /* DHCPv6 */
        !           588:        {
        !           589:                for (ip = interfaces ; ip ; ip = ip->next) {
        !           590:                        ip->flags |= INTERFACE_RUNNING;
        !           591:                        for (client = ip->client ; client ;
        !           592:                             client = client->next) {
        !           593:                                if (exit_mode)
        !           594:                                        state_stop(client);
        !           595:                                else if (release_mode)
        !           596:                                        do_release(client);
        !           597:                                else {
        !           598:                                        client->state = S_INIT;
        !           599: 
        !           600:                                        if (top_level_config.initial_delay>0)
        !           601:                                        {
        !           602:                                                tv.tv_sec = 0;
        !           603:                                                if (top_level_config.
        !           604:                                                    initial_delay>1)
        !           605:                                                        tv.tv_sec = cur_time
        !           606:                                                        + random()
        !           607:                                                        % (top_level_config.
        !           608:                                                           initial_delay-1);
        !           609:                                                tv.tv_usec = random()
        !           610:                                                        % 1000000;
        !           611:                                                /*
        !           612:                                                 * this gives better
        !           613:                                                 * distribution than just
        !           614:                                                 *whole seconds
        !           615:                                                 */
        !           616:                                                add_timeout(&tv, state_reboot,
        !           617:                                                            client, 0, 0);
        !           618:                                        } else {
        !           619:                                                state_reboot(client);
        !           620:                                        }
        !           621:                                }
        !           622:                        }
        !           623:                }
        !           624:        }
        !           625: 
        !           626:        if (exit_mode)
        !           627:                return 0;
        !           628:        if (release_mode) {
        !           629: #ifndef DHCPv6
        !           630:                return 0;
        !           631: #else
        !           632:                if (local_family == AF_INET6) {
        !           633:                        if (onetry)
        !           634:                                return 0;
        !           635:                } else
        !           636:                        return 0;
        !           637: #endif /* DHCPv6 */
        !           638:        }
        !           639: 
        !           640:        /* Start up a listener for the object management API protocol. */
        !           641:        if (top_level_config.omapi_port != -1) {
        !           642:                listener = NULL;
        !           643:                result = omapi_generic_new(&listener, MDL);
        !           644:                if (result != ISC_R_SUCCESS)
        !           645:                        log_fatal("Can't allocate new generic object: %s\n",
        !           646:                                  isc_result_totext(result));
        !           647:                result = omapi_protocol_listen(listener,
        !           648:                                               (unsigned)
        !           649:                                               top_level_config.omapi_port,
        !           650:                                               1);
        !           651:                if (result != ISC_R_SUCCESS)
        !           652:                        log_fatal("Can't start OMAPI protocol: %s",
        !           653:                                  isc_result_totext (result));
        !           654:        }
        !           655: 
        !           656:        /* Set up the bootp packet handler... */
        !           657:        bootp_packet_handler = do_packet;
        !           658: #ifdef DHCPv6
        !           659:        dhcpv6_packet_handler = do_packet6;
        !           660: #endif /* DHCPv6 */
        !           661: 
        !           662: #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
        !           663:                defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !           664:        dmalloc_cutoff_generation = dmalloc_generation;
        !           665:        dmalloc_longterm = dmalloc_outstanding;
        !           666:        dmalloc_outstanding = 0;
        !           667: #endif
        !           668: 
        !           669:        /* If we're not supposed to wait before getting the address,
        !           670:           don't. */
        !           671:        if (nowait)
        !           672:                go_daemon();
        !           673: 
        !           674:        /* If we're not going to daemonize, write the pid file
        !           675:           now. */
        !           676:        if (no_daemon || nowait)
        !           677:                write_client_pid_file();
        !           678: 
        !           679:        /* Start dispatching packets and timeouts... */
        !           680:        dispatch();
        !           681: 
        !           682:        /*NOTREACHED*/
        !           683:        return 0;
        !           684: }
        !           685: 
        !           686: static void usage()
        !           687: {
        !           688:        log_info("%s %s", message, PACKAGE_VERSION);
        !           689:        log_info(copyright);
        !           690:        log_info(arr);
        !           691:        log_info(url);
        !           692: 
        !           693: 
        !           694:        log_fatal("Usage: dhclient "
        !           695: #ifdef DHCPv6
        !           696:                  "[-4|-6] [-SNTP1dvrx] [-nw] [-p <port>]\n"
        !           697: #else /* DHCPv6 */
        !           698:                  "[-1dvrx] [-nw] [-p <port>]\n"
        !           699: #endif /* DHCPv6 */
        !           700:                  "                [-s server-addr] [-cf config-file] "
        !           701:                  "[-lf lease-file]\n"
        !           702:                  "                [-pf pid-file] [--no-pid] [-e VAR=val]\n"
        !           703:                  "                [-sf script-file] [interface]");
        !           704: }
        !           705: 
        !           706: void run_stateless(int exit_mode)
        !           707: {
        !           708: #ifdef DHCPv6
        !           709:        struct client_state *client;
        !           710:        omapi_object_t *listener;
        !           711:        isc_result_t result;
        !           712: 
        !           713:        /* Discover the network interface. */
        !           714:        discover_interfaces(DISCOVER_REQUESTED);
        !           715: 
        !           716:        if (!interfaces)
        !           717:                usage();
        !           718: 
        !           719:        /* Parse the dhclient.conf file. */
        !           720:        read_client_conf();
        !           721: 
        !           722:        /* Parse the lease database. */
        !           723:        read_client_leases();
        !           724: 
        !           725:        /* Establish a default DUID. */
        !           726:        if (default_duid.len == 0) {
        !           727:                if (default_duid.buffer != NULL)
        !           728:                        data_string_forget(&default_duid, MDL);
        !           729: 
        !           730:                form_duid(&default_duid, MDL);
        !           731:        }
        !           732: 
        !           733:        /* Start a configuration state machine. */
        !           734:        for (client = interfaces->client ;
        !           735:             client != NULL ;
        !           736:             client = client->next) {
        !           737:                if (exit_mode) {
        !           738:                        unconfigure6(client, "STOP6");
        !           739:                        continue;
        !           740:                }
        !           741:                start_info_request6(client);
        !           742:        }
        !           743:        if (exit_mode)
        !           744:                return;
        !           745: 
        !           746:        /* Start up a listener for the object management API protocol. */
        !           747:        if (top_level_config.omapi_port != -1) {
        !           748:                listener = NULL;
        !           749:                result = omapi_generic_new(&listener, MDL);
        !           750:                if (result != ISC_R_SUCCESS)
        !           751:                        log_fatal("Can't allocate new generic object: %s\n",
        !           752:                                  isc_result_totext(result));
        !           753:                result = omapi_protocol_listen(listener,
        !           754:                                               (unsigned)
        !           755:                                               top_level_config.omapi_port,
        !           756:                                               1);
        !           757:                if (result != ISC_R_SUCCESS)
        !           758:                        log_fatal("Can't start OMAPI protocol: %s",
        !           759:                                  isc_result_totext(result));
        !           760:        }
        !           761: 
        !           762:        /* Set up the packet handler... */
        !           763:        dhcpv6_packet_handler = do_packet6;
        !           764: 
        !           765: #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
        !           766:                defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
        !           767:        dmalloc_cutoff_generation = dmalloc_generation;
        !           768:        dmalloc_longterm = dmalloc_outstanding;
        !           769:        dmalloc_outstanding = 0;
        !           770: #endif
        !           771: 
        !           772:        /* If we're not supposed to wait before getting the address,
        !           773:           don't. */
        !           774:        if (nowait)
        !           775:                go_daemon();
        !           776: 
        !           777:        /* If we're not going to daemonize, write the pid file
        !           778:           now. */
        !           779:        if (no_daemon || nowait)
        !           780:                write_client_pid_file();
        !           781: 
        !           782:        /* Start dispatching packets and timeouts... */
        !           783:        dispatch();
        !           784: 
        !           785:        /*NOTREACHED*/
        !           786: #endif /* DHCPv6 */
        !           787:        return;
        !           788: }
        !           789: 
        !           790: isc_result_t find_class (struct class **c,
        !           791:                const char *s, const char *file, int line)
        !           792: {
        !           793:        return 0;
        !           794: }
        !           795: 
        !           796: int check_collection (packet, lease, collection)
        !           797:        struct packet *packet;
        !           798:        struct lease *lease;
        !           799:        struct collection *collection;
        !           800: {
        !           801:        return 0;
        !           802: }
        !           803: 
        !           804: void classify (packet, class)
        !           805:        struct packet *packet;
        !           806:        struct class *class;
        !           807: {
        !           808: }
        !           809: 
        !           810: int unbill_class (lease, class)
        !           811:        struct lease *lease;
        !           812:        struct class *class;
        !           813: {
        !           814:        return 0;
        !           815: }
        !           816: 
        !           817: int find_subnet (struct subnet **sp,
        !           818:                 struct iaddr addr, const char *file, int line)
        !           819: {
        !           820:        return 0;
        !           821: }
        !           822: 
        !           823: /* Individual States:
        !           824:  *
        !           825:  * Each routine is called from the dhclient_state_machine() in one of
        !           826:  * these conditions:
        !           827:  * -> entering INIT state
        !           828:  * -> recvpacket_flag == 0: timeout in this state
        !           829:  * -> otherwise: received a packet in this state
        !           830:  *
        !           831:  * Return conditions as handled by dhclient_state_machine():
        !           832:  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
        !           833:  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
        !           834:  * Returns 0: finish the nap which was interrupted for no good reason.
        !           835:  *
        !           836:  * Several per-interface variables are used to keep track of the process:
        !           837:  *   active_lease: the lease that is being used on the interface
        !           838:  *                 (null pointer if not configured yet).
        !           839:  *   offered_leases: leases corresponding to DHCPOFFER messages that have
        !           840:  *                  been sent to us by DHCP servers.
        !           841:  *   acked_leases: leases corresponding to DHCPACK messages that have been
        !           842:  *                sent to us by DHCP servers.
        !           843:  *   sendpacket: DHCP packet we're trying to send.
        !           844:  *   destination: IP address to send sendpacket to
        !           845:  * In addition, there are several relevant per-lease variables.
        !           846:  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
        !           847:  * In the active lease, these control the process of renewing the lease;
        !           848:  * In leases on the acked_leases list, this simply determines when we
        !           849:  * can no longer legitimately use the lease.
        !           850:  */
        !           851: 
        !           852: void state_reboot (cpp)
        !           853:        void *cpp;
        !           854: {
        !           855:        struct client_state *client = cpp;
        !           856: 
        !           857:        /* If we don't remember an active lease, go straight to INIT. */
        !           858:        if (!client -> active ||
        !           859:            client -> active -> is_bootp ||
        !           860:            client -> active -> expiry <= cur_time) {
        !           861:                state_init (client);
        !           862:                return;
        !           863:        }
        !           864: 
        !           865:        /* We are in the rebooting state. */
        !           866:        client -> state = S_REBOOTING;
        !           867: 
        !           868:        /*
        !           869:         * make_request doesn't initialize xid because it normally comes
        !           870:         * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
        !           871:         * so pick an xid now.
        !           872:         */
        !           873:        client -> xid = random ();
        !           874: 
        !           875:        /*
        !           876:         * Make a DHCPREQUEST packet, and set
        !           877:         * appropriate per-interface flags.
        !           878:         */
        !           879:        make_request (client, client -> active);
        !           880:        client -> destination = iaddr_broadcast;
        !           881:        client -> first_sending = cur_time;
        !           882:        client -> interval = client -> config -> initial_interval;
        !           883: 
        !           884:        /* Zap the medium list... */
        !           885:        client -> medium = NULL;
        !           886: 
        !           887:        /* Send out the first DHCPREQUEST packet. */
        !           888:        send_request (client);
        !           889: }
        !           890: 
        !           891: /* Called when a lease has completely expired and we've been unable to
        !           892:    renew it. */
        !           893: 
        !           894: void state_init (cpp)
        !           895:        void *cpp;
        !           896: {
        !           897:        struct client_state *client = cpp;
        !           898: 
        !           899:        ASSERT_STATE(state, S_INIT);
        !           900: 
        !           901:        /* Make a DHCPDISCOVER packet, and set appropriate per-interface
        !           902:           flags. */
        !           903:        make_discover (client, client -> active);
        !           904:        client -> xid = client -> packet.xid;
        !           905:        client -> destination = iaddr_broadcast;
        !           906:        client -> state = S_SELECTING;
        !           907:        client -> first_sending = cur_time;
        !           908:        client -> interval = client -> config -> initial_interval;
        !           909: 
        !           910:        /* Add an immediate timeout to cause the first DHCPDISCOVER packet
        !           911:           to go out. */
        !           912:        send_discover (client);
        !           913: }
        !           914: 
        !           915: /*
        !           916:  * state_selecting is called when one or more DHCPOFFER packets have been
        !           917:  * received and a configurable period of time has passed.
        !           918:  */
        !           919: 
        !           920: void state_selecting (cpp)
        !           921:        void *cpp;
        !           922: {
        !           923:        struct client_state *client = cpp;
        !           924:        struct client_lease *lp, *next, *picked;
        !           925: 
        !           926: 
        !           927:        ASSERT_STATE(state, S_SELECTING);
        !           928: 
        !           929:        /*
        !           930:         * Cancel state_selecting and send_discover timeouts, since either
        !           931:         * one could have got us here.
        !           932:         */
        !           933:        cancel_timeout (state_selecting, client);
        !           934:        cancel_timeout (send_discover, client);
        !           935: 
        !           936:        /*
        !           937:         * We have received one or more DHCPOFFER packets.   Currently,
        !           938:         * the only criterion by which we judge leases is whether or
        !           939:         * not we get a response when we arp for them.
        !           940:         */
        !           941:        picked = NULL;
        !           942:        for (lp = client -> offered_leases; lp; lp = next) {
        !           943:                next = lp -> next;
        !           944: 
        !           945:                /*
        !           946:                 * Check to see if we got an ARPREPLY for the address
        !           947:                 * in this particular lease.
        !           948:                 */
        !           949:                if (!picked) {
        !           950:                        picked = lp;
        !           951:                        picked -> next = NULL;
        !           952:                } else {
        !           953:                        destroy_client_lease (lp);
        !           954:                }
        !           955:        }
        !           956:        client -> offered_leases = NULL;
        !           957: 
        !           958:        /*
        !           959:         * If we just tossed all the leases we were offered, go back
        !           960:         * to square one.
        !           961:         */
        !           962:        if (!picked) {
        !           963:                client -> state = S_INIT;
        !           964:                state_init (client);
        !           965:                return;
        !           966:        }
        !           967: 
        !           968:        /* If it was a BOOTREPLY, we can just take the address right now. */
        !           969:        if (picked -> is_bootp) {
        !           970:                client -> new = picked;
        !           971: 
        !           972:                /* Make up some lease expiry times
        !           973:                   XXX these should be configurable. */
        !           974:                client -> new -> expiry = cur_time + 12000;
        !           975:                client -> new -> renewal += cur_time + 8000;
        !           976:                client -> new -> rebind += cur_time + 10000;
        !           977: 
        !           978:                client -> state = S_REQUESTING;
        !           979: 
        !           980:                /* Bind to the address we received. */
        !           981:                bind_lease (client);
        !           982:                return;
        !           983:        }
        !           984: 
        !           985:        /* Go to the REQUESTING state. */
        !           986:        client -> destination = iaddr_broadcast;
        !           987:        client -> state = S_REQUESTING;
        !           988:        client -> first_sending = cur_time;
        !           989:        client -> interval = client -> config -> initial_interval;
        !           990: 
        !           991:        /* Make a DHCPREQUEST packet from the lease we picked. */
        !           992:        make_request (client, picked);
        !           993:        client -> xid = client -> packet.xid;
        !           994: 
        !           995:        /* Toss the lease we picked - we'll get it back in a DHCPACK. */
        !           996:        destroy_client_lease (picked);
        !           997: 
        !           998:        /* Add an immediate timeout to send the first DHCPREQUEST packet. */
        !           999:        send_request (client);
        !          1000: }
        !          1001: 
        !          1002: /* state_requesting is called when we receive a DHCPACK message after
        !          1003:    having sent out one or more DHCPREQUEST packets. */
        !          1004: 
        !          1005: void dhcpack (packet)
        !          1006:        struct packet *packet;
        !          1007: {
        !          1008:        struct interface_info *ip = packet -> interface;
        !          1009:        struct client_state *client;
        !          1010:        struct client_lease *lease;
        !          1011:        struct option_cache *oc;
        !          1012:        struct data_string ds;
        !          1013: 
        !          1014:        /* If we're not receptive to an offer right now, or if the offer
        !          1015:           has an unrecognizable transaction id, then just drop it. */
        !          1016:        for (client = ip -> client; client; client = client -> next) {
        !          1017:                if (client -> xid == packet -> raw -> xid)
        !          1018:                        break;
        !          1019:        }
        !          1020:        if (!client ||
        !          1021:            (packet -> interface -> hw_address.hlen - 1 !=
        !          1022:             packet -> raw -> hlen) ||
        !          1023:            (memcmp (&packet -> interface -> hw_address.hbuf [1],
        !          1024:                     packet -> raw -> chaddr, packet -> raw -> hlen))) {
        !          1025: #if defined (DEBUG)
        !          1026:                log_debug ("DHCPACK in wrong transaction.");
        !          1027: #endif
        !          1028:                return;
        !          1029:        }
        !          1030: 
        !          1031:        if (client -> state != S_REBOOTING &&
        !          1032:            client -> state != S_REQUESTING &&
        !          1033:            client -> state != S_RENEWING &&
        !          1034:            client -> state != S_REBINDING) {
        !          1035: #if defined (DEBUG)
        !          1036:                log_debug ("DHCPACK in wrong state.");
        !          1037: #endif
        !          1038:                return;
        !          1039:        }
        !          1040: 
        !          1041:        log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
        !          1042: 
        !          1043:        lease = packet_to_lease (packet, client);
        !          1044:        if (!lease) {
        !          1045:                log_info ("packet_to_lease failed.");
        !          1046:                return;
        !          1047:        }
        !          1048: 
        !          1049:        client -> new = lease;
        !          1050: 
        !          1051:        /* Stop resending DHCPREQUEST. */
        !          1052:        cancel_timeout (send_request, client);
        !          1053: 
        !          1054:        /* Figure out the lease time. */
        !          1055:        oc = lookup_option (&dhcp_universe, client -> new -> options,
        !          1056:                            DHO_DHCP_LEASE_TIME);
        !          1057:        memset (&ds, 0, sizeof ds);
        !          1058:        if (oc &&
        !          1059:            evaluate_option_cache (&ds, packet, (struct lease *)0, client,
        !          1060:                                   packet -> options, client -> new -> options,
        !          1061:                                   &global_scope, oc, MDL)) {
        !          1062:                if (ds.len > 3)
        !          1063:                        client -> new -> expiry = getULong (ds.data);
        !          1064:                else
        !          1065:                        client -> new -> expiry = 0;
        !          1066:                data_string_forget (&ds, MDL);
        !          1067:        } else
        !          1068:                        client -> new -> expiry = 0;
        !          1069: 
        !          1070:        if (client->new->expiry == 0) {
        !          1071:                struct timeval tv;
        !          1072: 
        !          1073:                log_error ("no expiry time on offered lease.");
        !          1074: 
        !          1075:                /* Quench this (broken) server.  Return to INIT to reselect. */
        !          1076:                add_reject(packet);
        !          1077: 
        !          1078:                /* 1/2 second delay to restart at INIT. */
        !          1079:                tv.tv_sec = cur_tv.tv_sec;
        !          1080:                tv.tv_usec = cur_tv.tv_usec + 500000;
        !          1081: 
        !          1082:                if (tv.tv_usec >= 1000000) {
        !          1083:                        tv.tv_sec++;
        !          1084:                        tv.tv_usec -= 1000000;
        !          1085:                }
        !          1086: 
        !          1087:                add_timeout(&tv, state_init, client, 0, 0);
        !          1088:                return;
        !          1089:        }
        !          1090: 
        !          1091:        /*
        !          1092:         * A number that looks negative here is really just very large,
        !          1093:         * because the lease expiry offset is unsigned.
        !          1094:         */
        !          1095:        if (client->new->expiry < 0)
        !          1096:                client->new->expiry = TIME_MAX;
        !          1097: 
        !          1098:        /* Take the server-provided renewal time if there is one. */
        !          1099:        oc = lookup_option (&dhcp_universe, client -> new -> options,
        !          1100:                            DHO_DHCP_RENEWAL_TIME);
        !          1101:        if (oc &&
        !          1102:            evaluate_option_cache (&ds, packet, (struct lease *)0, client,
        !          1103:                                   packet -> options, client -> new -> options,
        !          1104:                                   &global_scope, oc, MDL)) {
        !          1105:                if (ds.len > 3)
        !          1106:                        client -> new -> renewal = getULong (ds.data);
        !          1107:                else
        !          1108:                        client -> new -> renewal = 0;
        !          1109:                data_string_forget (&ds, MDL);
        !          1110:        } else
        !          1111:                        client -> new -> renewal = 0;
        !          1112: 
        !          1113:        /* If it wasn't specified by the server, calculate it. */
        !          1114:        if (!client -> new -> renewal)
        !          1115:                client -> new -> renewal = client -> new -> expiry / 2 + 1;
        !          1116: 
        !          1117:        if (client -> new -> renewal <= 0)
        !          1118:                client -> new -> renewal = TIME_MAX;
        !          1119: 
        !          1120:        /* Now introduce some randomness to the renewal time: */
        !          1121:        if (client->new->renewal <= ((TIME_MAX / 3) - 3))
        !          1122:                client->new->renewal = (((client->new->renewal * 3) + 3) / 4) +
        !          1123:                                (((random() % client->new->renewal) + 3) / 4);
        !          1124: 
        !          1125:        /* Same deal with the rebind time. */
        !          1126:        oc = lookup_option (&dhcp_universe, client -> new -> options,
        !          1127:                            DHO_DHCP_REBINDING_TIME);
        !          1128:        if (oc &&
        !          1129:            evaluate_option_cache (&ds, packet, (struct lease *)0, client,
        !          1130:                                   packet -> options, client -> new -> options,
        !          1131:                                   &global_scope, oc, MDL)) {
        !          1132:                if (ds.len > 3)
        !          1133:                        client -> new -> rebind = getULong (ds.data);
        !          1134:                else
        !          1135:                        client -> new -> rebind = 0;
        !          1136:                data_string_forget (&ds, MDL);
        !          1137:        } else
        !          1138:                        client -> new -> rebind = 0;
        !          1139: 
        !          1140:        if (client -> new -> rebind <= 0) {
        !          1141:                if (client -> new -> expiry <= TIME_MAX / 7)
        !          1142:                        client -> new -> rebind =
        !          1143:                                        client -> new -> expiry * 7 / 8;
        !          1144:                else
        !          1145:                        client -> new -> rebind =
        !          1146:                                        client -> new -> expiry / 8 * 7;
        !          1147:        }
        !          1148: 
        !          1149:        /* Make sure our randomness didn't run the renewal time past the
        !          1150:           rebind time. */
        !          1151:        if (client -> new -> renewal > client -> new -> rebind) {
        !          1152:                if (client -> new -> rebind <= TIME_MAX / 3)
        !          1153:                        client -> new -> renewal =
        !          1154:                                        client -> new -> rebind * 3 / 4;
        !          1155:                else
        !          1156:                        client -> new -> renewal =
        !          1157:                                        client -> new -> rebind / 4 * 3;
        !          1158:        }
        !          1159: 
        !          1160:        client -> new -> expiry += cur_time;
        !          1161:        /* Lease lengths can never be negative. */
        !          1162:        if (client -> new -> expiry < cur_time)
        !          1163:                client -> new -> expiry = TIME_MAX;
        !          1164:        client -> new -> renewal += cur_time;
        !          1165:        if (client -> new -> renewal < cur_time)
        !          1166:                client -> new -> renewal = TIME_MAX;
        !          1167:        client -> new -> rebind += cur_time;
        !          1168:        if (client -> new -> rebind < cur_time)
        !          1169:                client -> new -> rebind = TIME_MAX;
        !          1170: 
        !          1171:        bind_lease (client);
        !          1172: }
        !          1173: 
        !          1174: void bind_lease (client)
        !          1175:        struct client_state *client;
        !          1176: {
        !          1177:        struct timeval tv;
        !          1178: 
        !          1179:        /* Remember the medium. */
        !          1180:        client -> new -> medium = client -> medium;
        !          1181: 
        !          1182:        /* Run the client script with the new parameters. */
        !          1183:        script_init (client, (client -> state == S_REQUESTING
        !          1184:                          ? "BOUND"
        !          1185:                          : (client -> state == S_RENEWING
        !          1186:                             ? "RENEW"
        !          1187:                             : (client -> state == S_REBOOTING
        !          1188:                                ? "REBOOT" : "REBIND"))),
        !          1189:                     client -> new -> medium);
        !          1190:        if (client -> active && client -> state != S_REBOOTING)
        !          1191:                script_write_params (client, "old_", client -> active);
        !          1192:        script_write_params (client, "new_", client -> new);
        !          1193:        if (client -> alias)
        !          1194:                script_write_params (client, "alias_", client -> alias);
        !          1195: 
        !          1196:        /* If the BOUND/RENEW code detects another machine using the
        !          1197:           offered address, it exits nonzero.  We need to send a
        !          1198:           DHCPDECLINE and toss the lease. */
        !          1199:        if (script_go (client)) {
        !          1200:                make_decline (client, client -> new);
        !          1201:                send_decline (client);
        !          1202:                destroy_client_lease (client -> new);
        !          1203:                client -> new = (struct client_lease *)0;
        !          1204:                state_init (client);
        !          1205:                return;
        !          1206:        }
        !          1207: 
        !          1208:        /* Write out the new lease if it has been long enough. */
        !          1209:        if (!client->last_write ||
        !          1210:            (cur_time - client->last_write) >= MIN_LEASE_WRITE)
        !          1211:                write_client_lease(client, client->new, 0, 0);
        !          1212: 
        !          1213:        /* Replace the old active lease with the new one. */
        !          1214:        if (client -> active)
        !          1215:                destroy_client_lease (client -> active);
        !          1216:        client -> active = client -> new;
        !          1217:        client -> new = (struct client_lease *)0;
        !          1218: 
        !          1219:        /* Set up a timeout to start the renewal process. */
        !          1220:        tv.tv_sec = client->active->renewal;
        !          1221:        tv.tv_usec = ((client->active->renewal - cur_tv.tv_sec) > 1) ?
        !          1222:                        random() % 1000000 : cur_tv.tv_usec;
        !          1223:        add_timeout(&tv, state_bound, client, 0, 0);
        !          1224: 
        !          1225:        log_info ("bound to %s -- renewal in %ld seconds.",
        !          1226:              piaddr (client -> active -> address),
        !          1227:              (long)(client -> active -> renewal - cur_time));
        !          1228:        client -> state = S_BOUND;
        !          1229:        reinitialize_interfaces ();
        !          1230:        go_daemon ();
        !          1231:        if (client->config->do_forward_update)
        !          1232:                dhclient_schedule_updates(client, &client->active->address,
        !          1233:                                          1);
        !          1234: }
        !          1235: 
        !          1236: /* state_bound is called when we've successfully bound to a particular
        !          1237:    lease, but the renewal time on that lease has expired.   We are
        !          1238:    expected to unicast a DHCPREQUEST to the server that gave us our
        !          1239:    original lease. */
        !          1240: 
        !          1241: void state_bound (cpp)
        !          1242:        void *cpp;
        !          1243: {
        !          1244:        struct client_state *client = cpp;
        !          1245:        struct option_cache *oc;
        !          1246:        struct data_string ds;
        !          1247: 
        !          1248:        ASSERT_STATE(state, S_BOUND);
        !          1249: 
        !          1250:        /* T1 has expired. */
        !          1251:        make_request (client, client -> active);
        !          1252:        client -> xid = client -> packet.xid;
        !          1253: 
        !          1254:        memset (&ds, 0, sizeof ds);
        !          1255:        oc = lookup_option (&dhcp_universe, client -> active -> options,
        !          1256:                            DHO_DHCP_SERVER_IDENTIFIER);
        !          1257:        if (oc &&
        !          1258:            evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
        !          1259:                                   client, (struct option_state *)0,
        !          1260:                                   client -> active -> options,
        !          1261:                                   &global_scope, oc, MDL)) {
        !          1262:                if (ds.len > 3) {
        !          1263:                        memcpy (client -> destination.iabuf, ds.data, 4);
        !          1264:                        client -> destination.len = 4;
        !          1265:                } else
        !          1266:                        client -> destination = iaddr_broadcast;
        !          1267: 
        !          1268:                data_string_forget (&ds, MDL);
        !          1269:        } else
        !          1270:                client -> destination = iaddr_broadcast;
        !          1271: 
        !          1272:        client -> first_sending = cur_time;
        !          1273:        client -> interval = client -> config -> initial_interval;
        !          1274:        client -> state = S_RENEWING;
        !          1275: 
        !          1276:        /* Send the first packet immediately. */
        !          1277:        send_request (client);
        !          1278: }
        !          1279: 
        !          1280: /* state_stop is called when we've been told to shut down.   We unconfigure
        !          1281:    the interfaces, and then stop operating until told otherwise. */
        !          1282: 
        !          1283: void state_stop (cpp)
        !          1284:        void *cpp;
        !          1285: {
        !          1286:        struct client_state *client = cpp;
        !          1287: 
        !          1288:        /* Cancel all timeouts. */
        !          1289:        cancel_timeout(state_selecting, client);
        !          1290:        cancel_timeout(send_discover, client);
        !          1291:        cancel_timeout(send_request, client);
        !          1292:        cancel_timeout(state_bound, client);
        !          1293: 
        !          1294:        /* If we have an address, unconfigure it. */
        !          1295:        if (client->active) {
        !          1296:                script_init(client, "STOP", client->active->medium);
        !          1297:                script_write_params(client, "old_", client->active);
        !          1298:                if (client->alias)
        !          1299:                        script_write_params(client, "alias_", client->alias);
        !          1300:                script_go(client);
        !          1301:        }
        !          1302: }
        !          1303: 
        !          1304: int commit_leases ()
        !          1305: {
        !          1306:        return 0;
        !          1307: }
        !          1308: 
        !          1309: int write_lease (lease)
        !          1310:        struct lease *lease;
        !          1311: {
        !          1312:        return 0;
        !          1313: }
        !          1314: 
        !          1315: int write_host (host)
        !          1316:        struct host_decl *host;
        !          1317: {
        !          1318:        return 0;
        !          1319: }
        !          1320: 
        !          1321: void db_startup (testp)
        !          1322:        int testp;
        !          1323: {
        !          1324: }
        !          1325: 
        !          1326: void bootp (packet)
        !          1327:        struct packet *packet;
        !          1328: {
        !          1329:        struct iaddrmatchlist *ap;
        !          1330:        char addrbuf[4*16];
        !          1331:        char maskbuf[4*16];
        !          1332: 
        !          1333:        if (packet -> raw -> op != BOOTREPLY)
        !          1334:                return;
        !          1335: 
        !          1336:        /* If there's a reject list, make sure this packet's sender isn't
        !          1337:           on it. */
        !          1338:        for (ap = packet -> interface -> client -> config -> reject_list;
        !          1339:             ap; ap = ap -> next) {
        !          1340:                if (addr_match(&packet->client_addr, &ap->match)) {
        !          1341: 
        !          1342:                        /* piaddr() returns its result in a static
        !          1343:                           buffer sized 4*16 (see common/inet.c). */
        !          1344: 
        !          1345:                        strcpy(addrbuf, piaddr(ap->match.addr));
        !          1346:                        strcpy(maskbuf, piaddr(ap->match.mask));
        !          1347: 
        !          1348:                        log_info("BOOTREPLY from %s rejected by rule %s "
        !          1349:                                 "mask %s.", piaddr(packet->client_addr),
        !          1350:                                 addrbuf, maskbuf);
        !          1351:                        return;
        !          1352:                }
        !          1353:        }
        !          1354: 
        !          1355:        dhcpoffer (packet);
        !          1356: 
        !          1357: }
        !          1358: 
        !          1359: void dhcp (packet)
        !          1360:        struct packet *packet;
        !          1361: {
        !          1362:        struct iaddrmatchlist *ap;
        !          1363:        void (*handler) (struct packet *);
        !          1364:        const char *type;
        !          1365:        char addrbuf[4*16];
        !          1366:        char maskbuf[4*16];
        !          1367: 
        !          1368:        switch (packet -> packet_type) {
        !          1369:              case DHCPOFFER:
        !          1370:                handler = dhcpoffer;
        !          1371:                type = "DHCPOFFER";
        !          1372:                break;
        !          1373: 
        !          1374:              case DHCPNAK:
        !          1375:                handler = dhcpnak;
        !          1376:                type = "DHCPNACK";
        !          1377:                break;
        !          1378: 
        !          1379:              case DHCPACK:
        !          1380:                handler = dhcpack;
        !          1381:                type = "DHCPACK";
        !          1382:                break;
        !          1383: 
        !          1384:              default:
        !          1385:                return;
        !          1386:        }
        !          1387: 
        !          1388:        /* If there's a reject list, make sure this packet's sender isn't
        !          1389:           on it. */
        !          1390:        for (ap = packet -> interface -> client -> config -> reject_list;
        !          1391:             ap; ap = ap -> next) {
        !          1392:                if (addr_match(&packet->client_addr, &ap->match)) {
        !          1393: 
        !          1394:                        /* piaddr() returns its result in a static
        !          1395:                           buffer sized 4*16 (see common/inet.c). */
        !          1396: 
        !          1397:                        strcpy(addrbuf, piaddr(ap->match.addr));
        !          1398:                        strcpy(maskbuf, piaddr(ap->match.mask));
        !          1399: 
        !          1400:                        log_info("%s from %s rejected by rule %s mask %s.",
        !          1401:                                 type, piaddr(packet->client_addr),
        !          1402:                                 addrbuf, maskbuf);
        !          1403:                        return;
        !          1404:                }
        !          1405:        }
        !          1406:        (*handler) (packet);
        !          1407: }
        !          1408: 
        !          1409: #ifdef DHCPv6
        !          1410: void
        !          1411: dhcpv6(struct packet *packet) {
        !          1412:        struct iaddrmatchlist *ap;
        !          1413:        struct client_state *client;
        !          1414:        char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
        !          1415: 
        !          1416:        /* Silently drop bogus messages. */
        !          1417:        if (packet->dhcpv6_msg_type >= dhcpv6_type_name_max)
        !          1418:                return;
        !          1419: 
        !          1420:        /* Discard, with log, packets from quenched sources. */
        !          1421:        for (ap = packet->interface->client->config->reject_list ;
        !          1422:             ap ; ap = ap->next) {
        !          1423:                if (addr_match(&packet->client_addr, &ap->match)) {
        !          1424:                        strcpy(addrbuf, piaddr(packet->client_addr));
        !          1425:                        log_info("%s from %s rejected by rule %s",
        !          1426:                                 dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          1427:                                 addrbuf,
        !          1428:                                 piaddrmask(&ap->match.addr, &ap->match.mask));
        !          1429:                        return;
        !          1430:                }
        !          1431:        }
        !          1432: 
        !          1433:        /* Screen out nonsensical messages. */
        !          1434:        switch(packet->dhcpv6_msg_type) {
        !          1435:              case DHCPV6_ADVERTISE:
        !          1436:              case DHCPV6_RECONFIGURE:
        !          1437:                if (stateless)
        !          1438:                  return;
        !          1439:              /* Falls through */
        !          1440:              case DHCPV6_REPLY:
        !          1441:                log_info("RCV: %s message on %s from %s.",
        !          1442:                         dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          1443:                         packet->interface->name, piaddr(packet->client_addr));
        !          1444:                break;
        !          1445: 
        !          1446:              default:
        !          1447:                return;
        !          1448:        }
        !          1449: 
        !          1450:        /* Find a client state that matches the incoming XID. */
        !          1451:        for (client = packet->interface->client ; client ;
        !          1452:             client = client->next) {
        !          1453:                if (memcmp(&client->dhcpv6_transaction_id,
        !          1454:                           packet->dhcpv6_transaction_id, 3) == 0) {
        !          1455:                        client->v6_handler(packet, client);
        !          1456:                        return;
        !          1457:                }
        !          1458:        }
        !          1459: 
        !          1460:        /* XXX: temporary log for debugging */
        !          1461:        log_info("Packet received, but nothing done with it.");
        !          1462: }
        !          1463: #endif /* DHCPv6 */
        !          1464: 
        !          1465: void dhcpoffer (packet)
        !          1466:        struct packet *packet;
        !          1467: {
        !          1468:        struct interface_info *ip = packet -> interface;
        !          1469:        struct client_state *client;
        !          1470:        struct client_lease *lease, *lp;
        !          1471:        struct option **req;
        !          1472:        int i;
        !          1473:        int stop_selecting;
        !          1474:        const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
        !          1475:        char obuf [1024];
        !          1476:        struct timeval tv;
        !          1477: 
        !          1478: #ifdef DEBUG_PACKET
        !          1479:        dump_packet (packet);
        !          1480: #endif
        !          1481: 
        !          1482:        /* Find a client state that matches the xid... */
        !          1483:        for (client = ip -> client; client; client = client -> next)
        !          1484:                if (client -> xid == packet -> raw -> xid)
        !          1485:                        break;
        !          1486: 
        !          1487:        /* If we're not receptive to an offer right now, or if the offer
        !          1488:           has an unrecognizable transaction id, then just drop it. */
        !          1489:        if (!client ||
        !          1490:            client -> state != S_SELECTING ||
        !          1491:            (packet -> interface -> hw_address.hlen - 1 !=
        !          1492:             packet -> raw -> hlen) ||
        !          1493:            (memcmp (&packet -> interface -> hw_address.hbuf [1],
        !          1494:                     packet -> raw -> chaddr, packet -> raw -> hlen))) {
        !          1495: #if defined (DEBUG)
        !          1496:                log_debug ("%s in wrong transaction.", name);
        !          1497: #endif
        !          1498:                return;
        !          1499:        }
        !          1500: 
        !          1501:        sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
        !          1502: 
        !          1503: 
        !          1504:        /* If this lease doesn't supply the minimum required DHCPv4 parameters,
        !          1505:         * ignore it.
        !          1506:         */
        !          1507:        req = client->config->required_options;
        !          1508:        if (req != NULL) {
        !          1509:                for (i = 0 ; req[i] != NULL ; i++) {
        !          1510:                        if ((req[i]->universe == &dhcp_universe) &&
        !          1511:                            !lookup_option(&dhcp_universe, packet->options,
        !          1512:                                           req[i]->code)) {
        !          1513:                                struct option *option = NULL;
        !          1514:                                unsigned code = req[i]->code;
        !          1515: 
        !          1516:                                option_code_hash_lookup(&option,
        !          1517:                                                        dhcp_universe.code_hash,
        !          1518:                                                        &code, 0, MDL);
        !          1519: 
        !          1520:                                if (option)
        !          1521:                                        log_info("%s: no %s option.", obuf,
        !          1522:                                                 option->name);
        !          1523:                                else
        !          1524:                                        log_info("%s: no unknown-%u option.",
        !          1525:                                                 obuf, code);
        !          1526: 
        !          1527:                                option_dereference(&option, MDL);
        !          1528: 
        !          1529:                                return;
        !          1530:                        }
        !          1531:                }
        !          1532:        }
        !          1533: 
        !          1534:        /* If we've already seen this lease, don't record it again. */
        !          1535:        for (lease = client -> offered_leases; lease; lease = lease -> next) {
        !          1536:                if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
        !          1537:                    !memcmp (lease -> address.iabuf,
        !          1538:                             &packet -> raw -> yiaddr, lease -> address.len)) {
        !          1539:                        log_debug ("%s: already seen.", obuf);
        !          1540:                        return;
        !          1541:                }
        !          1542:        }
        !          1543: 
        !          1544:        lease = packet_to_lease (packet, client);
        !          1545:        if (!lease) {
        !          1546:                log_info ("%s: packet_to_lease failed.", obuf);
        !          1547:                return;
        !          1548:        }
        !          1549: 
        !          1550:        /* If this lease was acquired through a BOOTREPLY, record that
        !          1551:           fact. */
        !          1552:        if (!packet -> options_valid || !packet -> packet_type)
        !          1553:                lease -> is_bootp = 1;
        !          1554: 
        !          1555:        /* Record the medium under which this lease was offered. */
        !          1556:        lease -> medium = client -> medium;
        !          1557: 
        !          1558:        /* Figure out when we're supposed to stop selecting. */
        !          1559:        stop_selecting = (client -> first_sending +
        !          1560:                          client -> config -> select_interval);
        !          1561: 
        !          1562:        /* If this is the lease we asked for, put it at the head of the
        !          1563:           list, and don't mess with the arp request timeout. */
        !          1564:        if (lease -> address.len == client -> requested_address.len &&
        !          1565:            !memcmp (lease -> address.iabuf,
        !          1566:                     client -> requested_address.iabuf,
        !          1567:                     client -> requested_address.len)) {
        !          1568:                lease -> next = client -> offered_leases;
        !          1569:                client -> offered_leases = lease;
        !          1570:        } else {
        !          1571:                /* Put the lease at the end of the list. */
        !          1572:                lease -> next = (struct client_lease *)0;
        !          1573:                if (!client -> offered_leases)
        !          1574:                        client -> offered_leases = lease;
        !          1575:                else {
        !          1576:                        for (lp = client -> offered_leases; lp -> next;
        !          1577:                             lp = lp -> next)
        !          1578:                                ;
        !          1579:                        lp -> next = lease;
        !          1580:                }
        !          1581:        }
        !          1582: 
        !          1583:        /* If the selecting interval has expired, go immediately to
        !          1584:           state_selecting().  Otherwise, time out into
        !          1585:           state_selecting at the select interval. */
        !          1586:        if (stop_selecting <= cur_tv.tv_sec)
        !          1587:                state_selecting (client);
        !          1588:        else {
        !          1589:                tv.tv_sec = stop_selecting;
        !          1590:                tv.tv_usec = cur_tv.tv_usec;
        !          1591:                add_timeout(&tv, state_selecting, client, 0, 0);
        !          1592:                cancel_timeout(send_discover, client);
        !          1593:        }
        !          1594:        log_info("%s", obuf);
        !          1595: }
        !          1596: 
        !          1597: /* Allocate a client_lease structure and initialize it from the parameters
        !          1598:    in the specified packet. */
        !          1599: 
        !          1600: struct client_lease *packet_to_lease (packet, client)
        !          1601:        struct packet *packet;
        !          1602:        struct client_state *client;
        !          1603: {
        !          1604:        struct client_lease *lease;
        !          1605:        unsigned i;
        !          1606:        struct option_cache *oc;
        !          1607:        struct option *option = NULL;
        !          1608:        struct data_string data;
        !          1609: 
        !          1610:        lease = (struct client_lease *)new_client_lease (MDL);
        !          1611: 
        !          1612:        if (!lease) {
        !          1613:                log_error ("packet_to_lease: no memory to record lease.\n");
        !          1614:                return (struct client_lease *)0;
        !          1615:        }
        !          1616: 
        !          1617:        memset (lease, 0, sizeof *lease);
        !          1618: 
        !          1619:        /* Copy the lease options. */
        !          1620:        option_state_reference (&lease -> options, packet -> options, MDL);
        !          1621: 
        !          1622:        lease -> address.len = sizeof (packet -> raw -> yiaddr);
        !          1623:        memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
        !          1624:                lease -> address.len);
        !          1625: 
        !          1626:        memset (&data, 0, sizeof data);
        !          1627: 
        !          1628:        if (client -> config -> vendor_space_name) {
        !          1629:                i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
        !          1630: 
        !          1631:                /* See if there was a vendor encapsulation option. */
        !          1632:                oc = lookup_option (&dhcp_universe, lease -> options, i);
        !          1633:                if (oc &&
        !          1634:                    client -> config -> vendor_space_name &&
        !          1635:                    evaluate_option_cache (&data, packet,
        !          1636:                                           (struct lease *)0, client,
        !          1637:                                           packet -> options, lease -> options,
        !          1638:                                           &global_scope, oc, MDL)) {
        !          1639:                        if (data.len) {
        !          1640:                                if (!option_code_hash_lookup(&option,
        !          1641:                                                dhcp_universe.code_hash,
        !          1642:                                                &i, 0, MDL))
        !          1643:                                        log_fatal("Unable to find VENDOR "
        !          1644:                                                  "option (%s:%d).", MDL);
        !          1645:                                parse_encapsulated_suboptions
        !          1646:                                        (packet -> options, option,
        !          1647:                                         data.data, data.len, &dhcp_universe,
        !          1648:                                         client -> config -> vendor_space_name
        !          1649:                                                );
        !          1650: 
        !          1651:                                option_dereference(&option, MDL);
        !          1652:                        }
        !          1653:                        data_string_forget (&data, MDL);
        !          1654:                }
        !          1655:        } else
        !          1656:                i = 0;
        !          1657: 
        !          1658:        /* Figure out the overload flag. */
        !          1659:        oc = lookup_option (&dhcp_universe, lease -> options,
        !          1660:                            DHO_DHCP_OPTION_OVERLOAD);
        !          1661:        if (oc &&
        !          1662:            evaluate_option_cache (&data, packet, (struct lease *)0, client,
        !          1663:                                   packet -> options, lease -> options,
        !          1664:                                   &global_scope, oc, MDL)) {
        !          1665:                if (data.len > 0)
        !          1666:                        i = data.data [0];
        !          1667:                else
        !          1668:                        i = 0;
        !          1669:                data_string_forget (&data, MDL);
        !          1670:        } else
        !          1671:                i = 0;
        !          1672: 
        !          1673:        /* If the server name was filled out, copy it. */
        !          1674:        if (!(i & 2) && packet -> raw -> sname [0]) {
        !          1675:                unsigned len;
        !          1676:                /* Don't count on the NUL terminator. */
        !          1677:                for (len = 0; len < DHCP_SNAME_LEN; len++)
        !          1678:                        if (!packet -> raw -> sname [len])
        !          1679:                                break;
        !          1680:                lease -> server_name = dmalloc (len + 1, MDL);
        !          1681:                if (!lease -> server_name) {
        !          1682:                        log_error ("dhcpoffer: no memory for server name.\n");
        !          1683:                        destroy_client_lease (lease);
        !          1684:                        return (struct client_lease *)0;
        !          1685:                } else {
        !          1686:                        memcpy (lease -> server_name,
        !          1687:                                packet -> raw -> sname, len);
        !          1688:                        lease -> server_name [len] = 0;
        !          1689:                }
        !          1690:        }
        !          1691: 
        !          1692:        /* Ditto for the filename. */
        !          1693:        if (!(i & 1) && packet -> raw -> file [0]) {
        !          1694:                unsigned len;
        !          1695:                /* Don't count on the NUL terminator. */
        !          1696:                for (len = 0; len < DHCP_FILE_LEN; len++)
        !          1697:                        if (!packet -> raw -> file [len])
        !          1698:                                break;
        !          1699:                lease -> filename = dmalloc (len + 1, MDL);
        !          1700:                if (!lease -> filename) {
        !          1701:                        log_error ("dhcpoffer: no memory for filename.\n");
        !          1702:                        destroy_client_lease (lease);
        !          1703:                        return (struct client_lease *)0;
        !          1704:                } else {
        !          1705:                        memcpy (lease -> filename,
        !          1706:                                packet -> raw -> file, len);
        !          1707:                        lease -> filename [len] = 0;
        !          1708:                }
        !          1709:        }
        !          1710: 
        !          1711:        execute_statements_in_scope ((struct binding_value **)0,
        !          1712:                                     (struct packet *)packet,
        !          1713:                                     (struct lease *)0, client,
        !          1714:                                     lease -> options, lease -> options,
        !          1715:                                     &global_scope,
        !          1716:                                     client -> config -> on_receipt,
        !          1717:                                     (struct group *)0);
        !          1718: 
        !          1719:        return lease;
        !          1720: }
        !          1721: 
        !          1722: void dhcpnak (packet)
        !          1723:        struct packet *packet;
        !          1724: {
        !          1725:        struct interface_info *ip = packet -> interface;
        !          1726:        struct client_state *client;
        !          1727: 
        !          1728:        /* Find a client state that matches the xid... */
        !          1729:        for (client = ip -> client; client; client = client -> next)
        !          1730:                if (client -> xid == packet -> raw -> xid)
        !          1731:                        break;
        !          1732: 
        !          1733:        /* If we're not receptive to an offer right now, or if the offer
        !          1734:           has an unrecognizable transaction id, then just drop it. */
        !          1735:        if (!client ||
        !          1736:            (packet -> interface -> hw_address.hlen - 1 !=
        !          1737:             packet -> raw -> hlen) ||
        !          1738:            (memcmp (&packet -> interface -> hw_address.hbuf [1],
        !          1739:                     packet -> raw -> chaddr, packet -> raw -> hlen))) {
        !          1740: #if defined (DEBUG)
        !          1741:                log_debug ("DHCPNAK in wrong transaction.");
        !          1742: #endif
        !          1743:                return;
        !          1744:        }
        !          1745: 
        !          1746:        if (client -> state != S_REBOOTING &&
        !          1747:            client -> state != S_REQUESTING &&
        !          1748:            client -> state != S_RENEWING &&
        !          1749:            client -> state != S_REBINDING) {
        !          1750: #if defined (DEBUG)
        !          1751:                log_debug ("DHCPNAK in wrong state.");
        !          1752: #endif
        !          1753:                return;
        !          1754:        }
        !          1755: 
        !          1756:        log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
        !          1757: 
        !          1758:        if (!client -> active) {
        !          1759: #if defined (DEBUG)
        !          1760:                log_info ("DHCPNAK with no active lease.\n");
        !          1761: #endif
        !          1762:                return;
        !          1763:        }
        !          1764: 
        !          1765:        /* If we get a DHCPNAK, we use the EXPIRE dhclient-script state
        !          1766:         * to indicate that we want all old bindings to be removed.  (It
        !          1767:         * is possible that we may get a NAK while in the RENEW state,
        !          1768:         * so we might have bindings active at that time)
        !          1769:         */
        !          1770:        script_init(client, "EXPIRE", NULL);
        !          1771:        script_write_params(client, "old_", client->active);
        !          1772:        if (client->alias)
        !          1773:                script_write_params(client, "alias_", client->alias);
        !          1774:        script_go(client);
        !          1775: 
        !          1776:        destroy_client_lease (client -> active);
        !          1777:        client -> active = (struct client_lease *)0;
        !          1778: 
        !          1779:        /* Stop sending DHCPREQUEST packets... */
        !          1780:        cancel_timeout (send_request, client);
        !          1781: 
        !          1782:        /* On some scripts, 'EXPIRE' causes the interface to be ifconfig'd
        !          1783:         * down (this expunges any routes and arp cache).  This makes the
        !          1784:         * interface unusable by state_init(), which we call next.  So, we
        !          1785:         * need to 'PREINIT' the interface to bring it back up.
        !          1786:         */
        !          1787:        script_init(client, "PREINIT", NULL);
        !          1788:        if (client->alias)
        !          1789:                script_write_params(client, "alias_", client->alias);
        !          1790:        script_go(client);
        !          1791: 
        !          1792:        client -> state = S_INIT;
        !          1793:        state_init (client);
        !          1794: }
        !          1795: 
        !          1796: /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
        !          1797:    one after the right interval has expired.  If we don't get an offer by
        !          1798:    the time we reach the panic interval, call the panic function. */
        !          1799: 
        !          1800: void send_discover (cpp)
        !          1801:        void *cpp;
        !          1802: {
        !          1803:        struct client_state *client = cpp;
        !          1804: 
        !          1805:        int result;
        !          1806:        int interval;
        !          1807:        int increase = 1;
        !          1808:        struct timeval tv;
        !          1809: 
        !          1810:        /* Figure out how long it's been since we started transmitting. */
        !          1811:        interval = cur_time - client -> first_sending;
        !          1812: 
        !          1813:        /* If we're past the panic timeout, call the script and tell it
        !          1814:           we haven't found anything for this interface yet. */
        !          1815:        if (interval > client -> config -> timeout) {
        !          1816:                state_panic (client);
        !          1817:                return;
        !          1818:        }
        !          1819: 
        !          1820:        /* If we're selecting media, try the whole list before doing
        !          1821:           the exponential backoff, but if we've already received an
        !          1822:           offer, stop looping, because we obviously have it right. */
        !          1823:        if (!client -> offered_leases &&
        !          1824:            client -> config -> media) {
        !          1825:                int fail = 0;
        !          1826:              again:
        !          1827:                if (client -> medium) {
        !          1828:                        client -> medium = client -> medium -> next;
        !          1829:                        increase = 0;
        !          1830:                }
        !          1831:                if (!client -> medium) {
        !          1832:                        if (fail)
        !          1833:                                log_fatal ("No valid media types for %s!",
        !          1834:                                       client -> interface -> name);
        !          1835:                        client -> medium =
        !          1836:                                client -> config -> media;
        !          1837:                        increase = 1;
        !          1838:                }
        !          1839: 
        !          1840:                log_info ("Trying medium \"%s\" %d",
        !          1841:                          client -> medium -> string, increase);
        !          1842:                script_init (client, "MEDIUM", client -> medium);
        !          1843:                if (script_go (client)) {
        !          1844:                        fail = 1;
        !          1845:                        goto again;
        !          1846:                }
        !          1847:        }
        !          1848: 
        !          1849:        /* If we're supposed to increase the interval, do so.  If it's
        !          1850:           currently zero (i.e., we haven't sent any packets yet), set
        !          1851:           it to initial_interval; otherwise, add to it a random number
        !          1852:           between zero and two times itself.  On average, this means
        !          1853:           that it will double with every transmission. */
        !          1854:        if (increase) {
        !          1855:                if (!client->interval)
        !          1856:                        client->interval = client->config->initial_interval;
        !          1857:                else
        !          1858:                        client->interval += random() % (2 * client->interval);
        !          1859: 
        !          1860:                /* Don't backoff past cutoff. */
        !          1861:                if (client->interval > client->config->backoff_cutoff)
        !          1862:                        client->interval = (client->config->backoff_cutoff / 2)
        !          1863:                                 + (random() % client->config->backoff_cutoff);
        !          1864:        } else if (!client->interval)
        !          1865:                client->interval = client->config->initial_interval;
        !          1866: 
        !          1867:        /* If the backoff would take us to the panic timeout, just use that
        !          1868:           as the interval. */
        !          1869:        if (cur_time + client -> interval >
        !          1870:            client -> first_sending + client -> config -> timeout)
        !          1871:                client -> interval =
        !          1872:                        (client -> first_sending +
        !          1873:                         client -> config -> timeout) - cur_time + 1;
        !          1874: 
        !          1875:        /* Record the number of seconds since we started sending. */
        !          1876:        if (interval < 65536)
        !          1877:                client -> packet.secs = htons (interval);
        !          1878:        else
        !          1879:                client -> packet.secs = htons (65535);
        !          1880:        client -> secs = client -> packet.secs;
        !          1881: 
        !          1882:        log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
        !          1883:              client -> name ? client -> name : client -> interface -> name,
        !          1884:              inet_ntoa (sockaddr_broadcast.sin_addr),
        !          1885:              ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
        !          1886: 
        !          1887:        /* Send out a packet. */
        !          1888:        result = send_packet (client -> interface, (struct packet *)0,
        !          1889:                              &client -> packet,
        !          1890:                              client -> packet_length,
        !          1891:                              inaddr_any, &sockaddr_broadcast,
        !          1892:                              (struct hardware *)0);
        !          1893: 
        !          1894:        /*
        !          1895:         * If we used 0 microseconds here, and there were other clients on the
        !          1896:         * same network with a synchronized local clock (ntp), and a similar
        !          1897:         * zero-microsecond-scheduler behavior, then we could be participating
        !          1898:         * in a sub-second DOS ttck.
        !          1899:         */
        !          1900:        tv.tv_sec = cur_tv.tv_sec + client->interval;
        !          1901:        tv.tv_usec = client->interval > 1 ? random() % 1000000 : cur_tv.tv_usec;
        !          1902:        add_timeout(&tv, send_discover, client, 0, 0);
        !          1903: }
        !          1904: 
        !          1905: /* state_panic gets called if we haven't received any offers in a preset
        !          1906:    amount of time.   When this happens, we try to use existing leases that
        !          1907:    haven't yet expired, and failing that, we call the client script and
        !          1908:    hope it can do something. */
        !          1909: 
        !          1910: void state_panic (cpp)
        !          1911:        void *cpp;
        !          1912: {
        !          1913:        struct client_state *client = cpp;
        !          1914:        struct client_lease *loop;
        !          1915:        struct client_lease *lp;
        !          1916:        struct timeval tv;
        !          1917: 
        !          1918:        loop = lp = client -> active;
        !          1919: 
        !          1920:        log_info ("No DHCPOFFERS received.");
        !          1921: 
        !          1922:        /* We may not have an active lease, but we may have some
        !          1923:           predefined leases that we can try. */
        !          1924:        if (!client -> active && client -> leases)
        !          1925:                goto activate_next;
        !          1926: 
        !          1927:        /* Run through the list of leases and see if one can be used. */
        !          1928:        while (client -> active) {
        !          1929:                if (client -> active -> expiry > cur_time) {
        !          1930:                        log_info ("Trying recorded lease %s",
        !          1931:                              piaddr (client -> active -> address));
        !          1932:                        /* Run the client script with the existing
        !          1933:                           parameters. */
        !          1934:                        script_init (client, "TIMEOUT",
        !          1935:                                     client -> active -> medium);
        !          1936:                        script_write_params (client, "new_", client -> active);
        !          1937:                        if (client -> alias)
        !          1938:                                script_write_params (client, "alias_",
        !          1939:                                                     client -> alias);
        !          1940: 
        !          1941:                        /* If the old lease is still good and doesn't
        !          1942:                           yet need renewal, go into BOUND state and
        !          1943:                           timeout at the renewal time. */
        !          1944:                        if (!script_go (client)) {
        !          1945:                            if (cur_time < client -> active -> renewal) {
        !          1946:                                client -> state = S_BOUND;
        !          1947:                                log_info ("bound: renewal in %ld %s.",
        !          1948:                                          (long)(client -> active -> renewal -
        !          1949:                                                 cur_time), "seconds");
        !          1950:                                tv.tv_sec = client->active->renewal;
        !          1951:                                tv.tv_usec = ((client->active->renewal -
        !          1952:                                                    cur_time) > 1) ?
        !          1953:                                                random() % 1000000 :
        !          1954:                                                cur_tv.tv_usec;
        !          1955:                                add_timeout(&tv, state_bound, client, 0, 0);
        !          1956:                            } else {
        !          1957:                                client -> state = S_BOUND;
        !          1958:                                log_info ("bound: immediate renewal.");
        !          1959:                                state_bound (client);
        !          1960:                            }
        !          1961:                            reinitialize_interfaces ();
        !          1962:                            go_daemon ();
        !          1963:                            return;
        !          1964:                        }
        !          1965:                }
        !          1966: 
        !          1967:                /* If there are no other leases, give up. */
        !          1968:                if (!client -> leases) {
        !          1969:                        client -> leases = client -> active;
        !          1970:                        client -> active = (struct client_lease *)0;
        !          1971:                        break;
        !          1972:                }
        !          1973: 
        !          1974:        activate_next:
        !          1975:                /* Otherwise, put the active lease at the end of the
        !          1976:                   lease list, and try another lease.. */
        !          1977:                for (lp = client -> leases; lp -> next; lp = lp -> next)
        !          1978:                        ;
        !          1979:                lp -> next = client -> active;
        !          1980:                if (lp -> next) {
        !          1981:                        lp -> next -> next = (struct client_lease *)0;
        !          1982:                }
        !          1983:                client -> active = client -> leases;
        !          1984:                client -> leases = client -> leases -> next;
        !          1985: 
        !          1986:                /* If we already tried this lease, we've exhausted the
        !          1987:                   set of leases, so we might as well give up for
        !          1988:                   now. */
        !          1989:                if (client -> active == loop)
        !          1990:                        break;
        !          1991:                else if (!loop)
        !          1992:                        loop = client -> active;
        !          1993:        }
        !          1994: 
        !          1995:        /* No leases were available, or what was available didn't work, so
        !          1996:           tell the shell script that we failed to allocate an address,
        !          1997:           and try again later. */
        !          1998:        if (onetry) {
        !          1999:                if (!quiet)
        !          2000:                        log_info ("Unable to obtain a lease on first try.%s",
        !          2001:                                  "  Exiting.");
        !          2002:                exit (2);
        !          2003:        }
        !          2004: 
        !          2005:        log_info ("No working leases in persistent database - sleeping.");
        !          2006:        script_init (client, "FAIL", (struct string_list *)0);
        !          2007:        if (client -> alias)
        !          2008:                script_write_params (client, "alias_", client -> alias);
        !          2009:        script_go (client);
        !          2010:        client -> state = S_INIT;
        !          2011:        tv.tv_sec = cur_tv.tv_sec + ((client->config->retry_interval + 1) / 2 +
        !          2012:                    (random() % client->config->retry_interval));
        !          2013:        tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
        !          2014:                        random() % 1000000 : cur_tv.tv_usec;
        !          2015:        add_timeout(&tv, state_init, client, 0, 0);
        !          2016:        go_daemon ();
        !          2017: }
        !          2018: 
        !          2019: void send_request (cpp)
        !          2020:        void *cpp;
        !          2021: {
        !          2022:        struct client_state *client = cpp;
        !          2023: 
        !          2024:        int result;
        !          2025:        int interval;
        !          2026:        struct sockaddr_in destination;
        !          2027:        struct in_addr from;
        !          2028:        struct timeval tv;
        !          2029: 
        !          2030:        /* Figure out how long it's been since we started transmitting. */
        !          2031:        interval = cur_time - client -> first_sending;
        !          2032: 
        !          2033:        /* If we're in the INIT-REBOOT or REQUESTING state and we're
        !          2034:           past the reboot timeout, go to INIT and see if we can
        !          2035:           DISCOVER an address... */
        !          2036:        /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
        !          2037:           means either that we're on a network with no DHCP server,
        !          2038:           or that our server is down.  In the latter case, assuming
        !          2039:           that there is a backup DHCP server, DHCPDISCOVER will get
        !          2040:           us a new address, but we could also have successfully
        !          2041:           reused our old address.  In the former case, we're hosed
        !          2042:           anyway.  This is not a win-prone situation. */
        !          2043:        if ((client -> state == S_REBOOTING ||
        !          2044:             client -> state == S_REQUESTING) &&
        !          2045:            interval > client -> config -> reboot_timeout) {
        !          2046:        cancel:
        !          2047:                client -> state = S_INIT;
        !          2048:                cancel_timeout (send_request, client);
        !          2049:                state_init (client);
        !          2050:                return;
        !          2051:        }
        !          2052: 
        !          2053:        /* If we're in the reboot state, make sure the media is set up
        !          2054:           correctly. */
        !          2055:        if (client -> state == S_REBOOTING &&
        !          2056:            !client -> medium &&
        !          2057:            client -> active -> medium ) {
        !          2058:                script_init (client, "MEDIUM", client -> active -> medium);
        !          2059: 
        !          2060:                /* If the medium we chose won't fly, go to INIT state. */
        !          2061:                if (script_go (client))
        !          2062:                        goto cancel;
        !          2063: 
        !          2064:                /* Record the medium. */
        !          2065:                client -> medium = client -> active -> medium;
        !          2066:        }
        !          2067: 
        !          2068:        /* If the lease has expired, relinquish the address and go back
        !          2069:           to the INIT state. */
        !          2070:        if (client -> state != S_REQUESTING &&
        !          2071:            cur_time > client -> active -> expiry) {
        !          2072:                /* Run the client script with the new parameters. */
        !          2073:                script_init (client, "EXPIRE", (struct string_list *)0);
        !          2074:                script_write_params (client, "old_", client -> active);
        !          2075:                if (client -> alias)
        !          2076:                        script_write_params (client, "alias_",
        !          2077:                                             client -> alias);
        !          2078:                script_go (client);
        !          2079: 
        !          2080:                /* Now do a preinit on the interface so that we can
        !          2081:                   discover a new address. */
        !          2082:                script_init (client, "PREINIT", (struct string_list *)0);
        !          2083:                if (client -> alias)
        !          2084:                        script_write_params (client, "alias_",
        !          2085:                                             client -> alias);
        !          2086:                script_go (client);
        !          2087: 
        !          2088:                client -> state = S_INIT;
        !          2089:                state_init (client);
        !          2090:                return;
        !          2091:        }
        !          2092: 
        !          2093:        /* Do the exponential backoff... */
        !          2094:        if (!client -> interval)
        !          2095:                client -> interval = client -> config -> initial_interval;
        !          2096:        else {
        !          2097:                client -> interval += ((random () >> 2) %
        !          2098:                                       (2 * client -> interval));
        !          2099:        }
        !          2100: 
        !          2101:        /* Don't backoff past cutoff. */
        !          2102:        if (client -> interval >
        !          2103:            client -> config -> backoff_cutoff)
        !          2104:                client -> interval =
        !          2105:                        ((client -> config -> backoff_cutoff / 2)
        !          2106:                         + ((random () >> 2) %
        !          2107:                                        client -> config -> backoff_cutoff));
        !          2108: 
        !          2109:        /* If the backoff would take us to the expiry time, just set the
        !          2110:           timeout to the expiry time. */
        !          2111:        if (client -> state != S_REQUESTING &&
        !          2112:            cur_time + client -> interval > client -> active -> expiry)
        !          2113:                client -> interval =
        !          2114:                        client -> active -> expiry - cur_time + 1;
        !          2115: 
        !          2116:        /* If the lease T2 time has elapsed, or if we're not yet bound,
        !          2117:           broadcast the DHCPREQUEST rather than unicasting. */
        !          2118:        if (client -> state == S_REQUESTING ||
        !          2119:            client -> state == S_REBOOTING ||
        !          2120:            cur_time > client -> active -> rebind)
        !          2121:                destination.sin_addr = sockaddr_broadcast.sin_addr;
        !          2122:        else
        !          2123:                memcpy (&destination.sin_addr.s_addr,
        !          2124:                        client -> destination.iabuf,
        !          2125:                        sizeof destination.sin_addr.s_addr);
        !          2126:        destination.sin_port = remote_port;
        !          2127:        destination.sin_family = AF_INET;
        !          2128: #ifdef HAVE_SA_LEN
        !          2129:        destination.sin_len = sizeof destination;
        !          2130: #endif
        !          2131: 
        !          2132:        if (client -> state == S_RENEWING ||
        !          2133:            client -> state == S_REBINDING)
        !          2134:                memcpy (&from, client -> active -> address.iabuf,
        !          2135:                        sizeof from);
        !          2136:        else
        !          2137:                from.s_addr = INADDR_ANY;
        !          2138: 
        !          2139:        /* Record the number of seconds since we started sending. */
        !          2140:        if (client -> state == S_REQUESTING)
        !          2141:                client -> packet.secs = client -> secs;
        !          2142:        else {
        !          2143:                if (interval < 65536)
        !          2144:                        client -> packet.secs = htons (interval);
        !          2145:                else
        !          2146:                        client -> packet.secs = htons (65535);
        !          2147:        }
        !          2148: 
        !          2149:        log_info ("DHCPREQUEST on %s to %s port %d",
        !          2150:              client -> name ? client -> name : client -> interface -> name,
        !          2151:              inet_ntoa (destination.sin_addr),
        !          2152:              ntohs (destination.sin_port));
        !          2153: 
        !          2154:        if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
        !          2155:            fallback_interface)
        !          2156:                result = send_packet (fallback_interface,
        !          2157:                                      (struct packet *)0,
        !          2158:                                      &client -> packet,
        !          2159:                                      client -> packet_length,
        !          2160:                                      from, &destination,
        !          2161:                                      (struct hardware *)0);
        !          2162:        else
        !          2163:                /* Send out a packet. */
        !          2164:                result = send_packet (client -> interface, (struct packet *)0,
        !          2165:                                      &client -> packet,
        !          2166:                                      client -> packet_length,
        !          2167:                                      from, &destination,
        !          2168:                                      (struct hardware *)0);
        !          2169: 
        !          2170:        tv.tv_sec = cur_tv.tv_sec + client->interval;
        !          2171:        tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
        !          2172:                        random() % 1000000 : cur_tv.tv_usec;
        !          2173:        add_timeout(&tv, send_request, client, 0, 0);
        !          2174: }
        !          2175: 
        !          2176: void send_decline (cpp)
        !          2177:        void *cpp;
        !          2178: {
        !          2179:        struct client_state *client = cpp;
        !          2180: 
        !          2181:        int result;
        !          2182: 
        !          2183:        log_info ("DHCPDECLINE on %s to %s port %d",
        !          2184:              client -> name ? client -> name : client -> interface -> name,
        !          2185:              inet_ntoa (sockaddr_broadcast.sin_addr),
        !          2186:              ntohs (sockaddr_broadcast.sin_port));
        !          2187: 
        !          2188:        /* Send out a packet. */
        !          2189:        result = send_packet (client -> interface, (struct packet *)0,
        !          2190:                              &client -> packet,
        !          2191:                              client -> packet_length,
        !          2192:                              inaddr_any, &sockaddr_broadcast,
        !          2193:                              (struct hardware *)0);
        !          2194: }
        !          2195: 
        !          2196: void send_release (cpp)
        !          2197:        void *cpp;
        !          2198: {
        !          2199:        struct client_state *client = cpp;
        !          2200: 
        !          2201:        int result;
        !          2202:        struct sockaddr_in destination;
        !          2203:        struct in_addr from;
        !          2204: 
        !          2205:        memcpy (&from, client -> active -> address.iabuf,
        !          2206:                sizeof from);
        !          2207:        memcpy (&destination.sin_addr.s_addr,
        !          2208:                client -> destination.iabuf,
        !          2209:                sizeof destination.sin_addr.s_addr);
        !          2210:        destination.sin_port = remote_port;
        !          2211:        destination.sin_family = AF_INET;
        !          2212: #ifdef HAVE_SA_LEN
        !          2213:        destination.sin_len = sizeof destination;
        !          2214: #endif
        !          2215: 
        !          2216:        /* Set the lease to end now, so that we don't accidentally
        !          2217:           reuse it if we restart before the old expiry time. */
        !          2218:        client -> active -> expiry =
        !          2219:                client -> active -> renewal =
        !          2220:                client -> active -> rebind = cur_time;
        !          2221:        if (!write_client_lease (client, client -> active, 1, 1)) {
        !          2222:                log_error ("Can't release lease: lease write failed.");
        !          2223:                return;
        !          2224:        }
        !          2225: 
        !          2226:        log_info ("DHCPRELEASE on %s to %s port %d",
        !          2227:              client -> name ? client -> name : client -> interface -> name,
        !          2228:              inet_ntoa (destination.sin_addr),
        !          2229:              ntohs (destination.sin_port));
        !          2230: 
        !          2231:        if (fallback_interface)
        !          2232:                result = send_packet (fallback_interface,
        !          2233:                                      (struct packet *)0,
        !          2234:                                      &client -> packet,
        !          2235:                                      client -> packet_length,
        !          2236:                                      from, &destination,
        !          2237:                                      (struct hardware *)0);
        !          2238:        else
        !          2239:                /* Send out a packet. */
        !          2240:                result = send_packet (client -> interface, (struct packet *)0,
        !          2241:                                      &client -> packet,
        !          2242:                                      client -> packet_length,
        !          2243:                                      from, &destination,
        !          2244:                                      (struct hardware *)0);
        !          2245: }
        !          2246: 
        !          2247: void
        !          2248: make_client_options(struct client_state *client, struct client_lease *lease,
        !          2249:                    u_int8_t *type, struct option_cache *sid,
        !          2250:                    struct iaddr *rip, struct option **prl,
        !          2251:                    struct option_state **op)
        !          2252: {
        !          2253:        unsigned i;
        !          2254:        struct option_cache *oc;
        !          2255:        struct option *option = NULL;
        !          2256:        struct buffer *bp = (struct buffer *)0;
        !          2257: 
        !          2258:        /* If there are any leftover options, get rid of them. */
        !          2259:        if (*op)
        !          2260:                option_state_dereference (op, MDL);
        !          2261: 
        !          2262:        /* Allocate space for options. */
        !          2263:        option_state_allocate (op, MDL);
        !          2264: 
        !          2265:        /* Send the server identifier if provided. */
        !          2266:        if (sid)
        !          2267:                save_option (&dhcp_universe, *op, sid);
        !          2268: 
        !          2269:        oc = (struct option_cache *)0;
        !          2270: 
        !          2271:        /* Send the requested address if provided. */
        !          2272:        if (rip) {
        !          2273:                client -> requested_address = *rip;
        !          2274:                i = DHO_DHCP_REQUESTED_ADDRESS;
        !          2275:                if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
        !          2276:                                              &i, 0, MDL) &&
        !          2277:                      make_const_option_cache(&oc, NULL, rip->iabuf, rip->len,
        !          2278:                                              option, MDL)))
        !          2279:                        log_error ("can't make requested address cache.");
        !          2280:                else {
        !          2281:                        save_option (&dhcp_universe, *op, oc);
        !          2282:                        option_cache_dereference (&oc, MDL);
        !          2283:                }
        !          2284:                option_dereference(&option, MDL);
        !          2285:        } else {
        !          2286:                client -> requested_address.len = 0;
        !          2287:        }
        !          2288: 
        !          2289:        i = DHO_DHCP_MESSAGE_TYPE;
        !          2290:        if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0,
        !          2291:                                      MDL) &&
        !          2292:              make_const_option_cache(&oc, NULL, type, 1, option, MDL)))
        !          2293:                log_error ("can't make message type.");
        !          2294:        else {
        !          2295:                save_option (&dhcp_universe, *op, oc);
        !          2296:                option_cache_dereference (&oc, MDL);
        !          2297:        }
        !          2298:        option_dereference(&option, MDL);
        !          2299: 
        !          2300:        if (prl) {
        !          2301:                int len;
        !          2302: 
        !          2303:                /* Probe the length of the list. */
        !          2304:                len = 0;
        !          2305:                for (i = 0 ; prl[i] != NULL ; i++)
        !          2306:                        if (prl[i]->universe == &dhcp_universe)
        !          2307:                                len++;
        !          2308: 
        !          2309:                if (!buffer_allocate (&bp, len, MDL))
        !          2310:                        log_error ("can't make parameter list buffer.");
        !          2311:                else {
        !          2312:                        unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST;
        !          2313: 
        !          2314:                        len = 0;
        !          2315:                        for (i = 0 ; prl[i] != NULL ; i++)
        !          2316:                                if (prl[i]->universe == &dhcp_universe)
        !          2317:                                        bp->data[len++] = prl[i]->code;
        !          2318: 
        !          2319:                        if (!(option_code_hash_lookup(&option,
        !          2320:                                                      dhcp_universe.code_hash,
        !          2321:                                                      &code, 0, MDL) &&
        !          2322:                              make_const_option_cache(&oc, &bp, NULL, len,
        !          2323:                                                      option, MDL)))
        !          2324:                                log_error ("can't make option cache");
        !          2325:                        else {
        !          2326:                                save_option (&dhcp_universe, *op, oc);
        !          2327:                                option_cache_dereference (&oc, MDL);
        !          2328:                        }
        !          2329:                        option_dereference(&option, MDL);
        !          2330:                }
        !          2331:        }
        !          2332: 
        !          2333:        /* Run statements that need to be run on transmission. */
        !          2334:        if (client -> config -> on_transmission)
        !          2335:                execute_statements_in_scope
        !          2336:                        ((struct binding_value **)0,
        !          2337:                         (struct packet *)0, (struct lease *)0, client,
        !          2338:                         (lease ? lease -> options : (struct option_state *)0),
        !          2339:                         *op, &global_scope,
        !          2340:                         client -> config -> on_transmission,
        !          2341:                         (struct group *)0);
        !          2342: }
        !          2343: 
        !          2344: void make_discover (client, lease)
        !          2345:        struct client_state *client;
        !          2346:        struct client_lease *lease;
        !          2347: {
        !          2348:        unsigned char discover = DHCPDISCOVER;
        !          2349:        struct option_state *options = (struct option_state *)0;
        !          2350: 
        !          2351:        memset (&client -> packet, 0, sizeof (client -> packet));
        !          2352: 
        !          2353:        make_client_options (client,
        !          2354:                             lease, &discover, (struct option_cache *)0,
        !          2355:                             lease ? &lease -> address : (struct iaddr *)0,
        !          2356:                             client -> config -> requested_options,
        !          2357:                             &options);
        !          2358: 
        !          2359:        /* Set up the option buffer... */
        !          2360:        client -> packet_length =
        !          2361:                cons_options ((struct packet *)0, &client -> packet,
        !          2362:                              (struct lease *)0, client,
        !          2363:                              /* maximum packet size */1500,
        !          2364:                              (struct option_state *)0,
        !          2365:                              options,
        !          2366:                              /* scope */ &global_scope,
        !          2367:                              /* overload */ 0,
        !          2368:                              /* terminate */0,
        !          2369:                              /* bootpp    */0,
        !          2370:                              (struct data_string *)0,
        !          2371:                              client -> config -> vendor_space_name);
        !          2372: 
        !          2373:        option_state_dereference (&options, MDL);
        !          2374:        if (client -> packet_length < BOOTP_MIN_LEN)
        !          2375:                client -> packet_length = BOOTP_MIN_LEN;
        !          2376: 
        !          2377:        client -> packet.op = BOOTREQUEST;
        !          2378:        client -> packet.htype = client -> interface -> hw_address.hbuf [0];
        !          2379:        client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
        !          2380:        client -> packet.hops = 0;
        !          2381:        client -> packet.xid = random ();
        !          2382:        client -> packet.secs = 0; /* filled in by send_discover. */
        !          2383: 
        !          2384:        if (can_receive_unicast_unconfigured (client -> interface))
        !          2385:                client -> packet.flags = 0;
        !          2386:        else
        !          2387:                client -> packet.flags = htons (BOOTP_BROADCAST);
        !          2388: 
        !          2389:        memset (&(client -> packet.ciaddr),
        !          2390:                0, sizeof client -> packet.ciaddr);
        !          2391:        memset (&(client -> packet.yiaddr),
        !          2392:                0, sizeof client -> packet.yiaddr);
        !          2393:        memset (&(client -> packet.siaddr),
        !          2394:                0, sizeof client -> packet.siaddr);
        !          2395:        client -> packet.giaddr = giaddr;
        !          2396:        if (client -> interface -> hw_address.hlen > 0)
        !          2397:            memcpy (client -> packet.chaddr,
        !          2398:                    &client -> interface -> hw_address.hbuf [1],
        !          2399:                    (unsigned)(client -> interface -> hw_address.hlen - 1));
        !          2400: 
        !          2401: #ifdef DEBUG_PACKET
        !          2402:        dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
        !          2403: #endif
        !          2404: }
        !          2405: 
        !          2406: 
        !          2407: void make_request (client, lease)
        !          2408:        struct client_state *client;
        !          2409:        struct client_lease *lease;
        !          2410: {
        !          2411:        unsigned char request = DHCPREQUEST;
        !          2412:        struct option_cache *oc;
        !          2413: 
        !          2414:        memset (&client -> packet, 0, sizeof (client -> packet));
        !          2415: 
        !          2416:        if (client -> state == S_REQUESTING)
        !          2417:                oc = lookup_option (&dhcp_universe, lease -> options,
        !          2418:                                    DHO_DHCP_SERVER_IDENTIFIER);
        !          2419:        else
        !          2420:                oc = (struct option_cache *)0;
        !          2421: 
        !          2422:        if (client -> sent_options)
        !          2423:                option_state_dereference (&client -> sent_options, MDL);
        !          2424: 
        !          2425:        make_client_options (client, lease, &request, oc,
        !          2426:                             ((client -> state == S_REQUESTING ||
        !          2427:                               client -> state == S_REBOOTING)
        !          2428:                              ? &lease -> address
        !          2429:                              : (struct iaddr *)0),
        !          2430:                             client -> config -> requested_options,
        !          2431:                             &client -> sent_options);
        !          2432: 
        !          2433:        /* Set up the option buffer... */
        !          2434:        client -> packet_length =
        !          2435:                cons_options ((struct packet *)0, &client -> packet,
        !          2436:                              (struct lease *)0, client,
        !          2437:                              /* maximum packet size */1500,
        !          2438:                              (struct option_state *)0,
        !          2439:                              client -> sent_options,
        !          2440:                              /* scope */ &global_scope,
        !          2441:                              /* overload */ 0,
        !          2442:                              /* terminate */0,
        !          2443:                              /* bootpp    */0,
        !          2444:                              (struct data_string *)0,
        !          2445:                              client -> config -> vendor_space_name);
        !          2446: 
        !          2447:        if (client -> packet_length < BOOTP_MIN_LEN)
        !          2448:                client -> packet_length = BOOTP_MIN_LEN;
        !          2449: 
        !          2450:        client -> packet.op = BOOTREQUEST;
        !          2451:        client -> packet.htype = client -> interface -> hw_address.hbuf [0];
        !          2452:        client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
        !          2453:        client -> packet.hops = 0;
        !          2454:        client -> packet.xid = client -> xid;
        !          2455:        client -> packet.secs = 0; /* Filled in by send_request. */
        !          2456: 
        !          2457:        /* If we own the address we're requesting, put it in ciaddr;
        !          2458:           otherwise set ciaddr to zero. */
        !          2459:        if (client -> state == S_BOUND ||
        !          2460:            client -> state == S_RENEWING ||
        !          2461:            client -> state == S_REBINDING) {
        !          2462:                memcpy (&client -> packet.ciaddr,
        !          2463:                        lease -> address.iabuf, lease -> address.len);
        !          2464:                client -> packet.flags = 0;
        !          2465:        } else {
        !          2466:                memset (&client -> packet.ciaddr, 0,
        !          2467:                        sizeof client -> packet.ciaddr);
        !          2468:                if (can_receive_unicast_unconfigured (client -> interface))
        !          2469:                        client -> packet.flags = 0;
        !          2470:                else
        !          2471:                        client -> packet.flags = htons (BOOTP_BROADCAST);
        !          2472:        }
        !          2473: 
        !          2474:        memset (&client -> packet.yiaddr, 0,
        !          2475:                sizeof client -> packet.yiaddr);
        !          2476:        memset (&client -> packet.siaddr, 0,
        !          2477:                sizeof client -> packet.siaddr);
        !          2478:        if (client -> state != S_BOUND &&
        !          2479:            client -> state != S_RENEWING)
        !          2480:                client -> packet.giaddr = giaddr;
        !          2481:        else
        !          2482:                memset (&client -> packet.giaddr, 0,
        !          2483:                        sizeof client -> packet.giaddr);
        !          2484:        if (client -> interface -> hw_address.hlen > 0)
        !          2485:            memcpy (client -> packet.chaddr,
        !          2486:                    &client -> interface -> hw_address.hbuf [1],
        !          2487:                    (unsigned)(client -> interface -> hw_address.hlen - 1));
        !          2488: 
        !          2489: #ifdef DEBUG_PACKET
        !          2490:        dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
        !          2491: #endif
        !          2492: }
        !          2493: 
        !          2494: void make_decline (client, lease)
        !          2495:        struct client_state *client;
        !          2496:        struct client_lease *lease;
        !          2497: {
        !          2498:        unsigned char decline = DHCPDECLINE;
        !          2499:        struct option_cache *oc;
        !          2500: 
        !          2501:        struct option_state *options = (struct option_state *)0;
        !          2502: 
        !          2503:        /* Create the options cache. */
        !          2504:        oc = lookup_option (&dhcp_universe, lease -> options,
        !          2505:                            DHO_DHCP_SERVER_IDENTIFIER);
        !          2506:        make_client_options(client, lease, &decline, oc, &lease->address,
        !          2507:                            NULL, &options);
        !          2508: 
        !          2509:        /* Consume the options cache into the option buffer. */
        !          2510:        memset (&client -> packet, 0, sizeof (client -> packet));
        !          2511:        client -> packet_length =
        !          2512:                cons_options ((struct packet *)0, &client -> packet,
        !          2513:                              (struct lease *)0, client, 0,
        !          2514:                              (struct option_state *)0, options,
        !          2515:                              &global_scope, 0, 0, 0, (struct data_string *)0,
        !          2516:                              client -> config -> vendor_space_name);
        !          2517: 
        !          2518:        /* Destroy the options cache. */
        !          2519:        option_state_dereference (&options, MDL);
        !          2520: 
        !          2521:        if (client -> packet_length < BOOTP_MIN_LEN)
        !          2522:                client -> packet_length = BOOTP_MIN_LEN;
        !          2523: 
        !          2524:        client -> packet.op = BOOTREQUEST;
        !          2525:        client -> packet.htype = client -> interface -> hw_address.hbuf [0];
        !          2526:        client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
        !          2527:        client -> packet.hops = 0;
        !          2528:        client -> packet.xid = client -> xid;
        !          2529:        client -> packet.secs = 0; /* Filled in by send_request. */
        !          2530:        if (can_receive_unicast_unconfigured (client -> interface))
        !          2531:                client -> packet.flags = 0;
        !          2532:        else
        !          2533:                client -> packet.flags = htons (BOOTP_BROADCAST);
        !          2534: 
        !          2535:        /* ciaddr must always be zero. */
        !          2536:        memset (&client -> packet.ciaddr, 0,
        !          2537:                sizeof client -> packet.ciaddr);
        !          2538:        memset (&client -> packet.yiaddr, 0,
        !          2539:                sizeof client -> packet.yiaddr);
        !          2540:        memset (&client -> packet.siaddr, 0,
        !          2541:                sizeof client -> packet.siaddr);
        !          2542:        client -> packet.giaddr = giaddr;
        !          2543:        memcpy (client -> packet.chaddr,
        !          2544:                &client -> interface -> hw_address.hbuf [1],
        !          2545:                client -> interface -> hw_address.hlen);
        !          2546: 
        !          2547: #ifdef DEBUG_PACKET
        !          2548:        dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
        !          2549: #endif
        !          2550: }
        !          2551: 
        !          2552: void make_release (client, lease)
        !          2553:        struct client_state *client;
        !          2554:        struct client_lease *lease;
        !          2555: {
        !          2556:        unsigned char request = DHCPRELEASE;
        !          2557:        struct option_cache *oc;
        !          2558: 
        !          2559:        struct option_state *options = (struct option_state *)0;
        !          2560: 
        !          2561:        memset (&client -> packet, 0, sizeof (client -> packet));
        !          2562: 
        !          2563:        oc = lookup_option (&dhcp_universe, lease -> options,
        !          2564:                            DHO_DHCP_SERVER_IDENTIFIER);
        !          2565:        make_client_options(client, lease, &request, oc, NULL, NULL, &options);
        !          2566: 
        !          2567:        /* Set up the option buffer... */
        !          2568:        client -> packet_length =
        !          2569:                cons_options ((struct packet *)0, &client -> packet,
        !          2570:                              (struct lease *)0, client,
        !          2571:                              /* maximum packet size */1500,
        !          2572:                              (struct option_state *)0,
        !          2573:                              options,
        !          2574:                              /* scope */ &global_scope,
        !          2575:                              /* overload */ 0,
        !          2576:                              /* terminate */0,
        !          2577:                              /* bootpp    */0,
        !          2578:                              (struct data_string *)0,
        !          2579:                              client -> config -> vendor_space_name);
        !          2580: 
        !          2581:        if (client -> packet_length < BOOTP_MIN_LEN)
        !          2582:                client -> packet_length = BOOTP_MIN_LEN;
        !          2583:        option_state_dereference (&options, MDL);
        !          2584: 
        !          2585:        client -> packet.op = BOOTREQUEST;
        !          2586:        client -> packet.htype = client -> interface -> hw_address.hbuf [0];
        !          2587:        client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
        !          2588:        client -> packet.hops = 0;
        !          2589:        client -> packet.xid = random ();
        !          2590:        client -> packet.secs = 0;
        !          2591:        client -> packet.flags = 0;
        !          2592:        memcpy (&client -> packet.ciaddr,
        !          2593:                lease -> address.iabuf, lease -> address.len);
        !          2594:        memset (&client -> packet.yiaddr, 0,
        !          2595:                sizeof client -> packet.yiaddr);
        !          2596:        memset (&client -> packet.siaddr, 0,
        !          2597:                sizeof client -> packet.siaddr);
        !          2598:        client -> packet.giaddr = giaddr;
        !          2599:        memcpy (client -> packet.chaddr,
        !          2600:                &client -> interface -> hw_address.hbuf [1],
        !          2601:                client -> interface -> hw_address.hlen);
        !          2602: 
        !          2603: #ifdef DEBUG_PACKET
        !          2604:        dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
        !          2605: #endif
        !          2606: }
        !          2607: 
        !          2608: void destroy_client_lease (lease)
        !          2609:        struct client_lease *lease;
        !          2610: {
        !          2611:        if (lease -> server_name)
        !          2612:                dfree (lease -> server_name, MDL);
        !          2613:        if (lease -> filename)
        !          2614:                dfree (lease -> filename, MDL);
        !          2615:        option_state_dereference (&lease -> options, MDL);
        !          2616:        free_client_lease (lease, MDL);
        !          2617: }
        !          2618: 
        !          2619: FILE *leaseFile = NULL;
        !          2620: int leases_written = 0;
        !          2621: 
        !          2622: void rewrite_client_leases ()
        !          2623: {
        !          2624:        struct interface_info *ip;
        !          2625:        struct client_state *client;
        !          2626:        struct client_lease *lp;
        !          2627: 
        !          2628:        if (leaseFile != NULL)
        !          2629:                fclose (leaseFile);
        !          2630:        leaseFile = fopen (path_dhclient_db, "w");
        !          2631:        if (leaseFile == NULL) {
        !          2632:                log_error ("can't create %s: %m", path_dhclient_db);
        !          2633:                return;
        !          2634:        }
        !          2635: 
        !          2636:        /* If there is a default duid, write it out. */
        !          2637:        if (default_duid.len != 0)
        !          2638:                write_duid(&default_duid);
        !          2639: 
        !          2640:        /* Write out all the leases attached to configured interfaces that
        !          2641:           we know about. */
        !          2642:        for (ip = interfaces; ip; ip = ip -> next) {
        !          2643:                for (client = ip -> client; client; client = client -> next) {
        !          2644:                        for (lp = client -> leases; lp; lp = lp -> next) {
        !          2645:                                write_client_lease (client, lp, 1, 0);
        !          2646:                        }
        !          2647:                        if (client -> active)
        !          2648:                                write_client_lease (client,
        !          2649:                                                    client -> active, 1, 0);
        !          2650: 
        !          2651:                        if (client->active_lease != NULL)
        !          2652:                                write_client6_lease(client,
        !          2653:                                                    client->active_lease,
        !          2654:                                                    1, 0);
        !          2655: 
        !          2656:                        /* Reset last_write after rewrites. */
        !          2657:                        client->last_write = 0;
        !          2658:                }
        !          2659:        }
        !          2660: 
        !          2661:        /* Write out any leases that are attached to interfaces that aren't
        !          2662:           currently configured. */
        !          2663:        for (ip = dummy_interfaces; ip; ip = ip -> next) {
        !          2664:                for (client = ip -> client; client; client = client -> next) {
        !          2665:                        for (lp = client -> leases; lp; lp = lp -> next) {
        !          2666:                                write_client_lease (client, lp, 1, 0);
        !          2667:                        }
        !          2668:                        if (client -> active)
        !          2669:                                write_client_lease (client,
        !          2670:                                                    client -> active, 1, 0);
        !          2671: 
        !          2672:                        if (client->active_lease != NULL)
        !          2673:                                write_client6_lease(client,
        !          2674:                                                    client->active_lease,
        !          2675:                                                    1, 0);
        !          2676: 
        !          2677:                        /* Reset last_write after rewrites. */
        !          2678:                        client->last_write = 0;
        !          2679:                }
        !          2680:        }
        !          2681:        fflush (leaseFile);
        !          2682: }
        !          2683: 
        !          2684: void write_lease_option (struct option_cache *oc,
        !          2685:                         struct packet *packet, struct lease *lease,
        !          2686:                         struct client_state *client_state,
        !          2687:                         struct option_state *in_options,
        !          2688:                         struct option_state *cfg_options,
        !          2689:                         struct binding_scope **scope,
        !          2690:                         struct universe *u, void *stuff)
        !          2691: {
        !          2692:        const char *name, *dot;
        !          2693:        struct data_string ds;
        !          2694:        char *preamble = stuff;
        !          2695: 
        !          2696:        memset (&ds, 0, sizeof ds);
        !          2697: 
        !          2698:        if (u != &dhcp_universe) {
        !          2699:                name = u -> name;
        !          2700:                dot = ".";
        !          2701:        } else {
        !          2702:                name = "";
        !          2703:                dot = "";
        !          2704:        }
        !          2705:        if (evaluate_option_cache (&ds, packet, lease, client_state,
        !          2706:                                   in_options, cfg_options, scope, oc, MDL)) {
        !          2707:                fprintf(leaseFile, "%soption %s%s%s %s;\n", preamble,
        !          2708:                        name, dot, oc->option->name,
        !          2709:                        pretty_print_option(oc->option, ds.data, ds.len,
        !          2710:                                            1, 1));
        !          2711:                data_string_forget (&ds, MDL);
        !          2712:        }
        !          2713: }
        !          2714: 
        !          2715: /* Write an option cache to the lease store. */
        !          2716: static void
        !          2717: write_options(struct client_state *client, struct option_state *options,
        !          2718:              const char *preamble)
        !          2719: {
        !          2720:        int i;
        !          2721: 
        !          2722:        for (i = 0; i < options->universe_count; i++) {
        !          2723:                option_space_foreach(NULL, NULL, client, NULL, options,
        !          2724:                                     &global_scope, universes[i],
        !          2725:                                     (char *)preamble, write_lease_option);
        !          2726:        }
        !          2727: }
        !          2728: 
        !          2729: /* Write the default DUID to the lease store. */
        !          2730: static isc_result_t
        !          2731: write_duid(struct data_string *duid)
        !          2732: {
        !          2733:        char *str;
        !          2734:        int stat;
        !          2735: 
        !          2736:        if ((duid == NULL) || (duid->len <= 2))
        !          2737:                return ISC_R_INVALIDARG;
        !          2738: 
        !          2739:        if (leaseFile == NULL) {        /* XXX? */
        !          2740:                leaseFile = fopen(path_dhclient_db, "w");
        !          2741:                if (leaseFile == NULL) {
        !          2742:                        log_error("can't create %s: %m", path_dhclient_db);
        !          2743:                        return ISC_R_IOERROR;
        !          2744:                }
        !          2745:        }
        !          2746: 
        !          2747:        /* It would make more sense to write this as a hex string,
        !          2748:         * but our function to do that (print_hex_n) uses a fixed
        !          2749:         * length buffer...and we can't guarantee a duid would be
        !          2750:         * less than the fixed length.
        !          2751:         */
        !          2752:        str = quotify_buf(duid->data, duid->len, MDL);
        !          2753:        if (str == NULL)
        !          2754:                return ISC_R_NOMEMORY;
        !          2755: 
        !          2756:        stat = fprintf(leaseFile, "default-duid \"%s\";\n", str);
        !          2757:        dfree(str, MDL);
        !          2758:        if (stat <= 0)
        !          2759:                return ISC_R_IOERROR;
        !          2760: 
        !          2761:        if (fflush(leaseFile) != 0)
        !          2762:                return ISC_R_IOERROR;
        !          2763: 
        !          2764:        return ISC_R_SUCCESS;
        !          2765: }
        !          2766: 
        !          2767: /* Write a DHCPv6 lease to the store. */
        !          2768: isc_result_t
        !          2769: write_client6_lease(struct client_state *client, struct dhc6_lease *lease,
        !          2770:                    int rewrite, int sync)
        !          2771: {
        !          2772:        struct dhc6_ia *ia;
        !          2773:        struct dhc6_addr *addr;
        !          2774:        int stat;
        !          2775:        const char *ianame;
        !          2776: 
        !          2777:        /* This should include the current lease. */
        !          2778:        if (!rewrite && (leases_written++ > 20)) {
        !          2779:                rewrite_client_leases();
        !          2780:                leases_written = 0;
        !          2781:                return ISC_R_SUCCESS;
        !          2782:        }
        !          2783: 
        !          2784:        if (client == NULL || lease == NULL)
        !          2785:                return ISC_R_INVALIDARG;
        !          2786: 
        !          2787:        if (leaseFile == NULL) {        /* XXX? */
        !          2788:                leaseFile = fopen(path_dhclient_db, "w");
        !          2789:                if (leaseFile == NULL) {
        !          2790:                        log_error("can't create %s: %m", path_dhclient_db);
        !          2791:                        return ISC_R_IOERROR;
        !          2792:                }
        !          2793:        }
        !          2794: 
        !          2795:        stat = fprintf(leaseFile, "lease6 {\n");
        !          2796:        if (stat <= 0)
        !          2797:                return ISC_R_IOERROR;
        !          2798: 
        !          2799:        stat = fprintf(leaseFile, "  interface \"%s\";\n",
        !          2800:                       client->interface->name);
        !          2801:        if (stat <= 0)
        !          2802:                return ISC_R_IOERROR;
        !          2803: 
        !          2804:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          2805:                switch (ia->ia_type) {
        !          2806:                        case D6O_IA_NA:
        !          2807:                        default:
        !          2808:                                ianame = "ia-na";
        !          2809:                                break;
        !          2810:                        case D6O_IA_TA:
        !          2811:                                ianame = "ia-ta";
        !          2812:                                break;
        !          2813:                        case D6O_IA_PD:
        !          2814:                                ianame = "ia-pd";
        !          2815:                                break;
        !          2816:                }
        !          2817:                stat = fprintf(leaseFile, "  %s %s {\n",
        !          2818:                               ianame, print_hex_1(4, ia->iaid, 12));
        !          2819:                if (stat <= 0)
        !          2820:                        return ISC_R_IOERROR;
        !          2821: 
        !          2822:                if (ia->ia_type != D6O_IA_TA)
        !          2823:                        stat = fprintf(leaseFile, "    starts %d;\n"
        !          2824:                                                  "    renew %u;\n"
        !          2825:                                                  "    rebind %u;\n",
        !          2826:                                       (int)ia->starts, ia->renew, ia->rebind);
        !          2827:                else
        !          2828:                        stat = fprintf(leaseFile, "    starts %d;\n",
        !          2829:                                       (int)ia->starts);
        !          2830:                if (stat <= 0)
        !          2831:                        return ISC_R_IOERROR;
        !          2832: 
        !          2833:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          2834:                        if (ia->ia_type != D6O_IA_PD)
        !          2835:                                stat = fprintf(leaseFile,
        !          2836:                                               "    iaaddr %s {\n",
        !          2837:                                               piaddr(addr->address));
        !          2838:                        else
        !          2839:                                stat = fprintf(leaseFile,
        !          2840:                                               "    iaprefix %s/%d {\n",
        !          2841:                                               piaddr(addr->address),
        !          2842:                                               (int)addr->plen);
        !          2843:                        if (stat <= 0)
        !          2844:                                return ISC_R_IOERROR;
        !          2845: 
        !          2846:                        stat = fprintf(leaseFile, "      starts %d;\n"
        !          2847:                                                  "      preferred-life %u;\n"
        !          2848:                                                  "      max-life %u;\n",
        !          2849:                                       (int)addr->starts, addr->preferred_life,
        !          2850:                                       addr->max_life);
        !          2851:                        if (stat <= 0)
        !          2852:                                return ISC_R_IOERROR;
        !          2853: 
        !          2854:                        if (addr->options != NULL)
        !          2855:                                write_options(client, addr->options, "      ");
        !          2856: 
        !          2857:                        stat = fprintf(leaseFile, "    }\n");
        !          2858:                        if (stat <= 0)
        !          2859:                                return ISC_R_IOERROR;
        !          2860:                }
        !          2861: 
        !          2862:                if (ia->options != NULL)
        !          2863:                        write_options(client, ia->options, "    ");
        !          2864: 
        !          2865:                stat = fprintf(leaseFile, "  }\n");
        !          2866:                if (stat <= 0)
        !          2867:                        return ISC_R_IOERROR;
        !          2868:        }
        !          2869: 
        !          2870:        if (lease->released) {
        !          2871:                stat = fprintf(leaseFile, "  released;\n");
        !          2872:                if (stat <= 0)
        !          2873:                        return ISC_R_IOERROR;
        !          2874:        }
        !          2875: 
        !          2876:        if (lease->options != NULL)
        !          2877:                write_options(client, lease->options, "  ");
        !          2878: 
        !          2879:        stat = fprintf(leaseFile, "}\n");
        !          2880:        if (stat <= 0)
        !          2881:                return ISC_R_IOERROR;
        !          2882: 
        !          2883:        if (fflush(leaseFile) != 0)
        !          2884:                return ISC_R_IOERROR;
        !          2885: 
        !          2886:        if (sync) {
        !          2887:                if (fsync(fileno(leaseFile)) < 0) {
        !          2888:                        log_error("write_client_lease: fsync(): %m");
        !          2889:                        return ISC_R_IOERROR;
        !          2890:                }
        !          2891:        }
        !          2892: 
        !          2893:        return ISC_R_SUCCESS;
        !          2894: }
        !          2895: 
        !          2896: int write_client_lease (client, lease, rewrite, makesure)
        !          2897:        struct client_state *client;
        !          2898:        struct client_lease *lease;
        !          2899:        int rewrite;
        !          2900:        int makesure;
        !          2901: {
        !          2902:        struct data_string ds;
        !          2903:        int errors = 0;
        !          2904:        char *s;
        !          2905:        const char *tval;
        !          2906: 
        !          2907:        if (!rewrite) {
        !          2908:                if (leases_written++ > 20) {
        !          2909:                        rewrite_client_leases ();
        !          2910:                        leases_written = 0;
        !          2911:                }
        !          2912:        }
        !          2913: 
        !          2914:        /* If the lease came from the config file, we don't need to stash
        !          2915:           a copy in the lease database. */
        !          2916:        if (lease -> is_static)
        !          2917:                return 1;
        !          2918: 
        !          2919:        if (leaseFile == NULL) {        /* XXX */
        !          2920:                leaseFile = fopen (path_dhclient_db, "w");
        !          2921:                if (leaseFile == NULL) {
        !          2922:                        log_error ("can't create %s: %m", path_dhclient_db);
        !          2923:                        return 0;
        !          2924:                }
        !          2925:        }
        !          2926: 
        !          2927:        errno = 0;
        !          2928:        fprintf (leaseFile, "lease {\n");
        !          2929:        if (lease -> is_bootp) {
        !          2930:                fprintf (leaseFile, "  bootp;\n");
        !          2931:                if (errno) {
        !          2932:                        ++errors;
        !          2933:                        errno = 0;
        !          2934:                }
        !          2935:        }
        !          2936:        fprintf (leaseFile, "  interface \"%s\";\n",
        !          2937:                 client -> interface -> name);
        !          2938:        if (errno) {
        !          2939:                ++errors;
        !          2940:                errno = 0;
        !          2941:        }
        !          2942:        if (client -> name) {
        !          2943:                fprintf (leaseFile, "  name \"%s\";\n", client -> name);
        !          2944:                if (errno) {
        !          2945:                        ++errors;
        !          2946:                        errno = 0;
        !          2947:                }
        !          2948:        }
        !          2949:        fprintf (leaseFile, "  fixed-address %s;\n",
        !          2950:                 piaddr (lease -> address));
        !          2951:        if (errno) {
        !          2952:                ++errors;
        !          2953:                errno = 0;
        !          2954:        }
        !          2955:        if (lease -> filename) {
        !          2956:                s = quotify_string (lease -> filename, MDL);
        !          2957:                if (s) {
        !          2958:                        fprintf (leaseFile, "  filename \"%s\";\n", s);
        !          2959:                        if (errno) {
        !          2960:                                ++errors;
        !          2961:                                errno = 0;
        !          2962:                        }
        !          2963:                        dfree (s, MDL);
        !          2964:                } else
        !          2965:                        errors++;
        !          2966: 
        !          2967:        }
        !          2968:        if (lease->server_name != NULL) {
        !          2969:                s = quotify_string(lease->server_name, MDL);
        !          2970:                if (s != NULL) {
        !          2971:                        fprintf(leaseFile, "  server-name \"%s\";\n", s);
        !          2972:                        if (errno) {
        !          2973:                                ++errors;
        !          2974:                                errno = 0;
        !          2975:                        }
        !          2976:                        dfree(s, MDL);
        !          2977:                } else
        !          2978:                        ++errors;
        !          2979:        }
        !          2980:        if (lease -> medium) {
        !          2981:                s = quotify_string (lease -> medium -> string, MDL);
        !          2982:                if (s) {
        !          2983:                        fprintf (leaseFile, "  medium \"%s\";\n", s);
        !          2984:                        if (errno) {
        !          2985:                                ++errors;
        !          2986:                                errno = 0;
        !          2987:                        }
        !          2988:                        dfree (s, MDL);
        !          2989:                } else
        !          2990:                        errors++;
        !          2991:        }
        !          2992:        if (errno != 0) {
        !          2993:                errors++;
        !          2994:                errno = 0;
        !          2995:        }
        !          2996: 
        !          2997:        memset (&ds, 0, sizeof ds);
        !          2998: 
        !          2999:        write_options(client, lease->options, "  ");
        !          3000: 
        !          3001:        tval = print_time(lease->renewal);
        !          3002:        if (tval == NULL ||
        !          3003:            fprintf(leaseFile, "  renew %s\n", tval) < 0)
        !          3004:                errors++;
        !          3005: 
        !          3006:        tval = print_time(lease->rebind);
        !          3007:        if (tval == NULL ||
        !          3008:            fprintf(leaseFile, "  rebind %s\n", tval) < 0)
        !          3009:                errors++;
        !          3010: 
        !          3011:        tval = print_time(lease->expiry);
        !          3012:        if (tval == NULL ||
        !          3013:            fprintf(leaseFile, "  expire %s\n", tval) < 0)
        !          3014:                errors++;
        !          3015: 
        !          3016:        if (fprintf(leaseFile, "}\n") < 0)
        !          3017:                errors++;
        !          3018: 
        !          3019:        if (fflush(leaseFile) != 0)
        !          3020:                errors++;
        !          3021: 
        !          3022:        client->last_write = cur_time;
        !          3023: 
        !          3024:        if (!errors && makesure) {
        !          3025:                if (fsync (fileno (leaseFile)) < 0) {
        !          3026:                        log_info ("write_client_lease: %m");
        !          3027:                        return 0;
        !          3028:                }
        !          3029:        }
        !          3030: 
        !          3031:        return errors ? 0 : 1;
        !          3032: }
        !          3033: 
        !          3034: /* Variables holding name of script and file pointer for writing to
        !          3035:    script.   Needless to say, this is not reentrant - only one script
        !          3036:    can be invoked at a time. */
        !          3037: char scriptName [256];
        !          3038: FILE *scriptFile;
        !          3039: 
        !          3040: void script_init (client, reason, medium)
        !          3041:        struct client_state *client;
        !          3042:        const char *reason;
        !          3043:        struct string_list *medium;
        !          3044: {
        !          3045:        struct string_list *sl, *next;
        !          3046: 
        !          3047:        if (client) {
        !          3048:                for (sl = client -> env; sl; sl = next) {
        !          3049:                        next = sl -> next;
        !          3050:                        dfree (sl, MDL);
        !          3051:                }
        !          3052:                client -> env = (struct string_list *)0;
        !          3053:                client -> envc = 0;
        !          3054: 
        !          3055:                if (client -> interface) {
        !          3056:                        client_envadd (client, "", "interface", "%s",
        !          3057:                                       client -> interface -> name);
        !          3058:                }
        !          3059:                if (client -> name)
        !          3060:                        client_envadd (client,
        !          3061:                                       "", "client", "%s", client -> name);
        !          3062:                if (medium)
        !          3063:                        client_envadd (client,
        !          3064:                                       "", "medium", "%s", medium -> string);
        !          3065: 
        !          3066:                client_envadd (client, "", "reason", "%s", reason);
        !          3067:                client_envadd (client, "", "pid", "%ld", (long int)getpid ());
        !          3068:        }
        !          3069: }
        !          3070: 
        !          3071: void client_option_envadd (struct option_cache *oc,
        !          3072:                           struct packet *packet, struct lease *lease,
        !          3073:                           struct client_state *client_state,
        !          3074:                           struct option_state *in_options,
        !          3075:                           struct option_state *cfg_options,
        !          3076:                           struct binding_scope **scope,
        !          3077:                           struct universe *u, void *stuff)
        !          3078: {
        !          3079:        struct envadd_state *es = stuff;
        !          3080:        struct data_string data;
        !          3081:        memset (&data, 0, sizeof data);
        !          3082: 
        !          3083:        if (evaluate_option_cache (&data, packet, lease, client_state,
        !          3084:                                   in_options, cfg_options, scope, oc, MDL)) {
        !          3085:                if (data.len) {
        !          3086:                        char name [256];
        !          3087:                        if (dhcp_option_ev_name (name, sizeof name,
        !          3088:                                                 oc->option)) {
        !          3089:                                const char *value;
        !          3090:                                value = pretty_print_option(oc->option,
        !          3091:                                                            data.data,
        !          3092:                                                            data.len, 0, 0);
        !          3093:                                size_t length = strlen(value);
        !          3094: 
        !          3095:                                if (check_option_values(oc->option->universe,
        !          3096:                                                        oc->option->code,
        !          3097:                                                        value, length) == 0) {
        !          3098:                                        client_envadd(es->client, es->prefix,
        !          3099:                                                      name, "%s", value);
        !          3100:                                } else {
        !          3101:                                        log_error("suspect value in %s "
        !          3102:                                                  "option - discarded",
        !          3103:                                                  name);
        !          3104:                                }
        !          3105:                                data_string_forget (&data, MDL);
        !          3106:                        }
        !          3107:                }
        !          3108:        }
        !          3109: }
        !          3110: 
        !          3111: void script_write_params (client, prefix, lease)
        !          3112:        struct client_state *client;
        !          3113:        const char *prefix;
        !          3114:        struct client_lease *lease;
        !          3115: {
        !          3116:        int i;
        !          3117:        struct data_string data;
        !          3118:        struct option_cache *oc;
        !          3119:        struct envadd_state es;
        !          3120: 
        !          3121:        es.client = client;
        !          3122:        es.prefix = prefix;
        !          3123: 
        !          3124:        client_envadd (client,
        !          3125:                       prefix, "ip_address", "%s", piaddr (lease -> address));
        !          3126: 
        !          3127:        /* For the benefit of Linux (and operating systems which may
        !          3128:           have similar needs), compute the network address based on
        !          3129:           the supplied ip address and netmask, if provided.  Also
        !          3130:           compute the broadcast address (the host address all ones
        !          3131:           broadcast address, not the host address all zeroes
        !          3132:           broadcast address). */
        !          3133: 
        !          3134:        memset (&data, 0, sizeof data);
        !          3135:        oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
        !          3136:        if (oc && evaluate_option_cache (&data, (struct packet *)0,
        !          3137:                                         (struct lease *)0, client,
        !          3138:                                         (struct option_state *)0,
        !          3139:                                         lease -> options,
        !          3140:                                         &global_scope, oc, MDL)) {
        !          3141:                if (data.len > 3) {
        !          3142:                        struct iaddr netmask, subnet, broadcast;
        !          3143: 
        !          3144:                        /*
        !          3145:                         * No matter the length of the subnet-mask option,
        !          3146:                         * use only the first four octets.  Note that
        !          3147:                         * subnet-mask options longer than 4 octets are not
        !          3148:                         * in conformance with RFC 2132, but servers with this
        !          3149:                         * flaw do exist.
        !          3150:                         */
        !          3151:                        memcpy(netmask.iabuf, data.data, 4);
        !          3152:                        netmask.len = 4;
        !          3153:                        data_string_forget (&data, MDL);
        !          3154: 
        !          3155:                        subnet = subnet_number (lease -> address, netmask);
        !          3156:                        if (subnet.len) {
        !          3157:                            client_envadd (client, prefix, "network_number",
        !          3158:                                           "%s", piaddr (subnet));
        !          3159: 
        !          3160:                            oc = lookup_option (&dhcp_universe,
        !          3161:                                                lease -> options,
        !          3162:                                                DHO_BROADCAST_ADDRESS);
        !          3163:                            if (!oc ||
        !          3164:                                !(evaluate_option_cache
        !          3165:                                  (&data, (struct packet *)0,
        !          3166:                                   (struct lease *)0, client,
        !          3167:                                   (struct option_state *)0,
        !          3168:                                   lease -> options,
        !          3169:                                   &global_scope, oc, MDL))) {
        !          3170:                                broadcast = broadcast_addr (subnet, netmask);
        !          3171:                                if (broadcast.len) {
        !          3172:                                    client_envadd (client,
        !          3173:                                                   prefix, "broadcast_address",
        !          3174:                                                   "%s", piaddr (broadcast));
        !          3175:                                }
        !          3176:                            }
        !          3177:                        }
        !          3178:                }
        !          3179:                data_string_forget (&data, MDL);
        !          3180:        }
        !          3181: 
        !          3182:        if (lease->filename) {
        !          3183:                if (check_option_values(NULL, DHO_ROOT_PATH,
        !          3184:                                        lease->filename,
        !          3185:                                        strlen(lease->filename)) == 0) {
        !          3186:                        client_envadd(client, prefix, "filename",
        !          3187:                                      "%s", lease->filename);
        !          3188:                } else {
        !          3189:                        log_error("suspect value in %s "
        !          3190:                                  "option - discarded",
        !          3191:                                  lease->filename);
        !          3192:                }
        !          3193:        }
        !          3194: 
        !          3195:        if (lease->server_name) {
        !          3196:                if (check_option_values(NULL, DHO_HOST_NAME,
        !          3197:                                        lease->server_name,
        !          3198:                                        strlen(lease->server_name)) == 0 ) {
        !          3199:                        client_envadd (client, prefix, "server_name",
        !          3200:                                       "%s", lease->server_name);
        !          3201:                } else {
        !          3202:                        log_error("suspect value in %s "
        !          3203:                                  "option - discarded",
        !          3204:                                  lease->server_name);
        !          3205:                }
        !          3206:        }
        !          3207:                                
        !          3208: 
        !          3209:        for (i = 0; i < lease -> options -> universe_count; i++) {
        !          3210:                option_space_foreach ((struct packet *)0, (struct lease *)0,
        !          3211:                                      client, (struct option_state *)0,
        !          3212:                                      lease -> options, &global_scope,
        !          3213:                                      universes [i],
        !          3214:                                      &es, client_option_envadd);
        !          3215:        }
        !          3216:        client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
        !          3217: }
        !          3218: 
        !          3219: int script_go (client)
        !          3220:        struct client_state *client;
        !          3221: {
        !          3222:        char *scriptName;
        !          3223:        char *argv [2];
        !          3224:        char **envp;
        !          3225:        char reason [] = "REASON=NBI";
        !          3226:        static char client_path [] = CLIENT_PATH;
        !          3227:        int i;
        !          3228:        struct string_list *sp, *next;
        !          3229:        int pid, wpid, wstatus;
        !          3230: 
        !          3231:        if (client)
        !          3232:                scriptName = client -> config -> script_name;
        !          3233:        else
        !          3234:                scriptName = top_level_config.script_name;
        !          3235: 
        !          3236:        envp = dmalloc (((client ? client -> envc : 2) +
        !          3237:                         client_env_count + 2) * sizeof (char *), MDL);
        !          3238:        if (!envp) {
        !          3239:                log_error ("No memory for client script environment.");
        !          3240:                return 0;
        !          3241:        }
        !          3242:        i = 0;
        !          3243:        /* Copy out the environment specified on the command line,
        !          3244:           if any. */
        !          3245:        for (sp = client_env; sp; sp = sp -> next) {
        !          3246:                envp [i++] = sp -> string;
        !          3247:        }
        !          3248:        /* Copy out the environment specified by dhclient. */
        !          3249:        if (client) {
        !          3250:                for (sp = client -> env; sp; sp = sp -> next) {
        !          3251:                        envp [i++] = sp -> string;
        !          3252:                }
        !          3253:        } else {
        !          3254:                envp [i++] = reason;
        !          3255:        }
        !          3256:        /* Set $PATH. */
        !          3257:        envp [i++] = client_path;
        !          3258:        envp [i] = (char *)0;
        !          3259: 
        !          3260:        argv [0] = scriptName;
        !          3261:        argv [1] = (char *)0;
        !          3262: 
        !          3263:        pid = fork ();
        !          3264:        if (pid < 0) {
        !          3265:                log_error ("fork: %m");
        !          3266:                wstatus = 0;
        !          3267:        } else if (pid) {
        !          3268:                do {
        !          3269:                        wpid = wait (&wstatus);
        !          3270:                } while (wpid != pid && wpid > 0);
        !          3271:                if (wpid < 0) {
        !          3272:                        log_error ("wait: %m");
        !          3273:                        wstatus = 0;
        !          3274:                }
        !          3275:        } else {
        !          3276:                /* We don't want to pass an open file descriptor for
        !          3277:                 * dhclient.leases when executing dhclient-script.
        !          3278:                 */
        !          3279:                if (leaseFile != NULL)
        !          3280:                        fclose(leaseFile);
        !          3281:                execve (scriptName, argv, envp);
        !          3282:                log_error ("execve (%s, ...): %m", scriptName);
        !          3283:                exit (0);
        !          3284:        }
        !          3285: 
        !          3286:        if (client) {
        !          3287:                for (sp = client -> env; sp; sp = next) {
        !          3288:                        next = sp -> next;
        !          3289:                        dfree (sp, MDL);
        !          3290:                }
        !          3291:                client -> env = (struct string_list *)0;
        !          3292:                client -> envc = 0;
        !          3293:        }
        !          3294:        dfree (envp, MDL);
        !          3295:        gettimeofday(&cur_tv, NULL);
        !          3296:        return (WIFEXITED (wstatus) ?
        !          3297:                WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
        !          3298: }
        !          3299: 
        !          3300: void client_envadd (struct client_state *client,
        !          3301:                    const char *prefix, const char *name, const char *fmt, ...)
        !          3302: {
        !          3303:        char spbuf [1024];
        !          3304:        char *s;
        !          3305:        unsigned len;
        !          3306:        struct string_list *val;
        !          3307:        va_list list;
        !          3308: 
        !          3309:        va_start (list, fmt);
        !          3310:        len = vsnprintf (spbuf, sizeof spbuf, fmt, list);
        !          3311:        va_end (list);
        !          3312: 
        !          3313:        val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
        !          3314:                       len + sizeof *val, MDL);
        !          3315:        if (!val)
        !          3316:                return;
        !          3317:        s = val -> string;
        !          3318:        strcpy (s, prefix);
        !          3319:        strcat (s, name);
        !          3320:        s += strlen (s);
        !          3321:        *s++ = '=';
        !          3322:        if (len >= sizeof spbuf) {
        !          3323:                va_start (list, fmt);
        !          3324:                vsnprintf (s, len + 1, fmt, list);
        !          3325:                va_end (list);
        !          3326:        } else
        !          3327:                strcpy (s, spbuf);
        !          3328:        val -> next = client -> env;
        !          3329:        client -> env = val;
        !          3330:        client -> envc++;
        !          3331: }
        !          3332: 
        !          3333: int dhcp_option_ev_name (buf, buflen, option)
        !          3334:        char *buf;
        !          3335:        size_t buflen;
        !          3336:        struct option *option;
        !          3337: {
        !          3338:        int i, j;
        !          3339:        const char *s;
        !          3340: 
        !          3341:        j = 0;
        !          3342:        if (option -> universe != &dhcp_universe) {
        !          3343:                s = option -> universe -> name;
        !          3344:                i = 0;
        !          3345:        } else {
        !          3346:                s = option -> name;
        !          3347:                i = 1;
        !          3348:        }
        !          3349: 
        !          3350:        do {
        !          3351:                while (*s) {
        !          3352:                        if (j + 1 == buflen)
        !          3353:                                return 0;
        !          3354:                        if (*s == '-')
        !          3355:                                buf [j++] = '_';
        !          3356:                        else
        !          3357:                                buf [j++] = *s;
        !          3358:                        ++s;
        !          3359:                }
        !          3360:                if (!i) {
        !          3361:                        s = option -> name;
        !          3362:                        if (j + 1 == buflen)
        !          3363:                                return 0;
        !          3364:                        buf [j++] = '_';
        !          3365:                }
        !          3366:                ++i;
        !          3367:        } while (i != 2);
        !          3368: 
        !          3369:        buf [j] = 0;
        !          3370:        return 1;
        !          3371: }
        !          3372: 
        !          3373: void go_daemon ()
        !          3374: {
        !          3375:        static int state = 0;
        !          3376:        int pid;
        !          3377: 
        !          3378:        /* Don't become a daemon if the user requested otherwise. */
        !          3379:        if (no_daemon) {
        !          3380:                write_client_pid_file ();
        !          3381:                return;
        !          3382:        }
        !          3383: 
        !          3384:        /* Only do it once. */
        !          3385:        if (state)
        !          3386:                return;
        !          3387:        state = 1;
        !          3388: 
        !          3389:        /* Stop logging to stderr... */
        !          3390:        log_perror = 0;
        !          3391: 
        !          3392:        /* Become a daemon... */
        !          3393:        if ((pid = fork ()) < 0)
        !          3394:                log_fatal ("Can't fork daemon: %m");
        !          3395:        else if (pid)
        !          3396:                exit (0);
        !          3397:        /* Become session leader and get pid... */
        !          3398:        pid = setsid ();
        !          3399: 
        !          3400:        /* Close standard I/O descriptors. */
        !          3401:        close(0);
        !          3402:        close(1);
        !          3403:        close(2);
        !          3404: 
        !          3405:        /* Reopen them on /dev/null. */
        !          3406:        open("/dev/null", O_RDWR);
        !          3407:        open("/dev/null", O_RDWR);
        !          3408:        open("/dev/null", O_RDWR);
        !          3409: 
        !          3410:        write_client_pid_file ();
        !          3411: 
        !          3412:        IGNORE_RET (chdir("/"));
        !          3413: }
        !          3414: 
        !          3415: void write_client_pid_file ()
        !          3416: {
        !          3417:        FILE *pf;
        !          3418:        int pfdesc;
        !          3419: 
        !          3420:        /* nothing to do if the user doesn't want a pid file */
        !          3421:        if (no_pid_file == ISC_TRUE) {
        !          3422:                return;
        !          3423:        }
        !          3424: 
        !          3425:        pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
        !          3426: 
        !          3427:        if (pfdesc < 0) {
        !          3428:                log_error ("Can't create %s: %m", path_dhclient_pid);
        !          3429:                return;
        !          3430:        }
        !          3431: 
        !          3432:        pf = fdopen (pfdesc, "w");
        !          3433:        if (!pf) {
        !          3434:                close(pfdesc);
        !          3435:                log_error ("Can't fdopen %s: %m", path_dhclient_pid);
        !          3436:        } else {
        !          3437:                fprintf (pf, "%ld\n", (long)getpid ());
        !          3438:                fclose (pf);
        !          3439:        }
        !          3440: }
        !          3441: 
        !          3442: void client_location_changed ()
        !          3443: {
        !          3444:        struct interface_info *ip;
        !          3445:        struct client_state *client;
        !          3446: 
        !          3447:        for (ip = interfaces; ip; ip = ip -> next) {
        !          3448:                for (client = ip -> client; client; client = client -> next) {
        !          3449:                        switch (client -> state) {
        !          3450:                              case S_SELECTING:
        !          3451:                                cancel_timeout (send_discover, client);
        !          3452:                                break;
        !          3453: 
        !          3454:                              case S_BOUND:
        !          3455:                                cancel_timeout (state_bound, client);
        !          3456:                                break;
        !          3457: 
        !          3458:                              case S_REBOOTING:
        !          3459:                              case S_REQUESTING:
        !          3460:                              case S_RENEWING:
        !          3461:                                cancel_timeout (send_request, client);
        !          3462:                                break;
        !          3463: 
        !          3464:                              case S_INIT:
        !          3465:                              case S_REBINDING:
        !          3466:                              case S_STOPPED:
        !          3467:                                break;
        !          3468:                        }
        !          3469:                        client -> state = S_INIT;
        !          3470:                        state_reboot (client);
        !          3471:                }
        !          3472:        }
        !          3473: }
        !          3474: 
        !          3475: void do_release(client)
        !          3476:        struct client_state *client;
        !          3477: {
        !          3478:        struct data_string ds;
        !          3479:        struct option_cache *oc;
        !          3480: 
        !          3481:        /* Pick a random xid. */
        !          3482:        client -> xid = random ();
        !          3483: 
        !          3484:        /* is there even a lease to release? */
        !          3485:        if (client -> active) {
        !          3486:                /* Make a DHCPRELEASE packet, and set appropriate per-interface
        !          3487:                   flags. */
        !          3488:                make_release (client, client -> active);
        !          3489: 
        !          3490:                memset (&ds, 0, sizeof ds);
        !          3491:                oc = lookup_option (&dhcp_universe,
        !          3492:                                    client -> active -> options,
        !          3493:                                    DHO_DHCP_SERVER_IDENTIFIER);
        !          3494:                if (oc &&
        !          3495:                    evaluate_option_cache (&ds, (struct packet *)0,
        !          3496:                                           (struct lease *)0, client,
        !          3497:                                           (struct option_state *)0,
        !          3498:                                           client -> active -> options,
        !          3499:                                           &global_scope, oc, MDL)) {
        !          3500:                        if (ds.len > 3) {
        !          3501:                                memcpy (client -> destination.iabuf,
        !          3502:                                        ds.data, 4);
        !          3503:                                client -> destination.len = 4;
        !          3504:                        } else
        !          3505:                                client -> destination = iaddr_broadcast;
        !          3506: 
        !          3507:                        data_string_forget (&ds, MDL);
        !          3508:                } else
        !          3509:                        client -> destination = iaddr_broadcast;
        !          3510:                client -> first_sending = cur_time;
        !          3511:                client -> interval = client -> config -> initial_interval;
        !          3512: 
        !          3513:                /* Zap the medium list... */
        !          3514:                client -> medium = (struct string_list *)0;
        !          3515: 
        !          3516:                /* Send out the first and only DHCPRELEASE packet. */
        !          3517:                send_release (client);
        !          3518: 
        !          3519:                /* Do the client script RELEASE operation. */
        !          3520:                script_init (client,
        !          3521:                             "RELEASE", (struct string_list *)0);
        !          3522:                if (client -> alias)
        !          3523:                        script_write_params (client, "alias_",
        !          3524:                                             client -> alias);
        !          3525:                script_write_params (client, "old_", client -> active);
        !          3526:                script_go (client);
        !          3527:        }
        !          3528: 
        !          3529:        /* Cancel any timeouts. */
        !          3530:        cancel_timeout (state_bound, client);
        !          3531:        cancel_timeout (send_discover, client);
        !          3532:        cancel_timeout (state_init, client);
        !          3533:        cancel_timeout (send_request, client);
        !          3534:        cancel_timeout (state_reboot, client);
        !          3535:        client -> state = S_STOPPED;
        !          3536: }
        !          3537: 
        !          3538: int dhclient_interface_shutdown_hook (struct interface_info *interface)
        !          3539: {
        !          3540:        do_release (interface -> client);
        !          3541: 
        !          3542:        return 1;
        !          3543: }
        !          3544: 
        !          3545: int dhclient_interface_discovery_hook (struct interface_info *tmp)
        !          3546: {
        !          3547:        struct interface_info *last, *ip;
        !          3548:        /* See if we can find the client from dummy_interfaces */
        !          3549:        last = 0;
        !          3550:        for (ip = dummy_interfaces; ip; ip = ip -> next) {
        !          3551:                if (!strcmp (ip -> name, tmp -> name)) {
        !          3552:                        /* Remove from dummy_interfaces */
        !          3553:                        if (last) {
        !          3554:                                ip = (struct interface_info *)0;
        !          3555:                                interface_reference (&ip, last -> next, MDL);
        !          3556:                                interface_dereference (&last -> next, MDL);
        !          3557:                                if (ip -> next) {
        !          3558:                                        interface_reference (&last -> next,
        !          3559:                                                             ip -> next, MDL);
        !          3560:                                        interface_dereference (&ip -> next,
        !          3561:                                                               MDL);
        !          3562:                                }
        !          3563:                        } else {
        !          3564:                                ip = (struct interface_info *)0;
        !          3565:                                interface_reference (&ip,
        !          3566:                                                     dummy_interfaces, MDL);
        !          3567:                                interface_dereference (&dummy_interfaces, MDL);
        !          3568:                                if (ip -> next) {
        !          3569:                                        interface_reference (&dummy_interfaces,
        !          3570:                                                             ip -> next, MDL);
        !          3571:                                        interface_dereference (&ip -> next,
        !          3572:                                                               MDL);
        !          3573:                                }
        !          3574:                        }
        !          3575:                        /* Copy "client" to tmp */
        !          3576:                        if (ip -> client) {
        !          3577:                                tmp -> client = ip -> client;
        !          3578:                                tmp -> client -> interface = tmp;
        !          3579:                        }
        !          3580:                        interface_dereference (&ip, MDL);
        !          3581:                        break;
        !          3582:                }
        !          3583:                last = ip;
        !          3584:        }
        !          3585:        return 1;
        !          3586: }
        !          3587: 
        !          3588: isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
        !          3589: {
        !          3590:        struct interface_info *ip;
        !          3591:        struct client_state *client;
        !          3592: 
        !          3593:        /* This code needs some rethinking.   It doesn't test against
        !          3594:           a signal name, and it just kind of bulls into doing something
        !          3595:           that may or may not be appropriate. */
        !          3596: 
        !          3597:        if (interfaces) {
        !          3598:                interface_reference (&interface -> next, interfaces, MDL);
        !          3599:                interface_dereference (&interfaces, MDL);
        !          3600:        }
        !          3601:        interface_reference (&interfaces, interface, MDL);
        !          3602: 
        !          3603:        discover_interfaces (DISCOVER_UNCONFIGURED);
        !          3604: 
        !          3605:        for (ip = interfaces; ip; ip = ip -> next) {
        !          3606:                /* If interfaces were specified, don't configure
        !          3607:                   interfaces that weren't specified! */
        !          3608:                if (ip -> flags & INTERFACE_RUNNING ||
        !          3609:                   (ip -> flags & (INTERFACE_REQUESTED |
        !          3610:                                     INTERFACE_AUTOMATIC)) !=
        !          3611:                     INTERFACE_REQUESTED)
        !          3612:                        continue;
        !          3613:                script_init (ip -> client,
        !          3614:                             "PREINIT", (struct string_list *)0);
        !          3615:                if (ip -> client -> alias)
        !          3616:                        script_write_params (ip -> client, "alias_",
        !          3617:                                             ip -> client -> alias);
        !          3618:                script_go (ip -> client);
        !          3619:        }
        !          3620: 
        !          3621:        discover_interfaces (interfaces_requested != 0
        !          3622:                             ? DISCOVER_REQUESTED
        !          3623:                             : DISCOVER_RUNNING);
        !          3624: 
        !          3625:        for (ip = interfaces; ip; ip = ip -> next) {
        !          3626:                if (ip -> flags & INTERFACE_RUNNING)
        !          3627:                        continue;
        !          3628:                ip -> flags |= INTERFACE_RUNNING;
        !          3629:                for (client = ip->client ; client ; client = client->next) {
        !          3630:                        client->state = S_INIT;
        !          3631:                        state_reboot(client);
        !          3632:                }
        !          3633:        }
        !          3634:        return ISC_R_SUCCESS;
        !          3635: }
        !          3636: 
        !          3637: /* The client should never receive a relay agent information option,
        !          3638:    so if it does, log it and discard it. */
        !          3639: 
        !          3640: int parse_agent_information_option (packet, len, data)
        !          3641:        struct packet *packet;
        !          3642:        int len;
        !          3643:        u_int8_t *data;
        !          3644: {
        !          3645:        return 1;
        !          3646: }
        !          3647: 
        !          3648: /* The client never sends relay agent information options. */
        !          3649: 
        !          3650: unsigned cons_agent_information_options (cfg_options, outpacket,
        !          3651:                                         agentix, length)
        !          3652:        struct option_state *cfg_options;
        !          3653:        struct dhcp_packet *outpacket;
        !          3654:        unsigned agentix;
        !          3655:        unsigned length;
        !          3656: {
        !          3657:        return length;
        !          3658: }
        !          3659: 
        !          3660: static void shutdown_exit (void *foo)
        !          3661: {
        !          3662:        exit (0);
        !          3663: }
        !          3664: 
        !          3665: isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
        !          3666:                                     control_object_state_t newstate)
        !          3667: {
        !          3668:        struct interface_info *ip;
        !          3669:        struct client_state *client;
        !          3670:        struct timeval tv;
        !          3671: 
        !          3672:        /* Do the right thing for each interface. */
        !          3673:        for (ip = interfaces; ip; ip = ip -> next) {
        !          3674:            for (client = ip -> client; client; client = client -> next) {
        !          3675:                switch (newstate) {
        !          3676:                  case server_startup:
        !          3677:                    return ISC_R_SUCCESS;
        !          3678: 
        !          3679:                  case server_running:
        !          3680:                    return ISC_R_SUCCESS;
        !          3681: 
        !          3682:                  case server_shutdown:
        !          3683:                    if (client -> active &&
        !          3684:                        client -> active -> expiry > cur_time) {
        !          3685:                            if (client -> config -> do_forward_update)
        !          3686:                                    client_dns_update(client, 0, 0,
        !          3687:                                                    &client->active->address);
        !          3688:                            do_release (client);
        !          3689:                    }
        !          3690:                    break;
        !          3691: 
        !          3692:                  case server_hibernate:
        !          3693:                    state_stop (client);
        !          3694:                    break;
        !          3695: 
        !          3696:                  case server_awaken:
        !          3697:                    state_reboot (client);
        !          3698:                    break;
        !          3699:                }
        !          3700:            }
        !          3701:        }
        !          3702: 
        !          3703:        if (newstate == server_shutdown) {
        !          3704:                tv.tv_sec = cur_tv.tv_sec;
        !          3705:                tv.tv_usec = cur_tv.tv_usec + 1;
        !          3706:                add_timeout(&tv, shutdown_exit, 0, 0, 0);
        !          3707:        }
        !          3708:        return ISC_R_SUCCESS;
        !          3709: }
        !          3710: 
        !          3711: /* Schedule updates to retry occasionally until it no longer times out.
        !          3712:  */
        !          3713: void
        !          3714: dhclient_schedule_updates(struct client_state *client, struct iaddr *addr,
        !          3715:                          int offset)
        !          3716: {
        !          3717:        struct dns_update_state *ustate;
        !          3718:        struct timeval tv;
        !          3719: 
        !          3720:        if (!client->config->do_forward_update)
        !          3721:                return;
        !          3722: 
        !          3723:        ustate = dmalloc(sizeof(*ustate), MDL);
        !          3724: 
        !          3725:        if (ustate != NULL) {
        !          3726:                ustate->client = client;
        !          3727:                ustate->address = *addr;
        !          3728:                ustate->dns_update_timeout = 1;
        !          3729: 
        !          3730:                tv.tv_sec = cur_tv.tv_sec + offset;
        !          3731:                tv.tv_usec = cur_tv.tv_usec;
        !          3732:                add_timeout(&tv, client_dns_update_timeout,
        !          3733:                            ustate, NULL, NULL);
        !          3734:        } else {
        !          3735:                log_error("Unable to allocate dns update state for %s.",
        !          3736:                          piaddr(*addr));
        !          3737:        }
        !          3738: }
        !          3739: 
        !          3740: /* Called after a timeout if the DNS update failed on the previous try.
        !          3741:    Retries the update, and if it times out, schedules a retry after
        !          3742:    ten times as long of a wait. */
        !          3743: 
        !          3744: void client_dns_update_timeout (void *cp)
        !          3745: {
        !          3746:        struct dns_update_state *ustate = cp;
        !          3747:        isc_result_t status = ISC_R_FAILURE;
        !          3748:        struct timeval tv;
        !          3749: 
        !          3750:        /* XXX: DNS TTL is a problem we need to solve properly.  Until
        !          3751:         * that time, 300 is a placeholder default for something that is
        !          3752:         * less insane than a value scaled by lease timeout.
        !          3753:         */
        !          3754:        if ((ustate->client->active != NULL) ||
        !          3755:            (ustate->client->active_lease != NULL))
        !          3756:                status = client_dns_update(ustate->client, 1, 300,
        !          3757:                                           &ustate->address);
        !          3758: 
        !          3759:        if (status == ISC_R_TIMEDOUT) {
        !          3760:                if (ustate->dns_update_timeout < 3600)
        !          3761:                        ustate->dns_update_timeout *= 10;
        !          3762:                tv.tv_sec = cur_tv.tv_sec + ustate->dns_update_timeout;
        !          3763:                tv.tv_usec = cur_tv.tv_usec;
        !          3764:                add_timeout(&tv, client_dns_update_timeout,
        !          3765:                            ustate, NULL, NULL);
        !          3766:        } else
        !          3767:                dfree(ustate, MDL);
        !          3768: }
        !          3769: 
        !          3770: /* See if we should do a DNS update, and if so, do it. */
        !          3771: 
        !          3772: isc_result_t client_dns_update (struct client_state *client, int addp,
        !          3773:                                int ttl, struct iaddr *address)
        !          3774: {
        !          3775:        struct data_string ddns_fwd_name, ddns_dhcid, client_identifier;
        !          3776:        struct option_cache *oc;
        !          3777:        int ignorep;
        !          3778:        int result;
        !          3779:        isc_result_t rcode;
        !          3780: 
        !          3781:        /* If we didn't send an FQDN option, we certainly aren't going to
        !          3782:           be doing an update. */
        !          3783:        if (!client -> sent_options)
        !          3784:                return ISC_R_SUCCESS;
        !          3785: 
        !          3786:        /* If we don't have a lease, we can't do an update. */
        !          3787:        if ((client->active == NULL) && (client->active_lease == NULL))
        !          3788:                return ISC_R_SUCCESS;
        !          3789: 
        !          3790:        /* If we set the no client update flag, don't do the update. */
        !          3791:        if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
        !          3792:                                  FQDN_NO_CLIENT_UPDATE)) &&
        !          3793:            evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
        !          3794:                                           (struct lease *)0, client,
        !          3795:                                           client -> sent_options,
        !          3796:                                           (struct option_state *)0,
        !          3797:                                           &global_scope, oc, MDL))
        !          3798:                return ISC_R_SUCCESS;
        !          3799: 
        !          3800:        /* If we set the "server, please update" flag, or didn't set it
        !          3801:           to false, don't do the update. */
        !          3802:        if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
        !          3803:                                  FQDN_SERVER_UPDATE)) ||
        !          3804:            evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
        !          3805:                                           (struct lease *)0, client,
        !          3806:                                           client -> sent_options,
        !          3807:                                           (struct option_state *)0,
        !          3808:                                           &global_scope, oc, MDL))
        !          3809:                return ISC_R_SUCCESS;
        !          3810: 
        !          3811:        /* If no FQDN option was supplied, don't do the update. */
        !          3812:        memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
        !          3813:        if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
        !          3814:                                  FQDN_FQDN)) ||
        !          3815:            !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
        !          3816:                                    (struct lease *)0, client,
        !          3817:                                    client -> sent_options,
        !          3818:                                    (struct option_state *)0,
        !          3819:                                    &global_scope, oc, MDL))
        !          3820:                return ISC_R_SUCCESS;
        !          3821: 
        !          3822:        /* If this is a DHCPv6 client update, make a dhcid string out of
        !          3823:         * the DUID.  If this is a DHCPv4 client update, choose either
        !          3824:         * the client identifier, if there is one, or the interface's
        !          3825:         * MAC address.
        !          3826:         */
        !          3827:        memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
        !          3828: 
        !          3829:        result = 0;
        !          3830:        memset(&client_identifier, 0, sizeof(client_identifier));
        !          3831:        if (client->active_lease != NULL) {
        !          3832:                if (((oc =
        !          3833:                      lookup_option(&dhcpv6_universe, client->sent_options,
        !          3834:                                    D6O_CLIENTID)) != NULL) &&
        !          3835:                    evaluate_option_cache(&client_identifier, NULL, NULL,
        !          3836:                                          client, client->sent_options, NULL,
        !          3837:                                          &global_scope, oc, MDL)) {
        !          3838:                        /* RFC4701 defines type '2' as being for the DUID
        !          3839:                         * field.  We aren't using RFC4701 DHCID RR's yet,
        !          3840:                         * but this is as good a value as any.
        !          3841:                         */
        !          3842:                        result = get_dhcid(&ddns_dhcid, 2,
        !          3843:                                           client_identifier.data,
        !          3844:                                           client_identifier.len);
        !          3845:                        data_string_forget(&client_identifier, MDL);
        !          3846:                } else
        !          3847:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3848:        } else {
        !          3849:                if (((oc =
        !          3850:                      lookup_option(&dhcp_universe, client->sent_options,
        !          3851:                                    DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) &&
        !          3852:                    evaluate_option_cache(&client_identifier, NULL, NULL,
        !          3853:                                          client, client->sent_options, NULL,
        !          3854:                                          &global_scope, oc, MDL)) {
        !          3855:                        result = get_dhcid(&ddns_dhcid,
        !          3856:                                           DHO_DHCP_CLIENT_IDENTIFIER,
        !          3857:                                           client_identifier.data,
        !          3858:                                           client_identifier.len);
        !          3859:                        data_string_forget(&client_identifier, MDL);
        !          3860:                } else
        !          3861:                        result = get_dhcid(&ddns_dhcid, 0,
        !          3862:                                           client->interface->hw_address.hbuf,
        !          3863:                                           client->interface->hw_address.hlen);
        !          3864:        }
        !          3865:        if (!result) {
        !          3866:                data_string_forget(&ddns_fwd_name, MDL);
        !          3867:                return ISC_R_SUCCESS;
        !          3868:        }
        !          3869: 
        !          3870:        /* Start the resolver, if necessary. */
        !          3871:        if (!resolver_inited) {
        !          3872:                minires_ninit (&resolver_state);
        !          3873:                resolver_inited = 1;
        !          3874:                resolver_state.retrans = 1;
        !          3875:                resolver_state.retry = 1;
        !          3876:        }
        !          3877: 
        !          3878:        /*
        !          3879:         * Perform updates.
        !          3880:         */
        !          3881:        if (ddns_fwd_name.len && ddns_dhcid.len) {
        !          3882:                if (addp)
        !          3883:                        rcode = ddns_update_fwd(&ddns_fwd_name, *address,
        !          3884:                                                &ddns_dhcid, ttl, 1, 1);
        !          3885:                else
        !          3886:                        rcode = ddns_remove_fwd(&ddns_fwd_name, *address,
        !          3887:                                                &ddns_dhcid);
        !          3888:        } else
        !          3889:                rcode = ISC_R_FAILURE;
        !          3890: 
        !          3891:        data_string_forget (&ddns_fwd_name, MDL);
        !          3892:        data_string_forget (&ddns_dhcid, MDL);
        !          3893:        return rcode;
        !          3894: }
        !          3895: 
        !          3896: void
        !          3897: dhcpv4_client_assignments(void)
        !          3898: {
        !          3899:        struct servent *ent;
        !          3900: 
        !          3901:        if (path_dhclient_pid == NULL)
        !          3902:                path_dhclient_pid = _PATH_DHCLIENT_PID;
        !          3903:        if (path_dhclient_db == NULL)
        !          3904:                path_dhclient_db = _PATH_DHCLIENT_DB;
        !          3905: 
        !          3906:        /* Default to the DHCP/BOOTP port. */
        !          3907:        if (!local_port) {
        !          3908:                /* If we're faking a relay agent, and we're not using loopback,
        !          3909:                   use the server port, not the client port. */
        !          3910:                if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
        !          3911:                        local_port = htons(67);
        !          3912:                } else {
        !          3913:                        ent = getservbyname ("dhcpc", "udp");
        !          3914:                        if (!ent)
        !          3915:                                local_port = htons (68);
        !          3916:                        else
        !          3917:                                local_port = ent -> s_port;
        !          3918: #ifndef __CYGWIN32__
        !          3919:                        endservent ();
        !          3920: #endif
        !          3921:                }
        !          3922:        }
        !          3923: 
        !          3924:        /* If we're faking a relay agent, and we're not using loopback,
        !          3925:           we're using the server port, not the client port. */
        !          3926:        if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
        !          3927:                remote_port = local_port;
        !          3928:        } else
        !          3929:                remote_port = htons (ntohs (local_port) - 1);   /* XXX */
        !          3930: }
        !          3931: 
        !          3932: /*
        !          3933:  * The following routines are used to check that certain
        !          3934:  * strings are reasonable before we pass them to the scripts.
        !          3935:  * This avoids some problems with scripts treating the strings
        !          3936:  * as commands - see ticket 23722
        !          3937:  * The domain checking code should be done as part of assembling
        !          3938:  * the string but we are doing it here for now due to time
        !          3939:  * constraints.
        !          3940:  */
        !          3941: 
        !          3942: static int check_domain_name(const char *ptr, size_t len, int dots)
        !          3943: {
        !          3944:        const char *p;
        !          3945: 
        !          3946:        /* not empty or complete length not over 255 characters   */
        !          3947:        if ((len == 0) || (len > 256))
        !          3948:                return(-1);
        !          3949: 
        !          3950:        /* consists of [[:alnum:]-]+ labels separated by [.]      */
        !          3951:        /* a [_] is against RFC but seems to be "widely used"...  */
        !          3952:        for (p=ptr; (*p != 0) && (len-- > 0); p++) {
        !          3953:                if ((*p == '-') || (*p == '_')) {
        !          3954:                        /* not allowed at begin or end of a label */
        !          3955:                        if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
        !          3956:                                return(-1);
        !          3957:                } else if (*p == '.') {
        !          3958:                        /* each label has to be 1-63 characters;
        !          3959:                           we allow [.] at the end ('foo.bar.')   */
        !          3960:                        size_t d = p - ptr;
        !          3961:                        if ((d <= 0) || (d >= 64))
        !          3962:                                return(-1);
        !          3963:                        ptr = p + 1; /* jump to the next label    */
        !          3964:                        if ((dots > 0) && (len > 0))
        !          3965:                                dots--;
        !          3966:                } else if (isalnum((unsigned char)*p) == 0) {
        !          3967:                        /* also numbers at the begin are fine     */
        !          3968:                        return(-1);
        !          3969:                }
        !          3970:        }
        !          3971:        return(dots ? -1 : 0);
        !          3972: }
        !          3973: 
        !          3974: static int check_domain_name_list(const char *ptr, size_t len, int dots)
        !          3975: {
        !          3976:        const char *p;
        !          3977:        int ret = -1; /* at least one needed */
        !          3978: 
        !          3979:        if ((ptr == NULL) || (len == 0))
        !          3980:                return(-1);
        !          3981: 
        !          3982:        for (p=ptr; (*p != 0) && (len > 0); p++, len--) {
        !          3983:                if (*p != ' ')
        !          3984:                        continue;
        !          3985:                if (p > ptr) {
        !          3986:                        if (check_domain_name(ptr, p - ptr, dots) != 0)
        !          3987:                                return(-1);
        !          3988:                        ret = 0;
        !          3989:                }
        !          3990:                ptr = p + 1;
        !          3991:        }
        !          3992:        if (p > ptr)
        !          3993:                return(check_domain_name(ptr, p - ptr, dots));
        !          3994:        else
        !          3995:                return(ret);
        !          3996: }
        !          3997: 
        !          3998: static int check_option_values(struct universe *universe,
        !          3999:                               unsigned int opt,
        !          4000:                               const char *ptr,
        !          4001:                               size_t len)
        !          4002: {
        !          4003:        if (ptr == NULL)
        !          4004:                return(-1);
        !          4005: 
        !          4006:        /* just reject options we want to protect, will be escaped anyway */
        !          4007:        if ((universe == NULL) || (universe == &dhcp_universe)) {
        !          4008:                switch(opt) {
        !          4009:                      case DHO_DOMAIN_NAME:
        !          4010: #ifdef ACCEPT_LIST_IN_DOMAIN_NAME
        !          4011:                              return check_domain_name_list(ptr, len, 0);
        !          4012: #else
        !          4013:                              return check_domain_name(ptr, len, 0);
        !          4014: #endif
        !          4015:                      case DHO_HOST_NAME:
        !          4016:                      case DHO_NIS_DOMAIN:
        !          4017:                      case DHO_NETBIOS_SCOPE:
        !          4018:                        return check_domain_name(ptr, len, 0);
        !          4019:                        break;
        !          4020:                      case DHO_DOMAIN_SEARCH:
        !          4021:                        return check_domain_name_list(ptr, len, 0);
        !          4022:                        break;
        !          4023:                      case DHO_ROOT_PATH:
        !          4024:                        if (len == 0)
        !          4025:                                return(-1);
        !          4026:                        for (; (*ptr != 0) && (len-- > 0); ptr++) {
        !          4027:                                if(!(isalnum((unsigned char)*ptr) ||
        !          4028:                                     *ptr == '#'  || *ptr == '%' ||
        !          4029:                                     *ptr == '+'  || *ptr == '-' ||
        !          4030:                                     *ptr == '_'  || *ptr == ':' ||
        !          4031:                                     *ptr == '.'  || *ptr == ',' ||
        !          4032:                                     *ptr == '@'  || *ptr == '~' ||
        !          4033:                                     *ptr == '\\' || *ptr == '/' ||
        !          4034:                                     *ptr == '['  || *ptr == ']' ||
        !          4035:                                     *ptr == '='  || *ptr == ' '))
        !          4036:                                        return(-1);
        !          4037:                        }
        !          4038:                        return(0);
        !          4039:                        break;
        !          4040:                }
        !          4041:        }
        !          4042: 
        !          4043: #ifdef DHCPv6
        !          4044:        if (universe == &dhcpv6_universe) {
        !          4045:                switch(opt) {
        !          4046:                      case D6O_SIP_SERVERS_DNS:
        !          4047:                      case D6O_DOMAIN_SEARCH:
        !          4048:                      case D6O_NIS_DOMAIN_NAME:
        !          4049:                      case D6O_NISP_DOMAIN_NAME:
        !          4050:                        return check_domain_name_list(ptr, len, 0);
        !          4051:                        break;
        !          4052:                }
        !          4053:        }
        !          4054: #endif
        !          4055: 
        !          4056:        return(0);
        !          4057: }
        !          4058: 
        !          4059: static void
        !          4060: add_reject(struct packet *packet) {
        !          4061:        struct iaddrmatchlist *list;
        !          4062:        
        !          4063:        list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
        !          4064:        if (!list)
        !          4065:                log_fatal ("no memory for reject list!");
        !          4066: 
        !          4067:        /*
        !          4068:         * client_addr is misleading - it is set to source address in common
        !          4069:         * code.
        !          4070:         */
        !          4071:        list->match.addr = packet->client_addr;
        !          4072:        /* Set mask to indicate host address. */
        !          4073:        list->match.mask.len = list->match.addr.len;
        !          4074:        memset(list->match.mask.iabuf, 0xff, sizeof(list->match.mask.iabuf));
        !          4075: 
        !          4076:        /* Append to reject list for the source interface. */
        !          4077:        list->next = packet->interface->client->config->reject_list;
        !          4078:        packet->interface->client->config->reject_list = list;
        !          4079: 
        !          4080:        /*
        !          4081:         * We should inform user that we won't be accepting this server
        !          4082:         * anymore.
        !          4083:         */
        !          4084:        log_info("Server added to list of rejected servers.");
        !          4085: }

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