xref: /freebsd/sbin/dhclient/dhclient.c (revision 38c63b52830c85013f30bc62b2b32f3936d84e65)
1 /*	$OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright 2004 Henning Brauer <henning@openbsd.org>
7  * Copyright (c) 1995, 1996, 1997, 1998, 1999
8  * The Internet Software Consortium.    All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of The Internet Software Consortium nor the names
20  *    of its contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * This software has been written for the Internet Software Consortium
38  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
39  * Enterprises.  To learn more about the Internet Software Consortium,
40  * see ``http://www.vix.com/isc''.  To learn more about Vixie
41  * Enterprises, see ``http://www.vix.com''.
42  *
43  * This client was substantially modified and enhanced by Elliot Poger
44  * for use on Linux while he was working on the MosquitoNet project at
45  * Stanford.
46  *
47  * The current version owes much to Elliot's Linux enhancements, but
48  * was substantially reorganized and partially rewritten by Ted Lemon
49  * so as to use the same networking framework that the Internet Software
50  * Consortium DHCP server uses.   Much system-specific configuration code
51  * was moved into a shell script so that as support for more operating
52  * systems is added, it will not be necessary to port and maintain
53  * system-specific configuration code to these operating systems - instead,
54  * the shell script can invoke the native tools to accomplish the same
55  * purpose.
56  */
57 
58 #include <sys/cdefs.h>
59 #include "dhcpd.h"
60 #include "privsep.h"
61 
62 #include <sys/capsicum.h>
63 #include <sys/endian.h>
64 
65 #include <capsicum_helpers.h>
66 #include <libgen.h>
67 
68 #include <net80211/ieee80211_freebsd.h>
69 
70 
71 #ifndef _PATH_VAREMPTY
72 #define	_PATH_VAREMPTY	"/var/empty"
73 #endif
74 
75 #define	PERIOD 0x2e
76 #define	hyphenchar(c) ((c) == 0x2d)
77 #define	bslashchar(c) ((c) == 0x5c)
78 #define	periodchar(c) ((c) == PERIOD)
79 #define	asterchar(c) ((c) == 0x2a)
80 #define	alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
81 	    ((c) >= 0x61 && (c) <= 0x7a))
82 #define	digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
83 #define	whitechar(c) ((c) == ' ' || (c) == '\t')
84 
85 #define	borderchar(c) (alphachar(c) || digitchar(c))
86 #define	middlechar(c) (borderchar(c) || hyphenchar(c))
87 #define	domainchar(c) ((c) > 0x20 && (c) < 0x7f)
88 
89 #define	CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
90 
91 cap_channel_t *capsyslog;
92 
93 time_t cur_time;
94 struct timespec time_now;
95 static time_t default_lease_time = 43200; /* 12 hours... */
96 
97 const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
98 char *path_dhclient_db = NULL;
99 
100 int log_perror = 1;
101 static int privfd;
102 static int nullfd = -1;
103 
104 static char hostname[_POSIX_HOST_NAME_MAX + 1];
105 
106 static struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
107 static struct in_addr inaddr_any, inaddr_broadcast;
108 
109 static char *path_dhclient_pidfile;
110 struct pidfh *pidfile;
111 
112 /*
113  * ASSERT_STATE() does nothing now; it used to be
114  * assert (state_is == state_shouldbe).
115  */
116 #define ASSERT_STATE(state_is, state_shouldbe) {}
117 
118 /*
119  * We need to check that the expiry, renewal and rebind times are not beyond
120  * the end of time (~2038 when a 32-bit time_t is being used).
121  */
122 #define TIME_MAX        ((((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
123 
124 static struct timespec arp_timeout = { .tv_sec = 0, .tv_nsec = 250 * 1000 * 1000 };
125 static const struct timespec zero_timespec = { .tv_sec = 0, .tv_nsec = 0 };
126 int		log_priority;
127 static int		no_daemon;
128 static int		unknown_ok = 1;
129 static int		routefd;
130 
131 struct interface_info	*ifi;
132 
133 int		 findproto(char *, int);
134 struct sockaddr	*get_ifa(char *, int);
135 void		 routehandler(struct protocol *);
136 void		 usage(void);
137 int		 check_option(struct client_lease *l, int option);
138 int		 check_classless_option(unsigned char *data, int len);
139 int		 ipv4addrs(const char * buf);
140 int		 res_hnok(const char *dn);
141 int		 check_search(const char *srch);
142 const char	*option_as_string(unsigned int code, unsigned char *data, int len);
143 int		 fork_privchld(int, int);
144 
145 #define	ROUNDUP(a) \
146 	    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
147 #define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
148 
149 /* Minimum MTU is 68 as per RFC791, p. 24 */
150 #define MIN_MTU 68
151 
152 static time_t	scripttime;
153 
154 int
findproto(char * cp,int n)155 findproto(char *cp, int n)
156 {
157 	struct sockaddr *sa;
158 	unsigned i;
159 
160 	if (n == 0)
161 		return -1;
162 	for (i = 1; i; i <<= 1) {
163 		if (i & n) {
164 			sa = (struct sockaddr *)cp;
165 			switch (i) {
166 			case RTA_IFA:
167 			case RTA_DST:
168 			case RTA_GATEWAY:
169 			case RTA_NETMASK:
170 				if (sa->sa_family == AF_INET)
171 					return AF_INET;
172 				if (sa->sa_family == AF_INET6)
173 					return AF_INET6;
174 				break;
175 			case RTA_IFP:
176 				break;
177 			}
178 			ADVANCE(cp, sa);
179 		}
180 	}
181 	return (-1);
182 }
183 
184 struct sockaddr *
get_ifa(char * cp,int n)185 get_ifa(char *cp, int n)
186 {
187 	struct sockaddr *sa;
188 	unsigned i;
189 
190 	if (n == 0)
191 		return (NULL);
192 	for (i = 1; i; i <<= 1)
193 		if (i & n) {
194 			sa = (struct sockaddr *)cp;
195 			if (i == RTA_IFA)
196 				return (sa);
197 			ADVANCE(cp, sa);
198 		}
199 
200 	return (NULL);
201 }
202 
203 static struct iaddr defaddr = { .len = 4 };
204 static uint8_t curbssid[6];
205 
206 static void
disassoc(void * arg)207 disassoc(void *arg)
208 {
209 	struct interface_info *_ifi = arg;
210 
211 	/*
212 	 * Clear existing state.
213 	 */
214 	if (_ifi->client->active != NULL) {
215 		script_init("EXPIRE", NULL);
216 		script_write_params("old_",
217 		    _ifi->client->active);
218 		if (_ifi->client->alias)
219 			script_write_params("alias_",
220 				_ifi->client->alias);
221 		script_go();
222 	}
223 	_ifi->client->state = S_INIT;
224 }
225 
226 void
routehandler(struct protocol * p __unused)227 routehandler(struct protocol *p __unused)
228 {
229 	char msg[2048], *addr;
230 	struct rt_msghdr *rtm;
231 	struct if_msghdr *ifm;
232 	struct ifa_msghdr *ifam;
233 	struct if_announcemsghdr *ifan;
234 	struct ieee80211_join_event *jev;
235 	struct client_lease *l;
236 	time_t t = time(NULL);
237 	struct sockaddr_in *sa;
238 	struct iaddr a;
239 	ssize_t n;
240 	int linkstat;
241 
242 	n = read(routefd, &msg, sizeof(msg));
243 	rtm = (struct rt_msghdr *)msg;
244 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) ||
245 	    n < (ssize_t)rtm->rtm_msglen ||
246 	    rtm->rtm_version != RTM_VERSION)
247 		return;
248 
249 	switch (rtm->rtm_type) {
250 	case RTM_NEWADDR:
251 	case RTM_DELADDR:
252 		ifam = (struct ifa_msghdr *)rtm;
253 
254 		if (ifam->ifam_index != ifi->index)
255 			break;
256 		if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
257 			break;
258 		if (scripttime == 0 || t < scripttime + 10)
259 			break;
260 
261 		sa = (struct sockaddr_in*)get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
262 		if (sa == NULL)
263 			break;
264 
265 		if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
266 			error("king bula sez: len mismatch");
267 		memcpy(a.iabuf, &sa->sin_addr, a.len);
268 		if (addr_eq(a, defaddr))
269 			break;
270 
271 		for (l = ifi->client->active; l != NULL; l = l->next)
272 			if (addr_eq(a, l->address))
273 				break;
274 
275 		if (l == NULL)	/* added/deleted addr is not the one we set */
276 			break;
277 
278 		addr = inet_ntoa(sa->sin_addr);
279 		if (rtm->rtm_type == RTM_NEWADDR)  {
280 			/*
281 			 * XXX: If someone other than us adds our address,
282 			 * should we assume they are taking over from us,
283 			 * delete the lease record, and exit without modifying
284 			 * the interface?
285 			 */
286 			warning("My address (%s) was re-added", addr);
287 		} else {
288 			warning("My address (%s) was deleted, dhclient exiting",
289 			    addr);
290 			goto die;
291 		}
292 		break;
293 	case RTM_IFINFO:
294 		ifm = (struct if_msghdr *)rtm;
295 		if (ifm->ifm_index != ifi->index)
296 			break;
297 		if ((rtm->rtm_flags & RTF_UP) == 0) {
298 			warning("Interface %s is down, dhclient exiting",
299 			    ifi->name);
300 			goto die;
301 		}
302 		linkstat = interface_link_status(ifi->name);
303 		if (linkstat != ifi->linkstat) {
304 			debug("%s link state %s -> %s", ifi->name,
305 			    ifi->linkstat ? "up" : "down",
306 			    linkstat ? "up" : "down");
307 			ifi->linkstat = linkstat;
308 			if (linkstat)
309 				state_reboot(ifi);
310 		}
311 		break;
312 	case RTM_IFANNOUNCE:
313 		ifan = (struct if_announcemsghdr *)rtm;
314 		if (ifan->ifan_what == IFAN_DEPARTURE &&
315 		    ifan->ifan_index == ifi->index) {
316 			warning("Interface %s is gone, dhclient exiting",
317 			    ifi->name);
318 			goto die;
319 		}
320 		break;
321 	case RTM_IEEE80211:
322 		ifan = (struct if_announcemsghdr *)rtm;
323 		if (ifan->ifan_index != ifi->index)
324 			break;
325 		switch (ifan->ifan_what) {
326 		case RTM_IEEE80211_ASSOC:
327 		case RTM_IEEE80211_REASSOC:
328 			/*
329 			 * Use assoc/reassoc event to kick state machine
330 			 * in case we roam.  Otherwise fall back to the
331 			 * normal state machine just like a wired network.
332 			 */
333 			jev = (struct ieee80211_join_event *) &ifan[1];
334 			if (memcmp(curbssid, jev->iev_addr, 6)) {
335 				disassoc(ifi);
336 				state_reboot(ifi);
337 			}
338 			memcpy(curbssid, jev->iev_addr, 6);
339 			break;
340 		}
341 		break;
342 	default:
343 		break;
344 	}
345 	return;
346 
347 die:
348 	script_init("FAIL", NULL);
349 	if (ifi->client->alias)
350 		script_write_params("alias_", ifi->client->alias);
351 	script_go();
352 	if (pidfile != NULL)
353 		pidfile_remove(pidfile);
354 	exit(1);
355 }
356 
357 static void
init_casper(void)358 init_casper(void)
359 {
360 	cap_channel_t		*casper;
361 
362 	casper = cap_init();
363 	if (casper == NULL)
364 		error("unable to start casper");
365 
366 	capsyslog = cap_service_open(casper, "system.syslog");
367 	cap_close(casper);
368 	if (capsyslog == NULL)
369 		error("unable to open system.syslog service");
370 }
371 
372 int
main(int argc,char * argv[])373 main(int argc, char *argv[])
374 {
375 	u_int			 capmode;
376 	int			 ch, fd, quiet = 0, i = 0;
377 	int			 pipe_fd[2];
378 	int			 immediate_daemon = 0;
379 	struct passwd		*pw;
380 	pid_t			 otherpid;
381 	cap_rights_t		 rights;
382 
383 	init_casper();
384 
385 	/* Initially, log errors to stderr as well as to syslogd. */
386 	cap_openlog(capsyslog, getprogname(), LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
387 	cap_setlogmask(capsyslog, LOG_UPTO(LOG_DEBUG));
388 
389 	while ((ch = getopt(argc, argv, "bc:dl:np:qu")) != -1)
390 		switch (ch) {
391 		case 'b':
392 			immediate_daemon = 1;
393 			break;
394 		case 'c':
395 			path_dhclient_conf = optarg;
396 			break;
397 		case 'd':
398 			no_daemon = 1;
399 			break;
400 		case 'l':
401 			path_dhclient_db = optarg;
402 			break;
403 		case 'n':
404 			arp_timeout = zero_timespec;
405 			break;
406 		case 'p':
407 			path_dhclient_pidfile = optarg;
408 			break;
409 		case 'q':
410 			quiet = 1;
411 			break;
412 		case 'u':
413 			unknown_ok = 0;
414 			break;
415 		default:
416 			usage();
417 		}
418 
419 	argc -= optind;
420 	argv += optind;
421 
422 	if (argc != 1)
423 		usage();
424 
425 	if (path_dhclient_pidfile == NULL) {
426 		asprintf(&path_dhclient_pidfile,
427 		    "%s/dhclient/dhclient.%s.pid", _PATH_VARRUN, *argv);
428 		if (path_dhclient_pidfile == NULL)
429 			error("asprintf");
430 	}
431 	pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
432 	if (pidfile == NULL) {
433 		if (errno == EEXIST)
434 			error("dhclient already running, pid: %d.", otherpid);
435 		if (errno == EAGAIN)
436 			error("dhclient already running.");
437 		warning("Cannot open or create pidfile: %m");
438 	}
439 
440 	if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
441 		error("calloc");
442 	if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
443 		error("Interface name too long");
444 	if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
445 	    _PATH_DHCLIENT_DB, ifi->name) == -1)
446 		error("asprintf");
447 
448 	if (quiet)
449 		log_perror = 0;
450 
451 	tzset();
452 	clock_gettime(CLOCK_MONOTONIC, &time_now);
453 	cur_time = time_now.tv_sec;
454 
455 	inaddr_broadcast.s_addr = INADDR_BROADCAST;
456 	inaddr_any.s_addr = INADDR_ANY;
457 
458 	read_client_conf();
459 
460 	/* The next bit is potentially very time-consuming, so write out
461 	   the pidfile right away.  We will write it out again with the
462 	   correct pid after daemonizing. */
463 	if (pidfile != NULL)
464 		pidfile_write(pidfile);
465 
466 	if (!interface_link_status(ifi->name)) {
467 		fprintf(stderr, "%s: no link ...", ifi->name);
468 		fflush(stderr);
469 		sleep(1);
470 		while (!interface_link_status(ifi->name)) {
471 			fprintf(stderr, ".");
472 			fflush(stderr);
473 			if (++i > 10) {
474 				fprintf(stderr, " giving up\n");
475 				exit(1);
476 			}
477 			sleep(1);
478 		}
479 		fprintf(stderr, " got link\n");
480 	}
481 	ifi->linkstat = 1;
482 
483 	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
484 		error("cannot open %s: %m", _PATH_DEVNULL);
485 
486 	if ((pw = getpwnam("_dhcp")) == NULL) {
487 		warning("no such user: _dhcp, falling back to \"nobody\"");
488 		if ((pw = getpwnam("nobody")) == NULL)
489 			error("no such user: nobody");
490 	}
491 
492 	/*
493 	 * Obtain hostname before entering capability mode - it won't be
494 	 * possible then, as reading kern.hostname is not permitted.
495 	 */
496 	if (gethostname(hostname, sizeof(hostname)) < 0)
497 		hostname[0] = '\0';
498 
499 	priv_script_init("PREINIT", NULL);
500 	if (ifi->client->alias)
501 		priv_script_write_params("alias_", ifi->client->alias);
502 	priv_script_go();
503 
504 	/* set up the interface */
505 	discover_interfaces(ifi);
506 
507 	if (pipe(pipe_fd) == -1)
508 		error("pipe");
509 
510 	fork_privchld(pipe_fd[0], pipe_fd[1]);
511 
512 	close(ifi->ufdesc);
513 	ifi->ufdesc = -1;
514 	close(ifi->wfdesc);
515 	ifi->wfdesc = -1;
516 
517 	close(pipe_fd[0]);
518 	privfd = pipe_fd[1];
519 	cap_rights_init(&rights, CAP_READ, CAP_WRITE);
520 	if (caph_rights_limit(privfd, &rights) < 0)
521 		error("can't limit private descriptor: %m");
522 
523 	if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
524 		error("can't open and lock %s: %m", path_dhclient_db);
525 	read_client_leases();
526 	rewrite_client_leases();
527 	close(fd);
528 
529 	if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
530 		add_protocol("AF_ROUTE", routefd, routehandler, ifi);
531 	if (shutdown(routefd, SHUT_WR) < 0)
532 		error("can't shutdown route socket: %m");
533 	cap_rights_init(&rights, CAP_EVENT, CAP_READ);
534 	if (caph_rights_limit(routefd, &rights) < 0)
535 		error("can't limit route socket: %m");
536 
537 	endpwent();
538 
539 	setproctitle("%s", ifi->name);
540 
541 	/* setgroups(2) is not permitted in capability mode. */
542 	if (setgroups(1, &pw->pw_gid) != 0)
543 		error("can't restrict groups: %m");
544 
545 	if (caph_enter_casper() < 0)
546 		error("can't enter capability mode: %m");
547 
548 	/*
549 	 * If we are not in capability mode (i.e., Capsicum or libcasper is
550 	 * disabled), try to restrict filesystem access.  This will fail if
551 	 * kern.chroot_allow_open_directories is 0 or the process is jailed.
552 	 */
553 	if (cap_getmode(&capmode) < 0 || capmode == 0) {
554 		if (chroot(_PATH_VAREMPTY) == -1)
555 			error("chroot");
556 		if (chdir("/") == -1)
557 			error("chdir(\"/\")");
558 	}
559 
560 	if (setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
561 	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
562 		error("can't drop privileges: %m");
563 
564 	if (immediate_daemon)
565 		go_daemon();
566 
567 	ifi->client->state = S_INIT;
568 	state_reboot(ifi);
569 
570 	bootp_packet_handler = do_packet;
571 
572 	dispatch();
573 
574 	/* not reached */
575 	return (0);
576 }
577 
578 void
usage(void)579 usage(void)
580 {
581 
582 	fprintf(stderr, "usage: %s [-bdnqu] ", getprogname());
583 	fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
584 	exit(1);
585 }
586 
587 /*
588  * Individual States:
589  *
590  * Each routine is called from the dhclient_state_machine() in one of
591  * these conditions:
592  * -> entering INIT state
593  * -> recvpacket_flag == 0: timeout in this state
594  * -> otherwise: received a packet in this state
595  *
596  * Return conditions as handled by dhclient_state_machine():
597  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
598  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
599  * Returns 0: finish the nap which was interrupted for no good reason.
600  *
601  * Several per-interface variables are used to keep track of the process:
602  *   active_lease: the lease that is being used on the interface
603  *                 (null pointer if not configured yet).
604  *   offered_leases: leases corresponding to DHCPOFFER messages that have
605  *                   been sent to us by DHCP servers.
606  *   acked_leases: leases corresponding to DHCPACK messages that have been
607  *                 sent to us by DHCP servers.
608  *   sendpacket: DHCP packet we're trying to send.
609  *   destination: IP address to send sendpacket to
610  * In addition, there are several relevant per-lease variables.
611  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
612  * In the active lease, these control the process of renewing the lease;
613  * In leases on the acked_leases list, this simply determines when we
614  * can no longer legitimately use the lease.
615  */
616 
617 void
state_reboot(void * ipp)618 state_reboot(void *ipp)
619 {
620 	struct interface_info *ip = ipp;
621 
622 	/* If we don't remember an active lease, go straight to INIT. */
623 	if (!ip->client->active || ip->client->active->is_bootp) {
624 		state_init(ip);
625 		return;
626 	}
627 
628 	/* We are in the rebooting state. */
629 	ip->client->state = S_REBOOTING;
630 
631 	/* make_request doesn't initialize xid because it normally comes
632 	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
633 	   so pick an xid now. */
634 	ip->client->xid = arc4random();
635 
636 	/* Make a DHCPREQUEST packet, and set appropriate per-interface
637 	   flags. */
638 	make_request(ip, ip->client->active);
639 	ip->client->destination = iaddr_broadcast;
640 	ip->client->first_sending = cur_time;
641 	ip->client->interval = ip->client->config->initial_interval;
642 
643 	/* Zap the medium list... */
644 	ip->client->medium = NULL;
645 
646 	/* Send out the first DHCPREQUEST packet. */
647 	send_request(ip);
648 }
649 
650 /*
651  * Called when a lease has completely expired and we've
652  * been unable to renew it.
653  */
654 void
state_init(void * ipp)655 state_init(void *ipp)
656 {
657 	struct interface_info *ip = ipp;
658 
659 	ASSERT_STATE(state, S_INIT);
660 
661 	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
662 	   flags. */
663 	make_discover(ip, ip->client->active);
664 	ip->client->xid = ip->client->packet.xid;
665 	ip->client->destination = iaddr_broadcast;
666 	ip->client->state = S_SELECTING;
667 	ip->client->first_sending = cur_time;
668 	ip->client->interval = ip->client->config->initial_interval;
669 
670 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
671 	   to go out. */
672 	send_discover(ip);
673 }
674 
675 /*
676  * state_selecting is called when one or more DHCPOFFER packets
677  * have been received and a configurable period of time has passed.
678  */
679 void
state_selecting(void * ipp)680 state_selecting(void *ipp)
681 {
682 	struct interface_info *ip = ipp;
683 	struct client_lease *lp, *next, *picked;
684 
685 	ASSERT_STATE(state, S_SELECTING);
686 
687 	/* Cancel state_selecting and send_discover timeouts, since either
688 	   one could have got us here. */
689 	cancel_timeout(state_selecting, ip);
690 	cancel_timeout(send_discover, ip);
691 
692 	/* We have received one or more DHCPOFFER packets.   Currently,
693 	   the only criterion by which we judge leases is whether or
694 	   not we get a response when we arp for them. */
695 	picked = NULL;
696 	for (lp = ip->client->offered_leases; lp; lp = next) {
697 		next = lp->next;
698 
699 		/* Check to see if we got an ARPREPLY for the address
700 		   in this particular lease. */
701 		if (!picked) {
702 			script_init("ARPCHECK", lp->medium);
703 			script_write_params("check_", lp);
704 
705 			/* If the ARPCHECK code detects another
706 			   machine using the offered address, it exits
707 			   nonzero.  We need to send a DHCPDECLINE and
708 			   toss the lease. */
709 			if (script_go()) {
710 				make_decline(ip, lp);
711 				send_decline(ip);
712 				goto freeit;
713 			}
714 			picked = lp;
715 			picked->next = NULL;
716 		} else {
717 freeit:
718 			free_client_lease(lp);
719 		}
720 	}
721 	ip->client->offered_leases = NULL;
722 
723 	/* If we just tossed all the leases we were offered, go back
724 	   to square one. */
725 	if (!picked) {
726 		ip->client->state = S_INIT;
727 		state_init(ip);
728 		return;
729 	}
730 
731 	/* If it was a BOOTREPLY, we can just take the address right now. */
732 	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
733 		ip->client->new = picked;
734 
735 		/* Make up some lease expiry times
736 		   XXX these should be configurable. */
737 		ip->client->new->expiry = cur_time + 12000;
738 		ip->client->new->renewal += cur_time + 8000;
739 		ip->client->new->rebind += cur_time + 10000;
740 
741 		ip->client->state = S_REQUESTING;
742 
743 		/* Bind to the address we received. */
744 		bind_lease(ip);
745 		return;
746 	}
747 
748 	/* Go to the REQUESTING state. */
749 	ip->client->destination = iaddr_broadcast;
750 	ip->client->state = S_REQUESTING;
751 	ip->client->first_sending = cur_time;
752 	ip->client->interval = ip->client->config->initial_interval;
753 
754 	/* Make a DHCPREQUEST packet from the lease we picked. */
755 	make_request(ip, picked);
756 	ip->client->xid = ip->client->packet.xid;
757 
758 	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
759 	free_client_lease(picked);
760 
761 	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
762 	send_request(ip);
763 }
764 
765 /* state_requesting is called when we receive a DHCPACK message after
766    having sent out one or more DHCPREQUEST packets. */
767 
768 void
dhcpack(struct packet * packet)769 dhcpack(struct packet *packet)
770 {
771 	struct interface_info *ip = packet->interface;
772 	struct client_lease *lease;
773 
774 	/* If we're not receptive to an offer right now, or if the offer
775 	   has an unrecognizable transaction id, then just drop it. */
776 	if (packet->interface->client->xid != packet->raw->xid ||
777 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
778 	    (memcmp(packet->interface->hw_address.haddr,
779 	    packet->raw->chaddr, packet->raw->hlen)))
780 		return;
781 
782 	if (ip->client->state != S_REBOOTING &&
783 	    ip->client->state != S_REQUESTING &&
784 	    ip->client->state != S_RENEWING &&
785 	    ip->client->state != S_REBINDING)
786 		return;
787 
788 	note("DHCPACK from %s", piaddr(packet->client_addr));
789 
790 	lease = packet_to_lease(packet);
791 	if (!lease) {
792 		note("packet_to_lease failed.");
793 		return;
794 	}
795 
796 	ip->client->new = lease;
797 
798 	/* Stop resending DHCPREQUEST. */
799 	cancel_timeout(send_request, ip);
800 
801 	/* Figure out the lease time. */
802         if (ip->client->config->default_actions[DHO_DHCP_LEASE_TIME] ==
803             ACTION_SUPERSEDE)
804 		ip->client->new->expiry = getULong(
805 		    ip->client->config->defaults[DHO_DHCP_LEASE_TIME].data);
806         else if (ip->client->new->options[DHO_DHCP_LEASE_TIME].len >= 4)
807 		ip->client->new->expiry = getULong(
808 		    ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
809 	else
810 		ip->client->new->expiry = default_lease_time;
811 	/* A number that looks negative here is really just very large,
812 	   because the lease expiry offset is unsigned. Also make sure that
813            the addition of cur_time below does not overflow (a 32 bit) time_t. */
814 	if (ip->client->new->expiry < 0 ||
815             ip->client->new->expiry > TIME_MAX - cur_time)
816 		ip->client->new->expiry = TIME_MAX - cur_time;
817 	/* XXX should be fixed by resetting the client state */
818 	if (ip->client->new->expiry < 60)
819 		ip->client->new->expiry = 60;
820 
821         /* Unless overridden in the config, take the server-provided renewal
822          * time if there is one. Otherwise figure it out according to the spec.
823          * Also make sure the renewal time does not exceed the expiry time.
824          */
825         if (ip->client->config->default_actions[DHO_DHCP_RENEWAL_TIME] ==
826             ACTION_SUPERSEDE)
827 		ip->client->new->renewal = getULong(
828 		    ip->client->config->defaults[DHO_DHCP_RENEWAL_TIME].data);
829         else if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len >= 4)
830 		ip->client->new->renewal = getULong(
831 		    ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
832 	else
833 		ip->client->new->renewal = ip->client->new->expiry / 2;
834         if (ip->client->new->renewal < 0 ||
835             ip->client->new->renewal > ip->client->new->expiry / 2)
836                 ip->client->new->renewal = ip->client->new->expiry / 2;
837 
838 	/* Same deal with the rebind time. */
839         if (ip->client->config->default_actions[DHO_DHCP_REBINDING_TIME] ==
840             ACTION_SUPERSEDE)
841 		ip->client->new->rebind = getULong(
842 		    ip->client->config->defaults[DHO_DHCP_REBINDING_TIME].data);
843         else if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len >= 4)
844 		ip->client->new->rebind = getULong(
845 		    ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
846 	else
847 		ip->client->new->rebind = ip->client->new->renewal / 4 * 7;
848 	if (ip->client->new->rebind < 0 ||
849             ip->client->new->rebind > ip->client->new->renewal / 4 * 7)
850                 ip->client->new->rebind = ip->client->new->renewal / 4 * 7;
851 
852         /* Convert the time offsets into seconds-since-the-epoch */
853         ip->client->new->expiry += cur_time;
854         ip->client->new->renewal += cur_time;
855         ip->client->new->rebind += cur_time;
856 
857 	bind_lease(ip);
858 }
859 
860 void
bind_lease(struct interface_info * ip)861 bind_lease(struct interface_info *ip)
862 {
863 	struct option_data *opt;
864 
865 	/* Remember the medium. */
866 	ip->client->new->medium = ip->client->medium;
867 
868 	opt = &ip->client->new->options[DHO_INTERFACE_MTU];
869 	if (opt->len == sizeof(u_int16_t)) {
870 		u_int16_t mtu = 0;
871 		u_int16_t old_mtu = 0;
872 		bool supersede = (ip->client->config->default_actions[DHO_INTERFACE_MTU] ==
873 			ACTION_SUPERSEDE);
874 
875 		if (supersede)
876 			mtu = getUShort(ip->client->config->defaults[DHO_INTERFACE_MTU].data);
877 		else
878 			mtu = be16dec(opt->data);
879 
880 		if (ip->client->active) {
881 			opt = &ip->client->active->options[DHO_INTERFACE_MTU];
882 			if (opt->len == sizeof(u_int16_t)) {
883 				old_mtu = be16dec(opt->data);
884 			}
885 		}
886 
887 		if (mtu < MIN_MTU) {
888 			/* Treat 0 like a user intentionally doesn't want to change MTU and,
889 			 * therefore, warning is not needed */
890 			if (!supersede || mtu != 0)
891 				warning("mtu size %u < %d: ignored", (unsigned)mtu, MIN_MTU);
892 		} else if (ip->client->state != S_RENEWING || mtu != old_mtu) {
893 			interface_set_mtu_unpriv(privfd, mtu);
894 		}
895 	}
896 
897 	/* Write out the new lease. */
898 	write_client_lease(ip, ip->client->new, 0);
899 
900 	/* Run the client script with the new parameters. */
901 	script_init((ip->client->state == S_REQUESTING ? "BOUND" :
902 	    (ip->client->state == S_RENEWING ? "RENEW" :
903 	    (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
904 	    ip->client->new->medium);
905 	if (ip->client->active && ip->client->state != S_REBOOTING)
906 		script_write_params("old_", ip->client->active);
907 	script_write_params("new_", ip->client->new);
908 	if (ip->client->alias)
909 		script_write_params("alias_", ip->client->alias);
910 	script_go();
911 
912 	/* Replace the old active lease with the new one. */
913 	if (ip->client->active)
914 		free_client_lease(ip->client->active);
915 	ip->client->active = ip->client->new;
916 	ip->client->new = NULL;
917 
918 	/* Set up a timeout to start the renewal process. */
919 	add_timeout(ip->client->active->renewal, state_bound, ip);
920 
921 	note("bound to %s -- renewal in %d seconds.",
922 	    piaddr(ip->client->active->address),
923 	    (int)(ip->client->active->renewal - cur_time));
924 	ip->client->state = S_BOUND;
925 	reinitialize_interfaces();
926 	go_daemon();
927 }
928 
929 /*
930  * state_bound is called when we've successfully bound to a particular
931  * lease, but the renewal time on that lease has expired.   We are
932  * expected to unicast a DHCPREQUEST to the server that gave us our
933  * original lease.
934  */
935 void
state_bound(void * ipp)936 state_bound(void *ipp)
937 {
938 	struct interface_info *ip = ipp;
939 	u_int8_t *dp = NULL;
940 	int len;
941 
942 	ASSERT_STATE(state, S_BOUND);
943 
944 	/* T1 has expired. */
945 	make_request(ip, ip->client->active);
946 	ip->client->xid = ip->client->packet.xid;
947 
948 	if (ip->client->config->default_actions[DHO_DHCP_SERVER_IDENTIFIER] ==
949 	    ACTION_SUPERSEDE) {
950 		dp = ip->client->config->defaults[DHO_DHCP_SERVER_IDENTIFIER].data;
951 		len = ip->client->config->defaults[DHO_DHCP_SERVER_IDENTIFIER].len;
952 	} else {
953 		dp = ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].data;
954 		len = ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len;
955 	}
956 	if (len == 4) {
957 		memcpy(ip->client->destination.iabuf, dp, len);
958 		ip->client->destination.len = len;
959 	} else
960 		ip->client->destination = iaddr_broadcast;
961 
962 	ip->client->first_sending = cur_time;
963 	ip->client->interval = ip->client->config->initial_interval;
964 	ip->client->state = S_RENEWING;
965 
966 	/* Send the first packet immediately. */
967 	send_request(ip);
968 }
969 
970 void
bootp(struct packet * packet)971 bootp(struct packet *packet)
972 {
973 	struct iaddrlist *ap;
974 
975 	if (packet->raw->op != BOOTREPLY)
976 		return;
977 
978 	/* If there's a reject list, make sure this packet's sender isn't
979 	   on it. */
980 	for (ap = packet->interface->client->config->reject_list;
981 	    ap; ap = ap->next) {
982 		if (addr_eq(packet->client_addr, ap->addr)) {
983 			note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
984 			return;
985 		}
986 	}
987 	dhcpoffer(packet);
988 }
989 
990 void
dhcp(struct packet * packet)991 dhcp(struct packet *packet)
992 {
993 	struct iaddrlist *ap;
994 	void (*handler)(struct packet *);
995 	const char *type;
996 
997 	switch (packet->packet_type) {
998 	case DHCPOFFER:
999 		handler = dhcpoffer;
1000 		type = "DHCPOFFER";
1001 		break;
1002 	case DHCPNAK:
1003 		handler = dhcpnak;
1004 		type = "DHCPNACK";
1005 		break;
1006 	case DHCPACK:
1007 		handler = dhcpack;
1008 		type = "DHCPACK";
1009 		break;
1010 	default:
1011 		return;
1012 	}
1013 
1014 	/* If there's a reject list, make sure this packet's sender isn't
1015 	   on it. */
1016 	for (ap = packet->interface->client->config->reject_list;
1017 	    ap; ap = ap->next) {
1018 		if (addr_eq(packet->client_addr, ap->addr)) {
1019 			note("%s from %s rejected.", type, piaddr(ap->addr));
1020 			return;
1021 		}
1022 	}
1023 	(*handler)(packet);
1024 }
1025 
1026 void
dhcpoffer(struct packet * packet)1027 dhcpoffer(struct packet *packet)
1028 {
1029 	struct interface_info *ip = packet->interface;
1030 	struct client_lease *lease, *lp;
1031 	int i;
1032 	struct timespec arp_timeout_needed;
1033 	struct timespec stop_selecting = { .tv_sec = 0, .tv_nsec = 0 };
1034 	time_now.tv_sec = cur_time;
1035 	time_now.tv_nsec = 0;
1036 
1037 	const char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
1038 	    "DHCPOFFER" : "BOOTREPLY";
1039 
1040 	/* If we're not receptive to an offer right now, or if the offer
1041 	   has an unrecognizable transaction id, then just drop it. */
1042 	if (ip->client->state != S_SELECTING ||
1043 	    packet->interface->client->xid != packet->raw->xid ||
1044 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1045 	    (memcmp(packet->interface->hw_address.haddr,
1046 	    packet->raw->chaddr, packet->raw->hlen)))
1047 		return;
1048 
1049 	note("%s from %s", name, piaddr(packet->client_addr));
1050 
1051 	/* If this lease doesn't supply the minimum required parameters,
1052 	   blow it off. */
1053 	for (i = 0; ip->client->config->required_options[i]; i++) {
1054 		if (!packet->options[ip->client->config->
1055 		    required_options[i]].len) {
1056 			note("%s isn't satisfactory.", name);
1057 			return;
1058 		}
1059 	}
1060 
1061 	/* If we've already seen this lease, don't record it again. */
1062 	for (lease = ip->client->offered_leases;
1063 	    lease; lease = lease->next) {
1064 		if (lease->address.len == sizeof(packet->raw->yiaddr) &&
1065 		    !memcmp(lease->address.iabuf,
1066 		    &packet->raw->yiaddr, lease->address.len)) {
1067 			debug("%s already seen.", name);
1068 			return;
1069 		}
1070 	}
1071 
1072 	lease = packet_to_lease(packet);
1073 	if (!lease) {
1074 		note("packet_to_lease failed.");
1075 		return;
1076 	}
1077 
1078 	/* If this lease was acquired through a BOOTREPLY, record that
1079 	   fact. */
1080 	if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
1081 		lease->is_bootp = 1;
1082 
1083 	/* Record the medium under which this lease was offered. */
1084 	lease->medium = ip->client->medium;
1085 
1086 	/* Send out an ARP Request for the offered IP address. */
1087 	script_init("ARPSEND", lease->medium);
1088 	script_write_params("check_", lease);
1089 	/* If the script can't send an ARP request without waiting,
1090 	   we'll be waiting when we do the ARPCHECK, so don't wait now. */
1091 	if (script_go())
1092 		arp_timeout_needed = zero_timespec;
1093 
1094 	else
1095 		arp_timeout_needed = arp_timeout;
1096 
1097 	/* Figure out when we're supposed to stop selecting. */
1098 	stop_selecting.tv_sec =
1099 	    ip->client->first_sending + ip->client->config->select_interval;
1100 
1101 	/* If this is the lease we asked for, put it at the head of the
1102 	   list, and don't mess with the arp request timeout. */
1103 	if (lease->address.len == ip->client->requested_address.len &&
1104 	    !memcmp(lease->address.iabuf,
1105 	    ip->client->requested_address.iabuf,
1106 	    ip->client->requested_address.len)) {
1107 		lease->next = ip->client->offered_leases;
1108 		ip->client->offered_leases = lease;
1109 	} else {
1110 		/* If we already have an offer, and arping for this
1111 		   offer would take us past the selection timeout,
1112 		   then don't extend the timeout - just hope for the
1113 		   best. */
1114 
1115 		struct timespec interm_struct;
1116 		timespecadd(&time_now, &arp_timeout_needed, &interm_struct);
1117 
1118 		if (ip->client->offered_leases &&
1119 		    timespeccmp(&interm_struct, &stop_selecting, >))
1120 			arp_timeout_needed = zero_timespec;
1121 
1122 		/* Put the lease at the end of the list. */
1123 		lease->next = NULL;
1124 		if (!ip->client->offered_leases)
1125 			ip->client->offered_leases = lease;
1126 		else {
1127 			for (lp = ip->client->offered_leases; lp->next;
1128 			    lp = lp->next)
1129 				;	/* nothing */
1130 			lp->next = lease;
1131 		}
1132 	}
1133 
1134 	/* If we're supposed to stop selecting before we've had time
1135 	   to wait for the ARPREPLY, add some delay to wait for
1136 	   the ARPREPLY. */
1137 	struct timespec time_left;
1138 	timespecsub(&stop_selecting, &time_now, &time_left);
1139 
1140 	if (timespeccmp(&time_left, &arp_timeout_needed, <)) {
1141 		timespecadd(&time_now, &arp_timeout_needed, &stop_selecting);
1142 	}
1143 
1144 	/* If the selecting interval has expired, go immediately to
1145 	   state_selecting().  Otherwise, time out into
1146 	   state_selecting at the select interval. */
1147 
1148 
1149 	if (timespeccmp(&stop_selecting, &zero_timespec, <=))
1150 		state_selecting(ip);
1151 	else {
1152 		add_timeout_timespec(stop_selecting, state_selecting, ip);
1153 		cancel_timeout(send_discover, ip);
1154 	}
1155 }
1156 
1157 /* Allocate a client_lease structure and initialize it from the parameters
1158    in the specified packet. */
1159 
1160 struct client_lease *
packet_to_lease(struct packet * packet)1161 packet_to_lease(struct packet *packet)
1162 {
1163 	struct interface_info *ip = packet->interface;
1164 	struct client_lease *lease;
1165 	int i, j;
1166 
1167 	lease = malloc(sizeof(struct client_lease));
1168 
1169 	if (!lease) {
1170 		warning("dhcpoffer: no memory to record lease.");
1171 		return (NULL);
1172 	}
1173 
1174 	memset(lease, 0, sizeof(*lease));
1175 
1176 	/* Copy the lease options. */
1177 	for (i = 0; i < 256; i++) {
1178 		if (packet->options[i].len) {
1179 			int ignored = 0;
1180 			for (j = 0; ip->client->config->ignored_options[j]; j++)
1181 				if (i ==
1182 				    ip->client->config->ignored_options[j]) {
1183 					ignored = 1;
1184 					break;
1185 				}
1186 			if (ignored)
1187 			    continue;
1188 			lease->options[i].data =
1189 			    malloc(packet->options[i].len + 1);
1190 			if (!lease->options[i].data) {
1191 				warning("dhcpoffer: no memory for option %d", i);
1192 				free_client_lease(lease);
1193 				return (NULL);
1194 			} else {
1195 				memcpy(lease->options[i].data,
1196 				    packet->options[i].data,
1197 				    packet->options[i].len);
1198 				lease->options[i].len =
1199 				    packet->options[i].len;
1200 				lease->options[i].data[lease->options[i].len] =
1201 				    0;
1202 			}
1203 			if (!check_option(lease,i)) {
1204 				/* ignore a bogus lease offer */
1205 				warning("Invalid lease option - ignoring offer");
1206 				free_client_lease(lease);
1207 				return (NULL);
1208 			}
1209 		}
1210 	}
1211 
1212 	lease->address.len = sizeof(packet->raw->yiaddr);
1213 	memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1214 
1215 	lease->nextserver.len = sizeof(packet->raw->siaddr);
1216 	memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
1217 
1218 	/* If the server name was filled out, copy it.
1219 	   Do not attempt to validate the server name as a host name.
1220 	   RFC 2131 merely states that sname is NUL-terminated (which do
1221 	   do not assume) and that it is the server's host name.  Since
1222 	   the ISC client and server allow arbitrary characters, we do
1223 	   as well. */
1224 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1225 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1226 	    packet->raw->sname[0]) {
1227 		lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1228 		if (!lease->server_name) {
1229 			warning("dhcpoffer: no memory for server name.");
1230 			free_client_lease(lease);
1231 			return (NULL);
1232 		}
1233 		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1234 		lease->server_name[DHCP_SNAME_LEN]='\0';
1235 	}
1236 
1237 	/* Ditto for the filename. */
1238 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1239 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1240 	    packet->raw->file[0]) {
1241 		/* Don't count on the NUL terminator. */
1242 		lease->filename = malloc(DHCP_FILE_LEN + 1);
1243 		if (!lease->filename) {
1244 			warning("dhcpoffer: no memory for filename.");
1245 			free_client_lease(lease);
1246 			return (NULL);
1247 		}
1248 		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1249 		lease->filename[DHCP_FILE_LEN]='\0';
1250 	}
1251 	return lease;
1252 }
1253 
1254 void
dhcpnak(struct packet * packet)1255 dhcpnak(struct packet *packet)
1256 {
1257 	struct interface_info *ip = packet->interface;
1258 
1259 	/* If we're not receptive to an offer right now, or if the offer
1260 	   has an unrecognizable transaction id, then just drop it. */
1261 	if (packet->interface->client->xid != packet->raw->xid ||
1262 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1263 	    (memcmp(packet->interface->hw_address.haddr,
1264 	    packet->raw->chaddr, packet->raw->hlen)))
1265 		return;
1266 
1267 	if (ip->client->state != S_REBOOTING &&
1268 	    ip->client->state != S_REQUESTING &&
1269 	    ip->client->state != S_RENEWING &&
1270 	    ip->client->state != S_REBINDING)
1271 		return;
1272 
1273 	note("DHCPNAK from %s", piaddr(packet->client_addr));
1274 
1275 	if (!ip->client->active) {
1276 		note("DHCPNAK with no active lease.\n");
1277 		return;
1278 	}
1279 
1280 	free_client_lease(ip->client->active);
1281 	ip->client->active = NULL;
1282 
1283 	/* Stop sending DHCPREQUEST packets... */
1284 	cancel_timeout(send_request, ip);
1285 
1286 	ip->client->state = S_INIT;
1287 	state_init(ip);
1288 }
1289 
1290 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1291    one after the right interval has expired.  If we don't get an offer by
1292    the time we reach the panic interval, call the panic function. */
1293 
1294 void
send_discover(void * ipp)1295 send_discover(void *ipp)
1296 {
1297 	struct interface_info *ip = ipp;
1298 	int interval, increase = 1;
1299 
1300 	/* Figure out how long it's been since we started transmitting. */
1301 	interval = cur_time - ip->client->first_sending;
1302 
1303 	/* If we're past the panic timeout, call the script and tell it
1304 	   we haven't found anything for this interface yet. */
1305 	if (interval > ip->client->config->timeout) {
1306 		state_panic(ip);
1307 		return;
1308 	}
1309 
1310 	/* If we're selecting media, try the whole list before doing
1311 	   the exponential backoff, but if we've already received an
1312 	   offer, stop looping, because we obviously have it right. */
1313 	if (!ip->client->offered_leases &&
1314 	    ip->client->config->media) {
1315 		int fail = 0;
1316 again:
1317 		if (ip->client->medium) {
1318 			ip->client->medium = ip->client->medium->next;
1319 			increase = 0;
1320 		}
1321 		if (!ip->client->medium) {
1322 			if (fail)
1323 				error("No valid media types for %s!", ip->name);
1324 			ip->client->medium = ip->client->config->media;
1325 			increase = 1;
1326 		}
1327 
1328 		note("Trying medium \"%s\" %d", ip->client->medium->string,
1329 		    increase);
1330 		script_init("MEDIUM", ip->client->medium);
1331 		if (script_go())
1332 			goto again;
1333 	}
1334 
1335 	/*
1336 	 * If we're supposed to increase the interval, do so.  If it's
1337 	 * currently zero (i.e., we haven't sent any packets yet), set
1338 	 * it to one; otherwise, add to it a random number between zero
1339 	 * and two times itself.  On average, this means that it will
1340 	 * double with every transmission.
1341 	 */
1342 	if (increase) {
1343 		if (!ip->client->interval)
1344 			ip->client->interval =
1345 			    ip->client->config->initial_interval;
1346 		else {
1347 			ip->client->interval += (arc4random() >> 2) %
1348 			    (2 * ip->client->interval);
1349 		}
1350 
1351 		/* Don't backoff past cutoff. */
1352 		if (ip->client->interval >
1353 		    ip->client->config->backoff_cutoff)
1354 			ip->client->interval =
1355 				((ip->client->config->backoff_cutoff / 2)
1356 				 + ((arc4random() >> 2) %
1357 				    ip->client->config->backoff_cutoff));
1358 	} else if (!ip->client->interval)
1359 		ip->client->interval =
1360 			ip->client->config->initial_interval;
1361 
1362 	/* If the backoff would take us to the panic timeout, just use that
1363 	   as the interval. */
1364 	if (cur_time + ip->client->interval >
1365 	    ip->client->first_sending + ip->client->config->timeout)
1366 		ip->client->interval =
1367 			(ip->client->first_sending +
1368 			 ip->client->config->timeout) - cur_time + 1;
1369 
1370 	/* Record the number of seconds since we started sending. */
1371 	if (interval < 65536)
1372 		ip->client->packet.secs = htons(interval);
1373 	else
1374 		ip->client->packet.secs = htons(65535);
1375 	ip->client->secs = ip->client->packet.secs;
1376 
1377 	note("DHCPDISCOVER on %s to %s port %d interval %d",
1378 	    ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
1379 	    (int)ip->client->interval);
1380 
1381 	/* Send out a packet. */
1382 	send_packet_unpriv(privfd, &ip->client->packet,
1383 	    ip->client->packet_length, inaddr_any, inaddr_broadcast);
1384 
1385 	add_timeout(cur_time + ip->client->interval, send_discover, ip);
1386 }
1387 
1388 /*
1389  * state_panic gets called if we haven't received any offers in a preset
1390  * amount of time.   When this happens, we try to use existing leases
1391  * that haven't yet expired, and failing that, we call the client script
1392  * and hope it can do something.
1393  */
1394 void
state_panic(void * ipp)1395 state_panic(void *ipp)
1396 {
1397 	struct interface_info *ip = ipp;
1398 	struct client_lease *loop = ip->client->active;
1399 	struct client_lease *lp;
1400 
1401 	note("No DHCPOFFERS received.");
1402 
1403 	/* We may not have an active lease, but we may have some
1404 	   predefined leases that we can try. */
1405 	if (!ip->client->active && ip->client->leases)
1406 		goto activate_next;
1407 
1408 	/* Run through the list of leases and see if one can be used. */
1409 	while (ip->client->active) {
1410 		if (ip->client->active->expiry > cur_time) {
1411 			note("Trying recorded lease %s",
1412 			    piaddr(ip->client->active->address));
1413 			/* Run the client script with the existing
1414 			   parameters. */
1415 			script_init("TIMEOUT",
1416 			    ip->client->active->medium);
1417 			script_write_params("new_", ip->client->active);
1418 			if (ip->client->alias)
1419 				script_write_params("alias_",
1420 				    ip->client->alias);
1421 
1422 			/* If the old lease is still good and doesn't
1423 			   yet need renewal, go into BOUND state and
1424 			   timeout at the renewal time. */
1425 			if (!script_go()) {
1426 				if (cur_time <
1427 				    ip->client->active->renewal) {
1428 					ip->client->state = S_BOUND;
1429 					note("bound: renewal in %d seconds.",
1430 					    (int)(ip->client->active->renewal -
1431 					    cur_time));
1432 					add_timeout(
1433 					    ip->client->active->renewal,
1434 					    state_bound, ip);
1435 				} else {
1436 					ip->client->state = S_BOUND;
1437 					note("bound: immediate renewal.");
1438 					state_bound(ip);
1439 				}
1440 				reinitialize_interfaces();
1441 				go_daemon();
1442 				return;
1443 			}
1444 		}
1445 
1446 		/* If there are no other leases, give up. */
1447 		if (!ip->client->leases) {
1448 			ip->client->leases = ip->client->active;
1449 			ip->client->active = NULL;
1450 			break;
1451 		}
1452 
1453 activate_next:
1454 		/* Otherwise, put the active lease at the end of the
1455 		   lease list, and try another lease.. */
1456 		for (lp = ip->client->leases; lp->next; lp = lp->next)
1457 			;
1458 		lp->next = ip->client->active;
1459 		if (lp->next)
1460 			lp->next->next = NULL;
1461 		ip->client->active = ip->client->leases;
1462 		ip->client->leases = ip->client->leases->next;
1463 
1464 		/* If we already tried this lease, we've exhausted the
1465 		   set of leases, so we might as well give up for
1466 		   now. */
1467 		if (ip->client->active == loop)
1468 			break;
1469 		else if (!loop)
1470 			loop = ip->client->active;
1471 	}
1472 
1473 	/* No leases were available, or what was available didn't work, so
1474 	   tell the shell script that we failed to allocate an address,
1475 	   and try again later. */
1476 	note("No working leases in persistent database - sleeping.\n");
1477 	script_init("FAIL", NULL);
1478 	if (ip->client->alias)
1479 		script_write_params("alias_", ip->client->alias);
1480 	script_go();
1481 	ip->client->state = S_INIT;
1482 	add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1483 	    ip);
1484 	go_daemon();
1485 }
1486 
1487 void
send_request(void * ipp)1488 send_request(void *ipp)
1489 {
1490 	struct interface_info *ip = ipp;
1491 	struct in_addr from, to;
1492 	int interval;
1493 
1494 	/* Figure out how long it's been since we started transmitting. */
1495 	interval = cur_time - ip->client->first_sending;
1496 
1497 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
1498 	   past the reboot timeout, go to INIT and see if we can
1499 	   DISCOVER an address... */
1500 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1501 	   means either that we're on a network with no DHCP server,
1502 	   or that our server is down.  In the latter case, assuming
1503 	   that there is a backup DHCP server, DHCPDISCOVER will get
1504 	   us a new address, but we could also have successfully
1505 	   reused our old address.  In the former case, we're hosed
1506 	   anyway.  This is not a win-prone situation. */
1507 	if ((ip->client->state == S_REBOOTING ||
1508 	    ip->client->state == S_REQUESTING) &&
1509 	    interval > ip->client->config->reboot_timeout) {
1510 cancel:
1511 		ip->client->state = S_INIT;
1512 		cancel_timeout(send_request, ip);
1513 		state_init(ip);
1514 		return;
1515 	}
1516 
1517 	/* If we're in the reboot state, make sure the media is set up
1518 	   correctly. */
1519 	if (ip->client->state == S_REBOOTING &&
1520 	    !ip->client->medium &&
1521 	    ip->client->active->medium ) {
1522 		script_init("MEDIUM", ip->client->active->medium);
1523 
1524 		/* If the medium we chose won't fly, go to INIT state. */
1525 		if (script_go())
1526 			goto cancel;
1527 
1528 		/* Record the medium. */
1529 		ip->client->medium = ip->client->active->medium;
1530 	}
1531 
1532 	/* If the lease has expired, relinquish the address and go back
1533 	   to the INIT state. */
1534 	if (ip->client->state != S_REQUESTING &&
1535 	    cur_time > ip->client->active->expiry) {
1536 		/* Run the client script with the new parameters. */
1537 		script_init("EXPIRE", NULL);
1538 		script_write_params("old_", ip->client->active);
1539 		if (ip->client->alias)
1540 			script_write_params("alias_", ip->client->alias);
1541 		script_go();
1542 
1543 		/* Now do a preinit on the interface so that we can
1544 		   discover a new address. */
1545 		script_init("PREINIT", NULL);
1546 		if (ip->client->alias)
1547 			script_write_params("alias_", ip->client->alias);
1548 		script_go();
1549 
1550 		ip->client->state = S_INIT;
1551 		state_init(ip);
1552 		return;
1553 	}
1554 
1555 	/* Do the exponential backoff... */
1556 	if (!ip->client->interval)
1557 		ip->client->interval = ip->client->config->initial_interval;
1558 	else
1559 		ip->client->interval += ((arc4random() >> 2) %
1560 		    (2 * ip->client->interval));
1561 
1562 	/* Don't backoff past cutoff. */
1563 	if (ip->client->interval >
1564 	    ip->client->config->backoff_cutoff)
1565 		ip->client->interval =
1566 		    ((ip->client->config->backoff_cutoff / 2) +
1567 		    ((arc4random() >> 2) % ip->client->interval));
1568 
1569 	/* If the backoff would take us to the expiry time, just set the
1570 	   timeout to the expiry time. */
1571 	if (ip->client->state != S_REQUESTING &&
1572 	    cur_time + ip->client->interval >
1573 	    ip->client->active->expiry)
1574 		ip->client->interval =
1575 		    ip->client->active->expiry - cur_time + 1;
1576 
1577 	/* If the lease T2 time has elapsed, or if we're not yet bound,
1578 	   broadcast the DHCPREQUEST rather than unicasting. */
1579 	if (ip->client->state == S_REQUESTING ||
1580 	    ip->client->state == S_REBOOTING ||
1581 	    cur_time > ip->client->active->rebind)
1582 		to.s_addr = INADDR_BROADCAST;
1583 	else
1584 		memcpy(&to.s_addr, ip->client->destination.iabuf,
1585 		    sizeof(to.s_addr));
1586 
1587 	if (ip->client->state != S_REQUESTING &&
1588 	    ip->client->state != S_REBOOTING)
1589 		memcpy(&from, ip->client->active->address.iabuf,
1590 		    sizeof(from));
1591 	else
1592 		from.s_addr = INADDR_ANY;
1593 
1594 	/* Record the number of seconds since we started sending. */
1595 	if (ip->client->state == S_REQUESTING)
1596 		ip->client->packet.secs = ip->client->secs;
1597 	else {
1598 		if (interval < 65536)
1599 			ip->client->packet.secs = htons(interval);
1600 		else
1601 			ip->client->packet.secs = htons(65535);
1602 	}
1603 
1604 	note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
1605 	    REMOTE_PORT);
1606 
1607 	/* Send out a packet. */
1608 	send_packet_unpriv(privfd, &ip->client->packet,
1609 	    ip->client->packet_length, from, to);
1610 
1611 	add_timeout(cur_time + ip->client->interval, send_request, ip);
1612 }
1613 
1614 void
send_decline(void * ipp)1615 send_decline(void *ipp)
1616 {
1617 	struct interface_info *ip = ipp;
1618 
1619 	note("DHCPDECLINE on %s to %s port %d", ip->name,
1620 	    inet_ntoa(inaddr_broadcast), REMOTE_PORT);
1621 
1622 	/* Send out a packet. */
1623 	send_packet_unpriv(privfd, &ip->client->packet,
1624 	    ip->client->packet_length, inaddr_any, inaddr_broadcast);
1625 }
1626 
1627 void
make_discover(struct interface_info * ip,struct client_lease * lease)1628 make_discover(struct interface_info *ip, struct client_lease *lease)
1629 {
1630 	unsigned char discover = DHCPDISCOVER;
1631 	struct tree_cache *options[256];
1632 	struct tree_cache option_elements[256];
1633 	int i;
1634 
1635 	memset(option_elements, 0, sizeof(option_elements));
1636 	memset(options, 0, sizeof(options));
1637 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1638 
1639 	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1640 	i = DHO_DHCP_MESSAGE_TYPE;
1641 	options[i] = &option_elements[i];
1642 	options[i]->value = &discover;
1643 	options[i]->len = sizeof(discover);
1644 	options[i]->buf_size = sizeof(discover);
1645 	options[i]->timeout = 0xFFFFFFFF;
1646 
1647 	/* Request the options we want */
1648 	i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
1649 	options[i] = &option_elements[i];
1650 	options[i]->value = ip->client->config->requested_options;
1651 	options[i]->len = ip->client->config->requested_option_count;
1652 	options[i]->buf_size =
1653 		ip->client->config->requested_option_count;
1654 	options[i]->timeout = 0xFFFFFFFF;
1655 
1656 	/* If we had an address, try to get it again. */
1657 	if (lease) {
1658 		ip->client->requested_address = lease->address;
1659 		i = DHO_DHCP_REQUESTED_ADDRESS;
1660 		options[i] = &option_elements[i];
1661 		options[i]->value = lease->address.iabuf;
1662 		options[i]->len = lease->address.len;
1663 		options[i]->buf_size = lease->address.len;
1664 		options[i]->timeout = 0xFFFFFFFF;
1665 	} else
1666 		ip->client->requested_address.len = 0;
1667 
1668 	/* Send any options requested in the config file. */
1669 	for (i = 0; i < 256; i++)
1670 		if (!options[i] &&
1671 		    ip->client->config->send_options[i].data) {
1672 			options[i] = &option_elements[i];
1673 			options[i]->value =
1674 			    ip->client->config->send_options[i].data;
1675 			options[i]->len =
1676 			    ip->client->config->send_options[i].len;
1677 			options[i]->buf_size =
1678 			    ip->client->config->send_options[i].len;
1679 			options[i]->timeout = 0xFFFFFFFF;
1680 		}
1681 
1682 	/* send host name if not set via config file. */
1683 	if (!options[DHO_HOST_NAME]) {
1684 		if (hostname[0] != '\0') {
1685 			size_t len;
1686 			char* posDot = strchr(hostname, '.');
1687 			if (posDot != NULL)
1688 				len = posDot - hostname;
1689 			else
1690 				len = strlen(hostname);
1691 			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1692 			options[DHO_HOST_NAME]->value = hostname;
1693 			options[DHO_HOST_NAME]->len = len;
1694 			options[DHO_HOST_NAME]->buf_size = len;
1695 			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1696 		}
1697 	}
1698 
1699 	/* set unique client identifier */
1700 	char client_ident[sizeof(ip->hw_address.haddr) + 1];
1701 	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1702 		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1703 				ip->hw_address.hlen : sizeof(client_ident)-1;
1704 		client_ident[0] = ip->hw_address.htype;
1705 		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1706 		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1707 		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1708 		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1709 		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1710 		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1711 	}
1712 
1713 	/* Set up the option buffer... */
1714 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1715 	    options, 0, 0, 0, NULL, 0);
1716 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1717 		ip->client->packet_length = BOOTP_MIN_LEN;
1718 
1719 	ip->client->packet.op = BOOTREQUEST;
1720 	ip->client->packet.htype = ip->hw_address.htype;
1721 	ip->client->packet.hlen = ip->hw_address.hlen;
1722 	ip->client->packet.hops = 0;
1723 	ip->client->packet.xid = arc4random();
1724 	ip->client->packet.secs = 0; /* filled in by send_discover. */
1725 	ip->client->packet.flags = 0;
1726 
1727 	memset(&(ip->client->packet.ciaddr),
1728 	    0, sizeof(ip->client->packet.ciaddr));
1729 	memset(&(ip->client->packet.yiaddr),
1730 	    0, sizeof(ip->client->packet.yiaddr));
1731 	memset(&(ip->client->packet.siaddr),
1732 	    0, sizeof(ip->client->packet.siaddr));
1733 	memset(&(ip->client->packet.giaddr),
1734 	    0, sizeof(ip->client->packet.giaddr));
1735 	memcpy(ip->client->packet.chaddr,
1736 	    ip->hw_address.haddr, ip->hw_address.hlen);
1737 }
1738 
1739 
1740 void
make_request(struct interface_info * ip,struct client_lease * lease)1741 make_request(struct interface_info *ip, struct client_lease * lease)
1742 {
1743 	unsigned char request = DHCPREQUEST;
1744 	struct tree_cache *options[256];
1745 	struct tree_cache option_elements[256];
1746 	int i;
1747 
1748 	memset(options, 0, sizeof(options));
1749 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1750 
1751 	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1752 	i = DHO_DHCP_MESSAGE_TYPE;
1753 	options[i] = &option_elements[i];
1754 	options[i]->value = &request;
1755 	options[i]->len = sizeof(request);
1756 	options[i]->buf_size = sizeof(request);
1757 	options[i]->timeout = 0xFFFFFFFF;
1758 
1759 	/* Request the options we want */
1760 	i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1761 	options[i] = &option_elements[i];
1762 	options[i]->value = ip->client->config->requested_options;
1763 	options[i]->len = ip->client->config->requested_option_count;
1764 	options[i]->buf_size =
1765 		ip->client->config->requested_option_count;
1766 	options[i]->timeout = 0xFFFFFFFF;
1767 
1768 	/* If we are requesting an address that hasn't yet been assigned
1769 	   to us, use the DHCP Requested Address option. */
1770 	if (ip->client->state == S_REQUESTING) {
1771 		/* Send back the server identifier... */
1772 		i = DHO_DHCP_SERVER_IDENTIFIER;
1773 		options[i] = &option_elements[i];
1774 		options[i]->value = lease->options[i].data;
1775 		options[i]->len = lease->options[i].len;
1776 		options[i]->buf_size = lease->options[i].len;
1777 		options[i]->timeout = 0xFFFFFFFF;
1778 	}
1779 	if (ip->client->state == S_REQUESTING ||
1780 	    ip->client->state == S_REBOOTING) {
1781 		ip->client->requested_address = lease->address;
1782 		i = DHO_DHCP_REQUESTED_ADDRESS;
1783 		options[i] = &option_elements[i];
1784 		options[i]->value = lease->address.iabuf;
1785 		options[i]->len = lease->address.len;
1786 		options[i]->buf_size = lease->address.len;
1787 		options[i]->timeout = 0xFFFFFFFF;
1788 	} else
1789 		ip->client->requested_address.len = 0;
1790 
1791 	/* Send any options requested in the config file. */
1792 	for (i = 0; i < 256; i++)
1793 		if (!options[i] &&
1794 		    ip->client->config->send_options[i].data) {
1795 			options[i] = &option_elements[i];
1796 			options[i]->value =
1797 			    ip->client->config->send_options[i].data;
1798 			options[i]->len =
1799 			    ip->client->config->send_options[i].len;
1800 			options[i]->buf_size =
1801 			    ip->client->config->send_options[i].len;
1802 			options[i]->timeout = 0xFFFFFFFF;
1803 		}
1804 
1805 	/* send host name if not set via config file. */
1806 	if (!options[DHO_HOST_NAME]) {
1807 		if (hostname[0] != '\0') {
1808 			size_t len;
1809 			char* posDot = strchr(hostname, '.');
1810 			if (posDot != NULL)
1811 				len = posDot - hostname;
1812 			else
1813 				len = strlen(hostname);
1814 			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1815 			options[DHO_HOST_NAME]->value = hostname;
1816 			options[DHO_HOST_NAME]->len = len;
1817 			options[DHO_HOST_NAME]->buf_size = len;
1818 			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1819 		}
1820 	}
1821 
1822 	/* set unique client identifier */
1823 	char client_ident[sizeof(ip->hw_address.haddr) + 1];
1824 	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1825 		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1826 				ip->hw_address.hlen : sizeof(client_ident)-1;
1827 		client_ident[0] = ip->hw_address.htype;
1828 		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1829 		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1830 		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1831 		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1832 		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1833 		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1834 	}
1835 
1836 	/* Set up the option buffer... */
1837 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1838 	    options, 0, 0, 0, NULL, 0);
1839 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1840 		ip->client->packet_length = BOOTP_MIN_LEN;
1841 
1842 	ip->client->packet.op = BOOTREQUEST;
1843 	ip->client->packet.htype = ip->hw_address.htype;
1844 	ip->client->packet.hlen = ip->hw_address.hlen;
1845 	ip->client->packet.hops = 0;
1846 	ip->client->packet.xid = ip->client->xid;
1847 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1848 
1849 	/* If we own the address we're requesting, put it in ciaddr;
1850 	   otherwise set ciaddr to zero. */
1851 	if (ip->client->state == S_BOUND ||
1852 	    ip->client->state == S_RENEWING ||
1853 	    ip->client->state == S_REBINDING) {
1854 		memcpy(&ip->client->packet.ciaddr,
1855 		    lease->address.iabuf, lease->address.len);
1856 		ip->client->packet.flags = 0;
1857 	} else {
1858 		memset(&ip->client->packet.ciaddr, 0,
1859 		    sizeof(ip->client->packet.ciaddr));
1860 		ip->client->packet.flags = 0;
1861 	}
1862 
1863 	memset(&ip->client->packet.yiaddr, 0,
1864 	    sizeof(ip->client->packet.yiaddr));
1865 	memset(&ip->client->packet.siaddr, 0,
1866 	    sizeof(ip->client->packet.siaddr));
1867 	memset(&ip->client->packet.giaddr, 0,
1868 	    sizeof(ip->client->packet.giaddr));
1869 	memcpy(ip->client->packet.chaddr,
1870 	    ip->hw_address.haddr, ip->hw_address.hlen);
1871 }
1872 
1873 void
make_decline(struct interface_info * ip,struct client_lease * lease)1874 make_decline(struct interface_info *ip, struct client_lease *lease)
1875 {
1876 	struct tree_cache *options[256], message_type_tree;
1877 	struct tree_cache requested_address_tree;
1878 	struct tree_cache server_id_tree, client_id_tree;
1879 	unsigned char decline = DHCPDECLINE;
1880 	int i;
1881 
1882 	memset(options, 0, sizeof(options));
1883 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1884 
1885 	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1886 	i = DHO_DHCP_MESSAGE_TYPE;
1887 	options[i] = &message_type_tree;
1888 	options[i]->value = &decline;
1889 	options[i]->len = sizeof(decline);
1890 	options[i]->buf_size = sizeof(decline);
1891 	options[i]->timeout = 0xFFFFFFFF;
1892 
1893 	/* Send back the server identifier... */
1894 	i = DHO_DHCP_SERVER_IDENTIFIER;
1895 	options[i] = &server_id_tree;
1896 	options[i]->value = lease->options[i].data;
1897 	options[i]->len = lease->options[i].len;
1898 	options[i]->buf_size = lease->options[i].len;
1899 	options[i]->timeout = 0xFFFFFFFF;
1900 
1901 	/* Send back the address we're declining. */
1902 	i = DHO_DHCP_REQUESTED_ADDRESS;
1903 	options[i] = &requested_address_tree;
1904 	options[i]->value = lease->address.iabuf;
1905 	options[i]->len = lease->address.len;
1906 	options[i]->buf_size = lease->address.len;
1907 	options[i]->timeout = 0xFFFFFFFF;
1908 
1909 	/* Send the uid if the user supplied one. */
1910 	i = DHO_DHCP_CLIENT_IDENTIFIER;
1911 	if (ip->client->config->send_options[i].len) {
1912 		options[i] = &client_id_tree;
1913 		options[i]->value = ip->client->config->send_options[i].data;
1914 		options[i]->len = ip->client->config->send_options[i].len;
1915 		options[i]->buf_size = ip->client->config->send_options[i].len;
1916 		options[i]->timeout = 0xFFFFFFFF;
1917 	}
1918 
1919 
1920 	/* Set up the option buffer... */
1921 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1922 	    options, 0, 0, 0, NULL, 0);
1923 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1924 		ip->client->packet_length = BOOTP_MIN_LEN;
1925 
1926 	ip->client->packet.op = BOOTREQUEST;
1927 	ip->client->packet.htype = ip->hw_address.htype;
1928 	ip->client->packet.hlen = ip->hw_address.hlen;
1929 	ip->client->packet.hops = 0;
1930 	ip->client->packet.xid = ip->client->xid;
1931 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1932 	ip->client->packet.flags = 0;
1933 
1934 	/* ciaddr must always be zero. */
1935 	memset(&ip->client->packet.ciaddr, 0,
1936 	    sizeof(ip->client->packet.ciaddr));
1937 	memset(&ip->client->packet.yiaddr, 0,
1938 	    sizeof(ip->client->packet.yiaddr));
1939 	memset(&ip->client->packet.siaddr, 0,
1940 	    sizeof(ip->client->packet.siaddr));
1941 	memset(&ip->client->packet.giaddr, 0,
1942 	    sizeof(ip->client->packet.giaddr));
1943 	memcpy(ip->client->packet.chaddr,
1944 	    ip->hw_address.haddr, ip->hw_address.hlen);
1945 }
1946 
1947 void
free_client_lease(struct client_lease * lease)1948 free_client_lease(struct client_lease *lease)
1949 {
1950 	int i;
1951 
1952 	if (lease->server_name)
1953 		free(lease->server_name);
1954 	if (lease->filename)
1955 		free(lease->filename);
1956 	for (i = 0; i < 256; i++) {
1957 		if (lease->options[i].len)
1958 			free(lease->options[i].data);
1959 	}
1960 	free(lease);
1961 }
1962 
1963 static FILE *leaseFile;
1964 
1965 void
rewrite_client_leases(void)1966 rewrite_client_leases(void)
1967 {
1968 	struct client_lease *lp;
1969 	cap_rights_t rights;
1970 
1971 	if (!leaseFile) {
1972 		leaseFile = fopen(path_dhclient_db, "w");
1973 		if (!leaseFile)
1974 			error("can't create %s: %m", path_dhclient_db);
1975 		cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC,
1976 		    CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
1977 		if (caph_rights_limit(fileno(leaseFile), &rights) < 0) {
1978 			error("can't limit lease descriptor: %m");
1979 		}
1980 		if (caph_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0) {
1981 			error("can't limit lease descriptor fcntls: %m");
1982 		}
1983 	} else {
1984 		fflush(leaseFile);
1985 		rewind(leaseFile);
1986 	}
1987 
1988 	for (lp = ifi->client->leases; lp; lp = lp->next)
1989 		write_client_lease(ifi, lp, 1);
1990 	if (ifi->client->active)
1991 		write_client_lease(ifi, ifi->client->active, 1);
1992 
1993 	fflush(leaseFile);
1994 	ftruncate(fileno(leaseFile), ftello(leaseFile));
1995 	fsync(fileno(leaseFile));
1996 }
1997 
1998 void
write_client_lease(struct interface_info * ip,struct client_lease * lease,int rewrite)1999 write_client_lease(struct interface_info *ip, struct client_lease *lease,
2000     int rewrite)
2001 {
2002 	static int leases_written;
2003 	struct tm *t;
2004 	int i;
2005 
2006 	if (!rewrite) {
2007 		if (leases_written++ > 20) {
2008 			rewrite_client_leases();
2009 			leases_written = 0;
2010 		}
2011 	}
2012 
2013 	/* If the lease came from the config file, we don't need to stash
2014 	   a copy in the lease database. */
2015 	if (lease->is_static)
2016 		return;
2017 
2018 	if (!leaseFile) {	/* XXX */
2019 		leaseFile = fopen(path_dhclient_db, "w");
2020 		if (!leaseFile)
2021 			error("can't create %s: %m", path_dhclient_db);
2022 	}
2023 
2024 	fprintf(leaseFile, "lease {\n");
2025 	if (lease->is_bootp)
2026 		fprintf(leaseFile, "  bootp;\n");
2027 	fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
2028 	fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
2029 	if (lease->nextserver.len == sizeof(inaddr_any) &&
2030 	    0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
2031 	    sizeof(inaddr_any)))
2032 		fprintf(leaseFile, "  next-server %s;\n",
2033 		    piaddr(lease->nextserver));
2034 	if (lease->filename)
2035 		fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
2036 	if (lease->server_name)
2037 		fprintf(leaseFile, "  server-name \"%s\";\n",
2038 		    lease->server_name);
2039 	if (lease->medium)
2040 		fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
2041 	for (i = 0; i < 256; i++)
2042 		if (lease->options[i].len)
2043 			fprintf(leaseFile, "  option %s %s;\n",
2044 			    dhcp_options[i].name,
2045 			    pretty_print_option(i, lease->options[i].data,
2046 			    lease->options[i].len, 1, 1));
2047 
2048 	t = gmtime(&lease->renewal);
2049 	fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
2050 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2051 	    t->tm_hour, t->tm_min, t->tm_sec);
2052 	t = gmtime(&lease->rebind);
2053 	fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
2054 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2055 	    t->tm_hour, t->tm_min, t->tm_sec);
2056 	t = gmtime(&lease->expiry);
2057 	fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
2058 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2059 	    t->tm_hour, t->tm_min, t->tm_sec);
2060 	fprintf(leaseFile, "}\n");
2061 	fflush(leaseFile);
2062 }
2063 
2064 void
script_init(const char * reason,struct string_list * medium)2065 script_init(const char *reason, struct string_list *medium)
2066 {
2067 	size_t		 len, mediumlen = 0;
2068 	struct imsg_hdr	 hdr;
2069 	struct buf	*buf;
2070 	int		 errs;
2071 
2072 	if (medium != NULL && medium->string != NULL)
2073 		mediumlen = strlen(medium->string);
2074 
2075 	hdr.code = IMSG_SCRIPT_INIT;
2076 	hdr.len = sizeof(struct imsg_hdr) +
2077 	    sizeof(size_t) + mediumlen +
2078 	    sizeof(size_t) + strlen(reason);
2079 
2080 	if ((buf = buf_open(hdr.len)) == NULL)
2081 		error("buf_open: %m");
2082 
2083 	errs = 0;
2084 	errs += buf_add(buf, &hdr, sizeof(hdr));
2085 	errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
2086 	if (mediumlen > 0)
2087 		errs += buf_add(buf, medium->string, mediumlen);
2088 	len = strlen(reason);
2089 	errs += buf_add(buf, &len, sizeof(len));
2090 	errs += buf_add(buf, reason, len);
2091 
2092 	if (errs)
2093 		error("buf_add: %m");
2094 
2095 	if (buf_close(privfd, buf) == -1)
2096 		error("buf_close: %m");
2097 }
2098 
2099 void
priv_script_init(const char * reason,char * medium)2100 priv_script_init(const char *reason, char *medium)
2101 {
2102 	struct interface_info *ip = ifi;
2103 
2104 	if (ip) {
2105 		ip->client->scriptEnvsize = 100;
2106 		if (ip->client->scriptEnv == NULL)
2107 			ip->client->scriptEnv =
2108 			    malloc(ip->client->scriptEnvsize * sizeof(char *));
2109 		if (ip->client->scriptEnv == NULL)
2110 			error("script_init: no memory for environment");
2111 
2112 		ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
2113 		if (ip->client->scriptEnv[0] == NULL)
2114 			error("script_init: no memory for environment");
2115 
2116 		ip->client->scriptEnv[1] = NULL;
2117 
2118 		script_set_env(ip->client, "", "interface", ip->name);
2119 
2120 		if (medium)
2121 			script_set_env(ip->client, "", "medium", medium);
2122 
2123 		script_set_env(ip->client, "", "reason", reason);
2124 	}
2125 }
2126 
2127 void
priv_script_write_params(const char * prefix,struct client_lease * lease)2128 priv_script_write_params(const char *prefix, struct client_lease *lease)
2129 {
2130 	struct interface_info *ip = ifi;
2131 	u_int8_t dbuf[1500], *dp = NULL;
2132 	int i;
2133 	size_t len;
2134 	char tbuf[128];
2135 
2136 	script_set_env(ip->client, prefix, "ip_address",
2137 	    piaddr(lease->address));
2138 
2139 	if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
2140 	    ACTION_SUPERSEDE) {
2141 		dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
2142 		len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
2143 	} else {
2144 		dp = lease->options[DHO_SUBNET_MASK].data;
2145 		len = lease->options[DHO_SUBNET_MASK].len;
2146 	}
2147 	if (len && (len < sizeof(lease->address.iabuf))) {
2148 		struct iaddr netmask, subnet, broadcast;
2149 
2150 		memcpy(netmask.iabuf, dp, len);
2151 		netmask.len = len;
2152 		subnet = subnet_number(lease->address, netmask);
2153 		if (subnet.len) {
2154 			script_set_env(ip->client, prefix, "network_number",
2155 			    piaddr(subnet));
2156 			if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
2157 				broadcast = broadcast_addr(subnet, netmask);
2158 				if (broadcast.len)
2159 					script_set_env(ip->client, prefix,
2160 					    "broadcast_address",
2161 					    piaddr(broadcast));
2162 			}
2163 		}
2164 	}
2165 
2166 	if (lease->filename)
2167 		script_set_env(ip->client, prefix, "filename", lease->filename);
2168 	if (lease->server_name)
2169 		script_set_env(ip->client, prefix, "server_name",
2170 		    lease->server_name);
2171 	for (i = 0; i < 256; i++) {
2172 		len = 0;
2173 
2174 		if (ip->client->config->defaults[i].len) {
2175 			if (lease->options[i].len) {
2176 				switch (
2177 				    ip->client->config->default_actions[i]) {
2178 				case ACTION_DEFAULT:
2179 					dp = lease->options[i].data;
2180 					len = lease->options[i].len;
2181 					break;
2182 				case ACTION_SUPERSEDE:
2183 supersede:
2184 					dp = ip->client->
2185 						config->defaults[i].data;
2186 					len = ip->client->
2187 						config->defaults[i].len;
2188 					break;
2189 				case ACTION_PREPEND:
2190 					len = ip->client->
2191 					    config->defaults[i].len +
2192 					    lease->options[i].len;
2193 					if (len >= sizeof(dbuf)) {
2194 						warning("no space to %s %s",
2195 						    "prepend option",
2196 						    dhcp_options[i].name);
2197 						goto supersede;
2198 					}
2199 					dp = dbuf;
2200 					memcpy(dp,
2201 						ip->client->
2202 						config->defaults[i].data,
2203 						ip->client->
2204 						config->defaults[i].len);
2205 					memcpy(dp + ip->client->
2206 						config->defaults[i].len,
2207 						lease->options[i].data,
2208 						lease->options[i].len);
2209 					dp[len] = '\0';
2210 					break;
2211 				case ACTION_APPEND:
2212 					/*
2213 					 * When we append, we assume that we're
2214 					 * appending to text.  Some MS servers
2215 					 * include a NUL byte at the end of
2216 					 * the search string provided.
2217 					 */
2218 					len = ip->client->
2219 					    config->defaults[i].len +
2220 					    lease->options[i].len;
2221 					if (len >= sizeof(dbuf)) {
2222 						warning("no space to %s %s",
2223 						    "append option",
2224 						    dhcp_options[i].name);
2225 						goto supersede;
2226 					}
2227 					memcpy(dbuf,
2228 						lease->options[i].data,
2229 						lease->options[i].len);
2230 					for (dp = dbuf + lease->options[i].len;
2231 					    dp > dbuf; dp--, len--)
2232 						if (dp[-1] != '\0')
2233 							break;
2234 					memcpy(dp,
2235 						ip->client->
2236 						config->defaults[i].data,
2237 						ip->client->
2238 						config->defaults[i].len);
2239 					dp = dbuf;
2240 					dp[len] = '\0';
2241 				}
2242 			} else {
2243 				dp = ip->client->
2244 					config->defaults[i].data;
2245 				len = ip->client->
2246 					config->defaults[i].len;
2247 			}
2248 		} else if (lease->options[i].len) {
2249 			len = lease->options[i].len;
2250 			dp = lease->options[i].data;
2251 		} else {
2252 			len = 0;
2253 		}
2254 		if (len) {
2255 			char name[256];
2256 
2257 			if (dhcp_option_ev_name(name, sizeof(name),
2258 			    &dhcp_options[i]))
2259 				script_set_env(ip->client, prefix, name,
2260 				    pretty_print_option(i, dp, len, 0, 0));
2261 		}
2262 	}
2263 	snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2264 	script_set_env(ip->client, prefix, "expiry", tbuf);
2265 }
2266 
2267 void
script_write_params(const char * prefix,struct client_lease * lease)2268 script_write_params(const char *prefix, struct client_lease *lease)
2269 {
2270 	size_t		 fn_len = 0, sn_len = 0, pr_len = 0;
2271 	struct imsg_hdr	 hdr;
2272 	struct buf	*buf;
2273 	int		 errs, i;
2274 
2275 	if (lease->filename != NULL)
2276 		fn_len = strlen(lease->filename);
2277 	if (lease->server_name != NULL)
2278 		sn_len = strlen(lease->server_name);
2279 	if (prefix != NULL)
2280 		pr_len = strlen(prefix);
2281 
2282 	hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2283 	hdr.len = sizeof(hdr) + sizeof(*lease) +
2284 	    sizeof(fn_len) + fn_len + sizeof(sn_len) + sn_len +
2285 	    sizeof(pr_len) + pr_len;
2286 
2287 	for (i = 0; i < 256; i++) {
2288 		hdr.len += sizeof(lease->options[i].len);
2289 		hdr.len += lease->options[i].len;
2290 	}
2291 
2292 	scripttime = time(NULL);
2293 
2294 	if ((buf = buf_open(hdr.len)) == NULL)
2295 		error("buf_open: %m");
2296 
2297 	errs = 0;
2298 	errs += buf_add(buf, &hdr, sizeof(hdr));
2299 	errs += buf_add(buf, lease, sizeof(*lease));
2300 	errs += buf_add(buf, &fn_len, sizeof(fn_len));
2301 	errs += buf_add(buf, lease->filename, fn_len);
2302 	errs += buf_add(buf, &sn_len, sizeof(sn_len));
2303 	errs += buf_add(buf, lease->server_name, sn_len);
2304 	errs += buf_add(buf, &pr_len, sizeof(pr_len));
2305 	errs += buf_add(buf, prefix, pr_len);
2306 
2307 	for (i = 0; i < 256; i++) {
2308 		errs += buf_add(buf, &lease->options[i].len,
2309 		    sizeof(lease->options[i].len));
2310 		errs += buf_add(buf, lease->options[i].data,
2311 		    lease->options[i].len);
2312 	}
2313 
2314 	if (errs)
2315 		error("buf_add: %m");
2316 
2317 	if (buf_close(privfd, buf) == -1)
2318 		error("buf_close: %m");
2319 }
2320 
2321 int
script_go(void)2322 script_go(void)
2323 {
2324 	struct imsg_hdr	 hdr;
2325 	struct buf	*buf;
2326 	int		 ret;
2327 
2328 	hdr.code = IMSG_SCRIPT_GO;
2329 	hdr.len = sizeof(struct imsg_hdr);
2330 
2331 	if ((buf = buf_open(hdr.len)) == NULL)
2332 		error("buf_open: %m");
2333 
2334 	if (buf_add(buf, &hdr, sizeof(hdr)))
2335 		error("buf_add: %m");
2336 
2337 	if (buf_close(privfd, buf) == -1)
2338 		error("buf_close: %m");
2339 
2340 	bzero(&hdr, sizeof(hdr));
2341 	buf_read(privfd, &hdr, sizeof(hdr));
2342 	if (hdr.code != IMSG_SCRIPT_GO_RET)
2343 		error("unexpected msg type %u", hdr.code);
2344 	if (hdr.len != sizeof(hdr) + sizeof(int))
2345 		error("received corrupted message");
2346 	buf_read(privfd, &ret, sizeof(ret));
2347 
2348 	scripttime = time(NULL);
2349 
2350 	return (ret);
2351 }
2352 
2353 int
priv_script_go(void)2354 priv_script_go(void)
2355 {
2356 	char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2357 	static char client_path[] = CLIENT_PATH;
2358 	struct interface_info *ip = ifi;
2359 	int pid, wpid, wstatus;
2360 
2361 	scripttime = time(NULL);
2362 
2363 	if (ip) {
2364 		scriptName = ip->client->config->script_name;
2365 		envp = ip->client->scriptEnv;
2366 	} else {
2367 		scriptName = top_level_config.script_name;
2368 		epp[0] = reason;
2369 		epp[1] = client_path;
2370 		epp[2] = NULL;
2371 		envp = epp;
2372 	}
2373 
2374 	argv[0] = scriptName;
2375 	argv[1] = NULL;
2376 
2377 	pid = fork();
2378 	if (pid < 0) {
2379 		error("fork: %m");
2380 		wstatus = 0;
2381 	} else if (pid) {
2382 		do {
2383 			wpid = wait(&wstatus);
2384 		} while (wpid != pid && wpid > 0);
2385 		if (wpid < 0) {
2386 			error("wait: %m");
2387 			wstatus = 0;
2388 		}
2389 	} else {
2390 		execve(scriptName, argv, envp);
2391 		error("execve (%s, ...): %m", scriptName);
2392 	}
2393 
2394 	if (ip)
2395 		script_flush_env(ip->client);
2396 
2397 	return (WIFEXITED(wstatus) ?
2398 	    WEXITSTATUS(wstatus) : 128 + WTERMSIG(wstatus));
2399 }
2400 
2401 void
script_set_env(struct client_state * client,const char * prefix,const char * name,const char * value)2402 script_set_env(struct client_state *client, const char *prefix,
2403     const char *name, const char *value)
2404 {
2405 	int i, namelen;
2406 	size_t j;
2407 
2408 	/* No `` or $() command substitution allowed in environment values! */
2409 	for (j=0; j < strlen(value); j++)
2410 		switch (value[j]) {
2411 		case '`':
2412 		case '$':
2413 			warning("illegal character (%c) in value '%s'",
2414 			    value[j], value);
2415 			/* Ignore this option */
2416 			return;
2417 		}
2418 
2419 	namelen = strlen(name);
2420 
2421 	for (i = 0; client->scriptEnv[i]; i++)
2422 		if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2423 		    client->scriptEnv[i][namelen] == '=')
2424 			break;
2425 
2426 	if (client->scriptEnv[i])
2427 		/* Reuse the slot. */
2428 		free(client->scriptEnv[i]);
2429 	else {
2430 		/* New variable.  Expand if necessary. */
2431 		if (i >= client->scriptEnvsize - 1) {
2432 			char **newscriptEnv;
2433 			int newscriptEnvsize = client->scriptEnvsize + 50;
2434 
2435 			newscriptEnv = realloc(client->scriptEnv,
2436 			    newscriptEnvsize);
2437 			if (newscriptEnv == NULL) {
2438 				free(client->scriptEnv);
2439 				client->scriptEnv = NULL;
2440 				client->scriptEnvsize = 0;
2441 				error("script_set_env: no memory for variable");
2442 			}
2443 			client->scriptEnv = newscriptEnv;
2444 			client->scriptEnvsize = newscriptEnvsize;
2445 		}
2446 		/* need to set the NULL pointer at end of array beyond
2447 		   the new slot. */
2448 		client->scriptEnv[i + 1] = NULL;
2449 	}
2450 	/* Allocate space and format the variable in the appropriate slot. */
2451 	client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2452 	    strlen(value) + 1);
2453 	if (client->scriptEnv[i] == NULL)
2454 		error("script_set_env: no memory for variable assignment");
2455 	snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2456 	    1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2457 }
2458 
2459 void
script_flush_env(struct client_state * client)2460 script_flush_env(struct client_state *client)
2461 {
2462 	int i;
2463 
2464 	for (i = 0; client->scriptEnv[i]; i++) {
2465 		free(client->scriptEnv[i]);
2466 		client->scriptEnv[i] = NULL;
2467 	}
2468 	client->scriptEnvsize = 0;
2469 }
2470 
2471 int
dhcp_option_ev_name(char * buf,size_t buflen,struct option * option)2472 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2473 {
2474 	size_t i;
2475 
2476 	for (i = 0; option->name[i]; i++) {
2477 		if (i + 1 == buflen)
2478 			return 0;
2479 		if (option->name[i] == '-')
2480 			buf[i] = '_';
2481 		else
2482 			buf[i] = option->name[i];
2483 	}
2484 
2485 	buf[i] = 0;
2486 	return 1;
2487 }
2488 
2489 void
go_daemon(void)2490 go_daemon(void)
2491 {
2492 	static int state = 0;
2493 	cap_rights_t rights;
2494 
2495 	if (no_daemon || state)
2496 		return;
2497 
2498 	state = 1;
2499 
2500 	/* Stop logging to stderr... */
2501 	log_perror = 0;
2502 
2503 	if (daemonfd(-1, nullfd) == -1)
2504 		error("daemon");
2505 
2506 	cap_rights_init(&rights);
2507 
2508 	if (pidfile != NULL) {
2509 		pidfile_write(pidfile);
2510 
2511 		if (caph_rights_limit(pidfile_fileno(pidfile), &rights) < 0)
2512 			error("can't limit pidfile descriptor: %m");
2513 	}
2514 
2515 	if (nullfd != -1) {
2516 		close(nullfd);
2517 		nullfd = -1;
2518 	}
2519 
2520 	if (caph_rights_limit(STDIN_FILENO, &rights) < 0)
2521 		error("can't limit stdin: %m");
2522 	cap_rights_init(&rights, CAP_WRITE);
2523 	if (caph_rights_limit(STDOUT_FILENO, &rights) < 0)
2524 		error("can't limit stdout: %m");
2525 	if (caph_rights_limit(STDERR_FILENO, &rights) < 0)
2526 		error("can't limit stderr: %m");
2527 }
2528 
2529 int
check_option(struct client_lease * l,int option)2530 check_option(struct client_lease *l, int option)
2531 {
2532 	const char *opbuf;
2533 	const char *sbuf;
2534 
2535 	/* we use this, since this is what gets passed to dhclient-script */
2536 
2537 	opbuf = pretty_print_option(option, l->options[option].data,
2538 	    l->options[option].len, 0, 0);
2539 
2540 	sbuf = option_as_string(option, l->options[option].data,
2541 	    l->options[option].len);
2542 
2543 	switch (option) {
2544 	case DHO_SUBNET_MASK:
2545 	case DHO_TIME_SERVERS:
2546 	case DHO_NAME_SERVERS:
2547 	case DHO_ROUTERS:
2548 	case DHO_DOMAIN_NAME_SERVERS:
2549 	case DHO_LOG_SERVERS:
2550 	case DHO_COOKIE_SERVERS:
2551 	case DHO_LPR_SERVERS:
2552 	case DHO_IMPRESS_SERVERS:
2553 	case DHO_RESOURCE_LOCATION_SERVERS:
2554 	case DHO_SWAP_SERVER:
2555 	case DHO_BROADCAST_ADDRESS:
2556 	case DHO_NIS_SERVERS:
2557 	case DHO_NTP_SERVERS:
2558 	case DHO_NETBIOS_NAME_SERVERS:
2559 	case DHO_NETBIOS_DD_SERVER:
2560 	case DHO_FONT_SERVERS:
2561 	case DHO_DHCP_SERVER_IDENTIFIER:
2562 	case DHO_NISPLUS_SERVERS:
2563 	case DHO_MOBILE_IP_HOME_AGENT:
2564 	case DHO_SMTP_SERVER:
2565 	case DHO_POP_SERVER:
2566 	case DHO_NNTP_SERVER:
2567 	case DHO_WWW_SERVER:
2568 	case DHO_FINGER_SERVER:
2569 	case DHO_IRC_SERVER:
2570 	case DHO_STREETTALK_SERVER:
2571 	case DHO_STREETTALK_DA_SERVER:
2572 		if (!ipv4addrs(opbuf)) {
2573 			warning("Invalid IP address in option: %s", opbuf);
2574 			return (0);
2575 		}
2576 		return (1)  ;
2577 	case DHO_HOST_NAME:
2578 	case DHO_NIS_DOMAIN:
2579 	case DHO_NISPLUS_DOMAIN:
2580 	case DHO_TFTP_SERVER_NAME:
2581 		if (!res_hnok(sbuf)) {
2582 			warning("Bogus Host Name option %d: %s (%s)", option,
2583 			    sbuf, opbuf);
2584 			l->options[option].len = 0;
2585 			free(l->options[option].data);
2586 		}
2587 		return (1);
2588 	case DHO_DOMAIN_NAME:
2589 	case DHO_DOMAIN_SEARCH:
2590 		if (!res_hnok(sbuf)) {
2591 			if (!check_search(sbuf)) {
2592 				warning("Bogus domain search list %d: %s (%s)",
2593 				    option, sbuf, opbuf);
2594 				l->options[option].len = 0;
2595 				free(l->options[option].data);
2596 			}
2597 		}
2598 		return (1);
2599 	case DHO_PAD:
2600 	case DHO_TIME_OFFSET:
2601 	case DHO_BOOT_SIZE:
2602 	case DHO_MERIT_DUMP:
2603 	case DHO_ROOT_PATH:
2604 	case DHO_EXTENSIONS_PATH:
2605 	case DHO_IP_FORWARDING:
2606 	case DHO_NON_LOCAL_SOURCE_ROUTING:
2607 	case DHO_POLICY_FILTER:
2608 	case DHO_MAX_DGRAM_REASSEMBLY:
2609 	case DHO_DEFAULT_IP_TTL:
2610 	case DHO_PATH_MTU_AGING_TIMEOUT:
2611 	case DHO_PATH_MTU_PLATEAU_TABLE:
2612 	case DHO_INTERFACE_MTU:
2613 	case DHO_ALL_SUBNETS_LOCAL:
2614 	case DHO_PERFORM_MASK_DISCOVERY:
2615 	case DHO_MASK_SUPPLIER:
2616 	case DHO_ROUTER_DISCOVERY:
2617 	case DHO_ROUTER_SOLICITATION_ADDRESS:
2618 	case DHO_STATIC_ROUTES:
2619 	case DHO_TRAILER_ENCAPSULATION:
2620 	case DHO_ARP_CACHE_TIMEOUT:
2621 	case DHO_IEEE802_3_ENCAPSULATION:
2622 	case DHO_DEFAULT_TCP_TTL:
2623 	case DHO_TCP_KEEPALIVE_INTERVAL:
2624 	case DHO_TCP_KEEPALIVE_GARBAGE:
2625 	case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2626 	case DHO_NETBIOS_NODE_TYPE:
2627 	case DHO_NETBIOS_SCOPE:
2628 	case DHO_X_DISPLAY_MANAGER:
2629 	case DHO_DHCP_REQUESTED_ADDRESS:
2630 	case DHO_DHCP_LEASE_TIME:
2631 	case DHO_DHCP_OPTION_OVERLOAD:
2632 	case DHO_DHCP_MESSAGE_TYPE:
2633 	case DHO_DHCP_PARAMETER_REQUEST_LIST:
2634 	case DHO_DHCP_MESSAGE:
2635 	case DHO_DHCP_MAX_MESSAGE_SIZE:
2636 	case DHO_DHCP_RENEWAL_TIME:
2637 	case DHO_DHCP_REBINDING_TIME:
2638 	case DHO_DHCP_CLASS_IDENTIFIER:
2639 	case DHO_DHCP_CLIENT_IDENTIFIER:
2640 	case DHO_BOOTFILE_NAME:
2641 	case DHO_DHCP_USER_CLASS_ID:
2642 	case DHO_URL:
2643 	case DHO_SIP_SERVERS:
2644 	case DHO_V_I_VENDOR_CLASS:
2645 	case DHO_V_I_VENDOR_OPTS:
2646 	case DHO_END:
2647 		return (1);
2648 	case DHO_CLASSLESS_ROUTES:
2649 		return (check_classless_option(l->options[option].data,
2650 		    l->options[option].len));
2651 	default:
2652 		warning("unknown dhcp option value 0x%x", option);
2653 		return (unknown_ok);
2654 	}
2655 }
2656 
2657 /* RFC 3442 The Classless Static Routes option checks */
2658 int
check_classless_option(unsigned char * data,int len)2659 check_classless_option(unsigned char *data, int len)
2660 {
2661 	int i = 0;
2662 	unsigned char width;
2663 	in_addr_t addr, mask;
2664 
2665 	if (len < 5) {
2666 		warning("Too small length: %d", len);
2667 		return (0);
2668 	}
2669 	while(i < len) {
2670 		width = data[i++];
2671 		if (width == 0) {
2672 			i += 4;
2673 			continue;
2674 		} else if (width < 9) {
2675 			addr =  (in_addr_t)(data[i]	<< 24);
2676 			i += 1;
2677 		} else if (width < 17) {
2678 			addr =  (in_addr_t)(data[i]	<< 24) +
2679 				(in_addr_t)(data[i + 1]	<< 16);
2680 			i += 2;
2681 		} else if (width < 25) {
2682 			addr =  (in_addr_t)(data[i]	<< 24) +
2683 				(in_addr_t)(data[i + 1]	<< 16) +
2684 				(in_addr_t)(data[i + 2]	<< 8);
2685 			i += 3;
2686 		} else if (width < 33) {
2687 			addr =  (in_addr_t)(data[i]	<< 24) +
2688 				(in_addr_t)(data[i + 1]	<< 16) +
2689 				(in_addr_t)(data[i + 2]	<< 8)  +
2690 				data[i + 3];
2691 			i += 4;
2692 		} else {
2693 			warning("Incorrect subnet width: %d", width);
2694 			return (0);
2695 		}
2696 		mask = (in_addr_t)(~0) << (32 - width);
2697 		addr = ntohl(addr);
2698 		mask = ntohl(mask);
2699 
2700 		/*
2701 		 * From RFC 3442:
2702 		 * ... After deriving a subnet number and subnet mask
2703 		 * from each destination descriptor, the DHCP client
2704 		 * MUST zero any bits in the subnet number where the
2705 		 * corresponding bit in the mask is zero...
2706 		 */
2707 		if ((addr & mask) != addr) {
2708 			addr &= mask;
2709 			data[i - 1] = (unsigned char)(
2710 				(addr >> (((32 - width)/8)*8)) & 0xFF);
2711 		}
2712 		i += 4;
2713 	}
2714 	if (i > len) {
2715 		warning("Incorrect data length: %d (must be %d)", len, i);
2716 		return (0);
2717 	}
2718 	return (1);
2719 }
2720 
2721 int
res_hnok(const char * dn)2722 res_hnok(const char *dn)
2723 {
2724 	int pch = PERIOD, ch = *dn++;
2725 
2726 	while (ch != '\0') {
2727 		int nch = *dn++;
2728 
2729 		if (periodchar(ch)) {
2730 			;
2731 		} else if (periodchar(pch)) {
2732 			if (!borderchar(ch))
2733 				return (0);
2734 		} else if (periodchar(nch) || nch == '\0') {
2735 			if (!borderchar(ch))
2736 				return (0);
2737 		} else {
2738 			if (!middlechar(ch))
2739 				return (0);
2740 		}
2741 		pch = ch, ch = nch;
2742 	}
2743 	return (1);
2744 }
2745 
2746 int
check_search(const char * srch)2747 check_search(const char *srch)
2748 {
2749         int pch = PERIOD, ch = *srch++;
2750 	int domains = 1;
2751 
2752 	/* 256 char limit re resolv.conf(5) */
2753 	if (strlen(srch) > 256)
2754 		return (0);
2755 
2756 	while (whitechar(ch))
2757 		ch = *srch++;
2758 
2759         while (ch != '\0') {
2760                 int nch = *srch++;
2761 
2762                 if (periodchar(ch) || whitechar(ch)) {
2763                         ;
2764                 } else if (periodchar(pch)) {
2765                         if (!borderchar(ch))
2766                                 return (0);
2767                 } else if (periodchar(nch) || nch == '\0') {
2768                         if (!borderchar(ch))
2769                                 return (0);
2770                 } else {
2771                         if (!middlechar(ch))
2772                                 return (0);
2773                 }
2774 		if (!whitechar(ch)) {
2775 			pch = ch;
2776 		} else {
2777 			while (whitechar(nch)) {
2778 				nch = *srch++;
2779 			}
2780 			if (nch != '\0')
2781 				domains++;
2782 			pch = PERIOD;
2783 		}
2784 		ch = nch;
2785         }
2786 	/* 6 domain limit re resolv.conf(5) */
2787 	if (domains > 6)
2788 		return (0);
2789         return (1);
2790 }
2791 
2792 /* Does buf consist only of dotted decimal ipv4 addrs?
2793  * return how many if so,
2794  * otherwise, return 0
2795  */
2796 int
ipv4addrs(const char * buf)2797 ipv4addrs(const char * buf)
2798 {
2799 	struct in_addr jnk;
2800 	int count = 0;
2801 
2802 	while (inet_aton(buf, &jnk) == 1){
2803 		count++;
2804 		while (periodchar(*buf) || digitchar(*buf))
2805 			buf++;
2806 		if (*buf == '\0')
2807 			return (count);
2808 		while (*buf ==  ' ')
2809 			buf++;
2810 	}
2811 	return (0);
2812 }
2813 
2814 
2815 const char *
option_as_string(unsigned int code,unsigned char * data,int len)2816 option_as_string(unsigned int code, unsigned char *data, int len)
2817 {
2818 	static char optbuf[32768]; /* XXX */
2819 	char *op = optbuf;
2820 	int opleft = sizeof(optbuf);
2821 	unsigned char *dp = data;
2822 
2823 	if (code > 255)
2824 		error("option_as_string: bad code %d", code);
2825 
2826 	for (; dp < data + len; dp++) {
2827 		if (!isascii(*dp) || !isprint(*dp)) {
2828 			if (dp + 1 != data + len || *dp != 0) {
2829 				snprintf(op, opleft, "\\%03o", *dp);
2830 				op += 4;
2831 				opleft -= 4;
2832 			}
2833 		} else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2834 		    *dp == '`' || *dp == '\\') {
2835 			*op++ = '\\';
2836 			*op++ = *dp;
2837 			opleft -= 2;
2838 		} else {
2839 			*op++ = *dp;
2840 			opleft--;
2841 		}
2842 	}
2843 	if (opleft < 1)
2844 		goto toobig;
2845 	*op = 0;
2846 	return optbuf;
2847 toobig:
2848 	warning("dhcp option too large");
2849 	return "<error>";
2850 }
2851 
2852 int
fork_privchld(int fd,int fd2)2853 fork_privchld(int fd, int fd2)
2854 {
2855 	struct pollfd pfd[1];
2856 	int nfds;
2857 
2858 	switch (fork()) {
2859 	case -1:
2860 		error("cannot fork");
2861 	case 0:
2862 		break;
2863 	default:
2864 		return (0);
2865 	}
2866 
2867 	setproctitle("%s [priv]", ifi->name);
2868 
2869 	setsid();
2870 	dup2(nullfd, STDIN_FILENO);
2871 	dup2(nullfd, STDOUT_FILENO);
2872 	dup2(nullfd, STDERR_FILENO);
2873 	close(nullfd);
2874 	close(fd2);
2875 	close(ifi->rfdesc);
2876 	ifi->rfdesc = -1;
2877 
2878 	for (;;) {
2879 		pfd[0].fd = fd;
2880 		pfd[0].events = POLLIN;
2881 		if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2882 			if (errno != EINTR)
2883 				error("poll error");
2884 
2885 		if (nfds == 0 || !(pfd[0].revents & POLLIN))
2886 			continue;
2887 
2888 		dispatch_imsg(ifi, fd);
2889 	}
2890 }
2891