File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / client / dhclient.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (12 years ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* dhclient.c
    2: 
    3:    DHCP Client. */
    4: 
    5: /*
    6:  * Copyright (c) 2004-2012 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-2012 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, NULL, &client->packet,
 1889: 			     client->packet_length, inaddr_any,
 1890:                              &sockaddr_broadcast, NULL);
 1891:         if (result < 0) {
 1892: 		log_error("%s:%d: Failed to send %d byte long packet over %s "
 1893: 			  "interface.", MDL, client->packet_length,
 1894: 			  client->interface->name);
 1895: 	}
 1896: 
 1897: 	/*
 1898: 	 * If we used 0 microseconds here, and there were other clients on the
 1899: 	 * same network with a synchronized local clock (ntp), and a similar
 1900: 	 * zero-microsecond-scheduler behavior, then we could be participating
 1901: 	 * in a sub-second DOS ttck.
 1902: 	 */
 1903: 	tv.tv_sec = cur_tv.tv_sec + client->interval;
 1904: 	tv.tv_usec = client->interval > 1 ? random() % 1000000 : cur_tv.tv_usec;
 1905: 	add_timeout(&tv, send_discover, client, 0, 0);
 1906: }
 1907: 
 1908: /* state_panic gets called if we haven't received any offers in a preset
 1909:    amount of time.   When this happens, we try to use existing leases that
 1910:    haven't yet expired, and failing that, we call the client script and
 1911:    hope it can do something. */
 1912: 
 1913: void state_panic (cpp)
 1914: 	void *cpp;
 1915: {
 1916: 	struct client_state *client = cpp;
 1917: 	struct client_lease *loop;
 1918: 	struct client_lease *lp;
 1919: 	struct timeval tv;
 1920: 
 1921: 	loop = lp = client -> active;
 1922: 
 1923: 	log_info ("No DHCPOFFERS received.");
 1924: 
 1925: 	/* We may not have an active lease, but we may have some
 1926: 	   predefined leases that we can try. */
 1927: 	if (!client -> active && client -> leases)
 1928: 		goto activate_next;
 1929: 
 1930: 	/* Run through the list of leases and see if one can be used. */
 1931: 	while (client -> active) {
 1932: 		if (client -> active -> expiry > cur_time) {
 1933: 			log_info ("Trying recorded lease %s",
 1934: 			      piaddr (client -> active -> address));
 1935: 			/* Run the client script with the existing
 1936: 			   parameters. */
 1937: 			script_init (client, "TIMEOUT",
 1938: 				     client -> active -> medium);
 1939: 			script_write_params (client, "new_", client -> active);
 1940: 			if (client -> alias)
 1941: 				script_write_params (client, "alias_",
 1942: 						     client -> alias);
 1943: 
 1944: 			/* If the old lease is still good and doesn't
 1945: 			   yet need renewal, go into BOUND state and
 1946: 			   timeout at the renewal time. */
 1947: 			if (!script_go (client)) {
 1948: 			    if (cur_time < client -> active -> renewal) {
 1949: 				client -> state = S_BOUND;
 1950: 				log_info ("bound: renewal in %ld %s.",
 1951: 					  (long)(client -> active -> renewal -
 1952: 						 cur_time), "seconds");
 1953: 				tv.tv_sec = client->active->renewal;
 1954: 				tv.tv_usec = ((client->active->renewal -
 1955: 						    cur_time) > 1) ?
 1956: 						random() % 1000000 :
 1957: 						cur_tv.tv_usec;
 1958: 				add_timeout(&tv, state_bound, client, 0, 0);
 1959: 			    } else {
 1960: 				client -> state = S_BOUND;
 1961: 				log_info ("bound: immediate renewal.");
 1962: 				state_bound (client);
 1963: 			    }
 1964: 			    reinitialize_interfaces ();
 1965: 			    go_daemon ();
 1966: 			    return;
 1967: 			}
 1968: 		}
 1969: 
 1970: 		/* If there are no other leases, give up. */
 1971: 		if (!client -> leases) {
 1972: 			client -> leases = client -> active;
 1973: 			client -> active = (struct client_lease *)0;
 1974: 			break;
 1975: 		}
 1976: 
 1977: 	activate_next:
 1978: 		/* Otherwise, put the active lease at the end of the
 1979: 		   lease list, and try another lease.. */
 1980: 		for (lp = client -> leases; lp -> next; lp = lp -> next)
 1981: 			;
 1982: 		lp -> next = client -> active;
 1983: 		if (lp -> next) {
 1984: 			lp -> next -> next = (struct client_lease *)0;
 1985: 		}
 1986: 		client -> active = client -> leases;
 1987: 		client -> leases = client -> leases -> next;
 1988: 
 1989: 		/* If we already tried this lease, we've exhausted the
 1990: 		   set of leases, so we might as well give up for
 1991: 		   now. */
 1992: 		if (client -> active == loop)
 1993: 			break;
 1994: 		else if (!loop)
 1995: 			loop = client -> active;
 1996: 	}
 1997: 
 1998: 	/* No leases were available, or what was available didn't work, so
 1999: 	   tell the shell script that we failed to allocate an address,
 2000: 	   and try again later. */
 2001: 	if (onetry) {
 2002: 		if (!quiet)
 2003: 			log_info ("Unable to obtain a lease on first try.%s",
 2004: 				  "  Exiting.");
 2005: 		exit (2);
 2006: 	}
 2007: 
 2008: 	log_info ("No working leases in persistent database - sleeping.");
 2009: 	script_init (client, "FAIL", (struct string_list *)0);
 2010: 	if (client -> alias)
 2011: 		script_write_params (client, "alias_", client -> alias);
 2012: 	script_go (client);
 2013: 	client -> state = S_INIT;
 2014: 	tv.tv_sec = cur_tv.tv_sec + ((client->config->retry_interval + 1) / 2 +
 2015: 		    (random() % client->config->retry_interval));
 2016: 	tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
 2017: 			random() % 1000000 : cur_tv.tv_usec;
 2018: 	add_timeout(&tv, state_init, client, 0, 0);
 2019: 	go_daemon ();
 2020: }
 2021: 
 2022: void send_request (cpp)
 2023: 	void *cpp;
 2024: {
 2025: 	struct client_state *client = cpp;
 2026: 
 2027: 	int result;
 2028: 	int interval;
 2029: 	struct sockaddr_in destination;
 2030: 	struct in_addr from;
 2031: 	struct timeval tv;
 2032: 
 2033: 	/* Figure out how long it's been since we started transmitting. */
 2034: 	interval = cur_time - client -> first_sending;
 2035: 
 2036: 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
 2037: 	   past the reboot timeout, go to INIT and see if we can
 2038: 	   DISCOVER an address... */
 2039: 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
 2040: 	   means either that we're on a network with no DHCP server,
 2041: 	   or that our server is down.  In the latter case, assuming
 2042: 	   that there is a backup DHCP server, DHCPDISCOVER will get
 2043: 	   us a new address, but we could also have successfully
 2044: 	   reused our old address.  In the former case, we're hosed
 2045: 	   anyway.  This is not a win-prone situation. */
 2046: 	if ((client -> state == S_REBOOTING ||
 2047: 	     client -> state == S_REQUESTING) &&
 2048: 	    interval > client -> config -> reboot_timeout) {
 2049: 	cancel:
 2050: 		client -> state = S_INIT;
 2051: 		cancel_timeout (send_request, client);
 2052: 		state_init (client);
 2053: 		return;
 2054: 	}
 2055: 
 2056: 	/* If we're in the reboot state, make sure the media is set up
 2057: 	   correctly. */
 2058: 	if (client -> state == S_REBOOTING &&
 2059: 	    !client -> medium &&
 2060: 	    client -> active -> medium ) {
 2061: 		script_init (client, "MEDIUM", client -> active -> medium);
 2062: 
 2063: 		/* If the medium we chose won't fly, go to INIT state. */
 2064: 		if (script_go (client))
 2065: 			goto cancel;
 2066: 
 2067: 		/* Record the medium. */
 2068: 		client -> medium = client -> active -> medium;
 2069: 	}
 2070: 
 2071: 	/* If the lease has expired, relinquish the address and go back
 2072: 	   to the INIT state. */
 2073: 	if (client -> state != S_REQUESTING &&
 2074: 	    cur_time > client -> active -> expiry) {
 2075: 		/* Run the client script with the new parameters. */
 2076: 		script_init (client, "EXPIRE", (struct string_list *)0);
 2077: 		script_write_params (client, "old_", client -> active);
 2078: 		if (client -> alias)
 2079: 			script_write_params (client, "alias_",
 2080: 					     client -> alias);
 2081: 		script_go (client);
 2082: 
 2083: 		/* Now do a preinit on the interface so that we can
 2084: 		   discover a new address. */
 2085: 		script_init (client, "PREINIT", (struct string_list *)0);
 2086: 		if (client -> alias)
 2087: 			script_write_params (client, "alias_",
 2088: 					     client -> alias);
 2089: 		script_go (client);
 2090: 
 2091: 		client -> state = S_INIT;
 2092: 		state_init (client);
 2093: 		return;
 2094: 	}
 2095: 
 2096: 	/* Do the exponential backoff... */
 2097: 	if (!client -> interval)
 2098: 		client -> interval = client -> config -> initial_interval;
 2099: 	else {
 2100: 		client -> interval += ((random () >> 2) %
 2101: 				       (2 * client -> interval));
 2102: 	}
 2103: 
 2104: 	/* Don't backoff past cutoff. */
 2105: 	if (client -> interval >
 2106: 	    client -> config -> backoff_cutoff)
 2107: 		client -> interval =
 2108: 			((client -> config -> backoff_cutoff / 2)
 2109: 			 + ((random () >> 2) %
 2110: 					client -> config -> backoff_cutoff));
 2111: 
 2112: 	/* If the backoff would take us to the expiry time, just set the
 2113: 	   timeout to the expiry time. */
 2114: 	if (client -> state != S_REQUESTING &&
 2115: 	    cur_time + client -> interval > client -> active -> expiry)
 2116: 		client -> interval =
 2117: 			client -> active -> expiry - cur_time + 1;
 2118: 
 2119: 	/* If the lease T2 time has elapsed, or if we're not yet bound,
 2120: 	   broadcast the DHCPREQUEST rather than unicasting. */
 2121: 	if (client -> state == S_REQUESTING ||
 2122: 	    client -> state == S_REBOOTING ||
 2123: 	    cur_time > client -> active -> rebind)
 2124: 		destination.sin_addr = sockaddr_broadcast.sin_addr;
 2125: 	else
 2126: 		memcpy (&destination.sin_addr.s_addr,
 2127: 			client -> destination.iabuf,
 2128: 			sizeof destination.sin_addr.s_addr);
 2129: 	destination.sin_port = remote_port;
 2130: 	destination.sin_family = AF_INET;
 2131: #ifdef HAVE_SA_LEN
 2132: 	destination.sin_len = sizeof destination;
 2133: #endif
 2134: 
 2135: 	if (client -> state == S_RENEWING ||
 2136: 	    client -> state == S_REBINDING)
 2137: 		memcpy (&from, client -> active -> address.iabuf,
 2138: 			sizeof from);
 2139: 	else
 2140: 		from.s_addr = INADDR_ANY;
 2141: 
 2142: 	/* Record the number of seconds since we started sending. */
 2143: 	if (client -> state == S_REQUESTING)
 2144: 		client -> packet.secs = client -> secs;
 2145: 	else {
 2146: 		if (interval < 65536)
 2147: 			client -> packet.secs = htons (interval);
 2148: 		else
 2149: 			client -> packet.secs = htons (65535);
 2150: 	}
 2151: 
 2152: 	log_info ("DHCPREQUEST on %s to %s port %d",
 2153: 	      client -> name ? client -> name : client -> interface -> name,
 2154: 	      inet_ntoa (destination.sin_addr),
 2155: 	      ntohs (destination.sin_port));
 2156: 
 2157: 	if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
 2158: 	    fallback_interface) {
 2159: 		result = send_packet(fallback_interface, NULL, &client->packet,
 2160: 				     client->packet_length, from, &destination,
 2161: 				     NULL);
 2162: 		if (result < 0) {
 2163: 			log_error("%s:%d: Failed to send %d byte long packet "
 2164: 				  "over %s interface.", MDL,
 2165: 				  client->packet_length,
 2166: 				  fallback_interface->name);
 2167: 		}
 2168:         }
 2169: 	else {
 2170: 		/* Send out a packet. */
 2171: 		result = send_packet(client->interface, NULL, &client->packet,
 2172: 				     client->packet_length, from, &destination,
 2173: 				     NULL);
 2174: 		if (result < 0) {
 2175: 			log_error("%s:%d: Failed to send %d byte long packet"
 2176: 				  " over %s interface.", MDL,
 2177: 				  client->packet_length,
 2178: 				  client->interface->name);
 2179: 		}
 2180:         }
 2181: 
 2182: 	tv.tv_sec = cur_tv.tv_sec + client->interval;
 2183: 	tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
 2184: 			random() % 1000000 : cur_tv.tv_usec;
 2185: 	add_timeout(&tv, send_request, client, 0, 0);
 2186: }
 2187: 
 2188: void send_decline (cpp)
 2189: 	void *cpp;
 2190: {
 2191: 	struct client_state *client = cpp;
 2192: 
 2193: 	int result;
 2194: 
 2195: 	log_info ("DHCPDECLINE on %s to %s port %d",
 2196: 	      client->name ? client->name : client->interface->name,
 2197: 	      inet_ntoa(sockaddr_broadcast.sin_addr),
 2198: 	      ntohs(sockaddr_broadcast.sin_port));
 2199: 
 2200: 	/* Send out a packet. */
 2201: 	result = send_packet(client->interface, NULL, &client->packet,
 2202: 			     client->packet_length, inaddr_any,
 2203: 			     &sockaddr_broadcast, NULL);
 2204: 	if (result < 0) {
 2205: 		log_error("%s:%d: Failed to send %d byte long packet over %s"
 2206: 			  " interface.", MDL, client->packet_length,
 2207: 			  client->interface->name);
 2208: 	}
 2209: }
 2210: 
 2211: void send_release (cpp)
 2212: 	void *cpp;
 2213: {
 2214: 	struct client_state *client = cpp;
 2215: 
 2216: 	int result;
 2217: 	struct sockaddr_in destination;
 2218: 	struct in_addr from;
 2219: 
 2220: 	memcpy (&from, client -> active -> address.iabuf,
 2221: 		sizeof from);
 2222: 	memcpy (&destination.sin_addr.s_addr,
 2223: 		client -> destination.iabuf,
 2224: 		sizeof destination.sin_addr.s_addr);
 2225: 	destination.sin_port = remote_port;
 2226: 	destination.sin_family = AF_INET;
 2227: #ifdef HAVE_SA_LEN
 2228: 	destination.sin_len = sizeof destination;
 2229: #endif
 2230: 
 2231: 	/* Set the lease to end now, so that we don't accidentally
 2232: 	   reuse it if we restart before the old expiry time. */
 2233: 	client -> active -> expiry =
 2234: 		client -> active -> renewal =
 2235: 		client -> active -> rebind = cur_time;
 2236: 	if (!write_client_lease (client, client -> active, 1, 1)) {
 2237: 		log_error ("Can't release lease: lease write failed.");
 2238: 		return;
 2239: 	}
 2240: 
 2241: 	log_info ("DHCPRELEASE on %s to %s port %d",
 2242: 	      client -> name ? client -> name : client -> interface -> name,
 2243: 	      inet_ntoa (destination.sin_addr),
 2244: 	      ntohs (destination.sin_port));
 2245: 
 2246: 	if (fallback_interface) {
 2247: 		result = send_packet(fallback_interface, NULL, &client->packet,
 2248: 				      client->packet_length, from, &destination,
 2249: 				      NULL);
 2250: 		if (result < 0) {
 2251: 			log_error("%s:%d: Failed to send %d byte long packet"
 2252: 				  " over %s interface.", MDL,
 2253: 				  client->packet_length,
 2254: 				  fallback_interface->name);
 2255: 		}
 2256:         } else {
 2257: 		/* Send out a packet. */
 2258: 		result = send_packet(client->interface, NULL, &client->packet,
 2259: 				      client->packet_length, from, &destination,
 2260: 				      NULL);
 2261: 		if (result < 0) {
 2262: 			log_error ("%s:%d: Failed to send %d byte long packet"
 2263: 				   " over %s interface.", MDL,
 2264: 				   client->packet_length,
 2265: 				   client->interface->name);
 2266: 		}
 2267: 
 2268:         }
 2269: }
 2270: 
 2271: void
 2272: make_client_options(struct client_state *client, struct client_lease *lease,
 2273: 		    u_int8_t *type, struct option_cache *sid,
 2274: 		    struct iaddr *rip, struct option **prl,
 2275: 		    struct option_state **op)
 2276: {
 2277: 	unsigned i;
 2278: 	struct option_cache *oc;
 2279: 	struct option *option = NULL;
 2280: 	struct buffer *bp = (struct buffer *)0;
 2281: 
 2282: 	/* If there are any leftover options, get rid of them. */
 2283: 	if (*op)
 2284: 		option_state_dereference (op, MDL);
 2285: 
 2286: 	/* Allocate space for options. */
 2287: 	option_state_allocate (op, MDL);
 2288: 
 2289: 	/* Send the server identifier if provided. */
 2290: 	if (sid)
 2291: 		save_option (&dhcp_universe, *op, sid);
 2292: 
 2293: 	oc = (struct option_cache *)0;
 2294: 
 2295: 	/* Send the requested address if provided. */
 2296: 	if (rip) {
 2297: 		client -> requested_address = *rip;
 2298: 		i = DHO_DHCP_REQUESTED_ADDRESS;
 2299: 		if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
 2300: 					      &i, 0, MDL) &&
 2301: 		      make_const_option_cache(&oc, NULL, rip->iabuf, rip->len,
 2302: 					      option, MDL)))
 2303: 			log_error ("can't make requested address cache.");
 2304: 		else {
 2305: 			save_option (&dhcp_universe, *op, oc);
 2306: 			option_cache_dereference (&oc, MDL);
 2307: 		}
 2308: 		option_dereference(&option, MDL);
 2309: 	} else {
 2310: 		client -> requested_address.len = 0;
 2311: 	}
 2312: 
 2313: 	i = DHO_DHCP_MESSAGE_TYPE;
 2314: 	if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0,
 2315: 				      MDL) &&
 2316: 	      make_const_option_cache(&oc, NULL, type, 1, option, MDL)))
 2317: 		log_error ("can't make message type.");
 2318: 	else {
 2319: 		save_option (&dhcp_universe, *op, oc);
 2320: 		option_cache_dereference (&oc, MDL);
 2321: 	}
 2322: 	option_dereference(&option, MDL);
 2323: 
 2324: 	if (prl) {
 2325: 		int len;
 2326: 
 2327: 		/* Probe the length of the list. */
 2328: 		len = 0;
 2329: 		for (i = 0 ; prl[i] != NULL ; i++)
 2330: 			if (prl[i]->universe == &dhcp_universe)
 2331: 				len++;
 2332: 
 2333: 		if (!buffer_allocate (&bp, len, MDL))
 2334: 			log_error ("can't make parameter list buffer.");
 2335: 		else {
 2336: 			unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST;
 2337: 
 2338: 			len = 0;
 2339: 			for (i = 0 ; prl[i] != NULL ; i++)
 2340: 				if (prl[i]->universe == &dhcp_universe)
 2341: 					bp->data[len++] = prl[i]->code;
 2342: 
 2343: 			if (!(option_code_hash_lookup(&option,
 2344: 						      dhcp_universe.code_hash,
 2345: 						      &code, 0, MDL) &&
 2346: 			      make_const_option_cache(&oc, &bp, NULL, len,
 2347: 						      option, MDL)))
 2348: 				log_error ("can't make option cache");
 2349: 			else {
 2350: 				save_option (&dhcp_universe, *op, oc);
 2351: 				option_cache_dereference (&oc, MDL);
 2352: 			}
 2353: 			option_dereference(&option, MDL);
 2354: 		}
 2355: 	}
 2356: 
 2357: 	/* Run statements that need to be run on transmission. */
 2358: 	if (client -> config -> on_transmission)
 2359: 		execute_statements_in_scope
 2360: 			((struct binding_value **)0,
 2361: 			 (struct packet *)0, (struct lease *)0, client,
 2362: 			 (lease ? lease -> options : (struct option_state *)0),
 2363: 			 *op, &global_scope,
 2364: 			 client -> config -> on_transmission,
 2365: 			 (struct group *)0);
 2366: }
 2367: 
 2368: void make_discover (client, lease)
 2369: 	struct client_state *client;
 2370: 	struct client_lease *lease;
 2371: {
 2372: 	unsigned char discover = DHCPDISCOVER;
 2373: 	struct option_state *options = (struct option_state *)0;
 2374: 
 2375: 	memset (&client -> packet, 0, sizeof (client -> packet));
 2376: 
 2377: 	make_client_options (client,
 2378: 			     lease, &discover, (struct option_cache *)0,
 2379: 			     lease ? &lease -> address : (struct iaddr *)0,
 2380: 			     client -> config -> requested_options,
 2381: 			     &options);
 2382: 
 2383: 	/* Set up the option buffer... */
 2384: 	client -> packet_length =
 2385: 		cons_options ((struct packet *)0, &client -> packet,
 2386: 			      (struct lease *)0, client,
 2387: 			      /* maximum packet size */1500,
 2388: 			      (struct option_state *)0,
 2389: 			      options,
 2390: 			      /* scope */ &global_scope,
 2391: 			      /* overload */ 0,
 2392: 			      /* terminate */0,
 2393: 			      /* bootpp    */0,
 2394: 			      (struct data_string *)0,
 2395: 			      client -> config -> vendor_space_name);
 2396: 
 2397: 	option_state_dereference (&options, MDL);
 2398: 	if (client -> packet_length < BOOTP_MIN_LEN)
 2399: 		client -> packet_length = BOOTP_MIN_LEN;
 2400: 
 2401: 	client -> packet.op = BOOTREQUEST;
 2402: 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
 2403: 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
 2404: 	client -> packet.hops = 0;
 2405: 	client -> packet.xid = random ();
 2406: 	client -> packet.secs = 0; /* filled in by send_discover. */
 2407: 
 2408: 	if (can_receive_unicast_unconfigured (client -> interface))
 2409: 		client -> packet.flags = 0;
 2410: 	else
 2411: 		client -> packet.flags = htons (BOOTP_BROADCAST);
 2412: 
 2413: 	memset (&(client -> packet.ciaddr),
 2414: 		0, sizeof client -> packet.ciaddr);
 2415: 	memset (&(client -> packet.yiaddr),
 2416: 		0, sizeof client -> packet.yiaddr);
 2417: 	memset (&(client -> packet.siaddr),
 2418: 		0, sizeof client -> packet.siaddr);
 2419: 	client -> packet.giaddr = giaddr;
 2420: 	if (client -> interface -> hw_address.hlen > 0)
 2421: 	    memcpy (client -> packet.chaddr,
 2422: 		    &client -> interface -> hw_address.hbuf [1],
 2423: 		    (unsigned)(client -> interface -> hw_address.hlen - 1));
 2424: 
 2425: #ifdef DEBUG_PACKET
 2426: 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
 2427: #endif
 2428: }
 2429: 
 2430: 
 2431: void make_request (client, lease)
 2432: 	struct client_state *client;
 2433: 	struct client_lease *lease;
 2434: {
 2435: 	unsigned char request = DHCPREQUEST;
 2436: 	struct option_cache *oc;
 2437: 
 2438: 	memset (&client -> packet, 0, sizeof (client -> packet));
 2439: 
 2440: 	if (client -> state == S_REQUESTING)
 2441: 		oc = lookup_option (&dhcp_universe, lease -> options,
 2442: 				    DHO_DHCP_SERVER_IDENTIFIER);
 2443: 	else
 2444: 		oc = (struct option_cache *)0;
 2445: 
 2446: 	if (client -> sent_options)
 2447: 		option_state_dereference (&client -> sent_options, MDL);
 2448: 
 2449: 	make_client_options (client, lease, &request, oc,
 2450: 			     ((client -> state == S_REQUESTING ||
 2451: 			       client -> state == S_REBOOTING)
 2452: 			      ? &lease -> address
 2453: 			      : (struct iaddr *)0),
 2454: 			     client -> config -> requested_options,
 2455: 			     &client -> sent_options);
 2456: 
 2457: 	/* Set up the option buffer... */
 2458: 	client -> packet_length =
 2459: 		cons_options ((struct packet *)0, &client -> packet,
 2460: 			      (struct lease *)0, client,
 2461: 			      /* maximum packet size */1500,
 2462: 			      (struct option_state *)0,
 2463: 			      client -> sent_options,
 2464: 			      /* scope */ &global_scope,
 2465: 			      /* overload */ 0,
 2466: 			      /* terminate */0,
 2467: 			      /* bootpp    */0,
 2468: 			      (struct data_string *)0,
 2469: 			      client -> config -> vendor_space_name);
 2470: 
 2471: 	if (client -> packet_length < BOOTP_MIN_LEN)
 2472: 		client -> packet_length = BOOTP_MIN_LEN;
 2473: 
 2474: 	client -> packet.op = BOOTREQUEST;
 2475: 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
 2476: 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
 2477: 	client -> packet.hops = 0;
 2478: 	client -> packet.xid = client -> xid;
 2479: 	client -> packet.secs = 0; /* Filled in by send_request. */
 2480: 
 2481: 	/* If we own the address we're requesting, put it in ciaddr;
 2482: 	   otherwise set ciaddr to zero. */
 2483: 	if (client -> state == S_BOUND ||
 2484: 	    client -> state == S_RENEWING ||
 2485: 	    client -> state == S_REBINDING) {
 2486: 		memcpy (&client -> packet.ciaddr,
 2487: 			lease -> address.iabuf, lease -> address.len);
 2488: 		client -> packet.flags = 0;
 2489: 	} else {
 2490: 		memset (&client -> packet.ciaddr, 0,
 2491: 			sizeof client -> packet.ciaddr);
 2492: 		if (can_receive_unicast_unconfigured (client -> interface))
 2493: 			client -> packet.flags = 0;
 2494: 		else
 2495: 			client -> packet.flags = htons (BOOTP_BROADCAST);
 2496: 	}
 2497: 
 2498: 	memset (&client -> packet.yiaddr, 0,
 2499: 		sizeof client -> packet.yiaddr);
 2500: 	memset (&client -> packet.siaddr, 0,
 2501: 		sizeof client -> packet.siaddr);
 2502: 	if (client -> state != S_BOUND &&
 2503: 	    client -> state != S_RENEWING)
 2504: 		client -> packet.giaddr = giaddr;
 2505: 	else
 2506: 		memset (&client -> packet.giaddr, 0,
 2507: 			sizeof client -> packet.giaddr);
 2508: 	if (client -> interface -> hw_address.hlen > 0)
 2509: 	    memcpy (client -> packet.chaddr,
 2510: 		    &client -> interface -> hw_address.hbuf [1],
 2511: 		    (unsigned)(client -> interface -> hw_address.hlen - 1));
 2512: 
 2513: #ifdef DEBUG_PACKET
 2514: 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
 2515: #endif
 2516: }
 2517: 
 2518: void make_decline (client, lease)
 2519: 	struct client_state *client;
 2520: 	struct client_lease *lease;
 2521: {
 2522: 	unsigned char decline = DHCPDECLINE;
 2523: 	struct option_cache *oc;
 2524: 
 2525: 	struct option_state *options = (struct option_state *)0;
 2526: 
 2527: 	/* Create the options cache. */
 2528: 	oc = lookup_option (&dhcp_universe, lease -> options,
 2529: 			    DHO_DHCP_SERVER_IDENTIFIER);
 2530: 	make_client_options(client, lease, &decline, oc, &lease->address,
 2531: 			    NULL, &options);
 2532: 
 2533: 	/* Consume the options cache into the option buffer. */
 2534: 	memset (&client -> packet, 0, sizeof (client -> packet));
 2535: 	client -> packet_length =
 2536: 		cons_options ((struct packet *)0, &client -> packet,
 2537: 			      (struct lease *)0, client, 0,
 2538: 			      (struct option_state *)0, options,
 2539: 			      &global_scope, 0, 0, 0, (struct data_string *)0,
 2540: 			      client -> config -> vendor_space_name);
 2541: 
 2542: 	/* Destroy the options cache. */
 2543: 	option_state_dereference (&options, MDL);
 2544: 
 2545: 	if (client -> packet_length < BOOTP_MIN_LEN)
 2546: 		client -> packet_length = BOOTP_MIN_LEN;
 2547: 
 2548: 	client -> packet.op = BOOTREQUEST;
 2549: 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
 2550: 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
 2551: 	client -> packet.hops = 0;
 2552: 	client -> packet.xid = client -> xid;
 2553: 	client -> packet.secs = 0; /* Filled in by send_request. */
 2554: 	if (can_receive_unicast_unconfigured (client -> interface))
 2555: 		client -> packet.flags = 0;
 2556: 	else
 2557: 		client -> packet.flags = htons (BOOTP_BROADCAST);
 2558: 
 2559: 	/* ciaddr must always be zero. */
 2560: 	memset (&client -> packet.ciaddr, 0,
 2561: 		sizeof client -> packet.ciaddr);
 2562: 	memset (&client -> packet.yiaddr, 0,
 2563: 		sizeof client -> packet.yiaddr);
 2564: 	memset (&client -> packet.siaddr, 0,
 2565: 		sizeof client -> packet.siaddr);
 2566: 	client -> packet.giaddr = giaddr;
 2567: 	memcpy (client -> packet.chaddr,
 2568: 		&client -> interface -> hw_address.hbuf [1],
 2569: 		client -> interface -> hw_address.hlen);
 2570: 
 2571: #ifdef DEBUG_PACKET
 2572: 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
 2573: #endif
 2574: }
 2575: 
 2576: void make_release (client, lease)
 2577: 	struct client_state *client;
 2578: 	struct client_lease *lease;
 2579: {
 2580: 	unsigned char request = DHCPRELEASE;
 2581: 	struct option_cache *oc;
 2582: 
 2583: 	struct option_state *options = (struct option_state *)0;
 2584: 
 2585: 	memset (&client -> packet, 0, sizeof (client -> packet));
 2586: 
 2587: 	oc = lookup_option (&dhcp_universe, lease -> options,
 2588: 			    DHO_DHCP_SERVER_IDENTIFIER);
 2589: 	make_client_options(client, lease, &request, oc, NULL, NULL, &options);
 2590: 
 2591: 	/* Set up the option buffer... */
 2592: 	client -> packet_length =
 2593: 		cons_options ((struct packet *)0, &client -> packet,
 2594: 			      (struct lease *)0, client,
 2595: 			      /* maximum packet size */1500,
 2596: 			      (struct option_state *)0,
 2597: 			      options,
 2598: 			      /* scope */ &global_scope,
 2599: 			      /* overload */ 0,
 2600: 			      /* terminate */0,
 2601: 			      /* bootpp    */0,
 2602: 			      (struct data_string *)0,
 2603: 			      client -> config -> vendor_space_name);
 2604: 
 2605: 	if (client -> packet_length < BOOTP_MIN_LEN)
 2606: 		client -> packet_length = BOOTP_MIN_LEN;
 2607: 	option_state_dereference (&options, MDL);
 2608: 
 2609: 	client -> packet.op = BOOTREQUEST;
 2610: 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
 2611: 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
 2612: 	client -> packet.hops = 0;
 2613: 	client -> packet.xid = random ();
 2614: 	client -> packet.secs = 0;
 2615: 	client -> packet.flags = 0;
 2616: 	memcpy (&client -> packet.ciaddr,
 2617: 		lease -> address.iabuf, lease -> address.len);
 2618: 	memset (&client -> packet.yiaddr, 0,
 2619: 		sizeof client -> packet.yiaddr);
 2620: 	memset (&client -> packet.siaddr, 0,
 2621: 		sizeof client -> packet.siaddr);
 2622: 	client -> packet.giaddr = giaddr;
 2623: 	memcpy (client -> packet.chaddr,
 2624: 		&client -> interface -> hw_address.hbuf [1],
 2625: 		client -> interface -> hw_address.hlen);
 2626: 
 2627: #ifdef DEBUG_PACKET
 2628: 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
 2629: #endif
 2630: }
 2631: 
 2632: void destroy_client_lease (lease)
 2633: 	struct client_lease *lease;
 2634: {
 2635: 	if (lease -> server_name)
 2636: 		dfree (lease -> server_name, MDL);
 2637: 	if (lease -> filename)
 2638: 		dfree (lease -> filename, MDL);
 2639: 	option_state_dereference (&lease -> options, MDL);
 2640: 	free_client_lease (lease, MDL);
 2641: }
 2642: 
 2643: FILE *leaseFile = NULL;
 2644: int leases_written = 0;
 2645: 
 2646: void rewrite_client_leases ()
 2647: {
 2648: 	struct interface_info *ip;
 2649: 	struct client_state *client;
 2650: 	struct client_lease *lp;
 2651: 
 2652: 	if (leaseFile != NULL)
 2653: 		fclose (leaseFile);
 2654: 	leaseFile = fopen (path_dhclient_db, "w");
 2655: 	if (leaseFile == NULL) {
 2656: 		log_error ("can't create %s: %m", path_dhclient_db);
 2657: 		return;
 2658: 	}
 2659: 
 2660: 	/* If there is a default duid, write it out. */
 2661: 	if (default_duid.len != 0)
 2662: 		write_duid(&default_duid);
 2663: 
 2664: 	/* Write out all the leases attached to configured interfaces that
 2665: 	   we know about. */
 2666: 	for (ip = interfaces; ip; ip = ip -> next) {
 2667: 		for (client = ip -> client; client; client = client -> next) {
 2668: 			for (lp = client -> leases; lp; lp = lp -> next) {
 2669: 				write_client_lease (client, lp, 1, 0);
 2670: 			}
 2671: 			if (client -> active)
 2672: 				write_client_lease (client,
 2673: 						    client -> active, 1, 0);
 2674: 
 2675: 			if (client->active_lease != NULL)
 2676: 				write_client6_lease(client,
 2677: 						    client->active_lease,
 2678: 						    1, 0);
 2679: 
 2680: 			/* Reset last_write after rewrites. */
 2681: 			client->last_write = 0;
 2682: 		}
 2683: 	}
 2684: 
 2685: 	/* Write out any leases that are attached to interfaces that aren't
 2686: 	   currently configured. */
 2687: 	for (ip = dummy_interfaces; ip; ip = ip -> next) {
 2688: 		for (client = ip -> client; client; client = client -> next) {
 2689: 			for (lp = client -> leases; lp; lp = lp -> next) {
 2690: 				write_client_lease (client, lp, 1, 0);
 2691: 			}
 2692: 			if (client -> active)
 2693: 				write_client_lease (client,
 2694: 						    client -> active, 1, 0);
 2695: 
 2696: 			if (client->active_lease != NULL)
 2697: 				write_client6_lease(client,
 2698: 						    client->active_lease,
 2699: 						    1, 0);
 2700: 
 2701: 			/* Reset last_write after rewrites. */
 2702: 			client->last_write = 0;
 2703: 		}
 2704: 	}
 2705: 	fflush (leaseFile);
 2706: }
 2707: 
 2708: void write_lease_option (struct option_cache *oc,
 2709: 			 struct packet *packet, struct lease *lease,
 2710: 			 struct client_state *client_state,
 2711: 			 struct option_state *in_options,
 2712: 			 struct option_state *cfg_options,
 2713: 			 struct binding_scope **scope,
 2714: 			 struct universe *u, void *stuff)
 2715: {
 2716: 	const char *name, *dot;
 2717: 	struct data_string ds;
 2718: 	char *preamble = stuff;
 2719: 
 2720: 	memset (&ds, 0, sizeof ds);
 2721: 
 2722: 	if (u != &dhcp_universe) {
 2723: 		name = u -> name;
 2724: 		dot = ".";
 2725: 	} else {
 2726: 		name = "";
 2727: 		dot = "";
 2728: 	}
 2729: 	if (evaluate_option_cache (&ds, packet, lease, client_state,
 2730: 				   in_options, cfg_options, scope, oc, MDL)) {
 2731: 		/* The option name */
 2732: 		fprintf(leaseFile, "%soption %s%s%s", preamble,
 2733: 			name, dot, oc->option->name);
 2734: 
 2735: 		/* The option value if there is one */
 2736: 		if ((oc->option->format == NULL) ||
 2737: 		    (oc->option->format[0] != 'Z')) {
 2738: 			fprintf(leaseFile, " %s",
 2739: 				pretty_print_option(oc->option, ds.data,
 2740: 						    ds.len, 1, 1));
 2741: 		}
 2742: 
 2743: 		/* The closing semi-colon and newline */
 2744: 		fprintf(leaseFile, ";\n");
 2745: 
 2746: 		data_string_forget (&ds, MDL);
 2747: 	}
 2748: }
 2749: 
 2750: /* Write an option cache to the lease store. */
 2751: static void
 2752: write_options(struct client_state *client, struct option_state *options,
 2753: 	      const char *preamble)
 2754: {
 2755: 	int i;
 2756: 
 2757: 	for (i = 0; i < options->universe_count; i++) {
 2758: 		option_space_foreach(NULL, NULL, client, NULL, options,
 2759: 				     &global_scope, universes[i],
 2760: 				     (char *)preamble, write_lease_option);
 2761: 	}
 2762: }
 2763: 
 2764: /* Write the default DUID to the lease store. */
 2765: static isc_result_t
 2766: write_duid(struct data_string *duid)
 2767: {
 2768: 	char *str;
 2769: 	int stat;
 2770: 
 2771: 	if ((duid == NULL) || (duid->len <= 2))
 2772: 		return ISC_R_INVALIDARG;
 2773: 
 2774: 	if (leaseFile == NULL) {	/* XXX? */
 2775: 		leaseFile = fopen(path_dhclient_db, "w");
 2776: 		if (leaseFile == NULL) {
 2777: 			log_error("can't create %s: %m", path_dhclient_db);
 2778: 			return ISC_R_IOERROR;
 2779: 		}
 2780: 	}
 2781: 
 2782: 	/* It would make more sense to write this as a hex string,
 2783: 	 * but our function to do that (print_hex_n) uses a fixed
 2784: 	 * length buffer...and we can't guarantee a duid would be
 2785: 	 * less than the fixed length.
 2786: 	 */
 2787: 	str = quotify_buf(duid->data, duid->len, MDL);
 2788: 	if (str == NULL)
 2789: 		return ISC_R_NOMEMORY;
 2790: 
 2791: 	stat = fprintf(leaseFile, "default-duid \"%s\";\n", str);
 2792: 	dfree(str, MDL);
 2793: 	if (stat <= 0)
 2794: 		return ISC_R_IOERROR;
 2795: 
 2796: 	if (fflush(leaseFile) != 0)
 2797: 		return ISC_R_IOERROR;
 2798: 
 2799: 	return ISC_R_SUCCESS;
 2800: }
 2801: 
 2802: /* Write a DHCPv6 lease to the store. */
 2803: isc_result_t
 2804: write_client6_lease(struct client_state *client, struct dhc6_lease *lease,
 2805: 		    int rewrite, int sync)
 2806: {
 2807: 	struct dhc6_ia *ia;
 2808: 	struct dhc6_addr *addr;
 2809: 	int stat;
 2810: 	const char *ianame;
 2811: 
 2812: 	/* This should include the current lease. */
 2813: 	if (!rewrite && (leases_written++ > 20)) {
 2814: 		rewrite_client_leases();
 2815: 		leases_written = 0;
 2816: 		return ISC_R_SUCCESS;
 2817: 	}
 2818: 
 2819: 	if (client == NULL || lease == NULL)
 2820: 		return ISC_R_INVALIDARG;
 2821: 
 2822: 	if (leaseFile == NULL) {	/* XXX? */
 2823: 		leaseFile = fopen(path_dhclient_db, "w");
 2824: 		if (leaseFile == NULL) {
 2825: 			log_error("can't create %s: %m", path_dhclient_db);
 2826: 			return ISC_R_IOERROR;
 2827: 		}
 2828: 	}
 2829: 
 2830: 	stat = fprintf(leaseFile, "lease6 {\n");
 2831: 	if (stat <= 0)
 2832: 		return ISC_R_IOERROR;
 2833: 
 2834: 	stat = fprintf(leaseFile, "  interface \"%s\";\n",
 2835: 		       client->interface->name);
 2836: 	if (stat <= 0)
 2837: 		return ISC_R_IOERROR;
 2838: 
 2839: 	for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
 2840: 		switch (ia->ia_type) {
 2841: 			case D6O_IA_NA:
 2842: 			default:
 2843: 				ianame = "ia-na";
 2844: 				break;
 2845: 			case D6O_IA_TA:
 2846: 				ianame = "ia-ta";
 2847: 				break;
 2848: 			case D6O_IA_PD:
 2849: 				ianame = "ia-pd";
 2850: 				break;
 2851: 		}
 2852: 		stat = fprintf(leaseFile, "  %s %s {\n",
 2853: 			       ianame, print_hex_1(4, ia->iaid, 12));
 2854: 		if (stat <= 0)
 2855: 			return ISC_R_IOERROR;
 2856: 
 2857: 		if (ia->ia_type != D6O_IA_TA)
 2858: 			stat = fprintf(leaseFile, "    starts %d;\n"
 2859: 						  "    renew %u;\n"
 2860: 						  "    rebind %u;\n",
 2861: 				       (int)ia->starts, ia->renew, ia->rebind);
 2862: 		else
 2863: 			stat = fprintf(leaseFile, "    starts %d;\n",
 2864: 				       (int)ia->starts);
 2865: 		if (stat <= 0)
 2866: 			return ISC_R_IOERROR;
 2867: 
 2868: 		for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
 2869: 			if (ia->ia_type != D6O_IA_PD)
 2870: 				stat = fprintf(leaseFile,
 2871: 					       "    iaaddr %s {\n",
 2872: 					       piaddr(addr->address));
 2873: 			else
 2874: 				stat = fprintf(leaseFile,
 2875: 					       "    iaprefix %s/%d {\n",
 2876: 					       piaddr(addr->address),
 2877: 					       (int)addr->plen);
 2878: 			if (stat <= 0)
 2879: 				return ISC_R_IOERROR;
 2880: 
 2881: 			stat = fprintf(leaseFile, "      starts %d;\n"
 2882: 						  "      preferred-life %u;\n"
 2883: 						  "      max-life %u;\n",
 2884: 				       (int)addr->starts, addr->preferred_life,
 2885: 				       addr->max_life);
 2886: 			if (stat <= 0)
 2887: 				return ISC_R_IOERROR;
 2888: 
 2889: 			if (addr->options != NULL)
 2890: 				write_options(client, addr->options, "      ");
 2891: 
 2892: 			stat = fprintf(leaseFile, "    }\n");
 2893: 			if (stat <= 0)
 2894: 				return ISC_R_IOERROR;
 2895: 		}
 2896: 
 2897: 		if (ia->options != NULL)
 2898: 			write_options(client, ia->options, "    ");
 2899: 
 2900: 		stat = fprintf(leaseFile, "  }\n");
 2901: 		if (stat <= 0)
 2902: 			return ISC_R_IOERROR;
 2903: 	}
 2904: 
 2905: 	if (lease->released) {
 2906: 		stat = fprintf(leaseFile, "  released;\n");
 2907: 		if (stat <= 0)
 2908: 			return ISC_R_IOERROR;
 2909: 	}
 2910: 
 2911: 	if (lease->options != NULL)
 2912: 		write_options(client, lease->options, "  ");
 2913: 
 2914: 	stat = fprintf(leaseFile, "}\n");
 2915: 	if (stat <= 0)
 2916: 		return ISC_R_IOERROR;
 2917: 
 2918: 	if (fflush(leaseFile) != 0)
 2919: 		return ISC_R_IOERROR;
 2920: 
 2921: 	if (sync) {
 2922: 		if (fsync(fileno(leaseFile)) < 0) {
 2923: 			log_error("write_client_lease: fsync(): %m");
 2924: 			return ISC_R_IOERROR;
 2925: 		}
 2926: 	}
 2927: 
 2928: 	return ISC_R_SUCCESS;
 2929: }
 2930: 
 2931: int write_client_lease (client, lease, rewrite, makesure)
 2932: 	struct client_state *client;
 2933: 	struct client_lease *lease;
 2934: 	int rewrite;
 2935: 	int makesure;
 2936: {
 2937: 	struct data_string ds;
 2938: 	int errors = 0;
 2939: 	char *s;
 2940: 	const char *tval;
 2941: 
 2942: 	if (!rewrite) {
 2943: 		if (leases_written++ > 20) {
 2944: 			rewrite_client_leases ();
 2945: 			leases_written = 0;
 2946: 		}
 2947: 	}
 2948: 
 2949: 	/* If the lease came from the config file, we don't need to stash
 2950: 	   a copy in the lease database. */
 2951: 	if (lease -> is_static)
 2952: 		return 1;
 2953: 
 2954: 	if (leaseFile == NULL) {	/* XXX */
 2955: 		leaseFile = fopen (path_dhclient_db, "w");
 2956: 		if (leaseFile == NULL) {
 2957: 			log_error ("can't create %s: %m", path_dhclient_db);
 2958: 			return 0;
 2959: 		}
 2960: 	}
 2961: 
 2962: 	errno = 0;
 2963: 	fprintf (leaseFile, "lease {\n");
 2964: 	if (lease -> is_bootp) {
 2965: 		fprintf (leaseFile, "  bootp;\n");
 2966: 		if (errno) {
 2967: 			++errors;
 2968: 			errno = 0;
 2969: 		}
 2970: 	}
 2971: 	fprintf (leaseFile, "  interface \"%s\";\n",
 2972: 		 client -> interface -> name);
 2973: 	if (errno) {
 2974: 		++errors;
 2975: 		errno = 0;
 2976: 	}
 2977: 	if (client -> name) {
 2978: 		fprintf (leaseFile, "  name \"%s\";\n", client -> name);
 2979: 		if (errno) {
 2980: 			++errors;
 2981: 			errno = 0;
 2982: 		}
 2983: 	}
 2984: 	fprintf (leaseFile, "  fixed-address %s;\n",
 2985: 		 piaddr (lease -> address));
 2986: 	if (errno) {
 2987: 		++errors;
 2988: 		errno = 0;
 2989: 	}
 2990: 	if (lease -> filename) {
 2991: 		s = quotify_string (lease -> filename, MDL);
 2992: 		if (s) {
 2993: 			fprintf (leaseFile, "  filename \"%s\";\n", s);
 2994: 			if (errno) {
 2995: 				++errors;
 2996: 				errno = 0;
 2997: 			}
 2998: 			dfree (s, MDL);
 2999: 		} else
 3000: 			errors++;
 3001: 
 3002: 	}
 3003: 	if (lease->server_name != NULL) {
 3004: 		s = quotify_string(lease->server_name, MDL);
 3005: 		if (s != NULL) {
 3006: 			fprintf(leaseFile, "  server-name \"%s\";\n", s);
 3007: 			if (errno) {
 3008: 				++errors;
 3009: 				errno = 0;
 3010: 			}
 3011: 			dfree(s, MDL);
 3012: 		} else
 3013: 			++errors;
 3014: 	}
 3015: 	if (lease -> medium) {
 3016: 		s = quotify_string (lease -> medium -> string, MDL);
 3017: 		if (s) {
 3018: 			fprintf (leaseFile, "  medium \"%s\";\n", s);
 3019: 			if (errno) {
 3020: 				++errors;
 3021: 				errno = 0;
 3022: 			}
 3023: 			dfree (s, MDL);
 3024: 		} else
 3025: 			errors++;
 3026: 	}
 3027: 	if (errno != 0) {
 3028: 		errors++;
 3029: 		errno = 0;
 3030: 	}
 3031: 
 3032: 	memset (&ds, 0, sizeof ds);
 3033: 
 3034: 	write_options(client, lease->options, "  ");
 3035: 
 3036: 	tval = print_time(lease->renewal);
 3037: 	if (tval == NULL ||
 3038: 	    fprintf(leaseFile, "  renew %s\n", tval) < 0)
 3039: 		errors++;
 3040: 
 3041: 	tval = print_time(lease->rebind);
 3042: 	if (tval == NULL ||
 3043: 	    fprintf(leaseFile, "  rebind %s\n", tval) < 0)
 3044: 		errors++;
 3045: 
 3046: 	tval = print_time(lease->expiry);
 3047: 	if (tval == NULL ||
 3048: 	    fprintf(leaseFile, "  expire %s\n", tval) < 0)
 3049: 		errors++;
 3050: 
 3051: 	if (fprintf(leaseFile, "}\n") < 0)
 3052: 		errors++;
 3053: 
 3054: 	if (fflush(leaseFile) != 0)
 3055: 		errors++;
 3056: 
 3057: 	client->last_write = cur_time;
 3058: 
 3059: 	if (!errors && makesure) {
 3060: 		if (fsync (fileno (leaseFile)) < 0) {
 3061: 			log_info ("write_client_lease: %m");
 3062: 			return 0;
 3063: 		}
 3064: 	}
 3065: 
 3066: 	return errors ? 0 : 1;
 3067: }
 3068: 
 3069: /* Variables holding name of script and file pointer for writing to
 3070:    script.   Needless to say, this is not reentrant - only one script
 3071:    can be invoked at a time. */
 3072: char scriptName [256];
 3073: FILE *scriptFile;
 3074: 
 3075: void script_init (client, reason, medium)
 3076: 	struct client_state *client;
 3077: 	const char *reason;
 3078: 	struct string_list *medium;
 3079: {
 3080: 	struct string_list *sl, *next;
 3081: 
 3082: 	if (client) {
 3083: 		for (sl = client -> env; sl; sl = next) {
 3084: 			next = sl -> next;
 3085: 			dfree (sl, MDL);
 3086: 		}
 3087: 		client -> env = (struct string_list *)0;
 3088: 		client -> envc = 0;
 3089: 
 3090: 		if (client -> interface) {
 3091: 			client_envadd (client, "", "interface", "%s",
 3092: 				       client -> interface -> name);
 3093: 		}
 3094: 		if (client -> name)
 3095: 			client_envadd (client,
 3096: 				       "", "client", "%s", client -> name);
 3097: 		if (medium)
 3098: 			client_envadd (client,
 3099: 				       "", "medium", "%s", medium -> string);
 3100: 
 3101: 		client_envadd (client, "", "reason", "%s", reason);
 3102: 		client_envadd (client, "", "pid", "%ld", (long int)getpid ());
 3103: 	}
 3104: }
 3105: 
 3106: void client_option_envadd (struct option_cache *oc,
 3107: 			   struct packet *packet, struct lease *lease,
 3108: 			   struct client_state *client_state,
 3109: 			   struct option_state *in_options,
 3110: 			   struct option_state *cfg_options,
 3111: 			   struct binding_scope **scope,
 3112: 			   struct universe *u, void *stuff)
 3113: {
 3114: 	struct envadd_state *es = stuff;
 3115: 	struct data_string data;
 3116: 	memset (&data, 0, sizeof data);
 3117: 
 3118: 	if (evaluate_option_cache (&data, packet, lease, client_state,
 3119: 				   in_options, cfg_options, scope, oc, MDL)) {
 3120: 		if (data.len) {
 3121: 			char name [256];
 3122: 			if (dhcp_option_ev_name (name, sizeof name,
 3123: 						 oc->option)) {
 3124: 				const char *value;
 3125: 				value = pretty_print_option(oc->option,
 3126: 							    data.data,
 3127: 							    data.len, 0, 0);
 3128: 				size_t length = strlen(value);
 3129: 
 3130: 				if (check_option_values(oc->option->universe,
 3131: 							oc->option->code,
 3132: 							value, length) == 0) {
 3133: 					client_envadd(es->client, es->prefix,
 3134: 						      name, "%s", value);
 3135: 				} else {
 3136: 					log_error("suspect value in %s "
 3137: 						  "option - discarded",
 3138: 						  name);
 3139: 				}
 3140: 				data_string_forget (&data, MDL);
 3141: 			}
 3142: 		}
 3143: 	}
 3144: }
 3145: 
 3146: void script_write_params (client, prefix, lease)
 3147: 	struct client_state *client;
 3148: 	const char *prefix;
 3149: 	struct client_lease *lease;
 3150: {
 3151: 	int i;
 3152: 	struct data_string data;
 3153: 	struct option_cache *oc;
 3154: 	struct envadd_state es;
 3155: 
 3156: 	es.client = client;
 3157: 	es.prefix = prefix;
 3158: 
 3159: 	client_envadd (client,
 3160: 		       prefix, "ip_address", "%s", piaddr (lease -> address));
 3161: 
 3162: 	/* For the benefit of Linux (and operating systems which may
 3163: 	   have similar needs), compute the network address based on
 3164: 	   the supplied ip address and netmask, if provided.  Also
 3165: 	   compute the broadcast address (the host address all ones
 3166: 	   broadcast address, not the host address all zeroes
 3167: 	   broadcast address). */
 3168: 
 3169: 	memset (&data, 0, sizeof data);
 3170: 	oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
 3171: 	if (oc && evaluate_option_cache (&data, (struct packet *)0,
 3172: 					 (struct lease *)0, client,
 3173: 					 (struct option_state *)0,
 3174: 					 lease -> options,
 3175: 					 &global_scope, oc, MDL)) {
 3176: 		if (data.len > 3) {
 3177: 			struct iaddr netmask, subnet, broadcast;
 3178: 
 3179: 			/*
 3180: 			 * No matter the length of the subnet-mask option,
 3181: 			 * use only the first four octets.  Note that
 3182: 			 * subnet-mask options longer than 4 octets are not
 3183: 			 * in conformance with RFC 2132, but servers with this
 3184: 			 * flaw do exist.
 3185: 			 */
 3186: 			memcpy(netmask.iabuf, data.data, 4);
 3187: 			netmask.len = 4;
 3188: 			data_string_forget (&data, MDL);
 3189: 
 3190: 			subnet = subnet_number (lease -> address, netmask);
 3191: 			if (subnet.len) {
 3192: 			    client_envadd (client, prefix, "network_number",
 3193: 					   "%s", piaddr (subnet));
 3194: 
 3195: 			    oc = lookup_option (&dhcp_universe,
 3196: 						lease -> options,
 3197: 						DHO_BROADCAST_ADDRESS);
 3198: 			    if (!oc ||
 3199: 				!(evaluate_option_cache
 3200: 				  (&data, (struct packet *)0,
 3201: 				   (struct lease *)0, client,
 3202: 				   (struct option_state *)0,
 3203: 				   lease -> options,
 3204: 				   &global_scope, oc, MDL))) {
 3205: 				broadcast = broadcast_addr (subnet, netmask);
 3206: 				if (broadcast.len) {
 3207: 				    client_envadd (client,
 3208: 						   prefix, "broadcast_address",
 3209: 						   "%s", piaddr (broadcast));
 3210: 				}
 3211: 			    }
 3212: 			}
 3213: 		}
 3214: 		data_string_forget (&data, MDL);
 3215: 	}
 3216: 
 3217: 	if (lease->filename) {
 3218: 		if (check_option_values(NULL, DHO_ROOT_PATH,
 3219: 					lease->filename,
 3220: 					strlen(lease->filename)) == 0) {
 3221: 			client_envadd(client, prefix, "filename",
 3222: 				      "%s", lease->filename);
 3223: 		} else {
 3224: 			log_error("suspect value in %s "
 3225: 				  "option - discarded",
 3226: 				  lease->filename);
 3227: 		}
 3228: 	}
 3229: 
 3230: 	if (lease->server_name) {
 3231: 		if (check_option_values(NULL, DHO_HOST_NAME,
 3232: 					lease->server_name,
 3233: 					strlen(lease->server_name)) == 0 ) {
 3234: 			client_envadd (client, prefix, "server_name",
 3235: 				       "%s", lease->server_name);
 3236: 		} else {
 3237: 			log_error("suspect value in %s "
 3238: 				  "option - discarded",
 3239: 				  lease->server_name);
 3240: 		}
 3241: 	}
 3242: 
 3243: 	for (i = 0; i < lease -> options -> universe_count; i++) {
 3244: 		option_space_foreach ((struct packet *)0, (struct lease *)0,
 3245: 				      client, (struct option_state *)0,
 3246: 				      lease -> options, &global_scope,
 3247: 				      universes [i],
 3248: 				      &es, client_option_envadd);
 3249: 	}
 3250: 	client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
 3251: }
 3252: 
 3253: int script_go (client)
 3254: 	struct client_state *client;
 3255: {
 3256: 	char *scriptName;
 3257: 	char *argv [2];
 3258: 	char **envp;
 3259: 	char reason [] = "REASON=NBI";
 3260: 	static char client_path [] = CLIENT_PATH;
 3261: 	int i;
 3262: 	struct string_list *sp, *next;
 3263: 	int pid, wpid, wstatus;
 3264: 
 3265: 	if (client)
 3266: 		scriptName = client -> config -> script_name;
 3267: 	else
 3268: 		scriptName = top_level_config.script_name;
 3269: 
 3270: 	envp = dmalloc (((client ? client -> envc : 2) +
 3271: 			 client_env_count + 2) * sizeof (char *), MDL);
 3272: 	if (!envp) {
 3273: 		log_error ("No memory for client script environment.");
 3274: 		return 0;
 3275: 	}
 3276: 	i = 0;
 3277: 	/* Copy out the environment specified on the command line,
 3278: 	   if any. */
 3279: 	for (sp = client_env; sp; sp = sp -> next) {
 3280: 		envp [i++] = sp -> string;
 3281: 	}
 3282: 	/* Copy out the environment specified by dhclient. */
 3283: 	if (client) {
 3284: 		for (sp = client -> env; sp; sp = sp -> next) {
 3285: 			envp [i++] = sp -> string;
 3286: 		}
 3287: 	} else {
 3288: 		envp [i++] = reason;
 3289: 	}
 3290: 	/* Set $PATH. */
 3291: 	envp [i++] = client_path;
 3292: 	envp [i] = (char *)0;
 3293: 
 3294: 	argv [0] = scriptName;
 3295: 	argv [1] = (char *)0;
 3296: 
 3297: 	pid = fork ();
 3298: 	if (pid < 0) {
 3299: 		log_error ("fork: %m");
 3300: 		wstatus = 0;
 3301: 	} else if (pid) {
 3302: 		do {
 3303: 			wpid = wait (&wstatus);
 3304: 		} while (wpid != pid && wpid > 0);
 3305: 		if (wpid < 0) {
 3306: 			log_error ("wait: %m");
 3307: 			wstatus = 0;
 3308: 		}
 3309: 	} else {
 3310: 		/* We don't want to pass an open file descriptor for
 3311: 		 * dhclient.leases when executing dhclient-script.
 3312: 		 */
 3313: 		if (leaseFile != NULL)
 3314: 			fclose(leaseFile);
 3315: 		execve (scriptName, argv, envp);
 3316: 		log_error ("execve (%s, ...): %m", scriptName);
 3317: 		exit (0);
 3318: 	}
 3319: 
 3320: 	if (client) {
 3321: 		for (sp = client -> env; sp; sp = next) {
 3322: 			next = sp -> next;
 3323: 			dfree (sp, MDL);
 3324: 		}
 3325: 		client -> env = (struct string_list *)0;
 3326: 		client -> envc = 0;
 3327: 	}
 3328: 	dfree (envp, MDL);
 3329: 	gettimeofday(&cur_tv, NULL);
 3330: 	return (WIFEXITED (wstatus) ?
 3331: 		WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
 3332: }
 3333: 
 3334: void client_envadd (struct client_state *client,
 3335: 		    const char *prefix, const char *name, const char *fmt, ...)
 3336: {
 3337: 	char spbuf [1024];
 3338: 	char *s;
 3339: 	unsigned len;
 3340: 	struct string_list *val;
 3341: 	va_list list;
 3342: 
 3343: 	va_start (list, fmt);
 3344: 	len = vsnprintf (spbuf, sizeof spbuf, fmt, list);
 3345: 	va_end (list);
 3346: 
 3347: 	val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
 3348: 		       len + sizeof *val, MDL);
 3349: 	if (!val)
 3350: 		return;
 3351: 	s = val -> string;
 3352: 	strcpy (s, prefix);
 3353: 	strcat (s, name);
 3354: 	s += strlen (s);
 3355: 	*s++ = '=';
 3356: 	if (len >= sizeof spbuf) {
 3357: 		va_start (list, fmt);
 3358: 		vsnprintf (s, len + 1, fmt, list);
 3359: 		va_end (list);
 3360: 	} else
 3361: 		strcpy (s, spbuf);
 3362: 	val -> next = client -> env;
 3363: 	client -> env = val;
 3364: 	client -> envc++;
 3365: }
 3366: 
 3367: int dhcp_option_ev_name (buf, buflen, option)
 3368: 	char *buf;
 3369: 	size_t buflen;
 3370: 	struct option *option;
 3371: {
 3372: 	int i, j;
 3373: 	const char *s;
 3374: 
 3375: 	j = 0;
 3376: 	if (option -> universe != &dhcp_universe) {
 3377: 		s = option -> universe -> name;
 3378: 		i = 0;
 3379: 	} else {
 3380: 		s = option -> name;
 3381: 		i = 1;
 3382: 	}
 3383: 
 3384: 	do {
 3385: 		while (*s) {
 3386: 			if (j + 1 == buflen)
 3387: 				return 0;
 3388: 			if (*s == '-')
 3389: 				buf [j++] = '_';
 3390: 			else
 3391: 				buf [j++] = *s;
 3392: 			++s;
 3393: 		}
 3394: 		if (!i) {
 3395: 			s = option -> name;
 3396: 			if (j + 1 == buflen)
 3397: 				return 0;
 3398: 			buf [j++] = '_';
 3399: 		}
 3400: 		++i;
 3401: 	} while (i != 2);
 3402: 
 3403: 	buf [j] = 0;
 3404: 	return 1;
 3405: }
 3406: 
 3407: void go_daemon ()
 3408: {
 3409: 	static int state = 0;
 3410: 	int pid;
 3411: 
 3412: 	/* Don't become a daemon if the user requested otherwise. */
 3413: 	if (no_daemon) {
 3414: 		write_client_pid_file ();
 3415: 		return;
 3416: 	}
 3417: 
 3418: 	/* Only do it once. */
 3419: 	if (state)
 3420: 		return;
 3421: 	state = 1;
 3422: 
 3423: 	/* Stop logging to stderr... */
 3424: 	log_perror = 0;
 3425: 
 3426: 	/* Become a daemon... */
 3427: 	if ((pid = fork ()) < 0)
 3428: 		log_fatal ("Can't fork daemon: %m");
 3429: 	else if (pid)
 3430: 		exit (0);
 3431: 	/* Become session leader and get pid... */
 3432: 	pid = setsid ();
 3433: 
 3434: 	/* Close standard I/O descriptors. */
 3435: 	close(0);
 3436: 	close(1);
 3437: 	close(2);
 3438: 
 3439: 	/* Reopen them on /dev/null. */
 3440: 	open("/dev/null", O_RDWR);
 3441: 	open("/dev/null", O_RDWR);
 3442: 	open("/dev/null", O_RDWR);
 3443: 
 3444: 	write_client_pid_file ();
 3445: 
 3446: 	IGNORE_RET (chdir("/"));
 3447: }
 3448: 
 3449: void write_client_pid_file ()
 3450: {
 3451: 	FILE *pf;
 3452: 	int pfdesc;
 3453: 
 3454: 	/* nothing to do if the user doesn't want a pid file */
 3455: 	if (no_pid_file == ISC_TRUE) {
 3456: 		return;
 3457: 	}
 3458: 
 3459: 	pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
 3460: 
 3461: 	if (pfdesc < 0) {
 3462: 		log_error ("Can't create %s: %m", path_dhclient_pid);
 3463: 		return;
 3464: 	}
 3465: 
 3466: 	pf = fdopen (pfdesc, "w");
 3467: 	if (!pf) {
 3468: 		close(pfdesc);
 3469: 		log_error ("Can't fdopen %s: %m", path_dhclient_pid);
 3470: 	} else {
 3471: 		fprintf (pf, "%ld\n", (long)getpid ());
 3472: 		fclose (pf);
 3473: 	}
 3474: }
 3475: 
 3476: void client_location_changed ()
 3477: {
 3478: 	struct interface_info *ip;
 3479: 	struct client_state *client;
 3480: 
 3481: 	for (ip = interfaces; ip; ip = ip -> next) {
 3482: 		for (client = ip -> client; client; client = client -> next) {
 3483: 			switch (client -> state) {
 3484: 			      case S_SELECTING:
 3485: 				cancel_timeout (send_discover, client);
 3486: 				break;
 3487: 
 3488: 			      case S_BOUND:
 3489: 				cancel_timeout (state_bound, client);
 3490: 				break;
 3491: 
 3492: 			      case S_REBOOTING:
 3493: 			      case S_REQUESTING:
 3494: 			      case S_RENEWING:
 3495: 				cancel_timeout (send_request, client);
 3496: 				break;
 3497: 
 3498: 			      case S_INIT:
 3499: 			      case S_REBINDING:
 3500: 			      case S_STOPPED:
 3501: 				break;
 3502: 			}
 3503: 			client -> state = S_INIT;
 3504: 			state_reboot (client);
 3505: 		}
 3506: 	}
 3507: }
 3508: 
 3509: void do_release(client)
 3510: 	struct client_state *client;
 3511: {
 3512: 	struct data_string ds;
 3513: 	struct option_cache *oc;
 3514: 
 3515: 	/* Pick a random xid. */
 3516: 	client -> xid = random ();
 3517: 
 3518: 	/* is there even a lease to release? */
 3519: 	if (client -> active) {
 3520: 		/* Make a DHCPRELEASE packet, and set appropriate per-interface
 3521: 		   flags. */
 3522: 		make_release (client, client -> active);
 3523: 
 3524: 		memset (&ds, 0, sizeof ds);
 3525: 		oc = lookup_option (&dhcp_universe,
 3526: 				    client -> active -> options,
 3527: 				    DHO_DHCP_SERVER_IDENTIFIER);
 3528: 		if (oc &&
 3529: 		    evaluate_option_cache (&ds, (struct packet *)0,
 3530: 					   (struct lease *)0, client,
 3531: 					   (struct option_state *)0,
 3532: 					   client -> active -> options,
 3533: 					   &global_scope, oc, MDL)) {
 3534: 			if (ds.len > 3) {
 3535: 				memcpy (client -> destination.iabuf,
 3536: 					ds.data, 4);
 3537: 				client -> destination.len = 4;
 3538: 			} else
 3539: 				client -> destination = iaddr_broadcast;
 3540: 
 3541: 			data_string_forget (&ds, MDL);
 3542: 		} else
 3543: 			client -> destination = iaddr_broadcast;
 3544: 		client -> first_sending = cur_time;
 3545: 		client -> interval = client -> config -> initial_interval;
 3546: 
 3547: 		/* Zap the medium list... */
 3548: 		client -> medium = (struct string_list *)0;
 3549: 
 3550: 		/* Send out the first and only DHCPRELEASE packet. */
 3551: 		send_release (client);
 3552: 
 3553: 		/* Do the client script RELEASE operation. */
 3554: 		script_init (client,
 3555: 			     "RELEASE", (struct string_list *)0);
 3556: 		if (client -> alias)
 3557: 			script_write_params (client, "alias_",
 3558: 					     client -> alias);
 3559: 		script_write_params (client, "old_", client -> active);
 3560: 		script_go (client);
 3561: 	}
 3562: 
 3563: 	/* Cancel any timeouts. */
 3564: 	cancel_timeout (state_bound, client);
 3565: 	cancel_timeout (send_discover, client);
 3566: 	cancel_timeout (state_init, client);
 3567: 	cancel_timeout (send_request, client);
 3568: 	cancel_timeout (state_reboot, client);
 3569: 	client -> state = S_STOPPED;
 3570: }
 3571: 
 3572: int dhclient_interface_shutdown_hook (struct interface_info *interface)
 3573: {
 3574: 	do_release (interface -> client);
 3575: 
 3576: 	return 1;
 3577: }
 3578: 
 3579: int dhclient_interface_discovery_hook (struct interface_info *tmp)
 3580: {
 3581: 	struct interface_info *last, *ip;
 3582: 	/* See if we can find the client from dummy_interfaces */
 3583: 	last = 0;
 3584: 	for (ip = dummy_interfaces; ip; ip = ip -> next) {
 3585: 		if (!strcmp (ip -> name, tmp -> name)) {
 3586: 			/* Remove from dummy_interfaces */
 3587: 			if (last) {
 3588: 				ip = (struct interface_info *)0;
 3589: 				interface_reference (&ip, last -> next, MDL);
 3590: 				interface_dereference (&last -> next, MDL);
 3591: 				if (ip -> next) {
 3592: 					interface_reference (&last -> next,
 3593: 							     ip -> next, MDL);
 3594: 					interface_dereference (&ip -> next,
 3595: 							       MDL);
 3596: 				}
 3597: 			} else {
 3598: 				ip = (struct interface_info *)0;
 3599: 				interface_reference (&ip,
 3600: 						     dummy_interfaces, MDL);
 3601: 				interface_dereference (&dummy_interfaces, MDL);
 3602: 				if (ip -> next) {
 3603: 					interface_reference (&dummy_interfaces,
 3604: 							     ip -> next, MDL);
 3605: 					interface_dereference (&ip -> next,
 3606: 							       MDL);
 3607: 				}
 3608: 			}
 3609: 			/* Copy "client" to tmp */
 3610: 			if (ip -> client) {
 3611: 				tmp -> client = ip -> client;
 3612: 				tmp -> client -> interface = tmp;
 3613: 			}
 3614: 			interface_dereference (&ip, MDL);
 3615: 			break;
 3616: 		}
 3617: 		last = ip;
 3618: 	}
 3619: 	return 1;
 3620: }
 3621: 
 3622: isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
 3623: {
 3624: 	struct interface_info *ip;
 3625: 	struct client_state *client;
 3626: 
 3627: 	/* This code needs some rethinking.   It doesn't test against
 3628: 	   a signal name, and it just kind of bulls into doing something
 3629: 	   that may or may not be appropriate. */
 3630: 
 3631: 	if (interfaces) {
 3632: 		interface_reference (&interface -> next, interfaces, MDL);
 3633: 		interface_dereference (&interfaces, MDL);
 3634: 	}
 3635: 	interface_reference (&interfaces, interface, MDL);
 3636: 
 3637: 	discover_interfaces (DISCOVER_UNCONFIGURED);
 3638: 
 3639: 	for (ip = interfaces; ip; ip = ip -> next) {
 3640: 		/* If interfaces were specified, don't configure
 3641: 		   interfaces that weren't specified! */
 3642: 		if (ip -> flags & INTERFACE_RUNNING ||
 3643: 		   (ip -> flags & (INTERFACE_REQUESTED |
 3644: 				     INTERFACE_AUTOMATIC)) !=
 3645: 		     INTERFACE_REQUESTED)
 3646: 			continue;
 3647: 		script_init (ip -> client,
 3648: 			     "PREINIT", (struct string_list *)0);
 3649: 		if (ip -> client -> alias)
 3650: 			script_write_params (ip -> client, "alias_",
 3651: 					     ip -> client -> alias);
 3652: 		script_go (ip -> client);
 3653: 	}
 3654: 
 3655: 	discover_interfaces (interfaces_requested != 0
 3656: 			     ? DISCOVER_REQUESTED
 3657: 			     : DISCOVER_RUNNING);
 3658: 
 3659: 	for (ip = interfaces; ip; ip = ip -> next) {
 3660: 		if (ip -> flags & INTERFACE_RUNNING)
 3661: 			continue;
 3662: 		ip -> flags |= INTERFACE_RUNNING;
 3663: 		for (client = ip->client ; client ; client = client->next) {
 3664: 			client->state = S_INIT;
 3665: 			state_reboot(client);
 3666: 		}
 3667: 	}
 3668: 	return ISC_R_SUCCESS;
 3669: }
 3670: 
 3671: /* The client should never receive a relay agent information option,
 3672:    so if it does, log it and discard it. */
 3673: 
 3674: int parse_agent_information_option (packet, len, data)
 3675: 	struct packet *packet;
 3676: 	int len;
 3677: 	u_int8_t *data;
 3678: {
 3679: 	return 1;
 3680: }
 3681: 
 3682: /* The client never sends relay agent information options. */
 3683: 
 3684: unsigned cons_agent_information_options (cfg_options, outpacket,
 3685: 					 agentix, length)
 3686: 	struct option_state *cfg_options;
 3687: 	struct dhcp_packet *outpacket;
 3688: 	unsigned agentix;
 3689: 	unsigned length;
 3690: {
 3691: 	return length;
 3692: }
 3693: 
 3694: static void shutdown_exit (void *foo)
 3695: {
 3696: 	exit (0);
 3697: }
 3698: 
 3699: isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
 3700: 				     control_object_state_t newstate)
 3701: {
 3702: 	struct interface_info *ip;
 3703: 	struct client_state *client;
 3704: 	struct timeval tv;
 3705: 
 3706: 	/* Do the right thing for each interface. */
 3707: 	for (ip = interfaces; ip; ip = ip -> next) {
 3708: 	    for (client = ip -> client; client; client = client -> next) {
 3709: 		switch (newstate) {
 3710: 		  case server_startup:
 3711: 		    return ISC_R_SUCCESS;
 3712: 
 3713: 		  case server_running:
 3714: 		    return ISC_R_SUCCESS;
 3715: 
 3716: 		  case server_shutdown:
 3717: 		    if (client -> active &&
 3718: 			client -> active -> expiry > cur_time) {
 3719: 			    if (client -> config -> do_forward_update)
 3720: 				    client_dns_update(client, 0, 0,
 3721: 						    &client->active->address);
 3722: 			    do_release (client);
 3723: 		    }
 3724: 		    break;
 3725: 
 3726: 		  case server_hibernate:
 3727: 		    state_stop (client);
 3728: 		    break;
 3729: 
 3730: 		  case server_awaken:
 3731: 		    state_reboot (client);
 3732: 		    break;
 3733: 		}
 3734: 	    }
 3735: 	}
 3736: 
 3737: 	if (newstate == server_shutdown) {
 3738: 		tv.tv_sec = cur_tv.tv_sec;
 3739: 		tv.tv_usec = cur_tv.tv_usec + 1;
 3740: 		add_timeout(&tv, shutdown_exit, 0, 0, 0);
 3741: 	}
 3742: 	return ISC_R_SUCCESS;
 3743: }
 3744: 
 3745: /* Schedule updates to retry occasionally until it no longer times out.
 3746:  */
 3747: void
 3748: dhclient_schedule_updates(struct client_state *client, struct iaddr *addr,
 3749: 			  int offset)
 3750: {
 3751: 	struct dns_update_state *ustate;
 3752: 	struct timeval tv;
 3753: 
 3754: 	if (!client->config->do_forward_update)
 3755: 		return;
 3756: 
 3757: 	ustate = dmalloc(sizeof(*ustate), MDL);
 3758: 
 3759: 	if (ustate != NULL) {
 3760: 		ustate->client = client;
 3761: 		ustate->address = *addr;
 3762: 		ustate->dns_update_timeout = 1;
 3763: 
 3764: 		tv.tv_sec = cur_tv.tv_sec + offset;
 3765: 		tv.tv_usec = cur_tv.tv_usec;
 3766: 		add_timeout(&tv, client_dns_update_timeout,
 3767: 			    ustate, NULL, NULL);
 3768: 	} else {
 3769: 		log_error("Unable to allocate dns update state for %s.",
 3770: 			  piaddr(*addr));
 3771: 	}
 3772: }
 3773: 
 3774: /* Called after a timeout if the DNS update failed on the previous try.
 3775:    Retries the update, and if it times out, schedules a retry after
 3776:    ten times as long of a wait. */
 3777: 
 3778: void client_dns_update_timeout (void *cp)
 3779: {
 3780: 	struct dns_update_state *ustate = cp;
 3781: 	isc_result_t status = ISC_R_FAILURE;
 3782: 	struct timeval tv;
 3783: 
 3784: 	/* XXX: DNS TTL is a problem we need to solve properly.  Until
 3785: 	 * that time, 300 is a placeholder default for something that is
 3786: 	 * less insane than a value scaled by lease timeout.
 3787: 	 */
 3788: 	if ((ustate->client->active != NULL) ||
 3789: 	    (ustate->client->active_lease != NULL))
 3790: 		status = client_dns_update(ustate->client, 1, 300,
 3791: 					   &ustate->address);
 3792: 
 3793: 	if (status == ISC_R_TIMEDOUT) {
 3794: 		if (ustate->dns_update_timeout < 3600)
 3795: 			ustate->dns_update_timeout *= 10;
 3796: 		tv.tv_sec = cur_tv.tv_sec + ustate->dns_update_timeout;
 3797: 		tv.tv_usec = cur_tv.tv_usec;
 3798: 		add_timeout(&tv, client_dns_update_timeout,
 3799: 			    ustate, NULL, NULL);
 3800: 	} else
 3801: 		dfree(ustate, MDL);
 3802: }
 3803: 
 3804: /* See if we should do a DNS update, and if so, do it. */
 3805: 
 3806: isc_result_t client_dns_update (struct client_state *client, int addp,
 3807: 				int ttl, struct iaddr *address)
 3808: {
 3809: 	struct data_string ddns_fwd_name, ddns_dhcid, client_identifier;
 3810: 	struct option_cache *oc;
 3811: 	int ignorep;
 3812: 	int result;
 3813: 	isc_result_t rcode;
 3814: 
 3815: 	/* If we didn't send an FQDN option, we certainly aren't going to
 3816: 	   be doing an update. */
 3817: 	if (!client -> sent_options)
 3818: 		return ISC_R_SUCCESS;
 3819: 
 3820: 	/* If we don't have a lease, we can't do an update. */
 3821: 	if ((client->active == NULL) && (client->active_lease == NULL))
 3822: 		return ISC_R_SUCCESS;
 3823: 
 3824: 	/* If we set the no client update flag, don't do the update. */
 3825: 	if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
 3826: 				  FQDN_NO_CLIENT_UPDATE)) &&
 3827: 	    evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
 3828: 					   (struct lease *)0, client,
 3829: 					   client -> sent_options,
 3830: 					   (struct option_state *)0,
 3831: 					   &global_scope, oc, MDL))
 3832: 		return ISC_R_SUCCESS;
 3833: 
 3834: 	/* If we set the "server, please update" flag, or didn't set it
 3835: 	   to false, don't do the update. */
 3836: 	if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
 3837: 				  FQDN_SERVER_UPDATE)) ||
 3838: 	    evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
 3839: 					   (struct lease *)0, client,
 3840: 					   client -> sent_options,
 3841: 					   (struct option_state *)0,
 3842: 					   &global_scope, oc, MDL))
 3843: 		return ISC_R_SUCCESS;
 3844: 
 3845: 	/* If no FQDN option was supplied, don't do the update. */
 3846: 	memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
 3847: 	if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
 3848: 				  FQDN_FQDN)) ||
 3849: 	    !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
 3850: 				    (struct lease *)0, client,
 3851: 				    client -> sent_options,
 3852: 				    (struct option_state *)0,
 3853: 				    &global_scope, oc, MDL))
 3854: 		return ISC_R_SUCCESS;
 3855: 
 3856: 	/* If this is a DHCPv6 client update, make a dhcid string out of
 3857: 	 * the DUID.  If this is a DHCPv4 client update, choose either
 3858: 	 * the client identifier, if there is one, or the interface's
 3859: 	 * MAC address.
 3860: 	 */
 3861: 	memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
 3862: 
 3863: 	result = 0;
 3864: 	memset(&client_identifier, 0, sizeof(client_identifier));
 3865: 	if (client->active_lease != NULL) {
 3866: 		if (((oc =
 3867: 		      lookup_option(&dhcpv6_universe, client->sent_options,
 3868: 				    D6O_CLIENTID)) != NULL) &&
 3869: 		    evaluate_option_cache(&client_identifier, NULL, NULL,
 3870: 					  client, client->sent_options, NULL,
 3871: 					  &global_scope, oc, MDL)) {
 3872: 			/* RFC4701 defines type '2' as being for the DUID
 3873: 			 * field.  We aren't using RFC4701 DHCID RR's yet,
 3874: 			 * but this is as good a value as any.
 3875: 			 */
 3876: 			result = get_dhcid(&ddns_dhcid, 2,
 3877: 					   client_identifier.data,
 3878: 					   client_identifier.len);
 3879: 			data_string_forget(&client_identifier, MDL);
 3880: 		} else
 3881: 			log_fatal("Impossible condition at %s:%d.", MDL);
 3882: 	} else {
 3883: 		if (((oc =
 3884: 		      lookup_option(&dhcp_universe, client->sent_options,
 3885: 				    DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) &&
 3886: 		    evaluate_option_cache(&client_identifier, NULL, NULL,
 3887: 					  client, client->sent_options, NULL,
 3888: 					  &global_scope, oc, MDL)) {
 3889: 			result = get_dhcid(&ddns_dhcid,
 3890: 					   DHO_DHCP_CLIENT_IDENTIFIER,
 3891: 					   client_identifier.data,
 3892: 					   client_identifier.len);
 3893: 			data_string_forget(&client_identifier, MDL);
 3894: 		} else
 3895: 			result = get_dhcid(&ddns_dhcid, 0,
 3896: 					   client->interface->hw_address.hbuf,
 3897: 					   client->interface->hw_address.hlen);
 3898: 	}
 3899: 	if (!result) {
 3900: 		data_string_forget(&ddns_fwd_name, MDL);
 3901: 		return ISC_R_SUCCESS;
 3902: 	}
 3903: 
 3904: 	/* Start the resolver, if necessary. */
 3905: 	if (!resolver_inited) {
 3906: 		minires_ninit (&resolver_state);
 3907: 		resolver_inited = 1;
 3908: 		resolver_state.retrans = 1;
 3909: 		resolver_state.retry = 1;
 3910: 	}
 3911: 
 3912: 	/*
 3913: 	 * Perform updates.
 3914: 	 */
 3915: 	if (ddns_fwd_name.len && ddns_dhcid.len) {
 3916: 		if (addp)
 3917: 			rcode = ddns_update_fwd(&ddns_fwd_name, *address,
 3918: 						&ddns_dhcid, ttl, 1, 1);
 3919: 		else
 3920: 			rcode = ddns_remove_fwd(&ddns_fwd_name, *address,
 3921: 						&ddns_dhcid);
 3922: 	} else
 3923: 		rcode = ISC_R_FAILURE;
 3924: 
 3925: 	data_string_forget (&ddns_fwd_name, MDL);
 3926: 	data_string_forget (&ddns_dhcid, MDL);
 3927: 	return rcode;
 3928: }
 3929: 
 3930: void
 3931: dhcpv4_client_assignments(void)
 3932: {
 3933: 	struct servent *ent;
 3934: 
 3935: 	if (path_dhclient_pid == NULL)
 3936: 		path_dhclient_pid = _PATH_DHCLIENT_PID;
 3937: 	if (path_dhclient_db == NULL)
 3938: 		path_dhclient_db = _PATH_DHCLIENT_DB;
 3939: 
 3940: 	/* Default to the DHCP/BOOTP port. */
 3941: 	if (!local_port) {
 3942: 		/* If we're faking a relay agent, and we're not using loopback,
 3943: 		   use the server port, not the client port. */
 3944: 		if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
 3945: 			local_port = htons(67);
 3946: 		} else {
 3947: 			ent = getservbyname ("dhcpc", "udp");
 3948: 			if (!ent)
 3949: 				local_port = htons (68);
 3950: 			else
 3951: 				local_port = ent -> s_port;
 3952: #ifndef __CYGWIN32__
 3953: 			endservent ();
 3954: #endif
 3955: 		}
 3956: 	}
 3957: 
 3958: 	/* If we're faking a relay agent, and we're not using loopback,
 3959: 	   we're using the server port, not the client port. */
 3960: 	if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
 3961: 		remote_port = local_port;
 3962: 	} else
 3963: 		remote_port = htons (ntohs (local_port) - 1);   /* XXX */
 3964: }
 3965: 
 3966: /*
 3967:  * The following routines are used to check that certain
 3968:  * strings are reasonable before we pass them to the scripts.
 3969:  * This avoids some problems with scripts treating the strings
 3970:  * as commands - see ticket 23722
 3971:  * The domain checking code should be done as part of assembling
 3972:  * the string but we are doing it here for now due to time
 3973:  * constraints.
 3974:  */
 3975: 
 3976: static int check_domain_name(const char *ptr, size_t len, int dots)
 3977: {
 3978: 	const char *p;
 3979: 
 3980: 	/* not empty or complete length not over 255 characters   */
 3981: 	if ((len == 0) || (len > 256))
 3982: 		return(-1);
 3983: 
 3984: 	/* consists of [[:alnum:]-]+ labels separated by [.]      */
 3985: 	/* a [_] is against RFC but seems to be "widely used"...  */
 3986: 	for (p=ptr; (*p != 0) && (len-- > 0); p++) {
 3987: 		if ((*p == '-') || (*p == '_')) {
 3988: 			/* not allowed at begin or end of a label */
 3989: 			if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
 3990: 				return(-1);
 3991: 		} else if (*p == '.') {
 3992: 			/* each label has to be 1-63 characters;
 3993: 			   we allow [.] at the end ('foo.bar.')   */
 3994: 			size_t d = p - ptr;
 3995: 			if ((d <= 0) || (d >= 64))
 3996: 				return(-1);
 3997: 			ptr = p + 1; /* jump to the next label    */
 3998: 			if ((dots > 0) && (len > 0))
 3999: 				dots--;
 4000: 		} else if (isalnum((unsigned char)*p) == 0) {
 4001: 			/* also numbers at the begin are fine     */
 4002: 			return(-1);
 4003: 		}
 4004: 	}
 4005: 	return(dots ? -1 : 0);
 4006: }
 4007: 
 4008: static int check_domain_name_list(const char *ptr, size_t len, int dots)
 4009: {
 4010: 	const char *p;
 4011: 	int ret = -1; /* at least one needed */
 4012: 
 4013: 	if ((ptr == NULL) || (len == 0))
 4014: 		return(-1);
 4015: 
 4016: 	for (p=ptr; (*p != 0) && (len > 0); p++, len--) {
 4017: 		if (*p != ' ')
 4018: 			continue;
 4019: 		if (p > ptr) {
 4020: 			if (check_domain_name(ptr, p - ptr, dots) != 0)
 4021: 				return(-1);
 4022: 			ret = 0;
 4023: 		}
 4024: 		ptr = p + 1;
 4025: 	}
 4026: 	if (p > ptr)
 4027: 		return(check_domain_name(ptr, p - ptr, dots));
 4028: 	else
 4029: 		return(ret);
 4030: }
 4031: 
 4032: static int check_option_values(struct universe *universe,
 4033: 			       unsigned int opt,
 4034: 			       const char *ptr,
 4035: 			       size_t len)
 4036: {
 4037: 	if (ptr == NULL)
 4038: 		return(-1);
 4039: 
 4040: 	/* just reject options we want to protect, will be escaped anyway */
 4041: 	if ((universe == NULL) || (universe == &dhcp_universe)) {
 4042: 		switch(opt) {
 4043: 		      case DHO_DOMAIN_NAME:
 4044: #ifdef ACCEPT_LIST_IN_DOMAIN_NAME
 4045: 			      return check_domain_name_list(ptr, len, 0);
 4046: #else
 4047: 			      return check_domain_name(ptr, len, 0);
 4048: #endif
 4049: 		      case DHO_HOST_NAME:
 4050: 		      case DHO_NIS_DOMAIN:
 4051: 		      case DHO_NETBIOS_SCOPE:
 4052: 			return check_domain_name(ptr, len, 0);
 4053: 			break;
 4054: 		      case DHO_DOMAIN_SEARCH:
 4055: 			return check_domain_name_list(ptr, len, 0);
 4056: 			break;
 4057: 		      case DHO_ROOT_PATH:
 4058: 			if (len == 0)
 4059: 				return(-1);
 4060: 			for (; (*ptr != 0) && (len-- > 0); ptr++) {
 4061: 				if(!(isalnum((unsigned char)*ptr) ||
 4062: 				     *ptr == '#'  || *ptr == '%' ||
 4063: 				     *ptr == '+'  || *ptr == '-' ||
 4064: 				     *ptr == '_'  || *ptr == ':' ||
 4065: 				     *ptr == '.'  || *ptr == ',' ||
 4066: 				     *ptr == '@'  || *ptr == '~' ||
 4067: 				     *ptr == '\\' || *ptr == '/' ||
 4068: 				     *ptr == '['  || *ptr == ']' ||
 4069: 				     *ptr == '='  || *ptr == ' '))
 4070: 					return(-1);
 4071: 			}
 4072: 			return(0);
 4073: 			break;
 4074: 		}
 4075: 	}
 4076: 
 4077: #ifdef DHCPv6
 4078: 	if (universe == &dhcpv6_universe) {
 4079: 		switch(opt) {
 4080: 		      case D6O_SIP_SERVERS_DNS:
 4081: 		      case D6O_DOMAIN_SEARCH:
 4082: 		      case D6O_NIS_DOMAIN_NAME:
 4083: 		      case D6O_NISP_DOMAIN_NAME:
 4084: 			return check_domain_name_list(ptr, len, 0);
 4085: 			break;
 4086: 		}
 4087: 	}
 4088: #endif
 4089: 
 4090: 	return(0);
 4091: }
 4092: 
 4093: static void
 4094: add_reject(struct packet *packet) {
 4095: 	struct iaddrmatchlist *list;
 4096: 	
 4097: 	list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
 4098: 	if (!list)
 4099: 		log_fatal ("no memory for reject list!");
 4100: 
 4101: 	/*
 4102: 	 * client_addr is misleading - it is set to source address in common
 4103: 	 * code.
 4104: 	 */
 4105: 	list->match.addr = packet->client_addr;
 4106: 	/* Set mask to indicate host address. */
 4107: 	list->match.mask.len = list->match.addr.len;
 4108: 	memset(list->match.mask.iabuf, 0xff, sizeof(list->match.mask.iabuf));
 4109: 
 4110: 	/* Append to reject list for the source interface. */
 4111: 	list->next = packet->interface->client->config->reject_list;
 4112: 	packet->interface->client->config->reject_list = list;
 4113: 
 4114: 	/*
 4115: 	 * We should inform user that we won't be accepting this server
 4116: 	 * anymore.
 4117: 	 */
 4118: 	log_info("Server added to list of rejected servers.");
 4119: }

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