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