home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / bootp-2.2.B / part02 / bootpd.c next >
Encoding:
C/C++ Source or Header  |  1993-10-11  |  39.6 KB  |  1,673 lines

  1. #ifndef _BLURB_
  2. #define _BLURB_
  3. /************************************************************************
  4.           Copyright 1988, 1991 by Carnegie Mellon University
  5.  
  6.                           All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its
  9. documentation for any purpose and without fee is hereby granted, provided
  10. that the above copyright notice appear in all copies and that both that
  11. copyright notice and this permission notice appear in supporting
  12. documentation, and that the name of Carnegie Mellon University not be used
  13. in advertising or publicity pertaining to distribution of the software
  14. without specific, written prior permission.
  15.  
  16. CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  17. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  18. IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  19. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  20. PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  21. ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. SOFTWARE.
  23. ************************************************************************/
  24. #endif /* _BLURB_ */
  25.  
  26.  
  27. #ifndef lint
  28. static char sccsid[] = "@(#)bootp.c    1.1 (Stanford) 1/22/86";
  29. static char rcsid[] = "$Header: /afs/andrew.cmu.edu/netdev/src/cmu/bootp-public/RCS/bootpd.c,v 1.3 1991/11/01 10:02:29 ww0n Exp ww0n $";
  30. #endif
  31.  
  32.  
  33. /*
  34.  * BOOTP (bootstrap protocol) server daemon.
  35.  *
  36.  * Answers BOOTP request packets from booting client machines.
  37.  * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
  38.  * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
  39.  * See accompanying man page -- bootpd.8
  40.  *
  41.  *
  42.  * HISTORY
  43.  *
  44.  * 01/22/86    Bill Croft at Stanford University
  45.  *            Created.
  46.  *
  47.  * 07/30/86     David Kovar at Carnegie Mellon University
  48.  *            Modified to work at CMU.
  49.  *
  50.  * 07/24/87    Drew D. Perkins at Carnegie Mellon University
  51.  *            Modified to use syslog instead of Kovar's
  52.  *            routines.  Add debugging dumps.  Many other fixups.
  53.  *
  54.  * 07/15/88    Walter L. Wimer at Carnegie Mellon University
  55.  *            Added vendor information to conform to RFC1048.
  56.  *            Adopted termcap-like file format to support above.
  57.  *            Added hash table lookup instead of linear search.
  58.  *            Other cleanups.
  59.  *
  60.  *
  61.  * BUGS
  62.  *
  63.  * Currently mallocs memory in a very haphazard manner.  As such, most of
  64.  * the program ends up core-resident all the time just to follow all the
  65.  * stupid pointers around. . . .
  66.  *
  67.  */
  68.  
  69.  
  70.  
  71.  
  72. #include <sys/types.h>
  73. #include <sys/socket.h>
  74. #include <sys/ioctl.h>
  75. #include <sys/file.h>
  76. #include <sys/time.h>
  77. #include <sys/stat.h>
  78. #include <net/if.h>
  79. #if defined(SUNOS4) || defined(SVR4)
  80. #include <sys/sockio.h>
  81. #include <net/if_arp.h>
  82. #endif
  83. #include <netinet/in.h>
  84. #include <stdlib.h>
  85. #include <signal.h>
  86. #include <stdio.h>
  87. #ifdef SVR4
  88. #include <sys/termios.h>    /* Why? */
  89. #include <string.h>
  90. #include <sys/fcntl.h>    /* Why? */
  91. #else
  92. #include <strings.h>
  93. #endif
  94. #include <errno.h>
  95. #include <ctype.h>
  96. #include <netdb.h>
  97. #ifdef SYSLOG
  98. #include <syslog.h>
  99. #endif
  100. #include "bootp.h"
  101. #include "hash.h"
  102. #include "bootpd.h"
  103.  
  104. #define HASHTABLESIZE        257    /* Hash table size (prime) */
  105. #define DEFAULT_TIMEOUT         15L    /* Default timeout in minutes */
  106. #define MAXPKT            (3*512) /* Maximum packet size */
  107.  
  108. #ifdef DEBUG
  109. #define CONFIG_FILE        "bootptab.debug"
  110. #endif    /* XXX */
  111.  
  112. #ifndef CONFIG_FILE
  113. #define CONFIG_FILE        "/etc/bootptab"
  114. #endif
  115. #ifndef DUMP_FILE
  116. #define DUMP_FILE        "/etc/bootpd.dump"
  117. #endif
  118.  
  119. #ifdef SVR4
  120. #define bcopy(a,b,c)    memcpy(b,a,c)
  121. #define bzero(p,l)      memset(p,0,l)
  122. #define bcmp(a,b,c)     memcmp(a,b,c)
  123. #define    index(a,b)    strchr(a,b)
  124. #endif
  125.  
  126.  
  127.  
  128. /*
  129.  * Externals, forward declarations, and global variables
  130.  */
  131.  
  132. extern char Version[];
  133. extern char *sys_errlist[];
  134. extern int  errno, sys_nerr;
  135.  
  136. void usage();
  137. void dump_host();
  138. void list_ipaddresses();
  139. #ifdef VEND_CMU
  140. void dovend_cmu();
  141. #endif
  142. void dovend_rfc1048();
  143. boolean hwlookcmp();
  144. boolean iplookcmp();
  145. void insert_generic();
  146. void insert_ip();
  147. void dumptab();
  148. int chk_access();
  149. void report();
  150. char *get_errmsg();
  151. void answer_request();
  152. void forward_reply();
  153.  
  154. /*
  155.  * IP port numbers for client and server obtained from /etc/services
  156.  */
  157.  
  158. u_short bootps_port, bootpc_port;
  159.  
  160.  
  161. /*
  162.  * Internet socket and interface config structures
  163.  */
  164.  
  165. struct sockaddr server_addr;
  166. struct sockaddr client_addr;
  167. struct ifreq ifreq[10];        /* Holds interface configuration */
  168. struct ifconf ifconf;        /* Int. config ioctl block (pnts to ifreq) */
  169. struct arpreq arpreq;        /* Arp request ioctl block */
  170.  
  171.  
  172. /*
  173.  * General
  174.  */
  175.  
  176. int debug = 0;                /* Debugging flag (level) */
  177. int s;                    /* Socket file descriptor */
  178. char *pktbuf;
  179. int pktlen;
  180. struct timezone tzp;            /* Time zone offset for clients */
  181. struct timeval tp;            /* Time (extra baggage) */
  182. long secondswest;            /* Time zone offset in seconds */
  183.  
  184. /*
  185.  * Globals below are associated with the bootp database file (bootptab).
  186.  */
  187.  
  188. char *bootptab = NULL;
  189. #ifdef DEBUG
  190. char *bootpd_dump = NULL;
  191. #endif
  192.  
  193.  
  194.  
  195. /*
  196.  * Vendor magic cookies for CMU and RFC1048
  197.  */
  198.  
  199. unsigned char vm_cmu[4]        = VM_CMU;
  200. unsigned char vm_rfc1048[4] = VM_RFC1048;
  201. unsigned char vm_zero[4]    = { 0, 0, 0, 0 };
  202.  
  203.  
  204. /*
  205.  * Hardware address lengths (in bytes) and network name based on hardware
  206.  * type code.  List in order specified by Assigned Numbers RFC; Array index
  207.  * is hardware type code.  Entries marked as zero are unknown to the author
  208.  * at this time.  .  .  .
  209.  */
  210.  
  211. struct hwinfo hwinfolist[] = {
  212.      { 0, "Reserved"     },    /* Type 0:  Reserved (don't use this)   */
  213.      { 6, "Ethernet"     },    /* Type 1:  10Mb Ethernet (48 bits)    */
  214.      { 1, "3Mb Ethernet" },    /* Type 2:   3Mb Ethernet (8 bits)    */
  215.      { 0, "AX.25"     },    /* Type 3:  Amateur Radio AX.25        */
  216.      { 1, "ProNET"     },    /* Type 4:  Proteon ProNET Token Ring   */
  217.      { 0, "Chaos"     },    /* Type 5:  Chaos            */
  218.      { 6, "IEEE 802"     },    /* Type 6:  IEEE 802 Networks        */
  219.      { 0, "ARCNET"     }    /* Type 7:  ARCNET            */
  220. };
  221. int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
  222.  
  223. /*
  224.  * Main hash tables
  225.  */
  226.  
  227. hash_tbl *hwhashtable;
  228. hash_tbl *iphashtable;
  229. hash_tbl *nmhashtable;
  230.  
  231.  
  232.  
  233.  
  234. /*
  235.  * Initialization such as command-line processing is done and then the main
  236.  * server loop is started.
  237.  */
  238.  
  239. main(argc, argv)
  240.     int argc;
  241.     char **argv;
  242. {
  243.     struct timeval actualtimeout, *timeout;
  244.     struct bootp *bp;
  245.     struct servent *servp;
  246.     struct sockaddr_in *s_sin;
  247.     char *stmp;
  248.     int n, sa_len, ca_len;
  249.     int nfound, readfds;
  250.     int standalone;
  251.  
  252.     stmp = NULL;
  253.     actualtimeout.tv_usec = 0L;
  254.     actualtimeout.tv_sec  = 60 * DEFAULT_TIMEOUT;
  255.     timeout = &actualtimeout;
  256.     s_sin = (struct sockaddr_in *) &server_addr;
  257.  
  258.     /* Get space for receiving packets and composing replies. */
  259.     pktbuf = malloc(MAXPKT);
  260.     bp = (struct bootp *) pktbuf;
  261.  
  262.     /*
  263.      * Check to see if a socket was passed to us from inetd.
  264.      *
  265.      * Use getsockname() to determine if descriptor 0 is indeed a socket
  266.      * (and thus we are probably a child of inetd) or if it is instead
  267.      * something else and we are running standalone.
  268.      */
  269.     s = 0;
  270.     sa_len = sizeof(server_addr);
  271.     bzero((char *) &server_addr, sa_len);
  272.     errno = 0;
  273.     standalone = TRUE;
  274.     if (getsockname(s, &server_addr, &sa_len) == 0) {
  275.     /*
  276.      * Descriptor 0 is a socket.  Assume we are a child of inetd.
  277.      */
  278.     if (s_sin->sin_family == AF_INET) {
  279.         standalone = FALSE;
  280.         bootps_port = ntohs(s_sin->sin_port);
  281.     } else {
  282.         report(LOG_INFO, "getsockname: not an INET socket\n");
  283.     }
  284.     }
  285.  
  286.     /*
  287.      * Read switches.
  288.      */
  289.     for (argc--, argv++; argc > 0; argc--, argv++) {
  290.     if (argv[0][0] == '-') {
  291.         switch (argv[0][1]) {
  292.         case 't':
  293.             if (argv[0][2]) {
  294.             stmp = &(argv[0][2]);
  295.             } else {
  296.             argc--;
  297.             argv++;
  298.             stmp = argv[0];
  299.             }
  300.             if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
  301.             fprintf(stderr,
  302.                 "bootpd: invalid timeout specification\n");
  303.             break;
  304.             }
  305.             actualtimeout.tv_sec = (long) (60 * n);
  306.             /*
  307.              * If the actual timeout is zero, pass a NULL pointer
  308.              * to select so it blocks indefinitely, otherwise,
  309.              * point to the actual timeout value.
  310.              */
  311.             timeout = (n > 0) ? &actualtimeout : NULL;
  312.             break;
  313.         case 'd':
  314.             if (argv[0][2]) {
  315.             stmp = &(argv[0][2]);
  316.             } else if (argv[1][0] == '-') {
  317.             /*
  318.              * Backwards-compatible behavior:
  319.              * no parameter, so just increment the debug flag.
  320.              */
  321.             debug++;
  322.             break;
  323.             } else {
  324.             argc--;
  325.             argv++;
  326.             stmp = argv[0];
  327.             }
  328.             if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
  329.             fprintf(stderr,
  330.                 "bootpd: invalid debug level\n");
  331.             break;
  332.             }
  333.             debug = n;
  334.             break;
  335.         case 's':
  336.             standalone = TRUE;
  337.             break;
  338.         case 'i':
  339.             standalone = FALSE;
  340.             break;
  341.         default:
  342.             fprintf(stderr, "bootpd: unknown switch: -%c\n",
  343.                 argv[0][1]);
  344.             usage();
  345.             break;
  346.         }
  347.     } else {
  348.         if (!bootptab) {
  349.         bootptab = argv[0];
  350. #ifdef DEBUG
  351.         } else if (!bootpd_dump) {
  352.         bootpd_dump = argv[0];
  353. #endif
  354.         } else {
  355.         fprintf(stderr, "bootpd: unknown argument: %s\n", argv[0]);
  356.         usage();
  357.         }
  358.     }
  359.     }
  360.  
  361.  
  362.     /*
  363.      * Set default file names if not specified on command line
  364.      */
  365.     if (!bootptab) {
  366.     bootptab = CONFIG_FILE;
  367.     }
  368. #ifdef DEBUG
  369.     if (!bootpd_dump) {
  370.     bootpd_dump = DUMP_FILE;
  371.     }
  372. #endif
  373.  
  374.  
  375.     if (standalone) {
  376.     /*
  377.      * Go into background and disassociate from controlling terminal.
  378.      * XXX - This is not the POSIX way... -gwr
  379.      */
  380.     if (debug < 3) {
  381.         if (fork())
  382.         exit(0);
  383.         for (n = 0; n < 10; n++)
  384.         (void) close(n);
  385.         (void) open("/", O_RDONLY);
  386.         (void) dup2(0, 1);
  387.         (void) dup2(0, 2);
  388.         n = open("/dev/tty", O_RDWR);
  389.         if (n >= 0) {
  390.         ioctl(n, TIOCNOTTY, (char *) 0);
  391.         (void) close(n);
  392.         }
  393.     }
  394.     /*
  395.      * Nuke any timeout value
  396.      */
  397.     timeout = NULL;
  398.     }
  399.  
  400.  
  401. #ifdef SYSLOG
  402.     /*
  403.      * Initialize logging.
  404.      */
  405. #ifndef LOG_CONS
  406. #define LOG_CONS    0    /* Don't bother if not defined... */
  407. #endif
  408. #ifndef LOG_DAEMON
  409. #define LOG_DAEMON    0
  410. #endif
  411.     openlog("bootpd", LOG_PID | LOG_CONS, LOG_DAEMON);
  412. #endif
  413.  
  414.     /*
  415.      * Log startup
  416.      */
  417.     report(LOG_INFO, "%s", Version);
  418.  
  419.     /*
  420.      * Get our timezone offset so we can give it to clients if the
  421.      * configuration file doesn't specify one.
  422.      */
  423.     if (gettimeofday(&tp, &tzp) < 0) {
  424.     secondswest = 0L;    /* Assume GMT for lack of anything better */
  425.     report(LOG_ERR, "gettimeofday: %s\n", get_errmsg());
  426.     } else {
  427.     secondswest = 60L * tzp.tz_minuteswest;        /* Convert to seconds */
  428.     }
  429.  
  430.     /*
  431.      * Allocate hash tables for hardware address, ip address, and hostname
  432.      */
  433.     hwhashtable = hash_Init(HASHTABLESIZE);
  434.     iphashtable = hash_Init(HASHTABLESIZE);
  435.     nmhashtable = hash_Init(HASHTABLESIZE);
  436.     if (!(hwhashtable && iphashtable && nmhashtable)) {
  437.     report(LOG_ERR, "Unable to allocate hash tables.\n");
  438.     exit(1);
  439.     }
  440.  
  441.  
  442.     /*
  443.      * Read the bootptab file once immediately upon startup.
  444.      */
  445.     readtab();
  446.  
  447.  
  448.     if (standalone) {
  449.     /*
  450.      * Create a socket.
  451.      */
  452.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  453.         report(LOG_ERR, "socket: %s\n", get_network_errmsg());
  454.         exit(1);
  455.     }
  456.  
  457.     /*
  458.      * Get server's listening port number
  459.      */
  460.     servp = getservbyname("bootps", "udp");
  461.     if (servp) {
  462.         bootps_port = ntohs((u_short) servp->s_port);
  463.     } else {
  464.         report(LOG_ERR,
  465.            "udp/bootps: unknown service -- assuming port %d\n",
  466.            IPPORT_BOOTPS);
  467.         bootps_port = (u_short) IPPORT_BOOTPS;
  468.     }
  469.  
  470.     /*
  471.      * Bind socket to BOOTPS port.
  472.      */
  473.     s_sin->sin_family = AF_INET;
  474.     s_sin->sin_addr.s_addr = INADDR_ANY;
  475.     s_sin->sin_port = htons(bootps_port);
  476.     if (bind(s, &server_addr, sizeof(*s_sin)) < 0) {
  477.         report(LOG_ERR, "bind: %s\n", get_network_errmsg());
  478.         exit(1);
  479.     }
  480.     }
  481.  
  482.  
  483.     /*
  484.      * Get destination port number so we can reply to client
  485.      */
  486.     servp = getservbyname("bootpc", "udp");
  487.     if (servp) {
  488.     bootpc_port = ntohs(servp->s_port);
  489.     } else {
  490.     report(LOG_ERR,
  491.            "udp/bootpc: unknown service -- assuming port %d\n",
  492.         IPPORT_BOOTPC);
  493.     bootpc_port = (u_short) IPPORT_BOOTPC;
  494.     }
  495.  
  496.  
  497.     /*
  498.      * Determine network configuration.
  499.      */
  500.     ifconf.ifc_len = sizeof(ifreq);
  501.     ifconf.ifc_req = ifreq;
  502.     if ((ioctl(s, SIOCGIFCONF, (caddr_t) &ifconf) < 0) ||
  503.     (ifconf.ifc_len <= 0)) {
  504.         report(LOG_ERR, "ioctl: %s\n", get_network_errmsg());
  505.         exit(1);
  506.     }
  507.  
  508.  
  509.     /*
  510.      * Set up signals to read or dump the table.
  511.      */
  512.     if ((int) signal(SIGHUP, readtab) < 0) {
  513.     report(LOG_ERR, "signal: %s\n", get_errmsg());
  514.     exit(1);
  515.     }
  516. #ifdef DEBUG
  517.     if ((int) signal(SIGUSR1, dumptab) < 0) {
  518.     report(LOG_ERR, "signal: %s\n", get_errmsg());
  519.     exit(1);
  520.     }
  521. #endif
  522.  
  523.     /*
  524.      * Process incoming requests.
  525.      */
  526.     for (;;) {
  527.     readfds = 1 << s;
  528.     nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
  529.     if (nfound < 0) {
  530.         if (errno != EINTR) {
  531.         report(LOG_ERR, "select: %s\n", get_errmsg());
  532.         }
  533.         continue;
  534.     }
  535.     if (!(readfds & (1 << s))) {
  536.         report(LOG_INFO, "exiting after %ld minutes of inactivity\n",
  537.            actualtimeout.tv_sec / 60);
  538.         exit(0);
  539.     }
  540.     ca_len = sizeof(client_addr);
  541.     n = recvfrom(s, pktbuf, MAXPKT, 0, &client_addr, &ca_len);
  542.     if (n <= 0) {
  543.         continue;
  544.     }
  545.  
  546.     if (n < sizeof(struct bootp)) {
  547.         if (debug) {
  548.         report(LOG_INFO, "received short packet\n");
  549.         }
  550.         continue;
  551.     }
  552.     pktlen = n;
  553.  
  554.     readtab();    /* maybe re-read bootptab */
  555.     switch (bp->bp_op) {
  556.     case BOOTREQUEST:
  557.         /* Handle a request by answering with a reply. */
  558.         answer_request();
  559.         break;
  560.  
  561.     case BOOTREPLY:
  562.         /* Handle a reply by forwarding it to the client. */
  563.         forward_reply();
  564.         break;
  565.     }
  566.     }
  567. }
  568.  
  569.  
  570.  
  571.  
  572. /*
  573.  * Print "usage" message and exit
  574.  */
  575.  
  576. void usage()
  577. {
  578.     fprintf(stderr,
  579. "usage:  bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
  580.     fprintf(stderr, "\t -d n\tset debug level\n");
  581.     fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n"); 
  582.     fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
  583.     fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
  584.     exit(1);
  585. }
  586.  
  587.  
  588.  
  589. /*
  590.  * Process BOOTREQUEST packet.
  591.  *
  592.  * (Note, this version of the bootpd.c server never forwards 
  593.  * the request to another server.  In our environment the 
  594.  * stand-alone gateways perform that function.)
  595.  *
  596.  * (Also this version does not interpret the hostname field of
  597.  * the request packet;  it COULD do a name->address lookup and
  598.  * forward the request there.)
  599.  */
  600. void
  601. answer_request()
  602. {
  603.     register struct bootp *bp = (struct bootp *) pktbuf;
  604.     register struct host *hp;
  605.     register int n;
  606.     char *path;
  607.     struct host dummyhost;
  608.     long bootsize;
  609.     unsigned hlen, hashcode;
  610.     char realpath[1024];
  611.  
  612.     bp->bp_op = BOOTREPLY;
  613.     if (bp->bp_ciaddr.s_addr == 0) { 
  614.     /*
  615.      * client doesnt know his IP address, 
  616.      * search by hardware address.
  617.      */
  618.     if (debug) {
  619.         report(LOG_INFO, "request from %s address %s\n",
  620.             netname(bp->bp_htype),
  621.             haddrtoa(bp->bp_chaddr, bp->bp_htype));
  622.     }
  623.  
  624.     dummyhost.htype = bp->bp_htype;
  625.     hlen = haddrlength(bp->bp_htype);
  626.     bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
  627.     hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
  628.     hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
  629.                      &dummyhost);
  630.     if (hp == NULL) {
  631.         /* XXX - Do we need more control over this noise? -gwr */
  632.         if (debug)
  633.         report(LOG_INFO, "unknown client %s address %s\n",
  634.                netname(bp->bp_htype),
  635.                haddrtoa(bp->bp_chaddr, bp->bp_htype));
  636.         return;    /* not found */
  637.     }
  638.     (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
  639.  
  640.     } else {
  641.  
  642.     /*
  643.      * search by IP address.
  644.      */
  645.     if (debug) {
  646.         report(LOG_INFO, "request from IP addr %s\n",
  647.             inet_ntoa(bp->bp_ciaddr));
  648.     }
  649.     dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
  650.     hashcode = hash_HashFunction((char *) &(bp->bp_ciaddr.s_addr), 4);
  651.     hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
  652.                      &dummyhost);
  653.     if (hp == NULL) {
  654.         report(LOG_NOTICE,
  655.             "IP address not found: %s\n", inet_ntoa(bp->bp_ciaddr));
  656.         return;
  657.     }
  658.     }
  659.  
  660.     if (debug) {
  661.     report(LOG_INFO, "found %s %s\n", inet_ntoa(hp->iaddr),
  662.         hp->hostname->string);
  663.     }
  664.  
  665.     /*
  666.      * If a specific TFTP server address was specified in the bootptab file,
  667.      * fill it in, otherwise zero it.
  668.      */
  669.     (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
  670.     hp->bootserver.s_addr : 0L;
  671.  
  672.     /*
  673.      * This next line is a bit of a mystery.  It seems to be vestigial
  674.      * code (from Stanford???) which should probably be axed.
  675.      */
  676.     if (strcmp(bp->bp_file, "sunboot14") == 0)
  677.     bp->bp_file[0] = 0;    /* pretend it's null */
  678.  
  679.  
  680.     /*
  681.      * Fill in the client's proper bootfile.
  682.      *
  683.      * If the client specifies an absolute path, try that file with a
  684.      * ".host" suffix and then without.  If the file cannot be found, no
  685.      * reply is made at all.
  686.      *
  687.      * [ I think this policy is too complicated.  Why not just send the
  688.      *   reply if we know how, whether or not the file exists? -gwr ]
  689.      *
  690.      * If the client specifies a null or relative file, use the following
  691.      * table to determine the appropriate action:
  692.      *
  693.      *  Homedir      Bootfile    Client's file
  694.      * specified?   specified?   specification   Action
  695.      * -------------------------------------------------------------------
  696.      *      No          No          Null         Send null filename
  697.      *      No          No          Relative     Discard request
  698.      *      No          Yes         Null         Send if absolute else null
  699.      *      No          Yes         Relative     Discard request
  700.      *      Yes         No          Null         Send null filename
  701.      *      Yes         No          Relative     Lookup with ".host"
  702.      *      Yes         Yes         Null         Send home/boot or bootfile
  703.      *      Yes         Yes         Relative     Lookup with ".host"
  704.      *
  705.      */
  706.  
  707.     if (hp->flags.tftpdir) {
  708.     strcpy(realpath, hp->tftpdir->string);
  709.     path = &realpath[strlen(realpath)];
  710.     } else {
  711.     path = realpath;
  712.     }
  713.  
  714.     if (bp->bp_file[0]) {
  715.     /*
  716.      * The client specified a file.
  717.      */
  718.     if (bp->bp_file[0] == '/') {
  719.         strcpy(path, bp->bp_file);        /* Absolute pathname */
  720.     } else {
  721.         if (hp->flags.homedir) {
  722.         strcpy(path, hp->homedir->string);
  723.         strcat(path, "/");
  724.         strcat(path, bp->bp_file);
  725.         } else {
  726.         report(LOG_NOTICE,
  727.             "requested file \"%s\" not found: hd unspecified\n",
  728.             bp->bp_file);
  729.         return;
  730.         }
  731.     }
  732.     } else {
  733.     /*
  734.      * No file specified by the client.
  735.      */
  736.     if (hp->flags.bootfile && ((hp->bootfile->string)[0] == '/')) {
  737.         strcpy(path, hp->bootfile->string);
  738.     } else if (hp->flags.homedir && hp->flags.bootfile) {
  739.         strcpy(path, hp->homedir->string);
  740.         strcat(path, "/");
  741.         strcat(path, hp->bootfile->string);
  742.     } else {
  743.         bzero(bp->bp_file, sizeof(bp->bp_file));
  744.         goto skip_file;    /* Don't bother trying to access the file */
  745.     }
  746.     }
  747.  
  748.     /*
  749.      * First try to find the file with a ".host" suffix
  750.      */
  751.     n = strlen(path);
  752.     strcat(path, ".");
  753.     strcat(path, hp->hostname->string);
  754.     if (chk_access(realpath, &bootsize) < 0) {
  755.     path[n] = 0;            /* Try it without the suffix */
  756.     if (chk_access(realpath, &bootsize) < 0) {
  757.         if (bp->bp_file[0]) {
  758.         /*
  759.          * Client wanted specific file
  760.          * and we didn't have it.
  761.          */
  762.         report(LOG_NOTICE,
  763.             "requested file not found: \"%s\"\n", path);
  764.         return;
  765.         } else {
  766.         /*
  767.          * Client didn't ask for a specific file and we couldn't
  768.          * access the default file, so just zero-out the bootfile
  769.          * field in the packet and continue processing the reply.
  770.          */
  771.         bzero(bp->bp_file, sizeof(bp->bp_file));
  772.         goto skip_file;
  773.         }
  774.     }
  775.     }
  776.     strcpy(bp->bp_file, path);
  777.  
  778. skip_file:  ;
  779.  
  780.  
  781.  
  782.     if (debug > 1) {
  783.     report(LOG_INFO, "vendor magic field is %d.%d.%d.%d\n",
  784.         (int) ((bp->bp_vend)[0]),
  785.         (int) ((bp->bp_vend)[1]),
  786.         (int) ((bp->bp_vend)[2]),
  787.         (int) ((bp->bp_vend)[3]));
  788.     }
  789.  
  790.     /*
  791.      * If this host isn't set for automatic vendor info then copy the
  792.      * specific cookie into the bootp packet, thus forcing a certain
  793.      * reply format.
  794.      */
  795.     if (!hp->flags.vm_auto) {
  796.         /*
  797.          * If the client supplies a vendor magic number,
  798.          * bootp probably should not change it...
  799.          */
  800.         if (debug > 1 && bcmp(bp->bp_vend, vm_zero, 4)) {
  801.             report(LOG_INFO, "vendor magic field forced\n");
  802.         }
  803.         bcopy(hp->vm_cookie, bp->bp_vend, 4);
  804.     }
  805.  
  806.     /*
  807.      * Figure out the format for the vendor-specific info.
  808.      */
  809.     if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
  810.         /* RFC1048 conformant bootp client */
  811.         dovend_rfc1048(bp, hp, bootsize);
  812.         if (debug > 1) {
  813.             report(LOG_INFO, "sending reply (with RFC1048 options)\n");
  814.         }
  815.     }
  816. #ifdef VEND_CMU
  817.     else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
  818.         dovend_cmu(bp, hp);
  819.         if (debug > 1) {
  820.             report(LOG_INFO, "sending reply (with CMU options)\n");
  821.         }
  822.     }
  823. #endif
  824.     else if (!bcmp(bp->bp_vend, vm_zero, 4)) {
  825.         if (debug > 1) {
  826.             report(LOG_INFO, "sending reply (no options)\n");
  827.         }
  828.     }
  829.     else {
  830.         if (debug > 1) {
  831.             report(LOG_INFO, "sending reply (unknown options)\n");
  832.         }
  833.     }
  834.  
  835.     sendreply(0);
  836. }
  837.  
  838.  
  839.  
  840. /*
  841.  * Process BOOTREPLY packet (something is using us as a gateway).
  842.  */
  843.  
  844. void
  845. forward_reply()
  846. {
  847.     if (debug) {
  848.         report(LOG_INFO, "processing boot reply\n");
  849.     }
  850.     sendreply(1);
  851. }
  852.  
  853.  
  854.  
  855. /*
  856.  * Send a reply packet to the client.  'forward' flag is set if we are
  857.  * not the originator of this reply packet.
  858.  */
  859. sendreply(forward)
  860.     int forward;
  861. {
  862.     register struct bootp *bp = (struct bootp *) pktbuf;
  863.     struct in_addr dst;    /* XXX */
  864.     struct sockaddr_in *c_sin;
  865.  
  866.     c_sin = (struct sockaddr_in *) &client_addr;
  867.  
  868.     c_sin->sin_port = htons(bootpc_port);
  869.     /*
  870.      * If the client IP address is specified, use that
  871.      * else if gateway IP address is specified, use that
  872.      * else make a temporary arp cache entry for the client's NEW 
  873.      * IP/hardware address and use that.
  874.      */
  875.     if (bp->bp_ciaddr.s_addr) {
  876.         dst = bp->bp_ciaddr;
  877.     } else if (bp->bp_giaddr.s_addr && forward == 0) {
  878.         dst = bp->bp_giaddr;
  879.         c_sin->sin_port = htons(bootps_port);
  880.     } else {
  881.         dst = bp->bp_yiaddr;
  882.         setarp(&dst, bp->bp_chaddr, bp->bp_hlen);
  883.     }
  884.  
  885.     if (forward == 0) {
  886.         /*
  887.          * If we are originating this reply, we
  888.          * need to find our own interface address to
  889.          * put in the bp_siaddr field of the reply.
  890.          * If this server is multi-homed, pick the
  891.          * 'best' interface (the one on the same net
  892.          * as the client).
  893.          */
  894.         int maxmatch = 0;
  895.         int len, m;
  896.         register struct ifreq *ifrq, *ifrmax;
  897.  
  898.         ifrmax = ifrq = &ifreq[0];
  899.         len = ifconf.ifc_len;
  900.         for (; len > 0; len -= sizeof(ifreq[0]), ifrq++) {
  901.             m = nmatch(&dst, &((struct sockaddr_in *)
  902.                       (&ifrq->ifr_addr))->sin_addr);
  903.             if (m > maxmatch) {
  904.                 maxmatch = m;
  905.                 ifrmax = ifrq;
  906.             }
  907.         }
  908.  
  909.         /* XXX - Should put anything here?  :gw=: ? */
  910.         if (bp->bp_giaddr.s_addr == 0) {
  911.             if (maxmatch == 0) {
  912.                 return;
  913.             }
  914.             bp->bp_giaddr = ((struct sockaddr_in *)
  915.                 (&ifrmax->ifr_addr))->sin_addr;
  916.         }
  917.  
  918.         /*
  919.          * If a specific TFTP server address wasn't specified
  920.          * in the bootptab file, fill in our own address.
  921.          */
  922.         if (bp->bp_siaddr.s_addr == 0) {
  923.             bp->bp_siaddr = ((struct sockaddr_in *)
  924.                      (&ifrmax->ifr_addr))->sin_addr;
  925.         }
  926.     }
  927.  
  928.     c_sin->sin_addr = dst; 
  929.     /* Send reply with same size packet as request used. */
  930.     if (sendto(s, pktbuf, pktlen, 0,
  931.            &client_addr, sizeof(*c_sin)) < 0) {
  932.         report(LOG_ERR, "sendto: %s\n", get_network_errmsg());
  933.     }
  934. } /* sendreply */
  935.  
  936.  
  937.  
  938. /*
  939.  * Return the number of leading bytes matching in the
  940.  * internet addresses supplied.
  941.  */
  942. nmatch(ca,cb)
  943.     register char *ca, *cb;
  944. {
  945.     register n,m;
  946.  
  947.     for (m = n = 0 ; n < 4 ; n++) {
  948.     if (*ca++ != *cb++)
  949.         return(m);
  950.     m++;
  951.     }
  952.     return(m);
  953. }
  954.  
  955.  
  956.  
  957. /*
  958.  * Setup the arp cache so that IP address 'ia' will be temporarily
  959.  * bound to hardware address 'ha' of length 'len'.
  960.  */
  961. setarp(ia, ha, len)
  962.     struct in_addr *ia;
  963.     byte *ha;
  964.     int len;
  965. {
  966.     struct sockaddr_in *si;
  967.     
  968.     bzero((caddr_t)&arpreq, sizeof(arpreq));
  969.     
  970.     arpreq.arp_pa.sa_family = AF_INET;
  971.     si = (struct sockaddr_in *) &arpreq.arp_pa;
  972.     si->sin_addr = *ia;
  973.  
  974.     arpreq.arp_flags = ATF_INUSE | ATF_COM;
  975.     
  976.     bcopy(ha, arpreq.arp_ha.sa_data, len);
  977.  
  978.     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
  979.         report(LOG_ERR, "ioctl(SIOCSARP): %s\n", get_network_errmsg());
  980.     }
  981. }
  982.  
  983.  
  984.  
  985. /*
  986.  * This call checks read access to a file.  It returns 0 if the file given
  987.  * by "path" exists and is publically readable.  A value of -1 is returned if
  988.  * access is not permitted or an error occurs.  Successful calls also
  989.  * return the file size in bytes using the long pointer "filesize".
  990.  *
  991.  * The read permission bit for "other" users is checked.  This bit must be
  992.  * set for tftpd(8) to allow clients to read the file.
  993.  */
  994.  
  995. int chk_access(path, filesize)
  996. char *path;
  997. long *filesize;
  998. {
  999.     struct stat st;
  1000.  
  1001.     if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
  1002.     *filesize = (long) st.st_size;
  1003.     return 0;
  1004.     } else {
  1005.     return -1;
  1006.     }
  1007. }
  1008.  
  1009.  
  1010.  
  1011. #ifdef DEBUG
  1012.  
  1013. /*
  1014.  * Dump the internal memory database to bootpd_dump.
  1015.  */
  1016.  
  1017. void dumptab()
  1018. {
  1019.     register int n;
  1020.     register struct host *hp;
  1021.     register FILE *fp;
  1022.     long t;
  1023.  
  1024.     /*
  1025.      * Open bootpd.dump file.
  1026.      */
  1027.     if ((fp = fopen(bootpd_dump, "w")) == NULL) {
  1028.     report(LOG_ERR, "error opening \"%s\": %s\n", bootpd_dump,
  1029.             get_errmsg());
  1030.     exit(1);
  1031.     }
  1032.  
  1033.     t = time(NULL);
  1034.     fprintf(fp, "\n# %s\n", Version);
  1035.     fprintf(fp, "# %s: dump of bootp server database.\n", bootpd_dump);
  1036.     fprintf(fp, "#\n# Dump taken %s", ctime(&t));
  1037.     fprintf(fp, "#\n#\n# Legend:\n");
  1038.     fprintf(fp, "#\thd -- home directory\n");
  1039.     fprintf(fp, "#\tbf -- bootfile\n");
  1040.     fprintf(fp, "#\tbs -- bootfile size in 512-octet blocks\n");
  1041.     fprintf(fp, "#\tcs -- cookie servers\n");
  1042.     fprintf(fp, "#\tds -- domain name servers\n");
  1043.     fprintf(fp, "#\tgw -- gateways\n");
  1044.     fprintf(fp, "#\tha -- hardware address\n");
  1045.     fprintf(fp, "#\thd -- home directory for bootfiles\n");
  1046.     fprintf(fp, "#\tht -- hardware type\n");
  1047.     fprintf(fp, "#\tim -- impress servers\n");
  1048.     fprintf(fp, "#\tip -- host IP address\n");
  1049.     fprintf(fp, "#\tlg -- log servers\n");
  1050.     fprintf(fp, "#\tlp -- LPR servers\n");
  1051.     fprintf(fp, "#\tns -- IEN-116 name servers\n");
  1052.     fprintf(fp, "#\trl -- resource location protocol servers\n");
  1053.     fprintf(fp, "#\tsm -- subnet mask\n");
  1054.     fprintf(fp, "#\tto -- time offset (seconds)\n");
  1055.     fprintf(fp, "#\tts -- time servers\n\n\n");
  1056.  
  1057.     n = 0;
  1058.     for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
  1059.      hp = (struct host *) hash_NextEntry(nmhashtable)) {
  1060.         dump_host(fp, hp);
  1061.         fprintf(fp, "\n");
  1062.         n++;
  1063.     }
  1064.     fclose(fp);
  1065.  
  1066.     report(LOG_INFO, "dumped %d entries to \"%s\".\n", n, bootpd_dump);
  1067. }
  1068.  
  1069.  
  1070.  
  1071. /*
  1072.  * Dump all the available information on the host pointed to by "hp".
  1073.  * The output is sent to the file pointed to by "fp".
  1074.  */
  1075.  
  1076. void dump_host(fp, hp)
  1077. FILE *fp;
  1078. struct host *hp;
  1079. {
  1080.     register int i;
  1081.     register byte *dataptr;
  1082.  
  1083.     if (hp) {
  1084.     if (hp->hostname) {
  1085.         fprintf(fp, "%s:", hp->hostname->string);
  1086.     }
  1087.     if (hp->flags.bootfile) {
  1088.         fprintf(fp, "bf=%s:", hp->bootfile->string);
  1089.     }
  1090.     if (hp->flags.bootsize) {
  1091.         fprintf(fp, "bs=");
  1092.         if (hp->flags.bootsize_auto) {
  1093.         fprintf(fp, "auto:");
  1094.         } else {
  1095.         fprintf(fp, "%d:", hp->bootsize);
  1096.         }
  1097.     }
  1098.     if (hp->flags.cookie_server) {
  1099.         fprintf(fp, "cs=");
  1100.         list_ipaddresses(fp, hp->cookie_server);
  1101.         fprintf(fp, ":");
  1102.     }
  1103.     if (hp->flags.domain_server) {
  1104.         fprintf(fp, "ds=");
  1105.         list_ipaddresses(fp, hp->domain_server);
  1106.         fprintf(fp, ":");
  1107.     }
  1108.     if (hp->flags.gateway) {
  1109.         fprintf(fp, "gw=");
  1110.         list_ipaddresses(fp, hp->gateway);
  1111.         fprintf(fp, ":");
  1112.     }
  1113.     if (hp->flags.homedir) {
  1114.         fprintf(fp, "hd=%s:", hp->homedir->string);
  1115.     }
  1116.     if (hp->flags.name_switch && hp->flags.send_name) {
  1117.         fprintf(fp, "hn:");
  1118.     }
  1119.     if (hp->flags.htype) {
  1120.         fprintf(fp, "ht=%u:", (unsigned) hp->htype);
  1121.         if (hp->flags.haddr) {
  1122.         fprintf(fp, "ha=%s:", haddrtoa(hp->haddr, hp->htype));
  1123.         }
  1124.     }
  1125.     if (hp->flags.impress_server) {
  1126.         fprintf(fp, "im=");
  1127.         list_ipaddresses(fp, hp->impress_server);
  1128.         fprintf(fp, ":");
  1129.     }
  1130.     if (hp->flags.iaddr) {
  1131.         fprintf(fp, "ip=%s:", inet_ntoa(hp->iaddr));
  1132.     }
  1133.     if (hp->flags.log_server) {
  1134.         fprintf(fp, "lg=");
  1135.         list_ipaddresses(fp, hp->log_server);
  1136.         fprintf(fp, ":");
  1137.     }
  1138.     if (hp->flags.lpr_server) {
  1139.         fprintf(fp, "lp=");
  1140.         list_ipaddresses(fp, hp->lpr_server);
  1141.         fprintf(fp, ":");
  1142.     }
  1143.     if (hp->flags.name_server) {
  1144.         fprintf(fp, "ns=");
  1145.         list_ipaddresses(fp, hp->name_server);
  1146.         fprintf(fp, ":");
  1147.     }
  1148.     if (hp->flags.rlp_server) {
  1149.         fprintf(fp, "rl=");
  1150.         list_ipaddresses(fp, hp->rlp_server);
  1151.         fprintf(fp, ":");
  1152.     }
  1153.     if (hp->flags.bootserver) {
  1154.         fprintf(fp, "sa=%s:", inet_ntoa(hp->bootserver));
  1155.     }
  1156.     if (hp->flags.subnet_mask) {
  1157.         fprintf(fp, "sm=%s:", inet_ntoa(hp->subnet_mask));
  1158.     }
  1159.     if (hp->flags.tftpdir) {
  1160.         fprintf(fp, "td=%s:", hp->tftpdir->string);
  1161.     }
  1162.     if (hp->flags.time_offset) {
  1163.         if (hp->flags.timeoff_auto) {
  1164.         fprintf(fp, "to=auto:");
  1165.         } else {
  1166.         fprintf(fp, "to=%ld:", hp->time_offset);
  1167.         }
  1168.     }
  1169.     if (hp->flags.time_server) {
  1170.         fprintf(fp, "ts=");
  1171.         list_ipaddresses(fp, hp->time_server);
  1172.         fprintf(fp, ":");
  1173.     }
  1174.     if (hp->flags.vendor_magic) {
  1175.         fprintf(fp, "vm=");
  1176.         if (hp->flags.vm_auto) {
  1177.         fprintf(fp, "auto:");
  1178.         } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
  1179.         fprintf(fp, "cmu:");
  1180.         } else if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
  1181.         fprintf(fp, "rfc1048");
  1182.         } else {
  1183.         fprintf(fp, "%d.%d.%d.%d:",
  1184.                 (int) ((hp->vm_cookie)[0]),
  1185.                 (int) ((hp->vm_cookie)[1]),
  1186.                 (int) ((hp->vm_cookie)[2]),
  1187.                 (int) ((hp->vm_cookie)[3]));
  1188.         }
  1189.     }
  1190.     if (hp->flags.generic) {
  1191.         fprintf(fp, "generic=");
  1192.         dataptr = hp->generic->data;
  1193.         for (i = hp->generic->length; i > 0; i--) {
  1194.         fprintf(fp, "%02X", (int) *dataptr++);
  1195.         }
  1196.         fprintf(fp, ":");
  1197.     }
  1198.     }
  1199. }
  1200.  
  1201.  
  1202.  
  1203. /*
  1204.  * Dump an entire struct in_addr_list of IP addresses to the indicated file.
  1205.  *
  1206.  * The addresses are printed in standard ASCII "dot" notation and separated
  1207.  * from one another by a single space.  A single leading space is also
  1208.  * printed before the first adddress.
  1209.  *
  1210.  * Null lists produce no output (and no error).
  1211.  */
  1212.  
  1213. void list_ipaddresses(fp, ipptr)
  1214.     FILE *fp;
  1215.     struct in_addr_list *ipptr;
  1216. {
  1217.     register unsigned count;
  1218.     register struct in_addr *addrptr;
  1219.  
  1220.     if (ipptr) {
  1221.     count = ipptr->addrcount;
  1222.     addrptr = ipptr->addr;
  1223.     if (count-- > 0) {
  1224.         fprintf(fp, "%s", inet_ntoa(*addrptr++));
  1225.         while (count-- > 0) {
  1226.         fprintf(fp, " %s", inet_ntoa(*addrptr++));
  1227.         }
  1228.     }
  1229.     }
  1230. }
  1231. #endif        /* DEBUG */
  1232.  
  1233.  
  1234.  
  1235. #ifdef VEND_CMU
  1236.  
  1237. /*
  1238.  * Insert the CMU "vendor" data for the host pointed to by "hp" into the
  1239.  * bootp packet pointed to by "bp".
  1240.  */
  1241.  
  1242. void dovend_cmu(bp, hp)
  1243.     register struct bootp *bp;
  1244.     register struct host *hp;
  1245. {
  1246.     struct cmu_vend *vendp;
  1247.     register struct in_addr_list *taddr;
  1248.  
  1249.     /*
  1250.      * Initialize the entire vendor field to zeroes.
  1251.      */
  1252.     bzero(bp->bp_vend, sizeof(bp->bp_vend));
  1253.  
  1254.     /*
  1255.      * Fill in vendor information. Subnet mask, default gateway,
  1256.      * domain name server, ien name server, time server
  1257.      */
  1258.     vendp = (struct cmu_vend *) bp->bp_vend;
  1259.     if (hp->flags.subnet_mask) {
  1260.     (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
  1261.     (vendp->v_flags) |= VF_SMASK;
  1262.     if (hp->flags.gateway) {
  1263.         (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
  1264.     }
  1265.     }
  1266.     if (hp->flags.domain_server) {
  1267.     taddr = hp->domain_server;
  1268.     if (taddr->addrcount > 0) {
  1269.         (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
  1270.         if (taddr->addrcount > 1) {
  1271.         (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
  1272.         }
  1273.     }
  1274.     }
  1275.     if (hp->flags.name_server) {
  1276.     taddr = hp->name_server;
  1277.     if (taddr->addrcount > 0) {
  1278.         (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
  1279.         if (taddr->addrcount > 1) {
  1280.         (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
  1281.         }
  1282.     }
  1283.     }
  1284.     if (hp->flags.time_server) {
  1285.     taddr = hp->time_server;
  1286.     if (taddr->addrcount > 0) {
  1287.         (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
  1288.         if (taddr->addrcount > 1) {
  1289.         (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
  1290.         }
  1291.     }
  1292.     }
  1293.     strcpy(vendp->v_magic, vm_cmu);    
  1294.  
  1295. } /* dovend_cmu */
  1296.  
  1297. #endif /* VEND_CMU */
  1298.  
  1299.  
  1300.  
  1301. /*
  1302.  * Fill in the RFC1048 options.  All tag and length bytes provided
  1303.  * by the client must be left where they are.  Data associated with
  1304.  * each option are updated if we have a value for the option.
  1305.  *
  1306.  * This implementation does not change any tag or length bytes.
  1307.  *
  1308.  * One could append additional options when there is room after the
  1309.  * end record but this implementation does not do so.  One would need
  1310.  * a way to know which options should be "forced" into the list.
  1311.  */
  1312. void dovend_rfc1048(bp, hp, bootsize)
  1313.     register struct bootp *bp;
  1314.     register struct host *hp;
  1315.     long bootsize;        /* "auto" value, from stat() */
  1316. {
  1317.     int i, n, len;
  1318.     byte *vp, *ep;
  1319.     byte tag;
  1320.     char *tmpstr;
  1321.     unsigned long ul;
  1322.     unsigned short us;
  1323.     
  1324.     /*
  1325.      * Compute pointers to beginning and end of option area.
  1326.      * Note that options (formerly "vendor data") are now
  1327.      * allowed to extend to the end of the packet, and are
  1328.      * not limited to a maximum of BP_VEND_LEN bytes.
  1329.      * That value is the MINIMUM size of the option area.
  1330.      * (See the IETF draft: Clarifications and Extensions
  1331.      * for the Bootstrap Protocol, W. Wimer, Sept. 1992.)
  1332.      */
  1333.     vp = bp->bp_vend;
  1334.     ep = ((char *)bp) + pktlen;
  1335.     
  1336.     /* Step over the magic cookie (checked by caller). */
  1337.     vp += 4;
  1338.     
  1339.     while (vp < ep) {
  1340.     tag = *vp++;
  1341.     
  1342.     /* Check for tags with no data first. */
  1343.     if (tag == TAG_PAD)
  1344.         continue;
  1345.     if (tag == TAG_END)
  1346.         return;
  1347.     
  1348.     /* Now scan the length byte. */
  1349.     len = *vp++;
  1350.     
  1351.     if (vp + len >= ep) {
  1352.         report(LOG_ERR, "truncated field in vendor data\n");
  1353.         /* do the best we can... */
  1354.         len = ep - vp;
  1355.     }
  1356.     
  1357.     switch (tag) {
  1358.         
  1359.     case TAG_SUBNET_MASK: /* may demand len==4 */
  1360.         if (len >= 4) {
  1361.         ul = hp->subnet_mask.s_addr;
  1362.         bcopy((char*)&ul, vp, 4);
  1363.         }
  1364.         break;
  1365.         
  1366.     case TAG_TIME_OFFSET: /* may demand len==4 */
  1367.         if (len >= 4) {
  1368.         ul = (hp->flags.timeoff_auto) ?
  1369.             secondswest : hp->time_offset;
  1370.         ul = htonl(ul);
  1371.         bcopy((char*)&ul, vp, 4);
  1372.         }
  1373.         break;
  1374.         
  1375.     case TAG_GATEWAY:
  1376.         if (hp->flags.gateway)
  1377.         insert_ip(hp->gateway, vp, len);
  1378.         break;
  1379.         
  1380.     case TAG_TIME_SERVER:
  1381.         if (hp->flags.time_server)
  1382.         insert_ip(hp->time_server, vp, len);
  1383.         break;
  1384.         
  1385.     case TAG_NAME_SERVER:
  1386.         if (hp->flags.name_server)
  1387.         insert_ip(hp->name_server, vp, len);
  1388.         break;
  1389.         
  1390.     case TAG_DOMAIN_SERVER:
  1391.         if (hp->flags.domain_server)
  1392.         insert_ip(hp->domain_server, vp, len);
  1393.         break;
  1394.         
  1395.     case TAG_LOG_SERVER:
  1396.         if (hp->flags.log_server)
  1397.         insert_ip(hp->log_server, vp, len);
  1398.         break;
  1399.         
  1400.     case TAG_COOKIE_SERVER:
  1401.         if (hp->flags.cookie_server)
  1402.         insert_ip(hp->cookie_server, vp, len);
  1403.         break;
  1404.         
  1405.     case TAG_LPR_SERVER:
  1406.         if (hp->flags.lpr_server)
  1407.         insert_ip(hp->lpr_server, vp, len);
  1408.         break;
  1409.         
  1410.     case TAG_IMPRESS_SERVER:
  1411.         if (hp->flags.impress_server)
  1412.         insert_ip(hp->impress_server, vp, len);
  1413.         break;
  1414.         
  1415.     case TAG_RLP_SERVER:
  1416.         if (hp->flags.rlp_server)
  1417.         insert_ip(hp->rlp_server, vp, len);
  1418.         break;
  1419.         
  1420.     case TAG_HOSTNAME: /* of client */
  1421.         if (hp->flags.name_switch &&
  1422.         hp->flags.send_name) {
  1423.         
  1424.         /* Room for the whole name? */
  1425.         n = strlen(hp->hostname->string);
  1426.         if (n < len) {
  1427.             bcopy(hp->hostname->string, vp, n);
  1428.         } else {
  1429.             /*
  1430.              * Not enough room for fully qualified hostname,
  1431.              * try stripping off the domain parts.
  1432.              */
  1433.             if (debug > 1)
  1434.             report(LOG_INFO, "shortening hostname to fit\n");
  1435.             tmpstr = index(hp->hostname->string, '.');
  1436.             if (tmpstr) {
  1437.             n = tmpstr - hp->hostname->string;
  1438.             bcopy(hp->hostname->string, vp, n);
  1439.             }
  1440.         }
  1441.         }
  1442.         break;
  1443.         
  1444.     case TAG_BOOTSIZE:
  1445.         if (len >= 2) {
  1446.         if (hp->flags.bootsize_auto)
  1447.             us = (bootsize + 511) / 512;    /* Round up */
  1448.         else us = hp->bootsize;
  1449.         bcopy((char*)&us, vp, 2);
  1450.         }
  1451.         break;
  1452.         
  1453.     default:
  1454.         if (hp->flags.generic)
  1455.         insert_generic(tag, hp->generic, vp, len);
  1456.         break;
  1457.         
  1458.     } /* switch (tag) */
  1459.     vp += len;
  1460.     } /* while */
  1461.     return;
  1462. } /* dovend_rfc1048 */
  1463.  
  1464.  
  1465.  
  1466. /*
  1467.  * Compare function to determine whether two hardware addresses are
  1468.  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
  1469.  * otherwise.
  1470.  *
  1471.  * This function is used when retrieving elements from the hardware address
  1472.  * hash table.
  1473.  */
  1474.  
  1475. boolean hwlookcmp(host1, host2)
  1476.     struct host *host1, *host2;
  1477. {
  1478.     if (host1->htype != host2->htype) {
  1479.     return FALSE;
  1480.     }
  1481.     if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
  1482.     return FALSE;
  1483.     }
  1484.     return TRUE;
  1485. }
  1486.  
  1487.  
  1488.  
  1489.  
  1490. /*
  1491.  * Compare function for doing IP address hash table lookup.
  1492.  */
  1493.  
  1494. boolean iplookcmp(host1, host2)
  1495.     struct host *host1, *host2;
  1496. {
  1497.     return (host1->iaddr.s_addr == host2->iaddr.s_addr);
  1498. }
  1499.  
  1500.  
  1501.  
  1502. /*
  1503.  * Copy a list of IP addresses to the memory buffer "dest".
  1504.  * The "iplist" is a pointer to a list of IP addresses
  1505.  * (struct in_addr_list), and "len" points to an integer which
  1506.  * indicates the size of the "dest" buffer.
  1507.  *
  1508.  * This is used to fill the vendor-specific area of a bootp packet in
  1509.  * conformance to RFC1048.
  1510.  */
  1511.  
  1512. void insert_ip(iplist, dest, len)
  1513.     struct in_addr_list *iplist;
  1514.     byte *dest;
  1515.     int len;    /* space for this list */
  1516. {
  1517.     register struct in_addr *addrptr;
  1518.     register unsigned addrcount;
  1519.  
  1520.     if (!iplist) return;
  1521.  
  1522.     addrptr = iplist->addr;
  1523.     addrcount = iplist->addrcount;
  1524.     while ((len >= 4) && (addrcount > 0)) {
  1525.         bcopy(addrptr, dest, 4);
  1526.         addrptr++;
  1527.         addrcount--;
  1528.         dest += 4;
  1529.         len -= 4;
  1530.     }
  1531. }
  1532.  
  1533.  
  1534.  
  1535. /*
  1536.  * Find an RFC1048 record of type "tag" and copy it to "dest".
  1537.  * The data in "gendata" is assumed to already in RFC1048 format.
  1538.  */
  1539.  
  1540. void insert_generic(tag, gendata, dest, destlen)
  1541.     int tag;
  1542.     struct shared_bindata *gendata;
  1543.     byte *dest;
  1544.     int destlen;
  1545. {
  1546.     byte *srcptr, *ep;
  1547.     register int t, n;
  1548.  
  1549.     if (!gendata) return;
  1550.  
  1551.     srcptr = gendata->data;
  1552.     ep = srcptr + gendata->length;
  1553.  
  1554.     /* Search the generic records for a tag of the desired type. */
  1555.     while (srcptr < ep) {
  1556.         t = *srcptr++;
  1557.         n = *srcptr++;
  1558.  
  1559.         if (t == tag) {
  1560.             /* Copy whatever fits. */
  1561.             if (n > destlen)
  1562.                 n = destlen;
  1563.             bcopy(srcptr, dest, n);
  1564.             return;
  1565.         }
  1566.         srcptr += n;
  1567.     }
  1568. }
  1569.  
  1570.  
  1571.  
  1572.  
  1573. /*
  1574.  * Convert a hardware address to an ASCII string.
  1575.  */
  1576.  
  1577. char *haddrtoa(haddr, htype)
  1578.     register byte *haddr;
  1579.     byte htype;
  1580. {
  1581.     static char haddrbuf[2 * MAXHADDRLEN + 1];
  1582.     register char *bufptr;
  1583.     register unsigned count;
  1584.  
  1585.     bufptr = haddrbuf;
  1586.     for (count = haddrlength(htype); count > 0; count--) {
  1587.     sprintf(bufptr, "%02X",    (unsigned) (*haddr++ & 0xFF));
  1588.     bufptr += 2;
  1589.     }
  1590.     return (haddrbuf);
  1591. }
  1592.  
  1593.  
  1594.  
  1595. /*
  1596.  * Return pointer to static string which gives full filesystem error message.
  1597.  */
  1598.  
  1599. char *get_errmsg()
  1600. {
  1601.     static char errmsg[80];
  1602.  
  1603.     if (errno < sys_nerr) {
  1604.     return sys_errlist[errno];
  1605.     } else {
  1606.     sprintf(errmsg, "Error %d", errno);
  1607.     return errmsg;
  1608.     }
  1609. }
  1610.  
  1611.  
  1612.  
  1613. /*
  1614.  * This routine reports errors and such via stderr and syslog() if
  1615.  * appopriate.  It just helps avoid a lot of "#ifdef SYSLOG" constructs
  1616.  * from being scattered throughout the code.
  1617.  *
  1618.  * The syntax is identical to syslog(3), but %m is not considered special
  1619.  * for output to stderr (i.e. you'll see "%m" in the output. . .).  Also,
  1620.  * control strings should normally end with \n since newlines aren't
  1621.  * automatically generated for stderr output (whereas syslog strips out all
  1622.  * newlines and adds its own at the end).
  1623.  */
  1624.  
  1625. /*VARARGS2*/
  1626. void report(priority, fmt, p0, p1, p2, p3, p4)
  1627.     int priority;
  1628.     char *fmt;
  1629. {
  1630. #ifdef LOG_SALERT
  1631.     static char *levelnames[] = {
  1632.     "unknown level: ",
  1633.     "alert(1):      ",
  1634.     "subalert(2):   ",
  1635.     "emergency(3):  ",
  1636.     "error(4):      ",
  1637.     "critical(5):   ",
  1638.     "warning(6):    ",
  1639.     "notice(7):     ",
  1640.     "information(8):",
  1641.     "debug(9):      ",
  1642.     "unknown level: "
  1643.     };
  1644. #else
  1645.     static char *levelnames[] = {
  1646.     "emergency(0):  ",
  1647.     "alert(1):      ",
  1648.     "critical(2):   ",
  1649.     "error(3):      ",
  1650.     "warning(4):    ",
  1651.     "notice(5):     ",
  1652.     "information(6):",
  1653.     "debug(7):      ",
  1654.     "unknown level: "
  1655.     };
  1656. #endif
  1657.  
  1658.     if ((priority < 0) || (priority >= sizeof(levelnames)/sizeof(char *))) {
  1659.     priority = sizeof(levelnames) / sizeof(char *) - 1;
  1660.     }
  1661.  
  1662.     /*
  1663.      * Print the message
  1664.      */
  1665.     if (debug > 2) {
  1666.     fprintf(stderr, "bootpd: %s ", levelnames[priority]);
  1667.     fprintf(stderr, fmt, p0, p1, p2, p3, p4);
  1668.     }
  1669. #ifdef SYSLOG
  1670.     syslog(priority, fmt, p0, p1, p2, p3, p4);
  1671. #endif
  1672. }
  1673.