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