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