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 */
85 #include "patchlevel.h"
88 #define CONFIG_FILE "/etc/bootptab"
91 #define DUMPTAB_FILE "/tmp/bootpd.dump"
97 * Externals, forward declarations, and global variables
100 extern void dumptab(char *);
102 PRIVATE void catcher(int);
103 PRIVATE int chk_access(char *, int32 *);
105 PRIVATE void dovend_cmu(struct bootp *, struct host *);
107 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
108 PRIVATE void handle_reply(void);
109 PRIVATE void handle_request(void);
110 PRIVATE void sendreply(int forward, int32 dest_override);
111 PRIVATE void usage(void);
114 * IP port numbers for client and server obtained from /etc/services
117 u_short bootps_port, bootpc_port;
121 * Internet socket and interface config structures
124 struct sockaddr_in bind_addr; /* Listening */
125 struct sockaddr_in recv_addr; /* Packet source */
126 struct sockaddr_in send_addr; /* destination */
132 int debug = 0; /* Debugging flag (level) */
133 struct timeval actualtimeout =
134 { /* fifteen minutes */
135 15 * 60L, /* tv_sec */
138 int arpmod = TRUE; /* modify the ARP table */
144 int s; /* Socket file descriptor */
145 char *pktbuf; /* Receive packet buffer */
149 struct in_addr my_ip_addr;
151 static const char *hostname;
152 static char default_hostname[MAXHOSTNAMELEN];
154 /* Flags set by signal catcher. */
155 PRIVATE int do_readtab = 0;
156 PRIVATE int do_dumptab = 0;
159 * Globals below are associated with the bootp database file (bootptab).
162 char *bootptab = CONFIG_FILE;
163 char *bootpd_dump = DUMPTAB_FILE;
168 * Initialization such as command-line processing is done and then the
169 * main server loop is started.
177 struct timeval *timeout;
179 struct servent *servp;
182 socklen_t ba_len, ra_len;
187 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
191 progname = strrchr(argv[0], '/');
192 if (progname) progname++;
193 else progname = argv[0];
196 * Initialize logging.
198 report_init(0); /* uses progname */
203 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
205 /* Debugging for compilers with struct padding. */
206 assert(sizeof(struct bootp) == BP_MINPKTSZ);
208 /* Get space for receiving packets and composing replies. */
209 pktbuf = malloc(MAX_MSG_SIZE);
211 report(LOG_ERR, "malloc failed");
214 bp = (struct bootp *) pktbuf;
217 * Check to see if a socket was passed to us from inetd.
219 * Use getsockname() to determine if descriptor 0 is indeed a socket
220 * (and thus we are probably a child of inetd) or if it is instead
221 * something else and we are running standalone.
224 ba_len = sizeof(bind_addr);
225 bzero((char *) &bind_addr, ba_len);
228 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
230 * Descriptor 0 is a socket. Assume we are a child of inetd.
232 if (bind_addr.sin_family == AF_INET) {
234 bootps_port = ntohs(bind_addr.sin_port);
236 /* Some other type of socket? */
237 report(LOG_ERR, "getsockname: not an INET socket");
242 * Set defaults that might be changed by option switches.
245 timeout = &actualtimeout;
247 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
248 report(LOG_ERR, "bootpd: can't get hostname\n");
251 default_hostname[sizeof(default_hostname) - 1] = '\0';
252 hostname = default_hostname;
257 for (argc--, argv++; argc > 0; argc--, argv++) {
258 if (argv[0][0] != '-')
260 switch (argv[0][1]) {
262 case 'a': /* don't modify the ARP table */
265 case 'c': /* chdir_path */
267 stmp = &(argv[0][2]);
273 if (!stmp || (stmp[0] != '/')) {
275 "bootpd: invalid chdir specification\n");
281 case 'd': /* debug level */
283 stmp = &(argv[0][2]);
284 } else if (argv[1] && argv[1][0] == '-') {
286 * Backwards-compatible behavior:
287 * no parameter, so just increment the debug flag.
296 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
298 "%s: invalid debug level\n", progname);
304 case 'h': /* override hostname */
306 stmp = &(argv[0][2]);
314 "bootpd: missing hostname\n");
320 case 'i': /* inetd mode */
324 case 's': /* standalone mode */
328 case 't': /* timeout */
330 stmp = &(argv[0][2]);
336 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
338 "%s: invalid timeout specification\n", progname);
341 actualtimeout.tv_sec = (int32) (60 * n);
343 * If the actual timeout is zero, pass a NULL pointer
344 * to select so it blocks indefinitely, otherwise,
345 * point to the actual timeout value.
347 timeout = (n > 0) ? &actualtimeout : NULL;
351 report(LOG_ERR, "%s: unknown switch: -%c\n",
352 progname, argv[0][1]);
360 * Override default file names if specified on the command line.
366 bootpd_dump = argv[1];
369 * Get my hostname and IP address.
372 hep = gethostbyname(hostname);
374 report(LOG_ERR, "Can not get my IP address\n");
377 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
381 * Go into background and disassociate from controlling terminal.
389 n = open(_PATH_TTY, O_RDWR);
391 ioctl(n, TIOCNOTTY, (char *) 0);
394 #endif /* TIOCNOTTY */
402 * Nuke any timeout value
406 } /* if standalone (1st) */
408 /* Set the cwd (i.e. to /tftpboot) */
410 if (chdir(chdir_path) < 0)
411 report(LOG_ERR, "%s: chdir failed", chdir_path);
414 /* Get the timezone. */
417 /* Allocate hash tables. */
421 * Read the bootptab file.
423 readtab(1); /* force read */
430 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
431 report(LOG_ERR, "socket: %s", get_network_errmsg());
436 * Get server's listening port number
438 servp = getservbyname("bootps", "udp");
440 bootps_port = ntohs((u_short) servp->s_port);
442 bootps_port = (u_short) IPPORT_BOOTPS;
444 "bootps/udp: unknown service -- using port %d",
449 * Bind socket to BOOTPS port.
451 bind_addr.sin_family = AF_INET;
452 bind_addr.sin_addr.s_addr = INADDR_ANY;
453 bind_addr.sin_port = htons(bootps_port);
454 if (bind(s, (struct sockaddr *) &bind_addr,
455 sizeof(bind_addr)) < 0)
457 report(LOG_ERR, "bind: %s", get_network_errmsg());
460 } /* if standalone (2nd)*/
463 * Get destination port number so we can reply to client
465 servp = getservbyname("bootpc", "udp");
467 bootpc_port = ntohs(servp->s_port);
470 "bootpc/udp: unknown service -- using port %d",
472 bootpc_port = (u_short) IPPORT_BOOTPC;
476 * Set up signals to read or dump the table.
478 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
479 sa.sa_handler = catcher;
480 sigemptyset(&sa.sa_mask);
482 if (sigaction(SIGHUP, &sa, NULL) < 0) {
483 report(LOG_ERR, "sigaction: %s", get_errmsg());
486 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
487 report(LOG_ERR, "sigaction: %s", get_errmsg());
490 #else /* SA_NOCLDSTOP */
491 /* Old-fashioned UNIX signals */
492 if ((int) signal(SIGHUP, catcher) < 0) {
493 report(LOG_ERR, "signal: %s", get_errmsg());
496 if ((int) signal(SIGUSR1, catcher) < 0) {
497 report(LOG_ERR, "signal: %s", get_errmsg());
500 #endif /* SA_NOCLDSTOP */
503 * Process incoming requests.
513 nfound = select(s + 1, &readfds, NULL, NULL,
514 (timeout) ? &tv : NULL);
516 if (errno != EINTR) {
517 report(LOG_ERR, "select: %s", get_errmsg());
520 * Call readtab() or dumptab() here to avoid the
521 * dangers of doing I/O from a signal handler.
525 readtab(1); /* force read */
529 dumptab(bootpd_dump);
533 if (!FD_ISSET(s, &readfds)) {
535 report(LOG_INFO, "exiting after %jd minutes of inactivity",
536 (intmax_t)actualtimeout.tv_sec / 60);
539 ra_len = sizeof(recv_addr);
540 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
541 (struct sockaddr *) &recv_addr, &ra_len);
546 report(LOG_INFO, "recvd pkt from IP addr %s",
547 inet_ntoa(recv_addr.sin_addr));
549 if (n < sizeof(struct bootp)) {
551 report(LOG_NOTICE, "received short packet");
557 readtab(0); /* maybe re-read bootptab */
575 * Print "usage" message and exit
582 "usage: bootpd [-a] [-i | -s] [-c chdir-path] [-d level] [-h hostname]\n"
583 " [-t timeout] [bootptab [dumpfile]]\n");
584 fprintf(stderr, "\t -a\tdon't modify ARP table\n");
585 fprintf(stderr, "\t -c n\tset current directory\n");
586 fprintf(stderr, "\t -d n\tset debug level\n");
587 fprintf(stderr, "\t -h n\tset the hostname to listen on\n");
588 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
589 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
590 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
594 /* Signal catchers */
603 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
604 /* For older "System V" derivatives with no sigaction(). */
605 signal(sig, catcher);
612 * Process BOOTREQUEST packet.
614 * Note: This version of the bootpd.c server never forwards
615 * a request to another server. That is the job of a gateway
616 * program such as the "bootpgw" program included here.
618 * (Also this version does not interpret the hostname field of
619 * the request packet; it COULD do a name->address lookup and
620 * forward the request there.)
625 struct bootp *bp = (struct bootp *) pktbuf;
626 struct host *hp = NULL;
627 struct host dummyhost;
629 unsigned hlen, hashcode;
633 char *homedir, *bootfile;
636 if (bp->bp_htype >= hwinfocnt) {
637 report(LOG_NOTICE, "bad hw addr type %u", bp->bp_htype);
640 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
642 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
645 * If the servername field is set, compare it against us.
646 * If we're not being addressed, ignore this request.
647 * If the server name field is null, throw in our name.
649 if (strlen(bp->bp_sname)) {
650 if (strcmp(bp->bp_sname, hostname)) {
653 ignoring request for server %s from client at %s address %s",
654 bp->bp_sname, netname(bp->bp_htype),
655 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
656 /* XXX - Is it correct to ignore such a request? -gwr */
660 strcpy(bp->bp_sname, hostname);
663 /* Convert the request into a reply. */
664 bp->bp_op = BOOTREPLY;
665 if (bp->bp_ciaddr.s_addr == 0) {
667 * client doesn't know his IP address,
668 * search by hardware address.
671 report(LOG_INFO, "request from %s address %s",
672 netname(bp->bp_htype),
673 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
675 hlen = haddrlength(bp->bp_htype);
676 if (hlen != bp->bp_hlen) {
677 report(LOG_NOTICE, "bad addr len from %s address %s",
678 netname(bp->bp_htype),
679 haddrtoa(bp->bp_chaddr, hlen));
681 dummyhost.htype = bp->bp_htype;
682 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
683 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
684 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
687 bp->bp_htype == HTYPE_IEEE802)
689 /* Try again with address in "canonical" form. */
690 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
693 HW addr type is IEEE 802. convert to %s and check again\n",
694 haddrtoa(dummyhost.haddr, bp->bp_hlen));
696 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
697 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
698 hwlookcmp, &dummyhost);
702 * XXX - Add dynamic IP address assignment?
705 report(LOG_NOTICE, "unknown client %s address %s",
706 netname(bp->bp_htype),
707 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
708 return; /* not found */
710 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
715 * search by IP address.
718 report(LOG_INFO, "request from IP addr %s",
719 inet_ntoa(bp->bp_ciaddr));
721 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
722 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
723 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
727 report(LOG_NOTICE, "IP address not found: %s",
728 inet_ntoa(bp->bp_ciaddr));
735 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
736 hp->hostname->string);
740 * If there is a response delay threshold, ignore requests
741 * with a timestamp lower than the threshold.
743 if (hp->flags.min_wait) {
744 u_int32 t = (u_int32) ntohs(bp->bp_secs);
745 if (t < hp->min_wait) {
748 "ignoring request due to timestamp (%d < %d)",
754 #ifdef YORK_EX_OPTION
756 * The need for the "ex" tag arose out of the need to empty
757 * shared networked drives on diskless PCs. This solution is
758 * not very clean but it does work fairly well.
759 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
761 * XXX - This could compromise security if a non-trusted user
762 * managed to write an entry in the bootptab with :ex=trojan:
763 * so I would leave this turned off unless you need it. -gwr
765 /* Run a program, passing the client name as a parameter. */
766 if (hp->flags.exec_file) {
768 /* XXX - Check string lengths? -gwr */
769 strcpy (tst, hp->exec_file->string);
771 strcat (tst, hp->hostname->string);
774 report(LOG_INFO, "executing %s", tst);
775 system(tst); /* Hope this finishes soon... */
777 #endif /* YORK_EX_OPTION */
780 * If a specific TFTP server address was specified in the bootptab file,
781 * fill it in, otherwise zero it.
782 * XXX - Rather than zero it, should it be the bootpd address? -gwr
784 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
785 hp->bootserver.s_addr : 0L;
787 #ifdef STANFORD_PROM_COMPAT
789 * Stanford bootp PROMs (for a Sun?) have no way to leave
790 * the boot file name field blank (because the boot file
791 * name is automatically generated from some index).
792 * As a work-around, this little hack allows those PROMs to
793 * specify "sunboot14" with the same effect as a NULL name.
794 * (The user specifies boot device 14 or some such magic.)
796 if (strcmp(bp->bp_file, "sunboot14") == 0)
797 bp->bp_file[0] = '\0'; /* treat it as unspecified */
801 * Fill in the client's proper bootfile.
803 * If the client specifies an absolute path, try that file with a
804 * ".host" suffix and then without. If the file cannot be found, no
805 * reply is made at all.
807 * If the client specifies a null or relative file, use the following
808 * table to determine the appropriate action:
810 * Homedir Bootfile Client's file
811 * specified? specified? specification Action
812 * -------------------------------------------------------------------
813 * No No Null Send null filename
814 * No No Relative Discard request
815 * No Yes Null Send if absolute else null
816 * No Yes Relative Discard request *XXX
817 * Yes No Null Send null filename
818 * Yes No Relative Lookup with ".host"
819 * Yes Yes Null Send home/boot or bootfile
820 * Yes Yes Relative Lookup with ".host" *XXX
825 * XXX - I don't like the policy of ignoring a client when the
826 * boot file is not accessible. The TFTP server might not be
827 * running on the same machine as the BOOTP server, in which
828 * case checking accessibility of the boot file is pointless.
830 * Therefore, file accessibility is now demanded ONLY if you
831 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
835 * The "real" path is as seen by the BOOTP daemon on this
836 * machine, while the client path is relative to the TFTP
837 * daemon chroot directory (i.e. /tftpboot).
839 if (hp->flags.tftpdir) {
840 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
841 clntpath = &realpath[strlen(realpath)];
848 * Determine client's requested homedir and bootfile.
852 if (bp->bp_file[0]) {
853 homedir = bp->bp_file;
854 bootfile = strrchr(homedir, '/');
856 if (homedir == bootfile)
860 /* no "/" in the string */
865 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
866 (homedir) ? homedir : "",
867 (bootfile) ? bootfile : "");
872 * Specifications in bootptab override client requested values.
874 if (hp->flags.homedir)
875 homedir = hp->homedir->string;
876 if (hp->flags.bootfile)
877 bootfile = hp->bootfile->string;
880 * Construct bootfile path.
883 if (homedir[0] != '/')
884 strcat(clntpath, "/");
885 strcat(clntpath, homedir);
889 if (bootfile[0] != '/')
890 strcat(clntpath, "/");
891 strcat(clntpath, bootfile);
896 * First try to find the file with a ".host" suffix
898 n = strlen(clntpath);
899 strcat(clntpath, ".");
900 strcat(clntpath, hp->hostname->string);
901 if (chk_access(realpath, &bootsize) < 0) {
902 clntpath[n] = 0; /* Try it without the suffix */
903 if (chk_access(realpath, &bootsize) < 0) {
904 /* neither "file.host" nor "file" was found */
905 #ifdef CHECK_FILE_ACCESS
907 if (bp->bp_file[0]) {
909 * Client wanted specific file
910 * and we didn't have it.
913 "requested file not found: \"%s\"", clntpath);
917 * Client didn't ask for a specific file and we couldn't
918 * access the default file, so just zero-out the bootfile
919 * field in the packet and continue processing the reply.
921 bzero(bp->bp_file, sizeof(bp->bp_file));
924 #else /* CHECK_FILE_ACCESS */
926 /* Complain only if boot file size was needed. */
927 if (hp->flags.bootsize_auto) {
928 report(LOG_ERR, "can not determine size of file \"%s\"",
932 #endif /* CHECK_FILE_ACCESS */
935 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
937 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
939 #ifdef CHECK_FILE_ACCESS
941 #endif /* CHECK_FILE_ACCESS */
945 * Handle vendor options based on magic number.
949 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
950 (int) ((bp->bp_vend)[0]),
951 (int) ((bp->bp_vend)[1]),
952 (int) ((bp->bp_vend)[2]),
953 (int) ((bp->bp_vend)[3]));
956 * If this host isn't set for automatic vendor info then copy the
957 * specific cookie into the bootp packet, thus forcing a certain
958 * reply format. Only force reply format if user specified it.
960 if (hp->flags.vm_cookie) {
961 /* Slam in the user specified magic number. */
962 bcopy(hp->vm_cookie, bp->bp_vend, 4);
965 * Figure out the format for the vendor-specific info.
966 * Note that bp->bp_vend may have been set above.
968 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
969 /* RFC1048 conformant bootp client */
970 dovend_rfc1048(bp, hp, bootsize);
972 report(LOG_INFO, "sending reply (with RFC1048 options)");
976 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
979 report(LOG_INFO, "sending reply (with CMU options)");
985 report(LOG_INFO, "sending reply (with no options)");
989 dest = (hp->flags.reply_addr) ?
990 hp->reply_addr.s_addr : 0L;
998 * Process BOOTREPLY packet.
1004 report(LOG_INFO, "processing boot reply");
1006 /* forwarded, no destination override */
1012 * Send a reply packet to the client. 'forward' flag is set if we are
1013 * not the originator of this reply packet.
1016 sendreply(forward, dst_override)
1020 struct bootp *bp = (struct bootp *) pktbuf;
1022 u_short port = bootpc_port;
1027 * XXX - Should honor bp_flags "broadcast" bit here.
1028 * Temporary workaround: use the :ra=ADDR: option to
1029 * set the reply address to the broadcast address.
1033 * If the destination address was specified explicitly
1034 * (i.e. the broadcast address for HP compatibility)
1035 * then send the response to that address. Otherwise,
1036 * act in accordance with RFC951:
1037 * If the client IP address is specified, use that
1038 * else if gateway IP address is specified, use that
1039 * else make a temporary arp cache entry for the client's
1040 * NEW IP/hardware address and use that.
1043 dst.s_addr = dst_override;
1045 report(LOG_INFO, "reply address override: %s",
1048 } else if (bp->bp_ciaddr.s_addr) {
1049 dst = bp->bp_ciaddr;
1050 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1051 dst = bp->bp_giaddr;
1054 report(LOG_INFO, "sending reply to gateway %s",
1058 dst = bp->bp_yiaddr;
1061 if (len > MAXHADDRLEN)
1063 haf = (int) bp->bp_htype;
1065 haf = HTYPE_ETHERNET;
1069 report(LOG_INFO, "setarp %s - %s",
1070 inet_ntoa(dst), haddrtoa(ha, len));
1071 setarp(s, &dst, haf, ha, len);
1075 if ((forward == 0) &&
1076 (bp->bp_siaddr.s_addr == 0))
1079 struct in_addr siaddr;
1081 * If we are originating this reply, we
1082 * need to find our own interface address to
1083 * put in the bp_siaddr field of the reply.
1084 * If this server is multi-homed, pick the
1085 * 'best' interface (the one on the same net
1086 * as the client). Of course, the client may
1087 * be on the other side of a BOOTP gateway...
1089 ifr = getif(s, &dst);
1091 struct sockaddr_in *sip;
1092 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1093 siaddr = sip->sin_addr;
1095 /* Just use my "official" IP address. */
1096 siaddr = my_ip_addr;
1099 /* XXX - No need to set bp_giaddr here. */
1101 /* Finally, set the server address field. */
1102 bp->bp_siaddr = siaddr;
1104 /* Set up socket address for send. */
1105 send_addr.sin_family = AF_INET;
1106 send_addr.sin_port = htons(port);
1107 send_addr.sin_addr = dst;
1109 /* Send reply with same size packet as request used. */
1110 if (sendto(s, pktbuf, pktlen, 0,
1111 (struct sockaddr *) &send_addr,
1112 sizeof(send_addr)) < 0)
1114 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1119 /* nmatch() - now in getif.c */
1120 /* setarp() - now in hwaddr.c */
1124 * This call checks read access to a file. It returns 0 if the file given
1125 * by "path" exists and is publicly readable. A value of -1 is returned if
1126 * access is not permitted or an error occurs. Successful calls also
1127 * return the file size in bytes using the long pointer "filesize".
1129 * The read permission bit for "other" users is checked. This bit must be
1130 * set for tftpd(8) to allow clients to read the file.
1134 chk_access(path, filesize)
1140 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1141 *filesize = (int32) st.st_size;
1150 * Now in dumptab.c :
1153 * list_ipaddresses()
1159 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1160 * bootp packet pointed to by "bp".
1168 struct cmu_vend *vendp;
1169 struct in_addr_list *taddr;
1172 * Initialize the entire vendor field to zeroes.
1174 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1177 * Fill in vendor information. Subnet mask, default gateway,
1178 * domain name server, ien name server, time server
1180 vendp = (struct cmu_vend *) bp->bp_vend;
1181 strcpy(vendp->v_magic, (char *)vm_cmu);
1182 if (hp->flags.subnet_mask) {
1183 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1184 (vendp->v_flags) |= VF_SMASK;
1185 if (hp->flags.gateway) {
1186 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1189 if (hp->flags.domain_server) {
1190 taddr = hp->domain_server;
1191 if (taddr->addrcount > 0) {
1192 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1193 if (taddr->addrcount > 1) {
1194 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1198 if (hp->flags.name_server) {
1199 taddr = hp->name_server;
1200 if (taddr->addrcount > 0) {
1201 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1202 if (taddr->addrcount > 1) {
1203 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1207 if (hp->flags.time_server) {
1208 taddr = hp->time_server;
1209 if (taddr->addrcount > 0) {
1210 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1211 if (taddr->addrcount > 1) {
1212 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1216 /* Log message now done by caller. */
1219 #endif /* VEND_CMU */
1224 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1225 * bootp packet pointed to by "bp".
1227 #define NEED(LEN, MSG) do \
1228 if (bytesleft < (LEN)) { \
1229 report(LOG_NOTICE, noroom, \
1230 hp->hostname->string, MSG); \
1234 dovend_rfc1048(bp, hp, bootsize)
1242 static const char noroom[] = "%s: No room for \"%s\" option";
1246 if (hp->flags.msg_size) {
1247 pktlen = hp->msg_size;
1250 * If the request was longer than the official length, build
1251 * a response of that same length where the additional length
1252 * is assumed to be part of the bp_vend (options) area.
1254 if (pktlen > sizeof(*bp)) {
1256 report(LOG_INFO, "request message length=%d", pktlen);
1259 * Check whether the request contains the option:
1260 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1261 * and if so, override the response length with its value.
1262 * This request must lie within the first BP_VEND_LEN
1263 * bytes of the option space.
1271 ep = p + BP_VEND_LEN - 4;
1274 /* Check for tags with no data first. */
1279 /* Now scan the length byte. */
1284 bcopy(p, (char*)&msgsz, 2);
1285 msgsz = ntohs(msgsz);
1288 case TAG_SUBNET_MASK:
1289 /* XXX - Should preserve this if given... */
1295 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1297 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1298 pktlen = msgsz - BP_MSG_OVERHEAD;
1303 if (pktlen < sizeof(*bp)) {
1304 report(LOG_ERR, "invalid response length=%d", pktlen);
1305 pktlen = sizeof(*bp);
1307 bytesleft = ((byte*)bp + pktlen) - vp;
1308 if (pktlen > sizeof(*bp)) {
1310 report(LOG_INFO, "extended reply, length=%d, options=%d",
1314 /* Copy in the magic cookie */
1315 bcopy(vm_rfc1048, vp, 4);
1319 if (hp->flags.subnet_mask) {
1320 /* always enough room here. */
1321 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1322 *vp++ = 4; /* -1 byte */
1323 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1324 bytesleft -= 6; /* Fix real count */
1325 if (hp->flags.gateway) {
1326 (void) insert_ip(TAG_GATEWAY,
1331 if (hp->flags.bootsize) {
1332 /* always enough room here */
1333 bootsize = (hp->flags.bootsize_auto) ?
1334 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1335 *vp++ = TAG_BOOT_SIZE;
1337 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1338 *vp++ = (byte) (bootsize & 0xFF);
1339 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1342 * This one is special: Remaining options go in the ext file.
1343 * Only the subnet_mask, bootsize, and gateway should precede.
1345 if (hp->flags.exten_file) {
1347 * Check for room for exten_file. Add 3 to account for
1348 * TAG_EXTEN_FILE, length, and TAG_END.
1350 len = strlen(hp->exten_file->string);
1351 NEED((len + 3), "ef");
1352 *vp++ = TAG_EXTEN_FILE;
1353 *vp++ = (byte) (len & 0xFF);
1354 bcopy(hp->exten_file->string, vp, len);
1357 bytesleft -= len + 3;
1358 return; /* no more options here. */
1361 * The remaining options are inserted by the following
1362 * function (which is shared with bootpef.c).
1363 * Keep back one byte for the TAG_END.
1365 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1369 /* There should be at least one byte left. */
1374 /* Log message done by caller. */
1375 if (bytesleft > 0) {
1377 * Zero out any remaining part of the vendor area.
1379 bzero(vp, bytesleft);
1381 } /* dovend_rfc1048 */
1386 * Now in readfile.c:
1391 /* haddrtoa() - now in hwaddr.c */
1399 /* get_errmsg() - now in report.c */
1405 * c-argdecl-indent: 4
1406 * c-continued-statement-offset: 4
1407 * c-continued-brace-offset: -4
1408 * c-label-offset: -4