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
21 ************************************************************************/
23 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: bootpd.c,v 1.22 2008/05/02 19:22:10 xtraeme Exp $");
29 * BOOTP (bootstrap protocol) server daemon.
31 * Answers BOOTP request packets from booting client machines.
32 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
33 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
34 * See RFC 1395 for option tags 14-17.
35 * See accompanying man page -- bootpd.8
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h> /* inet_ntoa */
74 # include <fcntl.h> /* for O_RDONLY, etc */
78 /* Using sigset() avoids the need to re-arm each time. */
91 #include "patchlevel.h"
94 #define CONFIG_FILE "/etc/bootptab"
97 #define DUMPTAB_FILE "/tmp/bootpd.dump"
103 * Externals, forward declarations, and global variables
106 extern void dumptab(const char *);
108 PRIVATE
void catcher(int);
109 PRIVATE
int chk_access(char *, int32
*);
111 PRIVATE
void dovend_cmu(struct bootp
*, struct host
*);
113 PRIVATE
void dovend_rfc1048(struct bootp
*, struct host
*, int32
);
114 PRIVATE
void handle_reply(void);
115 PRIVATE
void handle_request(void);
116 PRIVATE
void sendreply(int forward
, int32 dest_override
);
117 PRIVATE
void usage(void);
118 int main(int, char **);
121 * IP port numbers for client and server obtained from /etc/services
124 u_short bootps_port
, bootpc_port
;
128 * Internet socket and interface config structures
131 struct sockaddr_in bind_addr
; /* Listening */
132 struct sockaddr_in recv_addr
; /* Packet source */
133 struct sockaddr_in send_addr
; /* destination */
139 int debug
= 0; /* Debugging flag (level) */
140 int actualtimeout
= 15 * 60000; /* fifteen minutes */
146 int s
; /* Socket file descriptor */
147 char *pktbuf
; /* Receive packet buffer */
149 const char *progname
;
151 char hostname
[MAXHOSTNAMELEN
+ 1]; /* System host name */
152 struct in_addr my_ip_addr
;
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 const char *bootptab
= CONFIG_FILE
;
163 const char *bootpd_dump
= DUMPTAB_FILE
;
168 * Initialization such as command-line processing is done and then the
169 * main server loop is started.
173 main(int argc
, char **argv
)
177 struct servent
*servp
;
180 socklen_t ba_len
, ra_len
;
183 struct pollfd set
[1];
186 progname
= strrchr(argv
[0], '/');
193 * Initialize logging.
195 report_init(0); /* uses progname */
200 report(LOG_INFO
, "version %s.%d", VERSION
, PATCHLEVEL
);
202 /* Debugging for compilers with struct padding. */
203 assert(sizeof(struct bootp
) == BP_MINPKTSZ
);
205 /* Get space for receiving packets and composing replies. */
206 pktbuf
= malloc(MAX_MSG_SIZE
);
208 report(LOG_ERR
, "malloc failed");
211 bp
= (struct bootp
*) pktbuf
;
214 * Check to see if a socket was passed to us from inetd.
216 * Use getsockname() to determine if descriptor 0 is indeed a socket
217 * (and thus we are probably a child of inetd) or if it is instead
218 * something else and we are running standalone.
221 ba_len
= sizeof(bind_addr
);
222 bzero((char *) &bind_addr
, ba_len
);
225 if (getsockname(s
, (struct sockaddr
*) &bind_addr
, &ba_len
) == 0) {
227 * Descriptor 0 is a socket. Assume we are a child of inetd.
229 if (bind_addr
.sin_family
== AF_INET
) {
231 bootps_port
= ntohs(bind_addr
.sin_port
);
233 /* Some other type of socket? */
234 report(LOG_ERR
, "getsockname: not an INET socket");
239 * Set defaults that might be changed by option switches.
242 timeout
= actualtimeout
;
247 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
248 if (argv
[0][0] != '-')
250 switch (argv
[0][1]) {
252 case 'c': /* chdir_path */
254 stmp
= &(argv
[0][2]);
260 if (!stmp
|| (stmp
[0] != '/')) {
262 "bootpd: invalid chdir specification\n");
268 case 'd': /* debug level */
270 stmp
= &(argv
[0][2]);
271 } else if (argv
[1] && argv
[1][0] == '-') {
273 * Backwards-compatible behavior:
274 * no parameter, so just increment the debug flag.
283 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
285 "%s: invalid debug level\n", progname
);
291 case 'h': /* override hostname */
293 stmp
= &(argv
[0][2]);
301 "bootpd: missing hostname\n");
304 strlcpy(hostname
, stmp
, sizeof(hostname
));
307 case 'i': /* inetd mode */
311 case 's': /* standalone mode */
315 case 't': /* timeout */
317 stmp
= &(argv
[0][2]);
323 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
325 "%s: invalid timeout specification\n", progname
);
328 actualtimeout
= n
* 60000;
330 * If the actual timeout is zero, pass INFTIM
331 * to poll so it blocks indefinitely, otherwise,
332 * use the actual timeout value.
334 timeout
= (n
> 0) ? actualtimeout
: INFTIM
;
338 fprintf(stderr
, "%s: unknown switch: -%c\n",
339 progname
, argv
[0][1]);
347 * Override default file names if specified on the command line.
353 bootpd_dump
= argv
[1];
356 * Get my hostname and IP address.
358 if (hostname
[0] == '\0') {
359 if (gethostname(hostname
, sizeof(hostname
)) == -1) {
360 fprintf(stderr
, "bootpd: can't get hostname\n");
363 hostname
[sizeof(hostname
) - 1] = '\0';
365 hep
= gethostbyname(hostname
);
367 fprintf(stderr
, "Can not get my IP address\n");
370 bcopy(hep
->h_addr
, (char *)&my_ip_addr
, sizeof(my_ip_addr
));
374 * Go into background and disassociate from controlling terminal.
382 n
= open("/dev/tty", O_RDWR
);
384 ioctl(n
, TIOCNOTTY
, (char *) 0);
387 #endif /* TIOCNOTTY */
395 * Nuke any timeout value
399 } /* if standalone (1st) */
401 /* Set the cwd (i.e. to /tftpboot) */
403 if (chdir(chdir_path
) < 0)
404 report(LOG_ERR
, "%s: chdir failed", chdir_path
);
407 /* Get the timezone. */
410 /* Allocate hash tables. */
414 * Read the bootptab file.
416 readtab(1); /* force read */
423 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
424 report(LOG_ERR
, "socket: %s", get_network_errmsg());
429 * Get server's listening port number
431 servp
= getservbyname("bootps", "udp");
433 bootps_port
= ntohs((u_short
) servp
->s_port
);
435 bootps_port
= (u_short
) IPPORT_BOOTPS
;
437 "udp/bootps: unknown service -- assuming port %d",
442 * Bind socket to BOOTPS port.
444 bind_addr
.sin_family
= AF_INET
;
445 bind_addr
.sin_addr
.s_addr
= INADDR_ANY
;
446 bind_addr
.sin_port
= htons(bootps_port
);
447 if (bind(s
, (struct sockaddr
*) &bind_addr
,
448 sizeof(bind_addr
)) < 0)
450 report(LOG_ERR
, "bind: %s", get_network_errmsg());
453 } /* if standalone (2nd)*/
456 * Get destination port number so we can reply to client
458 servp
= getservbyname("bootpc", "udp");
460 bootpc_port
= ntohs(servp
->s_port
);
463 "udp/bootpc: unknown service -- assuming port %d",
465 bootpc_port
= (u_short
) IPPORT_BOOTPC
;
469 * Set up signals to read or dump the table.
471 if ((long) signal(SIGHUP
, catcher
) < 0) {
472 report(LOG_ERR
, "signal: %s", get_errmsg());
475 if ((long) signal(SIGUSR1
, catcher
) < 0) {
476 report(LOG_ERR
, "signal: %s", get_errmsg());
481 * Process incoming requests.
484 set
[0].events
= POLLIN
;
486 nfound
= poll(set
, 1, timeout
);
488 if (errno
!= EINTR
) {
489 report(LOG_ERR
, "poll: %s", get_errmsg());
492 * Call readtab() or dumptab() here to avoid the
493 * dangers of doing I/O from a signal handler.
497 readtab(1); /* force read */
501 dumptab(bootpd_dump
);
507 report(LOG_INFO
, "exiting after %d minute%s of inactivity",
508 actualtimeout
/ 60000,
509 actualtimeout
== 60000 ? "" : "s");
512 ra_len
= sizeof(recv_addr
);
513 n
= recvfrom(s
, pktbuf
, MAX_MSG_SIZE
, 0,
514 (struct sockaddr
*) &recv_addr
, &ra_len
);
519 report(LOG_INFO
, "recvd pkt from IP addr %s",
520 inet_ntoa(recv_addr
.sin_addr
));
522 if (n
< (int)sizeof(struct bootp
)) {
524 report(LOG_INFO
, "received short packet");
530 readtab(0); /* maybe re-read bootptab */
547 * Print "usage" message and exit
554 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
555 fprintf(stderr
, "\t -c n\tset current directory\n");
556 fprintf(stderr
, "\t -d n\tset debug level\n");
557 fprintf(stderr
, "\t -i\tforce inetd mode (run as child of inetd)\n");
558 fprintf(stderr
, "\t -s\tforce standalone mode (run without inetd)\n");
559 fprintf(stderr
, "\t -t n\tset inetd exit timeout to n minutes\n");
563 /* Signal catchers */
572 /* For older "System V" derivatives with no sigset(). */
573 /* XXX - Should just do it the POSIX way (sigaction). */
574 signal(sig
, catcher
);
581 * Process BOOTREQUEST packet.
583 * Note: This version of the bootpd.c server never forwards
584 * a request to another server. That is the job of a gateway
585 * program such as the "bootpgw" program included here.
587 * (Also this version does not interpret the hostname field of
588 * the request packet; it COULD do a name->address lookup and
589 * forward the request there.)
594 struct bootp
*bp
= (struct bootp
*) pktbuf
;
595 struct host
*hp
= NULL
;
596 struct host dummyhost
;
598 unsigned hlen
, hashcode
;
600 char lrealpath
[1024];
602 char *homedir
, *bootfile
;
605 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
608 * If the servername field is set, compare it against us.
609 * If we're not being addressed, ignore this request.
610 * If the server name field is null, throw in our name.
612 if (strlen(bp
->bp_sname
)) {
613 if (strcmp(bp
->bp_sname
, hostname
)) {
616 ignoring request for server %s from client at %s address %s",
617 bp
->bp_sname
, netname(bp
->bp_htype
),
618 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
619 /* XXX - Is it correct to ignore such a request? -gwr */
623 strlcpy(bp
->bp_sname
, hostname
, sizeof(bp
->bp_sname
));
626 /* If it uses an unknown network type, ignore the request. */
627 if (bp
->bp_htype
>= hwinfocnt
) {
630 "Request with unknown network type %u",
635 /* Convert the request into a reply. */
636 bp
->bp_op
= BOOTREPLY
;
637 if (bp
->bp_ciaddr
.s_addr
== 0) {
639 * client doesnt know his IP address,
640 * search by hardware address.
643 report(LOG_INFO
, "request from %s address %s",
644 netname(bp
->bp_htype
),
645 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
647 hlen
= haddrlength(bp
->bp_htype
);
648 if (hlen
!= bp
->bp_hlen
) {
649 report(LOG_NOTICE
, "bad addr len from %s address %s",
650 netname(bp
->bp_htype
),
651 haddrtoa(bp
->bp_chaddr
, hlen
));
653 dummyhost
.htype
= bp
->bp_htype
;
654 bcopy(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
655 hashcode
= hash_HashFunction(bp
->bp_chaddr
, hlen
);
656 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
, hwlookcmp
,
659 bp
->bp_htype
== HTYPE_IEEE802
)
661 /* Try again with address in "canonical" form. */
662 haddr_conv802(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
665 HW addr type is IEEE 802. convert to %s and check again\n",
666 haddrtoa(dummyhost
.haddr
, bp
->bp_hlen
));
668 hashcode
= hash_HashFunction(dummyhost
.haddr
, hlen
);
669 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
,
670 hwlookcmp
, &dummyhost
);
674 * XXX - Add dynamic IP address assignment?
677 report(LOG_INFO
, "unknown client %s address %s",
678 netname(bp
->bp_htype
),
679 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
680 return; /* not found */
682 (bp
->bp_yiaddr
).s_addr
= hp
->iaddr
.s_addr
;
687 * search by IP address.
690 report(LOG_INFO
, "request from IP addr %s",
691 inet_ntoa(bp
->bp_ciaddr
));
693 dummyhost
.iaddr
.s_addr
= bp
->bp_ciaddr
.s_addr
;
694 hashcode
= hash_HashFunction((u_char
*) &(bp
->bp_ciaddr
.s_addr
), 4);
695 hp
= (struct host
*) hash_Lookup(iphashtable
, hashcode
, iplookcmp
,
699 report(LOG_NOTICE
, "IP address not found: %s",
700 inet_ntoa(bp
->bp_ciaddr
));
707 report(LOG_INFO
, "found %s (%s)", inet_ntoa(hp
->iaddr
),
708 hp
->hostname
->string
);
712 * If there is a response delay threshold, ignore requests
713 * with a timestamp lower than the threshold.
715 if (hp
->flags
.min_wait
) {
716 u_int32 t
= (u_int32
) ntohs(bp
->bp_secs
);
717 if (t
< hp
->min_wait
) {
720 "ignoring request due to timestamp (%d < %d)",
726 #ifdef YORK_EX_OPTION
728 * The need for the "ex" tag arose out of the need to empty
729 * shared networked drives on diskless PCs. This solution is
730 * not very clean but it does work fairly well.
731 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
733 * XXX - This could compromise security if a non-trusted user
734 * managed to write an entry in the bootptab with :ex=trojan:
735 * so I would leave this turned off unless you need it. -gwr
737 /* Run a program, passing the client name as a parameter. */
738 if (hp
->flags
.exec_file
) {
740 /* XXX - Check string lengths? -gwr */
741 strlcpy(tst
, hp
->exec_file
->string
, sizeof(tst
));
742 strlcat(tst
, " ", sizeof(tst
));
743 strlcat(tst
, hp
->hostname
->string
, sizeof(tst
));
744 strlcat(tst
, " &", sizeof(tst
));
746 report(LOG_INFO
, "executing %s", tst
);
747 system(tst
); /* Hope this finishes soon... */
749 #endif /* YORK_EX_OPTION */
752 * If a specific TFTP server address was specified in the bootptab file,
753 * fill it in, otherwise zero it.
754 * XXX - Rather than zero it, should it be the bootpd address? -gwr
756 (bp
->bp_siaddr
).s_addr
= (hp
->flags
.bootserver
) ?
757 hp
->bootserver
.s_addr
: 0L;
759 #ifdef STANFORD_PROM_COMPAT
761 * Stanford bootp PROMs (for a Sun?) have no way to leave
762 * the boot file name field blank (because the boot file
763 * name is automatically generated from some index).
764 * As a work-around, this little hack allows those PROMs to
765 * specify "sunboot14" with the same effect as a NULL name.
766 * (The user specifies boot device 14 or some such magic.)
768 if (strcmp(bp
->bp_file
, "sunboot14") == 0)
769 bp
->bp_file
[0] = '\0'; /* treat it as unspecified */
773 * Fill in the client's proper bootfile.
775 * If the client specifies an absolute path, try that file with a
776 * ".host" suffix and then without. If the file cannot be found, no
777 * reply is made at all.
779 * If the client specifies a null or relative file, use the following
780 * table to determine the appropriate action:
782 * Homedir Bootfile Client's file
783 * specified? specified? specification Action
784 * -------------------------------------------------------------------
785 * No No Null Send null filename
786 * No No Relative Discard request
787 * No Yes Null Send if absolute else null
788 * No Yes Relative Discard request *XXX
789 * Yes No Null Send null filename
790 * Yes No Relative Lookup with ".host"
791 * Yes Yes Null Send home/boot or bootfile
792 * Yes Yes Relative Lookup with ".host" *XXX
797 * XXX - I don't like the policy of ignoring a client when the
798 * boot file is not accessible. The TFTP server might not be
799 * running on the same machine as the BOOTP server, in which
800 * case checking accessibility of the boot file is pointless.
802 * Therefore, file accessibility is now demanded ONLY if you
803 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
807 * The "real" path is as seen by the BOOTP daemon on this
808 * machine, while the client path is relative to the TFTP
809 * daemon chroot directory (i.e. /tftpboot).
811 if (hp
->flags
.tftpdir
) {
812 strlcpy(lrealpath
, hp
->tftpdir
->string
, sizeof(lrealpath
));
813 clntpath
= &lrealpath
[strlen(lrealpath
)];
816 clntpath
= lrealpath
;
820 * Determine client's requested homedir and bootfile.
824 if (bp
->bp_file
[0]) {
827 homedir
= bp
->bp_file
;
829 /* make sure that the file is nul terminated */
830 for (t
= homedir
; t
- homedir
< BP_FILE_LEN
; t
++)
833 if (t
- homedir
< BP_FILE_LEN
) {
834 report(LOG_INFO
, "requested path length > BP_FILE_LEN file = \"%s\", nul terminating", homedir
);
835 homedir
[BP_FILE_LEN
- 1] = '\0';
838 bootfile
= strrchr(homedir
, '/');
840 if (homedir
== bootfile
)
844 /* no "/" in the string */
849 report(LOG_INFO
, "requested path=\"%s\" file=\"%s\"",
850 (homedir
) ? homedir
: "",
851 (bootfile
) ? bootfile
: "");
856 * Specifications in bootptab override client requested values.
858 if (hp
->flags
.homedir
)
859 homedir
= hp
->homedir
->string
;
860 if (hp
->flags
.bootfile
)
861 bootfile
= hp
->bootfile
->string
;
864 * Construct bootfile path.
867 if (homedir
[0] != '/')
868 strlcat(lrealpath
, "/", sizeof(lrealpath
));
869 strlcat(lrealpath
, homedir
, sizeof(lrealpath
));
873 if (bootfile
[0] != '/') {
874 strlcat(lrealpath
, "/", sizeof(lrealpath
));
875 lrealpath
[sizeof(lrealpath
) - 1] = '\0';
877 strlcat(lrealpath
, bootfile
, sizeof(lrealpath
));
878 lrealpath
[sizeof(lrealpath
) - 1] = '\0';
883 * First try to find the file with a ".host" suffix
885 n
= strlen(clntpath
);
886 strlcat(clntpath
, ".", sizeof(clntpath
));
887 strlcat(clntpath
, hp
->hostname
->string
, sizeof(clntpath
));
888 if (chk_access(lrealpath
, &bootsize
) < 0) {
889 clntpath
[n
] = 0; /* Try it without the suffix */
890 if (chk_access(lrealpath
, &bootsize
) < 0) {
891 /* neither "file.host" nor "file" was found */
892 #ifdef CHECK_FILE_ACCESS
894 if (bp
->bp_file
[0]) {
896 * Client wanted specific file
897 * and we didn't have it.
900 "requested file not found: \"%s\"", clntpath
);
904 * Client didn't ask for a specific file and we couldn't
905 * access the default file, so just zero-out the bootfile
906 * field in the packet and continue processing the reply.
908 bzero(bp
->bp_file
, sizeof(bp
->bp_file
));
911 #else /* CHECK_FILE_ACCESS */
913 /* Complain only if boot file size was needed. */
914 if (hp
->flags
.bootsize_auto
) {
915 report(LOG_ERR
, "can not determine size of file \"%s\"",
919 #endif /* CHECK_FILE_ACCESS */
922 strlcpy(bp
->bp_file
, clntpath
, sizeof(bp
->bp_file
));
924 report(LOG_INFO
, "bootfile=\"%s\"", clntpath
);
926 #ifdef CHECK_FILE_ACCESS
928 #endif /* CHECK_FILE_ACCESS */
932 * Handle vendor options based on magic number.
936 report(LOG_INFO
, "vendor magic field is %d.%d.%d.%d",
937 (int) ((bp
->bp_vend
)[0]),
938 (int) ((bp
->bp_vend
)[1]),
939 (int) ((bp
->bp_vend
)[2]),
940 (int) ((bp
->bp_vend
)[3]));
943 * If this host isn't set for automatic vendor info then copy the
944 * specific cookie into the bootp packet, thus forcing a certain
945 * reply format. Only force reply format if user specified it.
947 if (hp
->flags
.vm_cookie
) {
948 /* Slam in the user specified magic number. */
949 bcopy(hp
->vm_cookie
, bp
->bp_vend
, 4);
952 * Figure out the format for the vendor-specific info.
953 * Note that bp->bp_vend may have been set above.
955 if (!bcmp(bp
->bp_vend
, vm_rfc1048
, 4)) {
956 /* RFC1048 conformant bootp client */
957 dovend_rfc1048(bp
, hp
, bootsize
);
959 report(LOG_INFO
, "sending reply (with RFC1048 options)");
963 else if (!bcmp(bp
->bp_vend
, vm_cmu
, 4)) {
966 report(LOG_INFO
, "sending reply (with CMU options)");
972 report(LOG_INFO
, "sending reply (with no options)");
976 dest
= (hp
->flags
.reply_addr
) ?
977 hp
->reply_addr
.s_addr
: 0L;
985 * Process BOOTREPLY packet.
991 report(LOG_INFO
, "processing boot reply");
993 /* forwarded, no destination override */
999 * Send a reply packet to the client. 'forward' flag is set if we are
1000 * not the originator of this reply packet.
1003 sendreply(int forward
, int32 dst_override
)
1005 struct bootp
*bp
= (struct bootp
*) pktbuf
;
1007 u_short port
= bootpc_port
;
1012 * XXX - Should honor bp_flags "broadcast" bit here.
1013 * Temporary workaround: use the :ra=ADDR: option to
1014 * set the reply address to the broadcast address.
1018 * If the destination address was specified explicitly
1019 * (i.e. the broadcast address for HP compatibility)
1020 * then send the response to that address. Otherwise,
1021 * act in accordance with RFC951:
1022 * If the client IP address is specified, use that
1023 * else if gateway IP address is specified, use that
1024 * else make a temporary arp cache entry for the client's
1025 * NEW IP/hardware address and use that.
1028 dst
.s_addr
= dst_override
;
1030 report(LOG_INFO
, "reply address override: %s",
1033 } else if (bp
->bp_ciaddr
.s_addr
) {
1034 dst
= bp
->bp_ciaddr
;
1035 } else if (bp
->bp_giaddr
.s_addr
&& forward
== 0) {
1036 dst
= bp
->bp_giaddr
;
1039 report(LOG_INFO
, "sending reply to gateway %s",
1043 dst
= bp
->bp_yiaddr
;
1046 if (len
> MAXHADDRLEN
)
1050 report(LOG_INFO
, "setarp %s - %s",
1051 inet_ntoa(dst
), haddrtoa(ha
, len
));
1052 setarp(s
, &dst
, ha
, len
);
1055 if ((forward
== 0) &&
1056 (bp
->bp_siaddr
.s_addr
== 0))
1059 struct in_addr siaddr
;
1061 * If we are originating this reply, we
1062 * need to find our own interface address to
1063 * put in the bp_siaddr field of the reply.
1064 * If this server is multi-homed, pick the
1065 * 'best' interface (the one on the same net
1066 * as the client). Of course, the client may
1067 * be on the other side of a BOOTP gateway...
1069 ifr
= getif(s
, &dst
);
1071 struct sockaddr_in
*sip
;
1072 sip
= (struct sockaddr_in
*) &(ifr
->ifr_addr
);
1073 siaddr
= sip
->sin_addr
;
1075 /* Just use my "official" IP address. */
1076 siaddr
= my_ip_addr
;
1079 /* XXX - No need to set bp_giaddr here. */
1081 /* Finally, set the server address field. */
1082 bp
->bp_siaddr
= siaddr
;
1084 /* Set up socket address for send. */
1085 send_addr
.sin_family
= AF_INET
;
1086 send_addr
.sin_port
= htons(port
);
1087 send_addr
.sin_addr
= dst
;
1089 /* Send reply with same size packet as request used. */
1090 if (sendto(s
, pktbuf
, pktlen
, 0,
1091 (struct sockaddr
*) &send_addr
,
1092 sizeof(send_addr
)) < 0)
1094 report(LOG_ERR
, "sendto: %s", get_network_errmsg());
1099 /* nmatch() - now in getif.c */
1100 /* setarp() - now in hwaddr.c */
1104 * This call checks read access to a file. It returns 0 if the file given
1105 * by "path" exists and is publically readable. A value of -1 is returned if
1106 * access is not permitted or an error occurs. Successful calls also
1107 * return the file size in bytes using the long pointer "filesize".
1109 * The read permission bit for "other" users is checked. This bit must be
1110 * set for tftpd(8) to allow clients to read the file.
1114 chk_access(char *path
, int32
*filesize
)
1118 if ((stat(path
, &st
) == 0) && (st
.st_mode
& (S_IREAD
>> 6))) {
1119 *filesize
= (int32
) st
.st_size
;
1128 * Now in dumptab.c :
1131 * list_ipaddresses()
1137 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1138 * bootp packet pointed to by "bp".
1142 dovend_cmu(struct bootp
*bp
, struct host
*hp
)
1144 struct cmu_vend
*vendp
;
1145 struct in_addr_list
*taddr
;
1148 * Initialize the entire vendor field to zeroes.
1150 bzero(bp
->bp_vend
, sizeof(bp
->bp_vend
));
1153 * Fill in vendor information. Subnet mask, default gateway,
1154 * domain name server, ien name server, time server
1156 vendp
= (struct cmu_vend
*) bp
->bp_vend
;
1157 strlcpy(vendp
->v_magic
, (char *)vm_cmu
, sizeof(vendp
->v_magic
));
1158 if (hp
->flags
.subnet_mask
) {
1159 (vendp
->v_smask
).s_addr
= hp
->subnet_mask
.s_addr
;
1160 (vendp
->v_flags
) |= VF_SMASK
;
1161 if (hp
->flags
.gateway
) {
1162 (vendp
->v_dgate
).s_addr
= hp
->gateway
->addr
->s_addr
;
1165 if (hp
->flags
.domain_server
) {
1166 taddr
= hp
->domain_server
;
1167 if (taddr
->addrcount
> 0) {
1168 (vendp
->v_dns1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1169 if (taddr
->addrcount
> 1) {
1170 (vendp
->v_dns2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1174 if (hp
->flags
.name_server
) {
1175 taddr
= hp
->name_server
;
1176 if (taddr
->addrcount
> 0) {
1177 (vendp
->v_ins1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1178 if (taddr
->addrcount
> 1) {
1179 (vendp
->v_ins2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1183 if (hp
->flags
.time_server
) {
1184 taddr
= hp
->time_server
;
1185 if (taddr
->addrcount
> 0) {
1186 (vendp
->v_ts1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1187 if (taddr
->addrcount
> 1) {
1188 (vendp
->v_ts2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1192 /* Log message now done by caller. */
1195 #endif /* VEND_CMU */
1200 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1201 * bootp packet pointed to by "bp".
1203 #define NEED(LEN, MSG) do \
1204 if (bytesleft < (LEN)) { \
1205 report(LOG_NOTICE, noroom, \
1206 hp->hostname->string, MSG); \
1210 dovend_rfc1048(struct bootp
*bp
, struct host
*hp
, int32 bootsize
)
1215 static const char noroom
[] = "%s: No room for \"%s\" option";
1219 if (hp
->flags
.msg_size
) {
1220 pktlen
= hp
->msg_size
;
1223 * If the request was longer than the official length, build
1224 * a response of that same length where the additional length
1225 * is assumed to be part of the bp_vend (options) area.
1227 if (pktlen
> (int)sizeof(*bp
)) {
1229 report(LOG_INFO
, "request message length=%d", pktlen
);
1232 * Check whether the request contains the option:
1233 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1234 * and if so, override the response length with its value.
1235 * This request must lie within the first BP_VEND_LEN
1236 * bytes of the option space.
1244 ep
= p
+ BP_VEND_LEN
- 4;
1247 /* Check for tags with no data first. */
1252 /* Now scan the length byte. */
1257 bcopy(p
, (char*)&msgsz
, 2);
1258 msgsz
= ntohs(msgsz
);
1261 case TAG_SUBNET_MASK
:
1262 /* XXX - Should preserve this if given... */
1268 if (msgsz
> (int)sizeof(*bp
)) {
1270 report(LOG_INFO
, "request has DHCP msglen=%d", msgsz
);
1276 if (pktlen
< (int)sizeof(*bp
)) {
1277 report(LOG_ERR
, "invalid response length=%d", pktlen
);
1278 pktlen
= sizeof(*bp
);
1280 bytesleft
= ((byte
*)bp
+ pktlen
) - vp
;
1281 if (pktlen
> (int)sizeof(*bp
)) {
1283 report(LOG_INFO
, "extended reply, length=%d, options=%d",
1287 /* Copy in the magic cookie */
1288 bcopy(vm_rfc1048
, vp
, 4);
1292 if (hp
->flags
.subnet_mask
) {
1293 /* always enough room here. */
1294 *vp
++ = TAG_SUBNET_MASK
;/* -1 byte */
1295 *vp
++ = 4; /* -1 byte */
1296 insert_u_long(hp
->subnet_mask
.s_addr
, &vp
); /* -4 bytes */
1297 bytesleft
-= 6; /* Fix real count */
1298 if (hp
->flags
.gateway
) {
1299 (void) insert_ip(TAG_GATEWAY
,
1304 if (hp
->flags
.bootsize
) {
1305 /* always enough room here */
1306 bootsize
= (hp
->flags
.bootsize_auto
) ?
1307 ((bootsize
+ 511) / 512) : ((int32_t)hp
->bootsize
); /* Round up */
1308 *vp
++ = TAG_BOOT_SIZE
;
1310 *vp
++ = (byte
) ((bootsize
>> 8) & 0xFF);
1311 *vp
++ = (byte
) (bootsize
& 0xFF);
1312 bytesleft
-= 4; /* Tag, length, and 16 bit blocksize */
1315 * This one is special: Remaining options go in the ext file.
1316 * Only the subnet_mask, bootsize, and gateway should precede.
1318 if (hp
->flags
.exten_file
) {
1320 * Check for room for exten_file. Add 3 to account for
1321 * TAG_EXTEN_FILE, length, and TAG_END.
1323 len
= strlen(hp
->exten_file
->string
);
1324 NEED((len
+ 3), "ef");
1325 *vp
++ = TAG_EXTEN_FILE
;
1326 *vp
++ = (byte
) (len
& 0xFF);
1327 bcopy(hp
->exten_file
->string
, vp
, len
);
1330 bytesleft
-= len
+ 3;
1331 return; /* no more options here. */
1334 * The remaining options are inserted by the following
1335 * function (which is shared with bootpef.c).
1336 * Keep back one byte for the TAG_END.
1338 len
= dovend_rfc1497(hp
, vp
, bytesleft
- 1);
1342 /* There should be at least one byte left. */
1347 /* Log message done by caller. */
1348 if (bytesleft
> 0) {
1350 * Zero out any remaining part of the vendor area.
1352 bzero(vp
, bytesleft
);
1354 } /* dovend_rfc1048 */
1359 * Now in readfile.c:
1364 /* haddrtoa() - now in hwaddr.c */
1372 /* get_errmsg() - now in report.c */
1378 * c-argdecl-indent: 4
1379 * c-continued-statement-offset: 4
1380 * c-continued-brace-offset: -4
1381 * c-label-offset: -4