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