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