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