1/* dhcpd.c
2
3   DHCP Server Daemon. */
4
5/*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 *   Internet Systems Consortium, Inc.
22 *   950 Charter Street
23 *   Redwood City, CA 94063
24 *   <info@isc.org>
25 *   http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35#ifndef lint
36static char ocopyright[] =
37"$Id: dhcpd.c,v 1.6 2005/08/11 17:13:30 drochner Exp $ Copyright 2004-2005 Internet Systems Consortium.";
38#endif
39
40  static char copyright[] =
41"Copyright 2004-2005 Internet Systems Consortium.";
42static char arr [] = "All rights reserved.";
43static char message [] = "Internet Systems Consortium DHCP Server";
44static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/";
45
46#include "dhcpd.h"
47#include "version.h"
48#include <omapip/omapip_p.h>
49
50static void usage PROTO ((void));
51
52struct iaddr server_identifier;
53int server_identifier_matched;
54
55#if defined (NSUPDATE)
56
57/* This stuff is always executed to figure the default values for certain
58   ddns variables. */
59
60char std_nsupdate [] = "						    \n\
61option server.ddns-hostname =						    \n\
62  pick (option fqdn.hostname, option host-name);			    \n\
63option server.ddns-domainname =	config-option domain-name;		    \n\
64option server.ddns-ttl = encode-int(lease-time / 2, 32);		    \n\
65option server.ddns-rev-domainname = \"in-addr.arpa.\";";
66
67/* This is the old-style name service updater that is executed
68   whenever a lease is committed.  It does not follow the DHCP-DNS
69   draft at all. */
70
71char old_nsupdate [] = "						    \n\
72on commit {								    \n\
73  if (not static and							    \n\
74      ((config-option server.ddns-updates = null) or			    \n\
75       (config-option server.ddns-updates != 0))) {			    \n\
76    set new-ddns-fwd-name =						    \n\
77      concat (pick (config-option server.ddns-hostname,			    \n\
78		    option host-name), \".\",				    \n\
79	      pick (config-option server.ddns-domainname,		    \n\
80		    config-option domain-name));			    \n\
81    if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) {   \n\
82      switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) {  \n\
83      case NOERROR:							    \n\
84	unset ddns-fwd-name;						    \n\
85	on expiry or release {						    \n\
86	}								    \n\
87      }									    \n\
88    }									    \n\
89									    \n\
90    if (not defined (ddns-fwd-name)) {					    \n\
91      set ddns-fwd-name = new-ddns-fwd-name;				    \n\
92      if defined (ddns-fwd-name) {					    \n\
93	switch (ns-update (not exists (IN, A, ddns-fwd-name, null),	    \n\
94			   add (IN, A, ddns-fwd-name, leased-address,	    \n\
95				lease-time / 2))) {			    \n\
96	default:							    \n\
97	  unset ddns-fwd-name;						    \n\
98	  break;							    \n\
99									    \n\
100	case NOERROR:							    \n\
101	  set ddns-rev-name =						    \n\
102	    concat (binary-to-ascii (10, 8, \".\",			    \n\
103				     reverse (1,			    \n\
104					      leased-address)), \".\",	    \n\
105		    pick (config-option server.ddns-rev-domainname,	    \n\
106			  \"in-addr.arpa.\"));				    \n\
107	  switch (ns-update (delete (IN, PTR, ddns-rev-name, null),	    \n\
108			     add (IN, PTR, ddns-rev-name, ddns-fwd-name,    \n\
109				  lease-time / 2)))			    \n\
110	    {								    \n\
111	    default:							    \n\
112	      unset ddns-rev-name;					    \n\
113	      on release or expiry {					    \n\
114		switch (ns-update (delete (IN, A, ddns-fwd-name,	    \n\
115					   leased-address))) {		    \n\
116		case NOERROR:						    \n\
117		  unset ddns-fwd-name;					    \n\
118		  break;						    \n\
119		}							    \n\
120		on release or expiry;					    \n\
121	      }								    \n\
122	      break;							    \n\
123									    \n\
124	    case NOERROR:						    \n\
125	      on release or expiry {					    \n\
126		switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
127		case NOERROR:						    \n\
128		  unset ddns-rev-name;					    \n\
129		  break;						    \n\
130		}							    \n\
131		switch (ns-update (delete (IN, A, ddns-fwd-name,	    \n\
132					   leased-address))) {		    \n\
133		case NOERROR:						    \n\
134		  unset ddns-fwd-name;					    \n\
135		  break;						    \n\
136		}							    \n\
137		on release or expiry;					    \n\
138	      }								    \n\
139	    }								    \n\
140	}								    \n\
141      }									    \n\
142    }									    \n\
143    unset new-ddns-fwd-name;						    \n\
144  }									    \n\
145}";
146
147int ddns_update_style;
148#endif /* NSUPDATE */
149
150const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
151const char *path_dhcpd_db = _PATH_DHCPD_DB;
152const char *path_dhcpd_pid = _PATH_DHCPD_PID;
153
154int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
155
156static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
157int omapi_port;
158
159#if defined (TRACING)
160trace_type_t *trace_srandom;
161#endif
162
163static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
164	return ISC_R_SUCCESS;
165}
166
167static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
168	if (a != omapi_key)
169		return ISC_R_INVALIDKEY;
170	return ISC_R_SUCCESS;
171}
172
173static void omapi_listener_start (void *foo)
174{
175	omapi_object_t *listener;
176	isc_result_t result;
177
178	listener = (omapi_object_t *)0;
179	result = omapi_generic_new (&listener, MDL);
180	if (result != ISC_R_SUCCESS)
181		log_fatal ("Can't allocate new generic object: %s",
182			   isc_result_totext (result));
183	result = omapi_protocol_listen (listener,
184					(unsigned)omapi_port, 1);
185	if (result == ISC_R_SUCCESS && omapi_key)
186		result = omapi_protocol_configure_security
187			(listener, verify_addr, verify_auth);
188	if (result != ISC_R_SUCCESS) {
189		log_error ("Can't start OMAPI protocol: %s",
190			   isc_result_totext (result));
191		add_timeout (cur_time + 5, omapi_listener_start, 0, 0, 0);
192	}
193	omapi_object_dereference (&listener, MDL);
194}
195
196int main (argc, argv, envp)
197	int argc;
198	char **argv, **envp;
199{
200	int i, status;
201	struct servent *ent;
202	char *s;
203	int cftest = 0;
204	int lftest = 0;
205#ifndef DEBUG
206	int pidfilewritten = 0;
207	int pid;
208	char pbuf [20];
209	int daemon = 1;
210#endif
211	int quiet = 0;
212	char *server = (char *)0;
213	isc_result_t result;
214	unsigned seed;
215	struct interface_info *ip;
216	struct parse *parse;
217	int lose;
218	int no_dhcpd_conf = 0;
219	int no_dhcpd_db = 0;
220	int no_dhcpd_pid = 0;
221#if defined (TRACING)
222	char *traceinfile = (char *)0;
223	char *traceoutfile = (char *)0;
224#endif
225
226	/* Make sure we have stdin, stdout and stderr. */
227	status = open ("/dev/null", O_RDWR);
228	if (status == 0)
229		status = open ("/dev/null", O_RDWR);
230	if (status == 1) {
231		status = open ("/dev/null", O_RDWR);
232		log_perror = 0; /* No sense logging to /dev/null. */
233	} else if (status != -1)
234		close (status);
235
236	/* Set up the client classification system. */
237	classification_setup ();
238
239	/* Initialize the omapi system. */
240	result = omapi_init ();
241	if (result != ISC_R_SUCCESS)
242		log_fatal ("Can't initialize OMAPI: %s",
243			   isc_result_totext (result));
244
245	/* Set up the OMAPI wrappers for common objects. */
246	dhcp_db_objects_setup ();
247	/* Set up the OMAPI wrappers for various server database internal
248	   objects. */
249	dhcp_common_objects_setup ();
250
251	/* Initially, log errors to stderr as well as to syslogd. */
252#ifdef SYSLOG_4_2
253	openlog ("dhcpd", LOG_NDELAY);
254	log_priority = DHCPD_LOG_FACILITY;
255#else
256	openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
257#endif
258
259	for (i = 1; i < argc; i++) {
260		if (!strcmp (argv [i], "-p")) {
261			if (++i == argc)
262				usage ();
263			for (s = argv [i]; *s; s++)
264				if (!isdigit ((unsigned char)*s))
265					log_fatal ("%s: not a valid UDP port",
266					       argv [i]);
267			status = atoi (argv [i]);
268			if (status < 1 || status > 65535)
269				log_fatal ("%s: not a valid UDP port",
270				       argv [i]);
271			local_port = htons (status);
272			log_debug ("binding to user-specified port %d",
273			       ntohs (local_port));
274		} else if (!strcmp (argv [i], "-f")) {
275#ifndef DEBUG
276			daemon = 0;
277#endif
278		} else if (!strcmp (argv [i], "-d")) {
279#ifndef DEBUG
280			daemon = 0;
281#endif
282			log_perror = -1;
283		} else if (!strcmp (argv [i], "-s")) {
284			if (++i == argc)
285				usage ();
286			server = argv [i];
287		} else if (!strcmp (argv [i], "-cf")) {
288			if (++i == argc)
289				usage ();
290			path_dhcpd_conf = argv [i];
291			no_dhcpd_conf = 1;
292		} else if (!strcmp (argv [i], "-lf")) {
293			if (++i == argc)
294				usage ();
295			path_dhcpd_db = argv [i];
296			no_dhcpd_db = 1;
297		} else if (!strcmp (argv [i], "-pf")) {
298			if (++i == argc)
299				usage ();
300			path_dhcpd_pid = argv [i];
301			no_dhcpd_pid = 1;
302                } else if (!strcmp (argv [i], "-t")) {
303			/* test configurations only */
304#ifndef DEBUG
305			daemon = 0;
306#endif
307			cftest = 1;
308			log_perror = -1;
309                } else if (!strcmp (argv [i], "-T")) {
310			/* test configurations and lease file only */
311#ifndef DEBUG
312			daemon = 0;
313#endif
314			cftest = 1;
315			lftest = 1;
316			log_perror = -1;
317		} else if (!strcmp (argv [i], "-q")) {
318			quiet = 1;
319			quiet_interface_discovery = 1;
320		} else if (!strcmp (argv [i], "--version")) {
321			log_info ("isc-dhcpd-%s", DHCP_VERSION);
322			exit (0);
323#if defined (TRACING)
324		} else if (!strcmp (argv [i], "-tf")) {
325			if (++i == argc)
326				usage ();
327			traceoutfile = argv [i];
328		} else if (!strcmp (argv [i], "-play")) {
329			if (++i == argc)
330				usage ();
331			traceinfile = argv [i];
332			trace_replay_init ();
333#endif /* TRACING */
334		} else if (argv [i][0] == '-') {
335			usage ();
336		} else {
337			struct interface_info *tmp =
338				(struct interface_info *)0;
339			result = interface_allocate (&tmp, MDL);
340			if (result != ISC_R_SUCCESS)
341				log_fatal ("Insufficient memory to %s %s: %s",
342					   "record interface", argv [i],
343					   isc_result_totext (result));
344			strcpy (tmp -> name, argv [i]);
345			if (interfaces) {
346				interface_reference (&tmp -> next,
347						     interfaces, MDL);
348				interface_dereference (&interfaces, MDL);
349			}
350			interface_reference (&interfaces, tmp, MDL);
351			tmp -> flags = INTERFACE_REQUESTED;
352		}
353	}
354
355	if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
356		path_dhcpd_conf = s;
357	}
358	if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
359		path_dhcpd_db = s;
360	}
361	if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
362		path_dhcpd_pid = s;
363	}
364
365	if (!quiet) {
366		log_info ("%s %s", message, DHCP_VERSION);
367		log_info (copyright);
368		log_info (arr);
369		log_info (url);
370	} else {
371		quiet = 0;
372		log_perror = 0;
373	}
374
375#if defined (TRACING)
376	trace_init (set_time, MDL);
377	if (traceoutfile) {
378		result = trace_begin (traceoutfile, MDL);
379		if (result != ISC_R_SUCCESS)
380			log_fatal ("Unable to begin trace: %s",
381				isc_result_totext (result));
382	}
383	interface_trace_setup ();
384	parse_trace_setup ();
385	trace_srandom = trace_type_register ("random-seed", (void *)0,
386					     trace_seed_input,
387					     trace_seed_stop, MDL);
388#endif
389
390	/* Default to the DHCP/BOOTP port. */
391	if (!local_port)
392	{
393		if ((s = getenv ("DHCPD_PORT"))) {
394			local_port = htons (atoi (s));
395			log_debug ("binding to environment-specified port %d",
396				   ntohs (local_port));
397		} else {
398			ent = getservbyname ("dhcp", "udp");
399			if (!ent)
400				local_port = htons (67);
401			else
402				local_port = ent -> s_port;
403#ifndef __CYGWIN32__ /* XXX */
404			endservent ();
405#endif
406		}
407	}
408
409	remote_port = htons (ntohs (local_port) + 1);
410
411	if (server) {
412		if (!inet_aton (server, &limited_broadcast)) {
413			struct hostent *he;
414			he = gethostbyname (server);
415			if (he) {
416				memcpy (&limited_broadcast,
417					he -> h_addr_list [0],
418					sizeof limited_broadcast);
419			} else
420				limited_broadcast.s_addr = INADDR_BROADCAST;
421		}
422	} else {
423		limited_broadcast.s_addr = INADDR_BROADCAST;
424	}
425
426	/* Get the current time... */
427	GET_TIME (&cur_time);
428
429	/* Set up the initial dhcp option universe. */
430	initialize_common_option_spaces ();
431	initialize_server_option_spaces ();
432
433	/* Add the ddns update style enumeration prior to parsing. */
434	add_enumeration (&ddns_styles);
435	add_enumeration (&syslog_enum);
436
437	if (!group_allocate (&root_group, MDL))
438		log_fatal ("Can't allocate root group!");
439	root_group -> authoritative = 0;
440
441	/* Set up various hooks. */
442	dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
443	bootp_packet_handler = do_packet;
444
445#if defined (NSUPDATE)
446	/* Set up the standard name service updater routine. */
447	parse = (struct parse *)0;
448	status = new_parse (&parse, -1,
449			    std_nsupdate, (sizeof std_nsupdate) - 1,
450			    "standard name service update routine", 0);
451	if (status != ISC_R_SUCCESS)
452		log_fatal ("can't begin parsing name service updater!");
453
454	lose = 0;
455	if (!(parse_executable_statements
456	      (&root_group -> statements, parse, &lose, context_any))) {
457		end_parse (&parse);
458		log_fatal ("can't parse standard name service updater!");
459	}
460	end_parse (&parse);
461#endif
462
463	/* Initialize icmp support... */
464	if (!cftest && !lftest)
465		icmp_startup (1, lease_pinged);
466
467#if defined (TRACING)
468	if (traceinfile) {
469	    if (!no_dhcpd_db) {
470		    log_error ("%s", "");
471		    log_error ("** You must specify a lease file with -lf.");
472		    log_error ("   Dhcpd will not overwrite your default");
473		    log_fatal ("   lease file when playing back a trace. **");
474	    }
475	    trace_file_replay (traceinfile);
476
477#if defined (DEBUG_MEMORY_LEAKAGE) && \
478                defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
479            free_everything ();
480            omapi_print_dmalloc_usage_by_caller ();
481#endif
482
483	    exit (0);
484	}
485#endif
486
487	/* Read the dhcpd.conf file... */
488	if (readconf () != ISC_R_SUCCESS)
489		log_fatal ("Configuration file errors encountered -- exiting");
490
491	postconf_initialization (quiet);
492
493        /* test option should cause an early exit */
494 	if (cftest && !lftest)
495 		exit(0);
496
497	group_write_hook = group_writer;
498
499	/* Start up the database... */
500	db_startup (lftest);
501
502	if (lftest)
503		exit (0);
504
505	/* Discover all the network interfaces and initialize them. */
506	discover_interfaces (DISCOVER_SERVER);
507
508	/* Make up a seed for the random number generator from current
509	   time plus the sum of the last four bytes of each
510	   interface's hardware address interpreted as an integer.
511	   Not much entropy, but we're booting, so we're not likely to
512	   find anything better. */
513	seed = 0;
514	for (ip = interfaces; ip; ip = ip -> next) {
515		int junk;
516		memcpy (&junk,
517			&ip -> hw_address.hbuf [ip -> hw_address.hlen -
518					       sizeof seed], sizeof seed);
519		seed += junk;
520	}
521	srandom (seed + cur_time);
522#if defined (TRACING)
523	trace_seed_stash (trace_srandom, seed + cur_time);
524#endif
525	postdb_startup ();
526
527#ifndef DEBUG
528	if (daemon) {
529		/* First part of becoming a daemon... */
530		if ((pid = fork ()) < 0)
531			log_fatal ("Can't fork daemon: %m");
532		else if (pid)
533			exit (0);
534	}
535
536	/* Read previous pid file. */
537	if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
538		status = read (i, pbuf, (sizeof pbuf) - 1);
539		close (i);
540		if (status > 0) {
541			pbuf [status] = 0;
542			pid = atoi (pbuf);
543
544			/* If the previous server process is not still running,
545			   write a new pid file immediately. */
546			if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
547				unlink (path_dhcpd_pid);
548				if ((i = open (path_dhcpd_pid,
549					O_WRONLY | O_CREAT, 0644)) >= 0) {
550				    sprintf (pbuf, "%d\n", (int)getpid ());
551				    write (i, pbuf, strlen (pbuf));
552				    close (i);
553				    pidfilewritten = 1;
554				}
555			} else
556				log_fatal ("There's already a DHCP server running.");
557		}
558	}
559
560	/* If we were requested to log to stdout on the command line,
561	   keep doing so; otherwise, stop. */
562	if (log_perror == -1)
563		log_perror = 1;
564	else
565		log_perror = 0;
566
567	if (daemon) {
568		/* Become session leader and get pid... */
569		close (0);
570		close (1);
571		close (2);
572		pid = setsid ();
573	}
574
575	/* If we didn't write the pid file earlier because we found a
576	   process running the logged pid, but we made it to here,
577	   meaning nothing is listening on the bootp port, then write
578	   the pid file out - what's in it now is bogus anyway. */
579	if (!pidfilewritten) {
580		unlink (path_dhcpd_pid);
581		if ((i = open (path_dhcpd_pid,
582			       O_WRONLY | O_CREAT, 0644)) >= 0) {
583			sprintf (pbuf, "%d\n", (int)getpid ());
584			write (i, pbuf, strlen (pbuf));
585			close (i);
586			pidfilewritten = 1;
587		}
588	}
589#endif /* !DEBUG */
590
591#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
592		defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
593	dmalloc_cutoff_generation = dmalloc_generation;
594	dmalloc_longterm = dmalloc_outstanding;
595	dmalloc_outstanding = 0;
596#endif
597
598#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
599	dump_rc_history ();
600#endif
601
602	omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
603			     (omapi_object_t *)0, "state", server_running);
604
605	/* Receive packets and dispatch them... */
606	dispatch ();
607
608	/* Not reached */
609	return 0;
610}
611
612void postconf_initialization (int quiet)
613{
614	struct option_state *options = (struct option_state *)0;
615	struct data_string db;
616	struct option_cache *oc;
617	char *s;
618	isc_result_t result;
619	struct parse *parse;
620	int tmp;
621
622	/* Now try to get the lease file name. */
623	option_state_allocate (&options, MDL);
624
625	execute_statements_in_scope ((struct binding_value **)0,
626				     (struct packet *)0,
627				     (struct lease *)0,
628				     (struct client_state *)0,
629				     (struct option_state *)0,
630				     options, &global_scope,
631				     root_group,
632				     (struct group *)0);
633	memset (&db, 0, sizeof db);
634	oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
635	if (oc &&
636	    evaluate_option_cache (&db, (struct packet *)0,
637				   (struct lease *)0, (struct client_state *)0,
638				   options, (struct option_state *)0,
639				   &global_scope, oc, MDL)) {
640		s = dmalloc (db.len + 1, MDL);
641		if (!s)
642			log_fatal ("no memory for lease db filename.");
643		memcpy (s, db.data, db.len);
644		s [db.len] = 0;
645		data_string_forget (&db, MDL);
646		path_dhcpd_db = s;
647	}
648
649	oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
650	if (oc &&
651	    evaluate_option_cache (&db, (struct packet *)0,
652				   (struct lease *)0, (struct client_state *)0,
653				   options, (struct option_state *)0,
654				   &global_scope, oc, MDL)) {
655		s = dmalloc (db.len + 1, MDL);
656		if (!s)
657			log_fatal ("no memory for lease db filename.");
658		memcpy (s, db.data, db.len);
659		s [db.len] = 0;
660		data_string_forget (&db, MDL);
661		path_dhcpd_pid = s;
662	}
663
664	omapi_port = -1;
665	oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
666	if (oc &&
667	    evaluate_option_cache (&db, (struct packet *)0,
668				   (struct lease *)0, (struct client_state *)0,
669				   options, (struct option_state *)0,
670				   &global_scope, oc, MDL)) {
671		if (db.len == 2) {
672			omapi_port = getUShort (db.data);
673		} else
674			log_fatal ("invalid omapi port data length");
675		data_string_forget (&db, MDL);
676	}
677
678	oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
679	if (oc &&
680	    evaluate_option_cache (&db, (struct packet *)0,
681				   (struct lease *)0, (struct client_state *)0,
682				   options,
683				   (struct option_state *)0,
684				   &global_scope, oc, MDL)) {
685		s = dmalloc (db.len + 1, MDL);
686		if (!s)
687			log_fatal ("no memory for OMAPI key filename.");
688		memcpy (s, db.data, db.len);
689		s [db.len] = 0;
690		data_string_forget (&db, MDL);
691		result = omapi_auth_key_lookup_name (&omapi_key, s);
692		dfree (s, MDL);
693		if (result != ISC_R_SUCCESS)
694			log_fatal ("OMAPI key %s: %s",
695				   s, isc_result_totext (result));
696	}
697
698	oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
699	if (oc &&
700	    evaluate_option_cache (&db, (struct packet *)0,
701				   (struct lease *)0, (struct client_state *)0,
702				   options,
703				   (struct option_state *)0,
704				   &global_scope, oc, MDL)) {
705		if (db.len == 2) {
706			local_port = htons (getUShort (db.data));
707		} else
708			log_fatal ("invalid local port data length");
709		data_string_forget (&db, MDL);
710	}
711
712	oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
713	if (oc &&
714	    evaluate_option_cache (&db, (struct packet *)0,
715				   (struct lease *)0, (struct client_state *)0,
716				   options, (struct option_state *)0,
717				   &global_scope, oc, MDL)) {
718		if (db.len == 2) {
719			remote_port = htons (getUShort (db.data));
720		} else
721			log_fatal ("invalid remote port data length");
722		data_string_forget (&db, MDL);
723	}
724
725	oc = lookup_option (&server_universe, options,
726			    SV_LIMITED_BROADCAST_ADDRESS);
727	if (oc &&
728	    evaluate_option_cache (&db, (struct packet *)0,
729				   (struct lease *)0, (struct client_state *)0,
730				   options, (struct option_state *)0,
731				   &global_scope, oc, MDL)) {
732		if (db.len == 4) {
733			memcpy (&limited_broadcast, db.data, 4);
734		} else
735			log_fatal ("invalid remote port data length");
736		data_string_forget (&db, MDL);
737	}
738
739	oc = lookup_option (&server_universe, options,
740			    SV_LOCAL_ADDRESS);
741	if (oc &&
742	    evaluate_option_cache (&db, (struct packet *)0,
743				   (struct lease *)0, (struct client_state *)0,
744				   options, (struct option_state *)0,
745				   &global_scope, oc, MDL)) {
746		if (db.len == 4) {
747			memcpy (&local_address, db.data, 4);
748		} else
749			log_fatal ("invalid remote port data length");
750		data_string_forget (&db, MDL);
751	}
752
753	oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
754	if (oc) {
755		if (evaluate_option_cache (&db, (struct packet *)0,
756					   (struct lease *)0,
757					   (struct client_state *)0,
758					   options,
759					   (struct option_state *)0,
760					   &global_scope, oc, MDL)) {
761			if (db.len == 1) {
762				ddns_update_style = db.data [0];
763			} else
764				log_fatal ("invalid dns update type");
765			data_string_forget (&db, MDL);
766		}
767	} else {
768		log_info ("%s", "");
769		log_error ("** You must add a global ddns-update-style %s%s.",
770			   "statement to ", path_dhcpd_conf);
771		log_error ("   To get the same behaviour as in 3.0b2pl11 %s",
772			   "and previous");
773		log_error ("   versions, add a line that says \"%s\"",
774			   "ddns-update-style ad-hoc;");
775		log_fatal ("   Please read the dhcpd.conf manual page %s",
776			   "for more information. **");
777	}
778
779	oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
780	if (oc) {
781		if (evaluate_option_cache (&db, (struct packet *)0,
782					   (struct lease *)0,
783					   (struct client_state *)0,
784					   options,
785					   (struct option_state *)0,
786					   &global_scope, oc, MDL)) {
787			if (db.len == 1) {
788				closelog ();
789#ifdef SYSLOG_4_2
790				openlog ("dhcpd", LOG_NDELAY);
791				log_priority = db.data [0];
792#else
793				openlog ("dhcpd",
794					 LOG_NDELAY, db.data [0]);
795#endif
796				/* Log the startup banner into the new
797				   log file. */
798				if (!quiet) {
799					/* Don't log to stderr twice. */
800					tmp = log_perror;
801					log_perror = 0;
802					log_info ("%s %s",
803						  message, DHCP_VERSION);
804					log_info (copyright);
805					log_info (arr);
806					log_info (url);
807					log_perror = tmp;
808				}
809			} else
810				log_fatal ("invalid log facility");
811			data_string_forget (&db, MDL);
812		}
813	}
814
815	/* Don't need the options anymore. */
816	option_state_dereference (&options, MDL);
817
818#if defined (NSUPDATE)
819	/* If old-style ddns updates have been requested, parse the
820	   old-style ddns updater. */
821	if (ddns_update_style == 1) {
822		struct executable_statement **e, *s;
823
824		if (root_group -> statements) {
825			s = (struct executable_statement *)0;
826			if (!executable_statement_allocate (&s, MDL))
827				log_fatal ("no memory for ddns updater");
828			executable_statement_reference
829				(&s -> next, root_group -> statements, MDL);
830			executable_statement_dereference
831				(&root_group -> statements, MDL);
832			executable_statement_reference
833				(&root_group -> statements, s, MDL);
834			s -> op = statements_statement;
835			e = &s -> data.statements;
836			executable_statement_dereference (&s, MDL);
837		} else {
838			e = &root_group -> statements;
839		}
840
841		/* Set up the standard name service updater routine. */
842		parse = (struct parse *)0;
843		result = new_parse (&parse, -1,
844				 old_nsupdate, (sizeof old_nsupdate) - 1,
845				 "old name service update routine", 0);
846		if (result != ISC_R_SUCCESS)
847			log_fatal ("can't begin parsing old ddns updater!");
848
849		tmp = 0;
850		if (!(parse_executable_statements (e, parse,
851						   &tmp, context_any))) {
852			end_parse (&parse);
853			log_fatal ("can't parse standard ddns updater!");
854		}
855		end_parse (&parse);
856	}
857#endif
858}
859
860void postdb_startup (void)
861{
862	/* Initialize the omapi listener state. */
863	if (omapi_port != -1) {
864		omapi_listener_start (0);
865	}
866
867#if defined (FAILOVER_PROTOCOL)
868	/* Initialize the failover listener state. */
869	dhcp_failover_startup ();
870#endif
871}
872
873/* Print usage message. */
874
875static void usage ()
876{
877	log_info ("%s %s", message, DHCP_VERSION);
878	log_info (copyright);
879	log_info (arr);
880
881	log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
882		   "\n             [-cf config-file] [-lf lease-file]",
883#if defined (TRACING)
884		   "\n		   [-tf trace-output-file]",
885		   "\n		   [-play trace-input-file]",
886#else
887		   "", "",
888#endif /* TRACING */
889		   "\n             [-t] [-T] [-s server] [if0 [...ifN]]");
890}
891
892void lease_pinged (from, packet, length)
893	struct iaddr from;
894	u_int8_t *packet;
895	int length;
896{
897	struct lease *lp;
898
899	/* Don't try to look up a pinged lease if we aren't trying to
900	   ping one - otherwise somebody could easily make us churn by
901	   just forging repeated ICMP EchoReply packets for us to look
902	   up. */
903	if (!outstanding_pings)
904		return;
905
906	lp = (struct lease *)0;
907	if (!find_lease_by_ip_addr (&lp, from, MDL)) {
908		log_debug ("unexpected ICMP Echo Reply from %s",
909			   piaddr (from));
910		return;
911	}
912
913	if (!lp -> state) {
914#if defined (FAILOVER_PROTOCOL)
915		if (!lp -> pool ||
916		    !lp -> pool -> failover_peer)
917#endif
918			log_debug ("ICMP Echo Reply for %s late or spurious.",
919				   piaddr (from));
920		goto out;
921	}
922
923	if (lp -> ends > cur_time) {
924		log_debug ("ICMP Echo reply while lease %s valid.",
925			   piaddr (from));
926	}
927
928	/* At this point it looks like we pinged a lease and got a
929	   response, which shouldn't have happened. */
930	data_string_forget (&lp -> state -> parameter_request_list, MDL);
931	free_lease_state (lp -> state, MDL);
932	lp -> state = (struct lease_state *)0;
933
934	abandon_lease (lp, "pinged before offer");
935	cancel_timeout (lease_ping_timeout, lp);
936	--outstanding_pings;
937      out:
938	lease_dereference (&lp, MDL);
939}
940
941void lease_ping_timeout (vlp)
942	void *vlp;
943{
944	struct lease *lp = vlp;
945
946#if defined (DEBUG_MEMORY_LEAKAGE)
947	unsigned long previous_outstanding = dmalloc_outstanding;
948#endif
949
950	--outstanding_pings;
951	dhcp_reply (lp);
952
953#if defined (DEBUG_MEMORY_LEAKAGE)
954	log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
955		  dmalloc_generation,
956		  dmalloc_outstanding - previous_outstanding,
957		  dmalloc_outstanding, dmalloc_longterm);
958#endif
959#if defined (DEBUG_MEMORY_LEAKAGE)
960	dmalloc_dump_outstanding ();
961#endif
962}
963
964int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
965{
966	struct subnet *subnet;
967	struct shared_network *share;
968	isc_result_t status;
969
970	/* Special case for fallback network - not sure why this is
971	   necessary. */
972	if (!ia) {
973		const char *fnn = "fallback-net";
974		status = shared_network_allocate (&ip -> shared_network, MDL);
975		if (status != ISC_R_SUCCESS)
976			log_fatal ("No memory for shared subnet: %s",
977				   isc_result_totext (status));
978		ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
979		strcpy (ip -> shared_network -> name, fnn);
980		return 1;
981	}
982
983	/* If there's a registered subnet for this address,
984	   connect it together... */
985	subnet = (struct subnet *)0;
986	if (find_subnet (&subnet, *ia, MDL)) {
987		/* If this interface has multiple aliases on the same
988		   subnet, ignore all but the first we encounter. */
989		if (!subnet -> interface) {
990			interface_reference (&subnet -> interface, ip, MDL);
991			subnet -> interface_address = *ia;
992		} else if (subnet -> interface != ip) {
993			log_error ("Multiple interfaces match the %s: %s %s",
994				   "same subnet",
995				   subnet -> interface -> name, ip -> name);
996		}
997		share = subnet -> shared_network;
998		if (ip -> shared_network &&
999		    ip -> shared_network != share) {
1000			log_fatal ("Interface %s matches multiple shared %s",
1001				   ip -> name, "networks");
1002		} else {
1003			if (!ip -> shared_network)
1004				shared_network_reference
1005					(&ip -> shared_network, share, MDL);
1006		}
1007
1008		if (!share -> interface) {
1009			interface_reference (&share -> interface, ip, MDL);
1010		} else if (share -> interface != ip) {
1011			log_error ("Multiple interfaces match the %s: %s %s",
1012				   "same shared network",
1013				   share -> interface -> name, ip -> name);
1014		}
1015		subnet_dereference (&subnet, MDL);
1016	}
1017	return 1;
1018}
1019
1020static TIME shutdown_time;
1021static int omapi_connection_count;
1022enum dhcp_shutdown_state shutdown_state;
1023
1024isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
1025{
1026	/* Shut down all listeners. */
1027	if (shutdown_state == shutdown_listeners &&
1028	    obj -> type == omapi_type_listener &&
1029	    obj -> inner &&
1030	    obj -> inner -> type == omapi_type_protocol_listener) {
1031		omapi_listener_destroy (obj, MDL);
1032		return ISC_R_SUCCESS;
1033	}
1034
1035	/* Shut down all existing omapi connections. */
1036	if (obj -> type == omapi_type_connection &&
1037	    obj -> inner &&
1038	    obj -> inner -> type == omapi_type_protocol) {
1039		if (shutdown_state == shutdown_drop_omapi_connections) {
1040			omapi_disconnect (obj, 1);
1041		}
1042		omapi_connection_count++;
1043		if (shutdown_state == shutdown_omapi_connections) {
1044			omapi_disconnect (obj, 0);
1045			return ISC_R_SUCCESS;
1046		}
1047	}
1048
1049	/* Shutdown all DHCP interfaces. */
1050	if (obj -> type == dhcp_type_interface &&
1051	    shutdown_state == shutdown_dhcp) {
1052		dhcp_interface_remove (obj, (omapi_object_t *)0);
1053		return ISC_R_SUCCESS;
1054	}
1055	return ISC_R_SUCCESS;
1056}
1057
1058static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
1059{
1060	dhcp_failover_state_t *state;
1061#if defined (FAILOVER_PROTOCOL)
1062	int failover_connection_count = 0;
1063#endif
1064
1065      oncemore:
1066	if (shutdown_state == shutdown_listeners ||
1067	    shutdown_state == shutdown_omapi_connections ||
1068	    shutdown_state == shutdown_drop_omapi_connections ||
1069	    shutdown_state == shutdown_dhcp) {
1070		omapi_connection_count = 0;
1071		omapi_io_state_foreach (dhcp_io_shutdown, 0);
1072	}
1073
1074	if ((shutdown_state == shutdown_listeners ||
1075	     shutdown_state == shutdown_omapi_connections ||
1076	     shutdown_state == shutdown_drop_omapi_connections) &&
1077	    omapi_connection_count == 0) {
1078		shutdown_state = shutdown_dhcp;
1079		shutdown_time = cur_time;
1080		goto oncemore;
1081	} else if (shutdown_state == shutdown_listeners &&
1082		   cur_time - shutdown_time > 4) {
1083		shutdown_state = shutdown_omapi_connections;
1084		shutdown_time = cur_time;
1085	} else if (shutdown_state == shutdown_omapi_connections &&
1086		   cur_time - shutdown_time > 4) {
1087		shutdown_state = shutdown_drop_omapi_connections;
1088		shutdown_time = cur_time;
1089	} else if (shutdown_state == shutdown_drop_omapi_connections &&
1090		   cur_time - shutdown_time > 4) {
1091		shutdown_state = shutdown_dhcp;
1092		shutdown_time = cur_time;
1093		goto oncemore;
1094	} else if (shutdown_state == shutdown_dhcp &&
1095		   cur_time - shutdown_time > 4) {
1096		shutdown_state = shutdown_done;
1097		shutdown_time = cur_time;
1098	}
1099
1100#if defined (FAILOVER_PROTOCOL)
1101	/* Set all failover peers into the shutdown state. */
1102	if (shutdown_state == shutdown_dhcp) {
1103	    for (state = failover_states; state; state = state -> next) {
1104		if (state -> me.state == normal) {
1105		    dhcp_failover_set_state (state, shut_down);
1106		    failover_connection_count++;
1107		}
1108		if (state -> me.state == shut_down &&
1109		    state -> partner.state != partner_down)
1110			failover_connection_count++;
1111	    }
1112	}
1113
1114	if (shutdown_state == shutdown_done) {
1115	    for (state = failover_states; state; state = state -> next) {
1116		if (state -> me.state == shut_down) {
1117		    if (state -> link_to_peer)
1118			dhcp_failover_link_dereference (&state -> link_to_peer,
1119							MDL);
1120		    dhcp_failover_set_state (state, recover);
1121		}
1122	    }
1123#if defined (DEBUG_MEMORY_LEAKAGE) && \
1124		defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1125	    free_everything ();
1126	    omapi_print_dmalloc_usage_by_caller ();
1127#endif
1128	    exit (0);
1129	}
1130#else
1131	if (shutdown_state == shutdown_done) {
1132#if defined (DEBUG_MEMORY_LEAKAGE) && \
1133		defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1134		free_everything ();
1135		omapi_print_dmalloc_usage_by_caller ();
1136#endif
1137		exit (0);
1138	}
1139#endif
1140	if (shutdown_state == shutdown_dhcp &&
1141	    !failover_connection_count) {
1142		shutdown_state = shutdown_done;
1143		shutdown_time = cur_time;
1144		goto oncemore;
1145	}
1146	add_timeout (cur_time + 1,
1147		     (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1148	return ISC_R_SUCCESS;
1149}
1150
1151isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
1152				     control_object_state_t newstate)
1153{
1154	if (newstate == server_shutdown) {
1155		shutdown_time = cur_time;
1156		shutdown_state = shutdown_listeners;
1157		dhcp_io_shutdown_countdown (0);
1158		return ISC_R_SUCCESS;
1159	}
1160	return ISC_R_INVALIDARG;
1161}
1162