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 $FreeBSD: src/libexec/bootpd/bootpd.c,v 1.13.2.3 2003/02/15 05:36:01 kris Exp $
24 ************************************************************************/
27 * BOOTP (bootstrap protocol) server daemon.
29 * Answers BOOTP request packets from booting client machines.
30 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
31 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
32 * See RFC 1395 for option tags 14-17.
33 * See accompanying man page -- bootpd.8
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/ioctl.h>
51 #include <sys/utsname.h>
54 #include <netinet/in.h>
55 #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
114 extern void dumptab P((char *));
116 PRIVATE void catcher P((int));
117 PRIVATE int chk_access P((char *, int32 *));
119 PRIVATE void dovend_cmu P((struct bootp *, struct host *));
121 PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
122 PRIVATE void handle_reply P((void));
123 PRIVATE void handle_request P((void));
124 PRIVATE void sendreply P((int forward, int32 dest_override));
125 PRIVATE void usage P((void));
130 * IP port numbers for client and server obtained from /etc/services
133 u_short bootps_port, bootpc_port;
137 * Internet socket and interface config structures
140 struct sockaddr_in bind_addr; /* Listening */
141 struct sockaddr_in recv_addr; /* Packet source */
142 struct sockaddr_in send_addr; /* destination */
148 int debug = 0; /* Debugging flag (level) */
149 struct timeval actualtimeout =
150 { /* fifteen minutes */
151 15 * 60L, /* tv_sec */
159 int s; /* Socket file descriptor */
160 char *pktbuf; /* Receive packet buffer */
164 struct in_addr my_ip_addr;
166 static const char *hostname;
167 static char default_hostname[MAXHOSTNAMELEN];
169 /* Flags set by signal catcher. */
170 PRIVATE int do_readtab = 0;
171 PRIVATE int do_dumptab = 0;
174 * Globals below are associated with the bootp database file (bootptab).
177 char *bootptab = CONFIG_FILE;
178 char *bootpd_dump = DUMPTAB_FILE;
183 * Initialization such as command-line processing is done and then the
184 * main server loop is started.
192 struct timeval *timeout;
194 struct servent *servp;
197 int n, ba_len, ra_len;
200 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
204 progname = strrchr(argv[0], '/');
205 if (progname) progname++;
206 else progname = argv[0];
209 * Initialize logging.
211 report_init(0); /* uses progname */
216 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
218 /* Debugging for compilers with struct padding. */
219 assert(sizeof(struct bootp) == BP_MINPKTSZ);
221 /* Get space for receiving packets and composing replies. */
222 pktbuf = malloc(MAX_MSG_SIZE);
224 report(LOG_ERR, "malloc failed");
227 bp = (struct bootp *) pktbuf;
230 * Check to see if a socket was passed to us from inetd.
232 * Use getsockname() to determine if descriptor 0 is indeed a socket
233 * (and thus we are probably a child of inetd) or if it is instead
234 * something else and we are running standalone.
237 ba_len = sizeof(bind_addr);
238 bzero((char *) &bind_addr, ba_len);
241 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
243 * Descriptor 0 is a socket. Assume we are a child of inetd.
245 if (bind_addr.sin_family == AF_INET) {
247 bootps_port = ntohs(bind_addr.sin_port);
249 /* Some other type of socket? */
250 report(LOG_ERR, "getsockname: not an INET socket");
255 * Set defaults that might be changed by option switches.
258 timeout = &actualtimeout;
260 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
261 report(LOG_ERR, "bootpd: can't get hostname\n");
264 default_hostname[sizeof(default_hostname) - 1] = '\0';
265 hostname = default_hostname;
270 for (argc--, argv++; argc > 0; argc--, argv++) {
271 if (argv[0][0] != '-')
273 switch (argv[0][1]) {
275 case 'c': /* chdir_path */
277 stmp = &(argv[0][2]);
283 if (!stmp || (stmp[0] != '/')) {
285 "bootpd: invalid chdir specification\n");
291 case 'd': /* debug level */
293 stmp = &(argv[0][2]);
294 } else if (argv[1] && argv[1][0] == '-') {
296 * Backwards-compatible behavior:
297 * no parameter, so just increment the debug flag.
306 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
308 "%s: invalid debug level\n", progname);
314 case 'h': /* override hostname */
316 stmp = &(argv[0][2]);
324 "bootpd: missing hostname\n");
330 case 'i': /* inetd mode */
334 case 's': /* standalone mode */
338 case 't': /* timeout */
340 stmp = &(argv[0][2]);
346 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
348 "%s: invalid timeout specification\n", progname);
351 actualtimeout.tv_sec = (int32) (60 * n);
353 * If the actual timeout is zero, pass a NULL pointer
354 * to select so it blocks indefinitely, otherwise,
355 * point to the actual timeout value.
357 timeout = (n > 0) ? &actualtimeout : NULL;
361 report(LOG_ERR, "%s: unknown switch: -%c\n",
362 progname, argv[0][1]);
370 * Override default file names if specified on the command line.
376 bootpd_dump = argv[1];
379 * Get my hostname and IP address.
382 hep = gethostbyname(hostname);
384 report(LOG_ERR, "Can not get my IP address\n");
387 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
391 * Go into background and disassociate from controlling terminal.
399 n = open(_PATH_TTY, O_RDWR);
401 ioctl(n, TIOCNOTTY, (char *) 0);
404 #endif /* TIOCNOTTY */
412 * Nuke any timeout value
416 } /* if standalone (1st) */
418 /* Set the cwd (i.e. to /tftpboot) */
420 if (chdir(chdir_path) < 0)
421 report(LOG_ERR, "%s: chdir failed", chdir_path);
424 /* Get the timezone. */
427 /* Allocate hash tables. */
431 * Read the bootptab file.
433 readtab(1); /* force read */
440 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
441 report(LOG_ERR, "socket: %s", get_network_errmsg());
446 * Get server's listening port number
448 servp = getservbyname("bootps", "udp");
450 bootps_port = ntohs((u_short) servp->s_port);
452 bootps_port = (u_short) IPPORT_BOOTPS;
454 "udp/bootps: unknown service -- assuming port %d",
459 * Bind socket to BOOTPS port.
461 bind_addr.sin_family = AF_INET;
462 bind_addr.sin_addr.s_addr = INADDR_ANY;
463 bind_addr.sin_port = htons(bootps_port);
464 if (bind(s, (struct sockaddr *) &bind_addr,
465 sizeof(bind_addr)) < 0)
467 report(LOG_ERR, "bind: %s", get_network_errmsg());
470 } /* if standalone (2nd)*/
473 * Get destination port number so we can reply to client
475 servp = getservbyname("bootpc", "udp");
477 bootpc_port = ntohs(servp->s_port);
480 "udp/bootpc: unknown service -- assuming port %d",
482 bootpc_port = (u_short) IPPORT_BOOTPC;
486 * Set up signals to read or dump the table.
488 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
489 sa.sa_handler = catcher;
490 sigemptyset(&sa.sa_mask);
492 if (sigaction(SIGHUP, &sa, NULL) < 0) {
493 report(LOG_ERR, "sigaction: %s", get_errmsg());
496 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
497 report(LOG_ERR, "sigaction: %s", get_errmsg());
500 #else /* SA_NOCLDSTOP */
501 /* Old-fashioned UNIX signals */
502 if ((int) signal(SIGHUP, catcher) < 0) {
503 report(LOG_ERR, "signal: %s", get_errmsg());
506 if ((int) signal(SIGUSR1, catcher) < 0) {
507 report(LOG_ERR, "signal: %s", get_errmsg());
510 #endif /* SA_NOCLDSTOP */
513 * Process incoming requests.
522 nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL,
523 (timeout) ? &tv : NULL);
525 if (errno != EINTR) {
526 report(LOG_ERR, "select: %s", get_errmsg());
529 * Call readtab() or dumptab() here to avoid the
530 * dangers of doing I/O from a signal handler.
534 readtab(1); /* force read */
538 dumptab(bootpd_dump);
542 if (!(readfds & (1 << s))) {
544 report(LOG_INFO, "exiting after %ld minutes of inactivity",
545 actualtimeout.tv_sec / 60);
548 ra_len = sizeof(recv_addr);
549 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
550 (struct sockaddr *) &recv_addr, &ra_len);
555 report(LOG_INFO, "recvd pkt from IP addr %s",
556 inet_ntoa(recv_addr.sin_addr));
558 if (n < sizeof(struct bootp)) {
560 report(LOG_NOTICE, "received short packet");
566 readtab(0); /* maybe re-read bootptab */
584 * Print "usage" message and exit
591 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
592 fprintf(stderr, "\t -c n\tset current directory\n");
593 fprintf(stderr, "\t -d n\tset debug level\n");
594 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
595 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
596 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
600 /* Signal catchers */
609 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
610 /* For older "System V" derivatives with no sigaction(). */
611 signal(sig, catcher);
618 * Process BOOTREQUEST packet.
620 * Note: This version of the bootpd.c server never forwards
621 * a request to another server. That is the job of a gateway
622 * program such as the "bootpgw" program included here.
624 * (Also this version does not interpret the hostname field of
625 * the request packet; it COULD do a name->address lookup and
626 * forward the request there.)
631 struct bootp *bp = (struct bootp *) pktbuf;
632 struct host *hp = NULL;
633 struct host dummyhost;
635 unsigned hlen, hashcode;
639 char *homedir, *bootfile;
642 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
644 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
647 * If the servername field is set, compare it against us.
648 * If we're not being addressed, ignore this request.
649 * If the server name field is null, throw in our name.
651 if (strlen(bp->bp_sname)) {
652 if (strcmp(bp->bp_sname, hostname)) {
655 ignoring request for server %s from client at %s address %s",
656 bp->bp_sname, netname(bp->bp_htype),
657 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
658 /* XXX - Is it correct to ignore such a request? -gwr */
662 strcpy(bp->bp_sname, hostname);
665 /* Convert the request into a reply. */
666 bp->bp_op = BOOTREPLY;
667 if (bp->bp_ciaddr.s_addr == 0) {
669 * client doesnt know his IP address,
670 * search by hardware address.
673 report(LOG_INFO, "request from %s address %s",
674 netname(bp->bp_htype),
675 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
677 hlen = haddrlength(bp->bp_htype);
678 if (hlen != bp->bp_hlen) {
679 report(LOG_NOTICE, "bad addr len from from %s address %s",
680 netname(bp->bp_htype),
681 haddrtoa(bp->bp_chaddr, hlen));
683 dummyhost.htype = bp->bp_htype;
684 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
685 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
686 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
689 bp->bp_htype == HTYPE_IEEE802)
691 /* Try again with address in "canonical" form. */
692 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
695 HW addr type is IEEE 802. convert to %s and check again\n",
696 haddrtoa(dummyhost.haddr, bp->bp_hlen));
698 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
699 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
700 hwlookcmp, &dummyhost);
704 * XXX - Add dynamic IP address assignment?
707 report(LOG_NOTICE, "unknown client %s address %s",
708 netname(bp->bp_htype),
709 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
710 return; /* not found */
712 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
717 * search by IP address.
720 report(LOG_INFO, "request from IP addr %s",
721 inet_ntoa(bp->bp_ciaddr));
723 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
724 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
725 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
729 report(LOG_NOTICE, "IP address not found: %s",
730 inet_ntoa(bp->bp_ciaddr));
737 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
738 hp->hostname->string);
742 * If there is a response delay threshold, ignore requests
743 * with a timestamp lower than the threshold.
745 if (hp->flags.min_wait) {
746 u_int32 t = (u_int32) ntohs(bp->bp_secs);
747 if (t < hp->min_wait) {
750 "ignoring request due to timestamp (%d < %d)",
756 #ifdef YORK_EX_OPTION
758 * The need for the "ex" tag arose out of the need to empty
759 * shared networked drives on diskless PCs. This solution is
760 * not very clean but it does work fairly well.
761 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
763 * XXX - This could compromise security if a non-trusted user
764 * managed to write an entry in the bootptab with :ex=trojan:
765 * so I would leave this turned off unless you need it. -gwr
767 /* Run a program, passing the client name as a parameter. */
768 if (hp->flags.exec_file) {
770 /* XXX - Check string lengths? -gwr */
771 strcpy (tst, hp->exec_file->string);
773 strcat (tst, hp->hostname->string);
776 report(LOG_INFO, "executing %s", tst);
777 system(tst); /* Hope this finishes soon... */
779 #endif /* YORK_EX_OPTION */
782 * If a specific TFTP server address was specified in the bootptab file,
783 * fill it in, otherwise zero it.
784 * XXX - Rather than zero it, should it be the bootpd address? -gwr
786 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
787 hp->bootserver.s_addr : 0L;
789 #ifdef STANFORD_PROM_COMPAT
791 * Stanford bootp PROMs (for a Sun?) have no way to leave
792 * the boot file name field blank (because the boot file
793 * name is automatically generated from some index).
794 * As a work-around, this little hack allows those PROMs to
795 * specify "sunboot14" with the same effect as a NULL name.
796 * (The user specifies boot device 14 or some such magic.)
798 if (strcmp(bp->bp_file, "sunboot14") == 0)
799 bp->bp_file[0] = '\0'; /* treat it as unspecified */
803 * Fill in the client's proper bootfile.
805 * If the client specifies an absolute path, try that file with a
806 * ".host" suffix and then without. If the file cannot be found, no
807 * reply is made at all.
809 * If the client specifies a null or relative file, use the following
810 * table to determine the appropriate action:
812 * Homedir Bootfile Client's file
813 * specified? specified? specification Action
814 * -------------------------------------------------------------------
815 * No No Null Send null filename
816 * No No Relative Discard request
817 * No Yes Null Send if absolute else null
818 * No Yes Relative Discard request *XXX
819 * Yes No Null Send null filename
820 * Yes No Relative Lookup with ".host"
821 * Yes Yes Null Send home/boot or bootfile
822 * Yes Yes Relative Lookup with ".host" *XXX
827 * XXX - I don't like the policy of ignoring a client when the
828 * boot file is not accessible. The TFTP server might not be
829 * running on the same machine as the BOOTP server, in which
830 * case checking accessibility of the boot file is pointless.
832 * Therefore, file accessibility is now demanded ONLY if you
833 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
837 * The "real" path is as seen by the BOOTP daemon on this
838 * machine, while the client path is relative to the TFTP
839 * daemon chroot directory (i.e. /tftpboot).
841 if (hp->flags.tftpdir) {
842 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
843 clntpath = &realpath[strlen(realpath)];
850 * Determine client's requested homedir and bootfile.
854 if (bp->bp_file[0]) {
855 homedir = bp->bp_file;
856 bootfile = strrchr(homedir, '/');
858 if (homedir == bootfile)
862 /* no "/" in the string */
867 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
868 (homedir) ? homedir : "",
869 (bootfile) ? bootfile : "");
874 * Specifications in bootptab override client requested values.
876 if (hp->flags.homedir)
877 homedir = hp->homedir->string;
878 if (hp->flags.bootfile)
879 bootfile = hp->bootfile->string;
882 * Construct bootfile path.
885 if (homedir[0] != '/')
886 strcat(clntpath, "/");
887 strcat(clntpath, homedir);
891 if (bootfile[0] != '/')
892 strcat(clntpath, "/");
893 strcat(clntpath, bootfile);
898 * First try to find the file with a ".host" suffix
900 n = strlen(clntpath);
901 strcat(clntpath, ".");
902 strcat(clntpath, hp->hostname->string);
903 if (chk_access(realpath, &bootsize) < 0) {
904 clntpath[n] = 0; /* Try it without the suffix */
905 if (chk_access(realpath, &bootsize) < 0) {
906 /* neither "file.host" nor "file" was found */
907 #ifdef CHECK_FILE_ACCESS
909 if (bp->bp_file[0]) {
911 * Client wanted specific file
912 * and we didn't have it.
915 "requested file not found: \"%s\"", clntpath);
919 * Client didn't ask for a specific file and we couldn't
920 * access the default file, so just zero-out the bootfile
921 * field in the packet and continue processing the reply.
923 bzero(bp->bp_file, sizeof(bp->bp_file));
926 #else /* CHECK_FILE_ACCESS */
928 /* Complain only if boot file size was needed. */
929 if (hp->flags.bootsize_auto) {
930 report(LOG_ERR, "can not determine size of file \"%s\"",
934 #endif /* CHECK_FILE_ACCESS */
937 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
939 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
941 #ifdef CHECK_FILE_ACCESS
943 #endif /* CHECK_FILE_ACCESS */
947 * Handle vendor options based on magic number.
951 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
952 (int) ((bp->bp_vend)[0]),
953 (int) ((bp->bp_vend)[1]),
954 (int) ((bp->bp_vend)[2]),
955 (int) ((bp->bp_vend)[3]));
958 * If this host isn't set for automatic vendor info then copy the
959 * specific cookie into the bootp packet, thus forcing a certain
960 * reply format. Only force reply format if user specified it.
962 if (hp->flags.vm_cookie) {
963 /* Slam in the user specified magic number. */
964 bcopy(hp->vm_cookie, bp->bp_vend, 4);
967 * Figure out the format for the vendor-specific info.
968 * Note that bp->bp_vend may have been set above.
970 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
971 /* RFC1048 conformant bootp client */
972 dovend_rfc1048(bp, hp, bootsize);
974 report(LOG_INFO, "sending reply (with RFC1048 options)");
978 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
981 report(LOG_INFO, "sending reply (with CMU options)");
987 report(LOG_INFO, "sending reply (with no options)");
991 dest = (hp->flags.reply_addr) ?
992 hp->reply_addr.s_addr : 0L;
1000 * Process BOOTREPLY packet.
1006 report(LOG_INFO, "processing boot reply");
1008 /* forwarded, no destination override */
1014 * Send a reply packet to the client. 'forward' flag is set if we are
1015 * not the originator of this reply packet.
1018 sendreply(forward, dst_override)
1022 struct bootp *bp = (struct bootp *) pktbuf;
1024 u_short port = bootpc_port;
1029 * XXX - Should honor bp_flags "broadcast" bit here.
1030 * Temporary workaround: use the :ra=ADDR: option to
1031 * set the reply address to the broadcast address.
1035 * If the destination address was specified explicitly
1036 * (i.e. the broadcast address for HP compatiblity)
1037 * then send the response to that address. Otherwise,
1038 * act in accordance with RFC951:
1039 * If the client IP address is specified, use that
1040 * else if gateway IP address is specified, use that
1041 * else make a temporary arp cache entry for the client's
1042 * NEW IP/hardware address and use that.
1045 dst.s_addr = dst_override;
1047 report(LOG_INFO, "reply address override: %s",
1050 } else if (bp->bp_ciaddr.s_addr) {
1051 dst = bp->bp_ciaddr;
1052 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1053 dst = bp->bp_giaddr;
1056 report(LOG_INFO, "sending reply to gateway %s",
1060 dst = bp->bp_yiaddr;
1063 if (len > MAXHADDRLEN)
1065 haf = (int) bp->bp_htype;
1067 haf = HTYPE_ETHERNET;
1070 report(LOG_INFO, "setarp %s - %s",
1071 inet_ntoa(dst), haddrtoa(ha, len));
1072 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 publically 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