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 */
73 # include <fcntl.h> /* for O_RDONLY, etc */
78 /* Yes, memcpy is OK here (no overlapped copies). */
79 # define bcopy(a,b,c) memcpy(b,a,c)
80 # define bzero(p,l) memset(p,0,l)
81 # define bcmp(a,b,c) memcmp(a,b,c)
93 #include "patchlevel.h"
96 #define CONFIG_FILE "/etc/bootptab"
99 #define DUMPTAB_FILE "/tmp/bootpd.dump"
105 * Externals, forward declarations, and global variables
108 extern void dumptab(char *);
110 PRIVATE void catcher(int);
111 PRIVATE int chk_access(char *, int32 *);
113 PRIVATE void dovend_cmu(struct bootp *, struct host *);
115 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
116 PRIVATE void handle_reply(void);
117 PRIVATE void handle_request(void);
118 PRIVATE void sendreply(int forward, int32 dest_override);
119 PRIVATE void usage(void);
122 * IP port numbers for client and server obtained from /etc/services
125 u_short bootps_port, bootpc_port;
129 * Internet socket and interface config structures
132 struct sockaddr_in bind_addr; /* Listening */
133 struct sockaddr_in recv_addr; /* Packet source */
134 struct sockaddr_in send_addr; /* destination */
140 int debug = 0; /* Debugging flag (level) */
141 struct timeval actualtimeout =
142 { /* fifteen minutes */
143 15 * 60L, /* tv_sec */
151 int s; /* Socket file descriptor */
152 char *pktbuf; /* Receive packet buffer */
156 struct in_addr my_ip_addr;
158 static const char *hostname;
159 static char default_hostname[MAXHOSTNAMELEN];
161 /* Flags set by signal catcher. */
162 PRIVATE int do_readtab = 0;
163 PRIVATE int do_dumptab = 0;
166 * Globals below are associated with the bootp database file (bootptab).
169 char *bootptab = CONFIG_FILE;
170 char *bootpd_dump = DUMPTAB_FILE;
175 * Initialization such as command-line processing is done and then the
176 * main server loop is started.
184 struct timeval *timeout;
186 struct servent *servp;
189 socklen_t ba_len, ra_len;
194 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
198 progname = strrchr(argv[0], '/');
199 if (progname) progname++;
200 else progname = argv[0];
203 * Initialize logging.
205 report_init(0); /* uses progname */
210 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
212 /* Debugging for compilers with struct padding. */
213 assert(sizeof(struct bootp) == BP_MINPKTSZ);
215 /* Get space for receiving packets and composing replies. */
216 pktbuf = malloc(MAX_MSG_SIZE);
218 report(LOG_ERR, "malloc failed");
221 bp = (struct bootp *) pktbuf;
224 * Check to see if a socket was passed to us from inetd.
226 * Use getsockname() to determine if descriptor 0 is indeed a socket
227 * (and thus we are probably a child of inetd) or if it is instead
228 * something else and we are running standalone.
231 ba_len = sizeof(bind_addr);
232 bzero((char *) &bind_addr, ba_len);
235 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
237 * Descriptor 0 is a socket. Assume we are a child of inetd.
239 if (bind_addr.sin_family == AF_INET) {
241 bootps_port = ntohs(bind_addr.sin_port);
243 /* Some other type of socket? */
244 report(LOG_ERR, "getsockname: not an INET socket");
249 * Set defaults that might be changed by option switches.
252 timeout = &actualtimeout;
254 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
255 report(LOG_ERR, "bootpd: can't get hostname\n");
258 default_hostname[sizeof(default_hostname) - 1] = '\0';
259 hostname = default_hostname;
264 for (argc--, argv++; argc > 0; argc--, argv++) {
265 if (argv[0][0] != '-')
267 switch (argv[0][1]) {
269 case 'c': /* chdir_path */
271 stmp = &(argv[0][2]);
277 if (!stmp || (stmp[0] != '/')) {
279 "bootpd: invalid chdir specification\n");
285 case 'd': /* debug level */
287 stmp = &(argv[0][2]);
288 } else if (argv[1] && argv[1][0] == '-') {
290 * Backwards-compatible behavior:
291 * no parameter, so just increment the debug flag.
300 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
302 "%s: invalid debug level\n", progname);
308 case 'h': /* override hostname */
310 stmp = &(argv[0][2]);
318 "bootpd: missing hostname\n");
324 case 'i': /* inetd mode */
328 case 's': /* standalone mode */
332 case 't': /* timeout */
334 stmp = &(argv[0][2]);
340 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
342 "%s: invalid timeout specification\n", progname);
345 actualtimeout.tv_sec = (int32) (60 * n);
347 * If the actual timeout is zero, pass a NULL pointer
348 * to select so it blocks indefinitely, otherwise,
349 * point to the actual timeout value.
351 timeout = (n > 0) ? &actualtimeout : NULL;
355 report(LOG_ERR, "%s: unknown switch: -%c\n",
356 progname, argv[0][1]);
364 * Override default file names if specified on the command line.
370 bootpd_dump = argv[1];
373 * Get my hostname and IP address.
376 hep = gethostbyname(hostname);
378 report(LOG_ERR, "Can not get my IP address\n");
381 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
385 * Go into background and disassociate from controlling terminal.
393 n = open(_PATH_TTY, O_RDWR);
395 ioctl(n, TIOCNOTTY, (char *) 0);
398 #endif /* TIOCNOTTY */
406 * Nuke any timeout value
410 } /* if standalone (1st) */
412 /* Set the cwd (i.e. to /tftpboot) */
414 if (chdir(chdir_path) < 0)
415 report(LOG_ERR, "%s: chdir failed", chdir_path);
418 /* Get the timezone. */
421 /* Allocate hash tables. */
425 * Read the bootptab file.
427 readtab(1); /* force read */
434 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
435 report(LOG_ERR, "socket: %s", get_network_errmsg());
440 * Get server's listening port number
442 servp = getservbyname("bootps", "udp");
444 bootps_port = ntohs((u_short) servp->s_port);
446 bootps_port = (u_short) IPPORT_BOOTPS;
448 "bootps/udp: unknown service -- using port %d",
453 * Bind socket to BOOTPS port.
455 bind_addr.sin_family = AF_INET;
456 bind_addr.sin_addr.s_addr = INADDR_ANY;
457 bind_addr.sin_port = htons(bootps_port);
458 if (bind(s, (struct sockaddr *) &bind_addr,
459 sizeof(bind_addr)) < 0)
461 report(LOG_ERR, "bind: %s", get_network_errmsg());
464 } /* if standalone (2nd)*/
467 * Get destination port number so we can reply to client
469 servp = getservbyname("bootpc", "udp");
471 bootpc_port = ntohs(servp->s_port);
474 "bootpc/udp: unknown service -- using port %d",
476 bootpc_port = (u_short) IPPORT_BOOTPC;
480 * Set up signals to read or dump the table.
482 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
483 sa.sa_handler = catcher;
484 sigemptyset(&sa.sa_mask);
486 if (sigaction(SIGHUP, &sa, NULL) < 0) {
487 report(LOG_ERR, "sigaction: %s", get_errmsg());
490 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
491 report(LOG_ERR, "sigaction: %s", get_errmsg());
494 #else /* SA_NOCLDSTOP */
495 /* Old-fashioned UNIX signals */
496 if ((int) signal(SIGHUP, catcher) < 0) {
497 report(LOG_ERR, "signal: %s", get_errmsg());
500 if ((int) signal(SIGUSR1, catcher) < 0) {
501 report(LOG_ERR, "signal: %s", get_errmsg());
504 #endif /* SA_NOCLDSTOP */
507 * Process incoming requests.
517 nfound = select(s + 1, &readfds, NULL, NULL,
518 (timeout) ? &tv : NULL);
520 if (errno != EINTR) {
521 report(LOG_ERR, "select: %s", get_errmsg());
524 * Call readtab() or dumptab() here to avoid the
525 * dangers of doing I/O from a signal handler.
529 readtab(1); /* force read */
533 dumptab(bootpd_dump);
537 if (!FD_ISSET(s, &readfds)) {
539 report(LOG_INFO, "exiting after %jd minutes of inactivity",
540 (intmax_t)actualtimeout.tv_sec / 60);
543 ra_len = sizeof(recv_addr);
544 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
545 (struct sockaddr *) &recv_addr, &ra_len);
550 report(LOG_INFO, "recvd pkt from IP addr %s",
551 inet_ntoa(recv_addr.sin_addr));
553 if (n < sizeof(struct bootp)) {
555 report(LOG_NOTICE, "received short packet");
561 readtab(0); /* maybe re-read bootptab */
579 * Print "usage" message and exit
586 "usage: bootpd [-i | -s] [-c chdir-path] [-d level] [-h hostname] [-t timeout]\n");
587 fprintf(stderr, " [bootptab [dumpfile]]\n");
588 fprintf(stderr, "\t -c n\tset current directory\n");
589 fprintf(stderr, "\t -d n\tset debug level\n");
590 fprintf(stderr, "\t -h n\tset the hostname to listen on\n");
591 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
592 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
593 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
597 /* Signal catchers */
606 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
607 /* For older "System V" derivatives with no sigaction(). */
608 signal(sig, catcher);
615 * Process BOOTREQUEST packet.
617 * Note: This version of the bootpd.c server never forwards
618 * a request to another server. That is the job of a gateway
619 * program such as the "bootpgw" program included here.
621 * (Also this version does not interpret the hostname field of
622 * the request packet; it COULD do a name->address lookup and
623 * forward the request there.)
628 struct bootp *bp = (struct bootp *) pktbuf;
629 struct host *hp = NULL;
630 struct host dummyhost;
632 unsigned hlen, hashcode;
636 char *homedir, *bootfile;
639 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
641 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
644 * If the servername field is set, compare it against us.
645 * If we're not being addressed, ignore this request.
646 * If the server name field is null, throw in our name.
648 if (strlen(bp->bp_sname)) {
649 if (strcmp(bp->bp_sname, hostname)) {
652 ignoring request for server %s from client at %s address %s",
653 bp->bp_sname, netname(bp->bp_htype),
654 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
655 /* XXX - Is it correct to ignore such a request? -gwr */
659 strcpy(bp->bp_sname, hostname);
662 /* Convert the request into a reply. */
663 bp->bp_op = BOOTREPLY;
664 if (bp->bp_ciaddr.s_addr == 0) {
666 * client doesn't know his IP address,
667 * search by hardware address.
670 report(LOG_INFO, "request from %s address %s",
671 netname(bp->bp_htype),
672 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
674 hlen = haddrlength(bp->bp_htype);
675 if (hlen != bp->bp_hlen) {
676 report(LOG_NOTICE, "bad addr len from %s address %s",
677 netname(bp->bp_htype),
678 haddrtoa(bp->bp_chaddr, hlen));
680 dummyhost.htype = bp->bp_htype;
681 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
682 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
683 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
686 bp->bp_htype == HTYPE_IEEE802)
688 /* Try again with address in "canonical" form. */
689 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
692 HW addr type is IEEE 802. convert to %s and check again\n",
693 haddrtoa(dummyhost.haddr, bp->bp_hlen));
695 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
696 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
697 hwlookcmp, &dummyhost);
701 * XXX - Add dynamic IP address assignment?
704 report(LOG_NOTICE, "unknown client %s address %s",
705 netname(bp->bp_htype),
706 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
707 return; /* not found */
709 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
714 * search by IP address.
717 report(LOG_INFO, "request from IP addr %s",
718 inet_ntoa(bp->bp_ciaddr));
720 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
721 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
722 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
726 report(LOG_NOTICE, "IP address not found: %s",
727 inet_ntoa(bp->bp_ciaddr));
734 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
735 hp->hostname->string);
739 * If there is a response delay threshold, ignore requests
740 * with a timestamp lower than the threshold.
742 if (hp->flags.min_wait) {
743 u_int32 t = (u_int32) ntohs(bp->bp_secs);
744 if (t < hp->min_wait) {
747 "ignoring request due to timestamp (%d < %d)",
753 #ifdef YORK_EX_OPTION
755 * The need for the "ex" tag arose out of the need to empty
756 * shared networked drives on diskless PCs. This solution is
757 * not very clean but it does work fairly well.
758 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
760 * XXX - This could compromise security if a non-trusted user
761 * managed to write an entry in the bootptab with :ex=trojan:
762 * so I would leave this turned off unless you need it. -gwr
764 /* Run a program, passing the client name as a parameter. */
765 if (hp->flags.exec_file) {
767 /* XXX - Check string lengths? -gwr */
768 strcpy (tst, hp->exec_file->string);
770 strcat (tst, hp->hostname->string);
773 report(LOG_INFO, "executing %s", tst);
774 system(tst); /* Hope this finishes soon... */
776 #endif /* YORK_EX_OPTION */
779 * If a specific TFTP server address was specified in the bootptab file,
780 * fill it in, otherwise zero it.
781 * XXX - Rather than zero it, should it be the bootpd address? -gwr
783 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
784 hp->bootserver.s_addr : 0L;
786 #ifdef STANFORD_PROM_COMPAT
788 * Stanford bootp PROMs (for a Sun?) have no way to leave
789 * the boot file name field blank (because the boot file
790 * name is automatically generated from some index).
791 * As a work-around, this little hack allows those PROMs to
792 * specify "sunboot14" with the same effect as a NULL name.
793 * (The user specifies boot device 14 or some such magic.)
795 if (strcmp(bp->bp_file, "sunboot14") == 0)
796 bp->bp_file[0] = '\0'; /* treat it as unspecified */
800 * Fill in the client's proper bootfile.
802 * If the client specifies an absolute path, try that file with a
803 * ".host" suffix and then without. If the file cannot be found, no
804 * reply is made at all.
806 * If the client specifies a null or relative file, use the following
807 * table to determine the appropriate action:
809 * Homedir Bootfile Client's file
810 * specified? specified? specification Action
811 * -------------------------------------------------------------------
812 * No No Null Send null filename
813 * No No Relative Discard request
814 * No Yes Null Send if absolute else null
815 * No Yes Relative Discard request *XXX
816 * Yes No Null Send null filename
817 * Yes No Relative Lookup with ".host"
818 * Yes Yes Null Send home/boot or bootfile
819 * Yes Yes Relative Lookup with ".host" *XXX
824 * XXX - I don't like the policy of ignoring a client when the
825 * boot file is not accessible. The TFTP server might not be
826 * running on the same machine as the BOOTP server, in which
827 * case checking accessibility of the boot file is pointless.
829 * Therefore, file accessibility is now demanded ONLY if you
830 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
834 * The "real" path is as seen by the BOOTP daemon on this
835 * machine, while the client path is relative to the TFTP
836 * daemon chroot directory (i.e. /tftpboot).
838 if (hp->flags.tftpdir) {
839 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
840 clntpath = &realpath[strlen(realpath)];
847 * Determine client's requested homedir and bootfile.
851 if (bp->bp_file[0]) {
852 homedir = bp->bp_file;
853 bootfile = strrchr(homedir, '/');
855 if (homedir == bootfile)
859 /* no "/" in the string */
864 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
865 (homedir) ? homedir : "",
866 (bootfile) ? bootfile : "");
871 * Specifications in bootptab override client requested values.
873 if (hp->flags.homedir)
874 homedir = hp->homedir->string;
875 if (hp->flags.bootfile)
876 bootfile = hp->bootfile->string;
879 * Construct bootfile path.
882 if (homedir[0] != '/')
883 strcat(clntpath, "/");
884 strcat(clntpath, homedir);
888 if (bootfile[0] != '/')
889 strcat(clntpath, "/");
890 strcat(clntpath, bootfile);
895 * First try to find the file with a ".host" suffix
897 n = strlen(clntpath);
898 strcat(clntpath, ".");
899 strcat(clntpath, hp->hostname->string);
900 if (chk_access(realpath, &bootsize) < 0) {
901 clntpath[n] = 0; /* Try it without the suffix */
902 if (chk_access(realpath, &bootsize) < 0) {
903 /* neither "file.host" nor "file" was found */
904 #ifdef CHECK_FILE_ACCESS
906 if (bp->bp_file[0]) {
908 * Client wanted specific file
909 * and we didn't have it.
912 "requested file not found: \"%s\"", clntpath);
916 * Client didn't ask for a specific file and we couldn't
917 * access the default file, so just zero-out the bootfile
918 * field in the packet and continue processing the reply.
920 bzero(bp->bp_file, sizeof(bp->bp_file));
923 #else /* CHECK_FILE_ACCESS */
925 /* Complain only if boot file size was needed. */
926 if (hp->flags.bootsize_auto) {
927 report(LOG_ERR, "can not determine size of file \"%s\"",
931 #endif /* CHECK_FILE_ACCESS */
934 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
936 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
938 #ifdef CHECK_FILE_ACCESS
940 #endif /* CHECK_FILE_ACCESS */
944 * Handle vendor options based on magic number.
948 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
949 (int) ((bp->bp_vend)[0]),
950 (int) ((bp->bp_vend)[1]),
951 (int) ((bp->bp_vend)[2]),
952 (int) ((bp->bp_vend)[3]));
955 * If this host isn't set for automatic vendor info then copy the
956 * specific cookie into the bootp packet, thus forcing a certain
957 * reply format. Only force reply format if user specified it.
959 if (hp->flags.vm_cookie) {
960 /* Slam in the user specified magic number. */
961 bcopy(hp->vm_cookie, bp->bp_vend, 4);
964 * Figure out the format for the vendor-specific info.
965 * Note that bp->bp_vend may have been set above.
967 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
968 /* RFC1048 conformant bootp client */
969 dovend_rfc1048(bp, hp, bootsize);
971 report(LOG_INFO, "sending reply (with RFC1048 options)");
975 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
978 report(LOG_INFO, "sending reply (with CMU options)");
984 report(LOG_INFO, "sending reply (with no options)");
988 dest = (hp->flags.reply_addr) ?
989 hp->reply_addr.s_addr : 0L;
997 * Process BOOTREPLY packet.
1003 report(LOG_INFO, "processing boot reply");
1005 /* forwarded, no destination override */
1011 * Send a reply packet to the client. 'forward' flag is set if we are
1012 * not the originator of this reply packet.
1015 sendreply(forward, dst_override)
1019 struct bootp *bp = (struct bootp *) pktbuf;
1021 u_short port = bootpc_port;
1026 * XXX - Should honor bp_flags "broadcast" bit here.
1027 * Temporary workaround: use the :ra=ADDR: option to
1028 * set the reply address to the broadcast address.
1032 * If the destination address was specified explicitly
1033 * (i.e. the broadcast address for HP compatibility)
1034 * then send the response to that address. Otherwise,
1035 * act in accordance with RFC951:
1036 * If the client IP address is specified, use that
1037 * else if gateway IP address is specified, use that
1038 * else make a temporary arp cache entry for the client's
1039 * NEW IP/hardware address and use that.
1042 dst.s_addr = dst_override;
1044 report(LOG_INFO, "reply address override: %s",
1047 } else if (bp->bp_ciaddr.s_addr) {
1048 dst = bp->bp_ciaddr;
1049 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1050 dst = bp->bp_giaddr;
1053 report(LOG_INFO, "sending reply to gateway %s",
1057 dst = bp->bp_yiaddr;
1060 if (len > MAXHADDRLEN)
1062 haf = (int) bp->bp_htype;
1064 haf = HTYPE_ETHERNET;
1067 report(LOG_INFO, "setarp %s - %s",
1068 inet_ntoa(dst), haddrtoa(ha, len));
1069 setarp(s, &dst, haf, ha, len);
1072 if ((forward == 0) &&
1073 (bp->bp_siaddr.s_addr == 0))
1076 struct in_addr siaddr;
1078 * If we are originating this reply, we
1079 * need to find our own interface address to
1080 * put in the bp_siaddr field of the reply.
1081 * If this server is multi-homed, pick the
1082 * 'best' interface (the one on the same net
1083 * as the client). Of course, the client may
1084 * be on the other side of a BOOTP gateway...
1086 ifr = getif(s, &dst);
1088 struct sockaddr_in *sip;
1089 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1090 siaddr = sip->sin_addr;
1092 /* Just use my "official" IP address. */
1093 siaddr = my_ip_addr;
1096 /* XXX - No need to set bp_giaddr here. */
1098 /* Finally, set the server address field. */
1099 bp->bp_siaddr = siaddr;
1101 /* Set up socket address for send. */
1102 send_addr.sin_family = AF_INET;
1103 send_addr.sin_port = htons(port);
1104 send_addr.sin_addr = dst;
1106 /* Send reply with same size packet as request used. */
1107 if (sendto(s, pktbuf, pktlen, 0,
1108 (struct sockaddr *) &send_addr,
1109 sizeof(send_addr)) < 0)
1111 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1116 /* nmatch() - now in getif.c */
1117 /* setarp() - now in hwaddr.c */
1121 * This call checks read access to a file. It returns 0 if the file given
1122 * by "path" exists and is publicly readable. A value of -1 is returned if
1123 * access is not permitted or an error occurs. Successful calls also
1124 * return the file size in bytes using the long pointer "filesize".
1126 * The read permission bit for "other" users is checked. This bit must be
1127 * set for tftpd(8) to allow clients to read the file.
1131 chk_access(path, filesize)
1137 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1138 *filesize = (int32) st.st_size;
1147 * Now in dumptab.c :
1150 * list_ipaddresses()
1156 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1157 * bootp packet pointed to by "bp".
1165 struct cmu_vend *vendp;
1166 struct in_addr_list *taddr;
1169 * Initialize the entire vendor field to zeroes.
1171 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1174 * Fill in vendor information. Subnet mask, default gateway,
1175 * domain name server, ien name server, time server
1177 vendp = (struct cmu_vend *) bp->bp_vend;
1178 strcpy(vendp->v_magic, (char *)vm_cmu);
1179 if (hp->flags.subnet_mask) {
1180 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1181 (vendp->v_flags) |= VF_SMASK;
1182 if (hp->flags.gateway) {
1183 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1186 if (hp->flags.domain_server) {
1187 taddr = hp->domain_server;
1188 if (taddr->addrcount > 0) {
1189 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1190 if (taddr->addrcount > 1) {
1191 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1195 if (hp->flags.name_server) {
1196 taddr = hp->name_server;
1197 if (taddr->addrcount > 0) {
1198 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1199 if (taddr->addrcount > 1) {
1200 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1204 if (hp->flags.time_server) {
1205 taddr = hp->time_server;
1206 if (taddr->addrcount > 0) {
1207 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1208 if (taddr->addrcount > 1) {
1209 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1213 /* Log message now done by caller. */
1216 #endif /* VEND_CMU */
1221 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1222 * bootp packet pointed to by "bp".
1224 #define NEED(LEN, MSG) do \
1225 if (bytesleft < (LEN)) { \
1226 report(LOG_NOTICE, noroom, \
1227 hp->hostname->string, MSG); \
1231 dovend_rfc1048(bp, hp, bootsize)
1239 static const char noroom[] = "%s: No room for \"%s\" option";
1243 if (hp->flags.msg_size) {
1244 pktlen = hp->msg_size;
1247 * If the request was longer than the official length, build
1248 * a response of that same length where the additional length
1249 * is assumed to be part of the bp_vend (options) area.
1251 if (pktlen > sizeof(*bp)) {
1253 report(LOG_INFO, "request message length=%d", pktlen);
1256 * Check whether the request contains the option:
1257 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1258 * and if so, override the response length with its value.
1259 * This request must lie within the first BP_VEND_LEN
1260 * bytes of the option space.
1268 ep = p + BP_VEND_LEN - 4;
1271 /* Check for tags with no data first. */
1276 /* Now scan the length byte. */
1281 bcopy(p, (char*)&msgsz, 2);
1282 msgsz = ntohs(msgsz);
1285 case TAG_SUBNET_MASK:
1286 /* XXX - Should preserve this if given... */
1292 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1294 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1295 pktlen = msgsz - BP_MSG_OVERHEAD;
1300 if (pktlen < sizeof(*bp)) {
1301 report(LOG_ERR, "invalid response length=%d", pktlen);
1302 pktlen = sizeof(*bp);
1304 bytesleft = ((byte*)bp + pktlen) - vp;
1305 if (pktlen > sizeof(*bp)) {
1307 report(LOG_INFO, "extended reply, length=%d, options=%d",
1311 /* Copy in the magic cookie */
1312 bcopy(vm_rfc1048, vp, 4);
1316 if (hp->flags.subnet_mask) {
1317 /* always enough room here. */
1318 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1319 *vp++ = 4; /* -1 byte */
1320 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1321 bytesleft -= 6; /* Fix real count */
1322 if (hp->flags.gateway) {
1323 (void) insert_ip(TAG_GATEWAY,
1328 if (hp->flags.bootsize) {
1329 /* always enough room here */
1330 bootsize = (hp->flags.bootsize_auto) ?
1331 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1332 *vp++ = TAG_BOOT_SIZE;
1334 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1335 *vp++ = (byte) (bootsize & 0xFF);
1336 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1339 * This one is special: Remaining options go in the ext file.
1340 * Only the subnet_mask, bootsize, and gateway should precede.
1342 if (hp->flags.exten_file) {
1344 * Check for room for exten_file. Add 3 to account for
1345 * TAG_EXTEN_FILE, length, and TAG_END.
1347 len = strlen(hp->exten_file->string);
1348 NEED((len + 3), "ef");
1349 *vp++ = TAG_EXTEN_FILE;
1350 *vp++ = (byte) (len & 0xFF);
1351 bcopy(hp->exten_file->string, vp, len);
1354 bytesleft -= len + 3;
1355 return; /* no more options here. */
1358 * The remaining options are inserted by the following
1359 * function (which is shared with bootpef.c).
1360 * Keep back one byte for the TAG_END.
1362 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1366 /* There should be at least one byte left. */
1371 /* Log message done by caller. */
1372 if (bytesleft > 0) {
1374 * Zero out any remaining part of the vendor area.
1376 bzero(vp, bytesleft);
1378 } /* dovend_rfc1048 */
1383 * Now in readfile.c:
1388 /* haddrtoa() - now in hwaddr.c */
1396 /* get_errmsg() - now in report.c */
1402 * c-argdecl-indent: 4
1403 * c-continued-statement-offset: 4
1404 * c-continued-brace-offset: -4
1405 * c-label-offset: -4