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 bp->bp_file[sizeof(bp->bp_file)-1] = '\0'; 640 641 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */ 642 643 /* 644 * If the servername field is set, compare it against us. 645 * If we're not being addressed, ignore this request. 646 * If the server name field is null, throw in our name. 647 */ 648 if (strlen(bp->bp_sname)) { 649 if (strcmp(bp->bp_sname, hostname)) { 650 if (debug) 651 report(LOG_INFO, "\ 652 ignoring request for server %s from client at %s address %s", 653 bp->bp_sname, netname(bp->bp_htype), 654 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 655 /* XXX - Is it correct to ignore such a request? -gwr */ 656 return; 657 } 658 } else { 659 strcpy(bp->bp_sname, hostname); 660 } 661 662 /* Convert the request into a reply. */ 663 bp->bp_op = BOOTREPLY; 664 if (bp->bp_ciaddr.s_addr == 0) { 665 /* 666 * client doesnt know his IP address, 667 * search by hardware address. 668 */ 669 if (debug > 1) { 670 report(LOG_INFO, "request from %s address %s", 671 netname(bp->bp_htype), 672 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 673 } 674 hlen = haddrlength(bp->bp_htype); 675 if (hlen != bp->bp_hlen) { 676 report(LOG_NOTICE, "bad addr len from %s address %s", 677 netname(bp->bp_htype), 678 haddrtoa(bp->bp_chaddr, hlen)); 679 } 680 dummyhost.htype = bp->bp_htype; 681 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen); 682 hashcode = hash_HashFunction(bp->bp_chaddr, hlen); 683 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp, 684 &dummyhost); 685 if (hp == NULL && 686 bp->bp_htype == HTYPE_IEEE802) 687 { 688 /* Try again with address in "canonical" form. */ 689 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen); 690 if (debug > 1) { 691 report(LOG_INFO, "\ 692 HW addr type is IEEE 802. convert to %s and check again\n", 693 haddrtoa(dummyhost.haddr, bp->bp_hlen)); 694 } 695 hashcode = hash_HashFunction(dummyhost.haddr, hlen); 696 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, 697 hwlookcmp, &dummyhost); 698 } 699 if (hp == NULL) { 700 /* 701 * XXX - Add dynamic IP address assignment? 702 */ 703 if (debug) 704 report(LOG_NOTICE, "unknown client %s address %s", 705 netname(bp->bp_htype), 706 haddrtoa(bp->bp_chaddr, bp->bp_hlen)); 707 return; /* not found */ 708 } 709 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr; 710 711 } else { 712 713 /* 714 * search by IP address. 715 */ 716 if (debug > 1) { 717 report(LOG_INFO, "request from IP addr %s", 718 inet_ntoa(bp->bp_ciaddr)); 719 } 720 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr; 721 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4); 722 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp, 723 &dummyhost); 724 if (hp == NULL) { 725 if (debug) { 726 report(LOG_NOTICE, "IP address not found: %s", 727 inet_ntoa(bp->bp_ciaddr)); 728 } 729 return; 730 } 731 } 732 733 if (debug) { 734 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr), 735 hp->hostname->string); 736 } 737 738 /* 739 * If there is a response delay threshold, ignore requests 740 * with a timestamp lower than the threshold. 741 */ 742 if (hp->flags.min_wait) { 743 u_int32 t = (u_int32) ntohs(bp->bp_secs); 744 if (t < hp->min_wait) { 745 if (debug > 1) 746 report(LOG_INFO, 747 "ignoring request due to timestamp (%d < %d)", 748 t, hp->min_wait); 749 return; 750 } 751 } 752 753 #ifdef YORK_EX_OPTION 754 /* 755 * The need for the "ex" tag arose out of the need to empty 756 * shared networked drives on diskless PCs. This solution is 757 * not very clean but it does work fairly well. 758 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk> 759 * 760 * XXX - This could compromise security if a non-trusted user 761 * managed to write an entry in the bootptab with :ex=trojan: 762 * so I would leave this turned off unless you need it. -gwr 763 */ 764 /* Run a program, passing the client name as a parameter. */ 765 if (hp->flags.exec_file) { 766 char tst[100]; 767 /* XXX - Check string lengths? -gwr */ 768 strcpy (tst, hp->exec_file->string); 769 strcat (tst, " "); 770 strcat (tst, hp->hostname->string); 771 strcat (tst, " &"); 772 if (debug) 773 report(LOG_INFO, "executing %s", tst); 774 system(tst); /* Hope this finishes soon... */ 775 } 776 #endif /* YORK_EX_OPTION */ 777 778 /* 779 * If a specific TFTP server address was specified in the bootptab file, 780 * fill it in, otherwise zero it. 781 * XXX - Rather than zero it, should it be the bootpd address? -gwr 782 */ 783 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ? 784 hp->bootserver.s_addr : 0L; 785 786 #ifdef STANFORD_PROM_COMPAT 787 /* 788 * Stanford bootp PROMs (for a Sun?) have no way to leave 789 * the boot file name field blank (because the boot file 790 * name is automatically generated from some index). 791 * As a work-around, this little hack allows those PROMs to 792 * specify "sunboot14" with the same effect as a NULL name. 793 * (The user specifies boot device 14 or some such magic.) 794 */ 795 if (strcmp(bp->bp_file, "sunboot14") == 0) 796 bp->bp_file[0] = '\0'; /* treat it as unspecified */ 797 #endif 798 799 /* 800 * Fill in the client's proper bootfile. 801 * 802 * If the client specifies an absolute path, try that file with a 803 * ".host" suffix and then without. If the file cannot be found, no 804 * reply is made at all. 805 * 806 * If the client specifies a null or relative file, use the following 807 * table to determine the appropriate action: 808 * 809 * Homedir Bootfile Client's file 810 * specified? specified? specification Action 811 * ------------------------------------------------------------------- 812 * No No Null Send null filename 813 * No No Relative Discard request 814 * No Yes Null Send if absolute else null 815 * No Yes Relative Discard request *XXX 816 * Yes No Null Send null filename 817 * Yes No Relative Lookup with ".host" 818 * Yes Yes Null Send home/boot or bootfile 819 * Yes Yes Relative Lookup with ".host" *XXX 820 * 821 */ 822 823 /* 824 * XXX - I don't like the policy of ignoring a client when the 825 * boot file is not accessible. The TFTP server might not be 826 * running on the same machine as the BOOTP server, in which 827 * case checking accessibility of the boot file is pointless. 828 * 829 * Therefore, file accessibility is now demanded ONLY if you 830 * define CHECK_FILE_ACCESS in the Makefile options. -gwr 831 */ 832 833 /* 834 * The "real" path is as seen by the BOOTP daemon on this 835 * machine, while the client path is relative to the TFTP 836 * daemon chroot directory (i.e. /tftpboot). 837 */ 838 if (hp->flags.tftpdir) { 839 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string); 840 clntpath = &realpath[strlen(realpath)]; 841 } else { 842 realpath[0] = '\0'; 843 clntpath = realpath; 844 } 845 846 /* 847 * Determine client's requested homedir and bootfile. 848 */ 849 homedir = NULL; 850 bootfile = NULL; 851 if (bp->bp_file[0]) { 852 homedir = bp->bp_file; 853 bootfile = strrchr(homedir, '/'); 854 if (bootfile) { 855 if (homedir == bootfile) 856 homedir = NULL; 857 *bootfile++ = '\0'; 858 } else { 859 /* no "/" in the string */ 860 bootfile = homedir; 861 homedir = NULL; 862 } 863 if (debug > 2) { 864 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"", 865 (homedir) ? homedir : "", 866 (bootfile) ? bootfile : ""); 867 } 868 } 869 870 /* 871 * Specifications in bootptab override client requested values. 872 */ 873 if (hp->flags.homedir) 874 homedir = hp->homedir->string; 875 if (hp->flags.bootfile) 876 bootfile = hp->bootfile->string; 877 878 /* 879 * Construct bootfile path. 880 */ 881 if (homedir) { 882 if (homedir[0] != '/') 883 strcat(clntpath, "/"); 884 strcat(clntpath, homedir); 885 homedir = NULL; 886 } 887 if (bootfile) { 888 if (bootfile[0] != '/') 889 strcat(clntpath, "/"); 890 strcat(clntpath, bootfile); 891 bootfile = NULL; 892 } 893 894 /* 895 * First try to find the file with a ".host" suffix 896 */ 897 n = strlen(clntpath); 898 strcat(clntpath, "."); 899 strcat(clntpath, hp->hostname->string); 900 if (chk_access(realpath, &bootsize) < 0) { 901 clntpath[n] = 0; /* Try it without the suffix */ 902 if (chk_access(realpath, &bootsize) < 0) { 903 /* neither "file.host" nor "file" was found */ 904 #ifdef CHECK_FILE_ACCESS 905 906 if (bp->bp_file[0]) { 907 /* 908 * Client wanted specific file 909 * and we didn't have it. 910 */ 911 report(LOG_NOTICE, 912 "requested file not found: \"%s\"", clntpath); 913 return; 914 } 915 /* 916 * Client didn't ask for a specific file and we couldn't 917 * access the default file, so just zero-out the bootfile 918 * field in the packet and continue processing the reply. 919 */ 920 bzero(bp->bp_file, sizeof(bp->bp_file)); 921 goto null_file_name; 922 923 #else /* CHECK_FILE_ACCESS */ 924 925 /* Complain only if boot file size was needed. */ 926 if (hp->flags.bootsize_auto) { 927 report(LOG_ERR, "can not determine size of file \"%s\"", 928 clntpath); 929 } 930 931 #endif /* CHECK_FILE_ACCESS */ 932 } 933 } 934 strncpy(bp->bp_file, clntpath, BP_FILE_LEN); 935 if (debug > 2) 936 report(LOG_INFO, "bootfile=\"%s\"", clntpath); 937 938 #ifdef CHECK_FILE_ACCESS 939 null_file_name: 940 #endif /* CHECK_FILE_ACCESS */ 941 942 943 /* 944 * Handle vendor options based on magic number. 945 */ 946 947 if (debug > 1) { 948 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d", 949 (int) ((bp->bp_vend)[0]), 950 (int) ((bp->bp_vend)[1]), 951 (int) ((bp->bp_vend)[2]), 952 (int) ((bp->bp_vend)[3])); 953 } 954 /* 955 * If this host isn't set for automatic vendor info then copy the 956 * specific cookie into the bootp packet, thus forcing a certain 957 * reply format. Only force reply format if user specified it. 958 */ 959 if (hp->flags.vm_cookie) { 960 /* Slam in the user specified magic number. */ 961 bcopy(hp->vm_cookie, bp->bp_vend, 4); 962 } 963 /* 964 * Figure out the format for the vendor-specific info. 965 * Note that bp->bp_vend may have been set above. 966 */ 967 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) { 968 /* RFC1048 conformant bootp client */ 969 dovend_rfc1048(bp, hp, bootsize); 970 if (debug > 1) { 971 report(LOG_INFO, "sending reply (with RFC1048 options)"); 972 } 973 } 974 #ifdef VEND_CMU 975 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) { 976 dovend_cmu(bp, hp); 977 if (debug > 1) { 978 report(LOG_INFO, "sending reply (with CMU options)"); 979 } 980 } 981 #endif 982 else { 983 if (debug > 1) { 984 report(LOG_INFO, "sending reply (with no options)"); 985 } 986 } 987 988 dest = (hp->flags.reply_addr) ? 989 hp->reply_addr.s_addr : 0L; 990 991 /* not forwarded */ 992 sendreply(0, dest); 993 } 994 995 996 /* 997 * Process BOOTREPLY packet. 998 */ 999 PRIVATE void 1000 handle_reply() 1001 { 1002 if (debug) { 1003 report(LOG_INFO, "processing boot reply"); 1004 } 1005 /* forwarded, no destination override */ 1006 sendreply(1, 0); 1007 } 1008 1009 1010 /* 1011 * Send a reply packet to the client. 'forward' flag is set if we are 1012 * not the originator of this reply packet. 1013 */ 1014 PRIVATE void 1015 sendreply(forward, dst_override) 1016 int forward; 1017 int32 dst_override; 1018 { 1019 struct bootp *bp = (struct bootp *) pktbuf; 1020 struct in_addr dst; 1021 u_short port = bootpc_port; 1022 unsigned char *ha; 1023 int len, haf; 1024 1025 /* 1026 * XXX - Should honor bp_flags "broadcast" bit here. 1027 * Temporary workaround: use the :ra=ADDR: option to 1028 * set the reply address to the broadcast address. 1029 */ 1030 1031 /* 1032 * If the destination address was specified explicitly 1033 * (i.e. the broadcast address for HP compatibility) 1034 * then send the response to that address. Otherwise, 1035 * act in accordance with RFC951: 1036 * If the client IP address is specified, use that 1037 * else if gateway IP address is specified, use that 1038 * else make a temporary arp cache entry for the client's 1039 * NEW IP/hardware address and use that. 1040 */ 1041 if (dst_override) { 1042 dst.s_addr = dst_override; 1043 if (debug > 1) { 1044 report(LOG_INFO, "reply address override: %s", 1045 inet_ntoa(dst)); 1046 } 1047 } else if (bp->bp_ciaddr.s_addr) { 1048 dst = bp->bp_ciaddr; 1049 } else if (bp->bp_giaddr.s_addr && forward == 0) { 1050 dst = bp->bp_giaddr; 1051 port = bootps_port; 1052 if (debug > 1) { 1053 report(LOG_INFO, "sending reply to gateway %s", 1054 inet_ntoa(dst)); 1055 } 1056 } else { 1057 dst = bp->bp_yiaddr; 1058 ha = bp->bp_chaddr; 1059 len = bp->bp_hlen; 1060 if (len > MAXHADDRLEN) 1061 len = MAXHADDRLEN; 1062 haf = (int) bp->bp_htype; 1063 if (haf == 0) 1064 haf = HTYPE_ETHERNET; 1065 1066 if (debug > 1) 1067 report(LOG_INFO, "setarp %s - %s", 1068 inet_ntoa(dst), haddrtoa(ha, len)); 1069 setarp(s, &dst, haf, ha, len); 1070 } 1071 1072 if ((forward == 0) && 1073 (bp->bp_siaddr.s_addr == 0)) 1074 { 1075 struct ifreq *ifr; 1076 struct in_addr siaddr; 1077 /* 1078 * If we are originating this reply, we 1079 * need to find our own interface address to 1080 * put in the bp_siaddr field of the reply. 1081 * If this server is multi-homed, pick the 1082 * 'best' interface (the one on the same net 1083 * as the client). Of course, the client may 1084 * be on the other side of a BOOTP gateway... 1085 */ 1086 ifr = getif(s, &dst); 1087 if (ifr) { 1088 struct sockaddr_in *sip; 1089 sip = (struct sockaddr_in *) &(ifr->ifr_addr); 1090 siaddr = sip->sin_addr; 1091 } else { 1092 /* Just use my "official" IP address. */ 1093 siaddr = my_ip_addr; 1094 } 1095 1096 /* XXX - No need to set bp_giaddr here. */ 1097 1098 /* Finally, set the server address field. */ 1099 bp->bp_siaddr = siaddr; 1100 } 1101 /* Set up socket address for send. */ 1102 send_addr.sin_family = AF_INET; 1103 send_addr.sin_port = htons(port); 1104 send_addr.sin_addr = dst; 1105 1106 /* Send reply with same size packet as request used. */ 1107 if (sendto(s, pktbuf, pktlen, 0, 1108 (struct sockaddr *) &send_addr, 1109 sizeof(send_addr)) < 0) 1110 { 1111 report(LOG_ERR, "sendto: %s", get_network_errmsg()); 1112 } 1113 } /* sendreply */ 1114 1115 1116 /* nmatch() - now in getif.c */ 1117 /* setarp() - now in hwaddr.c */ 1118 1119 1120 /* 1121 * This call checks read access to a file. It returns 0 if the file given 1122 * by "path" exists and is publically readable. A value of -1 is returned if 1123 * access is not permitted or an error occurs. Successful calls also 1124 * return the file size in bytes using the long pointer "filesize". 1125 * 1126 * The read permission bit for "other" users is checked. This bit must be 1127 * set for tftpd(8) to allow clients to read the file. 1128 */ 1129 1130 PRIVATE int 1131 chk_access(path, filesize) 1132 char *path; 1133 int32 *filesize; 1134 { 1135 struct stat st; 1136 1137 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) { 1138 *filesize = (int32) st.st_size; 1139 return 0; 1140 } else { 1141 return -1; 1142 } 1143 } 1144 1145 1146 /* 1147 * Now in dumptab.c : 1148 * dumptab() 1149 * dump_host() 1150 * list_ipaddresses() 1151 */ 1152 1153 #ifdef VEND_CMU 1154 1155 /* 1156 * Insert the CMU "vendor" data for the host pointed to by "hp" into the 1157 * bootp packet pointed to by "bp". 1158 */ 1159 1160 PRIVATE void 1161 dovend_cmu(bp, hp) 1162 struct bootp *bp; 1163 struct host *hp; 1164 { 1165 struct cmu_vend *vendp; 1166 struct in_addr_list *taddr; 1167 1168 /* 1169 * Initialize the entire vendor field to zeroes. 1170 */ 1171 bzero(bp->bp_vend, sizeof(bp->bp_vend)); 1172 1173 /* 1174 * Fill in vendor information. Subnet mask, default gateway, 1175 * domain name server, ien name server, time server 1176 */ 1177 vendp = (struct cmu_vend *) bp->bp_vend; 1178 strcpy(vendp->v_magic, (char *)vm_cmu); 1179 if (hp->flags.subnet_mask) { 1180 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr; 1181 (vendp->v_flags) |= VF_SMASK; 1182 if (hp->flags.gateway) { 1183 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr; 1184 } 1185 } 1186 if (hp->flags.domain_server) { 1187 taddr = hp->domain_server; 1188 if (taddr->addrcount > 0) { 1189 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr; 1190 if (taddr->addrcount > 1) { 1191 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr; 1192 } 1193 } 1194 } 1195 if (hp->flags.name_server) { 1196 taddr = hp->name_server; 1197 if (taddr->addrcount > 0) { 1198 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr; 1199 if (taddr->addrcount > 1) { 1200 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr; 1201 } 1202 } 1203 } 1204 if (hp->flags.time_server) { 1205 taddr = hp->time_server; 1206 if (taddr->addrcount > 0) { 1207 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr; 1208 if (taddr->addrcount > 1) { 1209 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr; 1210 } 1211 } 1212 } 1213 /* Log message now done by caller. */ 1214 } /* dovend_cmu */ 1215 1216 #endif /* VEND_CMU */ 1217 1218 1219 1220 /* 1221 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the 1222 * bootp packet pointed to by "bp". 1223 */ 1224 #define NEED(LEN, MSG) do \ 1225 if (bytesleft < (LEN)) { \ 1226 report(LOG_NOTICE, noroom, \ 1227 hp->hostname->string, MSG); \ 1228 return; \ 1229 } while (0) 1230 PRIVATE void 1231 dovend_rfc1048(bp, hp, bootsize) 1232 struct bootp *bp; 1233 struct host *hp; 1234 int32 bootsize; 1235 { 1236 int bytesleft, len; 1237 byte *vp; 1238 1239 static const char noroom[] = "%s: No room for \"%s\" option"; 1240 1241 vp = bp->bp_vend; 1242 1243 if (hp->flags.msg_size) { 1244 pktlen = hp->msg_size; 1245 } else { 1246 /* 1247 * If the request was longer than the official length, build 1248 * a response of that same length where the additional length 1249 * is assumed to be part of the bp_vend (options) area. 1250 */ 1251 if (pktlen > sizeof(*bp)) { 1252 if (debug > 1) 1253 report(LOG_INFO, "request message length=%d", pktlen); 1254 } 1255 /* 1256 * Check whether the request contains the option: 1257 * Maximum DHCP Message Size (RFC1533 sec. 9.8) 1258 * and if so, override the response length with its value. 1259 * This request must lie within the first BP_VEND_LEN 1260 * bytes of the option space. 1261 */ 1262 { 1263 byte *p, *ep; 1264 byte tag, len; 1265 short msgsz = 0; 1266 1267 p = vp + 4; 1268 ep = p + BP_VEND_LEN - 4; 1269 while (p < ep) { 1270 tag = *p++; 1271 /* Check for tags with no data first. */ 1272 if (tag == TAG_PAD) 1273 continue; 1274 if (tag == TAG_END) 1275 break; 1276 /* Now scan the length byte. */ 1277 len = *p++; 1278 switch (tag) { 1279 case TAG_MAX_MSGSZ: 1280 if (len == 2) { 1281 bcopy(p, (char*)&msgsz, 2); 1282 msgsz = ntohs(msgsz); 1283 } 1284 break; 1285 case TAG_SUBNET_MASK: 1286 /* XXX - Should preserve this if given... */ 1287 break; 1288 } /* swtich */ 1289 p += len; 1290 } 1291 1292 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) { 1293 if (debug > 1) 1294 report(LOG_INFO, "request has DHCP msglen=%d", msgsz); 1295 pktlen = msgsz - BP_MSG_OVERHEAD; 1296 } 1297 } 1298 } 1299 1300 if (pktlen < sizeof(*bp)) { 1301 report(LOG_ERR, "invalid response length=%d", pktlen); 1302 pktlen = sizeof(*bp); 1303 } 1304 bytesleft = ((byte*)bp + pktlen) - vp; 1305 if (pktlen > sizeof(*bp)) { 1306 if (debug > 1) 1307 report(LOG_INFO, "extended reply, length=%d, options=%d", 1308 pktlen, bytesleft); 1309 } 1310 1311 /* Copy in the magic cookie */ 1312 bcopy(vm_rfc1048, vp, 4); 1313 vp += 4; 1314 bytesleft -= 4; 1315 1316 if (hp->flags.subnet_mask) { 1317 /* always enough room here. */ 1318 *vp++ = TAG_SUBNET_MASK;/* -1 byte */ 1319 *vp++ = 4; /* -1 byte */ 1320 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */ 1321 bytesleft -= 6; /* Fix real count */ 1322 if (hp->flags.gateway) { 1323 (void) insert_ip(TAG_GATEWAY, 1324 hp->gateway, 1325 &vp, &bytesleft); 1326 } 1327 } 1328 if (hp->flags.bootsize) { 1329 /* always enough room here */ 1330 bootsize = (hp->flags.bootsize_auto) ? 1331 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */ 1332 *vp++ = TAG_BOOT_SIZE; 1333 *vp++ = 2; 1334 *vp++ = (byte) ((bootsize >> 8) & 0xFF); 1335 *vp++ = (byte) (bootsize & 0xFF); 1336 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */ 1337 } 1338 /* 1339 * This one is special: Remaining options go in the ext file. 1340 * Only the subnet_mask, bootsize, and gateway should precede. 1341 */ 1342 if (hp->flags.exten_file) { 1343 /* 1344 * Check for room for exten_file. Add 3 to account for 1345 * TAG_EXTEN_FILE, length, and TAG_END. 1346 */ 1347 len = strlen(hp->exten_file->string); 1348 NEED((len + 3), "ef"); 1349 *vp++ = TAG_EXTEN_FILE; 1350 *vp++ = (byte) (len & 0xFF); 1351 bcopy(hp->exten_file->string, vp, len); 1352 vp += len; 1353 *vp++ = TAG_END; 1354 bytesleft -= len + 3; 1355 return; /* no more options here. */ 1356 } 1357 /* 1358 * The remaining options are inserted by the following 1359 * function (which is shared with bootpef.c). 1360 * Keep back one byte for the TAG_END. 1361 */ 1362 len = dovend_rfc1497(hp, vp, bytesleft - 1); 1363 vp += len; 1364 bytesleft -= len; 1365 1366 /* There should be at least one byte left. */ 1367 NEED(1, "(end)"); 1368 *vp++ = TAG_END; 1369 bytesleft--; 1370 1371 /* Log message done by caller. */ 1372 if (bytesleft > 0) { 1373 /* 1374 * Zero out any remaining part of the vendor area. 1375 */ 1376 bzero(vp, bytesleft); 1377 } 1378 } /* dovend_rfc1048 */ 1379 #undef NEED 1380 1381 1382 /* 1383 * Now in readfile.c: 1384 * hwlookcmp() 1385 * iplookcmp() 1386 */ 1387 1388 /* haddrtoa() - now in hwaddr.c */ 1389 /* 1390 * Now in dovend.c: 1391 * insert_ip() 1392 * insert_generic() 1393 * insert_u_long() 1394 */ 1395 1396 /* get_errmsg() - now in report.c */ 1397 1398 /* 1399 * Local Variables: 1400 * tab-width: 4 1401 * c-indent-level: 4 1402 * c-argdecl-indent: 4 1403 * c-continued-statement-offset: 4 1404 * c-continued-brace-offset: -4 1405 * c-label-offset: -4 1406 * c-brace-offset: 0 1407 * End: 1408 */ 1409