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
109 extern void dumptab(char *);
111 PRIVATE
void catcher(int);
112 PRIVATE
int chk_access(char *, int32
*);
114 PRIVATE
void dovend_cmu(struct bootp
*, struct host
*);
116 PRIVATE
void dovend_rfc1048(struct bootp
*, struct host
*, int32
);
117 PRIVATE
void handle_reply(void);
118 PRIVATE
void handle_request(void);
119 PRIVATE
void sendreply(int forward
, int32 dest_override
);
120 PRIVATE
void usage(void);
123 * IP port numbers for client and server obtained from /etc/services
126 u_short bootps_port
, bootpc_port
;
130 * Internet socket and interface config structures
133 struct sockaddr_in bind_addr
; /* Listening */
134 struct sockaddr_in recv_addr
; /* Packet source */
135 struct sockaddr_in send_addr
; /* destination */
141 int debug
= 0; /* Debugging flag (level) */
142 struct timeval actualtimeout
=
143 { /* fifteen minutes */
144 15 * 60L, /* tv_sec */
152 int s
; /* Socket file descriptor */
153 char *pktbuf
; /* Receive packet buffer */
157 struct in_addr my_ip_addr
;
159 static const char *hostname
;
160 static char default_hostname
[MAXHOSTNAMELEN
];
162 /* Flags set by signal catcher. */
163 PRIVATE
int do_readtab
= 0;
164 PRIVATE
int do_dumptab
= 0;
167 * Globals below are associated with the bootp database file (bootptab).
170 char *bootptab
= CONFIG_FILE
;
171 char *bootpd_dump
= DUMPTAB_FILE
;
176 * Initialization such as command-line processing is done and then the
177 * main server loop is started.
181 main(int argc
, char **argv
)
183 struct timeval
*timeout
;
185 struct servent
*servp
;
188 int n
, ba_len
, ra_len
;
191 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
195 progname
= strrchr(argv
[0], '/');
196 if (progname
) progname
++;
197 else progname
= argv
[0];
200 * Initialize logging.
202 report_init(0); /* uses progname */
207 report(LOG_INFO
, "version %s.%d", VERSION
, PATCHLEVEL
);
209 /* Debugging for compilers with struct padding. */
210 assert(sizeof(struct bootp
) == BP_MINPKTSZ
);
212 /* Get space for receiving packets and composing replies. */
213 pktbuf
= malloc(MAX_MSG_SIZE
);
215 report(LOG_ERR
, "malloc failed");
218 bp
= (struct bootp
*) pktbuf
;
221 * Check to see if a socket was passed to us from inetd.
223 * Use getsockname() to determine if descriptor 0 is indeed a socket
224 * (and thus we are probably a child of inetd) or if it is instead
225 * something else and we are running standalone.
228 ba_len
= sizeof(bind_addr
);
229 bzero((char *) &bind_addr
, ba_len
);
232 if (getsockname(s
, (struct sockaddr
*) &bind_addr
, &ba_len
) == 0) {
234 * Descriptor 0 is a socket. Assume we are a child of inetd.
236 if (bind_addr
.sin_family
== AF_INET
) {
238 bootps_port
= ntohs(bind_addr
.sin_port
);
240 /* Some other type of socket? */
241 report(LOG_ERR
, "getsockname: not an INET socket");
246 * Set defaults that might be changed by option switches.
249 timeout
= &actualtimeout
;
251 if (gethostname(default_hostname
, sizeof(default_hostname
) - 1) < 0) {
252 report(LOG_ERR
, "bootpd: can't get hostname\n");
255 default_hostname
[sizeof(default_hostname
) - 1] = '\0';
256 hostname
= default_hostname
;
261 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
262 if (argv
[0][0] != '-')
264 switch (argv
[0][1]) {
266 case 'c': /* chdir_path */
268 stmp
= &(argv
[0][2]);
274 if (!stmp
|| (stmp
[0] != '/')) {
276 "bootpd: invalid chdir specification\n");
282 case 'd': /* debug level */
284 stmp
= &(argv
[0][2]);
285 } else if (argv
[1] && argv
[1][0] == '-') {
287 * Backwards-compatible behavior:
288 * no parameter, so just increment the debug flag.
297 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
299 "%s: invalid debug level\n", progname
);
305 case 'h': /* override hostname */
307 stmp
= &(argv
[0][2]);
315 "bootpd: missing hostname\n");
321 case 'i': /* inetd mode */
325 case 's': /* standalone mode */
329 case 't': /* timeout */
331 stmp
= &(argv
[0][2]);
337 if (!stmp
|| (sscanf(stmp
, "%d", &n
) != 1) || (n
< 0)) {
339 "%s: invalid timeout specification\n", progname
);
342 actualtimeout
.tv_sec
= (int32
) (60 * n
);
344 * If the actual timeout is zero, pass a NULL pointer
345 * to select so it blocks indefinitely, otherwise,
346 * point to the actual timeout value.
348 timeout
= (n
> 0) ? &actualtimeout
: NULL
;
352 report(LOG_ERR
, "%s: unknown switch: -%c\n",
353 progname
, argv
[0][1]);
361 * Override default file names if specified on the command line.
367 bootpd_dump
= argv
[1];
370 * Get my hostname and IP address.
373 hep
= gethostbyname(hostname
);
375 report(LOG_ERR
, "Can not get my IP address\n");
378 bcopy(hep
->h_addr
, (char *)&my_ip_addr
, sizeof(my_ip_addr
));
382 * Go into background and disassociate from controlling terminal.
390 n
= open(_PATH_TTY
, O_RDWR
);
392 ioctl(n
, TIOCNOTTY
, NULL
);
395 #endif /* TIOCNOTTY */
403 * Nuke any timeout value
407 } /* if standalone (1st) */
409 /* Set the cwd (i.e. to /tftpboot) */
411 if (chdir(chdir_path
) < 0)
412 report(LOG_ERR
, "%s: chdir failed", chdir_path
);
415 /* Get the timezone. */
418 /* Allocate hash tables. */
422 * Read the bootptab file.
424 readtab(1); /* force read */
431 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
432 report(LOG_ERR
, "socket: %s", get_network_errmsg());
437 * Get server's listening port number
439 servp
= getservbyname("bootps", "udp");
441 bootps_port
= ntohs((u_short
) servp
->s_port
);
443 bootps_port
= (u_short
) IPPORT_BOOTPS
;
445 "udp/bootps: unknown service -- assuming port %d",
450 * Bind socket to BOOTPS port.
452 bind_addr
.sin_family
= AF_INET
;
453 bind_addr
.sin_addr
.s_addr
= INADDR_ANY
;
454 bind_addr
.sin_port
= htons(bootps_port
);
455 if (bind(s
, (struct sockaddr
*) &bind_addr
,
456 sizeof(bind_addr
)) < 0)
458 report(LOG_ERR
, "bind: %s", get_network_errmsg());
461 } /* if standalone (2nd)*/
464 * Get destination port number so we can reply to client
466 servp
= getservbyname("bootpc", "udp");
468 bootpc_port
= ntohs(servp
->s_port
);
471 "udp/bootpc: unknown service -- assuming port %d",
473 bootpc_port
= (u_short
) IPPORT_BOOTPC
;
477 * Set up signals to read or dump the table.
479 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
480 sa
.sa_handler
= catcher
;
481 sigemptyset(&sa
.sa_mask
);
483 if (sigaction(SIGHUP
, &sa
, NULL
) < 0) {
484 report(LOG_ERR
, "sigaction: %s", get_errmsg());
487 if (sigaction(SIGUSR1
, &sa
, NULL
) < 0) {
488 report(LOG_ERR
, "sigaction: %s", get_errmsg());
491 #else /* SA_NOCLDSTOP */
492 /* Old-fashioned UNIX signals */
493 if ((int) signal(SIGHUP
, catcher
) < 0) {
494 report(LOG_ERR
, "signal: %s", get_errmsg());
497 if ((int) signal(SIGUSR1
, catcher
) < 0) {
498 report(LOG_ERR
, "signal: %s", get_errmsg());
501 #endif /* SA_NOCLDSTOP */
504 * Process incoming requests.
513 nfound
= select(s
+ 1, (fd_set
*)&readfds
, NULL
, NULL
,
514 (timeout
) ? &tv
: NULL
);
516 if (errno
!= EINTR
) {
517 report(LOG_ERR
, "select: %s", get_errmsg());
520 * Call readtab() or dumptab() here to avoid the
521 * dangers of doing I/O from a signal handler.
525 readtab(1); /* force read */
529 dumptab(bootpd_dump
);
533 if (!(readfds
& (1 << s
))) {
535 report(LOG_INFO
, "exiting after %ld minutes of inactivity",
536 actualtimeout
.tv_sec
/ 60);
539 ra_len
= sizeof(recv_addr
);
540 n
= recvfrom(s
, pktbuf
, MAX_MSG_SIZE
, 0,
541 (struct sockaddr
*) &recv_addr
, &ra_len
);
546 report(LOG_INFO
, "recvd pkt from IP addr %s",
547 inet_ntoa(recv_addr
.sin_addr
));
549 if (n
< sizeof(struct bootp
)) {
551 report(LOG_NOTICE
, "received short packet");
557 readtab(0); /* maybe re-read bootptab */
575 * Print "usage" message and exit
582 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
583 fprintf(stderr
, "\t -c n\tset current directory\n");
584 fprintf(stderr
, "\t -d n\tset debug level\n");
585 fprintf(stderr
, "\t -i\tforce inetd mode (run as child of inetd)\n");
586 fprintf(stderr
, "\t -s\tforce standalone mode (run without inetd)\n");
587 fprintf(stderr
, "\t -t n\tset inetd exit timeout to n minutes\n");
591 /* Signal catchers */
599 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
600 /* For older "System V" derivatives with no sigaction(). */
601 signal(sig
, catcher
);
608 * Process BOOTREQUEST packet.
610 * Note: This version of the bootpd.c server never forwards
611 * a request to another server. That is the job of a gateway
612 * program such as the "bootpgw" program included here.
614 * (Also this version does not interpret the hostname field of
615 * the request packet; it COULD do a name->address lookup and
616 * forward the request there.)
621 struct bootp
*bp
= (struct bootp
*) pktbuf
;
622 struct host
*hp
= NULL
;
623 struct host dummyhost
;
625 unsigned hlen
, hashcode
;
629 char *homedir
, *bootfile
;
632 bp
->bp_file
[sizeof(bp
->bp_file
)-1] = '\0';
634 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
637 * If the servername field is set, compare it against us.
638 * If we're not being addressed, ignore this request.
639 * If the server name field is null, throw in our name.
641 if (strlen(bp
->bp_sname
)) {
642 if (strcmp(bp
->bp_sname
, hostname
)) {
645 ignoring request for server %s from client at %s address %s",
646 bp
->bp_sname
, netname(bp
->bp_htype
),
647 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
648 /* XXX - Is it correct to ignore such a request? -gwr */
652 strcpy(bp
->bp_sname
, hostname
);
655 /* Convert the request into a reply. */
656 bp
->bp_op
= BOOTREPLY
;
657 if (bp
->bp_ciaddr
.s_addr
== 0) {
659 * client doesnt know his IP address,
660 * search by hardware address.
663 report(LOG_INFO
, "request from %s address %s",
664 netname(bp
->bp_htype
),
665 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
667 hlen
= haddrlength(bp
->bp_htype
);
668 if (hlen
!= bp
->bp_hlen
) {
669 report(LOG_NOTICE
, "bad addr len from from %s address %s",
670 netname(bp
->bp_htype
),
671 haddrtoa(bp
->bp_chaddr
, hlen
));
673 dummyhost
.htype
= bp
->bp_htype
;
674 bcopy(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
675 hashcode
= hash_HashFunction(bp
->bp_chaddr
, hlen
);
676 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
, hwlookcmp
,
679 bp
->bp_htype
== HTYPE_IEEE802
)
681 /* Try again with address in "canonical" form. */
682 haddr_conv802(bp
->bp_chaddr
, dummyhost
.haddr
, hlen
);
685 HW addr type is IEEE 802. convert to %s and check again\n",
686 haddrtoa(dummyhost
.haddr
, bp
->bp_hlen
));
688 hashcode
= hash_HashFunction(dummyhost
.haddr
, hlen
);
689 hp
= (struct host
*) hash_Lookup(hwhashtable
, hashcode
,
690 hwlookcmp
, &dummyhost
);
694 * XXX - Add dynamic IP address assignment?
697 report(LOG_NOTICE
, "unknown client %s address %s",
698 netname(bp
->bp_htype
),
699 haddrtoa(bp
->bp_chaddr
, bp
->bp_hlen
));
700 return; /* not found */
702 (bp
->bp_yiaddr
).s_addr
= hp
->iaddr
.s_addr
;
707 * search by IP address.
710 report(LOG_INFO
, "request from IP addr %s",
711 inet_ntoa(bp
->bp_ciaddr
));
713 dummyhost
.iaddr
.s_addr
= bp
->bp_ciaddr
.s_addr
;
714 hashcode
= hash_HashFunction((u_char
*) &(bp
->bp_ciaddr
.s_addr
), 4);
715 hp
= (struct host
*) hash_Lookup(iphashtable
, hashcode
, iplookcmp
,
719 report(LOG_NOTICE
, "IP address not found: %s",
720 inet_ntoa(bp
->bp_ciaddr
));
727 report(LOG_INFO
, "found %s (%s)", inet_ntoa(hp
->iaddr
),
728 hp
->hostname
->string
);
732 * If there is a response delay threshold, ignore requests
733 * with a timestamp lower than the threshold.
735 if (hp
->flags
.min_wait
) {
736 u_int32 t
= (u_int32
) ntohs(bp
->bp_secs
);
737 if (t
< hp
->min_wait
) {
740 "ignoring request due to timestamp (%d < %d)",
746 #ifdef YORK_EX_OPTION
748 * The need for the "ex" tag arose out of the need to empty
749 * shared networked drives on diskless PCs. This solution is
750 * not very clean but it does work fairly well.
751 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
753 * XXX - This could compromise security if a non-trusted user
754 * managed to write an entry in the bootptab with :ex=trojan:
755 * so I would leave this turned off unless you need it. -gwr
757 /* Run a program, passing the client name as a parameter. */
758 if (hp
->flags
.exec_file
) {
760 /* XXX - Check string lengths? -gwr */
761 strcpy (tst
, hp
->exec_file
->string
);
763 strcat (tst
, hp
->hostname
->string
);
766 report(LOG_INFO
, "executing %s", tst
);
767 system(tst
); /* Hope this finishes soon... */
769 #endif /* YORK_EX_OPTION */
772 * If a specific TFTP server address was specified in the bootptab file,
773 * fill it in, otherwise zero it.
774 * XXX - Rather than zero it, should it be the bootpd address? -gwr
776 (bp
->bp_siaddr
).s_addr
= (hp
->flags
.bootserver
) ?
777 hp
->bootserver
.s_addr
: 0L;
779 #ifdef STANFORD_PROM_COMPAT
781 * Stanford bootp PROMs (for a Sun?) have no way to leave
782 * the boot file name field blank (because the boot file
783 * name is automatically generated from some index).
784 * As a work-around, this little hack allows those PROMs to
785 * specify "sunboot14" with the same effect as a NULL name.
786 * (The user specifies boot device 14 or some such magic.)
788 if (strcmp(bp
->bp_file
, "sunboot14") == 0)
789 bp
->bp_file
[0] = '\0'; /* treat it as unspecified */
793 * Fill in the client's proper bootfile.
795 * If the client specifies an absolute path, try that file with a
796 * ".host" suffix and then without. If the file cannot be found, no
797 * reply is made at all.
799 * If the client specifies a null or relative file, use the following
800 * table to determine the appropriate action:
802 * Homedir Bootfile Client's file
803 * specified? specified? specification Action
804 * -------------------------------------------------------------------
805 * No No Null Send null filename
806 * No No Relative Discard request
807 * No Yes Null Send if absolute else null
808 * No Yes Relative Discard request *XXX
809 * Yes No Null Send null filename
810 * Yes No Relative Lookup with ".host"
811 * Yes Yes Null Send home/boot or bootfile
812 * Yes Yes Relative Lookup with ".host" *XXX
817 * XXX - I don't like the policy of ignoring a client when the
818 * boot file is not accessible. The TFTP server might not be
819 * running on the same machine as the BOOTP server, in which
820 * case checking accessibility of the boot file is pointless.
822 * Therefore, file accessibility is now demanded ONLY if you
823 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
827 * The "real" path is as seen by the BOOTP daemon on this
828 * machine, while the client path is relative to the TFTP
829 * daemon chroot directory (i.e. /tftpboot).
831 if (hp
->flags
.tftpdir
) {
832 snprintf(realpath
, sizeof(realpath
), "%s", hp
->tftpdir
->string
);
833 clntpath
= &realpath
[strlen(realpath
)];
840 * Determine client's requested homedir and bootfile.
844 if (bp
->bp_file
[0]) {
845 homedir
= bp
->bp_file
;
846 bootfile
= strrchr(homedir
, '/');
848 if (homedir
== bootfile
)
852 /* no "/" in the string */
857 report(LOG_INFO
, "requested path=\"%s\" file=\"%s\"",
858 (homedir
) ? homedir
: "",
859 (bootfile
) ? bootfile
: "");
864 * Specifications in bootptab override client requested values.
866 if (hp
->flags
.homedir
)
867 homedir
= hp
->homedir
->string
;
868 if (hp
->flags
.bootfile
)
869 bootfile
= hp
->bootfile
->string
;
872 * Construct bootfile path.
875 if (homedir
[0] != '/')
876 strcat(clntpath
, "/");
877 strcat(clntpath
, homedir
);
881 if (bootfile
[0] != '/')
882 strcat(clntpath
, "/");
883 strcat(clntpath
, bootfile
);
888 * First try to find the file with a ".host" suffix
890 n
= strlen(clntpath
);
891 strcat(clntpath
, ".");
892 strcat(clntpath
, hp
->hostname
->string
);
893 if (chk_access(realpath
, &bootsize
) < 0) {
894 clntpath
[n
] = 0; /* Try it without the suffix */
895 if (chk_access(realpath
, &bootsize
) < 0) {
896 /* neither "file.host" nor "file" was found */
897 #ifdef CHECK_FILE_ACCESS
899 if (bp
->bp_file
[0]) {
901 * Client wanted specific file
902 * and we didn't have it.
905 "requested file not found: \"%s\"", clntpath
);
909 * Client didn't ask for a specific file and we couldn't
910 * access the default file, so just zero-out the bootfile
911 * field in the packet and continue processing the reply.
913 bzero(bp
->bp_file
, sizeof(bp
->bp_file
));
916 #else /* CHECK_FILE_ACCESS */
918 /* Complain only if boot file size was needed. */
919 if (hp
->flags
.bootsize_auto
) {
920 report(LOG_ERR
, "can not determine size of file \"%s\"",
924 #endif /* CHECK_FILE_ACCESS */
927 strncpy(bp
->bp_file
, clntpath
, BP_FILE_LEN
);
929 report(LOG_INFO
, "bootfile=\"%s\"", clntpath
);
931 #ifdef CHECK_FILE_ACCESS
933 #endif /* CHECK_FILE_ACCESS */
937 * Handle vendor options based on magic number.
941 report(LOG_INFO
, "vendor magic field is %d.%d.%d.%d",
942 (int) ((bp
->bp_vend
)[0]),
943 (int) ((bp
->bp_vend
)[1]),
944 (int) ((bp
->bp_vend
)[2]),
945 (int) ((bp
->bp_vend
)[3]));
948 * If this host isn't set for automatic vendor info then copy the
949 * specific cookie into the bootp packet, thus forcing a certain
950 * reply format. Only force reply format if user specified it.
952 if (hp
->flags
.vm_cookie
) {
953 /* Slam in the user specified magic number. */
954 bcopy(hp
->vm_cookie
, bp
->bp_vend
, 4);
957 * Figure out the format for the vendor-specific info.
958 * Note that bp->bp_vend may have been set above.
960 if (!bcmp(bp
->bp_vend
, vm_rfc1048
, 4)) {
961 /* RFC1048 conformant bootp client */
962 dovend_rfc1048(bp
, hp
, bootsize
);
964 report(LOG_INFO
, "sending reply (with RFC1048 options)");
968 else if (!bcmp(bp
->bp_vend
, vm_cmu
, 4)) {
971 report(LOG_INFO
, "sending reply (with CMU options)");
977 report(LOG_INFO
, "sending reply (with no options)");
981 dest
= (hp
->flags
.reply_addr
) ?
982 hp
->reply_addr
.s_addr
: 0L;
990 * Process BOOTREPLY packet.
996 report(LOG_INFO
, "processing boot reply");
998 /* forwarded, no destination override */
1004 * Send a reply packet to the client. 'forward' flag is set if we are
1005 * not the originator of this reply packet.
1008 sendreply(int forward
, int32 dst_override
)
1010 struct bootp
*bp
= (struct bootp
*) pktbuf
;
1012 u_short port
= bootpc_port
;
1017 * XXX - Should honor bp_flags "broadcast" bit here.
1018 * Temporary workaround: use the :ra=ADDR: option to
1019 * set the reply address to the broadcast address.
1023 * If the destination address was specified explicitly
1024 * (i.e. the broadcast address for HP compatiblity)
1025 * then send the response to that address. Otherwise,
1026 * act in accordance with RFC951:
1027 * If the client IP address is specified, use that
1028 * else if gateway IP address is specified, use that
1029 * else make a temporary arp cache entry for the client's
1030 * NEW IP/hardware address and use that.
1033 dst
.s_addr
= dst_override
;
1035 report(LOG_INFO
, "reply address override: %s",
1038 } else if (bp
->bp_ciaddr
.s_addr
) {
1039 dst
= bp
->bp_ciaddr
;
1040 } else if (bp
->bp_giaddr
.s_addr
&& forward
== 0) {
1041 dst
= bp
->bp_giaddr
;
1044 report(LOG_INFO
, "sending reply to gateway %s",
1048 dst
= bp
->bp_yiaddr
;
1051 if (len
> MAXHADDRLEN
)
1053 haf
= (int) bp
->bp_htype
;
1055 haf
= HTYPE_ETHERNET
;
1058 report(LOG_INFO
, "setarp %s - %s",
1059 inet_ntoa(dst
), haddrtoa(ha
, len
));
1060 setarp(s
, &dst
, haf
, ha
, len
);
1063 if ((forward
== 0) &&
1064 (bp
->bp_siaddr
.s_addr
== 0))
1067 struct in_addr siaddr
;
1069 * If we are originating this reply, we
1070 * need to find our own interface address to
1071 * put in the bp_siaddr field of the reply.
1072 * If this server is multi-homed, pick the
1073 * 'best' interface (the one on the same net
1074 * as the client). Of course, the client may
1075 * be on the other side of a BOOTP gateway...
1077 ifr
= getif(s
, &dst
);
1079 struct sockaddr_in
*sip
;
1080 sip
= (struct sockaddr_in
*) &(ifr
->ifr_addr
);
1081 siaddr
= sip
->sin_addr
;
1083 /* Just use my "official" IP address. */
1084 siaddr
= my_ip_addr
;
1087 /* XXX - No need to set bp_giaddr here. */
1089 /* Finally, set the server address field. */
1090 bp
->bp_siaddr
= siaddr
;
1092 /* Set up socket address for send. */
1093 send_addr
.sin_family
= AF_INET
;
1094 send_addr
.sin_port
= htons(port
);
1095 send_addr
.sin_addr
= dst
;
1097 /* Send reply with same size packet as request used. */
1098 if (sendto(s
, pktbuf
, pktlen
, 0,
1099 (struct sockaddr
*) &send_addr
,
1100 sizeof(send_addr
)) < 0)
1102 report(LOG_ERR
, "sendto: %s", get_network_errmsg());
1107 /* nmatch() - now in getif.c */
1108 /* setarp() - now in hwaddr.c */
1112 * This call checks read access to a file. It returns 0 if the file given
1113 * by "path" exists and is publically readable. A value of -1 is returned if
1114 * access is not permitted or an error occurs. Successful calls also
1115 * return the file size in bytes using the long pointer "filesize".
1117 * The read permission bit for "other" users is checked. This bit must be
1118 * set for tftpd(8) to allow clients to read the file.
1122 chk_access(char *path
, int32
*filesize
)
1126 if ((stat(path
, &st
) == 0) && (st
.st_mode
& (S_IREAD
>> 6))) {
1127 *filesize
= (int32
) st
.st_size
;
1136 * Now in dumptab.c :
1139 * list_ipaddresses()
1145 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1146 * bootp packet pointed to by "bp".
1150 dovend_cmu(struct bootp
*bp
, struct host
*hp
)
1152 struct cmu_vend
*vendp
;
1153 struct in_addr_list
*taddr
;
1156 * Initialize the entire vendor field to zeroes.
1158 bzero(bp
->bp_vend
, sizeof(bp
->bp_vend
));
1161 * Fill in vendor information. Subnet mask, default gateway,
1162 * domain name server, ien name server, time server
1164 vendp
= (struct cmu_vend
*) bp
->bp_vend
;
1165 strcpy(vendp
->v_magic
, (char *)vm_cmu
);
1166 if (hp
->flags
.subnet_mask
) {
1167 (vendp
->v_smask
).s_addr
= hp
->subnet_mask
.s_addr
;
1168 (vendp
->v_flags
) |= VF_SMASK
;
1169 if (hp
->flags
.gateway
) {
1170 (vendp
->v_dgate
).s_addr
= hp
->gateway
->addr
->s_addr
;
1173 if (hp
->flags
.domain_server
) {
1174 taddr
= hp
->domain_server
;
1175 if (taddr
->addrcount
> 0) {
1176 (vendp
->v_dns1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1177 if (taddr
->addrcount
> 1) {
1178 (vendp
->v_dns2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1182 if (hp
->flags
.name_server
) {
1183 taddr
= hp
->name_server
;
1184 if (taddr
->addrcount
> 0) {
1185 (vendp
->v_ins1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1186 if (taddr
->addrcount
> 1) {
1187 (vendp
->v_ins2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1191 if (hp
->flags
.time_server
) {
1192 taddr
= hp
->time_server
;
1193 if (taddr
->addrcount
> 0) {
1194 (vendp
->v_ts1
).s_addr
= (taddr
->addr
)[0].s_addr
;
1195 if (taddr
->addrcount
> 1) {
1196 (vendp
->v_ts2
).s_addr
= (taddr
->addr
)[1].s_addr
;
1200 /* Log message now done by caller. */
1203 #endif /* VEND_CMU */
1208 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1209 * bootp packet pointed to by "bp".
1211 #define NEED(LEN, MSG) do \
1212 if (bytesleft < (LEN)) { \
1213 report(LOG_NOTICE, noroom, \
1214 hp->hostname->string, MSG); \
1218 dovend_rfc1048(struct bootp
*bp
, struct host
*hp
, int32 bootsize
)
1223 static const char noroom
[] = "%s: No room for \"%s\" option";
1227 if (hp
->flags
.msg_size
) {
1228 pktlen
= hp
->msg_size
;
1231 * If the request was longer than the official length, build
1232 * a response of that same length where the additional length
1233 * is assumed to be part of the bp_vend (options) area.
1235 if (pktlen
> sizeof(*bp
)) {
1237 report(LOG_INFO
, "request message length=%d", pktlen
);
1240 * Check whether the request contains the option:
1241 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1242 * and if so, override the response length with its value.
1243 * This request must lie within the first BP_VEND_LEN
1244 * bytes of the option space.
1252 ep
= p
+ BP_VEND_LEN
- 4;
1255 /* Check for tags with no data first. */
1260 /* Now scan the length byte. */
1265 bcopy(p
, (char*)&msgsz
, 2);
1266 msgsz
= ntohs(msgsz
);
1269 case TAG_SUBNET_MASK
:
1270 /* XXX - Should preserve this if given... */
1276 if (msgsz
> sizeof(*bp
) + BP_MSG_OVERHEAD
) {
1278 report(LOG_INFO
, "request has DHCP msglen=%d", msgsz
);
1279 pktlen
= msgsz
- BP_MSG_OVERHEAD
;
1284 if (pktlen
< sizeof(*bp
)) {
1285 report(LOG_ERR
, "invalid response length=%d", pktlen
);
1286 pktlen
= sizeof(*bp
);
1288 bytesleft
= ((byte
*)bp
+ pktlen
) - vp
;
1289 if (pktlen
> sizeof(*bp
)) {
1291 report(LOG_INFO
, "extended reply, length=%d, options=%d",
1295 /* Copy in the magic cookie */
1296 bcopy(vm_rfc1048
, vp
, 4);
1300 if (hp
->flags
.subnet_mask
) {
1301 /* always enough room here. */
1302 *vp
++ = TAG_SUBNET_MASK
;/* -1 byte */
1303 *vp
++ = 4; /* -1 byte */
1304 insert_u_long(hp
->subnet_mask
.s_addr
, &vp
); /* -4 bytes */
1305 bytesleft
-= 6; /* Fix real count */
1306 if (hp
->flags
.gateway
) {
1307 (void) insert_ip(TAG_GATEWAY
,
1312 if (hp
->flags
.bootsize
) {
1313 /* always enough room here */
1314 bootsize
= (hp
->flags
.bootsize_auto
) ?
1315 ((bootsize
+ 511) / 512) : (hp
->bootsize
); /* Round up */
1316 *vp
++ = TAG_BOOT_SIZE
;
1318 *vp
++ = (byte
) ((bootsize
>> 8) & 0xFF);
1319 *vp
++ = (byte
) (bootsize
& 0xFF);
1320 bytesleft
-= 4; /* Tag, length, and 16 bit blocksize */
1323 * This one is special: Remaining options go in the ext file.
1324 * Only the subnet_mask, bootsize, and gateway should precede.
1326 if (hp
->flags
.exten_file
) {
1328 * Check for room for exten_file. Add 3 to account for
1329 * TAG_EXTEN_FILE, length, and TAG_END.
1331 len
= strlen(hp
->exten_file
->string
);
1332 NEED((len
+ 3), "ef");
1333 *vp
++ = TAG_EXTEN_FILE
;
1334 *vp
++ = (byte
) (len
& 0xFF);
1335 bcopy(hp
->exten_file
->string
, vp
, len
);
1338 bytesleft
-= len
+ 3;
1339 return; /* no more options here. */
1342 * The remaining options are inserted by the following
1343 * function (which is shared with bootpef.c).
1344 * Keep back one byte for the TAG_END.
1346 len
= dovend_rfc1497(hp
, vp
, bytesleft
- 1);
1350 /* There should be at least one byte left. */
1355 /* Log message done by caller. */
1356 if (bytesleft
> 0) {
1358 * Zero out any remaining part of the vendor area.
1360 bzero(vp
, bytesleft
);
1362 } /* dovend_rfc1048 */
1367 * Now in readfile.c:
1372 /* haddrtoa() - now in hwaddr.c */
1380 /* get_errmsg() - now in report.c */
1386 * c-argdecl-indent: 4
1387 * c-continued-statement-offset: 4
1388 * c-continued-brace-offset: -4
1389 * c-label-offset: -4