1 /* $OpenBSD: dhclient.c,v 1.118 2008/05/09 05:19:14 reyk Exp $ */ 2 /* $DragonFly: src/sbin/dhclient/dhclient.c,v 1.2 2008/09/10 10:01:18 matthias Exp $ */ 3 4 /* 5 * Copyright 2004 Henning Brauer <henning@openbsd.org> 6 * Copyright (c) 1995, 1996, 1997, 1998, 1999 7 * The Internet Software Consortium. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of The Internet Software Consortium nor the names 19 * of its contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * This software has been written for the Internet Software Consortium 37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 38 * Enterprises. To learn more about the Internet Software Consortium, 39 * see ``http://www.vix.com/isc''. To learn more about Vixie 40 * Enterprises, see ``http://www.vix.com''. 41 * 42 * This client was substantially modified and enhanced by Elliot Poger 43 * for use on Linux while he was working on the MosquitoNet project at 44 * Stanford. 45 * 46 * The current version owes much to Elliot's Linux enhancements, but 47 * was substantially reorganized and partially rewritten by Ted Lemon 48 * so as to use the same networking framework that the Internet Software 49 * Consortium DHCP server uses. Much system-specific configuration code 50 * was moved into a shell script so that as support for more operating 51 * systems is added, it will not be necessary to port and maintain 52 * system-specific configuration code to these operating systems - instead, 53 * the shell script can invoke the native tools to accomplish the same 54 * purpose. 55 */ 56 57 #include <ctype.h> 58 #include <poll.h> 59 #include <pwd.h> 60 61 #include "dhcpd.h" 62 #include "privsep.h" 63 64 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" 65 #define DEFAULT_LEASE_TIME 43200 /* 12 hours... */ 66 #define TIME_MAX 2147483647 67 68 time_t cur_time; 69 70 char *path_dhclient_conf = _PATH_DHCLIENT_CONF; 71 char *path_dhclient_db = NULL; 72 73 int log_perror = 1; 74 int privfd; 75 int nullfd = -1; 76 int no_daemon; 77 int unknown_ok = 1; 78 int routefd = -1; 79 80 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; 81 struct in_addr inaddr_any; 82 struct sockaddr_in sockaddr_broadcast; 83 84 struct interface_info *ifi; 85 struct client_state *client; 86 struct client_config *config; 87 88 int findproto(char *, int); 89 struct sockaddr *get_ifa(char *, int); 90 void usage(void); 91 int check_option(struct client_lease *l, int option); 92 int ipv4addrs(char * buf); 93 int res_hnok(const char *dn); 94 char *option_as_string(unsigned int code, unsigned char *data, int len); 95 int fork_privchld(int, int); 96 97 #define ROUNDUP(a) \ 98 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 99 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 100 101 time_t scripttime; 102 static FILE *leaseFile; 103 104 int 105 findproto(char *cp, int n) 106 { 107 struct sockaddr *sa; 108 int i; 109 110 if (n == 0) 111 return -1; 112 for (i = 1; i; i <<= 1) { 113 if (i & n) { 114 sa = (struct sockaddr *)cp; 115 switch (i) { 116 case RTA_IFA: 117 case RTA_DST: 118 case RTA_GATEWAY: 119 case RTA_NETMASK: 120 if (sa->sa_family == AF_INET) 121 return AF_INET; 122 if (sa->sa_family == AF_INET6) 123 return AF_INET6; 124 break; 125 case RTA_IFP: 126 break; 127 } 128 ADVANCE(cp, sa); 129 } 130 } 131 return (-1); 132 } 133 134 struct sockaddr * 135 get_ifa(char *cp, int n) 136 { 137 struct sockaddr *sa; 138 int i; 139 140 if (n == 0) 141 return (NULL); 142 for (i = 1; i; i <<= 1) 143 if (i & n) { 144 sa = (struct sockaddr *)cp; 145 if (i == RTA_IFA) 146 return (sa); 147 ADVANCE(cp, sa); 148 } 149 150 return (NULL); 151 } 152 struct iaddr defaddr = { .len = 4 }; /* NULL is for silence warnings */ 153 154 /* ARGSUSED */ 155 void 156 routehandler(void) 157 { 158 int linkstat; 159 char msg[2048]; 160 struct rt_msghdr *rtm; 161 struct if_msghdr *ifm; 162 struct ifa_msghdr *ifam; 163 struct if_announcemsghdr *ifan; 164 struct client_lease *l; 165 time_t t = time(NULL); 166 struct sockaddr *sa; 167 struct iaddr a; 168 ssize_t n; 169 170 do { 171 n = read(routefd, &msg, sizeof(msg)); 172 } while (n == -1 && errno == EINTR); 173 174 rtm = (struct rt_msghdr *)msg; 175 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen || 176 rtm->rtm_version != RTM_VERSION) 177 return; 178 179 switch (rtm->rtm_type) { 180 case RTM_NEWADDR: 181 ifam = (struct ifa_msghdr *)rtm; 182 if (ifam->ifam_index != ifi->index) 183 break; 184 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) 185 break; 186 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs); 187 if (sa == NULL) 188 goto die; 189 190 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) 191 error("king bula sez: len mismatch"); 192 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len); 193 if (addr_eq(a, defaddr)) 194 break; 195 196 for (l = client->active; l != NULL; l = l->next) 197 if (addr_eq(a, l->address)) 198 break; 199 200 if (l != NULL || (client->alias && 201 addr_eq(a, client->alias->address))) 202 /* new addr is the one we set */ 203 break; 204 205 goto die; 206 case RTM_DELADDR: 207 ifam = (struct ifa_msghdr *)rtm; 208 if (ifam->ifam_index != ifi->index) 209 break; 210 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) 211 break; 212 if (scripttime == 0 || t < scripttime + 10) 213 break; 214 goto die; 215 case RTM_IFINFO: 216 ifm = (struct if_msghdr *)rtm; 217 if (ifm->ifm_index != ifi->index) 218 break; 219 if ((rtm->rtm_flags & RTF_UP) == 0) 220 goto die; 221 222 linkstat = 223 LINK_STATE_IS_UP(ifm->ifm_data.ifi_link_state) ? 1 : 0; 224 if (linkstat != ifi->linkstat) { 225 debug("link state %s -> %s", 226 ifi->linkstat ? "up" : "down", 227 linkstat ? "up" : "down"); 228 ifi->linkstat = interface_link_status(ifi->name); 229 if (ifi->linkstat) { 230 client->state = S_INIT; 231 state_reboot(); 232 } 233 } 234 break; 235 case RTM_IFANNOUNCE: 236 ifan = (struct if_announcemsghdr *)rtm; 237 if (ifan->ifan_what == IFAN_DEPARTURE && 238 ifan->ifan_index == ifi->index) 239 goto die; 240 break; 241 default: 242 break; 243 } 244 return; 245 246 die: 247 script_init("FAIL", NULL); 248 if (client->alias) 249 script_write_params("alias_", client->alias); 250 script_go(); 251 exit(1); 252 } 253 254 int 255 main(int argc, char *argv[]) 256 { 257 int ch, fd, quiet = 0, i = 0, pipe_fd[2]; 258 struct passwd *pw; 259 260 /* Initially, log errors to stderr as well as to syslogd. */ 261 openlog(getprogname(), LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); 262 setlogmask(LOG_UPTO(LOG_INFO)); 263 264 while ((ch = getopt(argc, argv, "c:dl:qu")) != -1) 265 switch (ch) { 266 case 'c': 267 path_dhclient_conf = optarg; 268 break; 269 case 'd': 270 no_daemon = 1; 271 break; 272 case 'l': 273 path_dhclient_db = optarg; 274 break; 275 case 'q': 276 quiet = 1; 277 break; 278 case 'u': 279 unknown_ok = 0; 280 break; 281 default: 282 usage(); 283 } 284 285 argc -= optind; 286 argv += optind; 287 288 if (argc != 1) 289 usage(); 290 291 ifi = calloc(1, sizeof(*ifi)); 292 if (ifi == NULL) 293 error("ifi calloc"); 294 client = calloc(1, sizeof(*client)); 295 if (client == NULL) 296 error("client calloc"); 297 config = calloc(1, sizeof(*config)); 298 if (config == NULL) 299 error("config calloc"); 300 301 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ) 302 error("Interface name too long"); 303 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s", 304 _PATH_DHCLIENT_DB, ifi->name) == -1) 305 error("asprintf"); 306 307 if (quiet) 308 log_perror = 0; 309 310 tzset(); 311 time(&cur_time); 312 313 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast)); 314 sockaddr_broadcast.sin_family = AF_INET; 315 sockaddr_broadcast.sin_port = htons(REMOTE_PORT); 316 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; 317 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast); 318 inaddr_any.s_addr = INADDR_ANY; 319 320 read_client_conf(); 321 322 if (interface_status(ifi->name) == 0) { 323 interface_link_forceup(ifi->name); 324 /* Give it up to 4 seconds of silent grace to find link */ 325 i = -4; 326 } else 327 i = 0; 328 329 while (!(ifi->linkstat = interface_link_status(ifi->name))) { 330 if (i == 0) 331 fprintf(stderr, "%s: no link ...", ifi->name); 332 else if (i > 0) 333 fprintf(stderr, "."); 334 fflush(stderr); 335 if (++i > config->link_timeout) { 336 fprintf(stderr, " sleeping\n"); 337 goto dispatch; 338 } 339 sleep(1); 340 } 341 if (i >= 0) 342 fprintf(stderr, " got link\n"); 343 344 dispatch: 345 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) 346 error("cannot open %s: %m", _PATH_DEVNULL); 347 348 if ((pw = getpwnam("_dhcp")) == NULL) { 349 warning("no such user: _dhcp, falling back to \"nobody\""); 350 if ((pw = getpwnam("nobody")) == NULL) 351 error("no such user: nobody"); 352 } 353 354 if (pipe(pipe_fd) == -1) 355 error("pipe"); 356 357 fork_privchld(pipe_fd[0], pipe_fd[1]); 358 359 close(pipe_fd[0]); 360 privfd = pipe_fd[1]; 361 362 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) 363 error("can't open and lock %s: %m", path_dhclient_db); 364 read_client_leases(); 365 if ((leaseFile = fopen(path_dhclient_db, "w")) == NULL) 366 error("can't open %s: %m", path_dhclient_db); 367 rewrite_client_leases(); 368 close(fd); 369 370 priv_script_init("PREINIT", NULL); 371 if (client->alias) 372 priv_script_write_params("alias_", client->alias); 373 priv_script_go(); 374 375 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1) 376 error("socket(PF_ROUTE, SOCK_RAW): %m"); 377 378 /* set up the interface */ 379 discover_interface(); 380 381 if (chroot(_PATH_VAREMPTY) == -1) 382 error("chroot"); 383 if (chdir("/") == -1) 384 error("chdir(\"/\")"); 385 386 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) 387 error("setresgid"); 388 if (setgroups(1, &pw->pw_gid) == -1) 389 error("setgroups"); 390 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) 391 error("setresuid"); 392 393 endpwent(); 394 395 setproctitle("%s", ifi->name); 396 397 if (ifi->linkstat) { 398 client->state = S_INIT; 399 state_reboot(); 400 } else 401 go_daemon(); 402 403 dispatch(); 404 405 /* not reached */ 406 return (0); 407 } 408 409 void 410 usage(void) 411 { 412 fprintf(stderr, "usage: %s [-dqu] [-c file] [-l file] interface\n", 413 getprogname()); 414 exit(1); 415 } 416 417 /* 418 * Individual States: 419 * 420 * Each routine is called from the dhclient_state_machine() in one of 421 * these conditions: 422 * -> entering INIT state 423 * -> recvpacket_flag == 0: timeout in this state 424 * -> otherwise: received a packet in this state 425 * 426 * Return conditions as handled by dhclient_state_machine(): 427 * Returns 1, sendpacket_flag = 1: send packet, reset timer. 428 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). 429 * Returns 0: finish the nap which was interrupted for no good reason. 430 * 431 * Several per-interface variables are used to keep track of the process: 432 * active_lease: the lease that is being used on the interface 433 * (null pointer if not configured yet). 434 * offered_leases: leases corresponding to DHCPOFFER messages that have 435 * been sent to us by DHCP servers. 436 * acked_leases: leases corresponding to DHCPACK messages that have been 437 * sent to us by DHCP servers. 438 * sendpacket: DHCP packet we're trying to send. 439 * destination: IP address to send sendpacket to 440 * In addition, there are several relevant per-lease variables. 441 * T1_expiry, T2_expiry, lease_expiry: lease milestones 442 * In the active lease, these control the process of renewing the lease; 443 * In leases on the acked_leases list, this simply determines when we 444 * can no longer legitimately use the lease. 445 */ 446 void 447 state_reboot(void) 448 { 449 /* If we don't remember an active lease, go straight to INIT. */ 450 if (!client->active || client->active->is_bootp) { 451 state_init(); 452 return; 453 } 454 455 /* We are in the rebooting state. */ 456 client->state = S_REBOOTING; 457 458 /* make_request doesn't initialize xid because it normally comes 459 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, 460 so pick an xid now. */ 461 client->xid = arc4random(); 462 463 /* Make a DHCPREQUEST packet, and set appropriate per-interface 464 flags. */ 465 make_request(client->active); 466 client->destination = iaddr_broadcast; 467 client->first_sending = cur_time; 468 client->interval = config->initial_interval; 469 470 /* Zap the medium list... */ 471 client->medium = NULL; 472 473 /* Send out the first DHCPREQUEST packet. */ 474 send_request(); 475 } 476 477 /* 478 * Called when a lease has completely expired and we've 479 * been unable to renew it. 480 */ 481 void 482 state_init(void) 483 { 484 /* Make a DHCPDISCOVER packet, and set appropriate per-interface 485 flags. */ 486 make_discover(client->active); 487 client->xid = client->packet.xid; 488 client->destination = iaddr_broadcast; 489 client->state = S_SELECTING; 490 client->first_sending = cur_time; 491 client->interval = config->initial_interval; 492 493 /* Add an immediate timeout to cause the first DHCPDISCOVER packet 494 to go out. */ 495 send_discover(); 496 } 497 498 /* 499 * state_selecting is called when one or more DHCPOFFER packets 500 * have been received and a configurable period of time has passed. 501 */ 502 void 503 state_selecting(void) 504 { 505 struct client_lease *lp, *next, *picked; 506 507 /* Cancel state_selecting and send_discover timeouts, since either 508 one could have got us here. */ 509 cancel_timeout(state_selecting); 510 cancel_timeout(send_discover); 511 512 /* We have received one or more DHCPOFFER packets. Currently, 513 the only criterion by which we judge leases is whether or 514 not we get a response when we arp for them. */ 515 picked = NULL; 516 for (lp = client->offered_leases; lp; lp = next) { 517 next = lp->next; 518 519 /* Check to see if we got an ARPREPLY for the address 520 in this particular lease. */ 521 if (!picked) { 522 script_init("ARPCHECK", lp->medium); 523 script_write_params("check_", lp); 524 525 /* If the ARPCHECK code detects another 526 machine using the offered address, it exits 527 nonzero. We need to send a DHCPDECLINE and 528 toss the lease. */ 529 if (script_go()) { 530 make_decline(lp); 531 send_decline(); 532 goto freeit; 533 } 534 picked = lp; 535 picked->next = NULL; 536 } else { 537 freeit: 538 free_client_lease(lp); 539 } 540 } 541 client->offered_leases = NULL; 542 543 /* If we just tossed all the leases we were offered, go back 544 to square one. */ 545 if (!picked) { 546 client->state = S_INIT; 547 state_init(); 548 return; 549 } 550 551 /* If it was a BOOTREPLY, we can just take the address right now. */ 552 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { 553 client->new = picked; 554 555 /* Make up some lease expiry times 556 XXX these should be configurable. */ 557 client->new->expiry = cur_time + 12000; 558 client->new->renewal += cur_time + 8000; 559 client->new->rebind += cur_time + 10000; 560 561 client->state = S_REQUESTING; 562 563 /* Bind to the address we received. */ 564 bind_lease(); 565 return; 566 } 567 568 /* Go to the REQUESTING state. */ 569 client->destination = iaddr_broadcast; 570 client->state = S_REQUESTING; 571 client->first_sending = cur_time; 572 client->interval = config->initial_interval; 573 574 /* Make a DHCPREQUEST packet from the lease we picked. */ 575 make_request(picked); 576 client->xid = client->packet.xid; 577 578 /* Toss the lease we picked - we'll get it back in a DHCPACK. */ 579 free_client_lease(picked); 580 581 /* Add an immediate timeout to send the first DHCPREQUEST packet. */ 582 send_request(); 583 } 584 585 void 586 dhcpack(struct iaddr client_addr, struct option_data *options) 587 { 588 struct client_lease *lease; 589 590 if (client->xid != client->packet.xid) 591 return; 592 593 if (client->state != S_REBOOTING && 594 client->state != S_REQUESTING && 595 client->state != S_RENEWING && 596 client->state != S_REBINDING) 597 return; 598 599 note("DHCPACK from %s", piaddr(client_addr)); 600 601 lease = packet_to_lease(options); 602 if (!lease) { 603 note("packet_to_lease failed."); 604 return; 605 } 606 607 client->new = lease; 608 609 /* Stop resending DHCPREQUEST. */ 610 cancel_timeout(send_request); 611 612 /* Figure out the lease time. */ 613 if (client->new->options[DHO_DHCP_LEASE_TIME].data) 614 client->new->expiry = 615 getULong(client->new->options[DHO_DHCP_LEASE_TIME].data); 616 else 617 client->new->expiry = DEFAULT_LEASE_TIME; 618 /* A number that looks negative here is really just very large, 619 because the lease expiry offset is unsigned. */ 620 if (client->new->expiry < 0) 621 client->new->expiry = TIME_MAX; 622 /* XXX should be fixed by resetting the client state */ 623 if (client->new->expiry < 60) 624 client->new->expiry = 60; 625 626 /* Take the server-provided renewal time if there is one; 627 otherwise figure it out according to the spec. */ 628 if (client->new->options[DHO_DHCP_RENEWAL_TIME].len) 629 client->new->renewal = 630 getULong(client->new->options[DHO_DHCP_RENEWAL_TIME].data); 631 else 632 client->new->renewal = client->new->expiry / 2; 633 634 /* Same deal with the rebind time. */ 635 if (client->new->options[DHO_DHCP_REBINDING_TIME].len) 636 client->new->rebind = 637 getULong(client->new->options[DHO_DHCP_REBINDING_TIME].data); 638 else 639 client->new->rebind = client->new->renewal + 640 client->new->renewal / 2 + client->new->renewal / 4; 641 642 client->new->expiry += cur_time; 643 /* Lease lengths can never be negative. */ 644 if (client->new->expiry < cur_time) 645 client->new->expiry = TIME_MAX; 646 client->new->renewal += cur_time; 647 if (client->new->renewal < cur_time) 648 client->new->renewal = TIME_MAX; 649 client->new->rebind += cur_time; 650 if (client->new->rebind < cur_time) 651 client->new->rebind = TIME_MAX; 652 653 bind_lease(); 654 } 655 656 void 657 bind_lease(void) 658 { 659 /* Remember the medium. */ 660 client->new->medium = client->medium; 661 662 /* Write out the new lease. */ 663 write_client_lease(client->new, 0); 664 665 /* Run the client script with the new parameters. */ 666 script_init((client->state == S_REQUESTING ? "BOUND" : 667 (client->state == S_RENEWING ? "RENEW" : 668 (client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), 669 client->new->medium); 670 if (client->active && client->state != S_REBOOTING) 671 script_write_params("old_", client->active); 672 script_write_params("new_", client->new); 673 if (client->alias) 674 script_write_params("alias_", client->alias); 675 script_go(); 676 677 /* Replace the old active lease with the new one. */ 678 if (client->active) 679 free_client_lease(client->active); 680 client->active = client->new; 681 client->new = NULL; 682 683 /* Set up a timeout to start the renewal process. */ 684 add_timeout(client->active->renewal, state_bound); 685 686 note("bound to %s -- renewal in %ld seconds.", 687 piaddr(client->active->address), 688 client->active->renewal - cur_time); 689 client->state = S_BOUND; 690 reinitialize_interface(); 691 go_daemon(); 692 } 693 694 /* 695 * state_bound is called when we've successfully bound to a particular 696 * lease, but the renewal time on that lease has expired. We are 697 * expected to unicast a DHCPREQUEST to the server that gave us our 698 * original lease. 699 */ 700 void 701 state_bound(void) 702 { 703 /* T1 has expired. */ 704 make_request(client->active); 705 client->xid = client->packet.xid; 706 707 if (client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { 708 memcpy(client->destination.iabuf, 709 client->active->options[DHO_DHCP_SERVER_IDENTIFIER].data, 710 4); 711 client->destination.len = 4; 712 } else 713 client->destination = iaddr_broadcast; 714 715 client->first_sending = cur_time; 716 client->interval = config->initial_interval; 717 client->state = S_RENEWING; 718 719 /* Send the first packet immediately. */ 720 send_request(); 721 } 722 723 void 724 dhcpoffer(struct iaddr client_addr, struct option_data *options) 725 { 726 struct client_lease *lease, *lp; 727 int i; 728 int arp_timeout_needed, stop_selecting; 729 char *name = options[DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" : 730 "BOOTREPLY"; 731 732 if (client->xid != client->packet.xid) 733 return; 734 735 if (client->state != S_SELECTING) 736 return; 737 738 note("%s from %s", name, piaddr(client_addr)); 739 740 /* If this lease doesn't supply the minimum required parameters, 741 blow it off. */ 742 for (i = 0; config->required_options[i]; i++) { 743 if (!options[config->required_options[i]].len) { 744 note("%s isn't satisfactory.", name); 745 return; 746 } 747 } 748 749 /* If we've already seen this lease, don't record it again. */ 750 for (lease = client->offered_leases; 751 lease; lease = lease->next) { 752 if (lease->address.len == sizeof(client->packet.yiaddr) && 753 !memcmp(lease->address.iabuf, 754 &client->packet.yiaddr, lease->address.len)) { 755 debug("%s already seen.", name); 756 return; 757 } 758 } 759 760 lease = packet_to_lease(options); 761 if (!lease) { 762 note("packet_to_lease failed."); 763 return; 764 } 765 766 /* If this lease was acquired through a BOOTREPLY, record that 767 fact. */ 768 if (!options[DHO_DHCP_MESSAGE_TYPE].len) 769 lease->is_bootp = 1; 770 771 /* Record the medium under which this lease was offered. */ 772 lease->medium = client->medium; 773 774 /* Send out an ARP Request for the offered IP address. */ 775 script_init("ARPSEND", lease->medium); 776 script_write_params("check_", lease); 777 /* If the script can't send an ARP request without waiting, 778 we'll be waiting when we do the ARPCHECK, so don't wait now. */ 779 if (script_go()) 780 arp_timeout_needed = 0; 781 else 782 arp_timeout_needed = 2; 783 784 /* Figure out when we're supposed to stop selecting. */ 785 stop_selecting = client->first_sending + config->select_interval; 786 787 /* If this is the lease we asked for, put it at the head of the 788 list, and don't mess with the arp request timeout. */ 789 if (lease->address.len == client->requested_address.len && 790 !memcmp(lease->address.iabuf, 791 client->requested_address.iabuf, 792 client->requested_address.len)) { 793 lease->next = client->offered_leases; 794 client->offered_leases = lease; 795 } else { 796 /* If we already have an offer, and arping for this 797 offer would take us past the selection timeout, 798 then don't extend the timeout - just hope for the 799 best. */ 800 if (client->offered_leases && 801 (cur_time + arp_timeout_needed) > stop_selecting) 802 arp_timeout_needed = 0; 803 804 /* Put the lease at the end of the list. */ 805 lease->next = NULL; 806 if (!client->offered_leases) 807 client->offered_leases = lease; 808 else { 809 for (lp = client->offered_leases; lp->next; 810 lp = lp->next) 811 ; /* nothing */ 812 lp->next = lease; 813 } 814 } 815 816 /* If we're supposed to stop selecting before we've had time 817 to wait for the ARPREPLY, add some delay to wait for 818 the ARPREPLY. */ 819 if (stop_selecting - cur_time < arp_timeout_needed) 820 stop_selecting = cur_time + arp_timeout_needed; 821 822 /* If the selecting interval has expired, go immediately to 823 state_selecting(). Otherwise, time out into 824 state_selecting at the select interval. */ 825 if (stop_selecting <= 0) 826 state_selecting(); 827 else { 828 add_timeout(stop_selecting, state_selecting); 829 cancel_timeout(send_discover); 830 } 831 } 832 833 /* 834 * Allocate a client_lease structure and initialize it from the 835 * parameters in the specified packet. 836 */ 837 struct client_lease * 838 packet_to_lease(struct option_data *options) 839 { 840 struct client_lease *lease; 841 int i; 842 843 lease = malloc(sizeof(struct client_lease)); 844 845 if (!lease) { 846 warning("dhcpoffer: no memory to record lease."); 847 return (NULL); 848 } 849 850 memset(lease, 0, sizeof(*lease)); 851 852 /* Copy the lease options. */ 853 for (i = 0; i < 256; i++) { 854 if (options[i].len) { 855 lease->options[i] = options[i]; 856 options[i].data = NULL; 857 options[i].len = 0; 858 if (!check_option(lease, i)) { 859 warning("Invalid lease option - ignoring offer"); 860 free_client_lease(lease); 861 return (NULL); 862 } 863 } 864 } 865 866 lease->address.len = sizeof(client->packet.yiaddr); 867 memcpy(lease->address.iabuf, &client->packet.yiaddr, 868 lease->address.len); 869 870 /* If the server name was filled out, copy it. */ 871 if ((!lease->options[DHO_DHCP_OPTION_OVERLOAD].len || 872 !(lease->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && 873 client->packet.sname[0]) { 874 lease->server_name = malloc(DHCP_SNAME_LEN + 1); 875 if (!lease->server_name) { 876 warning("dhcpoffer: no memory for server name."); 877 free_client_lease(lease); 878 return (NULL); 879 } 880 memcpy(lease->server_name, client->packet.sname, 881 DHCP_SNAME_LEN); 882 lease->server_name[DHCP_SNAME_LEN] = '\0'; 883 if (!res_hnok(lease->server_name)) { 884 warning("Bogus server name %s", lease->server_name); 885 free(lease->server_name); 886 lease->server_name = NULL; 887 } 888 } 889 890 /* Ditto for the filename. */ 891 if ((!lease->options[DHO_DHCP_OPTION_OVERLOAD].len || 892 !(lease->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && 893 client->packet.file[0]) { 894 /* Don't count on the NUL terminator. */ 895 lease->filename = malloc(DHCP_FILE_LEN + 1); 896 if (!lease->filename) { 897 warning("dhcpoffer: no memory for filename."); 898 free_client_lease(lease); 899 return (NULL); 900 } 901 memcpy(lease->filename, client->packet.file, DHCP_FILE_LEN); 902 lease->filename[DHCP_FILE_LEN] = '\0'; 903 } 904 return lease; 905 } 906 907 void 908 dhcpnak(struct iaddr client_addr, struct option_data *options) 909 { 910 if (client->xid != client->packet.xid) 911 return; 912 913 if (client->state != S_REBOOTING && 914 client->state != S_REQUESTING && 915 client->state != S_RENEWING && 916 client->state != S_REBINDING) 917 return; 918 919 note("DHCPNAK from %s", piaddr(client_addr)); 920 921 if (!client->active) { 922 note("DHCPNAK with no active lease."); 923 return; 924 } 925 926 free_client_lease(client->active); 927 client->active = NULL; 928 929 /* Stop sending DHCPREQUEST packets... */ 930 cancel_timeout(send_request); 931 932 client->state = S_INIT; 933 state_init(); 934 } 935 936 /* 937 * Send out a DHCPDISCOVER packet, and set a timeout to send out another 938 * one after the right interval has expired. If we don't get an offer by 939 * the time we reach the panic interval, call the panic function. 940 */ 941 void 942 send_discover(void) 943 { 944 int interval, increase = 1; 945 946 /* Figure out how long it's been since we started transmitting. */ 947 interval = cur_time - client->first_sending; 948 949 /* If we're past the panic timeout, call the script and tell it 950 we haven't found anything for this interface yet. */ 951 if (interval > config->timeout) { 952 state_panic(); 953 return; 954 } 955 956 /* If we're selecting media, try the whole list before doing 957 the exponential backoff, but if we've already received an 958 offer, stop looping, because we obviously have it right. */ 959 if (!client->offered_leases && config->media) { 960 int fail = 0; 961 again: 962 if (client->medium) { 963 client->medium = client->medium->next; 964 increase = 0; 965 } 966 if (!client->medium) { 967 if (fail) 968 error("No valid media types for %s!", ifi->name); 969 client->medium = config->media; 970 increase = 1; 971 } 972 973 note("Trying medium \"%s\" %d", client->medium->string, 974 increase); 975 script_init("MEDIUM", client->medium); 976 if (script_go()) 977 goto again; 978 } 979 980 /* 981 * If we're supposed to increase the interval, do so. If it's 982 * currently zero (i.e., we haven't sent any packets yet), set 983 * it to initial_interval; otherwise, add to it a random 984 * number between zero and two times itself. On average, this 985 * means that it will double with every transmission. 986 */ 987 if (increase) { 988 if (!client->interval) 989 client->interval = config->initial_interval; 990 else { 991 client->interval += (arc4random() >> 2) % 992 (2 * client->interval); 993 } 994 995 /* Don't backoff past cutoff. */ 996 if (client->interval > config->backoff_cutoff) 997 client->interval = ((config->backoff_cutoff / 2) 998 + ((arc4random() >> 2) % 999 config->backoff_cutoff)); 1000 } else if (!client->interval) 1001 client->interval = config->initial_interval; 1002 1003 /* If the backoff would take us to the panic timeout, just use that 1004 as the interval. */ 1005 if (cur_time + client->interval > 1006 client->first_sending + config->timeout) 1007 client->interval = (client->first_sending + 1008 config->timeout) - cur_time + 1; 1009 1010 /* Record the number of seconds since we started sending. */ 1011 if (interval < 65536) 1012 client->packet.secs = htons(interval); 1013 else 1014 client->packet.secs = htons(65535); 1015 client->secs = client->packet.secs; 1016 1017 note("DHCPDISCOVER on %s to %s port %d interval %ld", 1018 ifi->name, inet_ntoa(sockaddr_broadcast.sin_addr), 1019 ntohs(sockaddr_broadcast.sin_port), client->interval); 1020 1021 /* Send out a packet. */ 1022 send_packet(inaddr_any, &sockaddr_broadcast, NULL); 1023 1024 add_timeout(cur_time + client->interval, send_discover); 1025 } 1026 1027 /* 1028 * state_panic gets called if we haven't received any offers in a preset 1029 * amount of time. When this happens, we try to use existing leases 1030 * that haven't yet expired, and failing that, we call the client script 1031 * and hope it can do something. 1032 */ 1033 void 1034 state_panic(void) 1035 { 1036 struct client_lease *loop = client->active; 1037 struct client_lease *lp; 1038 1039 note("No DHCPOFFERS received."); 1040 1041 /* We may not have an active lease, but we may have some 1042 predefined leases that we can try. */ 1043 if (!client->active && client->leases) 1044 goto activate_next; 1045 1046 /* Run through the list of leases and see if one can be used. */ 1047 while (client->active) { 1048 if (client->active->expiry > cur_time) { 1049 note("Trying recorded lease %s", 1050 piaddr(client->active->address)); 1051 /* Run the client script with the existing 1052 parameters. */ 1053 script_init("TIMEOUT", 1054 client->active->medium); 1055 script_write_params("new_", client->active); 1056 if (client->alias) 1057 script_write_params("alias_", 1058 client->alias); 1059 1060 /* If the old lease is still good and doesn't 1061 yet need renewal, go into BOUND state and 1062 timeout at the renewal time. */ 1063 if (!script_go()) { 1064 if (cur_time < 1065 client->active->renewal) { 1066 client->state = S_BOUND; 1067 note("bound: renewal in %ld seconds.", 1068 client->active->renewal - 1069 cur_time); 1070 add_timeout(client->active->renewal, 1071 state_bound); 1072 } else { 1073 client->state = S_BOUND; 1074 note("bound: immediate renewal."); 1075 state_bound(); 1076 } 1077 reinitialize_interface(); 1078 go_daemon(); 1079 return; 1080 } 1081 } 1082 1083 /* If there are no other leases, give up. */ 1084 if (!client->leases) { 1085 client->leases = client->active; 1086 client->active = NULL; 1087 break; 1088 } 1089 1090 activate_next: 1091 /* Otherwise, put the active lease at the end of the 1092 lease list, and try another lease.. */ 1093 for (lp = client->leases; lp->next; lp = lp->next) 1094 ; 1095 lp->next = client->active; 1096 if (lp->next) 1097 lp->next->next = NULL; 1098 client->active = client->leases; 1099 client->leases = client->leases->next; 1100 1101 /* If we already tried this lease, we've exhausted the 1102 set of leases, so we might as well give up for 1103 now. */ 1104 if (client->active == loop) 1105 break; 1106 else if (!loop) 1107 loop = client->active; 1108 } 1109 1110 /* No leases were available, or what was available didn't work, so 1111 tell the shell script that we failed to allocate an address, 1112 and try again later. */ 1113 note("No working leases in persistent database - sleeping."); 1114 script_init("FAIL", NULL); 1115 if (client->alias) 1116 script_write_params("alias_", client->alias); 1117 script_go(); 1118 client->state = S_INIT; 1119 add_timeout(cur_time + config->retry_interval, state_init); 1120 go_daemon(); 1121 } 1122 1123 void 1124 send_request(void) 1125 { 1126 struct sockaddr_in destination; 1127 struct in_addr from; 1128 int interval; 1129 1130 /* Figure out how long it's been since we started transmitting. */ 1131 interval = cur_time - client->first_sending; 1132 1133 /* If we're in the INIT-REBOOT or REQUESTING state and we're 1134 past the reboot timeout, go to INIT and see if we can 1135 DISCOVER an address... */ 1136 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it 1137 means either that we're on a network with no DHCP server, 1138 or that our server is down. In the latter case, assuming 1139 that there is a backup DHCP server, DHCPDISCOVER will get 1140 us a new address, but we could also have successfully 1141 reused our old address. In the former case, we're hosed 1142 anyway. This is not a win-prone situation. */ 1143 if ((client->state == S_REBOOTING || 1144 client->state == S_REQUESTING) && 1145 interval > config->reboot_timeout) { 1146 cancel: 1147 client->state = S_INIT; 1148 cancel_timeout(send_request); 1149 state_init(); 1150 return; 1151 } 1152 1153 /* If we're in the reboot state, make sure the media is set up 1154 correctly. */ 1155 if (client->state == S_REBOOTING && 1156 !client->medium && 1157 client->active->medium) { 1158 script_init("MEDIUM", client->active->medium); 1159 1160 /* If the medium we chose won't fly, go to INIT state. */ 1161 if (script_go()) 1162 goto cancel; 1163 1164 /* Record the medium. */ 1165 client->medium = client->active->medium; 1166 } 1167 1168 /* If the lease has expired, relinquish the address and go back 1169 to the INIT state. */ 1170 if (client->state != S_REQUESTING && 1171 cur_time > client->active->expiry) { 1172 /* Run the client script with the new parameters. */ 1173 script_init("EXPIRE", NULL); 1174 script_write_params("old_", client->active); 1175 if (client->alias) 1176 script_write_params("alias_", client->alias); 1177 script_go(); 1178 1179 /* Now do a preinit on the interface so that we can 1180 discover a new address. */ 1181 script_init("PREINIT", NULL); 1182 if (client->alias) 1183 script_write_params("alias_", client->alias); 1184 script_go(); 1185 1186 client->state = S_INIT; 1187 state_init(); 1188 return; 1189 } 1190 1191 /* Do the exponential backoff... */ 1192 if (!client->interval) 1193 client->interval = config->initial_interval; 1194 else 1195 client->interval += ((arc4random() >> 2) % 1196 (2 * client->interval)); 1197 1198 /* Don't backoff past cutoff. */ 1199 if (client->interval > config->backoff_cutoff) 1200 client->interval = ((config->backoff_cutoff / 2) + 1201 ((arc4random() >> 2) % client->interval)); 1202 1203 /* If the backoff would take us to the expiry time, just set the 1204 timeout to the expiry time. */ 1205 if (client->state != S_REQUESTING && cur_time + client->interval > 1206 client->active->expiry) 1207 client->interval = client->active->expiry - cur_time + 1; 1208 1209 /* If the lease T2 time has elapsed, or if we're not yet bound, 1210 broadcast the DHCPREQUEST rather than unicasting. */ 1211 memset(&destination, 0, sizeof(destination)); 1212 if (client->state == S_REQUESTING || 1213 client->state == S_REBOOTING || 1214 cur_time > client->active->rebind) 1215 destination.sin_addr.s_addr = INADDR_BROADCAST; 1216 else 1217 memcpy(&destination.sin_addr.s_addr, client->destination.iabuf, 1218 sizeof(destination.sin_addr.s_addr)); 1219 destination.sin_port = htons(REMOTE_PORT); 1220 destination.sin_family = AF_INET; 1221 destination.sin_len = sizeof(destination); 1222 1223 if (client->state != S_REQUESTING) 1224 memcpy(&from, client->active->address.iabuf, sizeof(from)); 1225 else 1226 from.s_addr = INADDR_ANY; 1227 1228 /* Record the number of seconds since we started sending. */ 1229 if (client->state == S_REQUESTING) 1230 client->packet.secs = client->secs; 1231 else { 1232 if (interval < 65536) 1233 client->packet.secs = htons(interval); 1234 else 1235 client->packet.secs = htons(65535); 1236 } 1237 1238 note("DHCPREQUEST on %s to %s port %d", ifi->name, 1239 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); 1240 1241 /* Send out a packet. */ 1242 send_packet(from, &destination, NULL); 1243 1244 add_timeout(cur_time + client->interval, send_request); 1245 } 1246 1247 void 1248 send_decline(void) 1249 { 1250 note("DHCPDECLINE on %s to %s port %d", ifi->name, 1251 inet_ntoa(sockaddr_broadcast.sin_addr), 1252 ntohs(sockaddr_broadcast.sin_port)); 1253 1254 /* Send out a packet. */ 1255 send_packet(inaddr_any, &sockaddr_broadcast, NULL); 1256 } 1257 1258 void 1259 make_discover(struct client_lease *lease) 1260 { 1261 unsigned char discover = DHCPDISCOVER; 1262 struct option_data options[256]; 1263 int i; 1264 1265 memset(options, 0, sizeof(options)); 1266 memset(&client->packet, 0, sizeof(client->packet)); 1267 1268 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ 1269 i = DHO_DHCP_MESSAGE_TYPE; 1270 options[i].data = &discover; 1271 options[i].len = sizeof(discover); 1272 1273 /* Request the options we want */ 1274 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1275 options[i].data = config->requested_options; 1276 options[i].len = config->requested_option_count; 1277 1278 /* If we had an address, try to get it again. */ 1279 if (lease) { 1280 client->requested_address = lease->address; 1281 i = DHO_DHCP_REQUESTED_ADDRESS; 1282 options[i].data = lease->address.iabuf; 1283 options[i].len = lease->address.len; 1284 } else 1285 client->requested_address.len = 0; 1286 1287 /* Send any options requested in the config file. */ 1288 for (i = 0; i < 256; i++) 1289 if (!options[i].data && 1290 config->send_options[i].data) { 1291 options[i].data = config->send_options[i].data; 1292 options[i].len = config->send_options[i].len; 1293 } 1294 1295 /* Set up the option buffer to fit in a minimal UDP packet. */ 1296 i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN, 1297 options); 1298 if (i == -1 || client->packet.options[i] != DHO_END) 1299 error("options do not fit in DHCPDISCOVER packet."); 1300 client->packet_length = DHCP_FIXED_NON_UDP+i+1; 1301 if (client->packet_length < BOOTP_MIN_LEN) 1302 client->packet_length = BOOTP_MIN_LEN; 1303 1304 client->packet.op = BOOTREQUEST; 1305 client->packet.htype = ifi->hw_address.htype; 1306 client->packet.hlen = ifi->hw_address.hlen; 1307 client->packet.hops = 0; 1308 client->packet.xid = arc4random(); 1309 client->packet.secs = 0; /* filled in by send_discover. */ 1310 client->packet.flags = 0; 1311 1312 memset(&client->packet.ciaddr, 0, sizeof(client->packet.ciaddr)); 1313 memset(&client->packet.yiaddr, 0, sizeof(client->packet.yiaddr)); 1314 memset(&client->packet.siaddr, 0, sizeof(client->packet.siaddr)); 1315 memset(&client->packet.giaddr, 0, sizeof(client->packet.giaddr)); 1316 memcpy(client->packet.chaddr, ifi->hw_address.haddr, 1317 ifi->hw_address.hlen); 1318 } 1319 1320 void 1321 make_request(struct client_lease * lease) 1322 { 1323 unsigned char request = DHCPREQUEST; 1324 struct option_data options[256]; 1325 int i; 1326 1327 memset(options, 0, sizeof(options)); 1328 memset(&client->packet, 0, sizeof(client->packet)); 1329 1330 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ 1331 i = DHO_DHCP_MESSAGE_TYPE; 1332 options[i].data = &request; 1333 options[i].len = sizeof(request); 1334 1335 /* Request the options we want */ 1336 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1337 options[i].data = config->requested_options; 1338 options[i].len = config->requested_option_count; 1339 1340 /* If we are requesting an address that hasn't yet been assigned 1341 to us, use the DHCP Requested Address option. */ 1342 if (client->state == S_REQUESTING) { 1343 /* Send back the server identifier... */ 1344 i = DHO_DHCP_SERVER_IDENTIFIER; 1345 options[i].data = lease->options[i].data; 1346 options[i].len = lease->options[i].len; 1347 } 1348 if (client->state == S_REQUESTING || 1349 client->state == S_REBOOTING) { 1350 client->requested_address = lease->address; 1351 i = DHO_DHCP_REQUESTED_ADDRESS; 1352 options[i].data = lease->address.iabuf; 1353 options[i].len = lease->address.len; 1354 } else 1355 client->requested_address.len = 0; 1356 1357 /* Send any options requested in the config file. */ 1358 for (i = 0; i < 256; i++) 1359 if (!options[i].data && config->send_options[i].data) { 1360 options[i].data = config->send_options[i].data; 1361 options[i].len = config->send_options[i].len; 1362 } 1363 1364 /* Set up the option buffer to fit in a minimal UDP packet. */ 1365 i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN, 1366 options); 1367 if (i == -1 || client->packet.options[i] != DHO_END) 1368 error("options do not fit in DHCPREQUEST packet."); 1369 client->packet_length = DHCP_FIXED_NON_UDP+i+1; 1370 if (client->packet_length < BOOTP_MIN_LEN) 1371 client->packet_length = BOOTP_MIN_LEN; 1372 1373 client->packet.op = BOOTREQUEST; 1374 client->packet.htype = ifi->hw_address.htype; 1375 client->packet.hlen = ifi->hw_address.hlen; 1376 client->packet.hops = 0; 1377 client->packet.xid = client->xid; 1378 client->packet.secs = 0; /* Filled in by send_request. */ 1379 client->packet.flags = 0; 1380 1381 /* If we own the address we're requesting, put it in ciaddr; 1382 otherwise set ciaddr to zero. */ 1383 if (client->state == S_BOUND || 1384 client->state == S_RENEWING || 1385 client->state == S_REBINDING) { 1386 memcpy(&client->packet.ciaddr, 1387 lease->address.iabuf, lease->address.len); 1388 } else { 1389 memset(&client->packet.ciaddr, 0, 1390 sizeof(client->packet.ciaddr)); 1391 } 1392 1393 memset(&client->packet.yiaddr, 0, sizeof(client->packet.yiaddr)); 1394 memset(&client->packet.siaddr, 0, sizeof(client->packet.siaddr)); 1395 memset(&client->packet.giaddr, 0, sizeof(client->packet.giaddr)); 1396 memcpy(client->packet.chaddr, ifi->hw_address.haddr, 1397 ifi->hw_address.hlen); 1398 } 1399 1400 void 1401 make_decline(struct client_lease *lease) 1402 { 1403 struct option_data options[256]; 1404 unsigned char decline = DHCPDECLINE; 1405 int i; 1406 1407 memset(options, 0, sizeof(options)); 1408 memset(&client->packet, 0, sizeof(client->packet)); 1409 1410 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ 1411 i = DHO_DHCP_MESSAGE_TYPE; 1412 options[i].data = &decline; 1413 options[i].len = sizeof(decline); 1414 1415 /* Send back the server identifier... */ 1416 i = DHO_DHCP_SERVER_IDENTIFIER; 1417 options[i].data = lease->options[i].data; 1418 options[i].len = lease->options[i].len; 1419 1420 /* Send back the address we're declining. */ 1421 i = DHO_DHCP_REQUESTED_ADDRESS; 1422 options[i].data = lease->address.iabuf; 1423 options[i].len = lease->address.len; 1424 1425 /* Send the uid if the user supplied one. */ 1426 i = DHO_DHCP_CLIENT_IDENTIFIER; 1427 if (config->send_options[i].len) { 1428 options[i].data = config->send_options[i].data; 1429 options[i].len = config->send_options[i].len; 1430 } 1431 1432 /* Set up the option buffer to fit in a minimal UDP packet. */ 1433 i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN, 1434 options); 1435 if (i == -1 || client->packet.options[i] != DHO_END) 1436 error("options do not fit in DHCPDECLINE packet."); 1437 client->packet_length = DHCP_FIXED_NON_UDP+i+1; 1438 if (client->packet_length < BOOTP_MIN_LEN) 1439 client->packet_length = BOOTP_MIN_LEN; 1440 1441 client->packet.op = BOOTREQUEST; 1442 client->packet.htype = ifi->hw_address.htype; 1443 client->packet.hlen = ifi->hw_address.hlen; 1444 client->packet.hops = 0; 1445 client->packet.xid = client->xid; 1446 client->packet.secs = 0; /* Filled in by send_request. */ 1447 client->packet.flags = 0; 1448 1449 /* ciaddr must always be zero. */ 1450 memset(&client->packet.ciaddr, 0, sizeof(client->packet.ciaddr)); 1451 memset(&client->packet.yiaddr, 0, sizeof(client->packet.yiaddr)); 1452 memset(&client->packet.siaddr, 0, sizeof(client->packet.siaddr)); 1453 memset(&client->packet.giaddr, 0, sizeof(client->packet.giaddr)); 1454 memcpy(client->packet.chaddr, ifi->hw_address.haddr, 1455 ifi->hw_address.hlen); 1456 } 1457 1458 void 1459 free_client_lease(struct client_lease *lease) 1460 { 1461 int i; 1462 1463 if (lease->server_name) 1464 free(lease->server_name); 1465 if (lease->filename) 1466 free(lease->filename); 1467 for (i = 0; i < 256; i++) { 1468 if (lease->options[i].len) 1469 free(lease->options[i].data); 1470 } 1471 free(lease); 1472 } 1473 1474 void 1475 rewrite_client_leases(void) 1476 { 1477 struct client_lease *lp; 1478 1479 if (!leaseFile) /* XXX */ 1480 error("lease file not open"); 1481 1482 fflush(leaseFile); 1483 rewind(leaseFile); 1484 1485 for (lp = client->leases; lp; lp = lp->next) 1486 write_client_lease(lp, 1); 1487 if (client->active) 1488 write_client_lease(client->active, 1); 1489 1490 fflush(leaseFile); 1491 ftruncate(fileno(leaseFile), ftello(leaseFile)); 1492 fsync(fileno(leaseFile)); 1493 } 1494 1495 void 1496 write_client_lease(struct client_lease *lease, int rewrite) 1497 { 1498 static int leases_written; 1499 struct tm *t; 1500 int i; 1501 1502 if (!rewrite) { 1503 if (leases_written++ > 20) { 1504 rewrite_client_leases(); 1505 leases_written = 0; 1506 } 1507 } 1508 1509 /* If the lease came from the config file, we don't need to stash 1510 a copy in the lease database. */ 1511 if (lease->is_static) 1512 return; 1513 1514 if (!leaseFile) /* XXX */ 1515 error("lease file not open"); 1516 1517 fprintf(leaseFile, "lease {\n"); 1518 if (lease->is_bootp) 1519 fprintf(leaseFile, " bootp;\n"); 1520 fprintf(leaseFile, " interface \"%s\";\n", ifi->name); 1521 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); 1522 if (lease->filename) 1523 fprintf(leaseFile, " filename \"%s\";\n", lease->filename); 1524 if (lease->server_name) 1525 fprintf(leaseFile, " server-name \"%s\";\n", 1526 lease->server_name); 1527 if (lease->medium) 1528 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); 1529 for (i = 0; i < 256; i++) 1530 if (lease->options[i].len) 1531 fprintf(leaseFile, " option %s %s;\n", 1532 dhcp_options[i].name, 1533 pretty_print_option(i, lease->options[i].data, 1534 lease->options[i].len, 1, 1)); 1535 1536 t = gmtime(&lease->renewal); 1537 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", 1538 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1539 t->tm_hour, t->tm_min, t->tm_sec); 1540 t = gmtime(&lease->rebind); 1541 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", 1542 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1543 t->tm_hour, t->tm_min, t->tm_sec); 1544 t = gmtime(&lease->expiry); 1545 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", 1546 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1547 t->tm_hour, t->tm_min, t->tm_sec); 1548 fprintf(leaseFile, "}\n"); 1549 fflush(leaseFile); 1550 } 1551 1552 void 1553 script_init(char *reason, struct string_list *medium) 1554 { 1555 size_t len, mediumlen = 0; 1556 struct imsg_hdr hdr; 1557 struct buf *buf; 1558 1559 if (medium != NULL && medium->string != NULL) 1560 mediumlen = strlen(medium->string); 1561 1562 hdr.code = IMSG_SCRIPT_INIT; 1563 hdr.len = sizeof(struct imsg_hdr) + 1564 sizeof(size_t) + mediumlen + 1565 sizeof(size_t) + strlen(reason); 1566 1567 buf = buf_open(hdr.len); 1568 1569 buf_add(buf, &hdr, sizeof(hdr)); 1570 buf_add(buf, &mediumlen, sizeof(mediumlen)); 1571 if (mediumlen > 0) 1572 buf_add(buf, medium->string, mediumlen); 1573 len = strlen(reason); 1574 buf_add(buf, &len, sizeof(len)); 1575 buf_add(buf, reason, len); 1576 1577 buf_close(privfd, buf); 1578 } 1579 1580 void 1581 priv_script_init(char *reason, char *medium) 1582 { 1583 client->scriptEnvsize = 100; 1584 if (client->scriptEnv == NULL) 1585 client->scriptEnv = 1586 calloc(client->scriptEnvsize, sizeof(char *)); 1587 if (client->scriptEnv == NULL) 1588 error("script_init: no memory for environment"); 1589 1590 client->scriptEnv[0] = strdup(CLIENT_PATH); 1591 if (client->scriptEnv[0] == NULL) 1592 error("script_init: no memory for environment"); 1593 1594 client->scriptEnv[1] = NULL; 1595 1596 script_set_env("", "interface", ifi->name); 1597 1598 if (medium) 1599 script_set_env("", "medium", medium); 1600 1601 script_set_env("", "reason", reason); 1602 } 1603 1604 void 1605 priv_script_write_params(char *prefix, struct client_lease *lease) 1606 { 1607 u_int8_t dbuf[1500]; 1608 int i, len = 0; 1609 char tbuf[128]; 1610 1611 script_set_env(prefix, "ip_address", piaddr(lease->address)); 1612 1613 if (lease->options[DHO_SUBNET_MASK].len && 1614 (lease->options[DHO_SUBNET_MASK].len < 1615 sizeof(lease->address.iabuf))) { 1616 struct iaddr netmask, subnet, broadcast; 1617 1618 memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data, 1619 lease->options[DHO_SUBNET_MASK].len); 1620 netmask.len = lease->options[DHO_SUBNET_MASK].len; 1621 1622 subnet = subnet_number(lease->address, netmask); 1623 if (subnet.len) { 1624 script_set_env(prefix, "network_number", 1625 piaddr(subnet)); 1626 if (!lease->options[DHO_BROADCAST_ADDRESS].len) { 1627 broadcast = broadcast_addr(subnet, netmask); 1628 if (broadcast.len) 1629 script_set_env(prefix, 1630 "broadcast_address", 1631 piaddr(broadcast)); 1632 } 1633 } 1634 } 1635 1636 if (lease->filename) 1637 script_set_env(prefix, "filename", lease->filename); 1638 if (lease->server_name) 1639 script_set_env(prefix, "server_name", 1640 lease->server_name); 1641 for (i = 0; i < 256; i++) { 1642 u_int8_t *dp = NULL; 1643 1644 if (config->defaults[i].len) { 1645 if (lease->options[i].len) { 1646 switch (config->default_actions[i]) { 1647 case ACTION_DEFAULT: 1648 dp = lease->options[i].data; 1649 len = lease->options[i].len; 1650 break; 1651 case ACTION_SUPERSEDE: 1652 supersede: 1653 dp = config->defaults[i].data; 1654 len = config->defaults[i].len; 1655 break; 1656 case ACTION_PREPEND: 1657 len = config->defaults[i].len + 1658 lease->options[i].len; 1659 if (len > sizeof(dbuf)) { 1660 warning("no space to %s %s", 1661 "prepend option", 1662 dhcp_options[i].name); 1663 goto supersede; 1664 } 1665 dp = dbuf; 1666 memcpy(dp, 1667 config->defaults[i].data, 1668 config->defaults[i].len); 1669 memcpy(dp + 1670 config->defaults[i].len, 1671 lease->options[i].data, 1672 lease->options[i].len); 1673 dp[len] = '\0'; 1674 break; 1675 case ACTION_APPEND: 1676 len = config->defaults[i].len + 1677 lease->options[i].len; 1678 if (len > sizeof(dbuf)) { 1679 warning("no space to %s %s", 1680 "append option", 1681 dhcp_options[i].name); 1682 goto supersede; 1683 } 1684 dp = dbuf; 1685 memcpy(dp, lease->options[i].data, 1686 lease->options[i].len); 1687 memcpy(dp + lease->options[i].len, 1688 config->defaults[i].data, 1689 config->defaults[i].len); 1690 dp[len] = '\0'; 1691 } 1692 } else { 1693 dp = config->defaults[i].data; 1694 len = config->defaults[i].len; 1695 } 1696 } else if (lease->options[i].len) { 1697 len = lease->options[i].len; 1698 dp = lease->options[i].data; 1699 } else { 1700 len = 0; 1701 } 1702 if (len) { 1703 char name[256]; 1704 1705 if (dhcp_option_ev_name(name, sizeof(name), 1706 &dhcp_options[i])) 1707 script_set_env(prefix, name, 1708 pretty_print_option(i, dp, len, 0, 0)); 1709 } 1710 } 1711 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); 1712 script_set_env(prefix, "expiry", tbuf); 1713 } 1714 1715 void 1716 script_write_params(char *prefix, struct client_lease *lease) 1717 { 1718 size_t fn_len = 0, sn_len = 0, pr_len = 0; 1719 struct imsg_hdr hdr; 1720 struct buf *buf; 1721 int i; 1722 1723 if (lease->filename != NULL) 1724 fn_len = strlen(lease->filename); 1725 if (lease->server_name != NULL) 1726 sn_len = strlen(lease->server_name); 1727 if (prefix != NULL) 1728 pr_len = strlen(prefix); 1729 1730 hdr.code = IMSG_SCRIPT_WRITE_PARAMS; 1731 hdr.len = sizeof(hdr) + sizeof(struct client_lease) + 1732 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len + 1733 sizeof(size_t) + pr_len; 1734 1735 for (i = 0; i < 256; i++) 1736 hdr.len += sizeof(int) + lease->options[i].len; 1737 1738 scripttime = time(NULL); 1739 1740 buf = buf_open(hdr.len); 1741 1742 buf_add(buf, &hdr, sizeof(hdr)); 1743 buf_add(buf, lease, sizeof(struct client_lease)); 1744 buf_add(buf, &fn_len, sizeof(fn_len)); 1745 buf_add(buf, lease->filename, fn_len); 1746 buf_add(buf, &sn_len, sizeof(sn_len)); 1747 buf_add(buf, lease->server_name, sn_len); 1748 buf_add(buf, &pr_len, sizeof(pr_len)); 1749 buf_add(buf, prefix, pr_len); 1750 1751 for (i = 0; i < 256; i++) { 1752 buf_add(buf, &lease->options[i].len, 1753 sizeof(lease->options[i].len)); 1754 buf_add(buf, lease->options[i].data, 1755 lease->options[i].len); 1756 } 1757 1758 buf_close(privfd, buf); 1759 } 1760 1761 int 1762 script_go(void) 1763 { 1764 struct imsg_hdr hdr; 1765 struct buf *buf; 1766 int ret; 1767 1768 scripttime = time(NULL); 1769 1770 hdr.code = IMSG_SCRIPT_GO; 1771 hdr.len = sizeof(struct imsg_hdr); 1772 1773 buf = buf_open(hdr.len); 1774 1775 buf_add(buf, &hdr, sizeof(hdr)); 1776 buf_close(privfd, buf); 1777 1778 bzero(&hdr, sizeof(hdr)); 1779 buf_read(privfd, &hdr, sizeof(hdr)); 1780 if (hdr.code != IMSG_SCRIPT_GO_RET) 1781 error("unexpected msg type %u", hdr.code); 1782 if (hdr.len != sizeof(hdr) + sizeof(int)) 1783 error("received corrupted message"); 1784 buf_read(privfd, &ret, sizeof(ret)); 1785 1786 return (ret); 1787 } 1788 1789 int 1790 priv_script_go(void) 1791 { 1792 char *scriptName, *argv[2], **envp; 1793 int pid, wpid, wstatus; 1794 1795 scripttime = time(NULL); 1796 1797 scriptName = config->script_name; 1798 envp = client->scriptEnv; 1799 1800 argv[0] = scriptName; 1801 argv[1] = NULL; 1802 1803 pid = fork(); 1804 if (pid < 0) { 1805 error("fork: %m"); 1806 wstatus = 0; 1807 } else if (pid) { 1808 do { 1809 wpid = wait(&wstatus); 1810 } while (wpid != pid && wpid > 0); 1811 if (wpid < 0) { 1812 error("wait: %m"); 1813 wstatus = 0; 1814 } 1815 } else { 1816 execve(scriptName, argv, envp); 1817 error("execve (%s, ...): %m", scriptName); 1818 } 1819 1820 script_flush_env(); 1821 1822 return (WEXITSTATUS(wstatus)); 1823 } 1824 1825 void 1826 script_set_env(const char *prefix, const char *name, const char *value) 1827 { 1828 int i, j, namelen; 1829 1830 namelen = strlen(name); 1831 1832 for (i = 0; client->scriptEnv[i]; i++) 1833 if (strncmp(client->scriptEnv[i], name, namelen) == 0 && 1834 client->scriptEnv[i][namelen] == '=') 1835 break; 1836 1837 if (client->scriptEnv[i]) 1838 /* Reuse the slot. */ 1839 free(client->scriptEnv[i]); 1840 else { 1841 /* New variable. Expand if necessary. */ 1842 if (i >= client->scriptEnvsize - 1) { 1843 char **newscriptEnv; 1844 int newscriptEnvsize = client->scriptEnvsize + 50; 1845 1846 newscriptEnv = realloc(client->scriptEnv, 1847 newscriptEnvsize); 1848 if (newscriptEnv == NULL) { 1849 free(client->scriptEnv); 1850 client->scriptEnv = NULL; 1851 client->scriptEnvsize = 0; 1852 error("script_set_env: no memory for variable"); 1853 } 1854 client->scriptEnv = newscriptEnv; 1855 client->scriptEnvsize = newscriptEnvsize; 1856 } 1857 /* need to set the NULL pointer at end of array beyond 1858 the new slot. */ 1859 client->scriptEnv[i + 1] = NULL; 1860 } 1861 /* Allocate space and format the variable in the appropriate slot. */ 1862 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + 1863 strlen(value) + 1); 1864 if (client->scriptEnv[i] == NULL) 1865 error("script_set_env: no memory for variable assignment"); 1866 1867 /* No `` or $() command substitution allowed in environment values! */ 1868 for (j = 0; j < strlen(value); j++) 1869 switch (value[j]) { 1870 case '`': 1871 case '$': 1872 error("illegal character (%c) in value '%s'", value[j], 1873 value); 1874 /* not reached */ 1875 } 1876 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 1877 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); 1878 } 1879 1880 void 1881 script_flush_env(void) 1882 { 1883 int i; 1884 1885 for (i = 0; client->scriptEnv[i]; i++) { 1886 free(client->scriptEnv[i]); 1887 client->scriptEnv[i] = NULL; 1888 } 1889 client->scriptEnvsize = 0; 1890 } 1891 1892 int 1893 dhcp_option_ev_name(char *buf, size_t buflen, const struct option *option) 1894 { 1895 size_t i; 1896 1897 for (i = 0; option->name[i]; i++) { 1898 if (i + 1 == buflen) 1899 return 0; 1900 if (option->name[i] == '-') 1901 buf[i] = '_'; 1902 else 1903 buf[i] = option->name[i]; 1904 } 1905 1906 buf[i] = 0; 1907 return 1; 1908 } 1909 1910 void 1911 go_daemon(void) 1912 { 1913 static int state = 0; 1914 1915 if (no_daemon || state) 1916 return; 1917 1918 state = 1; 1919 1920 /* Stop logging to stderr... */ 1921 log_perror = 0; 1922 1923 if (daemon(1, 0) == -1) 1924 error("daemon"); 1925 1926 /* we are chrooted, daemon(3) fails to open /dev/null */ 1927 if (nullfd != -1) { 1928 dup2(nullfd, STDIN_FILENO); 1929 dup2(nullfd, STDOUT_FILENO); 1930 dup2(nullfd, STDERR_FILENO); 1931 close(nullfd); 1932 nullfd = -1; 1933 } 1934 } 1935 1936 int 1937 check_option(struct client_lease *l, int option) 1938 { 1939 char *opbuf; 1940 char *sbuf; 1941 1942 /* we use this, since this is what gets passed to dhclient-script */ 1943 1944 opbuf = pretty_print_option(option, l->options[option].data, 1945 l->options[option].len, 0, 0); 1946 1947 sbuf = option_as_string(option, l->options[option].data, 1948 l->options[option].len); 1949 1950 switch (option) { 1951 case DHO_SUBNET_MASK: 1952 case DHO_TIME_SERVERS: 1953 case DHO_NAME_SERVERS: 1954 case DHO_ROUTERS: 1955 case DHO_DOMAIN_NAME_SERVERS: 1956 case DHO_LOG_SERVERS: 1957 case DHO_COOKIE_SERVERS: 1958 case DHO_LPR_SERVERS: 1959 case DHO_IMPRESS_SERVERS: 1960 case DHO_RESOURCE_LOCATION_SERVERS: 1961 case DHO_SWAP_SERVER: 1962 case DHO_BROADCAST_ADDRESS: 1963 case DHO_NIS_SERVERS: 1964 case DHO_NTP_SERVERS: 1965 case DHO_NETBIOS_NAME_SERVERS: 1966 case DHO_NETBIOS_DD_SERVER: 1967 case DHO_FONT_SERVERS: 1968 case DHO_DHCP_SERVER_IDENTIFIER: 1969 if (!ipv4addrs(opbuf)) { 1970 warning("Invalid IP address in option: %s", opbuf); 1971 return (0); 1972 } 1973 return (1); 1974 case DHO_HOST_NAME: 1975 case DHO_DOMAIN_NAME: 1976 case DHO_NIS_DOMAIN: 1977 if (!res_hnok(sbuf)) { 1978 warning("Bogus Host Name option %d: %s (%s)", option, 1979 sbuf, opbuf); 1980 l->options[option].len = 0; 1981 free(l->options[option].data); 1982 } 1983 return (1); 1984 case DHO_PAD: 1985 case DHO_TIME_OFFSET: 1986 case DHO_BOOT_SIZE: 1987 case DHO_MERIT_DUMP: 1988 case DHO_ROOT_PATH: 1989 case DHO_EXTENSIONS_PATH: 1990 case DHO_IP_FORWARDING: 1991 case DHO_NON_LOCAL_SOURCE_ROUTING: 1992 case DHO_POLICY_FILTER: 1993 case DHO_MAX_DGRAM_REASSEMBLY: 1994 case DHO_DEFAULT_IP_TTL: 1995 case DHO_PATH_MTU_AGING_TIMEOUT: 1996 case DHO_PATH_MTU_PLATEAU_TABLE: 1997 case DHO_INTERFACE_MTU: 1998 case DHO_ALL_SUBNETS_LOCAL: 1999 case DHO_PERFORM_MASK_DISCOVERY: 2000 case DHO_MASK_SUPPLIER: 2001 case DHO_ROUTER_DISCOVERY: 2002 case DHO_ROUTER_SOLICITATION_ADDRESS: 2003 case DHO_STATIC_ROUTES: 2004 case DHO_TRAILER_ENCAPSULATION: 2005 case DHO_ARP_CACHE_TIMEOUT: 2006 case DHO_IEEE802_3_ENCAPSULATION: 2007 case DHO_DEFAULT_TCP_TTL: 2008 case DHO_TCP_KEEPALIVE_INTERVAL: 2009 case DHO_TCP_KEEPALIVE_GARBAGE: 2010 case DHO_VENDOR_ENCAPSULATED_OPTIONS: 2011 case DHO_NETBIOS_NODE_TYPE: 2012 case DHO_NETBIOS_SCOPE: 2013 case DHO_X_DISPLAY_MANAGER: 2014 case DHO_DHCP_REQUESTED_ADDRESS: 2015 case DHO_DHCP_LEASE_TIME: 2016 case DHO_DHCP_OPTION_OVERLOAD: 2017 case DHO_DHCP_MESSAGE_TYPE: 2018 case DHO_DHCP_PARAMETER_REQUEST_LIST: 2019 case DHO_DHCP_MESSAGE: 2020 case DHO_DHCP_MAX_MESSAGE_SIZE: 2021 case DHO_DHCP_RENEWAL_TIME: 2022 case DHO_DHCP_REBINDING_TIME: 2023 case DHO_DHCP_CLASS_IDENTIFIER: 2024 case DHO_DHCP_CLIENT_IDENTIFIER: 2025 case DHO_DHCP_USER_CLASS_ID: 2026 case DHO_END: 2027 return (1); 2028 default: 2029 warning("unknown dhcp option value 0x%x", option); 2030 return (unknown_ok); 2031 } 2032 } 2033 2034 int 2035 res_hnok(const char *name) 2036 { 2037 const char *dn = name; 2038 int pch = '.', ch = *dn++; 2039 int warn = 0; 2040 2041 while (ch != '\0') { 2042 int nch = *dn++; 2043 2044 if (ch == '.') { 2045 ; 2046 } else if (pch == '.' || nch == '.' || nch == '\0') { 2047 if (!isalnum(ch)) 2048 return (0); 2049 } else if (!isalnum(ch) && ch != '-' && ch != '_') 2050 return (0); 2051 else if (ch == '_' && warn == 0) { 2052 warning("warning: hostname %s contains an " 2053 "underscore which violates RFC 952", name); 2054 warn++; 2055 } 2056 pch = ch, ch = nch; 2057 } 2058 return (1); 2059 } 2060 2061 /* Does buf consist only of dotted decimal ipv4 addrs? 2062 * return how many if so, 2063 * otherwise, return 0 2064 */ 2065 int 2066 ipv4addrs(char * buf) 2067 { 2068 struct in_addr jnk; 2069 int count = 0; 2070 2071 while (inet_aton(buf, &jnk) == 1){ 2072 count++; 2073 while (*buf == '.' || isdigit(*buf)) 2074 buf++; 2075 if (*buf == '\0') 2076 return (count); 2077 while (*buf == ' ') 2078 buf++; 2079 } 2080 return (0); 2081 } 2082 2083 char * 2084 option_as_string(unsigned int code, unsigned char *data, int len) 2085 { 2086 static char optbuf[32768]; /* XXX */ 2087 char *op = optbuf; 2088 int opleft = sizeof(optbuf); 2089 unsigned char *dp = data; 2090 2091 if (code > 255) 2092 error("option_as_string: bad code %d", code); 2093 2094 for (; dp < data + len; dp++) { 2095 if (!isascii(*dp) || !isprint(*dp)) { 2096 if (dp + 1 != data + len || *dp != 0) { 2097 size_t oplen; 2098 snprintf(op, opleft, "\\%03o", *dp); 2099 oplen = strlen(op); 2100 op += oplen; 2101 opleft -= oplen; 2102 } 2103 } else if (*dp == '"' || *dp == '\'' || *dp == '$' || 2104 *dp == '`' || *dp == '\\') { 2105 *op++ = '\\'; 2106 *op++ = *dp; 2107 opleft -= 2; 2108 } else { 2109 *op++ = *dp; 2110 opleft--; 2111 } 2112 } 2113 if (opleft < 1) 2114 goto toobig; 2115 *op = 0; 2116 return optbuf; 2117 toobig: 2118 warning("dhcp option too large"); 2119 return "<error>"; 2120 } 2121 2122 int 2123 fork_privchld(int fd, int fd2) 2124 { 2125 struct pollfd pfd[1]; 2126 int nfds; 2127 2128 switch (fork()) { 2129 case -1: 2130 error("cannot fork"); 2131 break; 2132 case 0: 2133 break; 2134 default: 2135 return (0); 2136 } 2137 2138 if (chdir("/") == -1) 2139 error("chdir(\"/\")"); 2140 2141 setproctitle("%s [priv]", ifi->name); 2142 2143 dup2(nullfd, STDIN_FILENO); 2144 dup2(nullfd, STDOUT_FILENO); 2145 dup2(nullfd, STDERR_FILENO); 2146 close(nullfd); 2147 close(fd2); 2148 2149 for (;;) { 2150 pfd[0].fd = fd; 2151 pfd[0].events = POLLIN; 2152 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 2153 if (errno != EINTR) 2154 error("poll error"); 2155 2156 if (nfds == 0 || !(pfd[0].revents & POLLIN)) 2157 continue; 2158 2159 dispatch_imsg(fd); 2160 } 2161 } 2162