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