1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
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.
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
22 ************************************************************************/
25 * BOOTP (bootstrap protocol) server daemon.
27 * Answers BOOTP request packets from booting client machines.
28 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
29 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
30 * See RFC 1395 for option tags 14-17.
31 * See accompanying man page -- bootpd.8
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
50 #include <sys/utsname.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h> /* inet_ntoa */
72 # include <fcntl.h> /* for O_RDONLY, etc */
77 /* Yes, memcpy is OK here (no overlapped copies). */
78 # define bcopy(a,b,c) memcpy(b,a,c)
79 # define bzero(p,l) memset(p,0,l)
80 # define bcmp(a,b,c) memcmp(a,b,c)
92 #include "patchlevel.h"
95 #define CONFIG_FILE "/etc/bootptab"
98 #define DUMPTAB_FILE "/tmp/bootpd.dump"
104 * Externals, forward declarations, and global variables
107 extern void dumptab(char *);
109 PRIVATE void catcher(int);
110 PRIVATE int chk_access(char *, int32 *);
112 PRIVATE void dovend_cmu(struct bootp *, struct host *);
114 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
115 PRIVATE void handle_reply(void);
116 PRIVATE void handle_request(void);
117 PRIVATE void sendreply(int forward, int32 dest_override);
118 PRIVATE void usage(void);
121 * IP port numbers for client and server obtained from /etc/services
124 u_short bootps_port, bootpc_port;
128 * Internet socket and interface config structures
131 struct sockaddr_in bind_addr; /* Listening */
132 struct sockaddr_in recv_addr; /* Packet source */
133 struct sockaddr_in send_addr; /* destination */
139 int debug = 0; /* Debugging flag (level) */
140 struct timeval actualtimeout =
141 { /* fifteen minutes */
142 15 * 60L, /* tv_sec */
150 int s; /* Socket file descriptor */
151 char *pktbuf; /* Receive packet buffer */
155 struct in_addr my_ip_addr;
157 static const char *hostname;
158 static char default_hostname[MAXHOSTNAMELEN];
160 /* Flags set by signal catcher. */
161 PRIVATE int do_readtab = 0;
162 PRIVATE int do_dumptab = 0;
165 * Globals below are associated with the bootp database file (bootptab).
168 char *bootptab = CONFIG_FILE;
169 char *bootpd_dump = DUMPTAB_FILE;
174 * Initialization such as command-line processing is done and then the
175 * main server loop is started.
183 struct timeval *timeout;
185 struct servent *servp;
188 socklen_t ba_len, ra_len;
193 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
197 progname = strrchr(argv[0], '/');
198 if (progname) progname++;
199 else progname = argv[0];
202 * Initialize logging.
204 report_init(0); /* uses progname */
209 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
211 /* Debugging for compilers with struct padding. */
212 assert(sizeof(struct bootp) == BP_MINPKTSZ);
214 /* Get space for receiving packets and composing replies. */
215 pktbuf = malloc(MAX_MSG_SIZE);
217 report(LOG_ERR, "malloc failed");
220 bp = (struct bootp *) pktbuf;
223 * Check to see if a socket was passed to us from inetd.
225 * Use getsockname() to determine if descriptor 0 is indeed a socket
226 * (and thus we are probably a child of inetd) or if it is instead
227 * something else and we are running standalone.
230 ba_len = sizeof(bind_addr);
231 bzero((char *) &bind_addr, ba_len);
234 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
236 * Descriptor 0 is a socket. Assume we are a child of inetd.
238 if (bind_addr.sin_family == AF_INET) {
240 bootps_port = ntohs(bind_addr.sin_port);
242 /* Some other type of socket? */
243 report(LOG_ERR, "getsockname: not an INET socket");
248 * Set defaults that might be changed by option switches.
251 timeout = &actualtimeout;
253 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
254 report(LOG_ERR, "bootpd: can't get hostname\n");
257 default_hostname[sizeof(default_hostname) - 1] = '\0';
258 hostname = default_hostname;
263 for (argc--, argv++; argc > 0; argc--, argv++) {
264 if (argv[0][0] != '-')
266 switch (argv[0][1]) {
268 case 'c': /* chdir_path */
270 stmp = &(argv[0][2]);
276 if (!stmp || (stmp[0] != '/')) {
278 "bootpd: invalid chdir specification\n");
284 case 'd': /* debug level */
286 stmp = &(argv[0][2]);
287 } else if (argv[1] && argv[1][0] == '-') {
289 * Backwards-compatible behavior:
290 * no parameter, so just increment the debug flag.
299 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
301 "%s: invalid debug level\n", progname);
307 case 'h': /* override hostname */
309 stmp = &(argv[0][2]);
317 "bootpd: missing hostname\n");
323 case 'i': /* inetd mode */
327 case 's': /* standalone mode */
331 case 't': /* timeout */
333 stmp = &(argv[0][2]);
339 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
341 "%s: invalid timeout specification\n", progname);
344 actualtimeout.tv_sec = (int32) (60 * n);
346 * If the actual timeout is zero, pass a NULL pointer
347 * to select so it blocks indefinitely, otherwise,
348 * point to the actual timeout value.
350 timeout = (n > 0) ? &actualtimeout : NULL;
354 report(LOG_ERR, "%s: unknown switch: -%c\n",
355 progname, argv[0][1]);
363 * Override default file names if specified on the command line.
369 bootpd_dump = argv[1];
372 * Get my hostname and IP address.
375 hep = gethostbyname(hostname);
377 report(LOG_ERR, "Can not get my IP address\n");
380 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
384 * Go into background and disassociate from controlling terminal.
392 n = open(_PATH_TTY, O_RDWR);
394 ioctl(n, TIOCNOTTY, (char *) 0);
397 #endif /* TIOCNOTTY */
405 * Nuke any timeout value
409 } /* if standalone (1st) */
411 /* Set the cwd (i.e. to /tftpboot) */
413 if (chdir(chdir_path) < 0)
414 report(LOG_ERR, "%s: chdir failed", chdir_path);
417 /* Get the timezone. */
420 /* Allocate hash tables. */
424 * Read the bootptab file.
426 readtab(1); /* force read */
433 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
434 report(LOG_ERR, "socket: %s", get_network_errmsg());
439 * Get server's listening port number
441 servp = getservbyname("bootps", "udp");
443 bootps_port = ntohs((u_short) servp->s_port);
445 bootps_port = (u_short) IPPORT_BOOTPS;
447 "bootps/udp: unknown service -- using port %d",
452 * Bind socket to BOOTPS port.
454 bind_addr.sin_family = AF_INET;
455 bind_addr.sin_addr.s_addr = INADDR_ANY;
456 bind_addr.sin_port = htons(bootps_port);
457 if (bind(s, (struct sockaddr *) &bind_addr,
458 sizeof(bind_addr)) < 0)
460 report(LOG_ERR, "bind: %s", get_network_errmsg());
463 } /* if standalone (2nd)*/
466 * Get destination port number so we can reply to client
468 servp = getservbyname("bootpc", "udp");
470 bootpc_port = ntohs(servp->s_port);
473 "bootpc/udp: unknown service -- using port %d",
475 bootpc_port = (u_short) IPPORT_BOOTPC;
479 * Set up signals to read or dump the table.
481 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
482 sa.sa_handler = catcher;
483 sigemptyset(&sa.sa_mask);
485 if (sigaction(SIGHUP, &sa, NULL) < 0) {
486 report(LOG_ERR, "sigaction: %s", get_errmsg());
489 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
490 report(LOG_ERR, "sigaction: %s", get_errmsg());
493 #else /* SA_NOCLDSTOP */
494 /* Old-fashioned UNIX signals */
495 if ((int) signal(SIGHUP, catcher) < 0) {
496 report(LOG_ERR, "signal: %s", get_errmsg());
499 if ((int) signal(SIGUSR1, catcher) < 0) {
500 report(LOG_ERR, "signal: %s", get_errmsg());
503 #endif /* SA_NOCLDSTOP */
506 * Process incoming requests.
516 nfound = select(s + 1, &readfds, NULL, NULL,
517 (timeout) ? &tv : NULL);
519 if (errno != EINTR) {
520 report(LOG_ERR, "select: %s", get_errmsg());
523 * Call readtab() or dumptab() here to avoid the
524 * dangers of doing I/O from a signal handler.
528 readtab(1); /* force read */
532 dumptab(bootpd_dump);
536 if (!FD_ISSET(s, &readfds)) {
538 report(LOG_INFO, "exiting after %ld minutes of inactivity",
539 actualtimeout.tv_sec / 60);
542 ra_len = sizeof(recv_addr);
543 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
544 (struct sockaddr *) &recv_addr, &ra_len);
549 report(LOG_INFO, "recvd pkt from IP addr %s",
550 inet_ntoa(recv_addr.sin_addr));
552 if (n < sizeof(struct bootp)) {
554 report(LOG_NOTICE, "received short packet");
560 readtab(0); /* maybe re-read bootptab */
578 * Print "usage" message and exit
585 "usage: bootpd [-i | -s] [-c chdir-path] [-d level] [-h hostname] [-t timeout]\n");
586 fprintf(stderr, " [bootptab [dumpfile]]\n");
587 fprintf(stderr, "\t -c n\tset current directory\n");
588 fprintf(stderr, "\t -d n\tset debug level\n");
589 fprintf(stderr, "\t -h n\tset the hostname to listen on\n");
590 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
591 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
592 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
596 /* Signal catchers */
605 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
606 /* For older "System V" derivatives with no sigaction(). */
607 signal(sig, catcher);
614 * Process BOOTREQUEST packet.
616 * Note: This version of the bootpd.c server never forwards
617 * a request to another server. That is the job of a gateway
618 * program such as the "bootpgw" program included here.
620 * (Also this version does not interpret the hostname field of
621 * the request packet; it COULD do a name->address lookup and
622 * forward the request there.)
627 struct bootp *bp = (struct bootp *) pktbuf;
628 struct host *hp = NULL;
629 struct host dummyhost;
631 unsigned hlen, hashcode;
635 char *homedir, *bootfile;
638 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
640 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
643 * If the servername field is set, compare it against us.
644 * If we're not being addressed, ignore this request.
645 * If the server name field is null, throw in our name.
647 if (strlen(bp->bp_sname)) {
648 if (strcmp(bp->bp_sname, hostname)) {
651 ignoring request for server %s from client at %s address %s",
652 bp->bp_sname, netname(bp->bp_htype),
653 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
654 /* XXX - Is it correct to ignore such a request? -gwr */
658 strcpy(bp->bp_sname, hostname);
661 /* Convert the request into a reply. */
662 bp->bp_op = BOOTREPLY;
663 if (bp->bp_ciaddr.s_addr == 0) {
665 * client doesnt know his IP address,
666 * search by hardware address.
669 report(LOG_INFO, "request from %s address %s",
670 netname(bp->bp_htype),
671 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
673 hlen = haddrlength(bp->bp_htype);
674 if (hlen != bp->bp_hlen) {
675 report(LOG_NOTICE, "bad addr len from %s address %s",
676 netname(bp->bp_htype),
677 haddrtoa(bp->bp_chaddr, hlen));
679 dummyhost.htype = bp->bp_htype;
680 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
681 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
682 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
685 bp->bp_htype == HTYPE_IEEE802)
687 /* Try again with address in "canonical" form. */
688 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
691 HW addr type is IEEE 802. convert to %s and check again\n",
692 haddrtoa(dummyhost.haddr, bp->bp_hlen));
694 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
695 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
696 hwlookcmp, &dummyhost);
700 * XXX - Add dynamic IP address assignment?
703 report(LOG_NOTICE, "unknown client %s address %s",
704 netname(bp->bp_htype),
705 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
706 return; /* not found */
708 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
713 * search by IP address.
716 report(LOG_INFO, "request from IP addr %s",
717 inet_ntoa(bp->bp_ciaddr));
719 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
720 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
721 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
725 report(LOG_NOTICE, "IP address not found: %s",
726 inet_ntoa(bp->bp_ciaddr));
733 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
734 hp->hostname->string);
738 * If there is a response delay threshold, ignore requests
739 * with a timestamp lower than the threshold.
741 if (hp->flags.min_wait) {
742 u_int32 t = (u_int32) ntohs(bp->bp_secs);
743 if (t < hp->min_wait) {
746 "ignoring request due to timestamp (%d < %d)",
752 #ifdef YORK_EX_OPTION
754 * The need for the "ex" tag arose out of the need to empty
755 * shared networked drives on diskless PCs. This solution is
756 * not very clean but it does work fairly well.
757 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
759 * XXX - This could compromise security if a non-trusted user
760 * managed to write an entry in the bootptab with :ex=trojan:
761 * so I would leave this turned off unless you need it. -gwr
763 /* Run a program, passing the client name as a parameter. */
764 if (hp->flags.exec_file) {
766 /* XXX - Check string lengths? -gwr */
767 strcpy (tst, hp->exec_file->string);
769 strcat (tst, hp->hostname->string);
772 report(LOG_INFO, "executing %s", tst);
773 system(tst); /* Hope this finishes soon... */
775 #endif /* YORK_EX_OPTION */
778 * If a specific TFTP server address was specified in the bootptab file,
779 * fill it in, otherwise zero it.
780 * XXX - Rather than zero it, should it be the bootpd address? -gwr
782 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
783 hp->bootserver.s_addr : 0L;
785 #ifdef STANFORD_PROM_COMPAT
787 * Stanford bootp PROMs (for a Sun?) have no way to leave
788 * the boot file name field blank (because the boot file
789 * name is automatically generated from some index).
790 * As a work-around, this little hack allows those PROMs to
791 * specify "sunboot14" with the same effect as a NULL name.
792 * (The user specifies boot device 14 or some such magic.)
794 if (strcmp(bp->bp_file, "sunboot14") == 0)
795 bp->bp_file[0] = '\0'; /* treat it as unspecified */
799 * Fill in the client's proper bootfile.
801 * If the client specifies an absolute path, try that file with a
802 * ".host" suffix and then without. If the file cannot be found, no
803 * reply is made at all.
805 * If the client specifies a null or relative file, use the following
806 * table to determine the appropriate action:
808 * Homedir Bootfile Client's file
809 * specified? specified? specification Action
810 * -------------------------------------------------------------------
811 * No No Null Send null filename
812 * No No Relative Discard request
813 * No Yes Null Send if absolute else null
814 * No Yes Relative Discard request *XXX
815 * Yes No Null Send null filename
816 * Yes No Relative Lookup with ".host"
817 * Yes Yes Null Send home/boot or bootfile
818 * Yes Yes Relative Lookup with ".host" *XXX
823 * XXX - I don't like the policy of ignoring a client when the
824 * boot file is not accessible. The TFTP server might not be
825 * running on the same machine as the BOOTP server, in which
826 * case checking accessibility of the boot file is pointless.
828 * Therefore, file accessibility is now demanded ONLY if you
829 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
833 * The "real" path is as seen by the BOOTP daemon on this
834 * machine, while the client path is relative to the TFTP
835 * daemon chroot directory (i.e. /tftpboot).
837 if (hp->flags.tftpdir) {
838 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
839 clntpath = &realpath[strlen(realpath)];
846 * Determine client's requested homedir and bootfile.
850 if (bp->bp_file[0]) {
851 homedir = bp->bp_file;
852 bootfile = strrchr(homedir, '/');
854 if (homedir == bootfile)
858 /* no "/" in the string */
863 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
864 (homedir) ? homedir : "",
865 (bootfile) ? bootfile : "");
870 * Specifications in bootptab override client requested values.
872 if (hp->flags.homedir)
873 homedir = hp->homedir->string;
874 if (hp->flags.bootfile)
875 bootfile = hp->bootfile->string;
878 * Construct bootfile path.
881 if (homedir[0] != '/')
882 strcat(clntpath, "/");
883 strcat(clntpath, homedir);
887 if (bootfile[0] != '/')
888 strcat(clntpath, "/");
889 strcat(clntpath, bootfile);
894 * First try to find the file with a ".host" suffix
896 n = strlen(clntpath);
897 strcat(clntpath, ".");
898 strcat(clntpath, hp->hostname->string);
899 if (chk_access(realpath, &bootsize) < 0) {
900 clntpath[n] = 0; /* Try it without the suffix */
901 if (chk_access(realpath, &bootsize) < 0) {
902 /* neither "file.host" nor "file" was found */
903 #ifdef CHECK_FILE_ACCESS
905 if (bp->bp_file[0]) {
907 * Client wanted specific file
908 * and we didn't have it.
911 "requested file not found: \"%s\"", clntpath);
915 * Client didn't ask for a specific file and we couldn't
916 * access the default file, so just zero-out the bootfile
917 * field in the packet and continue processing the reply.
919 bzero(bp->bp_file, sizeof(bp->bp_file));
922 #else /* CHECK_FILE_ACCESS */
924 /* Complain only if boot file size was needed. */
925 if (hp->flags.bootsize_auto) {
926 report(LOG_ERR, "can not determine size of file \"%s\"",
930 #endif /* CHECK_FILE_ACCESS */
933 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
935 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
937 #ifdef CHECK_FILE_ACCESS
939 #endif /* CHECK_FILE_ACCESS */
943 * Handle vendor options based on magic number.
947 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
948 (int) ((bp->bp_vend)[0]),
949 (int) ((bp->bp_vend)[1]),
950 (int) ((bp->bp_vend)[2]),
951 (int) ((bp->bp_vend)[3]));
954 * If this host isn't set for automatic vendor info then copy the
955 * specific cookie into the bootp packet, thus forcing a certain
956 * reply format. Only force reply format if user specified it.
958 if (hp->flags.vm_cookie) {
959 /* Slam in the user specified magic number. */
960 bcopy(hp->vm_cookie, bp->bp_vend, 4);
963 * Figure out the format for the vendor-specific info.
964 * Note that bp->bp_vend may have been set above.
966 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
967 /* RFC1048 conformant bootp client */
968 dovend_rfc1048(bp, hp, bootsize);
970 report(LOG_INFO, "sending reply (with RFC1048 options)");
974 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
977 report(LOG_INFO, "sending reply (with CMU options)");
983 report(LOG_INFO, "sending reply (with no options)");
987 dest = (hp->flags.reply_addr) ?
988 hp->reply_addr.s_addr : 0L;
996 * Process BOOTREPLY packet.
1002 report(LOG_INFO, "processing boot reply");
1004 /* forwarded, no destination override */
1010 * Send a reply packet to the client. 'forward' flag is set if we are
1011 * not the originator of this reply packet.
1014 sendreply(forward, dst_override)
1018 struct bootp *bp = (struct bootp *) pktbuf;
1020 u_short port = bootpc_port;
1025 * XXX - Should honor bp_flags "broadcast" bit here.
1026 * Temporary workaround: use the :ra=ADDR: option to
1027 * set the reply address to the broadcast address.
1031 * If the destination address was specified explicitly
1032 * (i.e. the broadcast address for HP compatibility)
1033 * then send the response to that address. Otherwise,
1034 * act in accordance with RFC951:
1035 * If the client IP address is specified, use that
1036 * else if gateway IP address is specified, use that
1037 * else make a temporary arp cache entry for the client's
1038 * NEW IP/hardware address and use that.
1041 dst.s_addr = dst_override;
1043 report(LOG_INFO, "reply address override: %s",
1046 } else if (bp->bp_ciaddr.s_addr) {
1047 dst = bp->bp_ciaddr;
1048 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1049 dst = bp->bp_giaddr;
1052 report(LOG_INFO, "sending reply to gateway %s",
1056 dst = bp->bp_yiaddr;
1059 if (len > MAXHADDRLEN)
1061 haf = (int) bp->bp_htype;
1063 haf = HTYPE_ETHERNET;
1066 report(LOG_INFO, "setarp %s - %s",
1067 inet_ntoa(dst), haddrtoa(ha, len));
1068 setarp(s, &dst, haf, ha, len);
1071 if ((forward == 0) &&
1072 (bp->bp_siaddr.s_addr == 0))
1075 struct in_addr siaddr;
1077 * If we are originating this reply, we
1078 * need to find our own interface address to
1079 * put in the bp_siaddr field of the reply.
1080 * If this server is multi-homed, pick the
1081 * 'best' interface (the one on the same net
1082 * as the client). Of course, the client may
1083 * be on the other side of a BOOTP gateway...
1085 ifr = getif(s, &dst);
1087 struct sockaddr_in *sip;
1088 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1089 siaddr = sip->sin_addr;
1091 /* Just use my "official" IP address. */
1092 siaddr = my_ip_addr;
1095 /* XXX - No need to set bp_giaddr here. */
1097 /* Finally, set the server address field. */
1098 bp->bp_siaddr = siaddr;
1100 /* Set up socket address for send. */
1101 send_addr.sin_family = AF_INET;
1102 send_addr.sin_port = htons(port);
1103 send_addr.sin_addr = dst;
1105 /* Send reply with same size packet as request used. */
1106 if (sendto(s, pktbuf, pktlen, 0,
1107 (struct sockaddr *) &send_addr,
1108 sizeof(send_addr)) < 0)
1110 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1115 /* nmatch() - now in getif.c */
1116 /* setarp() - now in hwaddr.c */
1120 * This call checks read access to a file. It returns 0 if the file given
1121 * by "path" exists and is publically readable. A value of -1 is returned if
1122 * access is not permitted or an error occurs. Successful calls also
1123 * return the file size in bytes using the long pointer "filesize".
1125 * The read permission bit for "other" users is checked. This bit must be
1126 * set for tftpd(8) to allow clients to read the file.
1130 chk_access(path, filesize)
1136 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1137 *filesize = (int32) st.st_size;
1146 * Now in dumptab.c :
1149 * list_ipaddresses()
1155 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1156 * bootp packet pointed to by "bp".
1164 struct cmu_vend *vendp;
1165 struct in_addr_list *taddr;
1168 * Initialize the entire vendor field to zeroes.
1170 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1173 * Fill in vendor information. Subnet mask, default gateway,
1174 * domain name server, ien name server, time server
1176 vendp = (struct cmu_vend *) bp->bp_vend;
1177 strcpy(vendp->v_magic, (char *)vm_cmu);
1178 if (hp->flags.subnet_mask) {
1179 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1180 (vendp->v_flags) |= VF_SMASK;
1181 if (hp->flags.gateway) {
1182 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1185 if (hp->flags.domain_server) {
1186 taddr = hp->domain_server;
1187 if (taddr->addrcount > 0) {
1188 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1189 if (taddr->addrcount > 1) {
1190 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1194 if (hp->flags.name_server) {
1195 taddr = hp->name_server;
1196 if (taddr->addrcount > 0) {
1197 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1198 if (taddr->addrcount > 1) {
1199 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1203 if (hp->flags.time_server) {
1204 taddr = hp->time_server;
1205 if (taddr->addrcount > 0) {
1206 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1207 if (taddr->addrcount > 1) {
1208 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1212 /* Log message now done by caller. */
1215 #endif /* VEND_CMU */
1220 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1221 * bootp packet pointed to by "bp".
1223 #define NEED(LEN, MSG) do \
1224 if (bytesleft < (LEN)) { \
1225 report(LOG_NOTICE, noroom, \
1226 hp->hostname->string, MSG); \
1230 dovend_rfc1048(bp, hp, bootsize)
1238 static const char noroom[] = "%s: No room for \"%s\" option";
1242 if (hp->flags.msg_size) {
1243 pktlen = hp->msg_size;
1246 * If the request was longer than the official length, build
1247 * a response of that same length where the additional length
1248 * is assumed to be part of the bp_vend (options) area.
1250 if (pktlen > sizeof(*bp)) {
1252 report(LOG_INFO, "request message length=%d", pktlen);
1255 * Check whether the request contains the option:
1256 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1257 * and if so, override the response length with its value.
1258 * This request must lie within the first BP_VEND_LEN
1259 * bytes of the option space.
1267 ep = p + BP_VEND_LEN - 4;
1270 /* Check for tags with no data first. */
1275 /* Now scan the length byte. */
1280 bcopy(p, (char*)&msgsz, 2);
1281 msgsz = ntohs(msgsz);
1284 case TAG_SUBNET_MASK:
1285 /* XXX - Should preserve this if given... */
1291 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1293 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1294 pktlen = msgsz - BP_MSG_OVERHEAD;
1299 if (pktlen < sizeof(*bp)) {
1300 report(LOG_ERR, "invalid response length=%d", pktlen);
1301 pktlen = sizeof(*bp);
1303 bytesleft = ((byte*)bp + pktlen) - vp;
1304 if (pktlen > sizeof(*bp)) {
1306 report(LOG_INFO, "extended reply, length=%d, options=%d",
1310 /* Copy in the magic cookie */
1311 bcopy(vm_rfc1048, vp, 4);
1315 if (hp->flags.subnet_mask) {
1316 /* always enough room here. */
1317 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1318 *vp++ = 4; /* -1 byte */
1319 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1320 bytesleft -= 6; /* Fix real count */
1321 if (hp->flags.gateway) {
1322 (void) insert_ip(TAG_GATEWAY,
1327 if (hp->flags.bootsize) {
1328 /* always enough room here */
1329 bootsize = (hp->flags.bootsize_auto) ?
1330 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1331 *vp++ = TAG_BOOT_SIZE;
1333 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1334 *vp++ = (byte) (bootsize & 0xFF);
1335 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1338 * This one is special: Remaining options go in the ext file.
1339 * Only the subnet_mask, bootsize, and gateway should precede.
1341 if (hp->flags.exten_file) {
1343 * Check for room for exten_file. Add 3 to account for
1344 * TAG_EXTEN_FILE, length, and TAG_END.
1346 len = strlen(hp->exten_file->string);
1347 NEED((len + 3), "ef");
1348 *vp++ = TAG_EXTEN_FILE;
1349 *vp++ = (byte) (len & 0xFF);
1350 bcopy(hp->exten_file->string, vp, len);
1353 bytesleft -= len + 3;
1354 return; /* no more options here. */
1357 * The remaining options are inserted by the following
1358 * function (which is shared with bootpef.c).
1359 * Keep back one byte for the TAG_END.
1361 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1365 /* There should be at least one byte left. */
1370 /* Log message done by caller. */
1371 if (bytesleft > 0) {
1373 * Zero out any remaining part of the vendor area.
1375 bzero(vp, bytesleft);
1377 } /* dovend_rfc1048 */
1382 * Now in readfile.c:
1387 /* haddrtoa() - now in hwaddr.c */
1395 /* get_errmsg() - now in report.c */
1401 * c-argdecl-indent: 4
1402 * c-continued-statement-offset: 4
1403 * c-continued-brace-offset: -4
1404 * c-label-offset: -4