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