dhclient.c revision 252633
1/* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */ 2 3/* 4 * Copyright 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 1995, 1996, 1997, 1998, 1999 6 * The Internet Software Consortium. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of The Internet Software Consortium nor the names 18 * of its contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * This software has been written for the Internet Software Consortium 36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 37 * Enterprises. To learn more about the Internet Software Consortium, 38 * see ``http://www.vix.com/isc''. To learn more about Vixie 39 * Enterprises, see ``http://www.vix.com''. 40 * 41 * This client was substantially modified and enhanced by Elliot Poger 42 * for use on Linux while he was working on the MosquitoNet project at 43 * Stanford. 44 * 45 * The current version owes much to Elliot's Linux enhancements, but 46 * was substantially reorganized and partially rewritten by Ted Lemon 47 * so as to use the same networking framework that the Internet Software 48 * Consortium DHCP server uses. Much system-specific configuration code 49 * was moved into a shell script so that as support for more operating 50 * systems is added, it will not be necessary to port and maintain 51 * system-specific configuration code to these operating systems - instead, 52 * the shell script can invoke the native tools to accomplish the same 53 * purpose. 54 */ 55 56#include <sys/cdefs.h> 57__FBSDID("$FreeBSD: head/sbin/dhclient/dhclient.c 252633 2013-07-03 22:22:29Z pjd $"); 58 59#include "dhcpd.h" 60#include "privsep.h" 61 62#include <sys/capability.h> 63 64#include <net80211/ieee80211_freebsd.h> 65 66#ifndef _PATH_VAREMPTY 67#define _PATH_VAREMPTY "/var/empty" 68#endif 69 70#define PERIOD 0x2e 71#define hyphenchar(c) ((c) == 0x2d) 72#define bslashchar(c) ((c) == 0x5c) 73#define periodchar(c) ((c) == PERIOD) 74#define asterchar(c) ((c) == 0x2a) 75#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ 76 ((c) >= 0x61 && (c) <= 0x7a)) 77#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) 78#define whitechar(c) ((c) == ' ' || (c) == '\t') 79 80#define borderchar(c) (alphachar(c) || digitchar(c)) 81#define middlechar(c) (borderchar(c) || hyphenchar(c)) 82#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) 83 84#define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" 85 86time_t cur_time; 87time_t default_lease_time = 43200; /* 12 hours... */ 88 89char *path_dhclient_conf = _PATH_DHCLIENT_CONF; 90char *path_dhclient_db = NULL; 91 92int log_perror = 1; 93int privfd; 94int nullfd = -1; 95 96char hostname[_POSIX_HOST_NAME_MAX + 1]; 97 98struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; 99struct in_addr inaddr_any, inaddr_broadcast; 100 101char *path_dhclient_pidfile; 102struct pidfh *pidfile; 103 104/* 105 * ASSERT_STATE() does nothing now; it used to be 106 * assert (state_is == state_shouldbe). 107 */ 108#define ASSERT_STATE(state_is, state_shouldbe) {} 109 110#define TIME_MAX 2147483647 111 112int log_priority; 113int no_daemon; 114int unknown_ok = 1; 115int routefd; 116 117struct interface_info *ifi; 118 119int findproto(char *, int); 120struct sockaddr *get_ifa(char *, int); 121void routehandler(struct protocol *); 122void usage(void); 123int check_option(struct client_lease *l, int option); 124int check_classless_option(unsigned char *data, int len); 125int ipv4addrs(char * buf); 126int res_hnok(const char *dn); 127int check_search(const char *srch); 128char *option_as_string(unsigned int code, unsigned char *data, int len); 129int fork_privchld(int, int); 130 131#define ROUNDUP(a) \ 132 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 133#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 134 135static time_t scripttime; 136 137int 138findproto(char *cp, int n) 139{ 140 struct sockaddr *sa; 141 int i; 142 143 if (n == 0) 144 return -1; 145 for (i = 1; i; i <<= 1) { 146 if (i & n) { 147 sa = (struct sockaddr *)cp; 148 switch (i) { 149 case RTA_IFA: 150 case RTA_DST: 151 case RTA_GATEWAY: 152 case RTA_NETMASK: 153 if (sa->sa_family == AF_INET) 154 return AF_INET; 155 if (sa->sa_family == AF_INET6) 156 return AF_INET6; 157 break; 158 case RTA_IFP: 159 break; 160 } 161 ADVANCE(cp, sa); 162 } 163 } 164 return (-1); 165} 166 167struct sockaddr * 168get_ifa(char *cp, int n) 169{ 170 struct sockaddr *sa; 171 int i; 172 173 if (n == 0) 174 return (NULL); 175 for (i = 1; i; i <<= 1) 176 if (i & n) { 177 sa = (struct sockaddr *)cp; 178 if (i == RTA_IFA) 179 return (sa); 180 ADVANCE(cp, sa); 181 } 182 183 return (NULL); 184} 185 186struct iaddr defaddr = { 4 }; 187uint8_t curbssid[6]; 188 189static void 190disassoc(void *arg) 191{ 192 struct interface_info *ifi = arg; 193 194 /* 195 * Clear existing state. 196 */ 197 if (ifi->client->active != NULL) { 198 script_init("EXPIRE", NULL); 199 script_write_params("old_", 200 ifi->client->active); 201 if (ifi->client->alias) 202 script_write_params("alias_", 203 ifi->client->alias); 204 script_go(); 205 } 206 ifi->client->state = S_INIT; 207} 208 209/* ARGSUSED */ 210void 211routehandler(struct protocol *p) 212{ 213 char msg[2048], *addr; 214 struct rt_msghdr *rtm; 215 struct if_msghdr *ifm; 216 struct ifa_msghdr *ifam; 217 struct if_announcemsghdr *ifan; 218 struct ieee80211_join_event *jev; 219 struct client_lease *l; 220 time_t t = time(NULL); 221 struct sockaddr *sa; 222 struct iaddr a; 223 ssize_t n; 224 int linkstat; 225 226 n = read(routefd, &msg, sizeof(msg)); 227 rtm = (struct rt_msghdr *)msg; 228 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen || 229 rtm->rtm_version != RTM_VERSION) 230 return; 231 232 switch (rtm->rtm_type) { 233 case RTM_NEWADDR: 234 case RTM_DELADDR: 235 ifam = (struct ifa_msghdr *)rtm; 236 237 if (ifam->ifam_index != ifi->index) 238 break; 239 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) 240 break; 241 if (scripttime == 0 || t < scripttime + 10) 242 break; 243 244 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs); 245 if (sa == NULL) 246 break; 247 248 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) 249 error("king bula sez: len mismatch"); 250 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len); 251 if (addr_eq(a, defaddr)) 252 break; 253 254 for (l = ifi->client->active; l != NULL; l = l->next) 255 if (addr_eq(a, l->address)) 256 break; 257 258 if (l == NULL) /* added/deleted addr is not the one we set */ 259 break; 260 261 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); 262 if (rtm->rtm_type == RTM_NEWADDR) { 263 /* 264 * XXX: If someone other than us adds our address, 265 * should we assume they are taking over from us, 266 * delete the lease record, and exit without modifying 267 * the interface? 268 */ 269 warning("My address (%s) was re-added", addr); 270 } else { 271 warning("My address (%s) was deleted, dhclient exiting", 272 addr); 273 goto die; 274 } 275 break; 276 case RTM_IFINFO: 277 ifm = (struct if_msghdr *)rtm; 278 if (ifm->ifm_index != ifi->index) 279 break; 280 if ((rtm->rtm_flags & RTF_UP) == 0) { 281 warning("Interface %s is down, dhclient exiting", 282 ifi->name); 283 goto die; 284 } 285 linkstat = interface_link_status(ifi->name); 286 if (linkstat != ifi->linkstat) { 287 debug("%s link state %s -> %s", ifi->name, 288 ifi->linkstat ? "up" : "down", 289 linkstat ? "up" : "down"); 290 ifi->linkstat = linkstat; 291 if (linkstat) 292 state_reboot(ifi); 293 } 294 break; 295 case RTM_IFANNOUNCE: 296 ifan = (struct if_announcemsghdr *)rtm; 297 if (ifan->ifan_what == IFAN_DEPARTURE && 298 ifan->ifan_index == ifi->index) { 299 warning("Interface %s is gone, dhclient exiting", 300 ifi->name); 301 goto die; 302 } 303 break; 304 case RTM_IEEE80211: 305 ifan = (struct if_announcemsghdr *)rtm; 306 if (ifan->ifan_index != ifi->index) 307 break; 308 switch (ifan->ifan_what) { 309 case RTM_IEEE80211_ASSOC: 310 case RTM_IEEE80211_REASSOC: 311 /* 312 * Use assoc/reassoc event to kick state machine 313 * in case we roam. Otherwise fall back to the 314 * normal state machine just like a wired network. 315 */ 316 jev = (struct ieee80211_join_event *) &ifan[1]; 317 if (memcmp(curbssid, jev->iev_addr, 6)) { 318 disassoc(ifi); 319 state_reboot(ifi); 320 } 321 memcpy(curbssid, jev->iev_addr, 6); 322 break; 323 } 324 break; 325 default: 326 break; 327 } 328 return; 329 330die: 331 script_init("FAIL", NULL); 332 if (ifi->client->alias) 333 script_write_params("alias_", ifi->client->alias); 334 script_go(); 335 if (pidfile != NULL) 336 pidfile_remove(pidfile); 337 exit(1); 338} 339 340int 341main(int argc, char *argv[]) 342{ 343 extern char *__progname; 344 int ch, fd, quiet = 0, i = 0; 345 int pipe_fd[2]; 346 int immediate_daemon = 0; 347 struct passwd *pw; 348 pid_t otherpid; 349 350 /* Initially, log errors to stderr as well as to syslogd. */ 351 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); 352 setlogmask(LOG_UPTO(LOG_DEBUG)); 353 354 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1) 355 switch (ch) { 356 case 'b': 357 immediate_daemon = 1; 358 break; 359 case 'c': 360 path_dhclient_conf = optarg; 361 break; 362 case 'd': 363 no_daemon = 1; 364 break; 365 case 'l': 366 path_dhclient_db = optarg; 367 break; 368 case 'p': 369 path_dhclient_pidfile = optarg; 370 break; 371 case 'q': 372 quiet = 1; 373 break; 374 case 'u': 375 unknown_ok = 0; 376 break; 377 default: 378 usage(); 379 } 380 381 argc -= optind; 382 argv += optind; 383 384 if (argc != 1) 385 usage(); 386 387 if (path_dhclient_pidfile == NULL) { 388 asprintf(&path_dhclient_pidfile, 389 "%sdhclient.%s.pid", _PATH_VARRUN, *argv); 390 if (path_dhclient_pidfile == NULL) 391 error("asprintf"); 392 } 393 pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid); 394 if (pidfile == NULL) { 395 if (errno == EEXIST) 396 error("dhclient already running, pid: %d.", otherpid); 397 if (errno == EAGAIN) 398 error("dhclient already running."); 399 warning("Cannot open or create pidfile: %m"); 400 } 401 402 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL) 403 error("calloc"); 404 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ) 405 error("Interface name too long"); 406 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s", 407 _PATH_DHCLIENT_DB, ifi->name) == -1) 408 error("asprintf"); 409 410 if (quiet) 411 log_perror = 0; 412 413 tzset(); 414 time(&cur_time); 415 416 inaddr_broadcast.s_addr = INADDR_BROADCAST; 417 inaddr_any.s_addr = INADDR_ANY; 418 419 read_client_conf(); 420 421 /* The next bit is potentially very time-consuming, so write out 422 the pidfile right away. We will write it out again with the 423 correct pid after daemonizing. */ 424 if (pidfile != NULL) 425 pidfile_write(pidfile); 426 427 if (!interface_link_status(ifi->name)) { 428 fprintf(stderr, "%s: no link ...", ifi->name); 429 fflush(stderr); 430 sleep(1); 431 while (!interface_link_status(ifi->name)) { 432 fprintf(stderr, "."); 433 fflush(stderr); 434 if (++i > 10) { 435 fprintf(stderr, " giving up\n"); 436 exit(1); 437 } 438 sleep(1); 439 } 440 fprintf(stderr, " got link\n"); 441 } 442 ifi->linkstat = 1; 443 444 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) 445 error("cannot open %s: %m", _PATH_DEVNULL); 446 447 if ((pw = getpwnam("_dhcp")) == NULL) { 448 warning("no such user: _dhcp, falling back to \"nobody\""); 449 if ((pw = getpwnam("nobody")) == NULL) 450 error("no such user: nobody"); 451 } 452 453 /* 454 * Obtain hostname before entering capability mode - it won't be 455 * possible then, as reading kern.hostname is not permitted. 456 */ 457 if (gethostname(hostname, sizeof(hostname)) < 0) 458 hostname[0] = '\0'; 459 460 /* set up the interface */ 461 discover_interfaces(ifi); 462 463 if (pipe(pipe_fd) == -1) 464 error("pipe"); 465 466 fork_privchld(pipe_fd[0], pipe_fd[1]); 467 468 close(ifi->ufdesc); 469 ifi->ufdesc = -1; 470 close(ifi->wfdesc); 471 ifi->wfdesc = -1; 472 473 close(pipe_fd[0]); 474 privfd = pipe_fd[1]; 475 if (cap_rights_limit(privfd, CAP_READ | CAP_WRITE) < 0 && 476 errno != ENOSYS) { 477 error("can't limit private descriptor: %m"); 478 } 479 480 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) 481 error("can't open and lock %s: %m", path_dhclient_db); 482 read_client_leases(); 483 rewrite_client_leases(); 484 close(fd); 485 486 priv_script_init("PREINIT", NULL); 487 if (ifi->client->alias) 488 priv_script_write_params("alias_", ifi->client->alias); 489 priv_script_go(); 490 491 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) 492 add_protocol("AF_ROUTE", routefd, routehandler, ifi); 493 if (shutdown(routefd, SHUT_WR) < 0) 494 error("can't shutdown route socket: %m"); 495 if (cap_rights_limit(routefd, CAP_POLL_EVENT | CAP_READ) < 0 && 496 errno != ENOSYS) { 497 error("can't limit route socket: %m"); 498 } 499 500 if (chroot(_PATH_VAREMPTY) == -1) 501 error("chroot"); 502 if (chdir("/") == -1) 503 error("chdir(\"/\")"); 504 505 if (setgroups(1, &pw->pw_gid) || 506 setegid(pw->pw_gid) || setgid(pw->pw_gid) || 507 seteuid(pw->pw_uid) || setuid(pw->pw_uid)) 508 error("can't drop privileges: %m"); 509 510 endpwent(); 511 512 setproctitle("%s", ifi->name); 513 514 if (immediate_daemon) 515 go_daemon(); 516 517 ifi->client->state = S_INIT; 518 state_reboot(ifi); 519 520 bootp_packet_handler = do_packet; 521 522 dispatch(); 523 524 /* not reached */ 525 return (0); 526} 527 528void 529usage(void) 530{ 531 extern char *__progname; 532 533 fprintf(stderr, "usage: %s [-bdqu] ", __progname); 534 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n"); 535 exit(1); 536} 537 538/* 539 * Individual States: 540 * 541 * Each routine is called from the dhclient_state_machine() in one of 542 * these conditions: 543 * -> entering INIT state 544 * -> recvpacket_flag == 0: timeout in this state 545 * -> otherwise: received a packet in this state 546 * 547 * Return conditions as handled by dhclient_state_machine(): 548 * Returns 1, sendpacket_flag = 1: send packet, reset timer. 549 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). 550 * Returns 0: finish the nap which was interrupted for no good reason. 551 * 552 * Several per-interface variables are used to keep track of the process: 553 * active_lease: the lease that is being used on the interface 554 * (null pointer if not configured yet). 555 * offered_leases: leases corresponding to DHCPOFFER messages that have 556 * been sent to us by DHCP servers. 557 * acked_leases: leases corresponding to DHCPACK messages that have been 558 * sent to us by DHCP servers. 559 * sendpacket: DHCP packet we're trying to send. 560 * destination: IP address to send sendpacket to 561 * In addition, there are several relevant per-lease variables. 562 * T1_expiry, T2_expiry, lease_expiry: lease milestones 563 * In the active lease, these control the process of renewing the lease; 564 * In leases on the acked_leases list, this simply determines when we 565 * can no longer legitimately use the lease. 566 */ 567 568void 569state_reboot(void *ipp) 570{ 571 struct interface_info *ip = ipp; 572 573 /* If we don't remember an active lease, go straight to INIT. */ 574 if (!ip->client->active || ip->client->active->is_bootp) { 575 state_init(ip); 576 return; 577 } 578 579 /* We are in the rebooting state. */ 580 ip->client->state = S_REBOOTING; 581 582 /* make_request doesn't initialize xid because it normally comes 583 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, 584 so pick an xid now. */ 585 ip->client->xid = arc4random(); 586 587 /* Make a DHCPREQUEST packet, and set appropriate per-interface 588 flags. */ 589 make_request(ip, ip->client->active); 590 ip->client->destination = iaddr_broadcast; 591 ip->client->first_sending = cur_time; 592 ip->client->interval = ip->client->config->initial_interval; 593 594 /* Zap the medium list... */ 595 ip->client->medium = NULL; 596 597 /* Send out the first DHCPREQUEST packet. */ 598 send_request(ip); 599} 600 601/* 602 * Called when a lease has completely expired and we've 603 * been unable to renew it. 604 */ 605void 606state_init(void *ipp) 607{ 608 struct interface_info *ip = ipp; 609 610 ASSERT_STATE(state, S_INIT); 611 612 /* Make a DHCPDISCOVER packet, and set appropriate per-interface 613 flags. */ 614 make_discover(ip, ip->client->active); 615 ip->client->xid = ip->client->packet.xid; 616 ip->client->destination = iaddr_broadcast; 617 ip->client->state = S_SELECTING; 618 ip->client->first_sending = cur_time; 619 ip->client->interval = ip->client->config->initial_interval; 620 621 /* Add an immediate timeout to cause the first DHCPDISCOVER packet 622 to go out. */ 623 send_discover(ip); 624} 625 626/* 627 * state_selecting is called when one or more DHCPOFFER packets 628 * have been received and a configurable period of time has passed. 629 */ 630void 631state_selecting(void *ipp) 632{ 633 struct interface_info *ip = ipp; 634 struct client_lease *lp, *next, *picked; 635 636 ASSERT_STATE(state, S_SELECTING); 637 638 /* Cancel state_selecting and send_discover timeouts, since either 639 one could have got us here. */ 640 cancel_timeout(state_selecting, ip); 641 cancel_timeout(send_discover, ip); 642 643 /* We have received one or more DHCPOFFER packets. Currently, 644 the only criterion by which we judge leases is whether or 645 not we get a response when we arp for them. */ 646 picked = NULL; 647 for (lp = ip->client->offered_leases; lp; lp = next) { 648 next = lp->next; 649 650 /* Check to see if we got an ARPREPLY for the address 651 in this particular lease. */ 652 if (!picked) { 653 script_init("ARPCHECK", lp->medium); 654 script_write_params("check_", lp); 655 656 /* If the ARPCHECK code detects another 657 machine using the offered address, it exits 658 nonzero. We need to send a DHCPDECLINE and 659 toss the lease. */ 660 if (script_go()) { 661 make_decline(ip, lp); 662 send_decline(ip); 663 goto freeit; 664 } 665 picked = lp; 666 picked->next = NULL; 667 } else { 668freeit: 669 free_client_lease(lp); 670 } 671 } 672 ip->client->offered_leases = NULL; 673 674 /* If we just tossed all the leases we were offered, go back 675 to square one. */ 676 if (!picked) { 677 ip->client->state = S_INIT; 678 state_init(ip); 679 return; 680 } 681 682 /* If it was a BOOTREPLY, we can just take the address right now. */ 683 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { 684 ip->client->new = picked; 685 686 /* Make up some lease expiry times 687 XXX these should be configurable. */ 688 ip->client->new->expiry = cur_time + 12000; 689 ip->client->new->renewal += cur_time + 8000; 690 ip->client->new->rebind += cur_time + 10000; 691 692 ip->client->state = S_REQUESTING; 693 694 /* Bind to the address we received. */ 695 bind_lease(ip); 696 return; 697 } 698 699 /* Go to the REQUESTING state. */ 700 ip->client->destination = iaddr_broadcast; 701 ip->client->state = S_REQUESTING; 702 ip->client->first_sending = cur_time; 703 ip->client->interval = ip->client->config->initial_interval; 704 705 /* Make a DHCPREQUEST packet from the lease we picked. */ 706 make_request(ip, picked); 707 ip->client->xid = ip->client->packet.xid; 708 709 /* Toss the lease we picked - we'll get it back in a DHCPACK. */ 710 free_client_lease(picked); 711 712 /* Add an immediate timeout to send the first DHCPREQUEST packet. */ 713 send_request(ip); 714} 715 716/* state_requesting is called when we receive a DHCPACK message after 717 having sent out one or more DHCPREQUEST packets. */ 718 719void 720dhcpack(struct packet *packet) 721{ 722 struct interface_info *ip = packet->interface; 723 struct client_lease *lease; 724 725 /* If we're not receptive to an offer right now, or if the offer 726 has an unrecognizable transaction id, then just drop it. */ 727 if (packet->interface->client->xid != packet->raw->xid || 728 (packet->interface->hw_address.hlen != packet->raw->hlen) || 729 (memcmp(packet->interface->hw_address.haddr, 730 packet->raw->chaddr, packet->raw->hlen))) 731 return; 732 733 if (ip->client->state != S_REBOOTING && 734 ip->client->state != S_REQUESTING && 735 ip->client->state != S_RENEWING && 736 ip->client->state != S_REBINDING) 737 return; 738 739 note("DHCPACK from %s", piaddr(packet->client_addr)); 740 741 lease = packet_to_lease(packet); 742 if (!lease) { 743 note("packet_to_lease failed."); 744 return; 745 } 746 747 ip->client->new = lease; 748 749 /* Stop resending DHCPREQUEST. */ 750 cancel_timeout(send_request, ip); 751 752 /* Figure out the lease time. */ 753 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) 754 ip->client->new->expiry = getULong( 755 ip->client->new->options[DHO_DHCP_LEASE_TIME].data); 756 else 757 ip->client->new->expiry = default_lease_time; 758 /* A number that looks negative here is really just very large, 759 because the lease expiry offset is unsigned. */ 760 if (ip->client->new->expiry < 0) 761 ip->client->new->expiry = TIME_MAX; 762 /* XXX should be fixed by resetting the client state */ 763 if (ip->client->new->expiry < 60) 764 ip->client->new->expiry = 60; 765 766 /* Take the server-provided renewal time if there is one; 767 otherwise figure it out according to the spec. */ 768 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) 769 ip->client->new->renewal = getULong( 770 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); 771 else 772 ip->client->new->renewal = ip->client->new->expiry / 2; 773 774 /* Same deal with the rebind time. */ 775 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) 776 ip->client->new->rebind = getULong( 777 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); 778 else 779 ip->client->new->rebind = ip->client->new->renewal + 780 ip->client->new->renewal / 2 + ip->client->new->renewal / 4; 781 782 ip->client->new->expiry += cur_time; 783 /* Lease lengths can never be negative. */ 784 if (ip->client->new->expiry < cur_time) 785 ip->client->new->expiry = TIME_MAX; 786 ip->client->new->renewal += cur_time; 787 if (ip->client->new->renewal < cur_time) 788 ip->client->new->renewal = TIME_MAX; 789 ip->client->new->rebind += cur_time; 790 if (ip->client->new->rebind < cur_time) 791 ip->client->new->rebind = TIME_MAX; 792 793 bind_lease(ip); 794} 795 796void 797bind_lease(struct interface_info *ip) 798{ 799 /* Remember the medium. */ 800 ip->client->new->medium = ip->client->medium; 801 802 /* Write out the new lease. */ 803 write_client_lease(ip, ip->client->new, 0); 804 805 /* Run the client script with the new parameters. */ 806 script_init((ip->client->state == S_REQUESTING ? "BOUND" : 807 (ip->client->state == S_RENEWING ? "RENEW" : 808 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), 809 ip->client->new->medium); 810 if (ip->client->active && ip->client->state != S_REBOOTING) 811 script_write_params("old_", ip->client->active); 812 script_write_params("new_", ip->client->new); 813 if (ip->client->alias) 814 script_write_params("alias_", ip->client->alias); 815 script_go(); 816 817 /* Replace the old active lease with the new one. */ 818 if (ip->client->active) 819 free_client_lease(ip->client->active); 820 ip->client->active = ip->client->new; 821 ip->client->new = NULL; 822 823 /* Set up a timeout to start the renewal process. */ 824 add_timeout(ip->client->active->renewal, state_bound, ip); 825 826 note("bound to %s -- renewal in %d seconds.", 827 piaddr(ip->client->active->address), 828 (int)(ip->client->active->renewal - cur_time)); 829 ip->client->state = S_BOUND; 830 reinitialize_interfaces(); 831 go_daemon(); 832} 833 834/* 835 * state_bound is called when we've successfully bound to a particular 836 * lease, but the renewal time on that lease has expired. We are 837 * expected to unicast a DHCPREQUEST to the server that gave us our 838 * original lease. 839 */ 840void 841state_bound(void *ipp) 842{ 843 struct interface_info *ip = ipp; 844 845 ASSERT_STATE(state, S_BOUND); 846 847 /* T1 has expired. */ 848 make_request(ip, ip->client->active); 849 ip->client->xid = ip->client->packet.xid; 850 851 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { 852 memcpy(ip->client->destination.iabuf, ip->client->active-> 853 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); 854 ip->client->destination.len = 4; 855 } else 856 ip->client->destination = iaddr_broadcast; 857 858 ip->client->first_sending = cur_time; 859 ip->client->interval = ip->client->config->initial_interval; 860 ip->client->state = S_RENEWING; 861 862 /* Send the first packet immediately. */ 863 send_request(ip); 864} 865 866void 867bootp(struct packet *packet) 868{ 869 struct iaddrlist *ap; 870 871 if (packet->raw->op != BOOTREPLY) 872 return; 873 874 /* If there's a reject list, make sure this packet's sender isn't 875 on it. */ 876 for (ap = packet->interface->client->config->reject_list; 877 ap; ap = ap->next) { 878 if (addr_eq(packet->client_addr, ap->addr)) { 879 note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); 880 return; 881 } 882 } 883 dhcpoffer(packet); 884} 885 886void 887dhcp(struct packet *packet) 888{ 889 struct iaddrlist *ap; 890 void (*handler)(struct packet *); 891 char *type; 892 893 switch (packet->packet_type) { 894 case DHCPOFFER: 895 handler = dhcpoffer; 896 type = "DHCPOFFER"; 897 break; 898 case DHCPNAK: 899 handler = dhcpnak; 900 type = "DHCPNACK"; 901 break; 902 case DHCPACK: 903 handler = dhcpack; 904 type = "DHCPACK"; 905 break; 906 default: 907 return; 908 } 909 910 /* If there's a reject list, make sure this packet's sender isn't 911 on it. */ 912 for (ap = packet->interface->client->config->reject_list; 913 ap; ap = ap->next) { 914 if (addr_eq(packet->client_addr, ap->addr)) { 915 note("%s from %s rejected.", type, piaddr(ap->addr)); 916 return; 917 } 918 } 919 (*handler)(packet); 920} 921 922void 923dhcpoffer(struct packet *packet) 924{ 925 struct interface_info *ip = packet->interface; 926 struct client_lease *lease, *lp; 927 int i; 928 int arp_timeout_needed, stop_selecting; 929 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? 930 "DHCPOFFER" : "BOOTREPLY"; 931 932 /* If we're not receptive to an offer right now, or if the offer 933 has an unrecognizable transaction id, then just drop it. */ 934 if (ip->client->state != S_SELECTING || 935 packet->interface->client->xid != packet->raw->xid || 936 (packet->interface->hw_address.hlen != packet->raw->hlen) || 937 (memcmp(packet->interface->hw_address.haddr, 938 packet->raw->chaddr, packet->raw->hlen))) 939 return; 940 941 note("%s from %s", name, piaddr(packet->client_addr)); 942 943 944 /* If this lease doesn't supply the minimum required parameters, 945 blow it off. */ 946 for (i = 0; ip->client->config->required_options[i]; i++) { 947 if (!packet->options[ip->client->config-> 948 required_options[i]].len) { 949 note("%s isn't satisfactory.", name); 950 return; 951 } 952 } 953 954 /* If we've already seen this lease, don't record it again. */ 955 for (lease = ip->client->offered_leases; 956 lease; lease = lease->next) { 957 if (lease->address.len == sizeof(packet->raw->yiaddr) && 958 !memcmp(lease->address.iabuf, 959 &packet->raw->yiaddr, lease->address.len)) { 960 debug("%s already seen.", name); 961 return; 962 } 963 } 964 965 lease = packet_to_lease(packet); 966 if (!lease) { 967 note("packet_to_lease failed."); 968 return; 969 } 970 971 /* If this lease was acquired through a BOOTREPLY, record that 972 fact. */ 973 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) 974 lease->is_bootp = 1; 975 976 /* Record the medium under which this lease was offered. */ 977 lease->medium = ip->client->medium; 978 979 /* Send out an ARP Request for the offered IP address. */ 980 script_init("ARPSEND", lease->medium); 981 script_write_params("check_", lease); 982 /* If the script can't send an ARP request without waiting, 983 we'll be waiting when we do the ARPCHECK, so don't wait now. */ 984 if (script_go()) 985 arp_timeout_needed = 0; 986 else 987 arp_timeout_needed = 2; 988 989 /* Figure out when we're supposed to stop selecting. */ 990 stop_selecting = 991 ip->client->first_sending + ip->client->config->select_interval; 992 993 /* If this is the lease we asked for, put it at the head of the 994 list, and don't mess with the arp request timeout. */ 995 if (lease->address.len == ip->client->requested_address.len && 996 !memcmp(lease->address.iabuf, 997 ip->client->requested_address.iabuf, 998 ip->client->requested_address.len)) { 999 lease->next = ip->client->offered_leases; 1000 ip->client->offered_leases = lease; 1001 } else { 1002 /* If we already have an offer, and arping for this 1003 offer would take us past the selection timeout, 1004 then don't extend the timeout - just hope for the 1005 best. */ 1006 if (ip->client->offered_leases && 1007 (cur_time + arp_timeout_needed) > stop_selecting) 1008 arp_timeout_needed = 0; 1009 1010 /* Put the lease at the end of the list. */ 1011 lease->next = NULL; 1012 if (!ip->client->offered_leases) 1013 ip->client->offered_leases = lease; 1014 else { 1015 for (lp = ip->client->offered_leases; lp->next; 1016 lp = lp->next) 1017 ; /* nothing */ 1018 lp->next = lease; 1019 } 1020 } 1021 1022 /* If we're supposed to stop selecting before we've had time 1023 to wait for the ARPREPLY, add some delay to wait for 1024 the ARPREPLY. */ 1025 if (stop_selecting - cur_time < arp_timeout_needed) 1026 stop_selecting = cur_time + arp_timeout_needed; 1027 1028 /* If the selecting interval has expired, go immediately to 1029 state_selecting(). Otherwise, time out into 1030 state_selecting at the select interval. */ 1031 if (stop_selecting <= 0) 1032 state_selecting(ip); 1033 else { 1034 add_timeout(stop_selecting, state_selecting, ip); 1035 cancel_timeout(send_discover, ip); 1036 } 1037} 1038 1039/* Allocate a client_lease structure and initialize it from the parameters 1040 in the specified packet. */ 1041 1042struct client_lease * 1043packet_to_lease(struct packet *packet) 1044{ 1045 struct client_lease *lease; 1046 int i; 1047 1048 lease = malloc(sizeof(struct client_lease)); 1049 1050 if (!lease) { 1051 warning("dhcpoffer: no memory to record lease."); 1052 return (NULL); 1053 } 1054 1055 memset(lease, 0, sizeof(*lease)); 1056 1057 /* Copy the lease options. */ 1058 for (i = 0; i < 256; i++) { 1059 if (packet->options[i].len) { 1060 lease->options[i].data = 1061 malloc(packet->options[i].len + 1); 1062 if (!lease->options[i].data) { 1063 warning("dhcpoffer: no memory for option %d", i); 1064 free_client_lease(lease); 1065 return (NULL); 1066 } else { 1067 memcpy(lease->options[i].data, 1068 packet->options[i].data, 1069 packet->options[i].len); 1070 lease->options[i].len = 1071 packet->options[i].len; 1072 lease->options[i].data[lease->options[i].len] = 1073 0; 1074 } 1075 if (!check_option(lease,i)) { 1076 /* ignore a bogus lease offer */ 1077 warning("Invalid lease option - ignoring offer"); 1078 free_client_lease(lease); 1079 return (NULL); 1080 } 1081 } 1082 } 1083 1084 lease->address.len = sizeof(packet->raw->yiaddr); 1085 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); 1086 1087 lease->nextserver.len = sizeof(packet->raw->siaddr); 1088 memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len); 1089 1090 /* If the server name was filled out, copy it. 1091 Do not attempt to validate the server name as a host name. 1092 RFC 2131 merely states that sname is NUL-terminated (which do 1093 do not assume) and that it is the server's host name. Since 1094 the ISC client and server allow arbitrary characters, we do 1095 as well. */ 1096 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 1097 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && 1098 packet->raw->sname[0]) { 1099 lease->server_name = malloc(DHCP_SNAME_LEN + 1); 1100 if (!lease->server_name) { 1101 warning("dhcpoffer: no memory for server name."); 1102 free_client_lease(lease); 1103 return (NULL); 1104 } 1105 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); 1106 lease->server_name[DHCP_SNAME_LEN]='\0'; 1107 } 1108 1109 /* Ditto for the filename. */ 1110 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 1111 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && 1112 packet->raw->file[0]) { 1113 /* Don't count on the NUL terminator. */ 1114 lease->filename = malloc(DHCP_FILE_LEN + 1); 1115 if (!lease->filename) { 1116 warning("dhcpoffer: no memory for filename."); 1117 free_client_lease(lease); 1118 return (NULL); 1119 } 1120 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); 1121 lease->filename[DHCP_FILE_LEN]='\0'; 1122 } 1123 return lease; 1124} 1125 1126void 1127dhcpnak(struct packet *packet) 1128{ 1129 struct interface_info *ip = packet->interface; 1130 1131 /* If we're not receptive to an offer right now, or if the offer 1132 has an unrecognizable transaction id, then just drop it. */ 1133 if (packet->interface->client->xid != packet->raw->xid || 1134 (packet->interface->hw_address.hlen != packet->raw->hlen) || 1135 (memcmp(packet->interface->hw_address.haddr, 1136 packet->raw->chaddr, packet->raw->hlen))) 1137 return; 1138 1139 if (ip->client->state != S_REBOOTING && 1140 ip->client->state != S_REQUESTING && 1141 ip->client->state != S_RENEWING && 1142 ip->client->state != S_REBINDING) 1143 return; 1144 1145 note("DHCPNAK from %s", piaddr(packet->client_addr)); 1146 1147 if (!ip->client->active) { 1148 note("DHCPNAK with no active lease.\n"); 1149 return; 1150 } 1151 1152 free_client_lease(ip->client->active); 1153 ip->client->active = NULL; 1154 1155 /* Stop sending DHCPREQUEST packets... */ 1156 cancel_timeout(send_request, ip); 1157 1158 ip->client->state = S_INIT; 1159 state_init(ip); 1160} 1161 1162/* Send out a DHCPDISCOVER packet, and set a timeout to send out another 1163 one after the right interval has expired. If we don't get an offer by 1164 the time we reach the panic interval, call the panic function. */ 1165 1166void 1167send_discover(void *ipp) 1168{ 1169 struct interface_info *ip = ipp; 1170 int interval, increase = 1; 1171 1172 /* Figure out how long it's been since we started transmitting. */ 1173 interval = cur_time - ip->client->first_sending; 1174 1175 /* If we're past the panic timeout, call the script and tell it 1176 we haven't found anything for this interface yet. */ 1177 if (interval > ip->client->config->timeout) { 1178 state_panic(ip); 1179 return; 1180 } 1181 1182 /* If we're selecting media, try the whole list before doing 1183 the exponential backoff, but if we've already received an 1184 offer, stop looping, because we obviously have it right. */ 1185 if (!ip->client->offered_leases && 1186 ip->client->config->media) { 1187 int fail = 0; 1188again: 1189 if (ip->client->medium) { 1190 ip->client->medium = ip->client->medium->next; 1191 increase = 0; 1192 } 1193 if (!ip->client->medium) { 1194 if (fail) 1195 error("No valid media types for %s!", ip->name); 1196 ip->client->medium = ip->client->config->media; 1197 increase = 1; 1198 } 1199 1200 note("Trying medium \"%s\" %d", ip->client->medium->string, 1201 increase); 1202 script_init("MEDIUM", ip->client->medium); 1203 if (script_go()) 1204 goto again; 1205 } 1206 1207 /* 1208 * If we're supposed to increase the interval, do so. If it's 1209 * currently zero (i.e., we haven't sent any packets yet), set 1210 * it to one; otherwise, add to it a random number between zero 1211 * and two times itself. On average, this means that it will 1212 * double with every transmission. 1213 */ 1214 if (increase) { 1215 if (!ip->client->interval) 1216 ip->client->interval = 1217 ip->client->config->initial_interval; 1218 else { 1219 ip->client->interval += (arc4random() >> 2) % 1220 (2 * ip->client->interval); 1221 } 1222 1223 /* Don't backoff past cutoff. */ 1224 if (ip->client->interval > 1225 ip->client->config->backoff_cutoff) 1226 ip->client->interval = 1227 ((ip->client->config->backoff_cutoff / 2) 1228 + ((arc4random() >> 2) % 1229 ip->client->config->backoff_cutoff)); 1230 } else if (!ip->client->interval) 1231 ip->client->interval = 1232 ip->client->config->initial_interval; 1233 1234 /* If the backoff would take us to the panic timeout, just use that 1235 as the interval. */ 1236 if (cur_time + ip->client->interval > 1237 ip->client->first_sending + ip->client->config->timeout) 1238 ip->client->interval = 1239 (ip->client->first_sending + 1240 ip->client->config->timeout) - cur_time + 1; 1241 1242 /* Record the number of seconds since we started sending. */ 1243 if (interval < 65536) 1244 ip->client->packet.secs = htons(interval); 1245 else 1246 ip->client->packet.secs = htons(65535); 1247 ip->client->secs = ip->client->packet.secs; 1248 1249 note("DHCPDISCOVER on %s to %s port %d interval %d", 1250 ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, 1251 (int)ip->client->interval); 1252 1253 /* Send out a packet. */ 1254 send_packet_unpriv(privfd, &ip->client->packet, 1255 ip->client->packet_length, inaddr_any, inaddr_broadcast); 1256 1257 add_timeout(cur_time + ip->client->interval, send_discover, ip); 1258} 1259 1260/* 1261 * state_panic gets called if we haven't received any offers in a preset 1262 * amount of time. When this happens, we try to use existing leases 1263 * that haven't yet expired, and failing that, we call the client script 1264 * and hope it can do something. 1265 */ 1266void 1267state_panic(void *ipp) 1268{ 1269 struct interface_info *ip = ipp; 1270 struct client_lease *loop = ip->client->active; 1271 struct client_lease *lp; 1272 1273 note("No DHCPOFFERS received."); 1274 1275 /* We may not have an active lease, but we may have some 1276 predefined leases that we can try. */ 1277 if (!ip->client->active && ip->client->leases) 1278 goto activate_next; 1279 1280 /* Run through the list of leases and see if one can be used. */ 1281 while (ip->client->active) { 1282 if (ip->client->active->expiry > cur_time) { 1283 note("Trying recorded lease %s", 1284 piaddr(ip->client->active->address)); 1285 /* Run the client script with the existing 1286 parameters. */ 1287 script_init("TIMEOUT", 1288 ip->client->active->medium); 1289 script_write_params("new_", ip->client->active); 1290 if (ip->client->alias) 1291 script_write_params("alias_", 1292 ip->client->alias); 1293 1294 /* If the old lease is still good and doesn't 1295 yet need renewal, go into BOUND state and 1296 timeout at the renewal time. */ 1297 if (!script_go()) { 1298 if (cur_time < 1299 ip->client->active->renewal) { 1300 ip->client->state = S_BOUND; 1301 note("bound: renewal in %d seconds.", 1302 (int)(ip->client->active->renewal - 1303 cur_time)); 1304 add_timeout( 1305 ip->client->active->renewal, 1306 state_bound, ip); 1307 } else { 1308 ip->client->state = S_BOUND; 1309 note("bound: immediate renewal."); 1310 state_bound(ip); 1311 } 1312 reinitialize_interfaces(); 1313 go_daemon(); 1314 return; 1315 } 1316 } 1317 1318 /* If there are no other leases, give up. */ 1319 if (!ip->client->leases) { 1320 ip->client->leases = ip->client->active; 1321 ip->client->active = NULL; 1322 break; 1323 } 1324 1325activate_next: 1326 /* Otherwise, put the active lease at the end of the 1327 lease list, and try another lease.. */ 1328 for (lp = ip->client->leases; lp->next; lp = lp->next) 1329 ; 1330 lp->next = ip->client->active; 1331 if (lp->next) 1332 lp->next->next = NULL; 1333 ip->client->active = ip->client->leases; 1334 ip->client->leases = ip->client->leases->next; 1335 1336 /* If we already tried this lease, we've exhausted the 1337 set of leases, so we might as well give up for 1338 now. */ 1339 if (ip->client->active == loop) 1340 break; 1341 else if (!loop) 1342 loop = ip->client->active; 1343 } 1344 1345 /* No leases were available, or what was available didn't work, so 1346 tell the shell script that we failed to allocate an address, 1347 and try again later. */ 1348 note("No working leases in persistent database - sleeping.\n"); 1349 script_init("FAIL", NULL); 1350 if (ip->client->alias) 1351 script_write_params("alias_", ip->client->alias); 1352 script_go(); 1353 ip->client->state = S_INIT; 1354 add_timeout(cur_time + ip->client->config->retry_interval, state_init, 1355 ip); 1356 go_daemon(); 1357} 1358 1359void 1360send_request(void *ipp) 1361{ 1362 struct interface_info *ip = ipp; 1363 struct in_addr from, to; 1364 int interval; 1365 1366 /* Figure out how long it's been since we started transmitting. */ 1367 interval = cur_time - ip->client->first_sending; 1368 1369 /* If we're in the INIT-REBOOT or REQUESTING state and we're 1370 past the reboot timeout, go to INIT and see if we can 1371 DISCOVER an address... */ 1372 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it 1373 means either that we're on a network with no DHCP server, 1374 or that our server is down. In the latter case, assuming 1375 that there is a backup DHCP server, DHCPDISCOVER will get 1376 us a new address, but we could also have successfully 1377 reused our old address. In the former case, we're hosed 1378 anyway. This is not a win-prone situation. */ 1379 if ((ip->client->state == S_REBOOTING || 1380 ip->client->state == S_REQUESTING) && 1381 interval > ip->client->config->reboot_timeout) { 1382cancel: 1383 ip->client->state = S_INIT; 1384 cancel_timeout(send_request, ip); 1385 state_init(ip); 1386 return; 1387 } 1388 1389 /* If we're in the reboot state, make sure the media is set up 1390 correctly. */ 1391 if (ip->client->state == S_REBOOTING && 1392 !ip->client->medium && 1393 ip->client->active->medium ) { 1394 script_init("MEDIUM", ip->client->active->medium); 1395 1396 /* If the medium we chose won't fly, go to INIT state. */ 1397 if (script_go()) 1398 goto cancel; 1399 1400 /* Record the medium. */ 1401 ip->client->medium = ip->client->active->medium; 1402 } 1403 1404 /* If the lease has expired, relinquish the address and go back 1405 to the INIT state. */ 1406 if (ip->client->state != S_REQUESTING && 1407 cur_time > ip->client->active->expiry) { 1408 /* Run the client script with the new parameters. */ 1409 script_init("EXPIRE", NULL); 1410 script_write_params("old_", ip->client->active); 1411 if (ip->client->alias) 1412 script_write_params("alias_", ip->client->alias); 1413 script_go(); 1414 1415 /* Now do a preinit on the interface so that we can 1416 discover a new address. */ 1417 script_init("PREINIT", NULL); 1418 if (ip->client->alias) 1419 script_write_params("alias_", ip->client->alias); 1420 script_go(); 1421 1422 ip->client->state = S_INIT; 1423 state_init(ip); 1424 return; 1425 } 1426 1427 /* Do the exponential backoff... */ 1428 if (!ip->client->interval) 1429 ip->client->interval = ip->client->config->initial_interval; 1430 else 1431 ip->client->interval += ((arc4random() >> 2) % 1432 (2 * ip->client->interval)); 1433 1434 /* Don't backoff past cutoff. */ 1435 if (ip->client->interval > 1436 ip->client->config->backoff_cutoff) 1437 ip->client->interval = 1438 ((ip->client->config->backoff_cutoff / 2) + 1439 ((arc4random() >> 2) % ip->client->interval)); 1440 1441 /* If the backoff would take us to the expiry time, just set the 1442 timeout to the expiry time. */ 1443 if (ip->client->state != S_REQUESTING && 1444 cur_time + ip->client->interval > 1445 ip->client->active->expiry) 1446 ip->client->interval = 1447 ip->client->active->expiry - cur_time + 1; 1448 1449 /* If the lease T2 time has elapsed, or if we're not yet bound, 1450 broadcast the DHCPREQUEST rather than unicasting. */ 1451 if (ip->client->state == S_REQUESTING || 1452 ip->client->state == S_REBOOTING || 1453 cur_time > ip->client->active->rebind) 1454 to.s_addr = INADDR_BROADCAST; 1455 else 1456 memcpy(&to.s_addr, ip->client->destination.iabuf, 1457 sizeof(to.s_addr)); 1458 1459 if (ip->client->state != S_REQUESTING) 1460 memcpy(&from, ip->client->active->address.iabuf, 1461 sizeof(from)); 1462 else 1463 from.s_addr = INADDR_ANY; 1464 1465 /* Record the number of seconds since we started sending. */ 1466 if (ip->client->state == S_REQUESTING) 1467 ip->client->packet.secs = ip->client->secs; 1468 else { 1469 if (interval < 65536) 1470 ip->client->packet.secs = htons(interval); 1471 else 1472 ip->client->packet.secs = htons(65535); 1473 } 1474 1475 note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), 1476 REMOTE_PORT); 1477 1478 /* Send out a packet. */ 1479 send_packet_unpriv(privfd, &ip->client->packet, 1480 ip->client->packet_length, from, to); 1481 1482 add_timeout(cur_time + ip->client->interval, send_request, ip); 1483} 1484 1485void 1486send_decline(void *ipp) 1487{ 1488 struct interface_info *ip = ipp; 1489 1490 note("DHCPDECLINE on %s to %s port %d", ip->name, 1491 inet_ntoa(inaddr_broadcast), REMOTE_PORT); 1492 1493 /* Send out a packet. */ 1494 send_packet_unpriv(privfd, &ip->client->packet, 1495 ip->client->packet_length, inaddr_any, inaddr_broadcast); 1496} 1497 1498void 1499make_discover(struct interface_info *ip, struct client_lease *lease) 1500{ 1501 unsigned char discover = DHCPDISCOVER; 1502 struct tree_cache *options[256]; 1503 struct tree_cache option_elements[256]; 1504 int i; 1505 1506 memset(option_elements, 0, sizeof(option_elements)); 1507 memset(options, 0, sizeof(options)); 1508 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1509 1510 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ 1511 i = DHO_DHCP_MESSAGE_TYPE; 1512 options[i] = &option_elements[i]; 1513 options[i]->value = &discover; 1514 options[i]->len = sizeof(discover); 1515 options[i]->buf_size = sizeof(discover); 1516 options[i]->timeout = 0xFFFFFFFF; 1517 1518 /* Request the options we want */ 1519 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1520 options[i] = &option_elements[i]; 1521 options[i]->value = ip->client->config->requested_options; 1522 options[i]->len = ip->client->config->requested_option_count; 1523 options[i]->buf_size = 1524 ip->client->config->requested_option_count; 1525 options[i]->timeout = 0xFFFFFFFF; 1526 1527 /* If we had an address, try to get it again. */ 1528 if (lease) { 1529 ip->client->requested_address = lease->address; 1530 i = DHO_DHCP_REQUESTED_ADDRESS; 1531 options[i] = &option_elements[i]; 1532 options[i]->value = lease->address.iabuf; 1533 options[i]->len = lease->address.len; 1534 options[i]->buf_size = lease->address.len; 1535 options[i]->timeout = 0xFFFFFFFF; 1536 } else 1537 ip->client->requested_address.len = 0; 1538 1539 /* Send any options requested in the config file. */ 1540 for (i = 0; i < 256; i++) 1541 if (!options[i] && 1542 ip->client->config->send_options[i].data) { 1543 options[i] = &option_elements[i]; 1544 options[i]->value = 1545 ip->client->config->send_options[i].data; 1546 options[i]->len = 1547 ip->client->config->send_options[i].len; 1548 options[i]->buf_size = 1549 ip->client->config->send_options[i].len; 1550 options[i]->timeout = 0xFFFFFFFF; 1551 } 1552 1553 /* send host name if not set via config file. */ 1554 if (!options[DHO_HOST_NAME]) { 1555 if (hostname[0] != '\0') { 1556 size_t len; 1557 char* posDot = strchr(hostname, '.'); 1558 if (posDot != NULL) 1559 len = posDot - hostname; 1560 else 1561 len = strlen(hostname); 1562 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; 1563 options[DHO_HOST_NAME]->value = hostname; 1564 options[DHO_HOST_NAME]->len = len; 1565 options[DHO_HOST_NAME]->buf_size = len; 1566 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; 1567 } 1568 } 1569 1570 /* set unique client identifier */ 1571 char client_ident[sizeof(struct hardware)]; 1572 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { 1573 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? 1574 ip->hw_address.hlen : sizeof(client_ident)-1; 1575 client_ident[0] = ip->hw_address.htype; 1576 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 1577 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; 1578 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; 1579 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; 1580 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; 1581 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; 1582 } 1583 1584 /* Set up the option buffer... */ 1585 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1586 options, 0, 0, 0, NULL, 0); 1587 if (ip->client->packet_length < BOOTP_MIN_LEN) 1588 ip->client->packet_length = BOOTP_MIN_LEN; 1589 1590 ip->client->packet.op = BOOTREQUEST; 1591 ip->client->packet.htype = ip->hw_address.htype; 1592 ip->client->packet.hlen = ip->hw_address.hlen; 1593 ip->client->packet.hops = 0; 1594 ip->client->packet.xid = arc4random(); 1595 ip->client->packet.secs = 0; /* filled in by send_discover. */ 1596 ip->client->packet.flags = 0; 1597 1598 memset(&(ip->client->packet.ciaddr), 1599 0, sizeof(ip->client->packet.ciaddr)); 1600 memset(&(ip->client->packet.yiaddr), 1601 0, sizeof(ip->client->packet.yiaddr)); 1602 memset(&(ip->client->packet.siaddr), 1603 0, sizeof(ip->client->packet.siaddr)); 1604 memset(&(ip->client->packet.giaddr), 1605 0, sizeof(ip->client->packet.giaddr)); 1606 memcpy(ip->client->packet.chaddr, 1607 ip->hw_address.haddr, ip->hw_address.hlen); 1608} 1609 1610 1611void 1612make_request(struct interface_info *ip, struct client_lease * lease) 1613{ 1614 unsigned char request = DHCPREQUEST; 1615 struct tree_cache *options[256]; 1616 struct tree_cache option_elements[256]; 1617 int i; 1618 1619 memset(options, 0, sizeof(options)); 1620 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1621 1622 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ 1623 i = DHO_DHCP_MESSAGE_TYPE; 1624 options[i] = &option_elements[i]; 1625 options[i]->value = &request; 1626 options[i]->len = sizeof(request); 1627 options[i]->buf_size = sizeof(request); 1628 options[i]->timeout = 0xFFFFFFFF; 1629 1630 /* Request the options we want */ 1631 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1632 options[i] = &option_elements[i]; 1633 options[i]->value = ip->client->config->requested_options; 1634 options[i]->len = ip->client->config->requested_option_count; 1635 options[i]->buf_size = 1636 ip->client->config->requested_option_count; 1637 options[i]->timeout = 0xFFFFFFFF; 1638 1639 /* If we are requesting an address that hasn't yet been assigned 1640 to us, use the DHCP Requested Address option. */ 1641 if (ip->client->state == S_REQUESTING) { 1642 /* Send back the server identifier... */ 1643 i = DHO_DHCP_SERVER_IDENTIFIER; 1644 options[i] = &option_elements[i]; 1645 options[i]->value = lease->options[i].data; 1646 options[i]->len = lease->options[i].len; 1647 options[i]->buf_size = lease->options[i].len; 1648 options[i]->timeout = 0xFFFFFFFF; 1649 } 1650 if (ip->client->state == S_REQUESTING || 1651 ip->client->state == S_REBOOTING) { 1652 ip->client->requested_address = lease->address; 1653 i = DHO_DHCP_REQUESTED_ADDRESS; 1654 options[i] = &option_elements[i]; 1655 options[i]->value = lease->address.iabuf; 1656 options[i]->len = lease->address.len; 1657 options[i]->buf_size = lease->address.len; 1658 options[i]->timeout = 0xFFFFFFFF; 1659 } else 1660 ip->client->requested_address.len = 0; 1661 1662 /* Send any options requested in the config file. */ 1663 for (i = 0; i < 256; i++) 1664 if (!options[i] && 1665 ip->client->config->send_options[i].data) { 1666 options[i] = &option_elements[i]; 1667 options[i]->value = 1668 ip->client->config->send_options[i].data; 1669 options[i]->len = 1670 ip->client->config->send_options[i].len; 1671 options[i]->buf_size = 1672 ip->client->config->send_options[i].len; 1673 options[i]->timeout = 0xFFFFFFFF; 1674 } 1675 1676 /* send host name if not set via config file. */ 1677 if (!options[DHO_HOST_NAME]) { 1678 if (hostname[0] != '\0') { 1679 size_t len; 1680 char* posDot = strchr(hostname, '.'); 1681 if (posDot != NULL) 1682 len = posDot - hostname; 1683 else 1684 len = strlen(hostname); 1685 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; 1686 options[DHO_HOST_NAME]->value = hostname; 1687 options[DHO_HOST_NAME]->len = len; 1688 options[DHO_HOST_NAME]->buf_size = len; 1689 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; 1690 } 1691 } 1692 1693 /* set unique client identifier */ 1694 char client_ident[sizeof(struct hardware)]; 1695 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { 1696 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? 1697 ip->hw_address.hlen : sizeof(client_ident)-1; 1698 client_ident[0] = ip->hw_address.htype; 1699 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 1700 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; 1701 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; 1702 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; 1703 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; 1704 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; 1705 } 1706 1707 /* Set up the option buffer... */ 1708 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1709 options, 0, 0, 0, NULL, 0); 1710 if (ip->client->packet_length < BOOTP_MIN_LEN) 1711 ip->client->packet_length = BOOTP_MIN_LEN; 1712 1713 ip->client->packet.op = BOOTREQUEST; 1714 ip->client->packet.htype = ip->hw_address.htype; 1715 ip->client->packet.hlen = ip->hw_address.hlen; 1716 ip->client->packet.hops = 0; 1717 ip->client->packet.xid = ip->client->xid; 1718 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1719 1720 /* If we own the address we're requesting, put it in ciaddr; 1721 otherwise set ciaddr to zero. */ 1722 if (ip->client->state == S_BOUND || 1723 ip->client->state == S_RENEWING || 1724 ip->client->state == S_REBINDING) { 1725 memcpy(&ip->client->packet.ciaddr, 1726 lease->address.iabuf, lease->address.len); 1727 ip->client->packet.flags = 0; 1728 } else { 1729 memset(&ip->client->packet.ciaddr, 0, 1730 sizeof(ip->client->packet.ciaddr)); 1731 ip->client->packet.flags = 0; 1732 } 1733 1734 memset(&ip->client->packet.yiaddr, 0, 1735 sizeof(ip->client->packet.yiaddr)); 1736 memset(&ip->client->packet.siaddr, 0, 1737 sizeof(ip->client->packet.siaddr)); 1738 memset(&ip->client->packet.giaddr, 0, 1739 sizeof(ip->client->packet.giaddr)); 1740 memcpy(ip->client->packet.chaddr, 1741 ip->hw_address.haddr, ip->hw_address.hlen); 1742} 1743 1744void 1745make_decline(struct interface_info *ip, struct client_lease *lease) 1746{ 1747 struct tree_cache *options[256], message_type_tree; 1748 struct tree_cache requested_address_tree; 1749 struct tree_cache server_id_tree, client_id_tree; 1750 unsigned char decline = DHCPDECLINE; 1751 int i; 1752 1753 memset(options, 0, sizeof(options)); 1754 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1755 1756 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ 1757 i = DHO_DHCP_MESSAGE_TYPE; 1758 options[i] = &message_type_tree; 1759 options[i]->value = &decline; 1760 options[i]->len = sizeof(decline); 1761 options[i]->buf_size = sizeof(decline); 1762 options[i]->timeout = 0xFFFFFFFF; 1763 1764 /* Send back the server identifier... */ 1765 i = DHO_DHCP_SERVER_IDENTIFIER; 1766 options[i] = &server_id_tree; 1767 options[i]->value = lease->options[i].data; 1768 options[i]->len = lease->options[i].len; 1769 options[i]->buf_size = lease->options[i].len; 1770 options[i]->timeout = 0xFFFFFFFF; 1771 1772 /* Send back the address we're declining. */ 1773 i = DHO_DHCP_REQUESTED_ADDRESS; 1774 options[i] = &requested_address_tree; 1775 options[i]->value = lease->address.iabuf; 1776 options[i]->len = lease->address.len; 1777 options[i]->buf_size = lease->address.len; 1778 options[i]->timeout = 0xFFFFFFFF; 1779 1780 /* Send the uid if the user supplied one. */ 1781 i = DHO_DHCP_CLIENT_IDENTIFIER; 1782 if (ip->client->config->send_options[i].len) { 1783 options[i] = &client_id_tree; 1784 options[i]->value = ip->client->config->send_options[i].data; 1785 options[i]->len = ip->client->config->send_options[i].len; 1786 options[i]->buf_size = ip->client->config->send_options[i].len; 1787 options[i]->timeout = 0xFFFFFFFF; 1788 } 1789 1790 1791 /* Set up the option buffer... */ 1792 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1793 options, 0, 0, 0, NULL, 0); 1794 if (ip->client->packet_length < BOOTP_MIN_LEN) 1795 ip->client->packet_length = BOOTP_MIN_LEN; 1796 1797 ip->client->packet.op = BOOTREQUEST; 1798 ip->client->packet.htype = ip->hw_address.htype; 1799 ip->client->packet.hlen = ip->hw_address.hlen; 1800 ip->client->packet.hops = 0; 1801 ip->client->packet.xid = ip->client->xid; 1802 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1803 ip->client->packet.flags = 0; 1804 1805 /* ciaddr must always be zero. */ 1806 memset(&ip->client->packet.ciaddr, 0, 1807 sizeof(ip->client->packet.ciaddr)); 1808 memset(&ip->client->packet.yiaddr, 0, 1809 sizeof(ip->client->packet.yiaddr)); 1810 memset(&ip->client->packet.siaddr, 0, 1811 sizeof(ip->client->packet.siaddr)); 1812 memset(&ip->client->packet.giaddr, 0, 1813 sizeof(ip->client->packet.giaddr)); 1814 memcpy(ip->client->packet.chaddr, 1815 ip->hw_address.haddr, ip->hw_address.hlen); 1816} 1817 1818void 1819free_client_lease(struct client_lease *lease) 1820{ 1821 int i; 1822 1823 if (lease->server_name) 1824 free(lease->server_name); 1825 if (lease->filename) 1826 free(lease->filename); 1827 for (i = 0; i < 256; i++) { 1828 if (lease->options[i].len) 1829 free(lease->options[i].data); 1830 } 1831 free(lease); 1832} 1833 1834FILE *leaseFile; 1835 1836void 1837rewrite_client_leases(void) 1838{ 1839 struct client_lease *lp; 1840 1841 if (!leaseFile) { 1842 leaseFile = fopen(path_dhclient_db, "w"); 1843 if (!leaseFile) 1844 error("can't create %s: %m", path_dhclient_db); 1845 if (cap_rights_limit(fileno(leaseFile), CAP_FSTAT | CAP_FSYNC | 1846 CAP_FTRUNCATE | CAP_SEEK | CAP_WRITE) < 0 && 1847 errno != ENOSYS) { 1848 error("can't limit lease descriptor: %m"); 1849 } 1850 } else { 1851 fflush(leaseFile); 1852 rewind(leaseFile); 1853 } 1854 1855 for (lp = ifi->client->leases; lp; lp = lp->next) 1856 write_client_lease(ifi, lp, 1); 1857 if (ifi->client->active) 1858 write_client_lease(ifi, ifi->client->active, 1); 1859 1860 fflush(leaseFile); 1861 ftruncate(fileno(leaseFile), ftello(leaseFile)); 1862 fsync(fileno(leaseFile)); 1863} 1864 1865void 1866write_client_lease(struct interface_info *ip, struct client_lease *lease, 1867 int rewrite) 1868{ 1869 static int leases_written; 1870 struct tm *t; 1871 int i; 1872 1873 if (!rewrite) { 1874 if (leases_written++ > 20) { 1875 rewrite_client_leases(); 1876 leases_written = 0; 1877 } 1878 } 1879 1880 /* If the lease came from the config file, we don't need to stash 1881 a copy in the lease database. */ 1882 if (lease->is_static) 1883 return; 1884 1885 if (!leaseFile) { /* XXX */ 1886 leaseFile = fopen(path_dhclient_db, "w"); 1887 if (!leaseFile) 1888 error("can't create %s: %m", path_dhclient_db); 1889 } 1890 1891 fprintf(leaseFile, "lease {\n"); 1892 if (lease->is_bootp) 1893 fprintf(leaseFile, " bootp;\n"); 1894 fprintf(leaseFile, " interface \"%s\";\n", ip->name); 1895 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); 1896 if (lease->nextserver.len == sizeof(inaddr_any) && 1897 0 != memcmp(lease->nextserver.iabuf, &inaddr_any, 1898 sizeof(inaddr_any))) 1899 fprintf(leaseFile, " next-server %s;\n", 1900 piaddr(lease->nextserver)); 1901 if (lease->filename) 1902 fprintf(leaseFile, " filename \"%s\";\n", lease->filename); 1903 if (lease->server_name) 1904 fprintf(leaseFile, " server-name \"%s\";\n", 1905 lease->server_name); 1906 if (lease->medium) 1907 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); 1908 for (i = 0; i < 256; i++) 1909 if (lease->options[i].len) 1910 fprintf(leaseFile, " option %s %s;\n", 1911 dhcp_options[i].name, 1912 pretty_print_option(i, lease->options[i].data, 1913 lease->options[i].len, 1, 1)); 1914 1915 t = gmtime(&lease->renewal); 1916 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", 1917 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1918 t->tm_hour, t->tm_min, t->tm_sec); 1919 t = gmtime(&lease->rebind); 1920 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", 1921 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1922 t->tm_hour, t->tm_min, t->tm_sec); 1923 t = gmtime(&lease->expiry); 1924 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", 1925 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1926 t->tm_hour, t->tm_min, t->tm_sec); 1927 fprintf(leaseFile, "}\n"); 1928 fflush(leaseFile); 1929} 1930 1931void 1932script_init(char *reason, struct string_list *medium) 1933{ 1934 size_t len, mediumlen = 0; 1935 struct imsg_hdr hdr; 1936 struct buf *buf; 1937 int errs; 1938 1939 if (medium != NULL && medium->string != NULL) 1940 mediumlen = strlen(medium->string); 1941 1942 hdr.code = IMSG_SCRIPT_INIT; 1943 hdr.len = sizeof(struct imsg_hdr) + 1944 sizeof(size_t) + mediumlen + 1945 sizeof(size_t) + strlen(reason); 1946 1947 if ((buf = buf_open(hdr.len)) == NULL) 1948 error("buf_open: %m"); 1949 1950 errs = 0; 1951 errs += buf_add(buf, &hdr, sizeof(hdr)); 1952 errs += buf_add(buf, &mediumlen, sizeof(mediumlen)); 1953 if (mediumlen > 0) 1954 errs += buf_add(buf, medium->string, mediumlen); 1955 len = strlen(reason); 1956 errs += buf_add(buf, &len, sizeof(len)); 1957 errs += buf_add(buf, reason, len); 1958 1959 if (errs) 1960 error("buf_add: %m"); 1961 1962 if (buf_close(privfd, buf) == -1) 1963 error("buf_close: %m"); 1964} 1965 1966void 1967priv_script_init(char *reason, char *medium) 1968{ 1969 struct interface_info *ip = ifi; 1970 1971 if (ip) { 1972 ip->client->scriptEnvsize = 100; 1973 if (ip->client->scriptEnv == NULL) 1974 ip->client->scriptEnv = 1975 malloc(ip->client->scriptEnvsize * sizeof(char *)); 1976 if (ip->client->scriptEnv == NULL) 1977 error("script_init: no memory for environment"); 1978 1979 ip->client->scriptEnv[0] = strdup(CLIENT_PATH); 1980 if (ip->client->scriptEnv[0] == NULL) 1981 error("script_init: no memory for environment"); 1982 1983 ip->client->scriptEnv[1] = NULL; 1984 1985 script_set_env(ip->client, "", "interface", ip->name); 1986 1987 if (medium) 1988 script_set_env(ip->client, "", "medium", medium); 1989 1990 script_set_env(ip->client, "", "reason", reason); 1991 } 1992} 1993 1994void 1995priv_script_write_params(char *prefix, struct client_lease *lease) 1996{ 1997 struct interface_info *ip = ifi; 1998 u_int8_t dbuf[1500], *dp = NULL; 1999 int i, len; 2000 char tbuf[128]; 2001 2002 script_set_env(ip->client, prefix, "ip_address", 2003 piaddr(lease->address)); 2004 2005 if (ip->client->config->default_actions[DHO_SUBNET_MASK] == 2006 ACTION_SUPERSEDE) { 2007 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data; 2008 len = ip->client->config->defaults[DHO_SUBNET_MASK].len; 2009 } else { 2010 dp = lease->options[DHO_SUBNET_MASK].data; 2011 len = lease->options[DHO_SUBNET_MASK].len; 2012 } 2013 if (len && (len < sizeof(lease->address.iabuf))) { 2014 struct iaddr netmask, subnet, broadcast; 2015 2016 memcpy(netmask.iabuf, dp, len); 2017 netmask.len = len; 2018 subnet = subnet_number(lease->address, netmask); 2019 if (subnet.len) { 2020 script_set_env(ip->client, prefix, "network_number", 2021 piaddr(subnet)); 2022 if (!lease->options[DHO_BROADCAST_ADDRESS].len) { 2023 broadcast = broadcast_addr(subnet, netmask); 2024 if (broadcast.len) 2025 script_set_env(ip->client, prefix, 2026 "broadcast_address", 2027 piaddr(broadcast)); 2028 } 2029 } 2030 } 2031 2032 if (lease->filename) 2033 script_set_env(ip->client, prefix, "filename", lease->filename); 2034 if (lease->server_name) 2035 script_set_env(ip->client, prefix, "server_name", 2036 lease->server_name); 2037 for (i = 0; i < 256; i++) { 2038 len = 0; 2039 2040 if (ip->client->config->defaults[i].len) { 2041 if (lease->options[i].len) { 2042 switch ( 2043 ip->client->config->default_actions[i]) { 2044 case ACTION_DEFAULT: 2045 dp = lease->options[i].data; 2046 len = lease->options[i].len; 2047 break; 2048 case ACTION_SUPERSEDE: 2049supersede: 2050 dp = ip->client-> 2051 config->defaults[i].data; 2052 len = ip->client-> 2053 config->defaults[i].len; 2054 break; 2055 case ACTION_PREPEND: 2056 len = ip->client-> 2057 config->defaults[i].len + 2058 lease->options[i].len; 2059 if (len >= sizeof(dbuf)) { 2060 warning("no space to %s %s", 2061 "prepend option", 2062 dhcp_options[i].name); 2063 goto supersede; 2064 } 2065 dp = dbuf; 2066 memcpy(dp, 2067 ip->client-> 2068 config->defaults[i].data, 2069 ip->client-> 2070 config->defaults[i].len); 2071 memcpy(dp + ip->client-> 2072 config->defaults[i].len, 2073 lease->options[i].data, 2074 lease->options[i].len); 2075 dp[len] = '\0'; 2076 break; 2077 case ACTION_APPEND: 2078 /* 2079 * When we append, we assume that we're 2080 * appending to text. Some MS servers 2081 * include a NUL byte at the end of 2082 * the search string provided. 2083 */ 2084 len = ip->client-> 2085 config->defaults[i].len + 2086 lease->options[i].len; 2087 if (len >= sizeof(dbuf)) { 2088 warning("no space to %s %s", 2089 "append option", 2090 dhcp_options[i].name); 2091 goto supersede; 2092 } 2093 memcpy(dbuf, 2094 lease->options[i].data, 2095 lease->options[i].len); 2096 for (dp = dbuf + lease->options[i].len; 2097 dp > dbuf; dp--, len--) 2098 if (dp[-1] != '\0') 2099 break; 2100 memcpy(dp, 2101 ip->client-> 2102 config->defaults[i].data, 2103 ip->client-> 2104 config->defaults[i].len); 2105 dp = dbuf; 2106 dp[len] = '\0'; 2107 } 2108 } else { 2109 dp = ip->client-> 2110 config->defaults[i].data; 2111 len = ip->client-> 2112 config->defaults[i].len; 2113 } 2114 } else if (lease->options[i].len) { 2115 len = lease->options[i].len; 2116 dp = lease->options[i].data; 2117 } else { 2118 len = 0; 2119 } 2120 if (len) { 2121 char name[256]; 2122 2123 if (dhcp_option_ev_name(name, sizeof(name), 2124 &dhcp_options[i])) 2125 script_set_env(ip->client, prefix, name, 2126 pretty_print_option(i, dp, len, 0, 0)); 2127 } 2128 } 2129 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); 2130 script_set_env(ip->client, prefix, "expiry", tbuf); 2131} 2132 2133void 2134script_write_params(char *prefix, struct client_lease *lease) 2135{ 2136 size_t fn_len = 0, sn_len = 0, pr_len = 0; 2137 struct imsg_hdr hdr; 2138 struct buf *buf; 2139 int errs, i; 2140 2141 if (lease->filename != NULL) 2142 fn_len = strlen(lease->filename); 2143 if (lease->server_name != NULL) 2144 sn_len = strlen(lease->server_name); 2145 if (prefix != NULL) 2146 pr_len = strlen(prefix); 2147 2148 hdr.code = IMSG_SCRIPT_WRITE_PARAMS; 2149 hdr.len = sizeof(hdr) + sizeof(struct client_lease) + 2150 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len + 2151 sizeof(size_t) + pr_len; 2152 2153 for (i = 0; i < 256; i++) 2154 hdr.len += sizeof(int) + lease->options[i].len; 2155 2156 scripttime = time(NULL); 2157 2158 if ((buf = buf_open(hdr.len)) == NULL) 2159 error("buf_open: %m"); 2160 2161 errs = 0; 2162 errs += buf_add(buf, &hdr, sizeof(hdr)); 2163 errs += buf_add(buf, lease, sizeof(struct client_lease)); 2164 errs += buf_add(buf, &fn_len, sizeof(fn_len)); 2165 errs += buf_add(buf, lease->filename, fn_len); 2166 errs += buf_add(buf, &sn_len, sizeof(sn_len)); 2167 errs += buf_add(buf, lease->server_name, sn_len); 2168 errs += buf_add(buf, &pr_len, sizeof(pr_len)); 2169 errs += buf_add(buf, prefix, pr_len); 2170 2171 for (i = 0; i < 256; i++) { 2172 errs += buf_add(buf, &lease->options[i].len, 2173 sizeof(lease->options[i].len)); 2174 errs += buf_add(buf, lease->options[i].data, 2175 lease->options[i].len); 2176 } 2177 2178 if (errs) 2179 error("buf_add: %m"); 2180 2181 if (buf_close(privfd, buf) == -1) 2182 error("buf_close: %m"); 2183} 2184 2185int 2186script_go(void) 2187{ 2188 struct imsg_hdr hdr; 2189 struct buf *buf; 2190 int ret; 2191 2192 hdr.code = IMSG_SCRIPT_GO; 2193 hdr.len = sizeof(struct imsg_hdr); 2194 2195 if ((buf = buf_open(hdr.len)) == NULL) 2196 error("buf_open: %m"); 2197 2198 if (buf_add(buf, &hdr, sizeof(hdr))) 2199 error("buf_add: %m"); 2200 2201 if (buf_close(privfd, buf) == -1) 2202 error("buf_close: %m"); 2203 2204 bzero(&hdr, sizeof(hdr)); 2205 buf_read(privfd, &hdr, sizeof(hdr)); 2206 if (hdr.code != IMSG_SCRIPT_GO_RET) 2207 error("unexpected msg type %u", hdr.code); 2208 if (hdr.len != sizeof(hdr) + sizeof(int)) 2209 error("received corrupted message"); 2210 buf_read(privfd, &ret, sizeof(ret)); 2211 2212 scripttime = time(NULL); 2213 2214 return (ret); 2215} 2216 2217int 2218priv_script_go(void) 2219{ 2220 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI"; 2221 static char client_path[] = CLIENT_PATH; 2222 struct interface_info *ip = ifi; 2223 int pid, wpid, wstatus; 2224 2225 scripttime = time(NULL); 2226 2227 if (ip) { 2228 scriptName = ip->client->config->script_name; 2229 envp = ip->client->scriptEnv; 2230 } else { 2231 scriptName = top_level_config.script_name; 2232 epp[0] = reason; 2233 epp[1] = client_path; 2234 epp[2] = NULL; 2235 envp = epp; 2236 } 2237 2238 argv[0] = scriptName; 2239 argv[1] = NULL; 2240 2241 pid = fork(); 2242 if (pid < 0) { 2243 error("fork: %m"); 2244 wstatus = 0; 2245 } else if (pid) { 2246 do { 2247 wpid = wait(&wstatus); 2248 } while (wpid != pid && wpid > 0); 2249 if (wpid < 0) { 2250 error("wait: %m"); 2251 wstatus = 0; 2252 } 2253 } else { 2254 execve(scriptName, argv, envp); 2255 error("execve (%s, ...): %m", scriptName); 2256 } 2257 2258 if (ip) 2259 script_flush_env(ip->client); 2260 2261 return (wstatus & 0xff); 2262} 2263 2264void 2265script_set_env(struct client_state *client, const char *prefix, 2266 const char *name, const char *value) 2267{ 2268 int i, j, namelen; 2269 2270 namelen = strlen(name); 2271 2272 for (i = 0; client->scriptEnv[i]; i++) 2273 if (strncmp(client->scriptEnv[i], name, namelen) == 0 && 2274 client->scriptEnv[i][namelen] == '=') 2275 break; 2276 2277 if (client->scriptEnv[i]) 2278 /* Reuse the slot. */ 2279 free(client->scriptEnv[i]); 2280 else { 2281 /* New variable. Expand if necessary. */ 2282 if (i >= client->scriptEnvsize - 1) { 2283 char **newscriptEnv; 2284 int newscriptEnvsize = client->scriptEnvsize + 50; 2285 2286 newscriptEnv = realloc(client->scriptEnv, 2287 newscriptEnvsize); 2288 if (newscriptEnv == NULL) { 2289 free(client->scriptEnv); 2290 client->scriptEnv = NULL; 2291 client->scriptEnvsize = 0; 2292 error("script_set_env: no memory for variable"); 2293 } 2294 client->scriptEnv = newscriptEnv; 2295 client->scriptEnvsize = newscriptEnvsize; 2296 } 2297 /* need to set the NULL pointer at end of array beyond 2298 the new slot. */ 2299 client->scriptEnv[i + 1] = NULL; 2300 } 2301 /* Allocate space and format the variable in the appropriate slot. */ 2302 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + 2303 strlen(value) + 1); 2304 if (client->scriptEnv[i] == NULL) 2305 error("script_set_env: no memory for variable assignment"); 2306 2307 /* No `` or $() command substitution allowed in environment values! */ 2308 for (j=0; j < strlen(value); j++) 2309 switch (value[j]) { 2310 case '`': 2311 case '$': 2312 error("illegal character (%c) in value '%s'", value[j], 2313 value); 2314 /* not reached */ 2315 } 2316 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 2317 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); 2318} 2319 2320void 2321script_flush_env(struct client_state *client) 2322{ 2323 int i; 2324 2325 for (i = 0; client->scriptEnv[i]; i++) { 2326 free(client->scriptEnv[i]); 2327 client->scriptEnv[i] = NULL; 2328 } 2329 client->scriptEnvsize = 0; 2330} 2331 2332int 2333dhcp_option_ev_name(char *buf, size_t buflen, struct option *option) 2334{ 2335 int i; 2336 2337 for (i = 0; option->name[i]; i++) { 2338 if (i + 1 == buflen) 2339 return 0; 2340 if (option->name[i] == '-') 2341 buf[i] = '_'; 2342 else 2343 buf[i] = option->name[i]; 2344 } 2345 2346 buf[i] = 0; 2347 return 1; 2348} 2349 2350void 2351go_daemon(void) 2352{ 2353 static int state = 0; 2354 2355 if (no_daemon || state) 2356 return; 2357 2358 state = 1; 2359 2360 /* Stop logging to stderr... */ 2361 log_perror = 0; 2362 2363 if (daemon(1, 0) == -1) 2364 error("daemon"); 2365 2366 if (pidfile != NULL) { 2367 pidfile_write(pidfile); 2368 if (cap_rights_limit(pidfile_fileno(pidfile), CAP_NONE) < 0 && 2369 errno != ENOSYS) { 2370 error("can't limit pidfile descriptor: %m"); 2371 } 2372 } 2373 2374 /* we are chrooted, daemon(3) fails to open /dev/null */ 2375 if (nullfd != -1) { 2376 dup2(nullfd, STDIN_FILENO); 2377 dup2(nullfd, STDOUT_FILENO); 2378 dup2(nullfd, STDERR_FILENO); 2379 close(nullfd); 2380 nullfd = -1; 2381 } 2382 2383 if (cap_rights_limit(STDIN_FILENO, CAP_NONE) < 0 && errno != ENOSYS) 2384 error("can't limit stdin: %m"); 2385 if (cap_rights_limit(STDOUT_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) 2386 error("can't limit stdout: %m"); 2387 if (cap_rights_limit(STDERR_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) 2388 error("can't limit stderr: %m"); 2389} 2390 2391int 2392check_option(struct client_lease *l, int option) 2393{ 2394 char *opbuf; 2395 char *sbuf; 2396 2397 /* we use this, since this is what gets passed to dhclient-script */ 2398 2399 opbuf = pretty_print_option(option, l->options[option].data, 2400 l->options[option].len, 0, 0); 2401 2402 sbuf = option_as_string(option, l->options[option].data, 2403 l->options[option].len); 2404 2405 switch (option) { 2406 case DHO_SUBNET_MASK: 2407 case DHO_TIME_SERVERS: 2408 case DHO_NAME_SERVERS: 2409 case DHO_ROUTERS: 2410 case DHO_DOMAIN_NAME_SERVERS: 2411 case DHO_LOG_SERVERS: 2412 case DHO_COOKIE_SERVERS: 2413 case DHO_LPR_SERVERS: 2414 case DHO_IMPRESS_SERVERS: 2415 case DHO_RESOURCE_LOCATION_SERVERS: 2416 case DHO_SWAP_SERVER: 2417 case DHO_BROADCAST_ADDRESS: 2418 case DHO_NIS_SERVERS: 2419 case DHO_NTP_SERVERS: 2420 case DHO_NETBIOS_NAME_SERVERS: 2421 case DHO_NETBIOS_DD_SERVER: 2422 case DHO_FONT_SERVERS: 2423 case DHO_DHCP_SERVER_IDENTIFIER: 2424 case DHO_NISPLUS_SERVERS: 2425 case DHO_MOBILE_IP_HOME_AGENT: 2426 case DHO_SMTP_SERVER: 2427 case DHO_POP_SERVER: 2428 case DHO_NNTP_SERVER: 2429 case DHO_WWW_SERVER: 2430 case DHO_FINGER_SERVER: 2431 case DHO_IRC_SERVER: 2432 case DHO_STREETTALK_SERVER: 2433 case DHO_STREETTALK_DA_SERVER: 2434 if (!ipv4addrs(opbuf)) { 2435 warning("Invalid IP address in option: %s", opbuf); 2436 return (0); 2437 } 2438 return (1) ; 2439 case DHO_HOST_NAME: 2440 case DHO_NIS_DOMAIN: 2441 case DHO_NISPLUS_DOMAIN: 2442 case DHO_TFTP_SERVER_NAME: 2443 if (!res_hnok(sbuf)) { 2444 warning("Bogus Host Name option %d: %s (%s)", option, 2445 sbuf, opbuf); 2446 l->options[option].len = 0; 2447 free(l->options[option].data); 2448 } 2449 return (1); 2450 case DHO_DOMAIN_NAME: 2451 case DHO_DOMAIN_SEARCH: 2452 if (!res_hnok(sbuf)) { 2453 if (!check_search(sbuf)) { 2454 warning("Bogus domain search list %d: %s (%s)", 2455 option, sbuf, opbuf); 2456 l->options[option].len = 0; 2457 free(l->options[option].data); 2458 } 2459 } 2460 return (1); 2461 case DHO_PAD: 2462 case DHO_TIME_OFFSET: 2463 case DHO_BOOT_SIZE: 2464 case DHO_MERIT_DUMP: 2465 case DHO_ROOT_PATH: 2466 case DHO_EXTENSIONS_PATH: 2467 case DHO_IP_FORWARDING: 2468 case DHO_NON_LOCAL_SOURCE_ROUTING: 2469 case DHO_POLICY_FILTER: 2470 case DHO_MAX_DGRAM_REASSEMBLY: 2471 case DHO_DEFAULT_IP_TTL: 2472 case DHO_PATH_MTU_AGING_TIMEOUT: 2473 case DHO_PATH_MTU_PLATEAU_TABLE: 2474 case DHO_INTERFACE_MTU: 2475 case DHO_ALL_SUBNETS_LOCAL: 2476 case DHO_PERFORM_MASK_DISCOVERY: 2477 case DHO_MASK_SUPPLIER: 2478 case DHO_ROUTER_DISCOVERY: 2479 case DHO_ROUTER_SOLICITATION_ADDRESS: 2480 case DHO_STATIC_ROUTES: 2481 case DHO_TRAILER_ENCAPSULATION: 2482 case DHO_ARP_CACHE_TIMEOUT: 2483 case DHO_IEEE802_3_ENCAPSULATION: 2484 case DHO_DEFAULT_TCP_TTL: 2485 case DHO_TCP_KEEPALIVE_INTERVAL: 2486 case DHO_TCP_KEEPALIVE_GARBAGE: 2487 case DHO_VENDOR_ENCAPSULATED_OPTIONS: 2488 case DHO_NETBIOS_NODE_TYPE: 2489 case DHO_NETBIOS_SCOPE: 2490 case DHO_X_DISPLAY_MANAGER: 2491 case DHO_DHCP_REQUESTED_ADDRESS: 2492 case DHO_DHCP_LEASE_TIME: 2493 case DHO_DHCP_OPTION_OVERLOAD: 2494 case DHO_DHCP_MESSAGE_TYPE: 2495 case DHO_DHCP_PARAMETER_REQUEST_LIST: 2496 case DHO_DHCP_MESSAGE: 2497 case DHO_DHCP_MAX_MESSAGE_SIZE: 2498 case DHO_DHCP_RENEWAL_TIME: 2499 case DHO_DHCP_REBINDING_TIME: 2500 case DHO_DHCP_CLASS_IDENTIFIER: 2501 case DHO_DHCP_CLIENT_IDENTIFIER: 2502 case DHO_BOOTFILE_NAME: 2503 case DHO_DHCP_USER_CLASS_ID: 2504 case DHO_END: 2505 return (1); 2506 case DHO_CLASSLESS_ROUTES: 2507 return (check_classless_option(l->options[option].data, 2508 l->options[option].len)); 2509 default: 2510 warning("unknown dhcp option value 0x%x", option); 2511 return (unknown_ok); 2512 } 2513} 2514 2515/* RFC 3442 The Classless Static Routes option checks */ 2516int 2517check_classless_option(unsigned char *data, int len) 2518{ 2519 int i = 0; 2520 unsigned char width; 2521 in_addr_t addr, mask; 2522 2523 if (len < 5) { 2524 warning("Too small length: %d", len); 2525 return (0); 2526 } 2527 while(i < len) { 2528 width = data[i++]; 2529 if (width == 0) { 2530 i += 4; 2531 continue; 2532 } else if (width < 9) { 2533 addr = (in_addr_t)(data[i] << 24); 2534 i += 1; 2535 } else if (width < 17) { 2536 addr = (in_addr_t)(data[i] << 24) + 2537 (in_addr_t)(data[i + 1] << 16); 2538 i += 2; 2539 } else if (width < 25) { 2540 addr = (in_addr_t)(data[i] << 24) + 2541 (in_addr_t)(data[i + 1] << 16) + 2542 (in_addr_t)(data[i + 2] << 8); 2543 i += 3; 2544 } else if (width < 33) { 2545 addr = (in_addr_t)(data[i] << 24) + 2546 (in_addr_t)(data[i + 1] << 16) + 2547 (in_addr_t)(data[i + 2] << 8) + 2548 data[i + 3]; 2549 i += 4; 2550 } else { 2551 warning("Incorrect subnet width: %d", width); 2552 return (0); 2553 } 2554 mask = (in_addr_t)(~0) << (32 - width); 2555 addr = ntohl(addr); 2556 mask = ntohl(mask); 2557 2558 /* 2559 * From RFC 3442: 2560 * ... After deriving a subnet number and subnet mask 2561 * from each destination descriptor, the DHCP client 2562 * MUST zero any bits in the subnet number where the 2563 * corresponding bit in the mask is zero... 2564 */ 2565 if ((addr & mask) != addr) { 2566 addr &= mask; 2567 data[i - 1] = (unsigned char)( 2568 (addr >> (((32 - width)/8)*8)) & 0xFF); 2569 } 2570 i += 4; 2571 } 2572 if (i > len) { 2573 warning("Incorrect data length: %d (must be %d)", len, i); 2574 return (0); 2575 } 2576 return (1); 2577} 2578 2579int 2580res_hnok(const char *dn) 2581{ 2582 int pch = PERIOD, ch = *dn++; 2583 2584 while (ch != '\0') { 2585 int nch = *dn++; 2586 2587 if (periodchar(ch)) { 2588 ; 2589 } else if (periodchar(pch)) { 2590 if (!borderchar(ch)) 2591 return (0); 2592 } else if (periodchar(nch) || nch == '\0') { 2593 if (!borderchar(ch)) 2594 return (0); 2595 } else { 2596 if (!middlechar(ch)) 2597 return (0); 2598 } 2599 pch = ch, ch = nch; 2600 } 2601 return (1); 2602} 2603 2604int 2605check_search(const char *srch) 2606{ 2607 int pch = PERIOD, ch = *srch++; 2608 int domains = 1; 2609 2610 /* 256 char limit re resolv.conf(5) */ 2611 if (strlen(srch) > 256) 2612 return (0); 2613 2614 while (whitechar(ch)) 2615 ch = *srch++; 2616 2617 while (ch != '\0') { 2618 int nch = *srch++; 2619 2620 if (periodchar(ch) || whitechar(ch)) { 2621 ; 2622 } else if (periodchar(pch)) { 2623 if (!borderchar(ch)) 2624 return (0); 2625 } else if (periodchar(nch) || nch == '\0') { 2626 if (!borderchar(ch)) 2627 return (0); 2628 } else { 2629 if (!middlechar(ch)) 2630 return (0); 2631 } 2632 if (!whitechar(ch)) { 2633 pch = ch; 2634 } else { 2635 while (whitechar(nch)) { 2636 nch = *srch++; 2637 } 2638 if (nch != '\0') 2639 domains++; 2640 pch = PERIOD; 2641 } 2642 ch = nch; 2643 } 2644 /* 6 domain limit re resolv.conf(5) */ 2645 if (domains > 6) 2646 return (0); 2647 return (1); 2648} 2649 2650/* Does buf consist only of dotted decimal ipv4 addrs? 2651 * return how many if so, 2652 * otherwise, return 0 2653 */ 2654int 2655ipv4addrs(char * buf) 2656{ 2657 struct in_addr jnk; 2658 int count = 0; 2659 2660 while (inet_aton(buf, &jnk) == 1){ 2661 count++; 2662 while (periodchar(*buf) || digitchar(*buf)) 2663 buf++; 2664 if (*buf == '\0') 2665 return (count); 2666 while (*buf == ' ') 2667 buf++; 2668 } 2669 return (0); 2670} 2671 2672 2673char * 2674option_as_string(unsigned int code, unsigned char *data, int len) 2675{ 2676 static char optbuf[32768]; /* XXX */ 2677 char *op = optbuf; 2678 int opleft = sizeof(optbuf); 2679 unsigned char *dp = data; 2680 2681 if (code > 255) 2682 error("option_as_string: bad code %d", code); 2683 2684 for (; dp < data + len; dp++) { 2685 if (!isascii(*dp) || !isprint(*dp)) { 2686 if (dp + 1 != data + len || *dp != 0) { 2687 snprintf(op, opleft, "\\%03o", *dp); 2688 op += 4; 2689 opleft -= 4; 2690 } 2691 } else if (*dp == '"' || *dp == '\'' || *dp == '$' || 2692 *dp == '`' || *dp == '\\') { 2693 *op++ = '\\'; 2694 *op++ = *dp; 2695 opleft -= 2; 2696 } else { 2697 *op++ = *dp; 2698 opleft--; 2699 } 2700 } 2701 if (opleft < 1) 2702 goto toobig; 2703 *op = 0; 2704 return optbuf; 2705toobig: 2706 warning("dhcp option too large"); 2707 return "<error>"; 2708} 2709 2710int 2711fork_privchld(int fd, int fd2) 2712{ 2713 struct pollfd pfd[1]; 2714 int nfds; 2715 2716 switch (fork()) { 2717 case -1: 2718 error("cannot fork"); 2719 case 0: 2720 break; 2721 default: 2722 return (0); 2723 } 2724 2725 setproctitle("%s [priv]", ifi->name); 2726 2727 setsid(); 2728 dup2(nullfd, STDIN_FILENO); 2729 dup2(nullfd, STDOUT_FILENO); 2730 dup2(nullfd, STDERR_FILENO); 2731 close(nullfd); 2732 close(fd2); 2733 close(ifi->rfdesc); 2734 ifi->rfdesc = -1; 2735 2736 for (;;) { 2737 pfd[0].fd = fd; 2738 pfd[0].events = POLLIN; 2739 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 2740 if (errno != EINTR) 2741 error("poll error"); 2742 2743 if (nfds == 0 || !(pfd[0].revents & POLLIN)) 2744 continue; 2745 2746 dispatch_imsg(ifi, fd); 2747 } 2748} 2749