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