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