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