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