home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / bootpd-2.zip / BOOTPD.C < prev    next >
C/C++ Source or Header  |  1995-09-04  |  41KB  |  1,666 lines

  1. /************************************************************************
  2.           Copyright 1988, 1991 by Carnegie Mellon University
  3.  
  4.                           All Rights Reserved
  5.  
  6. Permission to use, copy, modify, and distribute this software and its
  7. documentation for any purpose and without fee is hereby granted, provided
  8. that the above copyright notice appear in all copies and that both that
  9. copyright notice and this permission notice appear in supporting
  10. documentation, and that the name of Carnegie Mellon University not be used
  11. in advertising or publicity pertaining to distribution of the software
  12. without specific, written prior permission.
  13.  
  14. CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  15. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16. IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  17. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  18. PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  19. ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  20. SOFTWARE.
  21. ************************************************************************/
  22.  
  23. /*
  24.  * BOOTP (bootstrap protocol) server daemon.
  25.  *
  26.  * Answers BOOTP request packets from booting client machines.
  27.  * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
  28.  * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
  29.  * See RFC 1395 for option tags 14-17.
  30.  * See accompanying man page -- bootpd.8
  31.  *
  32.  * HISTORY
  33.  *    See ./Changes
  34.  *
  35.  * BUGS
  36.  *    See ./ToDo
  37.  */
  38.  
  39.  
  40.  
  41. #include <sys/types.h>
  42. #include <sys/param.h>
  43. #include <sys/socket.h>
  44. #include <sys/ioctl.h>
  45. #include <sys/file.h>
  46. #include <sys/time.h>
  47. #include <sys/stat.h>
  48. #include <sys/utsname.h>
  49.  
  50. #include <net/if.h>
  51. #include <netinet/in.h>
  52. #include <arpa/inet.h>    /* inet_ntoa */
  53.  
  54. #ifndef    NO_UNISTD
  55. #include <unistd.h>
  56. #endif
  57.  
  58. #include <stdlib.h>
  59. #include <signal.h>
  60. #include <stdio.h>
  61. #include <string.h>
  62. #include <errno.h>
  63. #include <ctype.h>
  64. #include <netdb.h>
  65. #include <syslog.h>
  66. #include <assert.h>
  67.  
  68. #ifdef    NO_SETSID
  69. # include <fcntl.h>        /* for O_RDONLY, etc */
  70. #endif
  71.  
  72. #ifndef    USE_BFUNCS
  73. # include <memory.h>
  74. /* Yes, memcpy is OK here (no overlapped copies). */
  75. # define bcopy(a,b,c)    memcpy(b,a,c)
  76. # define bzero(p,l)      memset(p,0,l)
  77. # define bcmp(a,b,c)     memcmp(a,b,c)
  78. #endif
  79. #ifdef __linux__
  80. /* Use sigaction to make signal last... */
  81. inline void (*signal(int sig,void (*handler)(int)))(int) {
  82.     struct sigaction so,sa = {NULL,0,SA_NOMASK|SA_RESTART,NULL};
  83.     sa.sa_handler = handler;
  84.     if (sigaction(sig,&sa,&so)<0) return NULL;
  85.     return so.sa_handler;
  86. }
  87. #endif
  88.  
  89. #include "bootp.h"
  90. #include "hash.h"
  91. #include "hwaddr.h"
  92. #include "bootpd.h"
  93. #include "dovend.h"
  94. #include "getif.h"
  95. #include "readfile.h"
  96. #include "report.h"
  97. #include "tzone.h"
  98. #include "patchlevel.h"
  99.  
  100. #ifndef CONFIG_FILE
  101. #define CONFIG_FILE        "/etc/bootptab"
  102. #endif
  103. #ifndef DUMPTAB_FILE
  104. #define DUMPTAB_FILE        "/tmp/bootpd.dump"
  105. #endif
  106.  
  107.  
  108.  
  109. /*
  110.  * Externals, forward declarations, and global variables
  111.  */
  112.  
  113. #ifdef    __STDC__
  114. #define P(args) args
  115. #else
  116. #define P(args) ()
  117. #endif
  118.  
  119. extern void dumptab P((char *));
  120.  
  121. PRIVATE void catcher P((int));
  122. PRIVATE int chk_access P((char *, int32 *));
  123. #ifdef VEND_CMU
  124. PRIVATE void dovend_cmu P((struct bootp *, struct host *));
  125. #endif
  126. PRIVATE int  dovend_rfc1048 P((struct bootp *, struct host *, int32));
  127. PRIVATE void handle_reply P((void));
  128. PRIVATE void handle_request P((void));
  129. PRIVATE void sendreply P((int forward, int32 dest_override));
  130. PRIVATE void usage P((void));
  131.  
  132. #ifdef DHCP
  133. PRIVATE int dhcp_discover P((struct bootp *, struct host *, byte *, int));
  134. PRIVATE int dhcp_request P((struct bootp *, struct host *, byte *, int));
  135. PRIVATE int dhcp_decline P((struct bootp *, struct host *, byte *, int));
  136. PRIVATE int dhcp_release P((struct bootp *, struct host *, byte *, int));
  137. PRIVATE int dhcp_offer P((struct bootp *, struct host *, byte *, int));
  138. PRIVATE int dhcp_ack P((struct bootp *, struct host *, byte *, int));
  139. PRIVATE int dhcp_lease P((struct bootp *, struct host *, byte **));
  140. #endif
  141.  
  142. #undef    P
  143.  
  144. /*
  145.  * IP port numbers for client and server obtained from /etc/services
  146.  */
  147.  
  148. u_short bootps_port, bootpc_port;
  149.  
  150.  
  151. /*
  152.  * Internet socket and interface config structures
  153.  */
  154.  
  155. struct sockaddr_in bind_addr;    /* Listening */
  156. struct sockaddr_in recv_addr;    /* Packet source */
  157. struct sockaddr_in send_addr;    /*  destination */
  158.  
  159.  
  160. /*
  161.  * option defaults
  162.  */
  163. int debug = 0;                    /* Debugging flag (level) */
  164. struct timeval actualtimeout =
  165. {                                /* fifteen minutes */
  166.     15 * 60L,                    /* tv_sec */
  167.     0                            /* tv_usec */
  168. };
  169.  
  170. /*
  171.  * General
  172.  */
  173.  
  174. int s;                            /* Socket file descriptor */
  175. char *pktbuf;                    /* Receive packet buffer */
  176. int pktlen;
  177. char *progname;
  178. char *chdir_path;
  179. struct in_addr my_ip_addr;
  180.  
  181. struct utsname my_uname;
  182. char *hostname;
  183.  
  184. /* Flags set by signal catcher. */
  185. PRIVATE int do_readtab = 0;
  186. PRIVATE int do_dumptab = 0;
  187.  
  188. /*
  189.  * Globals below are associated with the bootp database file (bootptab).
  190.  */
  191.  
  192. char *bootptab = CONFIG_FILE;
  193. char *bootpd_dump = DUMPTAB_FILE;
  194.  
  195.  
  196.  
  197. /*
  198.  * Initialization such as command-line processing is done and then the
  199.  * main server loop is started.
  200.  */
  201.  
  202. void
  203. main(argc, argv)
  204.     int argc;
  205.     char **argv;
  206. {
  207.     struct timeval *timeout;
  208.     struct bootp *bp;
  209.     struct servent *servp;
  210.     struct hostent *hep;
  211.     char *stmp;
  212.     int n, ba_len, ra_len;
  213.     int nfound, readfds;
  214.     int standalone;
  215. #ifdef    SA_NOCLDSTOP    /* Have POSIX sigaction(2). */
  216.     struct sigaction sa;
  217. #endif
  218.  
  219. #ifdef __EMX__
  220.     static char bootptab_file[256];
  221.     char *etc = getenv("ETC");
  222.     if (etc != NULL)
  223.     {
  224.       strcpy(bootptab_file, etc);
  225.       strcat(bootptab_file, "\\bootptab");
  226.       bootptab = bootptab_file;
  227.     }
  228. #endif
  229.  
  230.     progname = strrchr(argv[0], '/');
  231.     if (progname) progname++;
  232.     else progname = argv[0];
  233.  
  234.     /*
  235.      * Initialize logging.
  236.      */
  237.     report_init(0);                /* uses progname */
  238.  
  239.     /*
  240.      * Log startup
  241.      */
  242.     report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
  243.  
  244.     /* Debugging for compilers with struct padding. */
  245.     assert(sizeof(struct bootp) == BP_MINPKTSZ);
  246.  
  247.     /* Get space for receiving packets and composing replies. */
  248.     pktbuf = malloc(MAX_MSG_SIZE);
  249.     if (!pktbuf) {
  250.         report(LOG_ERR, "malloc failed");
  251.         exit(1);
  252.     }
  253.     bp = (struct bootp *) pktbuf;
  254.  
  255.     /*
  256.      * Check to see if a socket was passed to us from inetd.
  257.      *
  258.      * Use getsockname() to determine if descriptor 0 is indeed a socket
  259.      * (and thus we are probably a child of inetd) or if it is instead
  260.      * something else and we are running standalone.
  261.      */
  262.     s = 0;
  263.     ba_len = sizeof(bind_addr);
  264.     bzero((char *) &bind_addr, ba_len);
  265.     errno = 0;
  266.     standalone = TRUE;
  267. #ifndef __EMX__
  268.     if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
  269.         /*
  270.          * Descriptor 0 is a socket.  Assume we are a child of inetd.
  271.          */
  272.         if (bind_addr.sin_family == AF_INET) {
  273.             standalone = FALSE;
  274.             bootps_port = ntohs(bind_addr.sin_port);
  275.         } else {
  276.             /* Some other type of socket? */
  277.             report(LOG_ERR, "getsockname: not an INET socket");
  278.         }
  279.     }
  280. #endif
  281.  
  282.     /*
  283.      * Set defaults that might be changed by option switches.
  284.      */
  285.     stmp = NULL;
  286.     timeout = &actualtimeout;
  287.  
  288.     if (uname(&my_uname) < 0) {
  289.         fprintf(stderr, "bootpd: can't get hostname\n");
  290.         exit(1);
  291.     }
  292.     hostname = my_uname.nodename;
  293.  
  294.     /*
  295.      * Read switches.
  296.      */
  297.     for (argc--, argv++; argc > 0; argc--, argv++) {
  298.         if (argv[0][0] != '-')
  299.             break;
  300.         switch (argv[0][1]) {
  301.  
  302.         case 'c':                /* chdir_path */
  303.             if (argv[0][2]) {
  304.                 stmp = &(argv[0][2]);
  305.             } else {
  306.                 argc--;
  307.                 argv++;
  308.                 stmp = argv[0];
  309.             }
  310.             if (!stmp || (stmp[0] != '/')) {
  311.                 fprintf(stderr,
  312.                         "bootpd: invalid chdir specification\n");
  313.                 break;
  314.             }
  315.             chdir_path = stmp;
  316.             break;
  317.  
  318.         case 'd':                /* debug level */
  319.             if (argv[0][2]) {
  320.                 stmp = &(argv[0][2]);
  321.             } else if (argv[1] && argv[1][0] == '-') {
  322.                 /*
  323.                  * Backwards-compatible behavior:
  324.                  * no parameter, so just increment the debug flag.
  325.                  */
  326.                 debug++;
  327.                 break;
  328.             } else {
  329.                 argc--;
  330.                 argv++;
  331.                 stmp = argv[0];
  332.             }
  333.             if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
  334.                 fprintf(stderr,
  335.                         "%s: invalid debug level\n", progname);
  336.                 break;
  337.             }
  338.             debug = n;
  339.             break;
  340.  
  341.         case 'h':                /* override hostname */
  342.             if (argv[0][2]) {
  343.                 stmp = &(argv[0][2]);
  344.             } else {
  345.                 argc--;
  346.                 argv++;
  347.                 stmp = argv[0];
  348.             }
  349.             if (!stmp) {
  350.                 fprintf(stderr,
  351.                         "bootpd: missing hostname\n");
  352.                 break;
  353.             }
  354.             hostname = stmp;
  355.             break;
  356.  
  357. #ifndef __EMX__
  358.         case 'i':                /* inetd mode */
  359.             standalone = FALSE;
  360.             break;
  361.  
  362.         case 's':                /* standalone mode */
  363.             standalone = TRUE;
  364.             break;
  365. #endif
  366.  
  367.         case 't':                /* timeout */
  368.             if (argv[0][2]) {
  369.                 stmp = &(argv[0][2]);
  370.             } else {
  371.                 argc--;
  372.                 argv++;
  373.                 stmp = argv[0];
  374.             }
  375.             if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
  376.                 fprintf(stderr,
  377.                         "%s: invalid timeout specification\n", progname);
  378.                 break;
  379.             }
  380.             actualtimeout.tv_sec = (int32) (60 * n);
  381.             /*
  382.              * If the actual timeout is zero, pass a NULL pointer
  383.              * to select so it blocks indefinitely, otherwise,
  384.              * point to the actual timeout value.
  385.              */
  386.             timeout = (n > 0) ? &actualtimeout : NULL;
  387.             break;
  388.  
  389.         default:
  390.             fprintf(stderr, "%s: unknown switch: -%c\n",
  391.                     progname, argv[0][1]);
  392.             usage();
  393.             break;
  394.  
  395.         } /* switch */
  396.     } /* for args */
  397.  
  398.     /*
  399.      * Override default file names if specified on the command line.
  400.      */
  401.     if (argc > 0)
  402.         bootptab = argv[0];
  403.  
  404.     if (argc > 1)
  405.         bootpd_dump = argv[1];
  406.  
  407.     /*
  408.      * Get my hostname and IP address.
  409.      */
  410.  
  411.     hep = gethostbyname(hostname);
  412.     if (!hep) {
  413.         fprintf(stderr, "Can not get my IP address\n");
  414.         exit(1);
  415.     }
  416.     bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
  417.  
  418. #ifndef __EMX__
  419.     if (standalone) {
  420.         /*
  421.          * Go into background and disassociate from controlling terminal.
  422.          */
  423.         if (debug < 3) {
  424.             if (fork())
  425.                 exit(0);
  426. #ifdef    NO_SETSID
  427.             setpgrp(0,0);
  428. #ifdef TIOCNOTTY
  429.             n = open("/dev/tty", O_RDWR);
  430.             if (n >= 0) {
  431.                 ioctl(n, TIOCNOTTY, (char *) 0);
  432.                 (void) close(n);
  433.             }
  434. #endif    /* TIOCNOTTY */
  435. #else    /* SETSID */
  436.             if (setsid() < 0)
  437.                 perror("setsid");
  438. #endif    /* SETSID */
  439.         } /* if debug < 3 */
  440.  
  441.         /*
  442.          * Nuke any timeout value
  443.          */
  444.         timeout = NULL;
  445.  
  446.     } /* if standalone (1st) */
  447. #endif
  448.  
  449.     /* Set the cwd (i.e. to /tftpboot) */
  450.     if (chdir_path) {
  451.         if (chdir(chdir_path) < 0)
  452.             report(LOG_ERR, "%s: chdir failed", chdir_path);
  453.     }
  454.  
  455.     /* Get the timezone. */
  456.     tzone_init();
  457.  
  458.     /* Allocate hash tables. */
  459.     rdtab_init();
  460.  
  461.     /*
  462.      * Read the bootptab file.
  463.      */
  464.     readtab(1);                    /* force read */
  465.  
  466.     if (standalone) {
  467.  
  468.         /*
  469.          * Create a socket.
  470.          */
  471.         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  472.             report(LOG_ERR, "socket: %s", get_network_errmsg());
  473.             exit(1);
  474.         }
  475.  
  476.         /*
  477.          * Get server's listening port number
  478.          */
  479.         servp = getservbyname("sbootp", "udp");
  480.         if (servp) {
  481.             bootps_port = ntohs((u_short) servp->s_port);
  482.         } else {
  483.             bootps_port = (u_short) IPPORT_BOOTPS;
  484.             report(LOG_ERR,
  485.                    "udp/bootps: unknown service -- assuming port %d",
  486.                    bootps_port);
  487.         }
  488.  
  489.         /*
  490.          * Bind socket to BOOTPS port.
  491.          */
  492.         bind_addr.sin_family = AF_INET;
  493.         bind_addr.sin_addr.s_addr = INADDR_ANY;
  494.         bind_addr.sin_port = htons(bootps_port);
  495.         if (bind(s, (struct sockaddr *) &bind_addr,
  496.                  sizeof(bind_addr)) < 0)
  497.         {
  498.             report(LOG_ERR, "bind: %s", get_network_errmsg());
  499.             exit(1);
  500.         }
  501.     } /* if standalone (2nd)*/
  502.  
  503.     /*
  504.      * Get destination port number so we can reply to client
  505.      */
  506.     servp = getservbyname("cbootp", "udp");
  507.     if (servp) {
  508.         bootpc_port = ntohs(servp->s_port);
  509.     } else {
  510.         report(LOG_ERR,
  511.                "udp/bootpc: unknown service -- assuming port %d",
  512.                IPPORT_BOOTPC);
  513.         bootpc_port = (u_short) IPPORT_BOOTPC;
  514.     }
  515.  
  516. #ifdef DHCP
  517.     /*
  518.      * Maybe we have to broadcast, so enable it.
  519.      */
  520.     n = 1;
  521.     if (setsockopt(s,SOL_SOCKET,SO_BROADCAST,&n,sizeof(n))<0) {
  522.         report(LOG_ERR, "setsockopt: %s\n", get_errmsg());
  523.         exit(1);
  524.     }
  525. #endif
  526.  
  527.     /*
  528.      * Set up signals to read or dump the table.
  529.      */
  530. #ifdef    SA_NOCLDSTOP    /* Have POSIX sigaction(2). */
  531.     sa.sa_handler = catcher;
  532.     sigemptyset(&sa.sa_mask);
  533.     sa.sa_flags = 0;
  534.     if (sigaction(SIGHUP, &sa, NULL) < 0) {
  535.         report(LOG_ERR, "sigaction: %s", get_errmsg());
  536.         exit(1);
  537.     }
  538.     if (sigaction(SIGUSR1, &sa, NULL) < 0) {
  539.         report(LOG_ERR, "sigaction: %s", get_errmsg());
  540.         exit(1);
  541.     }
  542. #else    /* SA_NOCLDSTOP */
  543.     /* Old-fashioned UNIX signals */
  544.     if ((int) signal(SIGHUP, catcher) < 0) {
  545.         report(LOG_ERR, "signal: %s", get_errmsg());
  546.         exit(1);
  547.     }
  548.     if ((int) signal(SIGUSR1, catcher) < 0) {
  549.         report(LOG_ERR, "signal: %s", get_errmsg());
  550.         exit(1);
  551.     }
  552. #endif    /* SA_NOCLDSTOP */
  553.  
  554.     /*
  555.      * Process incoming requests.
  556.      */
  557.     for (;;) {
  558.         struct timeval tv;
  559.  
  560.         readfds = 1 << s;
  561.         if (timeout)
  562.             tv = *timeout;
  563.  
  564.         nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL,
  565.                         (timeout) ? &tv : NULL);
  566.         if (nfound < 0) {
  567.             if (errno != EINTR) {
  568.                 report(LOG_ERR, "select: %s", get_errmsg());
  569.             }
  570.             /*
  571.              * Call readtab() or dumptab() here to avoid the
  572.              * dangers of doing I/O from a signal handler.
  573.              */
  574.             if (do_readtab) {
  575.                 do_readtab = 0;
  576.                 readtab(1);        /* force read */
  577.             }
  578.             if (do_dumptab) {
  579.                 do_dumptab = 0;
  580.                 dumptab(bootpd_dump);
  581.             }
  582.             continue;
  583.         }
  584.         if (!(readfds & (1 << s))) {
  585.             if (debug > 1)
  586.                 report(LOG_INFO, "exiting after %ld minutes of inactivity",
  587.                        actualtimeout.tv_sec / 60);
  588.             exit(0);
  589.         }
  590.         ra_len = sizeof(recv_addr);
  591.         n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
  592.                      (struct sockaddr *) &recv_addr, &ra_len);
  593.         if (n <= 0) {
  594.             continue;
  595.         }
  596.         if (debug > 1) {
  597.             report(LOG_INFO, "recvd pkt from IP addr %s",
  598.                    inet_ntoa(recv_addr.sin_addr));
  599.         }
  600.         if (n < sizeof(struct bootp)) {
  601.             if (debug) {
  602.                 report(LOG_NOTICE, "received short packet");
  603.             }
  604.             continue;
  605.         }
  606.         pktlen = n;
  607.  
  608.         readtab(0);                /* maybe re-read bootptab */
  609.  
  610.         switch (bp->bp_op) {
  611.         case BOOTREQUEST:
  612.             handle_request();
  613.             break;
  614.         case BOOTREPLY:
  615.             handle_reply();
  616.             break;
  617.         }
  618.     }
  619. }
  620.  
  621.  
  622.  
  623.  
  624. /*
  625.  * Print "usage" message and exit
  626.  */
  627.  
  628. PRIVATE void
  629. usage()
  630. {
  631.     fprintf(stderr,
  632.             "usage:  bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
  633.     fprintf(stderr, "\t -c n\tset current directory\n");
  634.     fprintf(stderr, "\t -d n\tset debug level\n");
  635. #ifndef __EMX__
  636.     fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
  637.     fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
  638. #endif
  639.     fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
  640.     exit(1);
  641. }
  642.  
  643. /* Signal catchers */
  644. PRIVATE void
  645. catcher(sig)
  646.     int sig;
  647. {
  648.     if (sig == SIGHUP)
  649.         do_readtab = 1;
  650.     if (sig == SIGUSR1)
  651.         do_dumptab = 1;
  652. #if    !defined(SA_NOCLDSTOP) && defined(SYSV)
  653.     /* For older "System V" derivatives with no sigaction(). */
  654.     signal(sig, catcher);
  655. #endif
  656. }
  657.  
  658.  
  659.  
  660. /*
  661.  * Process BOOTREQUEST packet.
  662.  *
  663.  * Note:  This version of the bootpd.c server never forwards
  664.  * a request to another server.  That is the job of a gateway
  665.  * program such as the "bootpgw" program included here.
  666.  *
  667.  * (Also this version does not interpret the hostname field of
  668.  * the request packet;  it COULD do a name->address lookup and
  669.  * forward the request there.)
  670.  */
  671. PRIVATE void
  672. handle_request()
  673. {
  674.     struct bootp *bp = (struct bootp *) pktbuf;
  675.     struct host *hp = NULL;
  676.     struct host dummyhost;
  677.     int32 bootsize = 0;
  678.     unsigned hlen, hashcode;
  679.     int32 dest;
  680.     char realpath[1024];
  681.     char *clntpath;
  682.     char *homedir, *bootfile;
  683.     int n;
  684.  
  685.     /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
  686.  
  687.     /*
  688.      * If the servername field is set, compare it against us.
  689.      * If we're not being addressed, ignore this request.
  690.      * If the server name field is null, throw in our name.
  691.      */
  692.     if (strlen(bp->bp_sname)) {
  693.         if (strcmp(bp->bp_sname, hostname)) {
  694.             if (debug)
  695.                 report(LOG_INFO, "\
  696. ignoring request for server %s from client at %s address %s",
  697.                        bp->bp_sname, netname(bp->bp_htype),
  698.                        haddrtoa(bp->bp_chaddr, bp->bp_hlen));
  699.             /* XXX - Is it correct to ignore such a request? -gwr */
  700.             return;
  701.         }
  702.     } else {
  703.         strcpy(bp->bp_sname, hostname);
  704.     }
  705.  
  706.     /* Convert the request into a reply. */
  707.     bp->bp_op = BOOTREPLY;
  708.     if (bp->bp_ciaddr.s_addr == 0) {
  709.         /*
  710.          * client doesnt know his IP address,
  711.          * search by hardware address.
  712.          */
  713.         if (debug > 1) {
  714.             report(LOG_INFO, "request from %s address %s",
  715.                    netname(bp->bp_htype),
  716.                    haddrtoa(bp->bp_chaddr, bp->bp_hlen));
  717.         }
  718.         hlen = haddrlength(bp->bp_htype);
  719.         if (hlen != bp->bp_hlen) {
  720.             report(LOG_NOTICE, "bad addr len from from %s address %s",
  721.                    netname(bp->bp_htype),
  722.                    haddrtoa(bp->bp_chaddr, hlen));
  723.         }
  724.         dummyhost.htype = bp->bp_htype;
  725.         bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
  726.         hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
  727.         hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
  728.                                          &dummyhost);
  729.         if (hp == NULL &&
  730.             bp->bp_htype == HTYPE_IEEE802)
  731.         {
  732.             /* Try again with address in "canonical" form. */
  733.             haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
  734.             if (debug > 1) {
  735.                 report(LOG_INFO, "\
  736. HW addr type is IEEE 802.  convert to %s and check again\n",
  737.                        haddrtoa(dummyhost.haddr, bp->bp_hlen));
  738.             }
  739.             hashcode = hash_HashFunction(dummyhost.haddr, hlen);
  740.             hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
  741.                                              hwlookcmp, &dummyhost);
  742.         }
  743.         if (hp == NULL) {
  744.             /*
  745.              * XXX - Add dynamic IP address assignment?
  746.              */
  747.             if (debug)
  748.                 report(LOG_NOTICE, "unknown client %s address %s",
  749.                        netname(bp->bp_htype),
  750.                        haddrtoa(bp->bp_chaddr, bp->bp_hlen));
  751.             return; /* not found */
  752.         }
  753.  
  754.     } else {
  755.  
  756.         /*
  757.          * search by IP address.
  758.          */
  759.         if (debug > 1) {
  760.             report(LOG_INFO, "request from IP addr %s",
  761.                    inet_ntoa(bp->bp_ciaddr));
  762.         }
  763.         dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
  764.         hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
  765.         hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
  766.                                          &dummyhost);
  767.         if (hp == NULL) {
  768.             if (debug) {
  769.                 report(LOG_NOTICE, "IP address not found: %s",
  770.                        inet_ntoa(bp->bp_ciaddr));
  771.             }
  772.             return;
  773.         }
  774.     }
  775.     (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
  776.  
  777.     if (debug) {
  778.         report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
  779.                hp->hostname->string);
  780.     }
  781.  
  782.     /*
  783.      * If there is a response delay threshold, ignore requests
  784.      * with a timestamp lower than the threshold.
  785.      */
  786.     if (hp->flags.min_wait) {
  787.         u_int32 t = (u_int32) ntohs(bp->bp_secs);
  788.         if (t < hp->min_wait) {
  789.             if (debug > 1)
  790.                 report(LOG_INFO,
  791.                        "ignoring request due to timestamp (%d < %d)",
  792.                        t, hp->min_wait);
  793.             return;
  794.         }
  795.     }
  796.  
  797. #ifdef    YORK_EX_OPTION
  798.     /*
  799.      * The need for the "ex" tag arose out of the need to empty
  800.      * shared networked drives on diskless PCs.  This solution is
  801.      * not very clean but it does work fairly well.
  802.      * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
  803.      *
  804.      * XXX - This could compromise security if a non-trusted user
  805.      * managed to write an entry in the bootptab with :ex=trojan:
  806.      * so I would leave this turned off unless you need it. -gwr
  807.      */
  808.     /* Run a program, passing the client name as a parameter. */
  809.     if (hp->flags.exec_file) {
  810.         char tst[100];
  811.         /* XXX - Check string lengths? -gwr */
  812.         strcpy (tst, hp->exec_file->string);
  813.         strcat (tst, " ");
  814.         strcat (tst, hp->hostname->string);
  815.         strcat (tst, " &");
  816.         if (debug)
  817.             report(LOG_INFO, "executing %s", tst);
  818.         system(tst);    /* Hope this finishes soon... */
  819.     }
  820. #endif    /* YORK_EX_OPTION */
  821.  
  822.     /*
  823.      * If a specific TFTP server address was specified in the bootptab file,
  824.      * fill it in, otherwise zero it.
  825.      * XXX - Rather than zero it, should it be the bootpd address? -gwr
  826.      */
  827.     (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
  828.         hp->bootserver.s_addr : 0L;
  829.  
  830. #ifdef    STANFORD_PROM_COMPAT
  831.     /*
  832.      * Stanford bootp PROMs (for a Sun?) have no way to leave
  833.      * the boot file name field blank (because the boot file
  834.      * name is automatically generated from some index).
  835.      * As a work-around, this little hack allows those PROMs to
  836.      * specify "sunboot14" with the same effect as a NULL name.
  837.      * (The user specifies boot device 14 or some such magic.)
  838.      */
  839.     if (strcmp(bp->bp_file, "sunboot14") == 0)
  840.         bp->bp_file[0] = '\0';    /* treat it as unspecified */
  841. #endif
  842.  
  843.     /*
  844.      * Fill in the client's proper bootfile.
  845.      *
  846.      * If the client specifies an absolute path, try that file with a
  847.      * ".host" suffix and then without.  If the file cannot be found, no
  848.      * reply is made at all.
  849.      *
  850.      * If the client specifies a null or relative file, use the following
  851.      * table to determine the appropriate action:
  852.      *
  853.      *  Homedir      Bootfile    Client's file
  854.      * specified?   specified?   specification   Action
  855.      * -------------------------------------------------------------------
  856.      *      No          No          Null         Send null filename
  857.      *      No          No          Relative     Discard request
  858.      *      No          Yes         Null         Send if absolute else null
  859.      *      No          Yes         Relative     Discard request     *XXX
  860.      *      Yes         No          Null         Send null filename
  861.      *      Yes         No          Relative     Lookup with ".host"
  862.      *      Yes         Yes         Null         Send home/boot or bootfile
  863.      *      Yes         Yes         Relative     Lookup with ".host" *XXX
  864.      *
  865.      */
  866.  
  867.     /*
  868.      * XXX - I don't like the policy of ignoring a client when the
  869.      * boot file is not accessible.  The TFTP server might not be
  870.      * running on the same machine as the BOOTP server, in which
  871.      * case checking accessibility of the boot file is pointless.
  872.      *
  873.      * Therefore, file accessibility is now demanded ONLY if you
  874.      * define CHECK_FILE_ACCESS in the Makefile options. -gwr
  875.      */
  876.  
  877.     /*
  878.      * The "real" path is as seen by the BOOTP daemon on this
  879.      * machine, while the client path is relative to the TFTP
  880.      * daemon chroot directory (i.e. /tftpboot).
  881.      */
  882.     if (hp->flags.tftpdir) {
  883.         strcpy(realpath, hp->tftpdir->string);
  884.         clntpath = &realpath[strlen(realpath)];
  885.     } else {
  886.         realpath[0] = '\0';
  887.         clntpath = realpath;
  888.     }
  889.  
  890.     /*
  891.      * Determine client's requested homedir and bootfile.
  892.      */
  893.     homedir = NULL;
  894.     bootfile = NULL;
  895.     if (bp->bp_file[0]) {
  896.         homedir = bp->bp_file;
  897.         bootfile = strrchr(homedir, '/');
  898.         if (bootfile) {
  899.             if (homedir == bootfile)
  900.                 homedir = NULL;
  901.             *bootfile++ = '\0';
  902.         } else {
  903.             /* no "/" in the string */
  904.             bootfile = homedir;
  905.             homedir = NULL;
  906.         }
  907.         if (debug > 2) {
  908.             report(LOG_INFO, "requested path=\"%s\"  file=\"%s\"",
  909.                    (homedir) ? homedir : "",
  910.                    (bootfile) ? bootfile : "");
  911.         }
  912.     }
  913.  
  914.     /*
  915.      * Specifications in bootptab override client requested values.
  916.      */
  917.     if (hp->flags.homedir)
  918.         homedir = hp->homedir->string;
  919.     if (hp->flags.bootfile)
  920.         bootfile = hp->bootfile->string;
  921.  
  922.     /*
  923.      * Construct bootfile path.
  924.      */
  925.     if (homedir) {
  926.         if (homedir[0] != '/')
  927.             strcat(clntpath, "/");
  928.         strcat(clntpath, homedir);
  929.         homedir = NULL;
  930.     }
  931.     if (bootfile) {
  932.         if (bootfile[0] != '/')
  933.             strcat(clntpath, "/");
  934.         strcat(clntpath, bootfile);
  935.         bootfile = NULL;
  936.     }
  937.  
  938.     /*
  939.      * First try to find the file with a ".host" suffix
  940.      */
  941.     n = strlen(clntpath);
  942.     strcat(clntpath, ".");
  943.     strcat(clntpath, hp->hostname->string);
  944.     if (chk_access(realpath, &bootsize) < 0) {
  945.         clntpath[n] = 0;            /* Try it without the suffix */
  946.         if (chk_access(realpath, &bootsize) < 0) {
  947.             /* neither "file.host" nor "file" was found */
  948. #ifdef    CHECK_FILE_ACCESS
  949.  
  950.             if (bp->bp_file[0]) {
  951.                 /*
  952.                  * Client wanted specific file
  953.                  * and we didn't have it.
  954.                  */
  955.                 report(LOG_NOTICE,
  956.                        "requested file not found: \"%s\"", clntpath);
  957.                 return;
  958.             }
  959.             /*
  960.              * Client didn't ask for a specific file and we couldn't
  961.              * access the default file, so just zero-out the bootfile
  962.              * field in the packet and continue processing the reply.
  963.              */
  964.             bzero(bp->bp_file, sizeof(bp->bp_file));
  965.             goto null_file_name;
  966.  
  967. #else    /* CHECK_FILE_ACCESS */
  968.  
  969.             /* Complain only if boot file size was needed. */
  970.             if (hp->flags.bootsize_auto) {
  971.                 report(LOG_ERR, "can not determine size of file \"%s\"",
  972.                        clntpath);
  973.             }
  974.  
  975. #endif    /* CHECK_FILE_ACCESS */
  976.         }
  977.     }
  978.     strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
  979.     if (debug > 2)
  980.         report(LOG_INFO, "bootfile=\"%s\"", clntpath);
  981.  
  982. #ifdef    CHECK_FILE_ACCESS
  983. null_file_name:
  984. #endif    /* CHECK_FILE_ACCESS */
  985.  
  986.  
  987.     /*
  988.      * Handle vendor options based on magic number.
  989.      */
  990.  
  991.     if (debug > 1) {
  992.         report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
  993.                (int) ((bp->bp_vend)[0]),
  994.                (int) ((bp->bp_vend)[1]),
  995.                (int) ((bp->bp_vend)[2]),
  996.                (int) ((bp->bp_vend)[3]));
  997.     }
  998.     /*
  999.      * If this host isn't set for automatic vendor info then copy the
  1000.      * specific cookie into the bootp packet, thus forcing a certain
  1001.      * reply format.  Only force reply format if user specified it.
  1002.      */
  1003.     if (hp->flags.vm_cookie) {
  1004.         /* Slam in the user specified magic number. */
  1005.         bcopy(hp->vm_cookie, bp->bp_vend, 4);
  1006.     }
  1007.     /*
  1008.      * Figure out the format for the vendor-specific info.
  1009.      * Note that bp->bp_vend may have been set above.
  1010.      */
  1011.     if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
  1012.         /* RFC1048 conformant bootp client */
  1013.         if (!dovend_rfc1048(bp, hp, bootsize))
  1014.             return;
  1015.         if (debug > 1) {
  1016.             report(LOG_INFO, "sending reply (with RFC1048 options)");
  1017.         }
  1018.     }
  1019. #ifdef VEND_CMU
  1020.     else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
  1021.         dovend_cmu(bp, hp);
  1022.         if (debug > 1) {
  1023.             report(LOG_INFO, "sending reply (with CMU options)");
  1024.         }
  1025.     }
  1026. #endif
  1027.     else {
  1028.         if (debug > 1) {
  1029.             report(LOG_INFO, "sending reply (with no options)");
  1030.         }
  1031.     }
  1032.  
  1033.     dest = (hp->flags.reply_addr) ?
  1034.         hp->reply_addr.s_addr : 0L;
  1035.  
  1036.     /* not forwarded */
  1037.     sendreply(0, dest);
  1038. }
  1039.  
  1040.  
  1041. /*
  1042.  * Process BOOTREPLY packet.
  1043.  */
  1044. PRIVATE void
  1045. handle_reply()
  1046. {
  1047.     if (debug) {
  1048.         report(LOG_INFO, "processing boot reply");
  1049.     }
  1050.     /* forwarded, no destination override */
  1051.     sendreply(1, 0);
  1052. }
  1053.  
  1054.  
  1055. /*
  1056.  * Send a reply packet to the client.  'forward' flag is set if we are
  1057.  * not the originator of this reply packet.
  1058.  */
  1059. PRIVATE void
  1060. sendreply(forward, dst_override)
  1061.     int forward;
  1062.     int32 dst_override;
  1063. {
  1064.     struct bootp *bp = (struct bootp *) pktbuf;
  1065.     struct in_addr dst;
  1066.     u_short port = bootpc_port;
  1067.     unsigned char *ha;
  1068.     int len, haf;
  1069.  
  1070.     /*
  1071.      * XXX - Should honor bp_flags "broadcast" bit here.
  1072.      * Temporary workaround: use the :ra=ADDR: option to
  1073.      * set the reply address to the broadcast address.
  1074.      */
  1075.  
  1076.     /*
  1077.      * If the destination address was specified explicitly
  1078.      * (i.e. the broadcast address for HP compatiblity)
  1079.      * then send the response to that address.  Otherwise,
  1080.      * act in accordance with RFC951:
  1081.      *   If the client IP address is specified, use that
  1082.      * else if gateway IP address is specified, use that
  1083.      * else make a temporary arp cache entry for the client's
  1084.      * NEW IP/hardware address and use that.
  1085.      */
  1086.     if (dst_override) {
  1087.         dst.s_addr = dst_override;
  1088.         if (debug > 1) {
  1089.             report(LOG_INFO, "reply address override: %s",
  1090.                    inet_ntoa(dst));
  1091.         }
  1092.     } else if (bp->bp_ciaddr.s_addr) {
  1093.         dst = bp->bp_ciaddr;
  1094.     } else if (bp->bp_giaddr.s_addr && forward == 0) {
  1095.         dst = bp->bp_giaddr;
  1096.         port = bootps_port;
  1097.         if (debug > 1) {
  1098.             report(LOG_INFO, "sending reply to gateway %s",
  1099.                    inet_ntoa(dst));
  1100.         }
  1101.     } else {
  1102.         dst = bp->bp_yiaddr;
  1103.         ha = bp->bp_chaddr;
  1104.         len = bp->bp_hlen;
  1105.         if (len > MAXHADDRLEN)
  1106.             len = MAXHADDRLEN;
  1107.         haf = (int) bp->bp_htype;
  1108.         if (haf == 0)
  1109.             haf = HTYPE_ETHERNET;
  1110.  
  1111.         if (debug > 1)
  1112.             report(LOG_INFO, "setarp %s - %s",
  1113.                    inet_ntoa(dst), haddrtoa(ha, len));
  1114.         setarp(s, &dst, haf, ha, len);
  1115.     }
  1116.  
  1117.     if ((forward == 0) &&
  1118.         (bp->bp_siaddr.s_addr == 0))
  1119.     {
  1120.         struct ifreq *ifr;
  1121.         struct in_addr siaddr;
  1122.         /*
  1123.          * If we are originating this reply, we
  1124.          * need to find our own interface address to
  1125.          * put in the bp_siaddr field of the reply.
  1126.          * If this server is multi-homed, pick the
  1127.          * 'best' interface (the one on the same net
  1128.          * as the client).  Of course, the client may
  1129.          * be on the other side of a BOOTP gateway...
  1130.          */
  1131.         ifr = getif(s, &dst);
  1132.         if (ifr) {
  1133.             struct sockaddr_in *sip;
  1134.             sip = (struct sockaddr_in *) &(ifr->ifr_addr);
  1135.             siaddr = sip->sin_addr;
  1136.         } else {
  1137.             /* Just use my "official" IP address. */
  1138.             siaddr = my_ip_addr;
  1139.         }
  1140.  
  1141.         /* XXX - No need to set bp_giaddr here. */
  1142.  
  1143.         /* Finally, set the server address field. */
  1144.         bp->bp_siaddr = siaddr;
  1145.     }
  1146. #ifdef DHCP
  1147.     /*
  1148.      * This code is placed here, because otherwise the siaddr
  1149.      * will not be found...
  1150.      */
  1151.     if (ntohs(bp->bp_flags) & 0x8000 && bp->bp_giaddr.s_addr==0)
  1152.         dst.s_addr = INADDR_BROADCAST;
  1153. #endif
  1154.     /* Set up socket address for send. */
  1155.     send_addr.sin_family = AF_INET;
  1156.     send_addr.sin_port = htons(port);
  1157.     send_addr.sin_addr = dst;
  1158.  
  1159.     /* Send reply with same size packet as request used. */
  1160.     if (sendto(s, pktbuf, pktlen, 0,
  1161.                (struct sockaddr *) &send_addr,
  1162.                sizeof(send_addr)) < 0)
  1163.     {
  1164.         report(LOG_ERR, "sendto: %s", get_network_errmsg());
  1165.     }
  1166. } /* sendreply */
  1167.  
  1168.  
  1169. /* nmatch() - now in getif.c */
  1170. /* setarp() - now in hwaddr.c */
  1171.  
  1172.  
  1173. /*
  1174.  * This call checks read access to a file.  It returns 0 if the file given
  1175.  * by "path" exists and is publically readable.  A value of -1 is returned if
  1176.  * access is not permitted or an error occurs.  Successful calls also
  1177.  * return the file size in bytes using the long pointer "filesize".
  1178.  *
  1179.  * The read permission bit for "other" users is checked.  This bit must be
  1180.  * set for tftpd(8) to allow clients to read the file.
  1181.  */
  1182.  
  1183. PRIVATE int
  1184. chk_access(path, filesize)
  1185.     char *path;
  1186.     int32 *filesize;
  1187. {
  1188.     struct stat st;
  1189.  
  1190.     if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
  1191.         *filesize = (int32) st.st_size;
  1192.         return 0;
  1193.     } else {
  1194.         return -1;
  1195.     }
  1196. }
  1197.  
  1198.  
  1199. /*
  1200.  * Now in dumptab.c :
  1201.  *    dumptab()
  1202.  *    dump_host()
  1203.  *    list_ipaddresses()
  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. PRIVATE void
  1214. dovend_cmu(bp, hp)
  1215.     struct bootp *bp;
  1216.     struct host *hp;
  1217. {
  1218.     struct cmu_vend *vendp;
  1219.     struct in_addr_list *taddr;
  1220.  
  1221.     /*
  1222.      * Initialize the entire vendor field to zeroes.
  1223.      */
  1224.     bzero(bp->bp_vend, sizeof(bp->bp_vend));
  1225.  
  1226.     /*
  1227.      * Fill in vendor information. Subnet mask, default gateway,
  1228.      * domain name server, ien name server, time server
  1229.      */
  1230.     vendp = (struct cmu_vend *) bp->bp_vend;
  1231.     strcpy(vendp->v_magic, (char *)vm_cmu);
  1232.     if (hp->flags.subnet_mask) {
  1233.         (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
  1234.         (vendp->v_flags) |= VF_SMASK;
  1235.         if (hp->flags.gateway) {
  1236.             (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
  1237.         }
  1238.     }
  1239.     if (hp->flags.domain_server) {
  1240.         taddr = hp->domain_server;
  1241.         if (taddr->addrcount > 0) {
  1242.             (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
  1243.             if (taddr->addrcount > 1) {
  1244.                 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
  1245.             }
  1246.         }
  1247.     }
  1248.     if (hp->flags.name_server) {
  1249.         taddr = hp->name_server;
  1250.         if (taddr->addrcount > 0) {
  1251.             (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
  1252.             if (taddr->addrcount > 1) {
  1253.                 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
  1254.             }
  1255.         }
  1256.     }
  1257.     if (hp->flags.time_server) {
  1258.         taddr = hp->time_server;
  1259.         if (taddr->addrcount > 0) {
  1260.             (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
  1261.             if (taddr->addrcount > 1) {
  1262.                 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
  1263.             }
  1264.         }
  1265.     }
  1266.     /* Log message now done by caller. */
  1267. } /* dovend_cmu */
  1268.  
  1269. #endif /* VEND_CMU */
  1270.  
  1271.  
  1272.  
  1273. /*
  1274.  * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
  1275.  * bootp packet pointed to by "bp".
  1276.  */
  1277. #define    NEED(LEN, MSG) do \
  1278.     if (bytesleft < (LEN)) { \
  1279.         report(LOG_NOTICE, noroom, \
  1280.                hp->hostname->string, MSG); \
  1281.         return 0; \
  1282.     } while (0)
  1283. PRIVATE int
  1284. dovend_rfc1048(bp, hp, bootsize)
  1285.     struct bootp *bp;
  1286.     struct host *hp;
  1287.     int32 bootsize;
  1288. {
  1289.     int bytesleft, len;
  1290.     byte *vp;
  1291. #ifdef DHCP
  1292.     int dhcp = 0;
  1293.     int isme = TRUE;    /* DHCP uses this for not-mine-requests */
  1294. #endif
  1295.  
  1296.     static char noroom[] = "%s: No room for \"%s\" option";
  1297.  
  1298.     vp = bp->bp_vend;
  1299.  
  1300.     if (hp->flags.msg_size) {
  1301.         pktlen = hp->msg_size;
  1302.     } else {
  1303.         /*
  1304.          * If the request was longer than the official length, build
  1305.          * a response of that same length where the additional length
  1306.          * is assumed to be part of the bp_vend (options) area.
  1307.          */
  1308.         if (pktlen > sizeof(*bp)) {
  1309.             if (debug > 1)
  1310.                 report(LOG_INFO, "request message length=%d", pktlen);
  1311.         }
  1312.         /*
  1313.          * Check whether the request contains the option:
  1314.          * Maximum DHCP Message Size (RFC1533 sec. 9.8)
  1315.          * and if so, override the response length with its value.
  1316.          * This request must lie within the first BP_VEND_LEN
  1317.          * bytes of the option space.
  1318.          */
  1319.         {
  1320.             byte *p, *ep;
  1321.             byte tag, len;
  1322.             short msgsz = 0;
  1323.             
  1324.             p = vp + 4;
  1325.             ep = p + BP_VEND_LEN - 4;
  1326.             while (p < ep) {
  1327.                 tag = *p++;
  1328.                 /* Check for tags with no data first. */
  1329.                 if (tag == TAG_PAD)
  1330.                     continue;
  1331.                 if (tag == TAG_END)
  1332.                     break;
  1333.                 /* Now scan the length byte. */
  1334.                 len = *p++;
  1335.                 switch (tag) {
  1336.                 case TAG_MAX_MSGSZ:
  1337.                     if (len == 2) {
  1338.                         bcopy(p, (char*)&msgsz, 2);
  1339.                         msgsz = ntohs(msgsz);
  1340.                     }
  1341.                     break;
  1342.                 case TAG_SUBNET_MASK:
  1343.                     /* XXX - Should preserve this if given... */
  1344.                     break;
  1345.                 case TAG_DHCP_MSG:
  1346.                     dhcp = *p;
  1347.                     break;
  1348.                 case TAG_DHCP_SERVERID:
  1349.                     isme = (len==4) && my_ip_addr.s_addr == ((struct in_addr *)p)->s_addr;
  1350.                     break;
  1351.                 } /* switch */
  1352.                 p += len;
  1353.             }
  1354.  
  1355.             if (msgsz > sizeof(*bp)) {
  1356.                 if (debug > 1)
  1357.                     report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
  1358.                 pktlen = msgsz;
  1359.             }
  1360.         }
  1361.     }
  1362.  
  1363.     if (pktlen < sizeof(*bp)) {
  1364.         report(LOG_ERR, "invalid response length=%d", pktlen);
  1365.         pktlen = sizeof(*bp);
  1366.     }
  1367.     bytesleft = ((byte*)bp + pktlen) - vp;
  1368.     if (pktlen > sizeof(*bp)) {
  1369.         if (debug > 1)
  1370.             report(LOG_INFO, "extended reply, length=%d, options=%d",
  1371.                    pktlen, bytesleft);
  1372.     }
  1373.  
  1374.     /* Copy in the magic cookie */
  1375.     bcopy(vm_rfc1048, vp, 4);
  1376.     vp += 4;
  1377.     bytesleft -= 4;
  1378.  
  1379.     if (hp->flags.subnet_mask) {
  1380.         /* always enough room here. */
  1381.         *vp++ = TAG_SUBNET_MASK;/* -1 byte  */
  1382.         *vp++ = 4;                /* -1 byte  */
  1383.         insert_u_long(hp->subnet_mask.s_addr, &vp);    /* -4 bytes */
  1384.         bytesleft -= 6;            /* Fix real count */
  1385.         if (hp->flags.gateway) {
  1386.             (void) insert_ip(TAG_GATEWAY,
  1387.                              hp->gateway,
  1388.                              &vp, &bytesleft);
  1389.         }
  1390.     }
  1391.     if (hp->flags.bootsize) {
  1392.         /* always enough room here */
  1393.         bootsize = (hp->flags.bootsize_auto) ?
  1394.             ((bootsize + 511) / 512) : (hp->bootsize);    /* Round up */
  1395.         *vp++ = TAG_BOOT_SIZE;
  1396.         *vp++ = 2;
  1397.         *vp++ = (byte) ((bootsize >> 8) & 0xFF);
  1398.         *vp++ = (byte) (bootsize & 0xFF);
  1399.         bytesleft -= 4;            /* Tag, length, and 16 bit blocksize */
  1400.     }
  1401.     /*
  1402.      * This one is special: Remaining options go in the ext file.
  1403.      * Only the subnet_mask, bootsize, and gateway should precede.
  1404.      */
  1405.     if (hp->flags.exten_file) {
  1406.         /*
  1407.          * Check for room for exten_file.  Add 3 to account for
  1408.          * TAG_EXTEN_FILE, length, and TAG_END.
  1409.          */
  1410.         len = strlen(hp->exten_file->string);
  1411.         NEED((len + 3), "ef");
  1412.         *vp++ = TAG_EXTEN_FILE;
  1413.         *vp++ = (byte) (len & 0xFF);
  1414.         bcopy(hp->exten_file->string, vp, len);
  1415.         vp += len;
  1416.         *vp++ = TAG_END;
  1417.         bytesleft -= len + 3;
  1418.         return 1;                /* no more options here. */
  1419.     }
  1420.  
  1421. #ifdef DHCP
  1422.     /*
  1423.      * Check if this is a DHCP request.
  1424.      */
  1425.     if (dhcp!=0) {
  1426.         if (!isme)
  1427.             return 0;    /* Not mine, discard! */
  1428.  
  1429.         switch (dhcp) {
  1430.          case 1 : len = dhcp_discover(bp,hp,vp,bytesleft-1); break;
  1431.          case 3 : len = dhcp_request(bp,hp,vp,bytesleft-1); break;
  1432.          case 4 : len = dhcp_decline(bp,hp,vp,bytesleft-1); break;
  1433.          case 7 : len = dhcp_release(bp,hp,vp,bytesleft-1); break;
  1434.          default : report(LOG_NOTICE,"Unknown DHCP request (%d)",dhcp);
  1435.                return 0;
  1436.         }
  1437.         /* Is there a DHCP reply at all? */
  1438.         if (len==0)
  1439.             return 0;
  1440.         vp += len;
  1441.         bytesleft -= len;
  1442.     }
  1443.     else {
  1444. #endif
  1445.         /*
  1446.          * The remaining options are inserted by the following
  1447.          * function (which is shared with bootpef.c).
  1448.          * Keep back one byte for the TAG_END.
  1449.          */
  1450.         len = dovend_rfc1497(hp, vp, bytesleft - 1);
  1451.         vp += len;
  1452.         bytesleft -= len;
  1453. #ifdef DHCP
  1454.     }
  1455. #endif
  1456.  
  1457.     /* There should be at least one byte left. */
  1458.     NEED(1, "(end)");
  1459.     *vp++ = TAG_END;
  1460.     bytesleft--;
  1461.  
  1462.     /* Log message done by caller. */
  1463.     if (bytesleft > 0) {
  1464.         /*
  1465.          * Zero out any remaining part of the vendor area.
  1466.          */
  1467.         bzero(vp, bytesleft);
  1468.     }
  1469.     return 1;    /* sent reply */
  1470. } /* dovend_rfc1048 */
  1471. #undef    NEED
  1472.  
  1473.  
  1474. /*
  1475.  * Now in readfile.c:
  1476.  *     hwlookcmp()
  1477.  *    iplookcmp()
  1478.  */
  1479.  
  1480. /* haddrtoa() - now in hwaddr.c */
  1481. /*
  1482.  * Now in dovend.c:
  1483.  * insert_ip()
  1484.  * insert_generic()
  1485.  * insert_u_long()
  1486.  */
  1487.  
  1488. /* get_errmsg() - now in report.c */
  1489.  
  1490.  
  1491. #ifdef DHCP
  1492.  
  1493. /*
  1494.  * PeP hic facet
  1495.  * Stuff the packet with the Lease info, We need to do this on the Offer and
  1496.  * the ack so separated out here
  1497.  */
  1498. PRIVATE
  1499. int dhcp_lease(bp, hp, vp)
  1500.     struct bootp *bp;
  1501.     struct host *hp;
  1502.     byte **vp;
  1503. {
  1504.     *(*vp)++ = TAG_DHCP_IPRENEW;    /* DHCP Renewal time 50% of lease */
  1505.     *(*vp)++ = 4;            /* Length */
  1506.     insert_u_long(htonl(hp->dhcp_lease/2),vp);
  1507.  
  1508.     *(*vp)++ = TAG_DHCP_IPREBIND;    /* DHCP Rebinding time 85% of lease */
  1509.     *(*vp)++ = 4;
  1510.     insert_u_long(htonl(hp->dhcp_lease*7/8),vp);
  1511.     
  1512.     *(*vp)++ = TAG_DHCP_IPLEASE;    /* IP address lease time */
  1513.     *(*vp)++ = 4;            /* Length */
  1514.     insert_u_long(htonl(hp->dhcp_lease),vp); /* PeP hic facet, lets see if this works */
  1515.  
  1516.     return(19);
  1517. }
  1518.  
  1519.  
  1520. /*
  1521.  * Formulate an DHCP_DISCOVER reply
  1522.  */
  1523. PRIVATE
  1524. int dhcp_discover(bp, hp, vp, bytesleft)
  1525.     struct bootp *bp;
  1526.     struct host *hp;
  1527.     byte *vp;
  1528.     int bytesleft;
  1529. {
  1530.     if(debug)
  1531.         report(LOG_INFO, "Received: DHCPDISCOVER");
  1532.     return(dhcp_offer(bp,hp,vp,bytesleft));
  1533. }
  1534.  
  1535. /*
  1536.  * formulate an DHCP_RELEASE reply
  1537.  */
  1538. PRIVATE
  1539. int dhcp_release(bp, hp, vp, bytesleft)
  1540.     struct bootp *bp;
  1541.     struct host *hp;
  1542.     byte *vp;
  1543.     int bytesleft;
  1544. {
  1545.     if (debug)
  1546.         report(LOG_INFO, "Received: DHCPRELEASE (discarded)");
  1547.     return 0;
  1548. }
  1549.  
  1550. PRIVATE
  1551. int dhcp_offer(bp, hp, vp, bytesleft)
  1552.     struct bootp *bp;
  1553.     struct host *hp;
  1554.     byte *vp;
  1555.     int bytesleft;
  1556. {
  1557.     int len=0;
  1558.     if (debug)
  1559.         report(LOG_INFO, "Sent: DHCPOFFER");
  1560.  
  1561.     bp->bp_secs = bp->bp_hops = 0;
  1562.     bp->bp_ciaddr.s_addr = 0;
  1563.  
  1564.     *vp++ = TAG_DHCP_MSG;        /* DHCP */
  1565.     *vp++ = 1;            /* length */
  1566.     *vp++ = 2;            /* DHCPOFFER */
  1567.     len +=  3;    
  1568.  
  1569.     len += dhcp_lease(bp,hp,&vp);
  1570.  
  1571.     *vp++ = TAG_DHCP_SERVERID;
  1572.     *vp++ = 4;
  1573.     insert_u_long(my_ip_addr.s_addr,&vp);
  1574.     len += 6;
  1575.  
  1576.     return len + dovend_rfc1497(hp, vp, bytesleft - len);
  1577. }
  1578.  
  1579. /*
  1580.  * Formulate an DHCP_REQUEST reply
  1581.  */
  1582. PRIVATE
  1583. int dhcp_request(bp, hp, vp, bytesleft)
  1584.     struct bootp *bp;
  1585.     struct host *hp;
  1586.     byte *vp;
  1587.     int bytesleft;
  1588. {
  1589.     bp->bp_secs = bp->bp_hops = 0;
  1590.  
  1591.     if(debug)
  1592.         report(LOG_INFO,"Received: DHCPREQUEST");
  1593.     /*
  1594.      * Make absolutely sure that if the client requests an address,
  1595.      * it is its own address, and also make sure the hardware
  1596.      * addresses match perfectly. We want to minimize spoofing!
  1597.      */
  1598.     if ((bp->bp_ciaddr.s_addr && bp->bp_ciaddr.s_addr!=bp->bp_yiaddr.s_addr) ||
  1599.         bp->bp_htype != hp->htype ||
  1600.             bcmp(bp->bp_chaddr, hp->haddr, haddrlength(hp->htype))) {
  1601.         if (debug)
  1602.             report(LOG_INFO, "Sent: DHCPNAK");
  1603.  
  1604.         *vp++ = TAG_DHCP_MSG;    /* DHCPNAK */
  1605.         *vp++ = 1;
  1606.         *vp++ = 6;
  1607.         return 3;
  1608.     }
  1609.     else 
  1610.         return(dhcp_ack(bp,hp,vp,bytesleft));    
  1611. }
  1612.  
  1613. PRIVATE
  1614. int dhcp_ack(bp, hp, vp, bytesleft)
  1615.     struct bootp *bp;
  1616.     struct host *hp;
  1617.     byte *vp;
  1618.     int bytesleft;
  1619. {
  1620.     int len=0;
  1621.     if (debug)
  1622.         report(LOG_INFO, "Sent: DHCPACK");
  1623.  
  1624.     *vp++ = TAG_DHCP_MSG;    /* DHCPACK */
  1625.     *vp++ = 1;
  1626.     *vp++ = 5;
  1627.     len += 3;
  1628.  
  1629.     len += dhcp_lease(bp,hp,&vp);
  1630.  
  1631.     *vp++ = TAG_DHCP_SERVERID;    /* Server id */
  1632.     *vp++ = 4;
  1633.     insert_u_long(my_ip_addr.s_addr,&vp);
  1634.     len += 6;
  1635.  
  1636.     return len + dovend_rfc1497(hp, vp, bytesleft - len);
  1637. }
  1638.  
  1639. /*
  1640.  * formulate an DHCP_DECLINE reply
  1641.  */
  1642. PRIVATE
  1643. int dhcp_decline(bp, hp, vp, bytesleft)
  1644.     struct bootp *bp;
  1645.     struct host *hp;
  1646.     byte *vp;
  1647.     int bytesleft;
  1648. {
  1649.     if (debug)
  1650.         report(LOG_INFO, "Recived: DHCPDECLINE (ignored)");
  1651.     return 0;
  1652. }
  1653. #endif
  1654.  
  1655. /*
  1656.  * Local Variables:
  1657.  * tab-width: 4
  1658.  * c-indent-level: 4
  1659.  * c-argdecl-indent: 4
  1660.  * c-continued-statement-offset: 4
  1661.  * c-continued-brace-offset: -4
  1662.  * c-label-offset: -4
  1663.  * c-brace-offset: 0
  1664.  * End:
  1665.  */
  1666.