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