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