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 */
146 int arpmod = TRUE; /* modify the ARP table */
152 int s; /* Socket file descriptor */
153 char *pktbuf; /* Receive packet buffer */
157 struct in_addr my_ip_addr;
159 static const char *hostname;
160 static char default_hostname[MAXHOSTNAMELEN];
162 /* Flags set by signal catcher. */
163 PRIVATE int do_readtab = 0;
164 PRIVATE int do_dumptab = 0;
167 * Globals below are associated with the bootp database file (bootptab).
170 char *bootptab = CONFIG_FILE;
171 char *bootpd_dump = DUMPTAB_FILE;
176 * Initialization such as command-line processing is done and then the
177 * main server loop is started.
185 struct timeval *timeout;
187 struct servent *servp;
190 socklen_t ba_len, ra_len;
195 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
199 progname = strrchr(argv[0], '/');
200 if (progname) progname++;
201 else progname = argv[0];
204 * Initialize logging.
206 report_init(0); /* uses progname */
211 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
213 /* Debugging for compilers with struct padding. */
214 assert(sizeof(struct bootp) == BP_MINPKTSZ);
216 /* Get space for receiving packets and composing replies. */
217 pktbuf = malloc(MAX_MSG_SIZE);
219 report(LOG_ERR, "malloc failed");
222 bp = (struct bootp *) pktbuf;
225 * Check to see if a socket was passed to us from inetd.
227 * Use getsockname() to determine if descriptor 0 is indeed a socket
228 * (and thus we are probably a child of inetd) or if it is instead
229 * something else and we are running standalone.
232 ba_len = sizeof(bind_addr);
233 bzero((char *) &bind_addr, ba_len);
236 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
238 * Descriptor 0 is a socket. Assume we are a child of inetd.
240 if (bind_addr.sin_family == AF_INET) {
242 bootps_port = ntohs(bind_addr.sin_port);
244 /* Some other type of socket? */
245 report(LOG_ERR, "getsockname: not an INET socket");
250 * Set defaults that might be changed by option switches.
253 timeout = &actualtimeout;
255 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
256 report(LOG_ERR, "bootpd: can't get hostname\n");
259 default_hostname[sizeof(default_hostname) - 1] = '\0';
260 hostname = default_hostname;
265 for (argc--, argv++; argc > 0; argc--, argv++) {
266 if (argv[0][0] != '-')
268 switch (argv[0][1]) {
270 case 'a': /* don't modify the ARP table */
273 case 'c': /* chdir_path */
275 stmp = &(argv[0][2]);
281 if (!stmp || (stmp[0] != '/')) {
283 "bootpd: invalid chdir specification\n");
289 case 'd': /* debug level */
291 stmp = &(argv[0][2]);
292 } else if (argv[1] && argv[1][0] == '-') {
294 * Backwards-compatible behavior:
295 * no parameter, so just increment the debug flag.
304 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
306 "%s: invalid debug level\n", progname);
312 case 'h': /* override hostname */
314 stmp = &(argv[0][2]);
322 "bootpd: missing hostname\n");
328 case 'i': /* inetd mode */
332 case 's': /* standalone mode */
336 case 't': /* timeout */
338 stmp = &(argv[0][2]);
344 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
346 "%s: invalid timeout specification\n", progname);
349 actualtimeout.tv_sec = (int32) (60 * n);
351 * If the actual timeout is zero, pass a NULL pointer
352 * to select so it blocks indefinitely, otherwise,
353 * point to the actual timeout value.
355 timeout = (n > 0) ? &actualtimeout : NULL;
359 report(LOG_ERR, "%s: unknown switch: -%c\n",
360 progname, argv[0][1]);
368 * Override default file names if specified on the command line.
374 bootpd_dump = argv[1];
377 * Get my hostname and IP address.
380 hep = gethostbyname(hostname);
382 report(LOG_ERR, "Can not get my IP address\n");
385 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
389 * Go into background and disassociate from controlling terminal.
397 n = open(_PATH_TTY, O_RDWR);
399 ioctl(n, TIOCNOTTY, (char *) 0);
402 #endif /* TIOCNOTTY */
410 * Nuke any timeout value
414 } /* if standalone (1st) */
416 /* Set the cwd (i.e. to /tftpboot) */
418 if (chdir(chdir_path) < 0)
419 report(LOG_ERR, "%s: chdir failed", chdir_path);
422 /* Get the timezone. */
425 /* Allocate hash tables. */
429 * Read the bootptab file.
431 readtab(1); /* force read */
438 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
439 report(LOG_ERR, "socket: %s", get_network_errmsg());
444 * Get server's listening port number
446 servp = getservbyname("bootps", "udp");
448 bootps_port = ntohs((u_short) servp->s_port);
450 bootps_port = (u_short) IPPORT_BOOTPS;
452 "bootps/udp: unknown service -- using port %d",
457 * Bind socket to BOOTPS port.
459 bind_addr.sin_family = AF_INET;
460 bind_addr.sin_addr.s_addr = INADDR_ANY;
461 bind_addr.sin_port = htons(bootps_port);
462 if (bind(s, (struct sockaddr *) &bind_addr,
463 sizeof(bind_addr)) < 0)
465 report(LOG_ERR, "bind: %s", get_network_errmsg());
468 } /* if standalone (2nd)*/
471 * Get destination port number so we can reply to client
473 servp = getservbyname("bootpc", "udp");
475 bootpc_port = ntohs(servp->s_port);
478 "bootpc/udp: unknown service -- using port %d",
480 bootpc_port = (u_short) IPPORT_BOOTPC;
484 * Set up signals to read or dump the table.
486 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
487 sa.sa_handler = catcher;
488 sigemptyset(&sa.sa_mask);
490 if (sigaction(SIGHUP, &sa, NULL) < 0) {
491 report(LOG_ERR, "sigaction: %s", get_errmsg());
494 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
495 report(LOG_ERR, "sigaction: %s", get_errmsg());
498 #else /* SA_NOCLDSTOP */
499 /* Old-fashioned UNIX signals */
500 if ((int) signal(SIGHUP, catcher) < 0) {
501 report(LOG_ERR, "signal: %s", get_errmsg());
504 if ((int) signal(SIGUSR1, catcher) < 0) {
505 report(LOG_ERR, "signal: %s", get_errmsg());
508 #endif /* SA_NOCLDSTOP */
511 * Process incoming requests.
521 nfound = select(s + 1, &readfds, NULL, NULL,
522 (timeout) ? &tv : NULL);
524 if (errno != EINTR) {
525 report(LOG_ERR, "select: %s", get_errmsg());
528 * Call readtab() or dumptab() here to avoid the
529 * dangers of doing I/O from a signal handler.
533 readtab(1); /* force read */
537 dumptab(bootpd_dump);
541 if (!FD_ISSET(s, &readfds)) {
543 report(LOG_INFO, "exiting after %jd minutes of inactivity",
544 (intmax_t)actualtimeout.tv_sec / 60);
547 ra_len = sizeof(recv_addr);
548 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
549 (struct sockaddr *) &recv_addr, &ra_len);
554 report(LOG_INFO, "recvd pkt from IP addr %s",
555 inet_ntoa(recv_addr.sin_addr));
557 if (n < sizeof(struct bootp)) {
559 report(LOG_NOTICE, "received short packet");
565 readtab(0); /* maybe re-read bootptab */
583 * Print "usage" message and exit
590 "usage: bootpd [-a] [-i | -s] [-c chdir-path] [-d level] [-h hostname]\n"
591 " [-t timeout] [bootptab [dumpfile]]\n");
592 fprintf(stderr, " -a\tdon't modify ARP table\n");
593 fprintf(stderr, " -c n\tset current directory\n");
594 fprintf(stderr, " -d n\tset debug level\n");
595 fprintf(stderr, " -h n\tset the hostname to listen on\n");
596 fprintf(stderr, " -i\tforce inetd mode (run as child of inetd)\n");
597 fprintf(stderr, " -s\tforce standalone mode (run without inetd)\n");
598 fprintf(stderr, " -t n\tset inetd exit timeout to n minutes\n");
602 /* Signal catchers */
611 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
612 /* For older "System V" derivatives with no sigaction(). */
613 signal(sig, catcher);
620 * Process BOOTREQUEST packet.
622 * Note: This version of the bootpd.c server never forwards
623 * a request to another server. That is the job of a gateway
624 * program such as the "bootpgw" program included here.
626 * (Also this version does not interpret the hostname field of
627 * the request packet; it COULD do a name->address lookup and
628 * forward the request there.)
633 struct bootp *bp = (struct bootp *) pktbuf;
634 struct host *hp = NULL;
635 struct host dummyhost;
637 unsigned hlen, hashcode;
641 char *homedir, *bootfile;
644 if (bp->bp_htype >= hwinfocnt) {
645 report(LOG_NOTICE, "bad hw addr type %u", bp->bp_htype);
648 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
650 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
653 * If the servername field is set, compare it against us.
654 * If we're not being addressed, ignore this request.
655 * If the server name field is null, throw in our name.
657 if (strlen(bp->bp_sname)) {
658 if (strcmp(bp->bp_sname, hostname)) {
661 ignoring request for server %s from client at %s address %s",
662 bp->bp_sname, netname(bp->bp_htype),
663 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
664 /* XXX - Is it correct to ignore such a request? -gwr */
668 strcpy(bp->bp_sname, hostname);
671 /* Convert the request into a reply. */
672 bp->bp_op = BOOTREPLY;
673 if (bp->bp_ciaddr.s_addr == 0) {
675 * client doesn't know his IP address,
676 * search by hardware address.
679 report(LOG_INFO, "request from %s address %s",
680 netname(bp->bp_htype),
681 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
683 hlen = haddrlength(bp->bp_htype);
684 if (hlen != bp->bp_hlen) {
685 report(LOG_NOTICE, "bad addr len from %s address %s",
686 netname(bp->bp_htype),
687 haddrtoa(bp->bp_chaddr, hlen));
689 dummyhost.htype = bp->bp_htype;
690 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
691 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
692 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
695 bp->bp_htype == HTYPE_IEEE802)
697 /* Try again with address in "canonical" form. */
698 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
701 HW addr type is IEEE 802. convert to %s and check again\n",
702 haddrtoa(dummyhost.haddr, bp->bp_hlen));
704 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
705 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
706 hwlookcmp, &dummyhost);
710 * XXX - Add dynamic IP address assignment?
713 report(LOG_NOTICE, "unknown client %s address %s",
714 netname(bp->bp_htype),
715 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
716 return; /* not found */
718 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
723 * search by IP address.
726 report(LOG_INFO, "request from IP addr %s",
727 inet_ntoa(bp->bp_ciaddr));
729 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
730 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
731 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
735 report(LOG_NOTICE, "IP address not found: %s",
736 inet_ntoa(bp->bp_ciaddr));
743 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
744 hp->hostname->string);
748 * If there is a response delay threshold, ignore requests
749 * with a timestamp lower than the threshold.
751 if (hp->flags.min_wait) {
752 u_int32 t = (u_int32) ntohs(bp->bp_secs);
753 if (t < hp->min_wait) {
756 "ignoring request due to timestamp (%d < %d)",
762 #ifdef YORK_EX_OPTION
764 * The need for the "ex" tag arose out of the need to empty
765 * shared networked drives on diskless PCs. This solution is
766 * not very clean but it does work fairly well.
767 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
769 * XXX - This could compromise security if a non-trusted user
770 * managed to write an entry in the bootptab with :ex=trojan:
771 * so I would leave this turned off unless you need it. -gwr
773 /* Run a program, passing the client name as a parameter. */
774 if (hp->flags.exec_file) {
776 /* XXX - Check string lengths? -gwr */
777 strcpy (tst, hp->exec_file->string);
779 strcat (tst, hp->hostname->string);
782 report(LOG_INFO, "executing %s", tst);
783 system(tst); /* Hope this finishes soon... */
785 #endif /* YORK_EX_OPTION */
788 * If a specific TFTP server address was specified in the bootptab file,
789 * fill it in, otherwise zero it.
790 * XXX - Rather than zero it, should it be the bootpd address? -gwr
792 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
793 hp->bootserver.s_addr : 0L;
795 #ifdef STANFORD_PROM_COMPAT
797 * Stanford bootp PROMs (for a Sun?) have no way to leave
798 * the boot file name field blank (because the boot file
799 * name is automatically generated from some index).
800 * As a work-around, this little hack allows those PROMs to
801 * specify "sunboot14" with the same effect as a NULL name.
802 * (The user specifies boot device 14 or some such magic.)
804 if (strcmp(bp->bp_file, "sunboot14") == 0)
805 bp->bp_file[0] = '\0'; /* treat it as unspecified */
809 * Fill in the client's proper bootfile.
811 * If the client specifies an absolute path, try that file with a
812 * ".host" suffix and then without. If the file cannot be found, no
813 * reply is made at all.
815 * If the client specifies a null or relative file, use the following
816 * table to determine the appropriate action:
818 * Homedir Bootfile Client's file
819 * specified? specified? specification Action
820 * -------------------------------------------------------------------
821 * No No Null Send null filename
822 * No No Relative Discard request
823 * No Yes Null Send if absolute else null
824 * No Yes Relative Discard request *XXX
825 * Yes No Null Send null filename
826 * Yes No Relative Lookup with ".host"
827 * Yes Yes Null Send home/boot or bootfile
828 * Yes Yes Relative Lookup with ".host" *XXX
833 * XXX - I don't like the policy of ignoring a client when the
834 * boot file is not accessible. The TFTP server might not be
835 * running on the same machine as the BOOTP server, in which
836 * case checking accessibility of the boot file is pointless.
838 * Therefore, file accessibility is now demanded ONLY if you
839 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
843 * The "real" path is as seen by the BOOTP daemon on this
844 * machine, while the client path is relative to the TFTP
845 * daemon chroot directory (i.e. /tftpboot).
847 if (hp->flags.tftpdir) {
848 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
849 clntpath = &realpath[strlen(realpath)];
856 * Determine client's requested homedir and bootfile.
860 if (bp->bp_file[0]) {
861 homedir = bp->bp_file;
862 bootfile = strrchr(homedir, '/');
864 if (homedir == bootfile)
868 /* no "/" in the string */
873 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
874 (homedir) ? homedir : "",
875 (bootfile) ? bootfile : "");
880 * Specifications in bootptab override client requested values.
882 if (hp->flags.homedir)
883 homedir = hp->homedir->string;
884 if (hp->flags.bootfile)
885 bootfile = hp->bootfile->string;
888 * Construct bootfile path.
891 if (homedir[0] != '/')
892 strcat(clntpath, "/");
893 strcat(clntpath, homedir);
897 if (bootfile[0] != '/')
898 strcat(clntpath, "/");
899 strcat(clntpath, bootfile);
904 * First try to find the file with a ".host" suffix
906 n = strlen(clntpath);
907 strcat(clntpath, ".");
908 strcat(clntpath, hp->hostname->string);
909 if (chk_access(realpath, &bootsize) < 0) {
910 clntpath[n] = 0; /* Try it without the suffix */
911 if (chk_access(realpath, &bootsize) < 0) {
912 /* neither "file.host" nor "file" was found */
913 #ifdef CHECK_FILE_ACCESS
915 if (bp->bp_file[0]) {
917 * Client wanted specific file
918 * and we didn't have it.
921 "requested file not found: \"%s\"", clntpath);
925 * Client didn't ask for a specific file and we couldn't
926 * access the default file, so just zero-out the bootfile
927 * field in the packet and continue processing the reply.
929 bzero(bp->bp_file, sizeof(bp->bp_file));
932 #else /* CHECK_FILE_ACCESS */
934 /* Complain only if boot file size was needed. */
935 if (hp->flags.bootsize_auto) {
936 report(LOG_ERR, "can not determine size of file \"%s\"",
940 #endif /* CHECK_FILE_ACCESS */
943 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
945 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
947 #ifdef CHECK_FILE_ACCESS
949 #endif /* CHECK_FILE_ACCESS */
953 * Handle vendor options based on magic number.
957 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
958 (int) ((bp->bp_vend)[0]),
959 (int) ((bp->bp_vend)[1]),
960 (int) ((bp->bp_vend)[2]),
961 (int) ((bp->bp_vend)[3]));
964 * If this host isn't set for automatic vendor info then copy the
965 * specific cookie into the bootp packet, thus forcing a certain
966 * reply format. Only force reply format if user specified it.
968 if (hp->flags.vm_cookie) {
969 /* Slam in the user specified magic number. */
970 bcopy(hp->vm_cookie, bp->bp_vend, 4);
973 * Figure out the format for the vendor-specific info.
974 * Note that bp->bp_vend may have been set above.
976 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
977 /* RFC1048 conformant bootp client */
978 dovend_rfc1048(bp, hp, bootsize);
980 report(LOG_INFO, "sending reply (with RFC1048 options)");
984 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
987 report(LOG_INFO, "sending reply (with CMU options)");
993 report(LOG_INFO, "sending reply (with no options)");
997 dest = (hp->flags.reply_addr) ?
998 hp->reply_addr.s_addr : 0L;
1006 * Process BOOTREPLY packet.
1012 report(LOG_INFO, "processing boot reply");
1014 /* forwarded, no destination override */
1020 * Send a reply packet to the client. 'forward' flag is set if we are
1021 * not the originator of this reply packet.
1024 sendreply(forward, dst_override)
1028 struct bootp *bp = (struct bootp *) pktbuf;
1030 u_short port = bootpc_port;
1035 * XXX - Should honor bp_flags "broadcast" bit here.
1036 * Temporary workaround: use the :ra=ADDR: option to
1037 * set the reply address to the broadcast address.
1041 * If the destination address was specified explicitly
1042 * (i.e. the broadcast address for HP compatibility)
1043 * then send the response to that address. Otherwise,
1044 * act in accordance with RFC951:
1045 * If the client IP address is specified, use that
1046 * else if gateway IP address is specified, use that
1047 * else make a temporary arp cache entry for the client's
1048 * NEW IP/hardware address and use that.
1051 dst.s_addr = dst_override;
1053 report(LOG_INFO, "reply address override: %s",
1056 } else if (bp->bp_ciaddr.s_addr) {
1057 dst = bp->bp_ciaddr;
1058 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1059 dst = bp->bp_giaddr;
1062 report(LOG_INFO, "sending reply to gateway %s",
1066 dst = bp->bp_yiaddr;
1069 if (len > MAXHADDRLEN)
1071 haf = (int) bp->bp_htype;
1073 haf = HTYPE_ETHERNET;
1077 report(LOG_INFO, "setarp %s - %s",
1078 inet_ntoa(dst), haddrtoa(ha, len));
1079 setarp(s, &dst, haf, ha, len);
1083 if ((forward == 0) &&
1084 (bp->bp_siaddr.s_addr == 0))
1087 struct in_addr siaddr;
1089 * If we are originating this reply, we
1090 * need to find our own interface address to
1091 * put in the bp_siaddr field of the reply.
1092 * If this server is multi-homed, pick the
1093 * 'best' interface (the one on the same net
1094 * as the client). Of course, the client may
1095 * be on the other side of a BOOTP gateway...
1097 ifr = getif(s, &dst);
1099 struct sockaddr_in *sip;
1100 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1101 siaddr = sip->sin_addr;
1103 /* Just use my "official" IP address. */
1104 siaddr = my_ip_addr;
1107 /* XXX - No need to set bp_giaddr here. */
1109 /* Finally, set the server address field. */
1110 bp->bp_siaddr = siaddr;
1112 /* Set up socket address for send. */
1113 send_addr.sin_family = AF_INET;
1114 send_addr.sin_port = htons(port);
1115 send_addr.sin_addr = dst;
1117 /* Send reply with same size packet as request used. */
1118 if (sendto(s, pktbuf, pktlen, 0,
1119 (struct sockaddr *) &send_addr,
1120 sizeof(send_addr)) < 0)
1122 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1127 /* nmatch() - now in getif.c */
1128 /* setarp() - now in hwaddr.c */
1132 * This call checks read access to a file. It returns 0 if the file given
1133 * by "path" exists and is publicly readable. A value of -1 is returned if
1134 * access is not permitted or an error occurs. Successful calls also
1135 * return the file size in bytes using the long pointer "filesize".
1137 * The read permission bit for "other" users is checked. This bit must be
1138 * set for tftpd(8) to allow clients to read the file.
1142 chk_access(path, filesize)
1148 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1149 *filesize = (int32) st.st_size;
1158 * Now in dumptab.c :
1161 * list_ipaddresses()
1167 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1168 * bootp packet pointed to by "bp".
1176 struct cmu_vend *vendp;
1177 struct in_addr_list *taddr;
1180 * Initialize the entire vendor field to zeroes.
1182 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1185 * Fill in vendor information. Subnet mask, default gateway,
1186 * domain name server, ien name server, time server
1188 vendp = (struct cmu_vend *) bp->bp_vend;
1189 strcpy(vendp->v_magic, (char *)vm_cmu);
1190 if (hp->flags.subnet_mask) {
1191 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1192 (vendp->v_flags) |= VF_SMASK;
1193 if (hp->flags.gateway) {
1194 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1197 if (hp->flags.domain_server) {
1198 taddr = hp->domain_server;
1199 if (taddr->addrcount > 0) {
1200 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1201 if (taddr->addrcount > 1) {
1202 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1206 if (hp->flags.name_server) {
1207 taddr = hp->name_server;
1208 if (taddr->addrcount > 0) {
1209 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1210 if (taddr->addrcount > 1) {
1211 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1215 if (hp->flags.time_server) {
1216 taddr = hp->time_server;
1217 if (taddr->addrcount > 0) {
1218 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1219 if (taddr->addrcount > 1) {
1220 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1224 /* Log message now done by caller. */
1227 #endif /* VEND_CMU */
1232 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1233 * bootp packet pointed to by "bp".
1235 #define NEED(LEN, MSG) do \
1236 if (bytesleft < (LEN)) { \
1237 report(LOG_NOTICE, noroom, \
1238 hp->hostname->string, MSG); \
1242 dovend_rfc1048(bp, hp, bootsize)
1250 static const char noroom[] = "%s: No room for \"%s\" option";
1254 if (hp->flags.msg_size) {
1255 pktlen = hp->msg_size;
1258 * If the request was longer than the official length, build
1259 * a response of that same length where the additional length
1260 * is assumed to be part of the bp_vend (options) area.
1262 if (pktlen > sizeof(*bp)) {
1264 report(LOG_INFO, "request message length=%d", pktlen);
1267 * Check whether the request contains the option:
1268 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1269 * and if so, override the response length with its value.
1270 * This request must lie within the first BP_VEND_LEN
1271 * bytes of the option space.
1279 ep = p + BP_VEND_LEN - 4;
1282 /* Check for tags with no data first. */
1287 /* Now scan the length byte. */
1292 bcopy(p, (char*)&msgsz, 2);
1293 msgsz = ntohs(msgsz);
1296 case TAG_SUBNET_MASK:
1297 /* XXX - Should preserve this if given... */
1303 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1305 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1306 pktlen = msgsz - BP_MSG_OVERHEAD;
1311 if (pktlen < sizeof(*bp)) {
1312 report(LOG_ERR, "invalid response length=%d", pktlen);
1313 pktlen = sizeof(*bp);
1315 bytesleft = ((byte*)bp + pktlen) - vp;
1316 if (pktlen > sizeof(*bp)) {
1318 report(LOG_INFO, "extended reply, length=%d, options=%d",
1322 /* Copy in the magic cookie */
1323 bcopy(vm_rfc1048, vp, 4);
1327 if (hp->flags.subnet_mask) {
1328 /* always enough room here. */
1329 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1330 *vp++ = 4; /* -1 byte */
1331 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1332 bytesleft -= 6; /* Fix real count */
1333 if (hp->flags.gateway) {
1334 (void) insert_ip(TAG_GATEWAY,
1339 if (hp->flags.bootsize) {
1340 /* always enough room here */
1341 bootsize = (hp->flags.bootsize_auto) ?
1342 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1343 *vp++ = TAG_BOOT_SIZE;
1345 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1346 *vp++ = (byte) (bootsize & 0xFF);
1347 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1350 * This one is special: Remaining options go in the ext file.
1351 * Only the subnet_mask, bootsize, and gateway should precede.
1353 if (hp->flags.exten_file) {
1355 * Check for room for exten_file. Add 3 to account for
1356 * TAG_EXTEN_FILE, length, and TAG_END.
1358 len = strlen(hp->exten_file->string);
1359 NEED((len + 3), "ef");
1360 *vp++ = TAG_EXTEN_FILE;
1361 *vp++ = (byte) (len & 0xFF);
1362 bcopy(hp->exten_file->string, vp, len);
1365 bytesleft -= len + 3;
1366 return; /* no more options here. */
1369 * The remaining options are inserted by the following
1370 * function (which is shared with bootpef.c).
1371 * Keep back one byte for the TAG_END.
1373 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1377 /* There should be at least one byte left. */
1382 /* Log message done by caller. */
1383 if (bytesleft > 0) {
1385 * Zero out any remaining part of the vendor area.
1387 bzero(vp, bytesleft);
1389 } /* dovend_rfc1048 */
1394 * Now in readfile.c:
1399 /* haddrtoa() - now in hwaddr.c */
1407 /* get_errmsg() - now in report.c */
1413 * c-argdecl-indent: 4
1414 * c-continued-statement-offset: 4
1415 * c-continued-brace-offset: -4
1416 * c-label-offset: -4