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 $
23 $DragonFly: src/libexec/bootpd/bootpd.c,v 1.2 2003/06/17 04:27:07 dillon Exp $
25 ************************************************************************/
28 * BOOTP (bootstrap protocol) server daemon.
30 * Answers BOOTP request packets from booting client machines.
31 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
32 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
33 * See RFC 1395 for option tags 14-17.
34 * See accompanying man page -- bootpd.8
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <sys/ioctl.h>
52 #include <sys/utsname.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h> /* inet_ntoa */
74 # include <fcntl.h> /* for O_RDONLY, etc */
79 /* Yes, memcpy is OK here (no overlapped copies). */
80 # define bcopy(a,b,c) memcpy(b,a,c)
81 # define bzero(p,l) memset(p,0,l)
82 # define bcmp(a,b,c) memcmp(a,b,c)
94 #include "patchlevel.h"
97 #define CONFIG_FILE "/etc/bootptab"
100 #define DUMPTAB_FILE "/tmp/bootpd.dump"
106 * Externals, forward declarations, and global variables
115 extern void dumptab
P((char *));
117 PRIVATE
void catcher
P((int));
118 PRIVATE
int chk_access
P((char *, int32
*));
120 PRIVATE
void dovend_cmu
P((struct bootp
*, struct host
*));
122 PRIVATE
void dovend_rfc1048
P((struct bootp
*, struct host
*, int32
));
123 PRIVATE
void handle_reply
P((void));
124 PRIVATE
void handle_request
P((void));
125 PRIVATE
void sendreply
P((int forward
, int32 dest_override
));
126 PRIVATE
void usage
P((void));
131 * IP port numbers for client and server obtained from /etc/services
134 u_short bootps_port
, bootpc_port
;
138 * Internet socket and interface config structures
141 struct sockaddr_in bind_addr
; /* Listening */
142 struct sockaddr_in recv_addr
; /* Packet source */
143 struct sockaddr_in send_addr
; /* destination */
149 int debug
= 0; /* Debugging flag (level) */
150 struct timeval actualtimeout
=
151 { /* fifteen minutes */
152 15 * 60L, /* tv_sec */
160 int s
; /* Socket file descriptor */
161 char *pktbuf
; /* Receive packet buffer */
165 struct in_addr my_ip_addr
;
167 static const char *hostname
;
168 static char default_hostname
[MAXHOSTNAMELEN
];
170 /* Flags set by signal catcher. */
171 PRIVATE
int do_readtab
= 0;
172 PRIVATE
int do_dumptab
= 0;
175 * Globals below are associated with the bootp database file (bootptab).
178 char *bootptab
= CONFIG_FILE
;
179 char *bootpd_dump
= DUMPTAB_FILE
;
184 * Initialization such as command-line processing is done and then the
185 * main server loop is started.
193 struct timeval
*timeout
;
195 struct servent
*servp
;
198 int n
, ba_len
, ra_len
;
201 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
205 progname
= strrchr(argv
[0], '/');
206 if (progname
) progname
++;
207 else progname
= argv
[0];
210 * Initialize logging.
212 report_init(0); /* uses progname */
217 report(LOG_INFO
, "version %s.%d", VERSION
, PATCHLEVEL
);
219 /* Debugging for compilers with struct padding. */
220 assert(sizeof(struct bootp
) == BP_MINPKTSZ
);
222 /* Get space for receiving packets and composing replies. */
223 pktbuf
= malloc(MAX_MSG_SIZE
);
225 report(LOG_ERR
, "malloc failed");
228 bp
= (struct bootp
*) pktbuf
;
231 * Check to see if a socket was passed to us from inetd.
233 * Use getsockname() to determine if descriptor 0 is indeed a socket
234 * (and thus we are probably a child of inetd) or if it is instead
235 * something else and we are running standalone.
238 ba_len
= sizeof(bind_addr
);
239 bzero((char *) &bind_addr
, ba_len
);
242 if (getsockname(s
, (struct sockaddr
*) &bind_addr
, &ba_len
) == 0) {
244 * Descriptor 0 is a socket. Assume we are a child of inetd.
246 if (bind_addr
.sin_family
== AF_INET
) {
248 bootps_port
= ntohs(bind_addr
.sin_port
);
250 /* Some other type of socket? */
251 report(LOG_ERR
, "getsockname: not an INET socket");
256 * Set defaults that might be changed by option switches.
259 timeout
= &actualtimeout
;
261 if (gethostname(default_hostname
, sizeof(default_hostname
) - 1) < 0) {
262 report(LOG_ERR
, "bootpd: can't get hostname\n");
265 default_hostname
[sizeof(default_hostname
) - 1] = '\0';
266 hostname
= default_hostname
;
271 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
272 if (argv
[0][0] != '-')
274 switch (argv
[0][1]) {
276 case 'c': /* chdir_path */
278 stmp
= &(argv
[0][2]);
284 if (!stmp
|| (stmp
[0] != '/')) {
286 "bootpd: invalid chdir specification\n");
292 case 'd': /* debug level */
294 stmp
= &(argv
[0][2]);
295 } else if (argv
[1] && argv
[1][0] == '-') {
297 * Backwards-compatible behavior:
298 * no parameter, so just increment the debug flag.
307 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
309 "%s: invalid debug level\n", progname
);
315 case 'h': /* override hostname */
317 stmp
= &(argv
[0][2]);
325 "bootpd: missing hostname\n");
331 case 'i': /* inetd mode */
335 case 's': /* standalone mode */
339 case 't': /* timeout */
341 stmp
= &(argv
[0][2]);
347 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
349 "%s: invalid timeout specification\n", progname
);
352 actualtimeout
.tv_sec
= (int32
) (60 * n
);
354 * If the actual timeout is zero, pass a NULL pointer
355 * to select so it blocks indefinitely, otherwise,
356 * point to the actual timeout value.
358 timeout
= (n
> 0) ? &actualtimeout
: NULL
;
362 report(LOG_ERR
, "%s: unknown switch: -%c\n",
363 progname
, argv
[0][1]);
371 * Override default file names if specified on the command line.
377 bootpd_dump
= argv
[1];
380 * Get my hostname and IP address.
383 hep
= gethostbyname(hostname
);
385 report(LOG_ERR
, "Can not get my IP address\n");
388 bcopy(hep
->h_addr
, (char *)&my_ip_addr
, sizeof(my_ip_addr
));
392 * Go into background and disassociate from controlling terminal.
400 n
= open(_PATH_TTY
, O_RDWR
);
402 ioctl(n
, TIOCNOTTY
, (char *) 0);
405 #endif /* TIOCNOTTY */
413 * Nuke any timeout value
417 } /* if standalone (1st) */
419 /* Set the cwd (i.e. to /tftpboot) */
421 if (chdir(chdir_path
) < 0)
422 report(LOG_ERR
, "%s: chdir failed", chdir_path
);
425 /* Get the timezone. */
428 /* Allocate hash tables. */
432 * Read the bootptab file.
434 readtab(1); /* force read */
441 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
442 report(LOG_ERR
, "socket: %s", get_network_errmsg());
447 * Get server's listening port number
449 servp
= getservbyname("bootps", "udp");
451 bootps_port
= ntohs((u_short
) servp
->s_port
);
453 bootps_port
= (u_short
) IPPORT_BOOTPS
;
455 "udp/bootps: unknown service -- assuming port %d",
460 * Bind socket to BOOTPS port.
462 bind_addr
.sin_family
= AF_INET
;
463 bind_addr
.sin_addr
.s_addr
= INADDR_ANY
;
464 bind_addr
.sin_port
= htons(bootps_port
);
465 if (bind(s
, (struct sockaddr
*) &bind_addr
,
466 sizeof(bind_addr
)) < 0)
468 report(LOG_ERR
, "bind: %s", get_network_errmsg());
471 } /* if standalone (2nd)*/
474 * Get destination port number so we can reply to client
476 servp
= getservbyname("bootpc", "udp");
478 bootpc_port
= ntohs(servp
->s_port
);
481 "udp/bootpc: unknown service -- assuming port %d",
483 bootpc_port
= (u_short
) IPPORT_BOOTPC
;
487 * Set up signals to read or dump the table.
489 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
490 sa
.sa_handler
= catcher
;
491 sigemptyset(&sa
.sa_mask
);
493 if (sigaction(SIGHUP
, &sa
, NULL
) < 0) {
494 report(LOG_ERR
, "sigaction: %s", get_errmsg());
497 if (sigaction(SIGUSR1
, &sa
, NULL
) < 0) {
498 report(LOG_ERR
, "sigaction: %s", get_errmsg());
501 #else /* SA_NOCLDSTOP */
502 /* Old-fashioned UNIX signals */
503 if ((int) signal(SIGHUP
, catcher
) < 0) {
504 report(LOG_ERR
, "signal: %s", get_errmsg());
507 if ((int) signal(SIGUSR1
, catcher
) < 0) {
508 report(LOG_ERR
, "signal: %s", get_errmsg());
511 #endif /* SA_NOCLDSTOP */
514 * Process incoming requests.
523 nfound
= select(s
+ 1, (fd_set
*)&readfds
, NULL
, NULL
,
524 (timeout
) ? &tv
: NULL
);
526 if (errno
!= EINTR
) {
527 report(LOG_ERR
, "select: %s", get_errmsg());
530 * Call readtab() or dumptab() here to avoid the
531 * dangers of doing I/O from a signal handler.
535 readtab(1); /* force read */
539 dumptab(bootpd_dump
);
543 if (!(readfds
& (1 << s
))) {
545 report(LOG_INFO
, "exiting after %ld minutes of inactivity",
546 actualtimeout
.tv_sec
/ 60);
549 ra_len
= sizeof(recv_addr
);
550 n
= recvfrom(s
, pktbuf
, MAX_MSG_SIZE
, 0,
551 (struct sockaddr
*) &recv_addr
, &ra_len
);
556 report(LOG_INFO
, "recvd pkt from IP addr %s",
557 inet_ntoa(recv_addr
.sin_addr
));
559 if (n
< sizeof(struct bootp
)) {
561 report(LOG_NOTICE
, "received short packet");
567 readtab(0); /* maybe re-read bootptab */
585 * Print "usage" message and exit
592 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
593 fprintf(stderr
, "\t -c n\tset current directory\n");
594 fprintf(stderr
, "\t -d n\tset debug level\n");
595 fprintf(stderr
, "\t -i\tforce inetd mode (run as child of inetd)\n");
596 fprintf(stderr
, "\t -s\tforce standalone mode (run without inetd)\n");
597 fprintf(stderr
, "\t -t n\tset inetd exit timeout to n minutes\n");
601 /* Signal catchers */
610 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
611 /* For older "System V" derivatives with no sigaction(). */
612 signal(sig
, catcher
);
619 * Process BOOTREQUEST packet.
621 * Note: This version of the bootpd.c server never forwards
622 * a request to another server. That is the job of a gateway
623 * program such as the "bootpgw" program included here.
625 * (Also this version does not interpret the hostname field of
626 * the request packet; it COULD do a name->address lookup and
627 * forward the request there.)
632 struct bootp
*bp
= (struct bootp
*) pktbuf
;
633 struct host
*hp
= NULL
;
634 struct host dummyhost
;
636 unsigned hlen
, hashcode
;
640 char *homedir
, *bootfile
;
643 bp
->bp_file
[sizeof(bp
->bp_file
)-1] = '\0';
645 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
648 * If the servername field is set, compare it against us.
649 * If we're not being addressed, ignore this request.
650 * If the server name field is null, throw in our name.
652 if (strlen(bp
->bp_sname
)) {
653 if (strcmp(bp
->bp_sname
, hostname
)) {
656 ignoring request for server %s from client at %s address %s",
657 bp
->bp_sname
, netname(bp
->bp_htype
),
658 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
659 /* XXX - Is it correct to ignore such a request? -gwr */
663 strcpy(bp
->bp_sname
, hostname
);
666 /* Convert the request into a reply. */
667 bp
->bp_op
= BOOTREPLY
;
668 if (bp
->bp_ciaddr
.s_addr
== 0) {
670 * client doesnt know his IP address,
671 * search by hardware address.
674 report(LOG_INFO
, "request from %s address %s",
675 netname(bp
->bp_htype
),
676 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
678 hlen
= haddrlength(bp
->bp_htype
);
679 if (hlen
!= bp
->bp_hlen
) {
680 report(LOG_NOTICE
, "bad addr len from from %s address %s",
681 netname(bp
->bp_htype
),
682 haddrtoa(bp
->bp_chaddr
, hlen
));
684 dummyhost
.htype
= bp
->bp_htype
;
685 bcopy(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
686 hashcode
= hash_HashFunction(bp
->bp_chaddr
, hlen
);
687 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
, hwlookcmp
,
690 bp
->bp_htype
== HTYPE_IEEE802
)
692 /* Try again with address in "canonical" form. */
693 haddr_conv802(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
696 HW addr type is IEEE 802. convert to %s and check again\n",
697 haddrtoa(dummyhost
.haddr
, bp
->bp_hlen
));
699 hashcode
= hash_HashFunction(dummyhost
.haddr
, hlen
);
700 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
,
701 hwlookcmp
, &dummyhost
);
705 * XXX - Add dynamic IP address assignment?
708 report(LOG_NOTICE
, "unknown client %s address %s",
709 netname(bp
->bp_htype
),
710 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
711 return; /* not found */
713 (bp
->bp_yiaddr
).s_addr
= hp
->iaddr
.s_addr
;
718 * search by IP address.
721 report(LOG_INFO
, "request from IP addr %s",
722 inet_ntoa(bp
->bp_ciaddr
));
724 dummyhost
.iaddr
.s_addr
= bp
->bp_ciaddr
.s_addr
;
725 hashcode
= hash_HashFunction((u_char
*) &(bp
->bp_ciaddr
.s_addr
), 4);
726 hp
= (struct host
*) hash_Lookup(iphashtable
, hashcode
, iplookcmp
,
730 report(LOG_NOTICE
, "IP address not found: %s",
731 inet_ntoa(bp
->bp_ciaddr
));
738 report(LOG_INFO
, "found %s (%s)", inet_ntoa(hp
->iaddr
),
739 hp
->hostname
->string
);
743 * If there is a response delay threshold, ignore requests
744 * with a timestamp lower than the threshold.
746 if (hp
->flags
.min_wait
) {
747 u_int32 t
= (u_int32
) ntohs(bp
->bp_secs
);
748 if (t
< hp
->min_wait
) {
751 "ignoring request due to timestamp (%d < %d)",
757 #ifdef YORK_EX_OPTION
759 * The need for the "ex" tag arose out of the need to empty
760 * shared networked drives on diskless PCs. This solution is
761 * not very clean but it does work fairly well.
762 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
764 * XXX - This could compromise security if a non-trusted user
765 * managed to write an entry in the bootptab with :ex=trojan:
766 * so I would leave this turned off unless you need it. -gwr
768 /* Run a program, passing the client name as a parameter. */
769 if (hp
->flags
.exec_file
) {
771 /* XXX - Check string lengths? -gwr */
772 strcpy (tst
, hp
->exec_file
->string
);
774 strcat (tst
, hp
->hostname
->string
);
777 report(LOG_INFO
, "executing %s", tst
);
778 system(tst
); /* Hope this finishes soon... */
780 #endif /* YORK_EX_OPTION */
783 * If a specific TFTP server address was specified in the bootptab file,
784 * fill it in, otherwise zero it.
785 * XXX - Rather than zero it, should it be the bootpd address? -gwr
787 (bp
->bp_siaddr
).s_addr
= (hp
->flags
.bootserver
) ?
788 hp
->bootserver
.s_addr
: 0L;
790 #ifdef STANFORD_PROM_COMPAT
792 * Stanford bootp PROMs (for a Sun?) have no way to leave
793 * the boot file name field blank (because the boot file
794 * name is automatically generated from some index).
795 * As a work-around, this little hack allows those PROMs to
796 * specify "sunboot14" with the same effect as a NULL name.
797 * (The user specifies boot device 14 or some such magic.)
799 if (strcmp(bp
->bp_file
, "sunboot14") == 0)
800 bp
->bp_file
[0] = '\0'; /* treat it as unspecified */
804 * Fill in the client's proper bootfile.
806 * If the client specifies an absolute path, try that file with a
807 * ".host" suffix and then without. If the file cannot be found, no
808 * reply is made at all.
810 * If the client specifies a null or relative file, use the following
811 * table to determine the appropriate action:
813 * Homedir Bootfile Client's file
814 * specified? specified? specification Action
815 * -------------------------------------------------------------------
816 * No No Null Send null filename
817 * No No Relative Discard request
818 * No Yes Null Send if absolute else null
819 * No Yes Relative Discard request *XXX
820 * Yes No Null Send null filename
821 * Yes No Relative Lookup with ".host"
822 * Yes Yes Null Send home/boot or bootfile
823 * Yes Yes Relative Lookup with ".host" *XXX
828 * XXX - I don't like the policy of ignoring a client when the
829 * boot file is not accessible. The TFTP server might not be
830 * running on the same machine as the BOOTP server, in which
831 * case checking accessibility of the boot file is pointless.
833 * Therefore, file accessibility is now demanded ONLY if you
834 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
838 * The "real" path is as seen by the BOOTP daemon on this
839 * machine, while the client path is relative to the TFTP
840 * daemon chroot directory (i.e. /tftpboot).
842 if (hp
->flags
.tftpdir
) {
843 snprintf(realpath
, sizeof(realpath
), "%s", hp
->tftpdir
->string
);
844 clntpath
= &realpath
[strlen(realpath
)];
851 * Determine client's requested homedir and bootfile.
855 if (bp
->bp_file
[0]) {
856 homedir
= bp
->bp_file
;
857 bootfile
= strrchr(homedir
, '/');
859 if (homedir
== bootfile
)
863 /* no "/" in the string */
868 report(LOG_INFO
, "requested path=\"%s\" file=\"%s\"",
869 (homedir
) ? homedir
: "",
870 (bootfile
) ? bootfile
: "");
875 * Specifications in bootptab override client requested values.
877 if (hp
->flags
.homedir
)
878 homedir
= hp
->homedir
->string
;
879 if (hp
->flags
.bootfile
)
880 bootfile
= hp
->bootfile
->string
;
883 * Construct bootfile path.
886 if (homedir
[0] != '/')
887 strcat(clntpath
, "/");
888 strcat(clntpath
, homedir
);
892 if (bootfile
[0] != '/')
893 strcat(clntpath
, "/");
894 strcat(clntpath
, bootfile
);
899 * First try to find the file with a ".host" suffix
901 n
= strlen(clntpath
);
902 strcat(clntpath
, ".");
903 strcat(clntpath
, hp
->hostname
->string
);
904 if (chk_access(realpath
, &bootsize
) < 0) {
905 clntpath
[n
] = 0; /* Try it without the suffix */
906 if (chk_access(realpath
, &bootsize
) < 0) {
907 /* neither "file.host" nor "file" was found */
908 #ifdef CHECK_FILE_ACCESS
910 if (bp
->bp_file
[0]) {
912 * Client wanted specific file
913 * and we didn't have it.
916 "requested file not found: \"%s\"", clntpath
);
920 * Client didn't ask for a specific file and we couldn't
921 * access the default file, so just zero-out the bootfile
922 * field in the packet and continue processing the reply.
924 bzero(bp
->bp_file
, sizeof(bp
->bp_file
));
927 #else /* CHECK_FILE_ACCESS */
929 /* Complain only if boot file size was needed. */
930 if (hp
->flags
.bootsize_auto
) {
931 report(LOG_ERR
, "can not determine size of file \"%s\"",
935 #endif /* CHECK_FILE_ACCESS */
938 strncpy(bp
->bp_file
, clntpath
, BP_FILE_LEN
);
940 report(LOG_INFO
, "bootfile=\"%s\"", clntpath
);
942 #ifdef CHECK_FILE_ACCESS
944 #endif /* CHECK_FILE_ACCESS */
948 * Handle vendor options based on magic number.
952 report(LOG_INFO
, "vendor magic field is %d.%d.%d.%d",
953 (int) ((bp
->bp_vend
)[0]),
954 (int) ((bp
->bp_vend
)[1]),
955 (int) ((bp
->bp_vend
)[2]),
956 (int) ((bp
->bp_vend
)[3]));
959 * If this host isn't set for automatic vendor info then copy the
960 * specific cookie into the bootp packet, thus forcing a certain
961 * reply format. Only force reply format if user specified it.
963 if (hp
->flags
.vm_cookie
) {
964 /* Slam in the user specified magic number. */
965 bcopy(hp
->vm_cookie
, bp
->bp_vend
, 4);
968 * Figure out the format for the vendor-specific info.
969 * Note that bp->bp_vend may have been set above.
971 if (!bcmp(bp
->bp_vend
, vm_rfc1048
, 4)) {
972 /* RFC1048 conformant bootp client */
973 dovend_rfc1048(bp
, hp
, bootsize
);
975 report(LOG_INFO
, "sending reply (with RFC1048 options)");
979 else if (!bcmp(bp
->bp_vend
, vm_cmu
, 4)) {
982 report(LOG_INFO
, "sending reply (with CMU options)");
988 report(LOG_INFO
, "sending reply (with no options)");
992 dest
= (hp
->flags
.reply_addr
) ?
993 hp
->reply_addr
.s_addr
: 0L;
1001 * Process BOOTREPLY packet.
1007 report(LOG_INFO
, "processing boot reply");
1009 /* forwarded, no destination override */
1015 * Send a reply packet to the client. 'forward' flag is set if we are
1016 * not the originator of this reply packet.
1019 sendreply(forward
, dst_override
)
1023 struct bootp
*bp
= (struct bootp
*) pktbuf
;
1025 u_short port
= bootpc_port
;
1030 * XXX - Should honor bp_flags "broadcast" bit here.
1031 * Temporary workaround: use the :ra=ADDR: option to
1032 * set the reply address to the broadcast address.
1036 * If the destination address was specified explicitly
1037 * (i.e. the broadcast address for HP compatiblity)
1038 * then send the response to that address. Otherwise,
1039 * act in accordance with RFC951:
1040 * If the client IP address is specified, use that
1041 * else if gateway IP address is specified, use that
1042 * else make a temporary arp cache entry for the client's
1043 * NEW IP/hardware address and use that.
1046 dst
.s_addr
= dst_override
;
1048 report(LOG_INFO
, "reply address override: %s",
1051 } else if (bp
->bp_ciaddr
.s_addr
) {
1052 dst
= bp
->bp_ciaddr
;
1053 } else if (bp
->bp_giaddr
.s_addr
&& forward
== 0) {
1054 dst
= bp
->bp_giaddr
;
1057 report(LOG_INFO
, "sending reply to gateway %s",
1061 dst
= bp
->bp_yiaddr
;
1064 if (len
> MAXHADDRLEN
)
1066 haf
= (int) bp
->bp_htype
;
1068 haf
= HTYPE_ETHERNET
;
1071 report(LOG_INFO
, "setarp %s - %s",
1072 inet_ntoa(dst
), haddrtoa(ha
, len
));
1073 setarp(s
, &dst
, haf
, ha
, len
);
1076 if ((forward
== 0) &&
1077 (bp
->bp_siaddr
.s_addr
== 0))
1080 struct in_addr siaddr
;
1082 * If we are originating this reply, we
1083 * need to find our own interface address to
1084 * put in the bp_siaddr field of the reply.
1085 * If this server is multi-homed, pick the
1086 * 'best' interface (the one on the same net
1087 * as the client). Of course, the client may
1088 * be on the other side of a BOOTP gateway...
1090 ifr
= getif(s
, &dst
);
1092 struct sockaddr_in
*sip
;
1093 sip
= (struct sockaddr_in
*) &(ifr
->ifr_addr
);
1094 siaddr
= sip
->sin_addr
;
1096 /* Just use my "official" IP address. */
1097 siaddr
= my_ip_addr
;
1100 /* XXX - No need to set bp_giaddr here. */
1102 /* Finally, set the server address field. */
1103 bp
->bp_siaddr
= siaddr
;
1105 /* Set up socket address for send. */
1106 send_addr
.sin_family
= AF_INET
;
1107 send_addr
.sin_port
= htons(port
);
1108 send_addr
.sin_addr
= dst
;
1110 /* Send reply with same size packet as request used. */
1111 if (sendto(s
, pktbuf
, pktlen
, 0,
1112 (struct sockaddr
*) &send_addr
,
1113 sizeof(send_addr
)) < 0)
1115 report(LOG_ERR
, "sendto: %s", get_network_errmsg());
1120 /* nmatch() - now in getif.c */
1121 /* setarp() - now in hwaddr.c */
1125 * This call checks read access to a file. It returns 0 if the file given
1126 * by "path" exists and is publically readable. A value of -1 is returned if
1127 * access is not permitted or an error occurs. Successful calls also
1128 * return the file size in bytes using the long pointer "filesize".
1130 * The read permission bit for "other" users is checked. This bit must be
1131 * set for tftpd(8) to allow clients to read the file.
1135 chk_access(path
, filesize
)
1141 if ((stat(path
, &st
) == 0) && (st
.st_mode
& (S_IREAD
>> 6))) {
1142 *filesize
= (int32
) st
.st_size
;
1151 * Now in dumptab.c :
1154 * list_ipaddresses()
1160 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1161 * bootp packet pointed to by "bp".
1169 struct cmu_vend
*vendp
;
1170 struct in_addr_list
*taddr
;
1173 * Initialize the entire vendor field to zeroes.
1175 bzero(bp
->bp_vend
, sizeof(bp
->bp_vend
));
1178 * Fill in vendor information. Subnet mask, default gateway,
1179 * domain name server, ien name server, time server
1181 vendp
= (struct cmu_vend
*) bp
->bp_vend
;
1182 strcpy(vendp
->v_magic
, (char *)vm_cmu
);
1183 if (hp
->flags
.subnet_mask
) {
1184 (vendp
->v_smask
).s_addr
= hp
->subnet_mask
.s_addr
;
1185 (vendp
->v_flags
) |= VF_SMASK
;
1186 if (hp
->flags
.gateway
) {
1187 (vendp
->v_dgate
).s_addr
= hp
->gateway
->addr
->s_addr
;
1190 if (hp
->flags
.domain_server
) {
1191 taddr
= hp
->domain_server
;
1192 if (taddr
->addrcount
> 0) {
1193 (vendp
->v_dns1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1194 if (taddr
->addrcount
> 1) {
1195 (vendp
->v_dns2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1199 if (hp
->flags
.name_server
) {
1200 taddr
= hp
->name_server
;
1201 if (taddr
->addrcount
> 0) {
1202 (vendp
->v_ins1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1203 if (taddr
->addrcount
> 1) {
1204 (vendp
->v_ins2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1208 if (hp
->flags
.time_server
) {
1209 taddr
= hp
->time_server
;
1210 if (taddr
->addrcount
> 0) {
1211 (vendp
->v_ts1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1212 if (taddr
->addrcount
> 1) {
1213 (vendp
->v_ts2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1217 /* Log message now done by caller. */
1220 #endif /* VEND_CMU */
1225 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1226 * bootp packet pointed to by "bp".
1228 #define NEED(LEN, MSG) do \
1229 if (bytesleft < (LEN)) { \
1230 report(LOG_NOTICE, noroom, \
1231 hp->hostname->string, MSG); \
1235 dovend_rfc1048(bp
, hp
, bootsize
)
1243 static const char noroom
[] = "%s: No room for \"%s\" option";
1247 if (hp
->flags
.msg_size
) {
1248 pktlen
= hp
->msg_size
;
1251 * If the request was longer than the official length, build
1252 * a response of that same length where the additional length
1253 * is assumed to be part of the bp_vend (options) area.
1255 if (pktlen
> sizeof(*bp
)) {
1257 report(LOG_INFO
, "request message length=%d", pktlen
);
1260 * Check whether the request contains the option:
1261 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1262 * and if so, override the response length with its value.
1263 * This request must lie within the first BP_VEND_LEN
1264 * bytes of the option space.
1272 ep
= p
+ BP_VEND_LEN
- 4;
1275 /* Check for tags with no data first. */
1280 /* Now scan the length byte. */
1285 bcopy(p
, (char*)&msgsz
, 2);
1286 msgsz
= ntohs(msgsz
);
1289 case TAG_SUBNET_MASK
:
1290 /* XXX - Should preserve this if given... */
1296 if (msgsz
> sizeof(*bp
) + BP_MSG_OVERHEAD
) {
1298 report(LOG_INFO
, "request has DHCP msglen=%d", msgsz
);
1299 pktlen
= msgsz
- BP_MSG_OVERHEAD
;
1304 if (pktlen
< sizeof(*bp
)) {
1305 report(LOG_ERR
, "invalid response length=%d", pktlen
);
1306 pktlen
= sizeof(*bp
);
1308 bytesleft
= ((byte
*)bp
+ pktlen
) - vp
;
1309 if (pktlen
> sizeof(*bp
)) {
1311 report(LOG_INFO
, "extended reply, length=%d, options=%d",
1315 /* Copy in the magic cookie */
1316 bcopy(vm_rfc1048
, vp
, 4);
1320 if (hp
->flags
.subnet_mask
) {
1321 /* always enough room here. */
1322 *vp
++ = TAG_SUBNET_MASK
;/* -1 byte */
1323 *vp
++ = 4; /* -1 byte */
1324 insert_u_long(hp
->subnet_mask
.s_addr
, &vp
); /* -4 bytes */
1325 bytesleft
-= 6; /* Fix real count */
1326 if (hp
->flags
.gateway
) {
1327 (void) insert_ip(TAG_GATEWAY
,
1332 if (hp
->flags
.bootsize
) {
1333 /* always enough room here */
1334 bootsize
= (hp
->flags
.bootsize_auto
) ?
1335 ((bootsize
+ 511) / 512) : (hp
->bootsize
); /* Round up */
1336 *vp
++ = TAG_BOOT_SIZE
;
1338 *vp
++ = (byte
) ((bootsize
>> 8) & 0xFF);
1339 *vp
++ = (byte
) (bootsize
& 0xFF);
1340 bytesleft
-= 4; /* Tag, length, and 16 bit blocksize */
1343 * This one is special: Remaining options go in the ext file.
1344 * Only the subnet_mask, bootsize, and gateway should precede.
1346 if (hp
->flags
.exten_file
) {
1348 * Check for room for exten_file. Add 3 to account for
1349 * TAG_EXTEN_FILE, length, and TAG_END.
1351 len
= strlen(hp
->exten_file
->string
);
1352 NEED((len
+ 3), "ef");
1353 *vp
++ = TAG_EXTEN_FILE
;
1354 *vp
++ = (byte
) (len
& 0xFF);
1355 bcopy(hp
->exten_file
->string
, vp
, len
);
1358 bytesleft
-= len
+ 3;
1359 return; /* no more options here. */
1362 * The remaining options are inserted by the following
1363 * function (which is shared with bootpef.c).
1364 * Keep back one byte for the TAG_END.
1366 len
= dovend_rfc1497(hp
, vp
, bytesleft
- 1);
1370 /* There should be at least one byte left. */
1375 /* Log message done by caller. */
1376 if (bytesleft
> 0) {
1378 * Zero out any remaining part of the vendor area.
1380 bzero(vp
, bytesleft
);
1382 } /* dovend_rfc1048 */
1387 * Now in readfile.c:
1392 /* haddrtoa() - now in hwaddr.c */
1400 /* get_errmsg() - now in report.c */
1406 * c-argdecl-indent: 4
1407 * c-continued-statement-offset: 4
1408 * c-continued-brace-offset: -4
1409 * c-label-offset: -4