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