1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Privilege Separation for dhcpcd, privileged actioneer
4 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
33 #include <sys/types.h>
59 __CTASSERT(sizeof(ioctl_request_t
) <= sizeof(unsigned long));
65 char psr_pad
[sizeof(ssize_t
) - sizeof(int)];
70 struct dhcpcd_ctx
*psr_ctx
;
71 struct psr_error psr_error
;
77 ps_root_readerrorsig(__unused
int sig
, void *arg
)
79 struct dhcpcd_ctx
*ctx
= arg
;
81 eloop_exit(ctx
->ps_eloop
, EXIT_FAILURE
);
85 ps_root_readerrorcb(void *arg
)
87 struct psr_ctx
*psr_ctx
= arg
;
88 struct dhcpcd_ctx
*ctx
= psr_ctx
->psr_ctx
;
89 struct psr_error
*psr_error
= &psr_ctx
->psr_error
;
90 struct iovec iov
[] = {
91 { .iov_base
= psr_error
, .iov_len
= sizeof(*psr_error
) },
92 { .iov_base
= psr_ctx
->psr_data
,
93 .iov_len
= psr_ctx
->psr_datalen
},
96 int exit_code
= EXIT_FAILURE
;
98 #define PSR_ERROR(e) \
100 psr_error->psr_result = -1; \
101 psr_error->psr_errno = (e); \
103 } while (0 /* CONSTCOND */)
105 len
= readv(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
108 else if ((size_t)len
< sizeof(*psr_error
))
110 exit_code
= EXIT_SUCCESS
;
113 eloop_exit(ctx
->ps_eloop
, exit_code
);
117 ps_root_readerror(struct dhcpcd_ctx
*ctx
, void *data
, size_t len
)
119 struct psr_ctx psr_ctx
= {
121 .psr_data
= data
, .psr_datalen
= len
,
124 if (eloop_event_add(ctx
->ps_eloop
, ctx
->ps_root_fd
,
125 ps_root_readerrorcb
, &psr_ctx
) == -1)
128 eloop_enter(ctx
->ps_eloop
);
129 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
131 errno
= psr_ctx
.psr_error
.psr_errno
;
132 return psr_ctx
.psr_error
.psr_result
;
135 #ifdef PRIVSEP_GETIFADDRS
137 ps_root_mreaderrorcb(void *arg
)
139 struct psr_ctx
*psr_ctx
= arg
;
140 struct dhcpcd_ctx
*ctx
= psr_ctx
->psr_ctx
;
141 struct psr_error
*psr_error
= &psr_ctx
->psr_error
;
142 struct iovec iov
[] = {
143 { .iov_base
= psr_error
, .iov_len
= sizeof(*psr_error
) },
144 { .iov_base
= NULL
, .iov_len
= 0 },
147 int exit_code
= EXIT_FAILURE
;
149 len
= recv(ctx
->ps_root_fd
, psr_error
, sizeof(*psr_error
), MSG_PEEK
);
152 else if ((size_t)len
< sizeof(*psr_error
))
155 if (psr_error
->psr_datalen
> SSIZE_MAX
)
157 else if (psr_error
->psr_datalen
!= 0) {
158 psr_ctx
->psr_data
= malloc(psr_error
->psr_datalen
);
159 if (psr_ctx
->psr_data
== NULL
)
161 psr_ctx
->psr_datalen
= psr_error
->psr_datalen
;
162 iov
[1].iov_base
= psr_ctx
->psr_data
;
163 iov
[1].iov_len
= psr_ctx
->psr_datalen
;
166 len
= readv(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
169 else if ((size_t)len
!= sizeof(*psr_error
) + psr_ctx
->psr_datalen
)
171 exit_code
= EXIT_SUCCESS
;
174 eloop_exit(ctx
->ps_eloop
, exit_code
);
178 ps_root_mreaderror(struct dhcpcd_ctx
*ctx
, void **data
, size_t *len
)
180 struct psr_ctx psr_ctx
= {
184 if (eloop_event_add(ctx
->ps_eloop
, ctx
->ps_root_fd
,
185 ps_root_mreaderrorcb
, &psr_ctx
) == -1)
188 eloop_enter(ctx
->ps_eloop
);
189 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
191 errno
= psr_ctx
.psr_error
.psr_errno
;
192 *data
= psr_ctx
.psr_data
;
193 *len
= psr_ctx
.psr_datalen
;
194 return psr_ctx
.psr_error
.psr_result
;
199 ps_root_writeerror(struct dhcpcd_ctx
*ctx
, ssize_t result
,
200 void *data
, size_t len
)
202 struct psr_error psr
= {
203 .psr_result
= result
,
207 struct iovec iov
[] = {
208 { .iov_base
= &psr
, .iov_len
= sizeof(psr
) },
209 { .iov_base
= data
, .iov_len
= len
},
213 logdebugx("%s: result %zd errno %d", __func__
, result
, errno
);
216 return writev(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
220 ps_root_doioctl(unsigned long req
, void *data
, size_t len
)
224 /* Only allow these ioctls */
227 case SIOCAIFADDR
: /* FALLTHROUGH */
228 case SIOCDIFADDR
: /* FALLTHROUGH */
231 case SIOCSIFHWADDR
: /* FALLTHROUGH */
233 #ifdef SIOCGIFPRIORITY
234 case SIOCGIFPRIORITY
: /* FALLTHROUGH */
236 case SIOCSIFFLAGS
: /* FALLTHROUGH */
237 case SIOCGIFMTU
: /* FALLTHROUGH */
245 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
247 #ifdef IOCTL_REQUEST_TYPE
249 ioctl_request_t reqt
;
251 memcpy(&reqt
, &req
, sizeof(reqt
));
252 err
= ioctl(s
, reqt
, data
, len
);
255 err
= ioctl(s
, req
, data
, len
);
265 ps_root_run_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
267 const char *envbuf
= data
;
268 char * const argv
[] = { ctx
->script
, NULL
};
275 if (script_buftoenv(ctx
, UNCONST(envbuf
), len
) == NULL
)
278 pid
= script_exec(argv
, ctx
->script_env
);
281 /* Wait for the script to finish */
282 while (waitpid(pid
, &status
, 0) == -1) {
283 if (errno
!= EINTR
) {
293 ps_root_validpath(const struct dhcpcd_ctx
*ctx
, uint16_t cmd
, const char *path
)
296 /* Avoid a previous directory attack to avoid /proc/../
297 * dhcpcd should never use a path with double dots. */
298 if (strstr(path
, "..") != NULL
)
301 if (cmd
== PS_READFILE
) {
302 #ifdef EMBEDDED_CONFIG
303 if (strcmp(ctx
->cffile
, EMBEDDED_CONFIG
) == 0)
306 if (strcmp(ctx
->cffile
, path
) == 0)
309 if (strncmp(DBDIR
, path
, strlen(DBDIR
)) == 0)
311 if (strncmp(RUNDIR
, path
, strlen(RUNDIR
)) == 0)
315 if (strncmp("/proc/net/", path
, strlen("/proc/net/")) == 0 ||
316 strncmp("/proc/sys/net/", path
, strlen("/proc/sys/net/")) == 0 ||
317 strncmp("/sys/class/net/", path
, strlen("/sys/class/net/")) == 0)
326 ps_root_dowritefile(const struct dhcpcd_ctx
*ctx
,
327 mode_t mode
, void *data
, size_t len
)
329 char *file
= data
, *nc
;
331 nc
= memchr(file
, '\0', len
);
337 if (!ps_root_validpath(ctx
, PS_WRITEFILE
, file
))
340 return writefile(file
, mode
, nc
, len
- (size_t)(nc
- file
));
345 ps_root_monordm(uint64_t *rdm
, size_t len
)
348 if (len
!= sizeof(*rdm
)) {
352 return auth_get_rdm_monotonic(rdm
);
356 #ifdef PRIVSEP_GETIFADDRS
359 ps_root_dogetifaddrs(void **rdata
, size_t *rlen
)
361 struct ifaddrs
*ifaddrs
, *ifa
, *ifa_next
;
367 if (getifaddrs(&ifaddrs
) == -1)
369 if (ifaddrs
== NULL
) {
375 /* Work out the buffer length required.
376 * Ensure everything is aligned correctly, which does
377 * create a larger buffer than what is needed to send,
378 * but makes creating the same structure in the client
381 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
382 len
+= ALIGN(sizeof(*ifa
));
383 len
+= ALIGN(IFNAMSIZ
);
384 len
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
385 if (ifa
->ifa_addr
!= NULL
)
386 len
+= ALIGN(sa_len(ifa
->ifa_addr
));
387 if (ifa
->ifa_netmask
!= NULL
)
388 len
+= ALIGN(sa_len(ifa
->ifa_netmask
));
389 if (ifa
->ifa_broadaddr
!= NULL
)
390 len
+= ALIGN(sa_len(ifa
->ifa_broadaddr
));
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
);
398 freeifaddrs(ifaddrs
);
404 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
405 /* Don't carry ifa_data or ifa_next. */
406 ifa_data
= ifa
->ifa_data
;
407 ifa_next
= ifa
->ifa_next
;
408 ifa
->ifa_data
= NULL
;
409 ifa
->ifa_next
= NULL
;
410 memcpy(buf
, ifa
, sizeof(*ifa
));
411 buf
+= ALIGN(sizeof(*ifa
));
412 ifa
->ifa_data
= ifa_data
;
413 ifa
->ifa_next
= ifa_next
;
415 strlcpy((char *)buf
, ifa
->ifa_name
, IFNAMSIZ
);
416 buf
+= ALIGN(IFNAMSIZ
);
418 buf
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
420 #define COPYINSA(addr) \
422 salen = sa_len((addr)); \
424 memcpy(sap, &salen, sizeof(salen)); \
425 memcpy(buf, (addr), salen); \
426 buf += ALIGN(salen); \
428 sap += sizeof(salen); \
429 } while (0 /*CONSTCOND */)
431 if (ifa
->ifa_addr
!= NULL
)
432 COPYINSA(ifa
->ifa_addr
);
433 if (ifa
->ifa_netmask
!= NULL
)
434 COPYINSA(ifa
->ifa_netmask
);
435 if (ifa
->ifa_broadaddr
!= NULL
)
436 COPYINSA(ifa
->ifa_broadaddr
);
439 freeifaddrs(ifaddrs
);
445 ps_root_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
447 struct dhcpcd_ctx
*ctx
= arg
;
449 struct ps_process
*psp
;
450 struct iovec
*iov
= msg
->msg_iov
;
451 void *data
= iov
->iov_base
, *rdata
= NULL
;
452 size_t len
= iov
->iov_len
, rlen
= 0;
453 uint8_t buf
[PS_BUFLEN
];
456 bool free_rdata
= false;
458 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
459 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
462 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
466 if (psm
->ps_cmd
& PS_STOP
) {
467 int ret
= ps_dostop(ctx
, &psp
->psp_pid
, &psp
->psp_fd
);
471 } else if (psm
->ps_cmd
& PS_START
) {
472 /* Process has already started .... */
476 err
= ps_sendpsmmsg(ctx
, psp
->psp_fd
, psm
, msg
);
478 logerr("%s: failed to send message to pid %d",
479 __func__
, psp
->psp_pid
);
480 shutdown(psp
->psp_fd
, SHUT_RDWR
);
488 if (psm
->ps_cmd
& PS_STOP
&& psp
== NULL
)
494 case PS_BPF_ARP
: /* FALLTHROUGH */
497 return ps_bpf_cmd(ctx
, psm
, msg
);
501 return ps_inet_cmd(ctx
, psm
, msg
);
505 case PS_DHCP6
: /* FALLTHROUGH */
508 return ps_inet_cmd(ctx
, psm
, msg
);
514 assert(msg
->msg_iovlen
== 0 || msg
->msg_iovlen
== 1);
519 switch (psm
->ps_cmd
) {
521 err
= ps_root_doioctl(psm
->ps_flags
, data
, len
);
528 err
= ps_root_run_script(ctx
, data
, len
);
531 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
538 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
542 err
= readfile(data
, buf
, sizeof(buf
));
549 err
= ps_root_dowritefile(ctx
, (mode_t
)psm
->ps_flags
,
553 err
= filemtime(data
, &mtime
);
556 rlen
= sizeof(mtime
);
560 case PS_AUTH_MONORDM
:
561 err
= ps_root_monordm(data
, len
);
568 #ifdef PRIVSEP_GETIFADDRS
570 err
= ps_root_dogetifaddrs(&rdata
, &rlen
);
574 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
575 case PS_IP6FORWARDING
:
576 err
= ip6_forwarding(data
);
581 err
= dev_initialized(ctx
, data
);
583 case PS_DEV_LISTENING
:
584 err
= dev_listening(ctx
);
588 err
= ps_root_os(psm
, msg
, &rdata
, &rlen
);
592 err
= ps_root_writeerror(ctx
, err
, rlen
!= 0 ? rdata
: 0, rlen
);
598 /* Receive from state engine, do an action. */
600 ps_root_recvmsg(void *arg
)
602 struct dhcpcd_ctx
*ctx
= arg
;
604 if (ps_recvpsmsg(ctx
, ctx
->ps_root_fd
, ps_root_recvmsgcb
, ctx
) == -1)
610 ps_root_handleinterface(void *arg
, int action
, const char *ifname
)
612 struct dhcpcd_ctx
*ctx
= arg
;
616 flag
= PS_DEV_IFADDED
;
617 else if (action
== -1)
618 flag
= PS_DEV_IFREMOVED
;
619 else if (action
== 0)
620 flag
= PS_DEV_IFUPDATED
;
626 return (int)ps_sendcmd(ctx
, ctx
->ps_data_fd
, PS_DEV_IFCMD
, flag
,
627 ifname
, strlen(ifname
) + 1);
632 ps_root_startcb(void *arg
)
634 struct dhcpcd_ctx
*ctx
= arg
;
636 if (ctx
->options
& DHCPCD_MASTER
)
637 setproctitle("[privileged actioneer]");
639 setproctitle("[privileged actioneer] %s%s%s",
641 ctx
->options
& DHCPCD_IPV4
? " [ip4]" : "",
642 ctx
->options
& DHCPCD_IPV6
? " [ip6]" : "");
643 ctx
->ps_root_pid
= getpid();
644 ctx
->options
|= DHCPCD_PRIVSEPROOT
;
646 /* Open network sockets for sending.
647 * This is a small bit wasteful for non sandboxed OS's
648 * but makes life very easy for unicasting DHCPv6 in non master
649 * mode as we no longer care about address selection. */
651 if (ctx
->options
& DHCPCD_IPV4
) {
652 ctx
->udp_wfd
= xsocket(PF_INET
,
653 SOCK_RAW
| SOCK_CXNB
, IPPROTO_UDP
);
654 if (ctx
->udp_wfd
== -1)
655 logerr("%s: dhcp_openraw", __func__
);
659 if (ctx
->options
& DHCPCD_IPV6
) {
660 ctx
->nd_fd
= ipv6nd_open(false);
661 if (ctx
->nd_fd
== -1)
662 logerr("%s: ipv6nd_open", __func__
);
666 if (ctx
->options
& DHCPCD_IPV6
) {
667 ctx
->dhcp6_wfd
= dhcp6_openraw();
668 if (ctx
->dhcp6_wfd
== -1)
669 logerr("%s: dhcp6_openraw", __func__
);
674 /* Start any dev listening plugin which may want to
675 * change the interface name provided by the kernel */
676 if ((ctx
->options
& (DHCPCD_MASTER
| DHCPCD_DEV
)) ==
677 (DHCPCD_MASTER
| DHCPCD_DEV
))
678 dev_start(ctx
, ps_root_handleinterface
);
685 ps_root_signalcb(int sig
, void *arg
)
687 struct dhcpcd_ctx
*ctx
= arg
;
689 /* Ignore SIGINT, respect PS_STOP command or SIGTERM. */
694 if (sig
== SIGCHLD
) {
695 while (waitpid(-1, NULL
, WNOHANG
) > 0)
700 logerrx("process %d unexpectedly terminating on signal %d",
702 if (ctx
->ps_root_pid
== getpid()) {
703 shutdown(ctx
->ps_root_fd
, SHUT_RDWR
);
704 shutdown(ctx
->ps_data_fd
, SHUT_RDWR
);
706 eloop_exit(ctx
->eloop
, sig
== SIGTERM
? EXIT_SUCCESS
: EXIT_FAILURE
);
709 int (*handle_interface
)(void *, int, const char *);
713 ps_root_devcb(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
716 struct iovec
*iov
= msg
->msg_iov
;
718 if (msg
->msg_iovlen
!= 1) {
723 switch(psm
->ps_flags
) {
727 case PS_DEV_IFREMOVED
:
730 case PS_DEV_IFUPDATED
:
738 return dhcpcd_handleinterface(ctx
, action
, iov
->iov_base
);
743 ps_root_dispatchcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
745 struct dhcpcd_ctx
*ctx
= arg
;
748 switch(psm
->ps_cmd
) {
751 err
= ps_root_devcb(ctx
, psm
, msg
);
756 err
= ps_bpf_dispatch(ctx
, psm
, msg
);
757 if (err
== -1 && errno
== ENOTSUP
)
759 err
= ps_inet_dispatch(ctx
, psm
, msg
);
765 ps_root_dispatch(void *arg
)
767 struct dhcpcd_ctx
*ctx
= arg
;
769 if (ps_recvpsmsg(ctx
, ctx
->ps_data_fd
, ps_root_dispatchcb
, ctx
) == -1)
774 ps_root_start(struct dhcpcd_ctx
*ctx
)
779 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CXNB
, 0, fd
) == -1)
781 if (ps_setbuf_fdpair(fd
) == -1)
783 #ifdef PRIVSEP_RIGHTS
784 if (ps_rights_limit_fdpair(fd
) == -1)
788 pid
= ps_dostart(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
,
789 ps_root_recvmsg
, NULL
, ctx
,
790 ps_root_startcb
, ps_root_signalcb
, 0);
793 ctx
->ps_data_fd
= fd
[1];
796 } else if (pid
== -1)
799 ctx
->ps_data_fd
= fd
[0];
801 if (eloop_event_add(ctx
->eloop
, ctx
->ps_data_fd
,
802 ps_root_dispatch
, ctx
) == -1)
805 if ((ctx
->ps_eloop
= eloop_new()) == NULL
)
808 eloop_signal_set_cb(ctx
->ps_eloop
,
809 dhcpcd_signals
, dhcpcd_signals_len
,
810 ps_root_readerrorsig
, ctx
);
816 ps_root_stop(struct dhcpcd_ctx
*ctx
)
819 return ps_dostop(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
);
823 ps_root_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
826 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_SCRIPT
, 0, data
, len
) == -1)
828 return ps_root_readerror(ctx
, NULL
, 0);
832 ps_root_ioctl(struct dhcpcd_ctx
*ctx
, ioctl_request_t req
, void *data
,
835 #ifdef IOCTL_REQUEST_TYPE
836 unsigned long ulreq
= 0;
838 memcpy(&ulreq
, &req
, sizeof(req
));
839 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, ulreq
, data
, len
) == -1)
842 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, req
, data
, len
) == -1)
845 return ps_root_readerror(ctx
, data
, len
);
849 ps_root_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
852 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_UNLINK
, 0,
853 file
, strlen(file
) + 1) == -1)
855 return ps_root_readerror(ctx
, NULL
, 0);
859 ps_root_readfile(struct dhcpcd_ctx
*ctx
, const char *file
,
860 void *data
, size_t len
)
862 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_READFILE
, 0,
863 file
, strlen(file
) + 1) == -1)
865 return ps_root_readerror(ctx
, data
, len
);
869 ps_root_writefile(struct dhcpcd_ctx
*ctx
, const char *file
, mode_t mode
,
870 const void *data
, size_t len
)
875 flen
= strlcpy(buf
, file
, sizeof(buf
));
877 if (flen
> sizeof(buf
) || flen
+ len
> sizeof(buf
)) {
881 memcpy(buf
+ flen
, data
, len
);
883 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_WRITEFILE
, mode
,
884 buf
, flen
+ len
) == -1)
886 return ps_root_readerror(ctx
, NULL
, 0);
890 ps_root_filemtime(struct dhcpcd_ctx
*ctx
, const char *file
, time_t *time
)
893 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_FILEMTIME
, 0,
894 file
, strlen(file
) + 1) == -1)
896 return ps_root_readerror(ctx
, time
, sizeof(*time
));
899 #ifdef PRIVSEP_GETIFADDRS
901 ps_root_getifaddrs(struct dhcpcd_ctx
*ctx
, struct ifaddrs
**ifahead
)
910 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
,
911 PS_GETIFADDRS
, 0, NULL
, 0) == -1)
913 err
= ps_root_mreaderror(ctx
, &buf
, &len
);
918 /* Should be impossible - lo0 will always exist. */
925 *ifahead
= (struct ifaddrs
*)(void *)bp
;
926 for (ifa
= *ifahead
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
927 if (len
< ALIGN(sizeof(*ifa
)) +
928 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
))
930 bp
+= ALIGN(sizeof(*ifa
));
932 bp
+= ALIGN(IFNAMSIZ
);
934 bp
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
935 len
-= ALIGN(sizeof(*ifa
)) +
936 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
);
938 #define COPYOUTSA(addr) \
940 memcpy(&salen, sap, sizeof(salen)); \
944 (addr) = (struct sockaddr *)bp; \
945 bp += ALIGN(salen); \
946 len -= ALIGN(salen); \
948 sap += sizeof(salen); \
949 } while (0 /* CONSTCOND */)
951 COPYOUTSA(ifa
->ifa_addr
);
952 COPYOUTSA(ifa
->ifa_netmask
);
953 COPYOUTSA(ifa
->ifa_broadaddr
);
955 ifa
->ifa_next
= (struct ifaddrs
*)(void *)bp
;
957 ifa
->ifa_next
= NULL
;
969 #if defined(__linux__) || defined(HAVE_PLEDGE)
971 ps_root_ip6forwarding(struct dhcpcd_ctx
*ctx
, const char *ifname
)
974 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IP6FORWARDING
, 0,
975 ifname
, ifname
!= NULL
? strlen(ifname
) + 1 : 0) == -1)
977 return ps_root_readerror(ctx
, NULL
, 0);
983 ps_root_getauthrdm(struct dhcpcd_ctx
*ctx
, uint64_t *rdm
)
986 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_AUTH_MONORDM
, 0,
987 rdm
, sizeof(*rdm
))== -1)
989 return (int)ps_root_readerror(ctx
, rdm
, sizeof(*rdm
));
995 ps_root_dev_initialized(struct dhcpcd_ctx
*ctx
, const char *ifname
)
998 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_INITTED
, 0,
999 ifname
, strlen(ifname
) + 1)== -1)
1001 return (int)ps_root_readerror(ctx
, NULL
, 0);
1005 ps_root_dev_listening(struct dhcpcd_ctx
* ctx
)
1008 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_LISTENING
, 0, NULL
, 0)== -1)
1010 return (int)ps_root_readerror(ctx
, NULL
, 0);