1 /************************************************************************ 2 Copyright 1988, 1991 by Carnegie Mellon University 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, provided 8 that the above copyright notice appear in all copies and that both that 9 copyright notice and this permission notice appear in supporting 10 documentation, and that the name of Carnegie Mellon University not be used 11 in advertising or publicity pertaining to distribution of the software 12 without specific, written prior permission. 13 14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 ************************************************************************/ 22 23 #include <sys/cdefs.h> 24 #ifndef lint 25 __RCSID("$NetBSD: bootpd.c,v 1.26 2014/03/29 22:45:31 joerg Exp $"); 26 #endif 27 28 /* 29 * BOOTP (bootstrap protocol) server daemon. 30 * 31 * Answers BOOTP request packets from booting client machines. 32 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol. 33 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions. 34 * See RFC 1395 for option tags 14-17. 35 * See accompanying man page -- bootpd.8 36 * 37 * HISTORY 38 * See ./Changes 39 * 40 * BUGS 41 * See ./ToDo 42 */ 43 44 45 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/ioctl.h> 50 #include <sys/file.h> 51 #include <sys/time.h> 52 #include <sys/stat.h> 53 #include <sys/poll.h> 54 55 #include <net/if.h> 56 #include <netinet/in.h> 57 #include <arpa/inet.h> /* inet_ntoa */ 58 59 #ifndef NO_UNISTD 60 #include <unistd.h> 61 #endif 62 #include <stdlib.h> 63 #include <signal.h> 64 #include <stdio.h> 65 #include <string.h> 66 #include <strings.h> 67 #include <errno.h> 68 #include <ctype.h> 69 #include <netdb.h> 70 #include <syslog.h> 71 #include <assert.h> 72 73 #ifdef NO_SETSID 74 # include <fcntl.h> /* for O_RDONLY, etc */ 75 #endif 76 77 #ifdef SVR4 78 /* Using sigset() avoids the need to re-arm each time. */ 79 #define signal sigset 80 #endif 81 82 #include "bootp.h" 83 #include "hash.h" 84 #include "hwaddr.h" 85 #include "bootpd.h" 86 #include "dovend.h" 87 #include "getif.h" 88 #include "readfile.h" 89 #include "report.h" 90 #include "tzone.h" 91 #include "patchlevel.h" 92 93 #ifndef CONFIG_FILE 94 #define CONFIG_FILE "/etc/bootptab" 95 #endif 96 #ifndef DUMPTAB_FILE 97 #define DUMPTAB_FILE "/tmp/bootpd.dump" 98 #endif 99 100 101 102 /* 103 * Externals, forward declarations, and global variables 104 */ 105 106 extern void dumptab(const char *); 107 108 PRIVATE void catcher(int); 109 PRIVATE int chk_access(char *, int32 *); 110 #ifdef VEND_CMU 111 PRIVATE void dovend_cmu(struct bootp *, struct host *); 112 #endif 113 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32); 114 PRIVATE void handle_reply(void); 115 PRIVATE void handle_request(void); 116 PRIVATE void sendreply(int forward, int32 dest_override); 117 __dead PRIVATE void usage(void); 118 int main(int, char **); 119 120 /* 121 * IP port numbers for client and server obtained from /etc/services 122 */ 123 124 u_short bootps_port, bootpc_port; 125 126 127 /* 128 * Internet socket and interface config structures 129 */ 130 131 struct sockaddr_in bind_addr; /* Listening */ 132 struct sockaddr_in recv_addr; /* Packet source */ 133 struct sockaddr_in send_addr; /* destination */ 134 135 136 /* 137 * option defaults 138 */ 139 int debug = 0; /* Debugging flag (level) */ 140 int actualtimeout = 15 * 60000; /* fifteen minutes */ 141 142 /* 143 * General 144 */ 145 146 int s; /* Socket file descriptor */ 147 char *pktbuf; /* Receive packet buffer */ 148 int pktlen; 149 const char *progname; 150 char *chdir_path; 151 char hostname[MAXHOSTNAMELEN + 1]; /* System host name */ 152 struct in_addr my_ip_addr; 153 154 /* Flags set by signal catcher. */ 155 PRIVATE int do_readtab = 0; 156 PRIVATE int do_dumptab = 0; 157 158 /* 159 * Globals below are associated with the bootp database file (bootptab). 160 */ 161 162 const char *bootptab = CONFIG_FILE; 163 const char *bootpd_dump = DUMPTAB_FILE; 164 165 166 167 /* 168 * Initialization such as command-line processing is done and then the 169 * main server loop is started. 170 */ 171 172 int 173 main(int argc, char **argv) 174 { 175 int timeout; 176 struct bootp *bp; 177 struct servent *servp; 178 struct hostent *hep; 179 char *stmp; 180 socklen_t ba_len, ra_len; 181 int n; 182 int nfound; 183 struct pollfd set[1]; 184 int standalone; 185 186 progname = strrchr(argv[0], '/'); 187 if (progname) 188 progname++; 189 else 190 progname = argv[0]; 191 192 /* 193 * Initialize logging. 194 */ 195 report_init(0); /* uses progname */ 196 197 /* 198 * Log startup 199 */ 200 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL); 201 202 /* Debugging for compilers with struct padding. */ 203 assert(sizeof(struct bootp) == BP_MINPKTSZ); 204 205 /* Get space for receiving packets and composing replies. */ 206 pktbuf = malloc(MAX_MSG_SIZE); 207 if (!pktbuf) { 208 report(LOG_ERR, "malloc failed"); 209 exit(1); 210 } 211 bp = (struct bootp *) pktbuf; 212 213 /* 214 * Check to see if a socket was passed to us from inetd. 215 * 216 * Use getsockname() to determine if descriptor 0 is indeed a socket 217 * (and thus we are probably a child of inetd) or if it is instead 218 * something else and we are running standalone. 219 */ 220 s = 0; 221 ba_len = sizeof(bind_addr); 222 bzero((char *) &bind_addr, ba_len); 223 errno = 0; 224 standalone = TRUE; 225 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) { 226 /* 227 * Descriptor 0 is a socket. Assume we are a child of inetd. 228 */ 229 if (bind_addr.sin_family == AF_INET) { 230 standalone = FALSE; 231 bootps_port = ntohs(bind_addr.sin_port); 232 } else { 233 /* Some other type of socket? */ 234 report(LOG_ERR, "getsockname: not an INET socket"); 235 } 236 } 237 238 /* 239 * Set defaults that might be changed by option switches. 240 */ 241 stmp = NULL; 242 timeout = actualtimeout; 243 244 /* 245 * Read switches. 246 */ 247 for (argc--, argv++; argc > 0; argc--, argv++) { 248 if (argv[0][0] != '-') 249 break; 250 switch (argv[0][1]) { 251 252 case 'c': /* chdir_path */ 253 if (argv[0][2]) { 254 stmp = &(argv[0][2]); 255 } else { 256 argc--; 257 argv++; 258 stmp = argv[0]; 259 } 260 if (!stmp || (stmp[0] != '/')) { 261 fprintf(stderr, 262 "bootpd: invalid chdir specification\n"); 263 break; 264 } 265 chdir_path = stmp; 266 break; 267 268 case 'd': /* debug level */ 269 if (argv[0][2]) { 270 stmp = &(argv[0][2]); 271 } else if (argv[1] && argv[1][0] == '-') { 272 /* 273 * Backwards-compatible behavior: 274 * no parameter, so just increment the debug flag. 275 */ 276 debug++; 277 break; 278 } else { 279 argc--; 280 argv++; 281 stmp = argv[0]; 282 } 283 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 284 fprintf(stderr, 285 "%s: invalid debug level\n", progname); 286 break; 287 } 288 debug = n; 289 break; 290 291 case 'h': /* override hostname */ 292 if (argv[0][2]) { 293 stmp = &(argv[0][2]); 294 } else { 295 argc--; 296 argv++; 297 stmp = argv[0]; 298 } 299 if (!stmp) { 300 fprintf(stderr, 301 "bootpd: missing hostname\n"); 302 break; 303 } 304 strlcpy(hostname, stmp, sizeof(hostname)); 305 break; 306 307 case 'i': /* inetd mode */ 308 standalone = FALSE; 309 break; 310 311 case 's': /* standalone mode */ 312 standalone = TRUE; 313 break; 314 315 case 't': /* timeout */ 316 if (argv[0][2]) { 317 stmp = &(argv[0][2]); 318 } else { 319 argc--; 320 argv++; 321 stmp = argv[0]; 322 } 323 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 324 fprintf(stderr, 325 "%s: invalid timeout specification\n", progname); 326 break; 327 } 328 actualtimeout = n * 60000; 329 /* 330 * If the actual timeout is zero, pass INFTIM 331 * to poll so it blocks indefinitely, otherwise, 332 * use the actual timeout value. 333 */ 334 timeout = (n > 0) ? actualtimeout : INFTIM; 335 break; 336 337 default: 338 fprintf(stderr, "%s: unknown switch: -%c\n", 339 progname, argv[0][1]); 340 usage(); 341 break; 342 343 } /* switch */ 344 } /* for args */ 345 346 /* 347 * Override default file names if specified on the command line. 348 */ 349 if (argc > 0) 350 bootptab = argv[0]; 351 352 if (argc > 1) 353 bootpd_dump = argv[1]; 354 355 /* 356 * Get my hostname and IP address. 357 */ 358 if (hostname[0] == '\0') { 359 if (gethostname(hostname, sizeof(hostname)) == -1) { 360 fprintf(stderr, "bootpd: can't get hostname\n"); 361 exit(1); 362 } 363 hostname[sizeof(hostname) - 1] = '\0'; 364 } 365 hep = gethostbyname(hostname); 366 if (!hep) { 367 fprintf(stderr, "Can not get my IP address\n"); 368 exit(1); 369 } 370 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr)); 371 372 if (standalone) { 373 /* 374 * Go into background and disassociate from controlling terminal. 375 */ 376 if (debug < 3) { 377 if (fork()) 378 exit(0); 379 #ifdef NO_SETSID 380 setpgrp(0,0); 381 #ifdef TIOCNOTTY 382 n = open("/dev/tty", O_RDWR); 383 if (n >= 0) { 384 ioctl(n, TIOCNOTTY, (char *) 0); 385 (void) close(n); 386 } 387 #endif /* TIOCNOTTY */ 388 #else /* SETSID */ 389 if (setsid() < 0) 390 perror("setsid"); 391 #endif /* SETSID */ 392 } /* if debug < 3 */ 393 394 /* 395 * Nuke any timeout value 396 */ 397 timeout = INFTIM; 398 399 } /* if standalone (1st) */ 400 401 /* Set the cwd (i.e. to /tftpboot) */ 402 if (chdir_path) { 403 if (chdir(chdir_path) < 0) 404 report(LOG_ERR, "%s: chdir failed", chdir_path); 405 } 406 407 /* Get the timezone. */ 408 tzone_init(); 409 410 /* Allocate hash tables. */ 411 rdtab_init(); 412 413 /* 414 * Read the bootptab file. 415 */ 416 readtab(1); /* force read */ 417 418 if (standalone) { 419 420 /* 421 * Create a socket. 422 */ 423 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 424 report(LOG_ERR, "socket: %s", get_network_errmsg()); 425 exit(1); 426 } 427 428 /* 429 * Get server's listening port number 430 */ 431 servp = getservbyname("bootps", "udp"); 432 if (servp) { 433 bootps_port = ntohs((u_short) servp->s_port); 434 } else { 435 bootps_port = (u_short) IPPORT_BOOTPS; 436 report(LOG_ERR, 437 "udp/bootps: unknown service -- assuming port %d", 438 bootps_port); 439 } 440 441 /* 442 * Bind socket to BOOTPS port. 443 */ 444 bind_addr.sin_family = AF_INET; 445 bind_addr.sin_addr.s_addr = INADDR_ANY; 446 bind_addr.sin_port = htons(bootps_port); 447 if (bind(s, (struct sockaddr *) &bind_addr, 448 sizeof(bind_addr)) < 0) 449 { 450 report(LOG_ERR, "bind: %s", get_network_errmsg()); 451 exit(1); 452 } 453 } /* if standalone (2nd)*/ 454 455 /* 456 * Get destination port number so we can reply to client 457 */ 458 servp = getservbyname("bootpc", "udp"); 459 if (servp) { 460 bootpc_port = ntohs(servp->s_port); 461 } else { 462 report(LOG_ERR, 463 "udp/bootpc: unknown service -- assuming port %d", 464 IPPORT_BOOTPC); 465 bootpc_port = (u_short) IPPORT_BOOTPC; 466 } 467 468 /* 469 * Set up signals to read or dump the table. 470 */ 471 if ((long) signal(SIGHUP, catcher) < 0) { 472 report(LOG_ERR, "signal: %s", get_errmsg()); 473 exit(1); 474 } 475 if ((long) signal(SIGUSR1, catcher) < 0) { 476 report(LOG_ERR, "signal: %s", get_errmsg()); 477 exit(1); 478 } 479 480 /* 481 * Process incoming requests. 482 */ 483 set[0].fd = s; 484 set[0].events = POLLIN; 485 for (;;) { 486 nfound = poll(set, 1, timeout); 487 if (nfound < 0) { 488 if (errno != EINTR) { 489 report(LOG_ERR, "poll: %s", get_errmsg()); 490 } 491 /* 492 * Call readtab() or dumptab() here to avoid the 493 * dangers of doing I/O from a signal handler. 494 */ 495 if (do_readtab) { 496 do_readtab = 0; 497 readtab(1); /* force read */ 498 } 499 if (do_dumptab) { 500 do_dumptab = 0; 501 dumptab(bootpd_dump); 502 } 503 continue; 504 } 505 if (nfound == 0) { 506 if (debug > 1) 507 report(LOG_INFO, "exiting after %d minute%s of inactivity", 508 actualtimeout / 60000, 509 actualtimeout == 60000 ? "" : "s"); 510 exit(0); 511 } 512 ra_len = sizeof(recv_addr); 513 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0, 514 (struct sockaddr *) &recv_addr, &ra_len); 515 if (n <= 0) { 516 continue; 517 } 518 if (debug > 1) { 519 report(LOG_INFO, "recvd pkt from IP addr %s", 520 inet_ntoa(recv_addr.sin_addr)); 521 } 522 if (n < (int)sizeof(struct bootp)) { 523 if (debug) { 524 report(LOG_INFO, "received short packet"); 525 } 526 continue; 527 } 528 pktlen = n; 529 530 readtab(0); /* maybe re-read bootptab */ 531 532 switch (bp->bp_op) { 533 case BOOTREQUEST: 534 handle_request(); 535 break; 536 case BOOTREPLY: 537 handle_reply(); 538 break; 539 } 540 } 541 } 542 543 544 545 546 /* 547 * Print "usage" message and exit 548 */ 549 550 PRIVATE void 551 usage(void) 552 { 553 fprintf(stderr, 554 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n"); 555 fprintf(stderr, "\t -c n\tset current directory\n"); 556 fprintf(stderr, "\t -d n\tset debug level\n"); 557 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n"); 558 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n"); 559 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n"); 560 exit(1); 561 } 562 563 /* Signal catchers */ 564 PRIVATE void 565 catcher(int sig) 566 { 567 if (sig == SIGHUP) 568 do_readtab = 1; 569 if (sig == SIGUSR1) 570 do_dumptab = 1; 571 #ifdef SYSV 572 /* For older "System V" derivatives with no sigset(). */ 573 /* XXX - Should just do it the POSIX way (sigaction). */ 574 signal(sig, catcher); 575 #endif 576 } 577 578 579 580 /* 581 * Process BOOTREQUEST packet. 582 * 583 * Note: This version of the bootpd.c server never forwards 584 * a request to another server. That is the job of a gateway 585 * program such as the "bootpgw" program included here. 586 * 587 * (Also this version does not interpret the hostname field of 588 * the request packet; it COULD do a name->address lookup and 589 * forward the request there.) 590 */ 591 PRIVATE void 592 handle_request(void) 593 { 594 struct bootp *bp = (struct bootp *) pktbuf; 595 struct host *hp = NULL; 596 struct host dummyhost; 597 int32 bootsize = 0; 598 unsigned hlen, hashcode; 599 int32 dest; 600 char lrealpath[1024]; 601 char *clntpath; 602 size_t clntpathmaxlen; 603 char *homedir, *bootfile; 604 int n; 605 606 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */ 607 608 /* 609 * If the servername field is set, compare it against us. 610 * If we're not being addressed, ignore this request. 611 * If the server name field is null, throw in our name. 612 */ 613 if (strlen(bp->bp_sname)) { 614 if (strcmp(bp->bp_sname, hostname)) { 615 if (debug) 616 report(LOG_INFO, "\ 617 ignoring request for server %s from client at %s address %s", 618 bp->bp_sname, netname(bp->bp_htype), 619 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 620 /* XXX - Is it correct to ignore such a request? -gwr */ 621 return; 622 } 623 } else { 624 strlcpy(bp->bp_sname, hostname, sizeof(bp->bp_sname)); 625 } 626 627 /* If it uses an unknown network type, ignore the request. */ 628 if (bp->bp_htype >= hwinfocnt) { 629 if (debug) 630 report(LOG_INFO, 631 "Request with unknown network type %u", 632 bp->bp_htype); 633 return; 634 } 635 636 /* Convert the request into a reply. */ 637 bp->bp_op = BOOTREPLY; 638 if (bp->bp_ciaddr.s_addr == 0) { 639 /* 640 * client doesnt know his IP address, 641 * search by hardware address. 642 */ 643 if (debug > 1) { 644 report(LOG_INFO, "request from %s address %s", 645 netname(bp->bp_htype), 646 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 647 } 648 hlen = haddrlength(bp->bp_htype); 649 if (hlen != bp->bp_hlen) { 650 report(LOG_NOTICE, "bad addr len from %s address %s", 651 netname(bp->bp_htype), 652 haddrtoa(bp->bp_chaddr, hlen)); 653 } 654 dummyhost.htype = bp->bp_htype; 655 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen); 656 hashcode = hash_HashFunction(bp->bp_chaddr, hlen); 657 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp, 658 &dummyhost); 659 if (hp == NULL && 660 bp->bp_htype == HTYPE_IEEE802) 661 { 662 /* Try again with address in "canonical" form. */ 663 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen); 664 if (debug > 1) { 665 report(LOG_INFO, "\ 666 HW addr type is IEEE 802. convert to %s and check again\n", 667 haddrtoa(dummyhost.haddr, bp->bp_hlen)); 668 } 669 hashcode = hash_HashFunction(dummyhost.haddr, hlen); 670 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, 671 hwlookcmp, &dummyhost); 672 } 673 if (hp == NULL) { 674 /* 675 * XXX - Add dynamic IP address assignment? 676 */ 677 if (debug > 1) 678 report(LOG_INFO, "unknown client %s address %s", 679 netname(bp->bp_htype), 680 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 681 return; /* not found */ 682 } 683 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr; 684 685 } else { 686 687 /* 688 * search by IP address. 689 */ 690 if (debug > 1) { 691 report(LOG_INFO, "request from IP addr %s", 692 inet_ntoa(bp->bp_ciaddr)); 693 } 694 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr; 695 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4); 696 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp, 697 &dummyhost); 698 if (hp == NULL) { 699 if (debug > 1) { 700 report(LOG_NOTICE, "IP address not found: %s", 701 inet_ntoa(bp->bp_ciaddr)); 702 } 703 return; 704 } 705 } 706 707 if (debug) { 708 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr), 709 hp->hostname->string); 710 } 711 712 /* 713 * If there is a response delay threshold, ignore requests 714 * with a timestamp lower than the threshold. 715 */ 716 if (hp->flags.min_wait) { 717 u_int32 t = (u_int32) ntohs(bp->bp_secs); 718 if (t < hp->min_wait) { 719 if (debug > 1) 720 report(LOG_INFO, 721 "ignoring request due to timestamp (%d < %d)", 722 t, hp->min_wait); 723 return; 724 } 725 } 726 727 #ifdef YORK_EX_OPTION 728 /* 729 * The need for the "ex" tag arose out of the need to empty 730 * shared networked drives on diskless PCs. This solution is 731 * not very clean but it does work fairly well. 732 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk> 733 * 734 * XXX - This could compromise security if a non-trusted user 735 * managed to write an entry in the bootptab with :ex=trojan: 736 * so I would leave this turned off unless you need it. -gwr 737 */ 738 /* Run a program, passing the client name as a parameter. */ 739 if (hp->flags.exec_file) { 740 char tst[100]; 741 /* XXX - Check string lengths? -gwr */ 742 strlcpy(tst, hp->exec_file->string, sizeof(tst)); 743 strlcat(tst, " ", sizeof(tst)); 744 strlcat(tst, hp->hostname->string, sizeof(tst)); 745 strlcat(tst, " &", sizeof(tst)); 746 if (debug) 747 report(LOG_INFO, "executing %s", tst); 748 system(tst); /* Hope this finishes soon... */ 749 } 750 #endif /* YORK_EX_OPTION */ 751 752 /* 753 * If a specific TFTP server address was specified in the bootptab file, 754 * fill it in, otherwise zero it. 755 * XXX - Rather than zero it, should it be the bootpd address? -gwr 756 */ 757 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ? 758 hp->bootserver.s_addr : 0L; 759 760 #ifdef STANFORD_PROM_COMPAT 761 /* 762 * Stanford bootp PROMs (for a Sun?) have no way to leave 763 * the boot file name field blank (because the boot file 764 * name is automatically generated from some index). 765 * As a work-around, this little hack allows those PROMs to 766 * specify "sunboot14" with the same effect as a NULL name. 767 * (The user specifies boot device 14 or some such magic.) 768 */ 769 if (strcmp(bp->bp_file, "sunboot14") == 0) 770 bp->bp_file[0] = '\0'; /* treat it as unspecified */ 771 #endif 772 773 /* 774 * Fill in the client's proper bootfile. 775 * 776 * If the client specifies an absolute path, try that file with a 777 * ".host" suffix and then without. If the file cannot be found, no 778 * reply is made at all. 779 * 780 * If the client specifies a null or relative file, use the following 781 * table to determine the appropriate action: 782 * 783 * Homedir Bootfile Client's file 784 * specified? specified? specification Action 785 * ------------------------------------------------------------------- 786 * No No Null Send null filename 787 * No No Relative Discard request 788 * No Yes Null Send if absolute else null 789 * No Yes Relative Discard request *XXX 790 * Yes No Null Send null filename 791 * Yes No Relative Lookup with ".host" 792 * Yes Yes Null Send home/boot or bootfile 793 * Yes Yes Relative Lookup with ".host" *XXX 794 * 795 */ 796 797 /* 798 * XXX - I don't like the policy of ignoring a client when the 799 * boot file is not accessible. The TFTP server might not be 800 * running on the same machine as the BOOTP server, in which 801 * case checking accessibility of the boot file is pointless. 802 * 803 * Therefore, file accessibility is now demanded ONLY if you 804 * define CHECK_FILE_ACCESS in the Makefile options. -gwr 805 */ 806 807 /* 808 * The "real" path is as seen by the BOOTP daemon on this 809 * machine, while the client path is relative to the TFTP 810 * daemon chroot directory (i.e. /tftpboot). 811 */ 812 if (hp->flags.tftpdir) { 813 strlcpy(lrealpath, hp->tftpdir->string, sizeof(lrealpath)); 814 clntpath = &lrealpath[strlen(lrealpath)]; 815 clntpathmaxlen = sizeof(lrealpath) + lrealpath - clntpath; 816 } else { 817 lrealpath[0] = '\0'; 818 clntpath = lrealpath; 819 clntpathmaxlen = sizeof(lrealpath); 820 } 821 822 /* 823 * Determine client's requested homedir and bootfile. 824 */ 825 homedir = NULL; 826 bootfile = NULL; 827 if (bp->bp_file[0]) { 828 char *t; 829 830 homedir = bp->bp_file; 831 832 /* make sure that the file is nul terminated */ 833 for (t = homedir; t - homedir < BP_FILE_LEN; t++) 834 if (*t == '\0') 835 break; 836 if (t - homedir < BP_FILE_LEN) { 837 report(LOG_INFO, "requested path length > BP_FILE_LEN file = \"%s\", nul terminating", homedir); 838 homedir[BP_FILE_LEN - 1] = '\0'; 839 } 840 841 bootfile = strrchr(homedir, '/'); 842 if (bootfile) { 843 if (homedir == bootfile) 844 homedir = NULL; 845 *bootfile++ = '\0'; 846 } else { 847 /* no "/" in the string */ 848 bootfile = homedir; 849 homedir = NULL; 850 } 851 if (debug > 2) { 852 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"", 853 (homedir) ? homedir : "", 854 (bootfile) ? bootfile : ""); 855 } 856 } 857 858 /* 859 * Specifications in bootptab override client requested values. 860 */ 861 if (hp->flags.homedir) 862 homedir = hp->homedir->string; 863 if (hp->flags.bootfile) 864 bootfile = hp->bootfile->string; 865 866 /* 867 * Construct bootfile path. 868 */ 869 if (homedir) { 870 if (homedir[0] != '/') 871 strlcat(lrealpath, "/", sizeof(lrealpath)); 872 strlcat(lrealpath, homedir, sizeof(lrealpath)); 873 homedir = NULL; 874 } 875 if (bootfile) { 876 if (bootfile[0] != '/') { 877 strlcat(lrealpath, "/", sizeof(lrealpath)); 878 lrealpath[sizeof(lrealpath) - 1] = '\0'; 879 } 880 strlcat(lrealpath, bootfile, sizeof(lrealpath)); 881 lrealpath[sizeof(lrealpath) - 1] = '\0'; 882 bootfile = NULL; 883 } 884 885 /* 886 * First try to find the file with a ".host" suffix 887 */ 888 n = strlen(clntpath); 889 strlcat(clntpath, ".", clntpathmaxlen); 890 strlcat(clntpath, hp->hostname->string, clntpathmaxlen); 891 if (chk_access(lrealpath, &bootsize) < 0) { 892 clntpath[n] = 0; /* Try it without the suffix */ 893 if (chk_access(lrealpath, &bootsize) < 0) { 894 /* neither "file.host" nor "file" was found */ 895 #ifdef CHECK_FILE_ACCESS 896 897 if (bp->bp_file[0]) { 898 /* 899 * Client wanted specific file 900 * and we didn't have it. 901 */ 902 report(LOG_NOTICE, 903 "requested file not found: \"%s\"", clntpath); 904 return; 905 } 906 /* 907 * Client didn't ask for a specific file and we couldn't 908 * access the default file, so just zero-out the bootfile 909 * field in the packet and continue processing the reply. 910 */ 911 bzero(bp->bp_file, sizeof(bp->bp_file)); 912 goto null_file_name; 913 914 #else /* CHECK_FILE_ACCESS */ 915 916 /* Complain only if boot file size was needed. */ 917 if (hp->flags.bootsize_auto) { 918 report(LOG_ERR, "can not determine size of file \"%s\"", 919 clntpath); 920 } 921 922 #endif /* CHECK_FILE_ACCESS */ 923 } 924 } 925 strlcpy(bp->bp_file, clntpath, sizeof(bp->bp_file)); 926 if (debug > 2) 927 report(LOG_INFO, "bootfile=\"%s\"", clntpath); 928 929 #ifdef CHECK_FILE_ACCESS 930 null_file_name: 931 #endif /* CHECK_FILE_ACCESS */ 932 933 934 /* 935 * Handle vendor options based on magic number. 936 */ 937 938 if (debug > 1) { 939 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d", 940 (int) ((bp->bp_vend)[0]), 941 (int) ((bp->bp_vend)[1]), 942 (int) ((bp->bp_vend)[2]), 943 (int) ((bp->bp_vend)[3])); 944 } 945 /* 946 * If this host isn't set for automatic vendor info then copy the 947 * specific cookie into the bootp packet, thus forcing a certain 948 * reply format. Only force reply format if user specified it. 949 */ 950 if (hp->flags.vm_cookie) { 951 /* Slam in the user specified magic number. */ 952 bcopy(hp->vm_cookie, bp->bp_vend, 4); 953 } 954 /* 955 * Figure out the format for the vendor-specific info. 956 * Note that bp->bp_vend may have been set above. 957 */ 958 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) { 959 /* RFC1048 conformant bootp client */ 960 dovend_rfc1048(bp, hp, bootsize); 961 if (debug > 1) { 962 report(LOG_INFO, "sending reply (with RFC1048 options)"); 963 } 964 } 965 #ifdef VEND_CMU 966 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) { 967 dovend_cmu(bp, hp); 968 if (debug > 1) { 969 report(LOG_INFO, "sending reply (with CMU options)"); 970 } 971 } 972 #endif 973 else { 974 if (debug > 1) { 975 report(LOG_INFO, "sending reply (with no options)"); 976 } 977 } 978 979 dest = (hp->flags.reply_addr) ? 980 hp->reply_addr.s_addr : 0L; 981 982 /* not forwarded */ 983 sendreply(0, dest); 984 } 985 986 987 /* 988 * Process BOOTREPLY packet. 989 */ 990 PRIVATE void 991 handle_reply(void) 992 { 993 if (debug) { 994 report(LOG_INFO, "processing boot reply"); 995 } 996 /* forwarded, no destination override */ 997 sendreply(1, 0); 998 } 999 1000 1001 /* 1002 * Send a reply packet to the client. 'forward' flag is set if we are 1003 * not the originator of this reply packet. 1004 */ 1005 PRIVATE void 1006 sendreply(int forward, int32 dst_override) 1007 { 1008 struct bootp *bp = (struct bootp *) pktbuf; 1009 struct in_addr dst; 1010 u_short port = bootpc_port; 1011 unsigned char *ha; 1012 int len; 1013 1014 /* 1015 * XXX - Should honor bp_flags "broadcast" bit here. 1016 * Temporary workaround: use the :ra=ADDR: option to 1017 * set the reply address to the broadcast address. 1018 */ 1019 1020 /* 1021 * If the destination address was specified explicitly 1022 * (i.e. the broadcast address for HP compatibility) 1023 * then send the response to that address. Otherwise, 1024 * act in accordance with RFC951: 1025 * If the client IP address is specified, use that 1026 * else if gateway IP address is specified, use that 1027 * else make a temporary arp cache entry for the client's 1028 * NEW IP/hardware address and use that. 1029 */ 1030 if (dst_override) { 1031 dst.s_addr = dst_override; 1032 if (debug > 1) { 1033 report(LOG_INFO, "reply address override: %s", 1034 inet_ntoa(dst)); 1035 } 1036 } else if (bp->bp_ciaddr.s_addr) { 1037 dst = bp->bp_ciaddr; 1038 } else if (bp->bp_giaddr.s_addr && forward == 0) { 1039 dst = bp->bp_giaddr; 1040 port = bootps_port; 1041 if (debug > 1) { 1042 report(LOG_INFO, "sending reply to gateway %s", 1043 inet_ntoa(dst)); 1044 } 1045 } else { 1046 dst = bp->bp_yiaddr; 1047 ha = bp->bp_chaddr; 1048 len = bp->bp_hlen; 1049 if (len > MAXHADDRLEN) 1050 len = MAXHADDRLEN; 1051 1052 if (debug > 1) 1053 report(LOG_INFO, "setarp %s - %s", 1054 inet_ntoa(dst), haddrtoa(ha, len)); 1055 setarp(s, &dst, ha, len); 1056 } 1057 1058 if ((forward == 0) && 1059 (bp->bp_siaddr.s_addr == 0)) 1060 { 1061 struct ifreq *ifr; 1062 struct in_addr siaddr; 1063 /* 1064 * If we are originating this reply, we 1065 * need to find our own interface address to 1066 * put in the bp_siaddr field of the reply. 1067 * If this server is multi-homed, pick the 1068 * 'best' interface (the one on the same net 1069 * as the client). Of course, the client may 1070 * be on the other side of a BOOTP gateway... 1071 */ 1072 ifr = getif(s, &dst); 1073 if (ifr) { 1074 struct sockaddr_in *sip; 1075 sip = (struct sockaddr_in *) &(ifr->ifr_addr); 1076 siaddr = sip->sin_addr; 1077 } else { 1078 /* Just use my "official" IP address. */ 1079 siaddr = my_ip_addr; 1080 } 1081 1082 /* XXX - No need to set bp_giaddr here. */ 1083 1084 /* Finally, set the server address field. */ 1085 bp->bp_siaddr = siaddr; 1086 } 1087 /* Set up socket address for send. */ 1088 send_addr.sin_family = AF_INET; 1089 send_addr.sin_port = htons(port); 1090 send_addr.sin_addr = dst; 1091 1092 /* Send reply with same size packet as request used. */ 1093 if (sendto(s, pktbuf, pktlen, 0, 1094 (struct sockaddr *) &send_addr, 1095 sizeof(send_addr)) < 0) 1096 { 1097 report(LOG_ERR, "sendto: %s", get_network_errmsg()); 1098 } 1099 } /* sendreply */ 1100 1101 1102 /* nmatch() - now in getif.c */ 1103 /* setarp() - now in hwaddr.c */ 1104 1105 1106 /* 1107 * This call checks read access to a file. It returns 0 if the file given 1108 * by "path" exists and is publically readable. A value of -1 is returned if 1109 * access is not permitted or an error occurs. Successful calls also 1110 * return the file size in bytes using the long pointer "filesize". 1111 * 1112 * The read permission bit for "other" users is checked. This bit must be 1113 * set for tftpd(8) to allow clients to read the file. 1114 */ 1115 1116 PRIVATE int 1117 chk_access(char *path, int32 *filesize) 1118 { 1119 struct stat st; 1120 1121 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) { 1122 *filesize = (int32) st.st_size; 1123 return 0; 1124 } else { 1125 return -1; 1126 } 1127 } 1128 1129 1130 /* 1131 * Now in dumptab.c : 1132 * dumptab() 1133 * dump_host() 1134 * list_ipaddresses() 1135 */ 1136 1137 #ifdef VEND_CMU 1138 1139 /* 1140 * Insert the CMU "vendor" data for the host pointed to by "hp" into the 1141 * bootp packet pointed to by "bp". 1142 */ 1143 1144 PRIVATE void 1145 dovend_cmu(struct bootp *bp, struct host *hp) 1146 { 1147 struct cmu_vend *vendp; 1148 struct in_addr_list *taddr; 1149 1150 /* 1151 * Initialize the entire vendor field to zeroes. 1152 */ 1153 bzero(bp->bp_vend, sizeof(bp->bp_vend)); 1154 1155 /* 1156 * Fill in vendor information. Subnet mask, default gateway, 1157 * domain name server, ien name server, time server 1158 */ 1159 vendp = (struct cmu_vend *) bp->bp_vend; 1160 strlcpy(vendp->v_magic, (char *)vm_cmu, sizeof(vendp->v_magic)); 1161 if (hp->flags.subnet_mask) { 1162 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr; 1163 (vendp->v_flags) |= VF_SMASK; 1164 if (hp->flags.gateway) { 1165 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr; 1166 } 1167 } 1168 if (hp->flags.domain_server) { 1169 taddr = hp->domain_server; 1170 if (taddr->addrcount > 0) { 1171 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr; 1172 if (taddr->addrcount > 1) { 1173 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr; 1174 } 1175 } 1176 } 1177 if (hp->flags.name_server) { 1178 taddr = hp->name_server; 1179 if (taddr->addrcount > 0) { 1180 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr; 1181 if (taddr->addrcount > 1) { 1182 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr; 1183 } 1184 } 1185 } 1186 if (hp->flags.time_server) { 1187 taddr = hp->time_server; 1188 if (taddr->addrcount > 0) { 1189 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr; 1190 if (taddr->addrcount > 1) { 1191 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr; 1192 } 1193 } 1194 } 1195 /* Log message now done by caller. */ 1196 } /* dovend_cmu */ 1197 1198 #endif /* VEND_CMU */ 1199 1200 1201 1202 /* 1203 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the 1204 * bootp packet pointed to by "bp". 1205 */ 1206 #define NEED(LEN, MSG) do \ 1207 if (bytesleft < (LEN)) { \ 1208 report(LOG_NOTICE, noroom, \ 1209 hp->hostname->string, MSG); \ 1210 return; \ 1211 } while (0) 1212 PRIVATE void 1213 dovend_rfc1048(struct bootp *bp, struct host *hp, int32 bootsize) 1214 { 1215 int bytesleft, len; 1216 byte *vp; 1217 1218 static const char noroom[] = "%s: No room for \"%s\" option"; 1219 1220 vp = bp->bp_vend; 1221 1222 if (hp->flags.msg_size) { 1223 pktlen = hp->msg_size; 1224 } else { 1225 /* 1226 * If the request was longer than the official length, build 1227 * a response of that same length where the additional length 1228 * is assumed to be part of the bp_vend (options) area. 1229 */ 1230 if (pktlen > (int)sizeof(*bp)) { 1231 if (debug > 1) 1232 report(LOG_INFO, "request message length=%d", pktlen); 1233 } 1234 /* 1235 * Check whether the request contains the option: 1236 * Maximum DHCP Message Size (RFC1533 sec. 9.8) 1237 * and if so, override the response length with its value. 1238 * This request must lie within the first BP_VEND_LEN 1239 * bytes of the option space. 1240 */ 1241 { 1242 byte *p, *ep; 1243 byte tag, llen; 1244 short msgsz = 0; 1245 1246 p = vp + 4; 1247 ep = p + BP_VEND_LEN - 4; 1248 while (p < ep) { 1249 tag = *p++; 1250 /* Check for tags with no data first. */ 1251 if (tag == TAG_PAD) 1252 continue; 1253 if (tag == TAG_END) 1254 break; 1255 /* Now scan the length byte. */ 1256 llen = *p++; 1257 switch (tag) { 1258 case TAG_MAX_MSGSZ: 1259 if (llen == 2) { 1260 bcopy(p, (char*)&msgsz, 2); 1261 msgsz = ntohs(msgsz); 1262 } 1263 break; 1264 case TAG_SUBNET_MASK: 1265 /* XXX - Should preserve this if given... */ 1266 break; 1267 } /* swtich */ 1268 p += llen; 1269 } 1270 1271 if (msgsz > (int)sizeof(*bp)) { 1272 if (debug > 1) 1273 report(LOG_INFO, "request has DHCP msglen=%d", msgsz); 1274 pktlen = msgsz; 1275 } 1276 } 1277 } 1278 1279 if (pktlen < (int)sizeof(*bp)) { 1280 report(LOG_ERR, "invalid response length=%d", pktlen); 1281 pktlen = sizeof(*bp); 1282 } 1283 bytesleft = ((byte*)bp + pktlen) - vp; 1284 if (pktlen > (int)sizeof(*bp)) { 1285 if (debug > 1) 1286 report(LOG_INFO, "extended reply, length=%d, options=%d", 1287 pktlen, bytesleft); 1288 } 1289 1290 /* Copy in the magic cookie */ 1291 bcopy(vm_rfc1048, vp, 4); 1292 vp += 4; 1293 bytesleft -= 4; 1294 1295 if (hp->flags.subnet_mask) { 1296 /* always enough room here. */ 1297 *vp++ = TAG_SUBNET_MASK;/* -1 byte */ 1298 *vp++ = 4; /* -1 byte */ 1299 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */ 1300 bytesleft -= 6; /* Fix real count */ 1301 if (hp->flags.gateway) { 1302 (void) insert_ip(TAG_GATEWAY, 1303 hp->gateway, 1304 &vp, &bytesleft); 1305 } 1306 } 1307 if (hp->flags.bootsize) { 1308 /* always enough room here */ 1309 bootsize = (hp->flags.bootsize_auto) ? 1310 ((bootsize + 511) / 512) : ((int32_t)hp->bootsize); /* Round up */ 1311 *vp++ = TAG_BOOT_SIZE; 1312 *vp++ = 2; 1313 *vp++ = (byte) ((bootsize >> 8) & 0xFF); 1314 *vp++ = (byte) (bootsize & 0xFF); 1315 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */ 1316 } 1317 /* 1318 * This one is special: Remaining options go in the ext file. 1319 * Only the subnet_mask, bootsize, and gateway should precede. 1320 */ 1321 if (hp->flags.exten_file) { 1322 /* 1323 * Check for room for exten_file. Add 3 to account for 1324 * TAG_EXTEN_FILE, length, and TAG_END. 1325 */ 1326 len = strlen(hp->exten_file->string); 1327 NEED((len + 3), "ef"); 1328 *vp++ = TAG_EXTEN_FILE; 1329 *vp++ = (byte) (len & 0xFF); 1330 bcopy(hp->exten_file->string, vp, len); 1331 vp += len; 1332 *vp++ = TAG_END; 1333 bytesleft -= len + 3; 1334 return; /* no more options here. */ 1335 } 1336 /* 1337 * The remaining options are inserted by the following 1338 * function (which is shared with bootpef.c). 1339 * Keep back one byte for the TAG_END. 1340 */ 1341 len = dovend_rfc1497(hp, vp, bytesleft - 1); 1342 vp += len; 1343 bytesleft -= len; 1344 1345 /* There should be at least one byte left. */ 1346 NEED(1, "(end)"); 1347 *vp++ = TAG_END; 1348 bytesleft--; 1349 1350 /* Log message done by caller. */ 1351 if (bytesleft > 0) { 1352 /* 1353 * Zero out any remaining part of the vendor area. 1354 */ 1355 bzero(vp, bytesleft); 1356 } 1357 } /* dovend_rfc1048 */ 1358 #undef NEED 1359 1360 1361 /* 1362 * Now in readfile.c: 1363 * hwlookcmp() 1364 * iplookcmp() 1365 */ 1366 1367 /* haddrtoa() - now in hwaddr.c */ 1368 /* 1369 * Now in dovend.c: 1370 * insert_ip() 1371 * insert_generic() 1372 * insert_u_long() 1373 */ 1374 1375 /* get_errmsg() - now in report.c */ 1376 1377 /* 1378 * Local Variables: 1379 * tab-width: 4 1380 * c-indent-level: 4 1381 * c-argdecl-indent: 4 1382 * c-continued-statement-offset: 4 1383 * c-continued-brace-offset: -4 1384 * c-label-offset: -4 1385 * c-brace-offset: 0 1386 * End: 1387 */ 1388