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