Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / dhcpcd / dist / configure.c
blob3e6dc98f1620868db4ecba6333c2ec98c53cee0d
1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
4 * All rights reserved
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include <sys/stat.h>
29 #include <sys/uio.h>
30 #include <sys/wait.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <unistd.h>
43 #include "config.h"
44 #include "common.h"
45 #include "configure.h"
46 #include "dhcp.h"
47 #include "if-options.h"
48 #include "if-pref.h"
49 #include "net.h"
50 #include "signals.h"
52 #define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
54 /* Some systems have route metrics */
55 #ifndef HAVE_ROUTE_METRIC
56 # ifdef __linux__
57 # define HAVE_ROUTE_METRIC 1
58 # endif
59 # ifndef HAVE_ROUTE_METRIC
60 # define HAVE_ROUTE_METRIC 0
61 # endif
62 #endif
64 static struct rt *routes;
67 static int
68 exec_script(char *const *argv, char *const *env)
70 pid_t pid;
71 sigset_t full;
72 sigset_t old;
74 /* OK, we need to block signals */
75 sigfillset(&full);
76 sigprocmask(SIG_SETMASK, &full, &old);
77 signal_reset();
79 switch (pid = vfork()) {
80 case -1:
81 syslog(LOG_ERR, "vfork: %m");
82 break;
83 case 0:
84 sigprocmask(SIG_SETMASK, &old, NULL);
85 execve(argv[0], argv, env);
86 syslog(LOG_ERR, "%s: %m", argv[0]);
87 _exit(127);
88 /* NOTREACHED */
91 /* Restore our signals */
92 signal_setup();
93 sigprocmask(SIG_SETMASK, &old, NULL);
94 return pid;
97 static char *
98 make_var(const char *prefix, const char *var)
100 size_t len;
101 char *v;
103 len = strlen(prefix) + strlen(var) + 2;
104 v = xmalloc(len);
105 snprintf(v, len, "%s_%s", prefix, var);
106 return v;
110 static void
111 append_config(char ***env, ssize_t *len,
112 const char *prefix, const char *const *config)
114 ssize_t i, j, e1;
115 char **ne, *eq;
117 if (config == NULL)
118 return;
120 ne = *env;
121 for (i = 0; config[i] != NULL; i++) {
122 eq = strchr(config[i], '=');
123 e1 = eq - config[i] + 1;
124 for (j = 0; j < *len; j++) {
125 if (strncmp(ne[j] + strlen(prefix) + 1,
126 config[i], e1) == 0)
128 free(ne[j]);
129 ne[j] = make_var(prefix, config[i]);
130 break;
133 if (j == *len) {
134 j++;
135 ne = xrealloc(ne, sizeof(char *) * (j + 1));
136 ne[j - 1] = make_var(prefix, config[i]);
137 *len = j;
140 *env = ne;
143 static size_t
144 arraytostr(const char *const *argv, char **s)
146 const char *const *ap;
147 char *p;
148 size_t len, l;
150 len = 0;
151 ap = argv;
152 while (*ap)
153 len += strlen(*ap++) + 1;
154 *s = p = xmalloc(len);
155 ap = argv;
156 while (*ap) {
157 l = strlen(*ap) + 1;
158 memcpy(p, *ap, l);
159 p += l;
160 ap++;
162 return len;
165 static ssize_t
166 make_env(const struct interface *iface, char ***argv)
168 char **env, *p;
169 ssize_t e, elen, l;
170 const struct if_options *ifo = iface->state->options;
171 const struct interface *ifp;
173 /* Make our env */
174 elen = 8;
175 env = xmalloc(sizeof(char *) * (elen + 1));
176 e = strlen("interface") + strlen(iface->name) + 2;
177 env[0] = xmalloc(e);
178 snprintf(env[0], e, "interface=%s", iface->name);
179 e = strlen("reason") + strlen(iface->state->reason) + 2;
180 env[1] = xmalloc(e);
181 snprintf(env[1], e, "reason=%s", iface->state->reason);
182 e = 20;
183 env[2] = xmalloc(e);
184 snprintf(env[2], e, "pid=%d", getpid());
185 env[3] = xmalloc(e);
186 snprintf(env[3], e, "ifmetric=%d", iface->metric);
187 env[4] = xmalloc(e);
188 snprintf(env[4], e, "ifwireless=%d", iface->wireless);
189 env[5] = xmalloc(e);
190 snprintf(env[5], e, "ifflags=%u", iface->flags);
191 env[6] = xmalloc(e);
192 snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
193 l = e = strlen("interface_order=");
194 for (ifp = ifaces; ifp; ifp = ifp->next)
195 e += strlen(ifp->name) + 1;
196 p = env[7] = xmalloc(e);
197 strlcpy(p, "interface_order=", e);
198 e -= l;
199 p += l;
200 for (ifp = ifaces; ifp; ifp = ifp->next) {
201 l = strlcpy(p, ifp->name, e);
202 p += l;
203 e -= l;
204 *p++ = ' ';
205 e--;
207 *--p = '\0';
208 if (*iface->state->profile) {
209 e = strlen("profile=") + strlen(iface->state->profile) + 2;
210 env[elen] = xmalloc(e);
211 snprintf(env[elen++], e, "profile=%s", iface->state->profile);
213 if (iface->wireless) {
214 e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
215 if (iface->state->new != NULL ||
216 strcmp(iface->state->reason, "CARRIER") == 0)
218 env = xrealloc(env, sizeof(char *) * (elen + 2));
219 env[elen] = xmalloc(e);
220 snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
222 if (iface->state->old != NULL ||
223 strcmp(iface->state->reason, "NOCARRIER") == 0)
225 env = xrealloc(env, sizeof(char *) * (elen + 2));
226 env[elen] = xmalloc(e);
227 snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
230 if (iface->state->old) {
231 e = configure_env(NULL, NULL, iface->state->old, ifo);
232 if (e > 0) {
233 env = xrealloc(env, sizeof(char *) * (elen + e + 1));
234 elen += configure_env(env + elen, "old",
235 iface->state->old, ifo);
237 append_config(&env, &elen, "old",
238 (const char *const *)ifo->config);
240 if (iface->state->new) {
241 e = configure_env(NULL, NULL, iface->state->new, ifo);
242 if (e > 0) {
243 env = xrealloc(env, sizeof(char *) * (elen + e + 1));
244 elen += configure_env(env + elen, "new",
245 iface->state->new, ifo);
247 append_config(&env, &elen, "new",
248 (const char *const *)ifo->config);
251 /* Add our base environment */
252 if (ifo->environ) {
253 e = 0;
254 while (ifo->environ[e++])
256 env = xrealloc(env, sizeof(char *) * (elen + e + 1));
257 e = 0;
258 while (ifo->environ[e]) {
259 env[elen + e] = xstrdup(ifo->environ[e]);
260 e++;
262 elen += e;
264 env[elen] = '\0';
266 *argv = env;
267 return elen;
271 send_interface(int fd, const struct interface *iface)
273 char **env, **ep, *s;
274 ssize_t elen;
275 struct iovec iov[2];
276 int retval;
278 retval = 0;
279 make_env(iface, &env);
280 elen = arraytostr((const char *const *)env, &s);
281 iov[0].iov_base = &elen;
282 iov[0].iov_len = sizeof(ssize_t);
283 iov[1].iov_base = s;
284 iov[1].iov_len = elen;
285 retval = writev(fd, iov, 2);
286 ep = env;
287 while (*ep)
288 free(*ep++);
289 free(env);
290 free(s);
291 return retval;
295 run_script(const struct interface *iface)
297 char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
298 char **env = NULL, **ep;
299 char *path, *bigenv;
300 ssize_t e, elen = 0;
301 pid_t pid;
302 int status = 0;
303 const struct fd_list *fd;
304 struct iovec iov[2];
306 syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
307 iface->name, argv[0], iface->state->reason);
309 /* Make our env */
310 elen = make_env(iface, &env);
311 env = xrealloc(env, sizeof(char *) * (elen + 2));
312 /* Add path to it */
313 path = getenv("PATH");
314 if (path) {
315 e = strlen("PATH") + strlen(path) + 2;
316 env[elen] = xmalloc(e);
317 snprintf(env[elen], e, "PATH=%s", path);
318 } else
319 env[elen] = xstrdup(DEFAULT_PATH);
320 env[++elen] = '\0';
322 pid = exec_script(argv, env);
323 if (pid == -1)
324 status = -1;
325 else if (pid != 0) {
326 /* Wait for the script to finish */
327 while (waitpid(pid, &status, 0) == -1) {
328 if (errno != EINTR) {
329 syslog(LOG_ERR, "waitpid: %m");
330 status = -1;
331 break;
336 /* Send to our listeners */
337 bigenv = NULL;
338 for (fd = fds; fd != NULL; fd = fd->next) {
339 if (fd->listener) {
340 if (bigenv == NULL) {
341 elen = arraytostr((const char *const *)env,
342 &bigenv);
343 iov[0].iov_base = &elen;
344 iov[0].iov_len = sizeof(ssize_t);
345 iov[1].iov_base = bigenv;
346 iov[1].iov_len = elen;
348 if (writev(fd->fd, iov, 2) == -1)
349 syslog(LOG_ERR, "writev: %m");
352 free(bigenv);
354 /* Cleanup */
355 ep = env;
356 while (*ep)
357 free(*ep++);
358 free(env);
359 return status;
362 static struct rt *
363 find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
364 const struct rt *srt)
366 struct rt *rt;
368 if (lrt)
369 *lrt = NULL;
370 for (rt = rts; rt; rt = rt->next) {
371 if (rt->dest.s_addr == r->dest.s_addr &&
372 #if HAVE_ROUTE_METRIC
373 (srt || (!rt->iface ||
374 rt->iface->metric == r->iface->metric)) &&
375 #endif
376 (!srt || srt != rt) &&
377 rt->net.s_addr == r->net.s_addr)
378 return rt;
379 if (lrt)
380 *lrt = rt;
382 return NULL;
385 static void
386 desc_route(const char *cmd, const struct rt *rt, const char *ifname)
388 char addr[sizeof("000.000.000.000") + 1];
390 strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
391 if (rt->gate.s_addr == INADDR_ANY)
392 syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd,
393 addr, inet_ntocidr(rt->net));
394 else if (rt->gate.s_addr == rt->dest.s_addr &&
395 rt->net.s_addr == INADDR_BROADCAST)
396 syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd,
397 addr);
398 else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
399 syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd,
400 inet_ntoa(rt->gate));
401 else
402 syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd,
403 addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
406 /* If something other than dhcpcd removes a route,
407 * we need to remove it from our internal table. */
409 route_deleted(const struct rt *rt)
411 struct rt *f, *l;
413 f = find_route(routes, rt, &l, NULL);
414 if (f == NULL)
415 return 0;
416 desc_route("removing", f, f->iface->name);
417 if (l)
418 l->next = f->next;
419 else
420 routes = f->next;
421 free(f);
422 return 1;
425 static int
426 n_route(struct rt *rt, const struct interface *iface)
428 /* Don't set default routes if not asked to */
429 if (rt->dest.s_addr == 0 &&
430 rt->net.s_addr == 0 &&
431 !(iface->state->options->options & DHCPCD_GATEWAY))
432 return -1;
434 desc_route("adding", rt, iface->name);
435 if (!add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric))
436 return 0;
437 if (errno == EEXIST) {
438 /* Pretend we added the subnet route */
439 if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr) &&
440 rt->net.s_addr == iface->net.s_addr &&
441 rt->gate.s_addr == 0)
442 return 0;
443 else
444 return -1;
446 syslog(LOG_ERR, "%s: add_route: %m", iface->name);
447 return -1;
450 static int
451 c_route(struct rt *ort, struct rt *nrt, const struct interface *iface)
453 /* Don't set default routes if not asked to */
454 if (nrt->dest.s_addr == 0 &&
455 nrt->net.s_addr == 0 &&
456 !(iface->state->options->options & DHCPCD_GATEWAY))
457 return -1;
459 desc_route("changing", nrt, iface->name);
460 /* We delete and add the route so that we can change metric.
461 * This also has the nice side effect of flushing ARP entries so
462 * we don't have to do that manually. */
463 del_route(ort->iface, &ort->dest, &ort->net, &ort->gate,
464 ort->iface->metric);
465 if (!add_route(iface, &nrt->dest, &nrt->net, &nrt->gate,
466 iface->metric))
467 return 0;
468 syslog(LOG_ERR, "%s: add_route: %m", iface->name);
469 return -1;
472 static int
473 d_route(struct rt *rt, const struct interface *iface, int metric)
475 int retval;
477 desc_route("deleting", rt, iface->name);
478 retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
479 if (retval != 0 && errno != ENOENT && errno != ESRCH)
480 syslog(LOG_ERR,"%s: del_route: %m", iface->name);
481 return retval;
484 static struct rt *
485 get_subnet_route(struct dhcp_message *dhcp)
487 in_addr_t addr;
488 struct in_addr net;
489 struct rt *rt;
491 addr = dhcp->yiaddr;
492 if (addr == 0)
493 addr = dhcp->ciaddr;
494 /* Ensure we have all the needed values */
495 if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
496 net.s_addr = get_netmask(addr);
497 if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
498 return NULL;
499 rt = malloc(sizeof(*rt));
500 rt->dest.s_addr = addr & net.s_addr;
501 rt->net.s_addr = net.s_addr;
502 rt->gate.s_addr = 0;
503 return rt;
506 static struct rt *
507 add_subnet_route(struct rt *rt, const struct interface *iface)
509 struct rt *r;
511 if (iface->net.s_addr == INADDR_BROADCAST ||
512 iface->net.s_addr == INADDR_ANY ||
513 (iface->state->options->options &
514 (DHCPCD_INFORM | DHCPCD_STATIC) &&
515 iface->state->options->req_addr.s_addr == INADDR_ANY))
516 return rt;
518 r = xmalloc(sizeof(*r));
519 r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
520 r->net.s_addr = iface->net.s_addr;
521 r->gate.s_addr = 0;
522 r->next = rt;
523 return r;
526 static struct rt *
527 get_routes(const struct interface *iface)
529 struct rt *rt, *nrt = NULL, *r = NULL;
531 if (iface->state->options->routes != NULL) {
532 for (rt = iface->state->options->routes;
533 rt != NULL;
534 rt = rt->next)
536 if (rt->gate.s_addr == 0)
537 break;
538 if (r == NULL)
539 r = nrt = xmalloc(sizeof(*r));
540 else {
541 r->next = xmalloc(sizeof(*r));
542 r = r->next;
544 memcpy(r, rt, sizeof(*r));
545 r->next = NULL;
547 return nrt;
550 return get_option_routes(iface->state->new,
551 iface->name, &iface->state->options->options);
554 static struct rt *
555 add_destination_route(struct rt *rt, const struct interface *iface)
557 struct rt *r;
559 if (!(iface->flags & IFF_POINTOPOINT) ||
560 !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
561 return rt;
562 r = xmalloc(sizeof(*r));
563 r->dest.s_addr = INADDR_ANY;
564 r->net.s_addr = INADDR_ANY;
565 r->gate.s_addr = iface->dst.s_addr;
566 r->next = rt;
567 return r;
570 void
571 build_routes(void)
573 struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
574 const struct interface *ifp;
576 for (ifp = ifaces; ifp; ifp = ifp->next) {
577 if (ifp->state->new == NULL)
578 continue;
579 dnr = get_routes(ifp);
580 dnr = add_subnet_route(dnr, ifp);
581 dnr = add_destination_route(dnr, ifp);
582 for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
583 rt->iface = ifp;
584 /* Is this route already in our table? */
585 if ((find_route(nrs, rt, NULL, NULL)) != NULL)
586 continue;
587 /* Do we already manage it? */
588 if ((or = find_route(routes, rt, &rtl, NULL))) {
589 if (or->iface != ifp ||
590 rt->gate.s_addr != or->gate.s_addr)
592 if (c_route(or, rt, ifp) != 0)
593 continue;
595 if (rtl != NULL)
596 rtl->next = or->next;
597 else
598 routes = or->next;
599 free(or);
600 } else {
601 if (n_route(rt, ifp) != 0)
602 continue;
604 if (dnr == rt)
605 dnr = rtn;
606 else if (lrt)
607 lrt->next = rtn;
608 rt->next = nrs;
609 nrs = rt;
611 free_routes(dnr);
614 /* Remove old routes we used to manage */
615 for (rt = routes; rt; rt = rt->next) {
616 if (find_route(nrs, rt, NULL, NULL) == NULL)
617 d_route(rt, rt->iface, rt->iface->metric);
620 free_routes(routes);
621 routes = nrs;
624 static int
625 delete_address(struct interface *iface)
627 int retval;
628 struct if_options *ifo;
630 ifo = iface->state->options;
631 if (ifo->options & DHCPCD_INFORM ||
632 (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
633 return 0;
634 syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
635 iface->name,
636 inet_ntoa(iface->addr),
637 inet_ntocidr(iface->net));
638 retval = del_address(iface, &iface->addr, &iface->net);
639 if (retval == -1 && errno != EADDRNOTAVAIL)
640 syslog(LOG_ERR, "del_address: %m");
641 iface->addr.s_addr = 0;
642 iface->net.s_addr = 0;
643 return retval;
647 configure(struct interface *iface)
649 struct dhcp_message *dhcp = iface->state->new;
650 struct dhcp_lease *lease = &iface->state->lease;
651 struct if_options *ifo = iface->state->options;
652 struct rt *rt;
654 /* As we are now adjusting an interface, we need to ensure
655 * we have them in the right order for routing and configuration. */
656 sort_interfaces();
658 if (dhcp == NULL) {
659 if (!(ifo->options & DHCPCD_PERSISTENT)) {
660 build_routes();
661 if (iface->addr.s_addr != 0)
662 delete_address(iface);
663 run_script(iface);
665 return 0;
668 /* This also changes netmask */
669 if (!(ifo->options & DHCPCD_INFORM) ||
670 !has_address(iface->name, &lease->addr, &lease->net))
672 syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
673 iface->name, inet_ntoa(lease->addr),
674 inet_ntocidr(lease->net));
675 if (add_address(iface,
676 &lease->addr, &lease->net, &lease->brd) == -1 &&
677 errno != EEXIST)
679 syslog(LOG_ERR, "add_address: %m");
680 return -1;
684 /* Now delete the old address if different */
685 if (iface->addr.s_addr != lease->addr.s_addr &&
686 iface->addr.s_addr != 0)
687 delete_address(iface);
689 iface->addr.s_addr = lease->addr.s_addr;
690 iface->net.s_addr = lease->net.s_addr;
692 /* We need to delete the subnet route to have our metric or
693 * prefer the interface. */
694 rt = get_subnet_route(dhcp);
695 if (rt != NULL) {
696 rt->iface = iface;
697 if (!find_route(routes, rt, NULL, NULL))
698 del_route(iface, &rt->dest, &rt->net, &rt->gate, 0);
699 free(rt);
702 build_routes();
703 if (!iface->state->lease.frominfo &&
704 !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
705 if (write_lease(iface, dhcp) == -1)
706 syslog(LOG_ERR, "write_lease: %m");
707 run_script(iface);
708 return 0;