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
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 */
72 # include <fcntl.h> /* for O_RDONLY, etc */
77 /* Yes, memcpy is OK here (no overlapped copies). */
78 # define bcopy(a,b,c) memcpy(b,a,c)
79 # define bzero(p,l) memset(p,0,l)
80 # define bcmp(a,b,c) memcmp(a,b,c)
92 #include "patchlevel.h"
95 #define CONFIG_FILE "/etc/bootptab"
98 #define DUMPTAB_FILE "/tmp/bootpd.dump"
104 * Externals, forward declarations, and global variables
113 extern void dumptab P((char *));
115 PRIVATE void catcher P((int));
116 PRIVATE int chk_access P((char *, int32 *));
118 PRIVATE void dovend_cmu P((struct bootp *, struct host *));
120 PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
121 PRIVATE void handle_reply P((void));
122 PRIVATE void handle_request P((void));
123 PRIVATE void sendreply P((int forward, int32 dest_override));
124 PRIVATE void usage P((void));
129 * IP port numbers for client and server obtained from /etc/services
132 u_short bootps_port, bootpc_port;
136 * Internet socket and interface config structures
139 struct sockaddr_in bind_addr; /* Listening */
140 struct sockaddr_in recv_addr; /* Packet source */
141 struct sockaddr_in send_addr; /* destination */
147 int debug = 0; /* Debugging flag (level) */
148 struct timeval actualtimeout =
149 { /* fifteen minutes */
150 15 * 60L, /* tv_sec */
158 int s; /* Socket file descriptor */
159 char *pktbuf; /* Receive packet buffer */
163 struct in_addr my_ip_addr;
165 static const char *hostname;
166 static char default_hostname[MAXHOSTNAMELEN];
168 /* Flags set by signal catcher. */
169 PRIVATE int do_readtab = 0;
170 PRIVATE int do_dumptab = 0;
173 * Globals below are associated with the bootp database file (bootptab).
176 char *bootptab = CONFIG_FILE;
177 char *bootpd_dump = DUMPTAB_FILE;
182 * Initialization such as command-line processing is done and then the
183 * main server loop is started.
191 struct timeval *timeout;
193 struct servent *servp;
196 int n, ba_len, ra_len;
199 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
203 progname = strrchr(argv[0], '/');
204 if (progname) progname++;
205 else progname = argv[0];
208 * Initialize logging.
210 report_init(0); /* uses progname */
215 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
217 /* Debugging for compilers with struct padding. */
218 assert(sizeof(struct bootp) == BP_MINPKTSZ);
220 /* Get space for receiving packets and composing replies. */
221 pktbuf = malloc(MAX_MSG_SIZE);
223 report(LOG_ERR, "malloc failed");
226 bp = (struct bootp *) pktbuf;
229 * Check to see if a socket was passed to us from inetd.
231 * Use getsockname() to determine if descriptor 0 is indeed a socket
232 * (and thus we are probably a child of inetd) or if it is instead
233 * something else and we are running standalone.
236 ba_len = sizeof(bind_addr);
237 bzero((char *) &bind_addr, ba_len);
240 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
242 * Descriptor 0 is a socket. Assume we are a child of inetd.
244 if (bind_addr.sin_family == AF_INET) {
246 bootps_port = ntohs(bind_addr.sin_port);
248 /* Some other type of socket? */
249 report(LOG_ERR, "getsockname: not an INET socket");
254 * Set defaults that might be changed by option switches.
257 timeout = &actualtimeout;
259 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
260 report(LOG_ERR, "bootpd: can't get hostname\n");
263 default_hostname[sizeof(default_hostname) - 1] = '\0';
264 hostname = default_hostname;
269 for (argc--, argv++; argc > 0; argc--, argv++) {
270 if (argv[0][0] != '-')
272 switch (argv[0][1]) {
274 case 'c': /* chdir_path */
276 stmp = &(argv[0][2]);
282 if (!stmp || (stmp[0] != '/')) {
284 "bootpd: invalid chdir specification\n");
290 case 'd': /* debug level */
292 stmp = &(argv[0][2]);
293 } else if (argv[1] && argv[1][0] == '-') {
295 * Backwards-compatible behavior:
296 * no parameter, so just increment the debug flag.
305 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
307 "%s: invalid debug level\n", progname);
313 case 'h': /* override hostname */
315 stmp = &(argv[0][2]);
323 "bootpd: missing hostname\n");
329 case 'i': /* inetd mode */
333 case 's': /* standalone mode */
337 case 't': /* timeout */
339 stmp = &(argv[0][2]);
345 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
347 "%s: invalid timeout specification\n", progname);
350 actualtimeout.tv_sec = (int32) (60 * n);
352 * If the actual timeout is zero, pass a NULL pointer
353 * to select so it blocks indefinitely, otherwise,
354 * point to the actual timeout value.
356 timeout = (n > 0) ? &actualtimeout : NULL;
360 report(LOG_ERR, "%s: unknown switch: -%c\n",
361 progname, argv[0][1]);
369 * Override default file names if specified on the command line.
375 bootpd_dump = argv[1];
378 * Get my hostname and IP address.
381 hep = gethostbyname(hostname);
383 report(LOG_ERR, "Can not get my IP address\n");
386 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
390 * Go into background and disassociate from controlling terminal.
398 n = open("/dev/tty", O_RDWR);
400 ioctl(n, TIOCNOTTY, (char *) 0);
403 #endif /* TIOCNOTTY */
411 * Nuke any timeout value
415 } /* if standalone (1st) */
417 /* Set the cwd (i.e. to /tftpboot) */
419 if (chdir(chdir_path) < 0)
420 report(LOG_ERR, "%s: chdir failed", chdir_path);
423 /* Get the timezone. */
426 /* Allocate hash tables. */
430 * Read the bootptab file.
432 readtab(1); /* force read */
439 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
440 report(LOG_ERR, "socket: %s", get_network_errmsg());
445 * Get server's listening port number
447 servp = getservbyname("bootps", "udp");
449 bootps_port = ntohs((u_short) servp->s_port);
451 bootps_port = (u_short) IPPORT_BOOTPS;
453 "udp/bootps: unknown service -- assuming port %d",
458 * Bind socket to BOOTPS port.
460 bind_addr.sin_family = AF_INET;
461 bind_addr.sin_addr.s_addr = INADDR_ANY;
462 bind_addr.sin_port = htons(bootps_port);
463 if (bind(s, (struct sockaddr *) &bind_addr,
464 sizeof(bind_addr)) < 0)
466 report(LOG_ERR, "bind: %s", get_network_errmsg());
469 } /* if standalone (2nd)*/
472 * Get destination port number so we can reply to client
474 servp = getservbyname("bootpc", "udp");
476 bootpc_port = ntohs(servp->s_port);
479 "udp/bootpc: unknown service -- assuming port %d",
481 bootpc_port = (u_short) IPPORT_BOOTPC;
485 * Set up signals to read or dump the table.
487 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
488 sa.sa_handler = catcher;
489 sigemptyset(&sa.sa_mask);
491 if (sigaction(SIGHUP, &sa, NULL) < 0) {
492 report(LOG_ERR, "sigaction: %s", get_errmsg());
495 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
496 report(LOG_ERR, "sigaction: %s", get_errmsg());
499 #else /* SA_NOCLDSTOP */
500 /* Old-fashioned UNIX signals */
501 if ((int) signal(SIGHUP, catcher) < 0) {
502 report(LOG_ERR, "signal: %s", get_errmsg());
505 if ((int) signal(SIGUSR1, catcher) < 0) {
506 report(LOG_ERR, "signal: %s", get_errmsg());
509 #endif /* SA_NOCLDSTOP */
512 * Process incoming requests.
521 nfound = select(s + 1, (fd_set *)&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 (!(readfds & (1 << s))) {
543 report(LOG_INFO, "exiting after %ld minutes of inactivity",
544 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 [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
591 fprintf(stderr, "\t -c n\tset current directory\n");
592 fprintf(stderr, "\t -d n\tset debug level\n");
593 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
594 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
595 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
599 /* Signal catchers */
608 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
609 /* For older "System V" derivatives with no sigaction(). */
610 signal(sig, catcher);
617 * Process BOOTREQUEST packet.
619 * Note: This version of the bootpd.c server never forwards
620 * a request to another server. That is the job of a gateway
621 * program such as the "bootpgw" program included here.
623 * (Also this version does not interpret the hostname field of
624 * the request packet; it COULD do a name->address lookup and
625 * forward the request there.)
630 struct bootp *bp = (struct bootp *) pktbuf;
631 struct host *hp = NULL;
632 struct host dummyhost;
634 unsigned hlen, hashcode;
638 char *homedir, *bootfile;
641 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
643 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
646 * If the servername field is set, compare it against us.
647 * If we're not being addressed, ignore this request.
648 * If the server name field is null, throw in our name.
650 if (strlen(bp->bp_sname)) {
651 if (strcmp(bp->bp_sname, hostname)) {
654 ignoring request for server %s from client at %s address %s",
655 bp->bp_sname, netname(bp->bp_htype),
656 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
657 /* XXX - Is it correct to ignore such a request? -gwr */
661 strcpy(bp->bp_sname, hostname);
664 /* Convert the request into a reply. */
665 bp->bp_op = BOOTREPLY;
666 if (bp->bp_ciaddr.s_addr == 0) {
668 * client doesnt know his IP address,
669 * search by hardware address.
672 report(LOG_INFO, "request from %s address %s",
673 netname(bp->bp_htype),
674 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
676 hlen = haddrlength(bp->bp_htype);
677 if (hlen != bp->bp_hlen) {
678 report(LOG_NOTICE, "bad addr len from from %s address %s",
679 netname(bp->bp_htype),
680 haddrtoa(bp->bp_chaddr, hlen));
682 dummyhost.htype = bp->bp_htype;
683 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
684 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
685 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
688 bp->bp_htype == HTYPE_IEEE802)
690 /* Try again with address in "canonical" form. */
691 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
694 HW addr type is IEEE 802. convert to %s and check again\n",
695 haddrtoa(dummyhost.haddr, bp->bp_hlen));
697 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
698 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
699 hwlookcmp, &dummyhost);
703 * XXX - Add dynamic IP address assignment?
706 report(LOG_NOTICE, "unknown client %s address %s",
707 netname(bp->bp_htype),
708 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
709 return; /* not found */
711 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
716 * search by IP address.
719 report(LOG_INFO, "request from IP addr %s",
720 inet_ntoa(bp->bp_ciaddr));
722 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
723 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
724 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
728 report(LOG_NOTICE, "IP address not found: %s",
729 inet_ntoa(bp->bp_ciaddr));
736 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
737 hp->hostname->string);
741 * If there is a response delay threshold, ignore requests
742 * with a timestamp lower than the threshold.
744 if (hp->flags.min_wait) {
745 u_int32 t = (u_int32) ntohs(bp->bp_secs);
746 if (t < hp->min_wait) {
749 "ignoring request due to timestamp (%d < %d)",
755 #ifdef YORK_EX_OPTION
757 * The need for the "ex" tag arose out of the need to empty
758 * shared networked drives on diskless PCs. This solution is
759 * not very clean but it does work fairly well.
760 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
762 * XXX - This could compromise security if a non-trusted user
763 * managed to write an entry in the bootptab with :ex=trojan:
764 * so I would leave this turned off unless you need it. -gwr
766 /* Run a program, passing the client name as a parameter. */
767 if (hp->flags.exec_file) {
769 /* XXX - Check string lengths? -gwr */
770 strcpy (tst, hp->exec_file->string);
772 strcat (tst, hp->hostname->string);
775 report(LOG_INFO, "executing %s", tst);
776 system(tst); /* Hope this finishes soon... */
778 #endif /* YORK_EX_OPTION */
781 * If a specific TFTP server address was specified in the bootptab file,
782 * fill it in, otherwise zero it.
783 * XXX - Rather than zero it, should it be the bootpd address? -gwr
785 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
786 hp->bootserver.s_addr : 0L;
788 #ifdef STANFORD_PROM_COMPAT
790 * Stanford bootp PROMs (for a Sun?) have no way to leave
791 * the boot file name field blank (because the boot file
792 * name is automatically generated from some index).
793 * As a work-around, this little hack allows those PROMs to
794 * specify "sunboot14" with the same effect as a NULL name.
795 * (The user specifies boot device 14 or some such magic.)
797 if (strcmp(bp->bp_file, "sunboot14") == 0)
798 bp->bp_file[0] = '\0'; /* treat it as unspecified */
802 * Fill in the client's proper bootfile.
804 * If the client specifies an absolute path, try that file with a
805 * ".host" suffix and then without. If the file cannot be found, no
806 * reply is made at all.
808 * If the client specifies a null or relative file, use the following
809 * table to determine the appropriate action:
811 * Homedir Bootfile Client's file
812 * specified? specified? specification Action
813 * -------------------------------------------------------------------
814 * No No Null Send null filename
815 * No No Relative Discard request
816 * No Yes Null Send if absolute else null
817 * No Yes Relative Discard request *XXX
818 * Yes No Null Send null filename
819 * Yes No Relative Lookup with ".host"
820 * Yes Yes Null Send home/boot or bootfile
821 * Yes Yes Relative Lookup with ".host" *XXX
826 * XXX - I don't like the policy of ignoring a client when the
827 * boot file is not accessible. The TFTP server might not be
828 * running on the same machine as the BOOTP server, in which
829 * case checking accessibility of the boot file is pointless.
831 * Therefore, file accessibility is now demanded ONLY if you
832 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
836 * The "real" path is as seen by the BOOTP daemon on this
837 * machine, while the client path is relative to the TFTP
838 * daemon chroot directory (i.e. /tftpboot).
840 if (hp->flags.tftpdir) {
841 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
842 clntpath = &realpath[strlen(realpath)];
849 * Determine client's requested homedir and bootfile.
853 if (bp->bp_file[0]) {
854 homedir = bp->bp_file;
855 bootfile = strrchr(homedir, '/');
857 if (homedir == bootfile)
861 /* no "/" in the string */
866 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
867 (homedir) ? homedir : "",
868 (bootfile) ? bootfile : "");
873 * Specifications in bootptab override client requested values.
875 if (hp->flags.homedir)
876 homedir = hp->homedir->string;
877 if (hp->flags.bootfile)
878 bootfile = hp->bootfile->string;
881 * Construct bootfile path.
884 if (homedir[0] != '/')
885 strcat(clntpath, "/");
886 strcat(clntpath, homedir);
890 if (bootfile[0] != '/')
891 strcat(clntpath, "/");
892 strcat(clntpath, bootfile);
897 * First try to find the file with a ".host" suffix
899 n = strlen(clntpath);
900 strcat(clntpath, ".");
901 strcat(clntpath, hp->hostname->string);
902 if (chk_access(realpath, &bootsize) < 0) {
903 clntpath[n] = 0; /* Try it without the suffix */
904 if (chk_access(realpath, &bootsize) < 0) {
905 /* neither "file.host" nor "file" was found */
906 #ifdef CHECK_FILE_ACCESS
908 if (bp->bp_file[0]) {
910 * Client wanted specific file
911 * and we didn't have it.
914 "requested file not found: \"%s\"", clntpath);
918 * Client didn't ask for a specific file and we couldn't
919 * access the default file, so just zero-out the bootfile
920 * field in the packet and continue processing the reply.
922 bzero(bp->bp_file, sizeof(bp->bp_file));
925 #else /* CHECK_FILE_ACCESS */
927 /* Complain only if boot file size was needed. */
928 if (hp->flags.bootsize_auto) {
929 report(LOG_ERR, "can not determine size of file \"%s\"",
933 #endif /* CHECK_FILE_ACCESS */
936 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
938 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
940 #ifdef CHECK_FILE_ACCESS
942 #endif /* CHECK_FILE_ACCESS */
946 * Handle vendor options based on magic number.
950 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
951 (int) ((bp->bp_vend)[0]),
952 (int) ((bp->bp_vend)[1]),
953 (int) ((bp->bp_vend)[2]),
954 (int) ((bp->bp_vend)[3]));
957 * If this host isn't set for automatic vendor info then copy the
958 * specific cookie into the bootp packet, thus forcing a certain
959 * reply format. Only force reply format if user specified it.
961 if (hp->flags.vm_cookie) {
962 /* Slam in the user specified magic number. */
963 bcopy(hp->vm_cookie, bp->bp_vend, 4);
966 * Figure out the format for the vendor-specific info.
967 * Note that bp->bp_vend may have been set above.
969 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
970 /* RFC1048 conformant bootp client */
971 dovend_rfc1048(bp, hp, bootsize);
973 report(LOG_INFO, "sending reply (with RFC1048 options)");
977 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
980 report(LOG_INFO, "sending reply (with CMU options)");
986 report(LOG_INFO, "sending reply (with no options)");
990 dest = (hp->flags.reply_addr) ?
991 hp->reply_addr.s_addr : 0L;
999 * Process BOOTREPLY packet.
1005 report(LOG_INFO, "processing boot reply");
1007 /* forwarded, no destination override */
1013 * Send a reply packet to the client. 'forward' flag is set if we are
1014 * not the originator of this reply packet.
1017 sendreply(forward, dst_override)
1021 struct bootp *bp = (struct bootp *) pktbuf;
1023 u_short port = bootpc_port;
1028 * XXX - Should honor bp_flags "broadcast" bit here.
1029 * Temporary workaround: use the :ra=ADDR: option to
1030 * set the reply address to the broadcast address.
1034 * If the destination address was specified explicitly
1035 * (i.e. the broadcast address for HP compatiblity)
1036 * then send the response to that address. Otherwise,
1037 * act in accordance with RFC951:
1038 * If the client IP address is specified, use that
1039 * else if gateway IP address is specified, use that
1040 * else make a temporary arp cache entry for the client's
1041 * NEW IP/hardware address and use that.
1044 dst.s_addr = dst_override;
1046 report(LOG_INFO, "reply address override: %s",
1049 } else if (bp->bp_ciaddr.s_addr) {
1050 dst = bp->bp_ciaddr;
1051 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1052 dst = bp->bp_giaddr;
1055 report(LOG_INFO, "sending reply to gateway %s",
1059 dst = bp->bp_yiaddr;
1062 if (len > MAXHADDRLEN)
1064 haf = (int) bp->bp_htype;
1066 haf = HTYPE_ETHERNET;
1069 report(LOG_INFO, "setarp %s - %s",
1070 inet_ntoa(dst), haddrtoa(ha, len));
1071 setarp(s, &dst, haf, ha, len);
1074 if ((forward == 0) &&
1075 (bp->bp_siaddr.s_addr == 0))
1078 struct in_addr siaddr;
1080 * If we are originating this reply, we
1081 * need to find our own interface address to
1082 * put in the bp_siaddr field of the reply.
1083 * If this server is multi-homed, pick the
1084 * 'best' interface (the one on the same net
1085 * as the client). Of course, the client may
1086 * be on the other side of a BOOTP gateway...
1088 ifr = getif(s, &dst);
1090 struct sockaddr_in *sip;
1091 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1092 siaddr = sip->sin_addr;
1094 /* Just use my "official" IP address. */
1095 siaddr = my_ip_addr;
1098 /* XXX - No need to set bp_giaddr here. */
1100 /* Finally, set the server address field. */
1101 bp->bp_siaddr = siaddr;
1103 /* Set up socket address for send. */
1104 send_addr.sin_family = AF_INET;
1105 send_addr.sin_port = htons(port);
1106 send_addr.sin_addr = dst;
1108 /* Send reply with same size packet as request used. */
1109 if (sendto(s, pktbuf, pktlen, 0,
1110 (struct sockaddr *) &send_addr,
1111 sizeof(send_addr)) < 0)
1113 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1118 /* nmatch() - now in getif.c */
1119 /* setarp() - now in hwaddr.c */
1123 * This call checks read access to a file. It returns 0 if the file given
1124 * by "path" exists and is publically readable. A value of -1 is returned if
1125 * access is not permitted or an error occurs. Successful calls also
1126 * return the file size in bytes using the long pointer "filesize".
1128 * The read permission bit for "other" users is checked. This bit must be
1129 * set for tftpd(8) to allow clients to read the file.
1133 chk_access(path, filesize)
1139 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1140 *filesize = (int32) st.st_size;
1149 * Now in dumptab.c :
1152 * list_ipaddresses()
1158 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1159 * bootp packet pointed to by "bp".
1167 struct cmu_vend *vendp;
1168 struct in_addr_list *taddr;
1171 * Initialize the entire vendor field to zeroes.
1173 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1176 * Fill in vendor information. Subnet mask, default gateway,
1177 * domain name server, ien name server, time server
1179 vendp = (struct cmu_vend *) bp->bp_vend;
1180 strcpy(vendp->v_magic, (char *)vm_cmu);
1181 if (hp->flags.subnet_mask) {
1182 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1183 (vendp->v_flags) |= VF_SMASK;
1184 if (hp->flags.gateway) {
1185 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1188 if (hp->flags.domain_server) {
1189 taddr = hp->domain_server;
1190 if (taddr->addrcount > 0) {
1191 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1192 if (taddr->addrcount > 1) {
1193 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1197 if (hp->flags.name_server) {
1198 taddr = hp->name_server;
1199 if (taddr->addrcount > 0) {
1200 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1201 if (taddr->addrcount > 1) {
1202 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1206 if (hp->flags.time_server) {
1207 taddr = hp->time_server;
1208 if (taddr->addrcount > 0) {
1209 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1210 if (taddr->addrcount > 1) {
1211 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1215 /* Log message now done by caller. */
1218 #endif /* VEND_CMU */
1223 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1224 * bootp packet pointed to by "bp".
1226 #define NEED(LEN, MSG) do \
1227 if (bytesleft < (LEN)) { \
1228 report(LOG_NOTICE, noroom, \
1229 hp->hostname->string, MSG); \
1233 dovend_rfc1048(bp, hp, bootsize)
1241 static char noroom[] = "%s: No room for \"%s\" option";
1245 if (hp->flags.msg_size) {
1246 pktlen = hp->msg_size;
1249 * If the request was longer than the official length, build
1250 * a response of that same length where the additional length
1251 * is assumed to be part of the bp_vend (options) area.
1253 if (pktlen > sizeof(*bp)) {
1255 report(LOG_INFO, "request message length=%d", pktlen);
1258 * Check whether the request contains the option:
1259 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1260 * and if so, override the response length with its value.
1261 * This request must lie within the first BP_VEND_LEN
1262 * bytes of the option space.
1270 ep = p + BP_VEND_LEN - 4;
1273 /* Check for tags with no data first. */
1278 /* Now scan the length byte. */
1283 bcopy(p, (char*)&msgsz, 2);
1284 msgsz = ntohs(msgsz);
1287 case TAG_SUBNET_MASK:
1288 /* XXX - Should preserve this if given... */
1294 if (msgsz > sizeof(*bp)) {
1296 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1302 if (pktlen < sizeof(*bp)) {
1303 report(LOG_ERR, "invalid response length=%d", pktlen);
1304 pktlen = sizeof(*bp);
1306 bytesleft = ((byte*)bp + pktlen) - vp;
1307 if (pktlen > sizeof(*bp)) {
1309 report(LOG_INFO, "extended reply, length=%d, options=%d",
1313 /* Copy in the magic cookie */
1314 bcopy(vm_rfc1048, vp, 4);
1318 if (hp->flags.subnet_mask) {
1319 /* always enough room here. */
1320 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1321 *vp++ = 4; /* -1 byte */
1322 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1323 bytesleft -= 6; /* Fix real count */
1324 if (hp->flags.gateway) {
1325 (void) insert_ip(TAG_GATEWAY,
1330 if (hp->flags.bootsize) {
1331 /* always enough room here */
1332 bootsize = (hp->flags.bootsize_auto) ?
1333 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1334 *vp++ = TAG_BOOT_SIZE;
1336 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1337 *vp++ = (byte) (bootsize & 0xFF);
1338 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1341 * This one is special: Remaining options go in the ext file.
1342 * Only the subnet_mask, bootsize, and gateway should precede.
1344 if (hp->flags.exten_file) {
1346 * Check for room for exten_file. Add 3 to account for
1347 * TAG_EXTEN_FILE, length, and TAG_END.
1349 len = strlen(hp->exten_file->string);
1350 NEED((len + 3), "ef");
1351 *vp++ = TAG_EXTEN_FILE;
1352 *vp++ = (byte) (len & 0xFF);
1353 bcopy(hp->exten_file->string, vp, len);
1356 bytesleft -= len + 3;
1357 return; /* no more options here. */
1360 * The remaining options are inserted by the following
1361 * function (which is shared with bootpef.c).
1362 * Keep back one byte for the TAG_END.
1364 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1368 /* There should be at least one byte left. */
1373 /* Log message done by caller. */
1374 if (bytesleft > 0) {
1376 * Zero out any remaining part of the vendor area.
1378 bzero(vp, bytesleft);
1380 } /* dovend_rfc1048 */
1385 * Now in readfile.c:
1390 /* haddrtoa() - now in hwaddr.c */
1398 /* get_errmsg() - now in report.c */
1404 * c-argdecl-indent: 4
1405 * c-continued-statement-offset: 4
1406 * c-continued-brace-offset: -4
1407 * c-label-offset: -4