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