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/types.h>
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
47 #include <sys/utsname.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h> /* inet_ntoa */
70 # include <fcntl.h> /* for O_RDONLY, etc */
82 #include "patchlevel.h"
85 #define CONFIG_FILE "/etc/bootptab"
88 #define DUMPTAB_FILE "/tmp/bootpd.dump"
94 * Externals, forward declarations, and global variables
97 extern void dumptab(char *);
99 PRIVATE void catcher(int);
100 PRIVATE int chk_access(char *, int32 *);
102 PRIVATE void dovend_cmu(struct bootp *, struct host *);
104 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
105 PRIVATE void handle_reply(void);
106 PRIVATE void handle_request(void);
107 PRIVATE void sendreply(int forward, int32 dest_override);
108 PRIVATE void usage(void);
111 * IP port numbers for client and server obtained from /etc/services
114 u_short bootps_port, bootpc_port;
118 * Internet socket and interface config structures
121 struct sockaddr_in bind_addr; /* Listening */
122 struct sockaddr_in recv_addr; /* Packet source */
123 struct sockaddr_in send_addr; /* destination */
129 int debug = 0; /* Debugging flag (level) */
130 struct timeval actualtimeout =
131 { /* fifteen minutes */
132 15 * 60L, /* tv_sec */
135 int arpmod = TRUE; /* modify the ARP table */
141 int s; /* Socket file descriptor */
142 char *pktbuf; /* Receive packet buffer */
146 struct in_addr my_ip_addr;
148 static const char *hostname;
149 static char default_hostname[MAXHOSTNAMELEN];
151 /* Flags set by signal catcher. */
152 PRIVATE int do_readtab = 0;
153 PRIVATE int do_dumptab = 0;
156 * Globals below are associated with the bootp database file (bootptab).
159 char *bootptab = CONFIG_FILE;
160 char *bootpd_dump = DUMPTAB_FILE;
165 * Initialization such as command-line processing is done and then the
166 * main server loop is started.
170 main(int argc, char **argv)
172 struct timeval *timeout;
174 struct servent *servp;
177 socklen_t ba_len, ra_len;
182 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
186 progname = strrchr(argv[0], '/');
187 if (progname) progname++;
188 else progname = argv[0];
191 * Initialize logging.
193 report_init(0); /* uses progname */
198 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
200 /* Debugging for compilers with struct padding. */
201 assert(sizeof(struct bootp) == BP_MINPKTSZ);
203 /* Get space for receiving packets and composing replies. */
204 pktbuf = malloc(MAX_MSG_SIZE);
206 report(LOG_ERR, "malloc failed");
209 bp = (struct bootp *) pktbuf;
212 * Check to see if a socket was passed to us from inetd.
214 * Use getsockname() to determine if descriptor 0 is indeed a socket
215 * (and thus we are probably a child of inetd) or if it is instead
216 * something else and we are running standalone.
219 ba_len = sizeof(bind_addr);
220 bzero((char *) &bind_addr, ba_len);
223 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
225 * Descriptor 0 is a socket. Assume we are a child of inetd.
227 if (bind_addr.sin_family == AF_INET) {
229 bootps_port = ntohs(bind_addr.sin_port);
231 /* Some other type of socket? */
232 report(LOG_ERR, "getsockname: not an INET socket");
237 * Set defaults that might be changed by option switches.
240 timeout = &actualtimeout;
242 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
243 report(LOG_ERR, "bootpd: can't get hostname\n");
246 default_hostname[sizeof(default_hostname) - 1] = '\0';
247 hostname = default_hostname;
252 for (argc--, argv++; argc > 0; argc--, argv++) {
253 if (argv[0][0] != '-')
255 switch (argv[0][1]) {
257 case 'a': /* don't modify the ARP table */
260 case 'c': /* chdir_path */
262 stmp = &(argv[0][2]);
268 if (!stmp || (stmp[0] != '/')) {
270 "bootpd: invalid chdir specification\n");
276 case 'd': /* debug level */
278 stmp = &(argv[0][2]);
279 } else if (argv[1] && argv[1][0] == '-') {
281 * Backwards-compatible behavior:
282 * no parameter, so just increment the debug flag.
291 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
293 "%s: invalid debug level\n", progname);
299 case 'h': /* override hostname */
301 stmp = &(argv[0][2]);
309 "bootpd: missing hostname\n");
315 case 'i': /* inetd mode */
319 case 's': /* standalone mode */
323 case 't': /* timeout */
325 stmp = &(argv[0][2]);
331 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
333 "%s: invalid timeout specification\n", progname);
336 actualtimeout.tv_sec = (int32) (60 * n);
338 * If the actual timeout is zero, pass a NULL pointer
339 * to select so it blocks indefinitely, otherwise,
340 * point to the actual timeout value.
342 timeout = (n > 0) ? &actualtimeout : NULL;
346 report(LOG_ERR, "%s: unknown switch: -%c\n",
347 progname, argv[0][1]);
355 * Override default file names if specified on the command line.
361 bootpd_dump = argv[1];
364 * Get my hostname and IP address.
367 hep = gethostbyname(hostname);
369 report(LOG_ERR, "Can not get my IP address\n");
372 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
376 * Go into background and disassociate from controlling terminal.
384 n = open(_PATH_TTY, O_RDWR);
386 ioctl(n, TIOCNOTTY, (char *) 0);
389 #endif /* TIOCNOTTY */
397 * Nuke any timeout value
401 } /* if standalone (1st) */
403 /* Set the cwd (i.e. to /tftpboot) */
405 if (chdir(chdir_path) < 0)
406 report(LOG_ERR, "%s: chdir failed", chdir_path);
409 /* Get the timezone. */
412 /* Allocate hash tables. */
416 * Read the bootptab file.
418 readtab(1); /* force read */
425 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
426 report(LOG_ERR, "socket: %s", get_network_errmsg());
431 * Get server's listening port number
433 servp = getservbyname("bootps", "udp");
435 bootps_port = ntohs((u_short) servp->s_port);
437 bootps_port = (u_short) IPPORT_BOOTPS;
439 "bootps/udp: unknown service -- using port %d",
444 * Bind socket to BOOTPS port.
446 bind_addr.sin_family = AF_INET;
447 bind_addr.sin_addr.s_addr = INADDR_ANY;
448 bind_addr.sin_port = htons(bootps_port);
449 if (bind(s, (struct sockaddr *) &bind_addr,
450 sizeof(bind_addr)) < 0)
452 report(LOG_ERR, "bind: %s", get_network_errmsg());
455 } /* if standalone (2nd)*/
458 * Get destination port number so we can reply to client
460 servp = getservbyname("bootpc", "udp");
462 bootpc_port = ntohs(servp->s_port);
465 "bootpc/udp: unknown service -- using port %d",
467 bootpc_port = (u_short) IPPORT_BOOTPC;
471 * Set up signals to read or dump the table.
473 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
474 sa.sa_handler = catcher;
475 sigemptyset(&sa.sa_mask);
477 if (sigaction(SIGHUP, &sa, NULL) < 0) {
478 report(LOG_ERR, "sigaction: %s", get_errmsg());
481 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
482 report(LOG_ERR, "sigaction: %s", get_errmsg());
485 #else /* SA_NOCLDSTOP */
486 /* Old-fashioned UNIX signals */
487 if ((int) signal(SIGHUP, catcher) < 0) {
488 report(LOG_ERR, "signal: %s", get_errmsg());
491 if ((int) signal(SIGUSR1, catcher) < 0) {
492 report(LOG_ERR, "signal: %s", get_errmsg());
495 #endif /* SA_NOCLDSTOP */
498 * Process incoming requests.
508 nfound = select(s + 1, &readfds, NULL, NULL,
509 (timeout) ? &tv : NULL);
511 if (errno != EINTR) {
512 report(LOG_ERR, "select: %s", get_errmsg());
515 * Call readtab() or dumptab() here to avoid the
516 * dangers of doing I/O from a signal handler.
520 readtab(1); /* force read */
524 dumptab(bootpd_dump);
528 if (!FD_ISSET(s, &readfds)) {
530 report(LOG_INFO, "exiting after %jd minutes of inactivity",
531 (intmax_t)actualtimeout.tv_sec / 60);
534 ra_len = sizeof(recv_addr);
535 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
536 (struct sockaddr *) &recv_addr, &ra_len);
541 report(LOG_INFO, "recvd pkt from IP addr %s",
542 inet_ntoa(recv_addr.sin_addr));
544 if (n < sizeof(struct bootp)) {
546 report(LOG_NOTICE, "received short packet");
552 readtab(0); /* maybe re-read bootptab */
570 * Print "usage" message and exit
577 "usage: bootpd [-a] [-i | -s] [-c chdir-path] [-d level] [-h hostname]\n"
578 " [-t timeout] [bootptab [dumpfile]]\n");
579 fprintf(stderr, " -a\tdon't modify ARP table\n");
580 fprintf(stderr, " -c n\tset current directory\n");
581 fprintf(stderr, " -d n\tset debug level\n");
582 fprintf(stderr, " -h n\tset the hostname to listen on\n");
583 fprintf(stderr, " -i\tforce inetd mode (run as child of inetd)\n");
584 fprintf(stderr, " -s\tforce standalone mode (run without inetd)\n");
585 fprintf(stderr, " -t n\tset inetd exit timeout to n minutes\n");
589 /* Signal catchers */
597 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
598 /* For older "System V" derivatives with no sigaction(). */
599 signal(sig, catcher);
606 * Process BOOTREQUEST packet.
608 * Note: This version of the bootpd.c server never forwards
609 * a request to another server. That is the job of a gateway
610 * program such as the "bootpgw" program included here.
612 * (Also this version does not interpret the hostname field of
613 * the request packet; it COULD do a name->address lookup and
614 * forward the request there.)
619 struct bootp *bp = (struct bootp *) pktbuf;
620 struct host *hp = NULL;
621 struct host dummyhost;
623 unsigned hlen, hashcode;
627 char *homedir, *bootfile;
630 if (bp->bp_htype >= hwinfocnt) {
631 report(LOG_NOTICE, "bad hw addr type %u", bp->bp_htype);
634 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
636 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
639 * If the servername field is set, compare it against us.
640 * If we're not being addressed, ignore this request.
641 * If the server name field is null, throw in our name.
643 if (strlen(bp->bp_sname)) {
644 if (strcmp(bp->bp_sname, hostname)) {
647 ignoring request for server %s from client at %s address %s",
648 bp->bp_sname, netname(bp->bp_htype),
649 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
650 /* XXX - Is it correct to ignore such a request? -gwr */
654 strcpy(bp->bp_sname, hostname);
657 /* Convert the request into a reply. */
658 bp->bp_op = BOOTREPLY;
659 if (bp->bp_ciaddr.s_addr == 0) {
661 * client doesn't know his IP address,
662 * search by hardware address.
665 report(LOG_INFO, "request from %s address %s",
666 netname(bp->bp_htype),
667 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
669 hlen = haddrlength(bp->bp_htype);
670 if (hlen != bp->bp_hlen) {
671 report(LOG_NOTICE, "bad addr len from %s address %s",
672 netname(bp->bp_htype),
673 haddrtoa(bp->bp_chaddr, hlen));
675 dummyhost.htype = bp->bp_htype;
676 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
677 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
678 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
681 bp->bp_htype == HTYPE_IEEE802)
683 /* Try again with address in "canonical" form. */
684 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
687 HW addr type is IEEE 802. convert to %s and check again\n",
688 haddrtoa(dummyhost.haddr, bp->bp_hlen));
690 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
691 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
692 hwlookcmp, &dummyhost);
696 * XXX - Add dynamic IP address assignment?
699 report(LOG_NOTICE, "unknown client %s address %s",
700 netname(bp->bp_htype),
701 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
702 return; /* not found */
704 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
709 * search by IP address.
712 report(LOG_INFO, "request from IP addr %s",
713 inet_ntoa(bp->bp_ciaddr));
715 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
716 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
717 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
721 report(LOG_NOTICE, "IP address not found: %s",
722 inet_ntoa(bp->bp_ciaddr));
729 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
730 hp->hostname->string);
734 * If there is a response delay threshold, ignore requests
735 * with a timestamp lower than the threshold.
737 if (hp->flags.min_wait) {
738 u_int32 t = (u_int32) ntohs(bp->bp_secs);
739 if (t < hp->min_wait) {
742 "ignoring request due to timestamp (%d < %d)",
748 #ifdef YORK_EX_OPTION
750 * The need for the "ex" tag arose out of the need to empty
751 * shared networked drives on diskless PCs. This solution is
752 * not very clean but it does work fairly well.
753 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
755 * XXX - This could compromise security if a non-trusted user
756 * managed to write an entry in the bootptab with :ex=trojan:
757 * so I would leave this turned off unless you need it. -gwr
759 /* Run a program, passing the client name as a parameter. */
760 if (hp->flags.exec_file) {
762 /* XXX - Check string lengths? -gwr */
763 strcpy (tst, hp->exec_file->string);
765 strcat (tst, hp->hostname->string);
768 report(LOG_INFO, "executing %s", tst);
769 system(tst); /* Hope this finishes soon... */
771 #endif /* YORK_EX_OPTION */
774 * If a specific TFTP server address was specified in the bootptab file,
775 * fill it in, otherwise zero it.
776 * XXX - Rather than zero it, should it be the bootpd address? -gwr
778 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
779 hp->bootserver.s_addr : 0L;
781 #ifdef STANFORD_PROM_COMPAT
783 * Stanford bootp PROMs (for a Sun?) have no way to leave
784 * the boot file name field blank (because the boot file
785 * name is automatically generated from some index).
786 * As a work-around, this little hack allows those PROMs to
787 * specify "sunboot14" with the same effect as a NULL name.
788 * (The user specifies boot device 14 or some such magic.)
790 if (strcmp(bp->bp_file, "sunboot14") == 0)
791 bp->bp_file[0] = '\0'; /* treat it as unspecified */
795 * Fill in the client's proper bootfile.
797 * If the client specifies an absolute path, try that file with a
798 * ".host" suffix and then without. If the file cannot be found, no
799 * reply is made at all.
801 * If the client specifies a null or relative file, use the following
802 * table to determine the appropriate action:
804 * Homedir Bootfile Client's file
805 * specified? specified? specification Action
806 * -------------------------------------------------------------------
807 * No No Null Send null filename
808 * No No Relative Discard request
809 * No Yes Null Send if absolute else null
810 * No Yes Relative Discard request *XXX
811 * Yes No Null Send null filename
812 * Yes No Relative Lookup with ".host"
813 * Yes Yes Null Send home/boot or bootfile
814 * Yes Yes Relative Lookup with ".host" *XXX
819 * XXX - I don't like the policy of ignoring a client when the
820 * boot file is not accessible. The TFTP server might not be
821 * running on the same machine as the BOOTP server, in which
822 * case checking accessibility of the boot file is pointless.
824 * Therefore, file accessibility is now demanded ONLY if you
825 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
829 * The "real" path is as seen by the BOOTP daemon on this
830 * machine, while the client path is relative to the TFTP
831 * daemon chroot directory (i.e. /tftpboot).
833 if (hp->flags.tftpdir) {
834 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
835 clntpath = &realpath[strlen(realpath)];
842 * Determine client's requested homedir and bootfile.
846 if (bp->bp_file[0]) {
847 homedir = bp->bp_file;
848 bootfile = strrchr(homedir, '/');
850 if (homedir == bootfile)
854 /* no "/" in the string */
859 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
860 (homedir) ? homedir : "",
861 (bootfile) ? bootfile : "");
866 * Specifications in bootptab override client requested values.
868 if (hp->flags.homedir)
869 homedir = hp->homedir->string;
870 if (hp->flags.bootfile)
871 bootfile = hp->bootfile->string;
874 * Construct bootfile path.
877 if (homedir[0] != '/')
878 strcat(clntpath, "/");
879 strcat(clntpath, homedir);
883 if (bootfile[0] != '/')
884 strcat(clntpath, "/");
885 strcat(clntpath, bootfile);
890 * First try to find the file with a ".host" suffix
892 n = strlen(clntpath);
893 strcat(clntpath, ".");
894 strcat(clntpath, hp->hostname->string);
895 if (chk_access(realpath, &bootsize) < 0) {
896 clntpath[n] = 0; /* Try it without the suffix */
897 if (chk_access(realpath, &bootsize) < 0) {
898 /* neither "file.host" nor "file" was found */
899 #ifdef CHECK_FILE_ACCESS
901 if (bp->bp_file[0]) {
903 * Client wanted specific file
904 * and we didn't have it.
907 "requested file not found: \"%s\"", clntpath);
911 * Client didn't ask for a specific file and we couldn't
912 * access the default file, so just zero-out the bootfile
913 * field in the packet and continue processing the reply.
915 bzero(bp->bp_file, sizeof(bp->bp_file));
918 #else /* CHECK_FILE_ACCESS */
920 /* Complain only if boot file size was needed. */
921 if (hp->flags.bootsize_auto) {
922 report(LOG_ERR, "can not determine size of file \"%s\"",
926 #endif /* CHECK_FILE_ACCESS */
929 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
931 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
933 #ifdef CHECK_FILE_ACCESS
935 #endif /* CHECK_FILE_ACCESS */
939 * Handle vendor options based on magic number.
943 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
944 (int) ((bp->bp_vend)[0]),
945 (int) ((bp->bp_vend)[1]),
946 (int) ((bp->bp_vend)[2]),
947 (int) ((bp->bp_vend)[3]));
950 * If this host isn't set for automatic vendor info then copy the
951 * specific cookie into the bootp packet, thus forcing a certain
952 * reply format. Only force reply format if user specified it.
954 if (hp->flags.vm_cookie) {
955 /* Slam in the user specified magic number. */
956 bcopy(hp->vm_cookie, bp->bp_vend, 4);
959 * Figure out the format for the vendor-specific info.
960 * Note that bp->bp_vend may have been set above.
962 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
963 /* RFC1048 conformant bootp client */
964 dovend_rfc1048(bp, hp, bootsize);
966 report(LOG_INFO, "sending reply (with RFC1048 options)");
970 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
973 report(LOG_INFO, "sending reply (with CMU options)");
979 report(LOG_INFO, "sending reply (with no options)");
983 dest = (hp->flags.reply_addr) ?
984 hp->reply_addr.s_addr : 0L;
992 * Process BOOTREPLY packet.
998 report(LOG_INFO, "processing boot reply");
1000 /* forwarded, no destination override */
1006 * Send a reply packet to the client. 'forward' flag is set if we are
1007 * not the originator of this reply packet.
1010 sendreply(int forward, int32 dst_override)
1012 struct bootp *bp = (struct bootp *) pktbuf;
1014 u_short port = bootpc_port;
1019 * XXX - Should honor bp_flags "broadcast" bit here.
1020 * Temporary workaround: use the :ra=ADDR: option to
1021 * set the reply address to the broadcast address.
1025 * If the destination address was specified explicitly
1026 * (i.e. the broadcast address for HP compatibility)
1027 * then send the response to that address. Otherwise,
1028 * act in accordance with RFC951:
1029 * If the client IP address is specified, use that
1030 * else if gateway IP address is specified, use that
1031 * else make a temporary arp cache entry for the client's
1032 * NEW IP/hardware address and use that.
1035 dst.s_addr = dst_override;
1037 report(LOG_INFO, "reply address override: %s",
1040 } else if (bp->bp_ciaddr.s_addr) {
1041 dst = bp->bp_ciaddr;
1042 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1043 dst = bp->bp_giaddr;
1046 report(LOG_INFO, "sending reply to gateway %s",
1050 dst = bp->bp_yiaddr;
1053 if (len > MAXHADDRLEN)
1055 haf = (int) bp->bp_htype;
1057 haf = HTYPE_ETHERNET;
1061 report(LOG_INFO, "setarp %s - %s",
1062 inet_ntoa(dst), haddrtoa(ha, len));
1063 setarp(s, &dst, haf, ha, len);
1067 if ((forward == 0) &&
1068 (bp->bp_siaddr.s_addr == 0))
1071 struct in_addr siaddr;
1073 * If we are originating this reply, we
1074 * need to find our own interface address to
1075 * put in the bp_siaddr field of the reply.
1076 * If this server is multi-homed, pick the
1077 * 'best' interface (the one on the same net
1078 * as the client). Of course, the client may
1079 * be on the other side of a BOOTP gateway...
1081 ifr = getif(s, &dst);
1083 struct sockaddr_in *sip;
1084 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1085 siaddr = sip->sin_addr;
1087 /* Just use my "official" IP address. */
1088 siaddr = my_ip_addr;
1091 /* XXX - No need to set bp_giaddr here. */
1093 /* Finally, set the server address field. */
1094 bp->bp_siaddr = siaddr;
1096 /* Set up socket address for send. */
1097 send_addr.sin_family = AF_INET;
1098 send_addr.sin_port = htons(port);
1099 send_addr.sin_addr = dst;
1101 /* Send reply with same size packet as request used. */
1102 if (sendto(s, pktbuf, pktlen, 0,
1103 (struct sockaddr *) &send_addr,
1104 sizeof(send_addr)) < 0)
1106 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1111 /* nmatch() - now in getif.c */
1112 /* setarp() - now in hwaddr.c */
1116 * This call checks read access to a file. It returns 0 if the file given
1117 * by "path" exists and is publicly readable. A value of -1 is returned if
1118 * access is not permitted or an error occurs. Successful calls also
1119 * return the file size in bytes using the long pointer "filesize".
1121 * The read permission bit for "other" users is checked. This bit must be
1122 * set for tftpd(8) to allow clients to read the file.
1126 chk_access(char *path, int32 *filesize)
1130 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1131 *filesize = (int32) st.st_size;
1140 * Now in dumptab.c :
1143 * list_ipaddresses()
1149 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1150 * bootp packet pointed to by "bp".
1154 dovend_cmu(struct bootp *bp, struct host *hp)
1156 struct cmu_vend *vendp;
1157 struct in_addr_list *taddr;
1160 * Initialize the entire vendor field to zeroes.
1162 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1165 * Fill in vendor information. Subnet mask, default gateway,
1166 * domain name server, ien name server, time server
1168 vendp = (struct cmu_vend *) bp->bp_vend;
1169 strcpy(vendp->v_magic, (char *)vm_cmu);
1170 if (hp->flags.subnet_mask) {
1171 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1172 (vendp->v_flags) |= VF_SMASK;
1173 if (hp->flags.gateway) {
1174 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1177 if (hp->flags.domain_server) {
1178 taddr = hp->domain_server;
1179 if (taddr->addrcount > 0) {
1180 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1181 if (taddr->addrcount > 1) {
1182 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1186 if (hp->flags.name_server) {
1187 taddr = hp->name_server;
1188 if (taddr->addrcount > 0) {
1189 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1190 if (taddr->addrcount > 1) {
1191 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1195 if (hp->flags.time_server) {
1196 taddr = hp->time_server;
1197 if (taddr->addrcount > 0) {
1198 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1199 if (taddr->addrcount > 1) {
1200 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1204 /* Log message now done by caller. */
1207 #endif /* VEND_CMU */
1212 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1213 * bootp packet pointed to by "bp".
1215 #define NEED(LEN, MSG) do \
1216 if (bytesleft < (LEN)) { \
1217 report(LOG_NOTICE, noroom, \
1218 hp->hostname->string, MSG); \
1222 dovend_rfc1048(struct bootp *bp, struct host *hp, int32 bootsize)
1227 static const char noroom[] = "%s: No room for \"%s\" option";
1231 if (hp->flags.msg_size) {
1232 pktlen = hp->msg_size;
1235 * If the request was longer than the official length, build
1236 * a response of that same length where the additional length
1237 * is assumed to be part of the bp_vend (options) area.
1239 if (pktlen > sizeof(*bp)) {
1241 report(LOG_INFO, "request message length=%d", pktlen);
1244 * Check whether the request contains the option:
1245 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1246 * and if so, override the response length with its value.
1247 * This request must lie within the first BP_VEND_LEN
1248 * bytes of the option space.
1256 ep = p + BP_VEND_LEN - 4;
1259 /* Check for tags with no data first. */
1264 /* Now scan the length byte. */
1269 bcopy(p, (char*)&msgsz, 2);
1270 msgsz = ntohs(msgsz);
1273 case TAG_SUBNET_MASK:
1274 /* XXX - Should preserve this if given... */
1280 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1282 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1283 pktlen = msgsz - BP_MSG_OVERHEAD;
1288 if (pktlen < sizeof(*bp)) {
1289 report(LOG_ERR, "invalid response length=%d", pktlen);
1290 pktlen = sizeof(*bp);
1292 bytesleft = ((byte*)bp + pktlen) - vp;
1293 if (pktlen > sizeof(*bp)) {
1295 report(LOG_INFO, "extended reply, length=%d, options=%d",
1299 /* Copy in the magic cookie */
1300 bcopy(vm_rfc1048, vp, 4);
1304 if (hp->flags.subnet_mask) {
1305 /* always enough room here. */
1306 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1307 *vp++ = 4; /* -1 byte */
1308 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1309 bytesleft -= 6; /* Fix real count */
1310 if (hp->flags.gateway) {
1311 (void) insert_ip(TAG_GATEWAY,
1316 if (hp->flags.bootsize) {
1317 /* always enough room here */
1318 bootsize = (hp->flags.bootsize_auto) ?
1319 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1320 *vp++ = TAG_BOOT_SIZE;
1322 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1323 *vp++ = (byte) (bootsize & 0xFF);
1324 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1327 * This one is special: Remaining options go in the ext file.
1328 * Only the subnet_mask, bootsize, and gateway should precede.
1330 if (hp->flags.exten_file) {
1332 * Check for room for exten_file. Add 3 to account for
1333 * TAG_EXTEN_FILE, length, and TAG_END.
1335 len = strlen(hp->exten_file->string);
1336 NEED((len + 3), "ef");
1337 *vp++ = TAG_EXTEN_FILE;
1338 *vp++ = (byte) (len & 0xFF);
1339 bcopy(hp->exten_file->string, vp, len);
1342 bytesleft -= len + 3;
1343 return; /* no more options here. */
1346 * The remaining options are inserted by the following
1347 * function (which is shared with bootpef.c).
1348 * Keep back one byte for the TAG_END.
1350 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1354 /* There should be at least one byte left. */
1359 /* Log message done by caller. */
1360 if (bytesleft > 0) {
1362 * Zero out any remaining part of the vendor area.
1364 bzero(vp, bytesleft);
1366 } /* dovend_rfc1048 */
1371 * Now in readfile.c:
1376 /* haddrtoa() - now in hwaddr.c */
1384 /* get_errmsg() - now in report.c */
1390 * c-argdecl-indent: 4
1391 * c-continued-statement-offset: 4
1392 * c-continued-brace-offset: -4
1393 * c-label-offset: -4