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