Update to dhcpcd-9.4.1 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / privsep-root.c
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Privilege Separation for dhcpcd, privileged proxy
4  * Copyright (c) 2006-2021 Roy Marples <roy@marples.name>
5  * All rights reserved
6
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <signal.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include "auth.h"
47 #include "common.h"
48 #include "dev.h"
49 #include "dhcpcd.h"
50 #include "dhcp6.h"
51 #include "eloop.h"
52 #include "if.h"
53 #include "ipv6nd.h"
54 #include "logerr.h"
55 #include "privsep.h"
56 #include "sa.h"
57 #include "script.h"
58
59 __CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long));
60
61 struct psr_error
62 {
63         ssize_t psr_result;
64         int psr_errno;
65         char psr_pad[sizeof(ssize_t) - sizeof(int)];
66         size_t psr_datalen;
67 };
68
69 struct psr_ctx {
70         struct dhcpcd_ctx *psr_ctx;
71         struct psr_error psr_error;
72         size_t psr_datalen;
73         void *psr_data;
74 };
75
76 static void
77 ps_root_readerrorcb(void *arg)
78 {
79         struct psr_ctx *psr_ctx = arg;
80         struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
81         struct psr_error *psr_error = &psr_ctx->psr_error;
82         struct iovec iov[] = {
83                 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
84                 { .iov_base = psr_ctx->psr_data,
85                   .iov_len = psr_ctx->psr_datalen },
86         };
87         ssize_t len;
88         int exit_code = EXIT_FAILURE;
89
90 #define PSR_ERROR(e)                            \
91         do {                                    \
92                 psr_error->psr_result = -1;     \
93                 psr_error->psr_errno = (e);     \
94                 goto out;                       \
95         } while (0 /* CONSTCOND */)
96
97         len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
98         if (len == -1)
99                 PSR_ERROR(errno);
100         else if ((size_t)len < sizeof(*psr_error))
101                 PSR_ERROR(EINVAL);
102         exit_code = EXIT_SUCCESS;
103
104 out:
105         eloop_exit(ctx->ps_eloop, exit_code);
106 }
107
108 ssize_t
109 ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
110 {
111         struct psr_ctx psr_ctx = {
112             .psr_ctx = ctx,
113             .psr_data = data, .psr_datalen = len,
114         };
115
116         if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd,
117             ps_root_readerrorcb, &psr_ctx) == -1)
118                 return -1;
119
120         eloop_enter(ctx->ps_eloop);
121         eloop_start(ctx->ps_eloop, &ctx->sigset);
122
123         errno = psr_ctx.psr_error.psr_errno;
124         return psr_ctx.psr_error.psr_result;
125 }
126
127 #ifdef PRIVSEP_GETIFADDRS
128 static void
129 ps_root_mreaderrorcb(void *arg)
130 {
131         struct psr_ctx *psr_ctx = arg;
132         struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
133         struct psr_error *psr_error = &psr_ctx->psr_error;
134         struct iovec iov[] = {
135                 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
136                 { .iov_base = NULL, .iov_len = 0 },
137         };
138         ssize_t len;
139         int exit_code = EXIT_FAILURE;
140
141         len = recv(ctx->ps_root_fd, psr_error, sizeof(*psr_error), MSG_PEEK);
142         if (len == -1)
143                 PSR_ERROR(errno);
144         else if ((size_t)len < sizeof(*psr_error))
145                 PSR_ERROR(EINVAL);
146
147         if (psr_error->psr_datalen > SSIZE_MAX)
148                 PSR_ERROR(ENOBUFS);
149         else if (psr_error->psr_datalen != 0) {
150                 psr_ctx->psr_data = malloc(psr_error->psr_datalen);
151                 if (psr_ctx->psr_data == NULL)
152                         PSR_ERROR(errno);
153                 psr_ctx->psr_datalen = psr_error->psr_datalen;
154                 iov[1].iov_base = psr_ctx->psr_data;
155                 iov[1].iov_len = psr_ctx->psr_datalen;
156         }
157
158         len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
159         if (len == -1)
160                 PSR_ERROR(errno);
161         else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen)
162                 PSR_ERROR(EINVAL);
163         exit_code = EXIT_SUCCESS;
164
165 out:
166         eloop_exit(ctx->ps_eloop, exit_code);
167 }
168
169 ssize_t
170 ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
171 {
172         struct psr_ctx psr_ctx = {
173             .psr_ctx = ctx,
174         };
175
176         if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd,
177             ps_root_mreaderrorcb, &psr_ctx) == -1)
178                 return -1;
179
180         eloop_enter(ctx->ps_eloop);
181         eloop_start(ctx->ps_eloop, &ctx->sigset);
182
183         errno = psr_ctx.psr_error.psr_errno;
184         *data = psr_ctx.psr_data;
185         *len = psr_ctx.psr_datalen;
186         return psr_ctx.psr_error.psr_result;
187 }
188 #endif
189
190 static ssize_t
191 ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
192     void *data, size_t len)
193 {
194         struct psr_error psr = {
195                 .psr_result = result,
196                 .psr_errno = errno,
197                 .psr_datalen = len,
198         };
199         struct iovec iov[] = {
200                 { .iov_base = &psr, .iov_len = sizeof(psr) },
201                 { .iov_base = data, .iov_len = len },
202         };
203
204 #ifdef PRIVSEP_DEBUG
205         logdebugx("%s: result %zd errno %d", __func__, result, errno);
206 #endif
207
208         return writev(ctx->ps_root_fd, iov, __arraycount(iov));
209 }
210
211 static ssize_t
212 ps_root_doioctl(unsigned long req, void *data, size_t len)
213 {
214         int s, err;
215
216         /* Only allow these ioctls */
217         switch(req) {
218 #ifdef SIOCAIFADDR
219         case SIOCAIFADDR:       /* FALLTHROUGH */
220         case SIOCDIFADDR:       /* FALLTHROUGH */
221 #endif
222 #ifdef SIOCSIFHWADDR
223         case SIOCSIFHWADDR:     /* FALLTHROUGH */
224 #endif
225 #ifdef SIOCGIFPRIORITY
226         case SIOCGIFPRIORITY:   /* FALLTHROUGH */
227 #endif
228         case SIOCSIFFLAGS:      /* FALLTHROUGH */
229         case SIOCGIFMTU:        /* FALLTHROUGH */
230         case SIOCSIFMTU:
231                 break;
232         default:
233                 errno = EPERM;
234                 return -1;
235         }
236
237         s = socket(PF_INET, SOCK_DGRAM, 0);
238         if (s != -1)
239 #ifdef IOCTL_REQUEST_TYPE
240         {
241                 ioctl_request_t reqt;
242
243                 memcpy(&reqt, &req, sizeof(reqt));
244                 err = ioctl(s, reqt, data, len);
245         }
246 #else
247                 err = ioctl(s, req, data, len);
248 #endif
249         else
250                 err = -1;
251         if (s != -1)
252                 close(s);
253         return err;
254 }
255
256 static ssize_t
257 ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
258 {
259         const char *envbuf = data;
260         char * const argv[] = { ctx->script, NULL };
261         pid_t pid;
262         int status;
263
264         if (len == 0)
265                 return 0;
266
267         if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL)
268                 return -1;
269
270         pid = script_exec(argv, ctx->script_env);
271         if (pid == -1)
272                 return -1;
273         /* Wait for the script to finish */
274         while (waitpid(pid, &status, 0) == -1) {
275                 if (errno != EINTR) {
276                         logerr(__func__);
277                         status = 0;
278                         break;
279                 }
280         }
281         return status;
282 }
283
284 static bool
285 ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path)
286 {
287
288         /* Avoid a previous directory attack to avoid /proc/../
289          * dhcpcd should never use a path with double dots. */
290         if (strstr(path, "..") != NULL)
291                 return false;
292
293         if (cmd == PS_READFILE) {
294 #ifdef EMBEDDED_CONFIG
295                 if (strcmp(ctx->cffile, EMBEDDED_CONFIG) == 0)
296                         return true;
297 #endif
298                 if (strcmp(ctx->cffile, path) == 0)
299                         return true;
300         }
301         if (strncmp(DBDIR, path, strlen(DBDIR)) == 0)
302                 return true;
303         if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0)
304                 return true;
305
306 #ifdef __linux__
307         if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 ||
308             strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 ||
309             strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0)
310                 return true;
311 #endif
312
313         errno = EPERM;
314         return false;
315 }
316
317 static ssize_t
318 ps_root_dowritefile(const struct dhcpcd_ctx *ctx,
319     mode_t mode, void *data, size_t len)
320 {
321         char *file = data, *nc;
322
323         nc = memchr(file, '\0', len);
324         if (nc == NULL) {
325                 errno = EINVAL;
326                 return -1;
327         }
328
329         if (!ps_root_validpath(ctx, PS_WRITEFILE, file))
330                 return -1;
331         nc++;
332         return writefile(file, mode, nc, len - (size_t)(nc - file));
333 }
334
335 #ifdef AUTH
336 static ssize_t
337 ps_root_monordm(uint64_t *rdm, size_t len)
338 {
339
340         if (len != sizeof(*rdm)) {
341                 errno = EINVAL;
342                 return -1;
343         }
344         return auth_get_rdm_monotonic(rdm);
345 }
346 #endif
347
348 #ifdef PRIVSEP_GETIFADDRS
349 #define IFA_NADDRS      4
350 static ssize_t
351 ps_root_dogetifaddrs(void **rdata, size_t *rlen)
352 {
353         struct ifaddrs *ifaddrs, *ifa;
354         size_t len;
355         uint8_t *buf, *sap;
356         socklen_t salen;
357
358         if (getifaddrs(&ifaddrs) == -1)
359                 return -1;
360         if (ifaddrs == NULL) {
361                 *rdata = NULL;
362                 *rlen = 0;
363                 return 0;
364         }
365
366         /* Work out the buffer length required.
367          * Ensure everything is aligned correctly, which does
368          * create a larger buffer than what is needed to send,
369          * but makes creating the same structure in the client
370          * much easier. */
371         len = 0;
372         for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
373                 len += ALIGN(sizeof(*ifa));
374                 len += ALIGN(IFNAMSIZ);
375                 len += ALIGN(sizeof(salen) * IFA_NADDRS);
376                 if (ifa->ifa_addr != NULL)
377                         len += ALIGN(sa_len(ifa->ifa_addr));
378                 if (ifa->ifa_netmask != NULL)
379                         len += ALIGN(sa_len(ifa->ifa_netmask));
380                 if (ifa->ifa_broadaddr != NULL)
381                         len += ALIGN(sa_len(ifa->ifa_broadaddr));
382 #ifdef BSD
383                 /*
384                  * On BSD we need to carry ifa_data so we can access
385                  * if_data->ifi_link_state
386                  */
387                 if (ifa->ifa_addr != NULL &&
388                     ifa->ifa_addr->sa_family == AF_LINK)
389                         len += ALIGN(sizeof(struct if_data));
390 #endif
391         }
392
393         /* Use calloc to set everything to zero.
394          * This satisfies memory sanitizers because don't write
395          * where we don't need to. */
396         buf = calloc(1, len);
397         if (buf == NULL) {
398                 freeifaddrs(ifaddrs);
399                 return -1;
400         }
401         *rdata = buf;
402         *rlen = len;
403
404         for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
405                 memcpy(buf, ifa, sizeof(*ifa));
406                 buf += ALIGN(sizeof(*ifa));
407
408                 strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ);
409                 buf += ALIGN(IFNAMSIZ);
410                 sap = buf;
411                 buf += ALIGN(sizeof(salen) * IFA_NADDRS);
412
413 #define COPYINSA(addr)                                          \
414         do {                                                    \
415                 if ((addr) != NULL)                             \
416                         salen = sa_len((addr));                 \
417                 else                                            \
418                         salen = 0;                              \
419                 if (salen != 0) {                               \
420                         memcpy(sap, &salen, sizeof(salen));     \
421                         memcpy(buf, (addr), salen);             \
422                         buf += ALIGN(salen);                    \
423                 }                                               \
424                 sap += sizeof(salen);                           \
425         } while (0 /*CONSTCOND */)
426
427                 COPYINSA(ifa->ifa_addr);
428                 COPYINSA(ifa->ifa_netmask);
429                 COPYINSA(ifa->ifa_broadaddr);
430
431 #ifdef BSD
432                 if (ifa->ifa_addr != NULL &&
433                     ifa->ifa_addr->sa_family == AF_LINK)
434                 {
435                         salen = (socklen_t)sizeof(struct if_data);
436                         memcpy(buf, ifa->ifa_data, salen);
437                         buf += ALIGN(salen);
438                 } else
439 #endif
440                         salen = 0;
441                 memcpy(sap, &salen, sizeof(salen));
442         }
443
444         freeifaddrs(ifaddrs);
445         return 0;
446 }
447 #endif
448
449 static ssize_t
450 ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
451 {
452         struct dhcpcd_ctx *ctx = arg;
453         uint16_t cmd;
454         struct ps_process *psp;
455         struct iovec *iov = msg->msg_iov;
456         void *data = iov->iov_base, *rdata = NULL;
457         size_t len = iov->iov_len, rlen = 0;
458         uint8_t buf[PS_BUFLEN];
459         time_t mtime;
460         ssize_t err;
461         bool free_rdata = false;
462
463         cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
464         psp = ps_findprocess(ctx, &psm->ps_id);
465
466 #ifdef PRIVSEP_DEBUG
467         logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
468 #endif
469
470         if (psp != NULL) {
471                 if (psm->ps_cmd & PS_STOP) {
472                         int ret = ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
473
474                         ps_freeprocess(psp);
475                         return ret;
476                 } else if (psm->ps_cmd & PS_START) {
477                         /* Process has already started .... */
478                         return 0;
479                 }
480
481                 err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
482                 if (err == -1) {
483                         logerr("%s: failed to send message to pid %d",
484                             __func__, psp->psp_pid);
485                         shutdown(psp->psp_fd, SHUT_RDWR);
486                         close(psp->psp_fd);
487                         psp->psp_fd = -1;
488                         ps_freeprocess(psp);
489                 }
490                 return 0;
491         }
492
493         if (psm->ps_cmd & PS_STOP && psp == NULL)
494                 return 0;
495
496         switch (cmd) {
497 #ifdef INET
498 #ifdef ARP
499         case PS_BPF_ARP:        /* FALLTHROUGH */
500 #endif
501         case PS_BPF_BOOTP:
502                 return ps_bpf_cmd(ctx, psm, msg);
503 #endif
504 #ifdef INET
505         case PS_BOOTP:
506                 return ps_inet_cmd(ctx, psm, msg);
507 #endif
508 #ifdef INET6
509 #ifdef DHCP6
510         case PS_DHCP6:  /* FALLTHROUGH */
511 #endif
512         case PS_ND:
513                 return ps_inet_cmd(ctx, psm, msg);
514 #endif
515         default:
516                 break;
517         }
518
519         assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1);
520
521         /* Reset errno */
522         errno = 0;
523
524         switch (psm->ps_cmd) {
525         case PS_IOCTL:
526                 err = ps_root_doioctl(psm->ps_flags, data, len);
527                 if (err != -1) {
528                         rdata = data;
529                         rlen = len;
530                 }
531                 break;
532         case PS_SCRIPT:
533                 err = ps_root_run_script(ctx, data, len);
534                 break;
535         case PS_UNLINK:
536                 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
537                         err = -1;
538                         break;
539                 }
540                 err = unlink(data);
541                 break;
542         case PS_READFILE:
543                 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
544                         err = -1;
545                         break;
546                 }
547                 err = readfile(data, buf, sizeof(buf));
548                 if (err != -1) {
549                         rdata = buf;
550                         rlen = (size_t)err;
551                 }
552                 break;
553         case PS_WRITEFILE:
554                 err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags,
555                     data, len);
556                 break;
557         case PS_FILEMTIME:
558                 err = filemtime(data, &mtime);
559                 if (err != -1) {
560                         rdata = &mtime;
561                         rlen = sizeof(mtime);
562                 }
563                 break;
564         case PS_LOGREOPEN:
565                 err = logopen(ctx->logfile);
566                 break;
567 #ifdef AUTH
568         case PS_AUTH_MONORDM:
569                 err = ps_root_monordm(data, len);
570                 if (err != -1) {
571                         rdata = data;
572                         rlen = len;
573                 }
574                 break;
575 #endif
576 #ifdef PRIVSEP_GETIFADDRS
577         case PS_GETIFADDRS:
578                 err = ps_root_dogetifaddrs(&rdata, &rlen);
579                 free_rdata = true;
580                 break;
581 #endif
582 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
583         case PS_IP6FORWARDING:
584                  err = ip6_forwarding(data);
585                  break;
586 #endif
587 #ifdef PLUGIN_DEV
588         case PS_DEV_INITTED:
589                 err = dev_initialised(ctx, data);
590                 break;
591         case PS_DEV_LISTENING:
592                 err = dev_listening(ctx);
593                 break;
594 #endif
595         default:
596                 err = ps_root_os(psm, msg, &rdata, &rlen);
597                 break;
598         }
599
600         err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen);
601         if (free_rdata)
602                 free(rdata);
603         return err;
604 }
605
606 /* Receive from state engine, do an action. */
607 static void
608 ps_root_recvmsg(void *arg)
609 {
610         struct dhcpcd_ctx *ctx = arg;
611
612         if (ps_recvpsmsg(ctx, ctx->ps_root_fd, ps_root_recvmsgcb, ctx) == -1)
613                 logerr(__func__);
614 }
615
616 #ifdef PLUGIN_DEV
617 static int
618 ps_root_handleinterface(void *arg, int action, const char *ifname)
619 {
620         struct dhcpcd_ctx *ctx = arg;
621         unsigned long flag;
622
623         if (action == 1)
624                 flag = PS_DEV_IFADDED;
625         else if (action == -1)
626                 flag = PS_DEV_IFREMOVED;
627         else if (action == 0)
628                 flag = PS_DEV_IFUPDATED;
629         else {
630                 errno = EINVAL;
631                 return -1;
632         }
633
634         return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag,
635             ifname, strlen(ifname) + 1);
636 }
637 #endif
638
639 static int
640 ps_root_startcb(void *arg)
641 {
642         struct dhcpcd_ctx *ctx = arg;
643
644         if (ctx->options & DHCPCD_MANAGER)
645                 setproctitle("[privileged proxy]");
646         else
647                 setproctitle("[privileged proxy] %s%s%s",
648                     ctx->ifv[0],
649                     ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
650                     ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
651         ctx->ps_root_pid = getpid();
652         ctx->options |= DHCPCD_PRIVSEPROOT;
653
654         /* Open network sockets for sending.
655          * This is a small bit wasteful for non sandboxed OS's
656          * but makes life very easy for unicasting DHCPv6 in non manager
657          * mode as we no longer care about address selection.
658          * We can't call shutdown SHUT_RD on the socket because it's
659          * not connectd. All we can do is try and set a zero sized
660          * receive buffer and just let it overflow.
661          * Reading from it just to drain it is a waste of CPU time. */
662 #ifdef INET
663         if (ctx->options & DHCPCD_IPV4) {
664                 int buflen = 1;
665
666                 ctx->udp_wfd = xsocket(PF_INET,
667                     SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
668                 if (ctx->udp_wfd == -1)
669                         logerr("%s: dhcp_openraw", __func__);
670                 else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF,
671                     &buflen, sizeof(buflen)) == -1)
672                         logerr("%s: setsockopt SO_RCVBUF DHCP", __func__);
673         }
674 #endif
675 #ifdef INET6
676         if (ctx->options & DHCPCD_IPV6) {
677                 int buflen = 1;
678
679                 ctx->nd_fd = ipv6nd_open(false);
680                 if (ctx->nd_fd == -1)
681                         logerr("%s: ipv6nd_open", __func__);
682                 else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF,
683                     &buflen, sizeof(buflen)) == -1)
684                         logerr("%s: setsockopt SO_RCVBUF ND", __func__);
685         }
686 #endif
687 #ifdef DHCP6
688         if (ctx->options & DHCPCD_IPV6) {
689                 int buflen = 1;
690
691                 ctx->dhcp6_wfd = dhcp6_openraw();
692                 if (ctx->dhcp6_wfd == -1)
693                         logerr("%s: dhcp6_openraw", __func__);
694                 else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF,
695                     &buflen, sizeof(buflen)) == -1)
696                         logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__);
697         }
698 #endif
699
700 #ifdef PLUGIN_DEV
701         /* Start any dev listening plugin which may want to
702          * change the interface name provided by the kernel */
703         if ((ctx->options & (DHCPCD_MANAGER | DHCPCD_DEV)) ==
704             (DHCPCD_MANAGER | DHCPCD_DEV))
705                 dev_start(ctx, ps_root_handleinterface);
706 #endif
707
708         return 0;
709 }
710
711 static void
712 ps_root_signalcb(int sig, __unused void *arg)
713 {
714
715         if (sig == SIGCHLD) {
716                 while (waitpid(-1, NULL, WNOHANG) > 0)
717                         ;
718                 return;
719         }
720 }
721
722 int (*handle_interface)(void *, int, const char *);
723
724 #ifdef PLUGIN_DEV
725 static ssize_t
726 ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
727 {
728         int action;
729         struct iovec *iov = msg->msg_iov;
730
731         if (msg->msg_iovlen != 1) {
732                 errno = EINVAL;
733                 return -1;
734         }
735
736         switch(psm->ps_flags) {
737         case PS_DEV_IFADDED:
738                 action = 1;
739                 break;
740         case PS_DEV_IFREMOVED:
741                 action = -1;
742                 break;
743         case PS_DEV_IFUPDATED:
744                 action = 0;
745                 break;
746         default:
747                 errno = EINVAL;
748                 return -1;
749         }
750
751         return dhcpcd_handleinterface(ctx, action, iov->iov_base);
752 }
753 #endif
754
755 static ssize_t
756 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
757 {
758         struct dhcpcd_ctx *ctx = arg;
759         ssize_t err;
760
761         switch(psm->ps_cmd) {
762 #ifdef PLUGIN_DEV
763         case PS_DEV_IFCMD:
764                 err = ps_root_devcb(ctx, psm, msg);
765                 break;
766 #endif
767         default:
768 #ifdef INET
769                 err = ps_bpf_dispatch(ctx, psm, msg);
770                 if (err == -1 && errno == ENOTSUP)
771 #endif
772                         err = ps_inet_dispatch(ctx, psm, msg);
773         }
774         return err;
775 }
776
777 static void
778 ps_root_dispatch(void *arg)
779 {
780         struct dhcpcd_ctx *ctx = arg;
781
782         if (ps_recvpsmsg(ctx, ctx->ps_data_fd, ps_root_dispatchcb, ctx) == -1)
783                 logerr(__func__);
784 }
785
786 static void
787 ps_root_log(void *arg)
788 {
789         struct dhcpcd_ctx *ctx = arg;
790
791         if (logreadfd(ctx->ps_log_fd) == -1)
792                 logerr(__func__);
793 }
794
795 pid_t
796 ps_root_start(struct dhcpcd_ctx *ctx)
797 {
798         int logfd[2], datafd[2];
799         pid_t pid;
800
801         if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, logfd) == -1)
802                 return -1;
803 #ifdef PRIVSEP_RIGHTS
804         if (ps_rights_limit_fdpair(logfd) == -1)
805                 return -1;
806 #endif
807
808         if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, datafd) == -1)
809                 return -1;
810         if (ps_setbuf_fdpair(datafd) == -1)
811                 return -1;
812 #ifdef PRIVSEP_RIGHTS
813         if (ps_rights_limit_fdpair(datafd) == -1)
814                 return -1;
815 #endif
816
817         pid = ps_dostart(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd,
818             ps_root_recvmsg, NULL, ctx,
819             ps_root_startcb, ps_root_signalcb, 0);
820
821         if (pid == 0) {
822                 ctx->ps_log_fd = logfd[1];
823                 if (eloop_event_add(ctx->eloop, ctx->ps_log_fd,
824                     ps_root_log, ctx) == -1)
825                         return -1;
826                 close(logfd[0]);
827                 ctx->ps_data_fd = datafd[1];
828                 close(datafd[0]);
829                 return 0;
830         } else if (pid == -1)
831                 return -1;
832
833         logsetfd(logfd[0]);
834         close(logfd[1]);
835
836         ctx->ps_data_fd = datafd[0];
837         close(datafd[1]);
838         if (eloop_event_add(ctx->eloop, ctx->ps_data_fd,
839             ps_root_dispatch, ctx) == -1)
840                 return -1;
841
842         if ((ctx->ps_eloop = eloop_new()) == NULL)
843                 return -1;
844
845         eloop_signal_set_cb(ctx->ps_eloop,
846             dhcpcd_signals, dhcpcd_signals_len,
847             ps_root_signalcb, ctx);
848
849         return pid;
850 }
851
852 int
853 ps_root_stop(struct dhcpcd_ctx *ctx)
854 {
855
856         return ps_dostop(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd);
857 }
858
859 ssize_t
860 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
861 {
862
863         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1)
864                 return -1;
865         return ps_root_readerror(ctx, NULL, 0);
866 }
867
868 ssize_t
869 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
870     size_t len)
871 {
872 #ifdef IOCTL_REQUEST_TYPE
873         unsigned long ulreq = 0;
874
875         memcpy(&ulreq, &req, sizeof(req));
876         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1)
877                 return -1;
878 #else
879         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1)
880                 return -1;
881 #endif
882         return ps_root_readerror(ctx, data, len);
883 }
884
885 ssize_t
886 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
887 {
888
889         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0,
890             file, strlen(file) + 1) == -1)
891                 return -1;
892         return ps_root_readerror(ctx, NULL, 0);
893 }
894
895 ssize_t
896 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
897     void *data, size_t len)
898 {
899         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0,
900             file, strlen(file) + 1) == -1)
901                 return -1;
902         return ps_root_readerror(ctx, data, len);
903 }
904
905 ssize_t
906 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
907     const void *data, size_t len)
908 {
909         char buf[PS_BUFLEN];
910         size_t flen;
911
912         flen = strlcpy(buf, file, sizeof(buf));
913         flen += 1;
914         if (flen > sizeof(buf) || flen + len > sizeof(buf)) {
915                 errno = ENOBUFS;
916                 return -1;
917         }
918         memcpy(buf + flen, data, len);
919
920         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode,
921             buf, flen + len) == -1)
922                 return -1;
923         return ps_root_readerror(ctx, NULL, 0);
924 }
925
926 ssize_t
927 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
928 {
929
930         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0,
931             file, strlen(file) + 1) == -1)
932                 return -1;
933         return ps_root_readerror(ctx, time, sizeof(*time));
934 }
935
936 ssize_t
937 ps_root_logreopen(struct dhcpcd_ctx *ctx)
938 {
939
940         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_LOGREOPEN, 0, NULL, 0) == -1)
941                 return -1;
942         return ps_root_readerror(ctx, NULL, 0);
943 }
944
945 #ifdef PRIVSEP_GETIFADDRS
946 int
947 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
948 {
949         struct ifaddrs *ifa;
950         void *buf = NULL;
951         char *bp, *sap;
952         socklen_t salen;
953         size_t len;
954         ssize_t err;
955
956         if (ps_sendcmd(ctx, ctx->ps_root_fd,
957             PS_GETIFADDRS, 0, NULL, 0) == -1)
958                 return -1;
959         err = ps_root_mreaderror(ctx, &buf, &len);
960
961         if (err == -1)
962                 return -1;
963
964         /* Should be impossible - lo0 will always exist. */
965         if (len == 0) {
966                 *ifahead = NULL;
967                 return 0;
968         }
969
970         bp = buf;
971         *ifahead = (struct ifaddrs *)(void *)bp;
972         for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) {
973                 if (len < ALIGN(sizeof(*ifa)) +
974                     ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS))
975                         goto err;
976                 bp += ALIGN(sizeof(*ifa));
977                 ifa->ifa_name = bp;
978                 bp += ALIGN(IFNAMSIZ);
979                 sap = bp;
980                 bp += ALIGN(sizeof(salen) * IFA_NADDRS);
981                 len -= ALIGN(sizeof(*ifa)) +
982                     ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS);
983
984 #define COPYOUTSA(addr)                                         \
985         do {                                                    \
986                 memcpy(&salen, sap, sizeof(salen));             \
987                 if (len < salen)                                \
988                         goto err;                               \
989                 if (salen != 0) {                               \
990                         (addr) = (struct sockaddr *)bp;         \
991                         bp += ALIGN(salen);                     \
992                         len -= ALIGN(salen);                    \
993                 }                                               \
994                 sap += sizeof(salen);                           \
995         } while (0 /* CONSTCOND */)
996
997                 COPYOUTSA(ifa->ifa_addr);
998                 COPYOUTSA(ifa->ifa_netmask);
999                 COPYOUTSA(ifa->ifa_broadaddr);
1000
1001                 memcpy(&salen, sap, sizeof(salen));
1002                 if (len < salen)
1003                         goto err;
1004                 if (salen != 0) {
1005                         ifa->ifa_data = bp;
1006                         bp += ALIGN(salen);
1007                         len -= ALIGN(salen);
1008                 } else
1009                         ifa->ifa_data = NULL;
1010
1011                 if (len != 0)
1012                         ifa->ifa_next = (struct ifaddrs *)(void *)bp;
1013                 else
1014                         ifa->ifa_next = NULL;
1015         }
1016         return 0;
1017
1018 err:
1019         free(buf);
1020         *ifahead = NULL;
1021         errno = EINVAL;
1022         return -1;
1023 }
1024 #endif
1025
1026 #if defined(__linux__) || defined(HAVE_PLEDGE)
1027 ssize_t
1028 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
1029 {
1030
1031         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0,
1032             ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1)
1033                 return -1;
1034         return ps_root_readerror(ctx, NULL, 0);
1035 }
1036 #endif
1037
1038 #ifdef AUTH
1039 int
1040 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm)
1041 {
1042
1043         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0,
1044             rdm, sizeof(*rdm))== -1)
1045                 return -1;
1046         return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm));
1047 }
1048 #endif
1049
1050 #ifdef PLUGIN_DEV
1051 int
1052 ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname)
1053 {
1054
1055         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0,
1056             ifname, strlen(ifname) + 1)== -1)
1057                 return -1;
1058         return (int)ps_root_readerror(ctx, NULL, 0);
1059 }
1060
1061 int
1062 ps_root_dev_listening(struct dhcpcd_ctx * ctx)
1063 {
1064
1065         if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1)
1066                 return -1;
1067         return (int)ps_root_readerror(ctx, NULL, 0);
1068 }
1069 #endif