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