bootpd.c revision 1.11 1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
3
4 All Rights Reserved
5
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.
13
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
20 SOFTWARE.
21 ************************************************************************/
22
23 #include <sys/cdefs.h>
24 #ifndef lint
25 __RCSID("$NetBSD: bootpd.c,v 1.11 1999/01/31 10:06:16 mrg Exp $");
26 #endif
27
28 /*
29 * BOOTP (bootstrap protocol) server daemon.
30 *
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
36 *
37 * HISTORY
38 * See ./Changes
39 *
40 * BUGS
41 * See ./ToDo
42 */
43
44
45
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/ioctl.h>
51 #include <sys/file.h>
52 #include <sys/time.h>
53 #include <sys/stat.h>
54
55 #include <net/if.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h> /* inet_ntoa */
58
59 #ifndef NO_UNISTD
60 #include <unistd.h>
61 #endif
62 #include <stdlib.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <string.h>
66 #include <errno.h>
67 #include <ctype.h>
68 #include <netdb.h>
69 #include <syslog.h>
70 #include <assert.h>
71
72 #ifdef NO_SETSID
73 # include <fcntl.h> /* for O_RDONLY, etc */
74 #endif
75
76 #ifdef SVR4
77 /* Using sigset() avoids the need to re-arm each time. */
78 #define signal sigset
79 #endif
80
81 #ifndef USE_BFUNCS
82 # include <memory.h>
83 /* Yes, memcpy is OK here (no overlapped copies). */
84 # define bcopy(a,b,c) memcpy(b,a,c)
85 # define bzero(p,l) memset(p,0,l)
86 # define bcmp(a,b,c) memcmp(a,b,c)
87 #endif
88
89 #include "bootp.h"
90 #include "hash.h"
91 #include "hwaddr.h"
92 #include "bootpd.h"
93 #include "dovend.h"
94 #include "getif.h"
95 #include "readfile.h"
96 #include "report.h"
97 #include "tzone.h"
98 #include "patchlevel.h"
99
100 #ifndef CONFIG_FILE
101 #define CONFIG_FILE "/etc/bootptab"
102 #endif
103 #ifndef DUMPTAB_FILE
104 #define DUMPTAB_FILE "/tmp/bootpd.dump"
105 #endif
106
107
108
110 /*
111 * Externals, forward declarations, and global variables
112 */
113
114 #ifdef __STDC__
115 #define P(args) args
116 #else
117 #define P(args) ()
118 #endif
119
120 extern void dumptab P((char *));
121
122 PRIVATE void catcher P((int));
123 PRIVATE int chk_access P((char *, int32 *));
124 #ifdef VEND_CMU
125 PRIVATE void dovend_cmu P((struct bootp *, struct host *));
126 #endif
127 PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
128 PRIVATE void handle_reply P((void));
129 PRIVATE void handle_request P((void));
130 PRIVATE void sendreply P((int forward, int32 dest_override));
131 PRIVATE void usage P((void));
132 int main P((int, char **));
133
134 #undef P
135
136 /*
137 * IP port numbers for client and server obtained from /etc/services
138 */
139
140 u_short bootps_port, bootpc_port;
141
142
143 /*
144 * Internet socket and interface config structures
145 */
146
147 struct sockaddr_in bind_addr; /* Listening */
148 struct sockaddr_in recv_addr; /* Packet source */
149 struct sockaddr_in send_addr; /* destination */
150
151
152 /*
153 * option defaults
154 */
155 int debug = 0; /* Debugging flag (level) */
156 struct timeval actualtimeout =
157 { /* fifteen minutes */
158 15 * 60L, /* tv_sec */
159 0 /* tv_usec */
160 };
161
162 /*
163 * General
164 */
165
166 int s; /* Socket file descriptor */
167 char *pktbuf; /* Receive packet buffer */
168 int pktlen;
169 char *progname;
170 char *chdir_path;
171 char hostname[MAXHOSTNAMELEN + 1]; /* System host name */
172 struct in_addr my_ip_addr;
173
174 /* Flags set by signal catcher. */
175 PRIVATE int do_readtab = 0;
176 PRIVATE int do_dumptab = 0;
177
178 /*
179 * Globals below are associated with the bootp database file (bootptab).
180 */
181
182 char *bootptab = CONFIG_FILE;
183 char *bootpd_dump = DUMPTAB_FILE;
184
185
186
188 /*
189 * Initialization such as command-line processing is done and then the
190 * main server loop is started.
191 */
192
193 int
194 main(argc, argv)
195 int argc;
196 char **argv;
197 {
198 struct timeval *timeout;
199 struct bootp *bp;
200 struct servent *servp;
201 struct hostent *hep;
202 char *stmp;
203 int n, ba_len, ra_len;
204 int nfound, readfds;
205 int standalone;
206
207 progname = strrchr(argv[0], '/');
208 if (progname)
209 progname++;
210 else
211 progname = argv[0];
212
213 /*
214 * Initialize logging.
215 */
216 report_init(0); /* uses progname */
217
218 /*
219 * Log startup
220 */
221 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
222
223 /* Debugging for compilers with struct padding. */
224 assert(sizeof(struct bootp) == BP_MINPKTSZ);
225
226 /* Get space for receiving packets and composing replies. */
227 pktbuf = malloc(MAX_MSG_SIZE);
228 if (!pktbuf) {
229 report(LOG_ERR, "malloc failed");
230 exit(1);
231 }
232 bp = (struct bootp *) pktbuf;
233
234 /*
235 * Check to see if a socket was passed to us from inetd.
236 *
237 * Use getsockname() to determine if descriptor 0 is indeed a socket
238 * (and thus we are probably a child of inetd) or if it is instead
239 * something else and we are running standalone.
240 */
241 s = 0;
242 ba_len = sizeof(bind_addr);
243 bzero((char *) &bind_addr, ba_len);
244 errno = 0;
245 standalone = TRUE;
246 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
247 /*
248 * Descriptor 0 is a socket. Assume we are a child of inetd.
249 */
250 if (bind_addr.sin_family == AF_INET) {
251 standalone = FALSE;
252 bootps_port = ntohs(bind_addr.sin_port);
253 } else {
254 /* Some other type of socket? */
255 report(LOG_ERR, "getsockname: not an INET socket");
256 }
257 }
258
259 /*
260 * Set defaults that might be changed by option switches.
261 */
262 stmp = NULL;
263 timeout = &actualtimeout;
264
265 /*
266 * Read switches.
267 */
268 for (argc--, argv++; argc > 0; argc--, argv++) {
269 if (argv[0][0] != '-')
270 break;
271 switch (argv[0][1]) {
272
273 case 'c': /* chdir_path */
274 if (argv[0][2]) {
275 stmp = &(argv[0][2]);
276 } else {
277 argc--;
278 argv++;
279 stmp = argv[0];
280 }
281 if (!stmp || (stmp[0] != '/')) {
282 fprintf(stderr,
283 "bootpd: invalid chdir specification\n");
284 break;
285 }
286 chdir_path = stmp;
287 break;
288
289 case 'd': /* debug level */
290 if (argv[0][2]) {
291 stmp = &(argv[0][2]);
292 } else if (argv[1] && argv[1][0] == '-') {
293 /*
294 * Backwards-compatible behavior:
295 * no parameter, so just increment the debug flag.
296 */
297 debug++;
298 break;
299 } else {
300 argc--;
301 argv++;
302 stmp = argv[0];
303 }
304 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
305 fprintf(stderr,
306 "%s: invalid debug level\n", progname);
307 break;
308 }
309 debug = n;
310 break;
311
312 case 'h': /* override hostname */
313 if (argv[0][2]) {
314 stmp = &(argv[0][2]);
315 } else {
316 argc--;
317 argv++;
318 stmp = argv[0];
319 }
320 if (!stmp) {
321 fprintf(stderr,
322 "bootpd: missing hostname\n");
323 break;
324 }
325 strncpy(hostname, stmp, sizeof(hostname)-1);
326 break;
327
328 case 'i': /* inetd mode */
329 standalone = FALSE;
330 break;
331
332 case 's': /* standalone mode */
333 standalone = TRUE;
334 break;
335
336 case 't': /* timeout */
337 if (argv[0][2]) {
338 stmp = &(argv[0][2]);
339 } else {
340 argc--;
341 argv++;
342 stmp = argv[0];
343 }
344 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
345 fprintf(stderr,
346 "%s: invalid timeout specification\n", progname);
347 break;
348 }
349 actualtimeout.tv_sec = (int32) (60 * n);
350 /*
351 * If the actual timeout is zero, pass a NULL pointer
352 * to select so it blocks indefinitely, otherwise,
353 * point to the actual timeout value.
354 */
355 timeout = (n > 0) ? &actualtimeout : NULL;
356 break;
357
358 default:
359 fprintf(stderr, "%s: unknown switch: -%c\n",
360 progname, argv[0][1]);
361 usage();
362 break;
363
364 } /* switch */
365 } /* for args */
366
367 /*
368 * Override default file names if specified on the command line.
369 */
370 if (argc > 0)
371 bootptab = argv[0];
372
373 if (argc > 1)
374 bootpd_dump = argv[1];
375
376 /*
377 * Get my hostname and IP address.
378 */
379 if (hostname[0] == '\0') {
380 if (gethostname(hostname, sizeof(hostname)) == -1) {
381 fprintf(stderr, "bootpd: can't get hostname\n");
382 exit(1);
383 }
384 hostname[sizeof(hostname) - 1] = '\0';
385 }
386 hep = gethostbyname(hostname);
387 if (!hep) {
388 fprintf(stderr, "Can not get my IP address\n");
389 exit(1);
390 }
391 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
392
393 if (standalone) {
394 /*
395 * Go into background and disassociate from controlling terminal.
396 */
397 if (debug < 3) {
398 if (fork())
399 exit(0);
400 #ifdef NO_SETSID
401 setpgrp(0,0);
402 #ifdef TIOCNOTTY
403 n = open("/dev/tty", O_RDWR);
404 if (n >= 0) {
405 ioctl(n, TIOCNOTTY, (char *) 0);
406 (void) close(n);
407 }
408 #endif /* TIOCNOTTY */
409 #else /* SETSID */
410 if (setsid() < 0)
411 perror("setsid");
412 #endif /* SETSID */
413 } /* if debug < 3 */
414
415 /*
416 * Nuke any timeout value
417 */
418 timeout = NULL;
419
420 } /* if standalone (1st) */
421
422 /* Set the cwd (i.e. to /tftpboot) */
423 if (chdir_path) {
424 if (chdir(chdir_path) < 0)
425 report(LOG_ERR, "%s: chdir failed", chdir_path);
426 }
427
428 /* Get the timezone. */
429 tzone_init();
430
431 /* Allocate hash tables. */
432 rdtab_init();
433
434 /*
435 * Read the bootptab file.
436 */
437 readtab(1); /* force read */
438
439 if (standalone) {
440
441 /*
442 * Create a socket.
443 */
444 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
445 report(LOG_ERR, "socket: %s", get_network_errmsg());
446 exit(1);
447 }
448
449 /*
450 * Get server's listening port number
451 */
452 servp = getservbyname("bootps", "udp");
453 if (servp) {
454 bootps_port = ntohs((u_short) servp->s_port);
455 } else {
456 bootps_port = (u_short) IPPORT_BOOTPS;
457 report(LOG_ERR,
458 "udp/bootps: unknown service -- assuming port %d",
459 bootps_port);
460 }
461
462 /*
463 * Bind socket to BOOTPS port.
464 */
465 bind_addr.sin_family = AF_INET;
466 bind_addr.sin_addr.s_addr = INADDR_ANY;
467 bind_addr.sin_port = htons(bootps_port);
468 if (bind(s, (struct sockaddr *) &bind_addr,
469 sizeof(bind_addr)) < 0)
470 {
471 report(LOG_ERR, "bind: %s", get_network_errmsg());
472 exit(1);
473 }
474 } /* if standalone (2nd)*/
475
476 /*
477 * Get destination port number so we can reply to client
478 */
479 servp = getservbyname("bootpc", "udp");
480 if (servp) {
481 bootpc_port = ntohs(servp->s_port);
482 } else {
483 report(LOG_ERR,
484 "udp/bootpc: unknown service -- assuming port %d",
485 IPPORT_BOOTPC);
486 bootpc_port = (u_short) IPPORT_BOOTPC;
487 }
488
489 /*
490 * Set up signals to read or dump the table.
491 */
492 if ((long) signal(SIGHUP, catcher) < 0) {
493 report(LOG_ERR, "signal: %s", get_errmsg());
494 exit(1);
495 }
496 if ((long) signal(SIGUSR1, catcher) < 0) {
497 report(LOG_ERR, "signal: %s", get_errmsg());
498 exit(1);
499 }
500
501 /*
502 * Process incoming requests.
503 */
504 for (;;) {
505 readfds = 1 << s;
506 nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
507 if (nfound < 0) {
508 if (errno != EINTR) {
509 report(LOG_ERR, "select: %s", get_errmsg());
510 }
511 /*
512 * Call readtab() or dumptab() here to avoid the
513 * dangers of doing I/O from a signal handler.
514 */
515 if (do_readtab) {
516 do_readtab = 0;
517 readtab(1); /* force read */
518 }
519 if (do_dumptab) {
520 do_dumptab = 0;
521 dumptab(bootpd_dump);
522 }
523 continue;
524 }
525 if (!(readfds & (1 << s))) {
526 if (debug > 1)
527 report(LOG_INFO, "exiting after %ld minutes of inactivity",
528 actualtimeout.tv_sec / 60);
529 exit(0);
530 }
531 ra_len = sizeof(recv_addr);
532 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
533 (struct sockaddr *) &recv_addr, &ra_len);
534 if (n <= 0) {
535 continue;
536 }
537 if (debug > 1) {
538 report(LOG_INFO, "recvd pkt from IP addr %s",
539 inet_ntoa(recv_addr.sin_addr));
540 }
541 if (n < sizeof(struct bootp)) {
542 if (debug) {
543 report(LOG_INFO, "received short packet");
544 }
545 continue;
546 }
547 pktlen = n;
548
549 readtab(0); /* maybe re-read bootptab */
550
551 switch (bp->bp_op) {
552 case BOOTREQUEST:
553 handle_request();
554 break;
555 case BOOTREPLY:
556 handle_reply();
557 break;
558 }
559 }
560 }
561
562
563
565
566 /*
567 * Print "usage" message and exit
568 */
569
570 PRIVATE void
571 usage()
572 {
573 fprintf(stderr,
574 "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
575 fprintf(stderr, "\t -c n\tset current directory\n");
576 fprintf(stderr, "\t -d n\tset debug level\n");
577 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
578 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
579 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
580 exit(1);
581 }
582
583 /* Signal catchers */
584 PRIVATE void
585 catcher(sig)
586 int sig;
587 {
588 if (sig == SIGHUP)
589 do_readtab = 1;
590 if (sig == SIGUSR1)
591 do_dumptab = 1;
592 #ifdef SYSV
593 /* For older "System V" derivatives with no sigset(). */
594 /* XXX - Should just do it the POSIX way (sigaction). */
595 signal(sig, catcher);
596 #endif
597 }
598
599
600
602 /*
603 * Process BOOTREQUEST packet.
604 *
605 * Note: This version of the bootpd.c server never forwards
606 * a request to another server. That is the job of a gateway
607 * program such as the "bootpgw" program included here.
608 *
609 * (Also this version does not interpret the hostname field of
610 * the request packet; it COULD do a name->address lookup and
611 * forward the request there.)
612 */
613 PRIVATE void
614 handle_request()
615 {
616 struct bootp *bp = (struct bootp *) pktbuf;
617 struct host *hp = NULL;
618 struct host dummyhost;
619 int32 bootsize = 0;
620 unsigned hlen, hashcode;
621 int32 dest;
622 char realpath[1024];
623 char *clntpath;
624 char *homedir, *bootfile;
625 int n;
626
627 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
628
629 /*
630 * If the servername field is set, compare it against us.
631 * If we're not being addressed, ignore this request.
632 * If the server name field is null, throw in our name.
633 */
634 if (strlen(bp->bp_sname)) {
635 if (strcmp(bp->bp_sname, hostname)) {
636 if (debug)
637 report(LOG_INFO, "\
638 ignoring request for server %s from client at %s address %s",
639 bp->bp_sname, netname(bp->bp_htype),
640 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
641 /* XXX - Is it correct to ignore such a request? -gwr */
642 return;
643 }
644 } else {
645 strcpy(bp->bp_sname, hostname);
646 }
647
648 /* If it uses an unknown network type, ignore the request. */
649 if (bp->bp_htype >= hwinfocnt) {
650 if (debug)
651 report(LOG_INFO,
652 "Request with unknown network type %u",
653 bp->bp_htype);
654 return;
655 }
656
657 /* Convert the request into a reply. */
658 bp->bp_op = BOOTREPLY;
659 if (bp->bp_ciaddr.s_addr == 0) {
660 /*
661 * client doesnt know his IP address,
662 * search by hardware address.
663 */
664 if (debug > 1) {
665 report(LOG_INFO, "request from %s address %s",
666 netname(bp->bp_htype),
667 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
668 }
669 hlen = haddrlength(bp->bp_htype);
670 if (hlen != bp->bp_hlen) {
671 report(LOG_NOTICE, "bad addr len from %s address %s",
672 netname(bp->bp_htype),
673 haddrtoa(bp->bp_chaddr, hlen));
674 }
675 dummyhost.htype = bp->bp_htype;
676 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
677 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
678 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
679 &dummyhost);
680 if (hp == NULL &&
681 bp->bp_htype == HTYPE_IEEE802)
682 {
683 /* Try again with address in "canonical" form. */
684 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
685 if (debug > 1) {
686 report(LOG_INFO, "\
687 HW addr type is IEEE 802. convert to %s and check again\n",
688 haddrtoa(dummyhost.haddr, bp->bp_hlen));
689 }
690 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
691 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
692 hwlookcmp, &dummyhost);
693 }
694 if (hp == NULL) {
695 /*
696 * XXX - Add dynamic IP address assignment?
697 */
698 if (debug > 1)
699 report(LOG_INFO, "unknown client %s address %s",
700 netname(bp->bp_htype),
701 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
702 return; /* not found */
703 }
704 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
705
706 } else {
707
708 /*
709 * search by IP address.
710 */
711 if (debug > 1) {
712 report(LOG_INFO, "request from IP addr %s",
713 inet_ntoa(bp->bp_ciaddr));
714 }
715 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
716 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
717 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
718 &dummyhost);
719 if (hp == NULL) {
720 if (debug > 1) {
721 report(LOG_NOTICE, "IP address not found: %s",
722 inet_ntoa(bp->bp_ciaddr));
723 }
724 return;
725 }
726 }
727
728 if (debug) {
729 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
730 hp->hostname->string);
731 }
732
733 /*
734 * If there is a response delay threshold, ignore requests
735 * with a timestamp lower than the threshold.
736 */
737 if (hp->flags.min_wait) {
738 u_int32 t = (u_int32) ntohs(bp->bp_secs);
739 if (t < hp->min_wait) {
740 if (debug > 1)
741 report(LOG_INFO,
742 "ignoring request due to timestamp (%d < %d)",
743 t, hp->min_wait);
744 return;
745 }
746 }
747
748 #ifdef YORK_EX_OPTION
749 /*
750 * The need for the "ex" tag arose out of the need to empty
751 * shared networked drives on diskless PCs. This solution is
752 * not very clean but it does work fairly well.
753 * Written by Edmund J. Sutcliffe <edmund (at) york.ac.uk>
754 *
755 * XXX - This could compromise security if a non-trusted user
756 * managed to write an entry in the bootptab with :ex=trojan:
757 * so I would leave this turned off unless you need it. -gwr
758 */
759 /* Run a program, passing the client name as a parameter. */
760 if (hp->flags.exec_file) {
761 char tst[100];
762 /* XXX - Check string lengths? -gwr */
763 strcpy (tst, hp->exec_file->string);
764 strcat (tst, " ");
765 strcat (tst, hp->hostname->string);
766 strcat (tst, " &");
767 if (debug)
768 report(LOG_INFO, "executing %s", tst);
769 system(tst); /* Hope this finishes soon... */
770 }
771 #endif /* YORK_EX_OPTION */
772
773 /*
774 * If a specific TFTP server address was specified in the bootptab file,
775 * fill it in, otherwise zero it.
776 * XXX - Rather than zero it, should it be the bootpd address? -gwr
777 */
778 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
779 hp->bootserver.s_addr : 0L;
780
781 #ifdef STANFORD_PROM_COMPAT
782 /*
783 * Stanford bootp PROMs (for a Sun?) have no way to leave
784 * the boot file name field blank (because the boot file
785 * name is automatically generated from some index).
786 * As a work-around, this little hack allows those PROMs to
787 * specify "sunboot14" with the same effect as a NULL name.
788 * (The user specifies boot device 14 or some such magic.)
789 */
790 if (strcmp(bp->bp_file, "sunboot14") == 0)
791 bp->bp_file[0] = '\0'; /* treat it as unspecified */
792 #endif
793
794 /*
795 * Fill in the client's proper bootfile.
796 *
797 * If the client specifies an absolute path, try that file with a
798 * ".host" suffix and then without. If the file cannot be found, no
799 * reply is made at all.
800 *
801 * If the client specifies a null or relative file, use the following
802 * table to determine the appropriate action:
803 *
804 * Homedir Bootfile Client's file
805 * specified? specified? specification Action
806 * -------------------------------------------------------------------
807 * No No Null Send null filename
808 * No No Relative Discard request
809 * No Yes Null Send if absolute else null
810 * No Yes Relative Discard request *XXX
811 * Yes No Null Send null filename
812 * Yes No Relative Lookup with ".host"
813 * Yes Yes Null Send home/boot or bootfile
814 * Yes Yes Relative Lookup with ".host" *XXX
815 *
816 */
817
818 /*
819 * XXX - I don't like the policy of ignoring a client when the
820 * boot file is not accessible. The TFTP server might not be
821 * running on the same machine as the BOOTP server, in which
822 * case checking accessibility of the boot file is pointless.
823 *
824 * Therefore, file accessibility is now demanded ONLY if you
825 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
826 */
827
828 /*
829 * The "real" path is as seen by the BOOTP daemon on this
830 * machine, while the client path is relative to the TFTP
831 * daemon chroot directory (i.e. /tftpboot).
832 */
833 if (hp->flags.tftpdir) {
834 strncpy(realpath, hp->tftpdir->string, sizeof(realpath) - 1);
835 realpath[sizeof(realpath) - 1] = '\0';
836 clntpath = &realpath[strlen(realpath)];
837 } else {
838 realpath[0] = '\0';
839 clntpath = realpath;
840 }
841
842 /*
843 * Determine client's requested homedir and bootfile.
844 */
845 homedir = NULL;
846 bootfile = NULL;
847 if (bp->bp_file[0]) {
848 char *t;
849
850 homedir = bp->bp_file;
851
852 /* make sure that the file is nul terminated */
853 for (t = homedir; t - homedir < BP_FILE_LEN; t++)
854 if (*t == '\0')
855 break;
856 if (t - homedir < BP_FILE_LEN) {
857 report(LOG_INFO, "requested path length > BP_FILE_LEN file = \"%s\", nul terminating", homedir;
858 homedir[BP_FILE_LEN - 1] = '\0';
859 }
860
861 bootfile = strrchr(homedir, '/');
862 if (bootfile) {
863 if (homedir == bootfile)
864 homedir = NULL;
865 *bootfile++ = '\0';
866 } else {
867 /* no "/" in the string */
868 bootfile = homedir;
869 homedir = NULL;
870 }
871 if (debug > 2) {
872 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
873 (homedir) ? homedir : "",
874 (bootfile) ? bootfile : "");
875 }
876 }
877
878 /*
879 * Specifications in bootptab override client requested values.
880 */
881 if (hp->flags.homedir)
882 homedir = hp->homedir->string;
883 if (hp->flags.bootfile)
884 bootfile = hp->bootfile->string;
885
886 /*
887 * Construct bootfile path.
888 */
889 if (homedir) {
890 if (homedir[0] != '/') {
891 strncat(realpath, "/", sizeof(realpath) - 1);
892 realpath[sizeof(realpath) - 1] = '\0';
893 }
894 strncat(realpath, homedir, sizeof(realpath) - 1);
895 realpath[sizeof(realpath) - 1] = '\0';
896 homedir = NULL;
897 }
898 if (bootfile) {
899 if (bootfile[0] != '/') {
900 strcat(realpath, "/");
901 realpath[sizeof(realpath) - 1] = '\0';
902 }
903 strcat(realpath, bootfile);
904 realpath[sizeof(realpath) - 1] = '\0';
905 bootfile = NULL;
906 }
907
908 /*
909 * First try to find the file with a ".host" suffix
910 */
911 n = strlen(clntpath);
912 strcat(clntpath, ".");
913 strcat(clntpath, hp->hostname->string);
914 if (chk_access(realpath, &bootsize) < 0) {
915 clntpath[n] = 0; /* Try it without the suffix */
916 if (chk_access(realpath, &bootsize) < 0) {
917 /* neither "file.host" nor "file" was found */
918 #ifdef CHECK_FILE_ACCESS
919
920 if (bp->bp_file[0]) {
921 /*
922 * Client wanted specific file
923 * and we didn't have it.
924 */
925 report(LOG_NOTICE,
926 "requested file not found: \"%s\"", clntpath);
927 return;
928 }
929 /*
930 * Client didn't ask for a specific file and we couldn't
931 * access the default file, so just zero-out the bootfile
932 * field in the packet and continue processing the reply.
933 */
934 bzero(bp->bp_file, sizeof(bp->bp_file));
935 goto null_file_name;
936
937 #else /* CHECK_FILE_ACCESS */
938
939 /* Complain only if boot file size was needed. */
940 if (hp->flags.bootsize_auto) {
941 report(LOG_ERR, "can not determine size of file \"%s\"",
942 clntpath);
943 }
944
945 #endif /* CHECK_FILE_ACCESS */
946 }
947 }
948 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
949 if (debug > 2)
950 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
951
952 #ifdef CHECK_FILE_ACCESS
953 null_file_name:
954 #endif /* CHECK_FILE_ACCESS */
955
956
957 /*
959 * Handle vendor options based on magic number.
960 */
961
962 if (debug > 1) {
963 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
964 (int) ((bp->bp_vend)[0]),
965 (int) ((bp->bp_vend)[1]),
966 (int) ((bp->bp_vend)[2]),
967 (int) ((bp->bp_vend)[3]));
968 }
969 /*
970 * If this host isn't set for automatic vendor info then copy the
971 * specific cookie into the bootp packet, thus forcing a certain
972 * reply format. Only force reply format if user specified it.
973 */
974 if (hp->flags.vm_cookie) {
975 /* Slam in the user specified magic number. */
976 bcopy(hp->vm_cookie, bp->bp_vend, 4);
977 }
978 /*
979 * Figure out the format for the vendor-specific info.
980 * Note that bp->bp_vend may have been set above.
981 */
982 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
983 /* RFC1048 conformant bootp client */
984 dovend_rfc1048(bp, hp, bootsize);
985 if (debug > 1) {
986 report(LOG_INFO, "sending reply (with RFC1048 options)");
987 }
988 }
989 #ifdef VEND_CMU
990 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
991 dovend_cmu(bp, hp);
992 if (debug > 1) {
993 report(LOG_INFO, "sending reply (with CMU options)");
994 }
995 }
996 #endif
997 else {
998 if (debug > 1) {
999 report(LOG_INFO, "sending reply (with no options)");
1000 }
1001 }
1002
1003 dest = (hp->flags.reply_addr) ?
1004 hp->reply_addr.s_addr : 0L;
1005
1006 /* not forwarded */
1007 sendreply(0, dest);
1008 }
1009
1010
1011 /*
1012 * Process BOOTREPLY packet.
1013 */
1014 PRIVATE void
1015 handle_reply()
1016 {
1017 if (debug) {
1018 report(LOG_INFO, "processing boot reply");
1019 }
1020 /* forwarded, no destination override */
1021 sendreply(1, 0);
1022 }
1023
1024
1025 /*
1026 * Send a reply packet to the client. 'forward' flag is set if we are
1027 * not the originator of this reply packet.
1028 */
1029 PRIVATE void
1030 sendreply(forward, dst_override)
1031 int forward;
1032 int32 dst_override;
1033 {
1034 struct bootp *bp = (struct bootp *) pktbuf;
1035 struct in_addr dst;
1036 u_short port = bootpc_port;
1037 unsigned char *ha;
1038 int len;
1039
1040 /*
1041 * XXX - Should honor bp_flags "broadcast" bit here.
1042 * Temporary workaround: use the :ra=ADDR: option to
1043 * set the reply address to the broadcast address.
1044 */
1045
1046 /*
1047 * If the destination address was specified explicitly
1048 * (i.e. the broadcast address for HP compatiblity)
1049 * then send the response to that address. Otherwise,
1050 * act in accordance with RFC951:
1051 * If the client IP address is specified, use that
1052 * else if gateway IP address is specified, use that
1053 * else make a temporary arp cache entry for the client's
1054 * NEW IP/hardware address and use that.
1055 */
1056 if (dst_override) {
1057 dst.s_addr = dst_override;
1058 if (debug > 1) {
1059 report(LOG_INFO, "reply address override: %s",
1060 inet_ntoa(dst));
1061 }
1062 } else if (bp->bp_ciaddr.s_addr) {
1063 dst = bp->bp_ciaddr;
1064 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1065 dst = bp->bp_giaddr;
1066 port = bootps_port;
1067 if (debug > 1) {
1068 report(LOG_INFO, "sending reply to gateway %s",
1069 inet_ntoa(dst));
1070 }
1071 } else {
1072 dst = bp->bp_yiaddr;
1073 ha = bp->bp_chaddr;
1074 len = bp->bp_hlen;
1075 if (len > MAXHADDRLEN)
1076 len = MAXHADDRLEN;
1077
1078 if (debug > 1)
1079 report(LOG_INFO, "setarp %s - %s",
1080 inet_ntoa(dst), haddrtoa(ha, len));
1081 setarp(s, &dst, ha, len);
1082 }
1083
1084 if ((forward == 0) &&
1085 (bp->bp_siaddr.s_addr == 0))
1086 {
1087 struct ifreq *ifr;
1088 struct in_addr siaddr;
1089 /*
1090 * If we are originating this reply, we
1091 * need to find our own interface address to
1092 * put in the bp_siaddr field of the reply.
1093 * If this server is multi-homed, pick the
1094 * 'best' interface (the one on the same net
1095 * as the client). Of course, the client may
1096 * be on the other side of a BOOTP gateway...
1097 */
1098 ifr = getif(s, &dst);
1099 if (ifr) {
1100 struct sockaddr_in *sip;
1101 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1102 siaddr = sip->sin_addr;
1103 } else {
1104 /* Just use my "official" IP address. */
1105 siaddr = my_ip_addr;
1106 }
1107
1108 /* XXX - No need to set bp_giaddr here. */
1109
1110 /* Finally, set the server address field. */
1111 bp->bp_siaddr = siaddr;
1112 }
1113 /* Set up socket address for send. */
1114 send_addr.sin_family = AF_INET;
1115 send_addr.sin_port = htons(port);
1116 send_addr.sin_addr = dst;
1117
1118 /* Send reply with same size packet as request used. */
1119 if (sendto(s, pktbuf, pktlen, 0,
1120 (struct sockaddr *) &send_addr,
1121 sizeof(send_addr)) < 0)
1122 {
1123 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1124 }
1125 } /* sendreply */
1126
1127
1129 /* nmatch() - now in getif.c */
1130 /* setarp() - now in hwaddr.c */
1131
1132
1133 /*
1134 * This call checks read access to a file. It returns 0 if the file given
1135 * by "path" exists and is publically readable. A value of -1 is returned if
1136 * access is not permitted or an error occurs. Successful calls also
1137 * return the file size in bytes using the long pointer "filesize".
1138 *
1139 * The read permission bit for "other" users is checked. This bit must be
1140 * set for tftpd(8) to allow clients to read the file.
1141 */
1142
1143 PRIVATE int
1144 chk_access(path, filesize)
1145 char *path;
1146 int32 *filesize;
1147 {
1148 struct stat st;
1149
1150 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1151 *filesize = (int32) st.st_size;
1152 return 0;
1153 } else {
1154 return -1;
1155 }
1156 }
1157
1158
1160 /*
1161 * Now in dumptab.c :
1162 * dumptab()
1163 * dump_host()
1164 * list_ipaddresses()
1165 */
1166
1167 #ifdef VEND_CMU
1168
1169 /*
1170 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1171 * bootp packet pointed to by "bp".
1172 */
1173
1174 PRIVATE void
1175 dovend_cmu(bp, hp)
1176 struct bootp *bp;
1177 struct host *hp;
1178 {
1179 struct cmu_vend *vendp;
1180 struct in_addr_list *taddr;
1181
1182 /*
1183 * Initialize the entire vendor field to zeroes.
1184 */
1185 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1186
1187 /*
1188 * Fill in vendor information. Subnet mask, default gateway,
1189 * domain name server, ien name server, time server
1190 */
1191 vendp = (struct cmu_vend *) bp->bp_vend;
1192 strcpy(vendp->v_magic, (char *)vm_cmu);
1193 if (hp->flags.subnet_mask) {
1194 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1195 (vendp->v_flags) |= VF_SMASK;
1196 if (hp->flags.gateway) {
1197 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1198 }
1199 }
1200 if (hp->flags.domain_server) {
1201 taddr = hp->domain_server;
1202 if (taddr->addrcount > 0) {
1203 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1204 if (taddr->addrcount > 1) {
1205 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1206 }
1207 }
1208 }
1209 if (hp->flags.name_server) {
1210 taddr = hp->name_server;
1211 if (taddr->addrcount > 0) {
1212 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1213 if (taddr->addrcount > 1) {
1214 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1215 }
1216 }
1217 }
1218 if (hp->flags.time_server) {
1219 taddr = hp->time_server;
1220 if (taddr->addrcount > 0) {
1221 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1222 if (taddr->addrcount > 1) {
1223 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1224 }
1225 }
1226 }
1227 /* Log message now done by caller. */
1228 } /* dovend_cmu */
1229
1230 #endif /* VEND_CMU */
1231
1232
1234
1235 /*
1236 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1237 * bootp packet pointed to by "bp".
1238 */
1239 #define NEED(LEN, MSG) do \
1240 if (bytesleft < (LEN)) { \
1241 report(LOG_NOTICE, noroom, \
1242 hp->hostname->string, MSG); \
1243 return; \
1244 } while (0)
1245 PRIVATE void
1246 dovend_rfc1048(bp, hp, bootsize)
1247 struct bootp *bp;
1248 struct host *hp;
1249 int32 bootsize;
1250 {
1251 int bytesleft, len;
1252 byte *vp;
1253
1254 static char noroom[] = "%s: No room for \"%s\" option";
1255
1256 vp = bp->bp_vend;
1257
1258 if (hp->flags.msg_size) {
1259 pktlen = hp->msg_size;
1260 } else {
1261 /*
1262 * If the request was longer than the official length, build
1263 * a response of that same length where the additional length
1264 * is assumed to be part of the bp_vend (options) area.
1265 */
1266 if (pktlen > sizeof(*bp)) {
1267 if (debug > 1)
1268 report(LOG_INFO, "request message length=%d", pktlen);
1269 }
1270 /*
1271 * Check whether the request contains the option:
1272 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1273 * and if so, override the response length with its value.
1274 * This request must lie within the first BP_VEND_LEN
1275 * bytes of the option space.
1276 */
1277 {
1278 byte *p, *ep;
1279 byte tag, len;
1280 short msgsz = 0;
1281
1282 p = vp + 4;
1283 ep = p + BP_VEND_LEN - 4;
1284 while (p < ep) {
1285 tag = *p++;
1286 /* Check for tags with no data first. */
1287 if (tag == TAG_PAD)
1288 continue;
1289 if (tag == TAG_END)
1290 break;
1291 /* Now scan the length byte. */
1292 len = *p++;
1293 switch (tag) {
1294 case TAG_MAX_MSGSZ:
1295 if (len == 2) {
1296 bcopy(p, (char*)&msgsz, 2);
1297 msgsz = ntohs(msgsz);
1298 }
1299 break;
1300 case TAG_SUBNET_MASK:
1301 /* XXX - Should preserve this if given... */
1302 break;
1303 } /* swtich */
1304 p += len;
1305 }
1306
1307 if (msgsz > sizeof(*bp)) {
1308 if (debug > 1)
1309 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1310 pktlen = msgsz;
1311 }
1312 }
1313 }
1314
1315 if (pktlen < sizeof(*bp)) {
1316 report(LOG_ERR, "invalid response length=%d", pktlen);
1317 pktlen = sizeof(*bp);
1318 }
1319 bytesleft = ((byte*)bp + pktlen) - vp;
1320 if (pktlen > sizeof(*bp)) {
1321 if (debug > 1)
1322 report(LOG_INFO, "extended reply, length=%d, options=%d",
1323 pktlen, bytesleft);
1324 }
1325
1326 /* Copy in the magic cookie */
1327 bcopy(vm_rfc1048, vp, 4);
1328 vp += 4;
1329 bytesleft -= 4;
1330
1331 if (hp->flags.subnet_mask) {
1332 /* always enough room here. */
1333 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1334 *vp++ = 4; /* -1 byte */
1335 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1336 bytesleft -= 6; /* Fix real count */
1337 if (hp->flags.gateway) {
1338 (void) insert_ip(TAG_GATEWAY,
1339 hp->gateway,
1340 &vp, &bytesleft);
1341 }
1342 }
1343 if (hp->flags.bootsize) {
1344 /* always enough room here */
1345 bootsize = (hp->flags.bootsize_auto) ?
1346 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1347 *vp++ = TAG_BOOT_SIZE;
1348 *vp++ = 2;
1349 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1350 *vp++ = (byte) (bootsize & 0xFF);
1351 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1352 }
1353 /*
1354 * This one is special: Remaining options go in the ext file.
1355 * Only the subnet_mask, bootsize, and gateway should precede.
1356 */
1357 if (hp->flags.exten_file) {
1358 /*
1359 * Check for room for exten_file. Add 3 to account for
1360 * TAG_EXTEN_FILE, length, and TAG_END.
1361 */
1362 len = strlen(hp->exten_file->string);
1363 NEED((len + 3), "ef");
1364 *vp++ = TAG_EXTEN_FILE;
1365 *vp++ = (byte) (len & 0xFF);
1366 bcopy(hp->exten_file->string, vp, len);
1367 vp += len;
1368 *vp++ = TAG_END;
1369 bytesleft -= len + 3;
1370 return; /* no more options here. */
1371 }
1372 /*
1373 * The remaining options are inserted by the following
1374 * function (which is shared with bootpef.c).
1375 * Keep back one byte for the TAG_END.
1376 */
1377 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1378 vp += len;
1379 bytesleft -= len;
1380
1381 /* There should be at least one byte left. */
1382 NEED(1, "(end)");
1383 *vp++ = TAG_END;
1384 bytesleft--;
1385
1386 /* Log message done by caller. */
1387 if (bytesleft > 0) {
1388 /*
1389 * Zero out any remaining part of the vendor area.
1390 */
1391 bzero(vp, bytesleft);
1392 }
1393 } /* dovend_rfc1048 */
1394 #undef NEED
1395
1396
1398 /*
1399 * Now in readfile.c:
1400 * hwlookcmp()
1401 * iplookcmp()
1402 */
1403
1404 /* haddrtoa() - now in hwaddr.c */
1405 /*
1406 * Now in dovend.c:
1407 * insert_ip()
1408 * insert_generic()
1409 * insert_u_long()
1410 */
1411
1412 /* get_errmsg() - now in report.c */
1413
1414 /*
1415 * Local Variables:
1416 * tab-width: 4
1417 * c-indent-level: 4
1418 * c-argdecl-indent: 4
1419 * c-continued-statement-offset: 4
1420 * c-continued-brace-offset: -4
1421 * c-label-offset: -4
1422 * c-brace-offset: 0
1423 * End:
1424 */
1425