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