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