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