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