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
108 extern void dumptab(char *);
110 PRIVATE
void catcher(int);
111 PRIVATE
int chk_access(char *, int32
*);
113 PRIVATE
void dovend_cmu(struct bootp
*, struct host
*);
115 PRIVATE
void dovend_rfc1048(struct bootp
*, struct host
*, int32
);
116 PRIVATE
void handle_reply(void);
117 PRIVATE
void handle_request(void);
118 PRIVATE
void sendreply(int forward
, int32 dest_override
);
119 PRIVATE
void usage(void);
122 * IP port numbers for client and server obtained from /etc/services
125 u_short bootps_port
, bootpc_port
;
129 * Internet socket and interface config structures
132 struct sockaddr_in bind_addr
; /* Listening */
133 struct sockaddr_in recv_addr
; /* Packet source */
134 struct sockaddr_in send_addr
; /* destination */
140 int debug
= 0; /* Debugging flag (level) */
141 struct timeval actualtimeout
=
142 { /* fifteen minutes */
143 15 * 60L, /* tv_sec */
151 int s
; /* Socket file descriptor */
152 char *pktbuf
; /* Receive packet buffer */
156 struct in_addr my_ip_addr
;
158 static const char *hostname
;
159 static char default_hostname
[MAXHOSTNAMELEN
];
161 /* Flags set by signal catcher. */
162 PRIVATE
int do_readtab
= 0;
163 PRIVATE
int do_dumptab
= 0;
166 * Globals below are associated with the bootp database file (bootptab).
169 char *bootptab
= CONFIG_FILE
;
170 char *bootpd_dump
= DUMPTAB_FILE
;
175 * Initialization such as command-line processing is done and then the
176 * main server loop is started.
180 main(int argc
, char **argv
)
182 struct timeval
*timeout
;
184 struct servent
*servp
;
187 int n
, ba_len
, ra_len
;
190 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
194 progname
= strrchr(argv
[0], '/');
195 if (progname
) progname
++;
196 else progname
= argv
[0];
199 * Initialize logging.
201 report_init(0); /* uses progname */
206 report(LOG_INFO
, "version %s.%d", VERSION
, PATCHLEVEL
);
208 /* Debugging for compilers with struct padding. */
209 assert(sizeof(struct bootp
) == BP_MINPKTSZ
);
211 /* Get space for receiving packets and composing replies. */
212 pktbuf
= malloc(MAX_MSG_SIZE
);
214 report(LOG_ERR
, "malloc failed");
217 bp
= (struct bootp
*) pktbuf
;
220 * Check to see if a socket was passed to us from inetd.
222 * Use getsockname() to determine if descriptor 0 is indeed a socket
223 * (and thus we are probably a child of inetd) or if it is instead
224 * something else and we are running standalone.
227 ba_len
= sizeof(bind_addr
);
228 bzero((char *) &bind_addr
, ba_len
);
231 if (getsockname(s
, (struct sockaddr
*) &bind_addr
, &ba_len
) == 0) {
233 * Descriptor 0 is a socket. Assume we are a child of inetd.
235 if (bind_addr
.sin_family
== AF_INET
) {
237 bootps_port
= ntohs(bind_addr
.sin_port
);
239 /* Some other type of socket? */
240 report(LOG_ERR
, "getsockname: not an INET socket");
245 * Set defaults that might be changed by option switches.
248 timeout
= &actualtimeout
;
250 if (gethostname(default_hostname
, sizeof(default_hostname
) - 1) < 0) {
251 report(LOG_ERR
, "bootpd: can't get hostname\n");
254 default_hostname
[sizeof(default_hostname
) - 1] = '\0';
255 hostname
= default_hostname
;
260 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
261 if (argv
[0][0] != '-')
263 switch (argv
[0][1]) {
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
, NULL
);
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 "udp/bootps: unknown service -- assuming 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 "udp/bootpc: unknown service -- assuming 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.
512 nfound
= select(s
+ 1, (fd_set
*)&readfds
, NULL
, NULL
,
513 (timeout
) ? &tv
: NULL
);
515 if (errno
!= EINTR
) {
516 report(LOG_ERR
, "select: %s", get_errmsg());
519 * Call readtab() or dumptab() here to avoid the
520 * dangers of doing I/O from a signal handler.
524 readtab(1); /* force read */
528 dumptab(bootpd_dump
);
532 if (!(readfds
& (1 << s
))) {
534 report(LOG_INFO
, "exiting after %ld minutes of inactivity",
535 actualtimeout
.tv_sec
/ 60);
538 ra_len
= sizeof(recv_addr
);
539 n
= recvfrom(s
, pktbuf
, MAX_MSG_SIZE
, 0,
540 (struct sockaddr
*) &recv_addr
, &ra_len
);
545 report(LOG_INFO
, "recvd pkt from IP addr %s",
546 inet_ntoa(recv_addr
.sin_addr
));
548 if (n
< sizeof(struct bootp
)) {
550 report(LOG_NOTICE
, "received short packet");
556 readtab(0); /* maybe re-read bootptab */
574 * Print "usage" message and exit
581 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
582 fprintf(stderr
, "\t -c n\tset current directory\n");
583 fprintf(stderr
, "\t -d n\tset debug level\n");
584 fprintf(stderr
, "\t -i\tforce inetd mode (run as child of inetd)\n");
585 fprintf(stderr
, "\t -s\tforce standalone mode (run without inetd)\n");
586 fprintf(stderr
, "\t -t n\tset inetd exit timeout to n minutes\n");
590 /* Signal catchers */
598 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
599 /* For older "System V" derivatives with no sigaction(). */
600 signal(sig
, catcher
);
607 * Process BOOTREQUEST packet.
609 * Note: This version of the bootpd.c server never forwards
610 * a request to another server. That is the job of a gateway
611 * program such as the "bootpgw" program included here.
613 * (Also this version does not interpret the hostname field of
614 * the request packet; it COULD do a name->address lookup and
615 * forward the request there.)
620 struct bootp
*bp
= (struct bootp
*) pktbuf
;
621 struct host
*hp
= NULL
;
622 struct host dummyhost
;
624 unsigned hlen
, hashcode
;
628 char *homedir
, *bootfile
;
631 bp
->bp_file
[sizeof(bp
->bp_file
)-1] = '\0';
633 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
636 * If the servername field is set, compare it against us.
637 * If we're not being addressed, ignore this request.
638 * If the server name field is null, throw in our name.
640 if (strlen(bp
->bp_sname
)) {
641 if (strcmp(bp
->bp_sname
, hostname
)) {
644 ignoring request for server %s from client at %s address %s",
645 bp
->bp_sname
, netname(bp
->bp_htype
),
646 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
647 /* XXX - Is it correct to ignore such a request? -gwr */
651 strcpy(bp
->bp_sname
, hostname
);
654 /* Convert the request into a reply. */
655 bp
->bp_op
= BOOTREPLY
;
656 if (bp
->bp_ciaddr
.s_addr
== 0) {
658 * client doesnt know his IP address,
659 * search by hardware address.
662 report(LOG_INFO
, "request from %s address %s",
663 netname(bp
->bp_htype
),
664 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
666 hlen
= haddrlength(bp
->bp_htype
);
667 if (hlen
!= bp
->bp_hlen
) {
668 report(LOG_NOTICE
, "bad addr len from %s address %s",
669 netname(bp
->bp_htype
),
670 haddrtoa(bp
->bp_chaddr
, hlen
));
672 dummyhost
.htype
= bp
->bp_htype
;
673 bcopy(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
674 hashcode
= hash_HashFunction(bp
->bp_chaddr
, hlen
);
675 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
, hwlookcmp
,
678 bp
->bp_htype
== HTYPE_IEEE802
)
680 /* Try again with address in "canonical" form. */
681 haddr_conv802(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
684 HW addr type is IEEE 802. convert to %s and check again\n",
685 haddrtoa(dummyhost
.haddr
, bp
->bp_hlen
));
687 hashcode
= hash_HashFunction(dummyhost
.haddr
, hlen
);
688 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
,
689 hwlookcmp
, &dummyhost
);
693 * XXX - Add dynamic IP address assignment?
696 report(LOG_NOTICE
, "unknown client %s address %s",
697 netname(bp
->bp_htype
),
698 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
699 return; /* not found */
701 (bp
->bp_yiaddr
).s_addr
= hp
->iaddr
.s_addr
;
706 * search by IP address.
709 report(LOG_INFO
, "request from IP addr %s",
710 inet_ntoa(bp
->bp_ciaddr
));
712 dummyhost
.iaddr
.s_addr
= bp
->bp_ciaddr
.s_addr
;
713 hashcode
= hash_HashFunction((u_char
*) &(bp
->bp_ciaddr
.s_addr
), 4);
714 hp
= (struct host
*) hash_Lookup(iphashtable
, hashcode
, iplookcmp
,
718 report(LOG_NOTICE
, "IP address not found: %s",
719 inet_ntoa(bp
->bp_ciaddr
));
726 report(LOG_INFO
, "found %s (%s)", inet_ntoa(hp
->iaddr
),
727 hp
->hostname
->string
);
731 * If there is a response delay threshold, ignore requests
732 * with a timestamp lower than the threshold.
734 if (hp
->flags
.min_wait
) {
735 u_int32 t
= (u_int32
) ntohs(bp
->bp_secs
);
736 if (t
< hp
->min_wait
) {
739 "ignoring request due to timestamp (%d < %d)",
745 #ifdef YORK_EX_OPTION
747 * The need for the "ex" tag arose out of the need to empty
748 * shared networked drives on diskless PCs. This solution is
749 * not very clean but it does work fairly well.
750 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
752 * XXX - This could compromise security if a non-trusted user
753 * managed to write an entry in the bootptab with :ex=trojan:
754 * so I would leave this turned off unless you need it. -gwr
756 /* Run a program, passing the client name as a parameter. */
757 if (hp
->flags
.exec_file
) {
759 /* XXX - Check string lengths? -gwr */
760 strcpy (tst
, hp
->exec_file
->string
);
762 strcat (tst
, hp
->hostname
->string
);
765 report(LOG_INFO
, "executing %s", tst
);
766 system(tst
); /* Hope this finishes soon... */
768 #endif /* YORK_EX_OPTION */
771 * If a specific TFTP server address was specified in the bootptab file,
772 * fill it in, otherwise zero it.
773 * XXX - Rather than zero it, should it be the bootpd address? -gwr
775 (bp
->bp_siaddr
).s_addr
= (hp
->flags
.bootserver
) ?
776 hp
->bootserver
.s_addr
: 0L;
778 #ifdef STANFORD_PROM_COMPAT
780 * Stanford bootp PROMs (for a Sun?) have no way to leave
781 * the boot file name field blank (because the boot file
782 * name is automatically generated from some index).
783 * As a work-around, this little hack allows those PROMs to
784 * specify "sunboot14" with the same effect as a NULL name.
785 * (The user specifies boot device 14 or some such magic.)
787 if (strcmp(bp
->bp_file
, "sunboot14") == 0)
788 bp
->bp_file
[0] = '\0'; /* treat it as unspecified */
792 * Fill in the client's proper bootfile.
794 * If the client specifies an absolute path, try that file with a
795 * ".host" suffix and then without. If the file cannot be found, no
796 * reply is made at all.
798 * If the client specifies a null or relative file, use the following
799 * table to determine the appropriate action:
801 * Homedir Bootfile Client's file
802 * specified? specified? specification Action
803 * -------------------------------------------------------------------
804 * No No Null Send null filename
805 * No No Relative Discard request
806 * No Yes Null Send if absolute else null
807 * No Yes Relative Discard request *XXX
808 * Yes No Null Send null filename
809 * Yes No Relative Lookup with ".host"
810 * Yes Yes Null Send home/boot or bootfile
811 * Yes Yes Relative Lookup with ".host" *XXX
816 * XXX - I don't like the policy of ignoring a client when the
817 * boot file is not accessible. The TFTP server might not be
818 * running on the same machine as the BOOTP server, in which
819 * case checking accessibility of the boot file is pointless.
821 * Therefore, file accessibility is now demanded ONLY if you
822 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
826 * The "real" path is as seen by the BOOTP daemon on this
827 * machine, while the client path is relative to the TFTP
828 * daemon chroot directory (i.e. /tftpboot).
830 if (hp
->flags
.tftpdir
) {
831 snprintf(realpath
, sizeof(realpath
), "%s", hp
->tftpdir
->string
);
832 clntpath
= &realpath
[strlen(realpath
)];
839 * Determine client's requested homedir and bootfile.
843 if (bp
->bp_file
[0]) {
844 homedir
= bp
->bp_file
;
845 bootfile
= strrchr(homedir
, '/');
847 if (homedir
== bootfile
)
851 /* no "/" in the string */
856 report(LOG_INFO
, "requested path=\"%s\" file=\"%s\"",
857 (homedir
) ? homedir
: "",
858 (bootfile
) ? bootfile
: "");
863 * Specifications in bootptab override client requested values.
865 if (hp
->flags
.homedir
)
866 homedir
= hp
->homedir
->string
;
867 if (hp
->flags
.bootfile
)
868 bootfile
= hp
->bootfile
->string
;
871 * Construct bootfile path.
874 if (homedir
[0] != '/')
875 strcat(clntpath
, "/");
876 strcat(clntpath
, homedir
);
880 if (bootfile
[0] != '/')
881 strcat(clntpath
, "/");
882 strcat(clntpath
, bootfile
);
887 * First try to find the file with a ".host" suffix
889 n
= strlen(clntpath
);
890 strcat(clntpath
, ".");
891 strcat(clntpath
, hp
->hostname
->string
);
892 if (chk_access(realpath
, &bootsize
) < 0) {
893 clntpath
[n
] = 0; /* Try it without the suffix */
894 if (chk_access(realpath
, &bootsize
) < 0) {
895 /* neither "file.host" nor "file" was found */
896 #ifdef CHECK_FILE_ACCESS
898 if (bp
->bp_file
[0]) {
900 * Client wanted specific file
901 * and we didn't have it.
904 "requested file not found: \"%s\"", clntpath
);
908 * Client didn't ask for a specific file and we couldn't
909 * access the default file, so just zero-out the bootfile
910 * field in the packet and continue processing the reply.
912 bzero(bp
->bp_file
, sizeof(bp
->bp_file
));
915 #else /* CHECK_FILE_ACCESS */
917 /* Complain only if boot file size was needed. */
918 if (hp
->flags
.bootsize_auto
) {
919 report(LOG_ERR
, "can not determine size of file \"%s\"",
923 #endif /* CHECK_FILE_ACCESS */
926 strncpy(bp
->bp_file
, clntpath
, BP_FILE_LEN
);
928 report(LOG_INFO
, "bootfile=\"%s\"", clntpath
);
930 #ifdef CHECK_FILE_ACCESS
932 #endif /* CHECK_FILE_ACCESS */
936 * Handle vendor options based on magic number.
940 report(LOG_INFO
, "vendor magic field is %d.%d.%d.%d",
941 (int) ((bp
->bp_vend
)[0]),
942 (int) ((bp
->bp_vend
)[1]),
943 (int) ((bp
->bp_vend
)[2]),
944 (int) ((bp
->bp_vend
)[3]));
947 * If this host isn't set for automatic vendor info then copy the
948 * specific cookie into the bootp packet, thus forcing a certain
949 * reply format. Only force reply format if user specified it.
951 if (hp
->flags
.vm_cookie
) {
952 /* Slam in the user specified magic number. */
953 bcopy(hp
->vm_cookie
, bp
->bp_vend
, 4);
956 * Figure out the format for the vendor-specific info.
957 * Note that bp->bp_vend may have been set above.
959 if (!bcmp(bp
->bp_vend
, vm_rfc1048
, 4)) {
960 /* RFC1048 conformant bootp client */
961 dovend_rfc1048(bp
, hp
, bootsize
);
963 report(LOG_INFO
, "sending reply (with RFC1048 options)");
967 else if (!bcmp(bp
->bp_vend
, vm_cmu
, 4)) {
970 report(LOG_INFO
, "sending reply (with CMU options)");
976 report(LOG_INFO
, "sending reply (with no options)");
980 dest
= (hp
->flags
.reply_addr
) ?
981 hp
->reply_addr
.s_addr
: 0L;
989 * Process BOOTREPLY packet.
995 report(LOG_INFO
, "processing boot reply");
997 /* forwarded, no destination override */
1003 * Send a reply packet to the client. 'forward' flag is set if we are
1004 * not the originator of this reply packet.
1007 sendreply(int forward
, int32 dst_override
)
1009 struct bootp
*bp
= (struct bootp
*) pktbuf
;
1011 u_short port
= bootpc_port
;
1016 * XXX - Should honor bp_flags "broadcast" bit here.
1017 * Temporary workaround: use the :ra=ADDR: option to
1018 * set the reply address to the broadcast address.
1022 * If the destination address was specified explicitly
1023 * (i.e. the broadcast address for HP compatiblity)
1024 * then send the response to that address. Otherwise,
1025 * act in accordance with RFC951:
1026 * If the client IP address is specified, use that
1027 * else if gateway IP address is specified, use that
1028 * else make a temporary arp cache entry for the client's
1029 * NEW IP/hardware address and use that.
1032 dst
.s_addr
= dst_override
;
1034 report(LOG_INFO
, "reply address override: %s",
1037 } else if (bp
->bp_ciaddr
.s_addr
) {
1038 dst
= bp
->bp_ciaddr
;
1039 } else if (bp
->bp_giaddr
.s_addr
&& forward
== 0) {
1040 dst
= bp
->bp_giaddr
;
1043 report(LOG_INFO
, "sending reply to gateway %s",
1047 dst
= bp
->bp_yiaddr
;
1050 if (len
> MAXHADDRLEN
)
1052 haf
= (int) bp
->bp_htype
;
1054 haf
= HTYPE_ETHERNET
;
1057 report(LOG_INFO
, "setarp %s - %s",
1058 inet_ntoa(dst
), haddrtoa(ha
, len
));
1059 setarp(s
, &dst
, haf
, ha
, len
);
1062 if ((forward
== 0) &&
1063 (bp
->bp_siaddr
.s_addr
== 0))
1066 struct in_addr siaddr
;
1068 * If we are originating this reply, we
1069 * need to find our own interface address to
1070 * put in the bp_siaddr field of the reply.
1071 * If this server is multi-homed, pick the
1072 * 'best' interface (the one on the same net
1073 * as the client). Of course, the client may
1074 * be on the other side of a BOOTP gateway...
1076 ifr
= getif(s
, &dst
);
1078 struct sockaddr_in
*sip
;
1079 sip
= (struct sockaddr_in
*) &(ifr
->ifr_addr
);
1080 siaddr
= sip
->sin_addr
;
1082 /* Just use my "official" IP address. */
1083 siaddr
= my_ip_addr
;
1086 /* XXX - No need to set bp_giaddr here. */
1088 /* Finally, set the server address field. */
1089 bp
->bp_siaddr
= siaddr
;
1091 /* Set up socket address for send. */
1092 send_addr
.sin_family
= AF_INET
;
1093 send_addr
.sin_port
= htons(port
);
1094 send_addr
.sin_addr
= dst
;
1096 /* Send reply with same size packet as request used. */
1097 if (sendto(s
, pktbuf
, pktlen
, 0,
1098 (struct sockaddr
*) &send_addr
,
1099 sizeof(send_addr
)) < 0)
1101 report(LOG_ERR
, "sendto: %s", get_network_errmsg());
1106 /* nmatch() - now in getif.c */
1107 /* setarp() - now in hwaddr.c */
1111 * This call checks read access to a file. It returns 0 if the file given
1112 * by "path" exists and is publically readable. A value of -1 is returned if
1113 * access is not permitted or an error occurs. Successful calls also
1114 * return the file size in bytes using the long pointer "filesize".
1116 * The read permission bit for "other" users is checked. This bit must be
1117 * set for tftpd(8) to allow clients to read the file.
1121 chk_access(char *path
, int32
*filesize
)
1125 if ((stat(path
, &st
) == 0) && (st
.st_mode
& (S_IREAD
>> 6))) {
1126 *filesize
= (int32
) st
.st_size
;
1135 * Now in dumptab.c :
1138 * list_ipaddresses()
1144 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1145 * bootp packet pointed to by "bp".
1149 dovend_cmu(struct bootp
*bp
, struct host
*hp
)
1151 struct cmu_vend
*vendp
;
1152 struct in_addr_list
*taddr
;
1155 * Initialize the entire vendor field to zeroes.
1157 bzero(bp
->bp_vend
, sizeof(bp
->bp_vend
));
1160 * Fill in vendor information. Subnet mask, default gateway,
1161 * domain name server, ien name server, time server
1163 vendp
= (struct cmu_vend
*) bp
->bp_vend
;
1164 strcpy(vendp
->v_magic
, (char *)vm_cmu
);
1165 if (hp
->flags
.subnet_mask
) {
1166 (vendp
->v_smask
).s_addr
= hp
->subnet_mask
.s_addr
;
1167 (vendp
->v_flags
) |= VF_SMASK
;
1168 if (hp
->flags
.gateway
) {
1169 (vendp
->v_dgate
).s_addr
= hp
->gateway
->addr
->s_addr
;
1172 if (hp
->flags
.domain_server
) {
1173 taddr
= hp
->domain_server
;
1174 if (taddr
->addrcount
> 0) {
1175 (vendp
->v_dns1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1176 if (taddr
->addrcount
> 1) {
1177 (vendp
->v_dns2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1181 if (hp
->flags
.name_server
) {
1182 taddr
= hp
->name_server
;
1183 if (taddr
->addrcount
> 0) {
1184 (vendp
->v_ins1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1185 if (taddr
->addrcount
> 1) {
1186 (vendp
->v_ins2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1190 if (hp
->flags
.time_server
) {
1191 taddr
= hp
->time_server
;
1192 if (taddr
->addrcount
> 0) {
1193 (vendp
->v_ts1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1194 if (taddr
->addrcount
> 1) {
1195 (vendp
->v_ts2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1199 /* Log message now done by caller. */
1202 #endif /* VEND_CMU */
1207 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1208 * bootp packet pointed to by "bp".
1210 #define NEED(LEN, MSG) do \
1211 if (bytesleft < (LEN)) { \
1212 report(LOG_NOTICE, noroom, \
1213 hp->hostname->string, MSG); \
1217 dovend_rfc1048(struct bootp
*bp
, struct host
*hp
, int32 bootsize
)
1222 static const char noroom
[] = "%s: No room for \"%s\" option";
1226 if (hp
->flags
.msg_size
) {
1227 pktlen
= hp
->msg_size
;
1230 * If the request was longer than the official length, build
1231 * a response of that same length where the additional length
1232 * is assumed to be part of the bp_vend (options) area.
1234 if (pktlen
> sizeof(*bp
)) {
1236 report(LOG_INFO
, "request message length=%d", pktlen
);
1239 * Check whether the request contains the option:
1240 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1241 * and if so, override the response length with its value.
1242 * This request must lie within the first BP_VEND_LEN
1243 * bytes of the option space.
1251 ep
= p
+ BP_VEND_LEN
- 4;
1254 /* Check for tags with no data first. */
1259 /* Now scan the length byte. */
1264 bcopy(p
, (char*)&msgsz
, 2);
1265 msgsz
= ntohs(msgsz
);
1268 case TAG_SUBNET_MASK
:
1269 /* XXX - Should preserve this if given... */
1275 if (msgsz
> sizeof(*bp
) + BP_MSG_OVERHEAD
) {
1277 report(LOG_INFO
, "request has DHCP msglen=%d", msgsz
);
1278 pktlen
= msgsz
- BP_MSG_OVERHEAD
;
1283 if (pktlen
< sizeof(*bp
)) {
1284 report(LOG_ERR
, "invalid response length=%d", pktlen
);
1285 pktlen
= sizeof(*bp
);
1287 bytesleft
= ((byte
*)bp
+ pktlen
) - vp
;
1288 if (pktlen
> sizeof(*bp
)) {
1290 report(LOG_INFO
, "extended reply, length=%d, options=%d",
1294 /* Copy in the magic cookie */
1295 bcopy(vm_rfc1048
, vp
, 4);
1299 if (hp
->flags
.subnet_mask
) {
1300 /* always enough room here. */
1301 *vp
++ = TAG_SUBNET_MASK
;/* -1 byte */
1302 *vp
++ = 4; /* -1 byte */
1303 insert_u_long(hp
->subnet_mask
.s_addr
, &vp
); /* -4 bytes */
1304 bytesleft
-= 6; /* Fix real count */
1305 if (hp
->flags
.gateway
) {
1306 (void) insert_ip(TAG_GATEWAY
,
1311 if (hp
->flags
.bootsize
) {
1312 /* always enough room here */
1313 bootsize
= (hp
->flags
.bootsize_auto
) ?
1314 ((bootsize
+ 511) / 512) : (hp
->bootsize
); /* Round up */
1315 *vp
++ = TAG_BOOT_SIZE
;
1317 *vp
++ = (byte
) ((bootsize
>> 8) & 0xFF);
1318 *vp
++ = (byte
) (bootsize
& 0xFF);
1319 bytesleft
-= 4; /* Tag, length, and 16 bit blocksize */
1322 * This one is special: Remaining options go in the ext file.
1323 * Only the subnet_mask, bootsize, and gateway should precede.
1325 if (hp
->flags
.exten_file
) {
1327 * Check for room for exten_file. Add 3 to account for
1328 * TAG_EXTEN_FILE, length, and TAG_END.
1330 len
= strlen(hp
->exten_file
->string
);
1331 NEED((len
+ 3), "ef");
1332 *vp
++ = TAG_EXTEN_FILE
;
1333 *vp
++ = (byte
) (len
& 0xFF);
1334 bcopy(hp
->exten_file
->string
, vp
, len
);
1337 bytesleft
-= len
+ 3;
1338 return; /* no more options here. */
1341 * The remaining options are inserted by the following
1342 * function (which is shared with bootpef.c).
1343 * Keep back one byte for the TAG_END.
1345 len
= dovend_rfc1497(hp
, vp
, bytesleft
- 1);
1349 /* There should be at least one byte left. */
1354 /* Log message done by caller. */
1355 if (bytesleft
> 0) {
1357 * Zero out any remaining part of the vendor area.
1359 bzero(vp
, bytesleft
);
1361 } /* dovend_rfc1048 */
1366 * Now in readfile.c:
1371 /* haddrtoa() - now in hwaddr.c */
1379 /* get_errmsg() - now in report.c */