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