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_readerrorcb(void *arg
)
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
},
88 int exit_code
= EXIT_FAILURE
;
90 #define PSR_ERROR(e) \
92 psr_error->psr_result = -1; \
93 psr_error->psr_errno = (e); \
95 } while (0 /* CONSTCOND */)
97 len
= readv(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
100 else if ((size_t)len
< sizeof(*psr_error
))
102 exit_code
= EXIT_SUCCESS
;
105 eloop_exit(ctx
->ps_eloop
, exit_code
);
109 ps_root_readerror(struct dhcpcd_ctx
*ctx
, void *data
, size_t len
)
111 struct psr_ctx psr_ctx
= {
113 .psr_data
= data
, .psr_datalen
= len
,
116 if (eloop_event_add(ctx
->ps_eloop
, ctx
->ps_root_fd
,
117 ps_root_readerrorcb
, &psr_ctx
) == -1)
120 eloop_enter(ctx
->ps_eloop
);
121 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
123 errno
= psr_ctx
.psr_error
.psr_errno
;
124 return psr_ctx
.psr_error
.psr_result
;
127 #ifdef PRIVSEP_GETIFADDRS
129 ps_root_mreaderrorcb(void *arg
)
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 },
139 int exit_code
= EXIT_FAILURE
;
141 len
= recv(ctx
->ps_root_fd
, psr_error
, sizeof(*psr_error
), MSG_PEEK
);
144 else if ((size_t)len
< sizeof(*psr_error
))
147 if (psr_error
->psr_datalen
> SSIZE_MAX
)
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
)
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
;
158 len
= readv(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
161 else if ((size_t)len
!= sizeof(*psr_error
) + psr_ctx
->psr_datalen
)
163 exit_code
= EXIT_SUCCESS
;
166 eloop_exit(ctx
->ps_eloop
, exit_code
);
170 ps_root_mreaderror(struct dhcpcd_ctx
*ctx
, void **data
, size_t *len
)
172 struct psr_ctx psr_ctx
= {
176 if (eloop_event_add(ctx
->ps_eloop
, ctx
->ps_root_fd
,
177 ps_root_mreaderrorcb
, &psr_ctx
) == -1)
180 eloop_enter(ctx
->ps_eloop
);
181 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
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
;
191 ps_root_writeerror(struct dhcpcd_ctx
*ctx
, ssize_t result
,
192 void *data
, size_t len
)
194 struct psr_error psr
= {
195 .psr_result
= result
,
199 struct iovec iov
[] = {
200 { .iov_base
= &psr
, .iov_len
= sizeof(psr
) },
201 { .iov_base
= data
, .iov_len
= len
},
205 logdebugx("%s: result %zd errno %d", __func__
, result
, errno
);
208 return writev(ctx
->ps_root_fd
, iov
, __arraycount(iov
));
212 ps_root_doioctl(unsigned long req
, void *data
, size_t len
)
216 /* Only allow these ioctls */
219 case SIOCAIFADDR
: /* FALLTHROUGH */
220 case SIOCDIFADDR
: /* FALLTHROUGH */
223 case SIOCSIFHWADDR
: /* FALLTHROUGH */
225 #ifdef SIOCGIFPRIORITY
226 case SIOCGIFPRIORITY
: /* FALLTHROUGH */
228 case SIOCSIFFLAGS
: /* FALLTHROUGH */
229 case SIOCGIFMTU
: /* FALLTHROUGH */
237 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
239 #ifdef IOCTL_REQUEST_TYPE
241 ioctl_request_t reqt
;
243 memcpy(&reqt
, &req
, sizeof(reqt
));
244 err
= ioctl(s
, reqt
, data
, len
);
247 err
= ioctl(s
, req
, data
, len
);
257 ps_root_run_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
259 const char *envbuf
= data
;
260 char * const argv
[] = { ctx
->script
, NULL
};
267 if (script_buftoenv(ctx
, UNCONST(envbuf
), len
) == NULL
)
270 pid
= script_exec(argv
, ctx
->script_env
);
273 /* Wait for the script to finish */
274 while (waitpid(pid
, &status
, 0) == -1) {
275 if (errno
!= EINTR
) {
285 ps_root_validpath(const struct dhcpcd_ctx
*ctx
, uint16_t cmd
, const char *path
)
288 /* Avoid a previous directory attack to avoid /proc/../
289 * dhcpcd should never use a path with double dots. */
290 if (strstr(path
, "..") != NULL
)
293 if (cmd
== PS_READFILE
) {
294 #ifdef EMBEDDED_CONFIG
295 if (strcmp(ctx
->cffile
, EMBEDDED_CONFIG
) == 0)
298 if (strcmp(ctx
->cffile
, path
) == 0)
301 if (strncmp(DBDIR
, path
, strlen(DBDIR
)) == 0)
303 if (strncmp(RUNDIR
, path
, strlen(RUNDIR
)) == 0)
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)
318 ps_root_dowritefile(const struct dhcpcd_ctx
*ctx
,
319 mode_t mode
, void *data
, size_t len
)
321 char *file
= data
, *nc
;
323 nc
= memchr(file
, '\0', len
);
329 if (!ps_root_validpath(ctx
, PS_WRITEFILE
, file
))
332 return writefile(file
, mode
, nc
, len
- (size_t)(nc
- file
));
337 ps_root_monordm(uint64_t *rdm
, size_t len
)
340 if (len
!= sizeof(*rdm
)) {
344 return auth_get_rdm_monotonic(rdm
);
348 #ifdef PRIVSEP_GETIFADDRS
351 ps_root_dogetifaddrs(void **rdata
, size_t *rlen
)
353 struct ifaddrs
*ifaddrs
, *ifa
, *ifa_next
;
359 if (getifaddrs(&ifaddrs
) == -1)
361 if (ifaddrs
== NULL
) {
367 /* Work out the buffer length required.
368 * Ensure everything is aligned correctly, which does
369 * create a larger buffer than what is needed to send,
370 * but makes creating the same structure in the client
373 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
374 len
+= ALIGN(sizeof(*ifa
));
375 len
+= ALIGN(IFNAMSIZ
);
376 len
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
377 if (ifa
->ifa_addr
!= NULL
)
378 len
+= ALIGN(sa_len(ifa
->ifa_addr
));
379 if (ifa
->ifa_netmask
!= NULL
)
380 len
+= ALIGN(sa_len(ifa
->ifa_netmask
));
381 if (ifa
->ifa_broadaddr
!= NULL
)
382 len
+= ALIGN(sa_len(ifa
->ifa_broadaddr
));
385 /* Use calloc to set everything to zero.
386 * This satisfies memory sanitizers because don't write
387 * where we don't need to. */
388 buf
= calloc(1, len
);
390 freeifaddrs(ifaddrs
);
396 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
397 /* Don't carry ifa_data or ifa_next. */
398 ifa_data
= ifa
->ifa_data
;
399 ifa_next
= ifa
->ifa_next
;
400 ifa
->ifa_data
= NULL
;
401 ifa
->ifa_next
= NULL
;
402 memcpy(buf
, ifa
, sizeof(*ifa
));
403 buf
+= ALIGN(sizeof(*ifa
));
404 ifa
->ifa_data
= ifa_data
;
405 ifa
->ifa_next
= ifa_next
;
407 strlcpy((char *)buf
, ifa
->ifa_name
, IFNAMSIZ
);
408 buf
+= ALIGN(IFNAMSIZ
);
410 buf
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
412 #define COPYINSA(addr) \
414 salen = sa_len((addr)); \
416 memcpy(sap, &salen, sizeof(salen)); \
417 memcpy(buf, (addr), salen); \
418 buf += ALIGN(salen); \
420 sap += sizeof(salen); \
421 } while (0 /*CONSTCOND */)
423 if (ifa
->ifa_addr
!= NULL
)
424 COPYINSA(ifa
->ifa_addr
);
425 if (ifa
->ifa_netmask
!= NULL
)
426 COPYINSA(ifa
->ifa_netmask
);
427 if (ifa
->ifa_broadaddr
!= NULL
)
428 COPYINSA(ifa
->ifa_broadaddr
);
431 freeifaddrs(ifaddrs
);
437 ps_root_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
439 struct dhcpcd_ctx
*ctx
= arg
;
441 struct ps_process
*psp
;
442 struct iovec
*iov
= msg
->msg_iov
;
443 void *data
= iov
->iov_base
, *rdata
= NULL
;
444 size_t len
= iov
->iov_len
, rlen
= 0;
445 uint8_t buf
[PS_BUFLEN
];
448 bool free_rdata
= false;
450 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
451 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
454 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
458 if (psm
->ps_cmd
& PS_STOP
) {
459 int ret
= ps_dostop(ctx
, &psp
->psp_pid
, &psp
->psp_fd
);
463 } else if (psm
->ps_cmd
& PS_START
) {
464 /* Process has already started .... */
468 err
= ps_sendpsmmsg(ctx
, psp
->psp_fd
, psm
, msg
);
470 logerr("%s: failed to send message to pid %d",
471 __func__
, psp
->psp_pid
);
472 shutdown(psp
->psp_fd
, SHUT_RDWR
);
480 if (psm
->ps_cmd
& PS_STOP
&& psp
== NULL
)
486 case PS_BPF_ARP
: /* FALLTHROUGH */
489 return ps_bpf_cmd(ctx
, psm
, msg
);
493 return ps_inet_cmd(ctx
, psm
, msg
);
497 case PS_DHCP6
: /* FALLTHROUGH */
500 return ps_inet_cmd(ctx
, psm
, msg
);
506 assert(msg
->msg_iovlen
== 0 || msg
->msg_iovlen
== 1);
511 switch (psm
->ps_cmd
) {
513 err
= ps_root_doioctl(psm
->ps_flags
, data
, len
);
520 err
= ps_root_run_script(ctx
, data
, len
);
523 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
530 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
534 err
= readfile(data
, buf
, sizeof(buf
));
541 err
= ps_root_dowritefile(ctx
, (mode_t
)psm
->ps_flags
,
545 err
= filemtime(data
, &mtime
);
548 rlen
= sizeof(mtime
);
552 case PS_AUTH_MONORDM
:
553 err
= ps_root_monordm(data
, len
);
560 #ifdef PRIVSEP_GETIFADDRS
562 err
= ps_root_dogetifaddrs(&rdata
, &rlen
);
566 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
567 case PS_IP6FORWARDING
:
568 err
= ip6_forwarding(data
);
573 err
= dev_initialized(ctx
, data
);
575 case PS_DEV_LISTENING
:
576 err
= dev_listening(ctx
);
580 err
= ps_root_os(psm
, msg
, &rdata
, &rlen
);
584 err
= ps_root_writeerror(ctx
, err
, rlen
!= 0 ? rdata
: 0, rlen
);
590 /* Receive from state engine, do an action. */
592 ps_root_recvmsg(void *arg
)
594 struct dhcpcd_ctx
*ctx
= arg
;
596 if (ps_recvpsmsg(ctx
, ctx
->ps_root_fd
, ps_root_recvmsgcb
, ctx
) == -1)
602 ps_root_handleinterface(void *arg
, int action
, const char *ifname
)
604 struct dhcpcd_ctx
*ctx
= arg
;
608 flag
= PS_DEV_IFADDED
;
609 else if (action
== -1)
610 flag
= PS_DEV_IFREMOVED
;
611 else if (action
== 0)
612 flag
= PS_DEV_IFUPDATED
;
618 return (int)ps_sendcmd(ctx
, ctx
->ps_data_fd
, PS_DEV_IFCMD
, flag
,
619 ifname
, strlen(ifname
) + 1);
624 ps_root_startcb(void *arg
)
626 struct dhcpcd_ctx
*ctx
= arg
;
628 if (ctx
->options
& DHCPCD_MASTER
)
629 setproctitle("[privileged actioneer]");
631 setproctitle("[privileged actioneer] %s%s%s",
633 ctx
->options
& DHCPCD_IPV4
? " [ip4]" : "",
634 ctx
->options
& DHCPCD_IPV6
? " [ip6]" : "");
635 ctx
->ps_root_pid
= getpid();
636 ctx
->options
|= DHCPCD_PRIVSEPROOT
;
638 /* Open network sockets for sending.
639 * This is a small bit wasteful for non sandboxed OS's
640 * but makes life very easy for unicasting DHCPv6 in non master
641 * mode as we no longer care about address selection.
642 * We can't call shutdown SHUT_RD on the socket because it's
643 * not connectd. All we can do is try and set a zero sized
644 * receive buffer and just let it overflow.
645 * Reading from it just to drain it is a waste of CPU time. */
647 if (ctx
->options
& DHCPCD_IPV4
) {
650 ctx
->udp_wfd
= xsocket(PF_INET
,
651 SOCK_RAW
| SOCK_CXNB
, IPPROTO_UDP
);
652 if (ctx
->udp_wfd
== -1)
653 logerr("%s: dhcp_openraw", __func__
);
654 else if (setsockopt(ctx
->udp_wfd
, SOL_SOCKET
, SO_RCVBUF
,
655 &buflen
, sizeof(buflen
)) == -1)
656 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__
);
660 if (ctx
->options
& DHCPCD_IPV6
) {
663 ctx
->nd_fd
= ipv6nd_open(false);
664 if (ctx
->nd_fd
== -1)
665 logerr("%s: ipv6nd_open", __func__
);
666 else if (setsockopt(ctx
->nd_fd
, SOL_SOCKET
, SO_RCVBUF
,
667 &buflen
, sizeof(buflen
)) == -1)
668 logerr("%s: setsockopt SO_RCVBUF ND", __func__
);
672 if (ctx
->options
& DHCPCD_IPV6
) {
675 ctx
->dhcp6_wfd
= dhcp6_openraw();
676 if (ctx
->dhcp6_wfd
== -1)
677 logerr("%s: dhcp6_openraw", __func__
);
678 else if (setsockopt(ctx
->dhcp6_wfd
, SOL_SOCKET
, SO_RCVBUF
,
679 &buflen
, sizeof(buflen
)) == -1)
680 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__
);
685 /* Start any dev listening plugin which may want to
686 * change the interface name provided by the kernel */
687 if ((ctx
->options
& (DHCPCD_MASTER
| DHCPCD_DEV
)) ==
688 (DHCPCD_MASTER
| DHCPCD_DEV
))
689 dev_start(ctx
, ps_root_handleinterface
);
696 ps_root_signalcb(int sig
, __unused
void *arg
)
699 if (sig
== SIGCHLD
) {
700 while (waitpid(-1, NULL
, WNOHANG
) > 0)
706 int (*handle_interface
)(void *, int, const char *);
710 ps_root_devcb(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
713 struct iovec
*iov
= msg
->msg_iov
;
715 if (msg
->msg_iovlen
!= 1) {
720 switch(psm
->ps_flags
) {
724 case PS_DEV_IFREMOVED
:
727 case PS_DEV_IFUPDATED
:
735 return dhcpcd_handleinterface(ctx
, action
, iov
->iov_base
);
740 ps_root_dispatchcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
742 struct dhcpcd_ctx
*ctx
= arg
;
745 switch(psm
->ps_cmd
) {
748 err
= ps_root_devcb(ctx
, psm
, msg
);
753 err
= ps_bpf_dispatch(ctx
, psm
, msg
);
754 if (err
== -1 && errno
== ENOTSUP
)
756 err
= ps_inet_dispatch(ctx
, psm
, msg
);
762 ps_root_dispatch(void *arg
)
764 struct dhcpcd_ctx
*ctx
= arg
;
766 if (ps_recvpsmsg(ctx
, ctx
->ps_data_fd
, ps_root_dispatchcb
, ctx
) == -1)
771 ps_root_start(struct dhcpcd_ctx
*ctx
)
776 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CXNB
, 0, fd
) == -1)
778 if (ps_setbuf_fdpair(fd
) == -1)
780 #ifdef PRIVSEP_RIGHTS
781 if (ps_rights_limit_fdpair(fd
) == -1)
785 pid
= ps_dostart(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
,
786 ps_root_recvmsg
, NULL
, ctx
,
787 ps_root_startcb
, ps_root_signalcb
, 0);
790 ctx
->ps_data_fd
= fd
[1];
793 } else if (pid
== -1)
796 ctx
->ps_data_fd
= fd
[0];
798 if (eloop_event_add(ctx
->eloop
, ctx
->ps_data_fd
,
799 ps_root_dispatch
, ctx
) == -1)
802 if ((ctx
->ps_eloop
= eloop_new()) == NULL
)
805 eloop_signal_set_cb(ctx
->ps_eloop
,
806 dhcpcd_signals
, dhcpcd_signals_len
,
807 ps_root_signalcb
, ctx
);
813 ps_root_stop(struct dhcpcd_ctx
*ctx
)
816 return ps_dostop(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
);
820 ps_root_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
823 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_SCRIPT
, 0, data
, len
) == -1)
825 return ps_root_readerror(ctx
, NULL
, 0);
829 ps_root_ioctl(struct dhcpcd_ctx
*ctx
, ioctl_request_t req
, void *data
,
832 #ifdef IOCTL_REQUEST_TYPE
833 unsigned long ulreq
= 0;
835 memcpy(&ulreq
, &req
, sizeof(req
));
836 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, ulreq
, data
, len
) == -1)
839 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, req
, data
, len
) == -1)
842 return ps_root_readerror(ctx
, data
, len
);
846 ps_root_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
849 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_UNLINK
, 0,
850 file
, strlen(file
) + 1) == -1)
852 return ps_root_readerror(ctx
, NULL
, 0);
856 ps_root_readfile(struct dhcpcd_ctx
*ctx
, const char *file
,
857 void *data
, size_t len
)
859 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_READFILE
, 0,
860 file
, strlen(file
) + 1) == -1)
862 return ps_root_readerror(ctx
, data
, len
);
866 ps_root_writefile(struct dhcpcd_ctx
*ctx
, const char *file
, mode_t mode
,
867 const void *data
, size_t len
)
872 flen
= strlcpy(buf
, file
, sizeof(buf
));
874 if (flen
> sizeof(buf
) || flen
+ len
> sizeof(buf
)) {
878 memcpy(buf
+ flen
, data
, len
);
880 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_WRITEFILE
, mode
,
881 buf
, flen
+ len
) == -1)
883 return ps_root_readerror(ctx
, NULL
, 0);
887 ps_root_filemtime(struct dhcpcd_ctx
*ctx
, const char *file
, time_t *time
)
890 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_FILEMTIME
, 0,
891 file
, strlen(file
) + 1) == -1)
893 return ps_root_readerror(ctx
, time
, sizeof(*time
));
896 #ifdef PRIVSEP_GETIFADDRS
898 ps_root_getifaddrs(struct dhcpcd_ctx
*ctx
, struct ifaddrs
**ifahead
)
907 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
,
908 PS_GETIFADDRS
, 0, NULL
, 0) == -1)
910 err
= ps_root_mreaderror(ctx
, &buf
, &len
);
915 /* Should be impossible - lo0 will always exist. */
922 *ifahead
= (struct ifaddrs
*)(void *)bp
;
923 for (ifa
= *ifahead
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
924 if (len
< ALIGN(sizeof(*ifa
)) +
925 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
))
927 bp
+= ALIGN(sizeof(*ifa
));
929 bp
+= ALIGN(IFNAMSIZ
);
931 bp
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
932 len
-= ALIGN(sizeof(*ifa
)) +
933 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
);
935 #define COPYOUTSA(addr) \
937 memcpy(&salen, sap, sizeof(salen)); \
941 (addr) = (struct sockaddr *)bp; \
942 bp += ALIGN(salen); \
943 len -= ALIGN(salen); \
945 sap += sizeof(salen); \
946 } while (0 /* CONSTCOND */)
948 COPYOUTSA(ifa
->ifa_addr
);
949 COPYOUTSA(ifa
->ifa_netmask
);
950 COPYOUTSA(ifa
->ifa_broadaddr
);
952 ifa
->ifa_next
= (struct ifaddrs
*)(void *)bp
;
954 ifa
->ifa_next
= NULL
;
966 #if defined(__linux__) || defined(HAVE_PLEDGE)
968 ps_root_ip6forwarding(struct dhcpcd_ctx
*ctx
, const char *ifname
)
971 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IP6FORWARDING
, 0,
972 ifname
, ifname
!= NULL
? strlen(ifname
) + 1 : 0) == -1)
974 return ps_root_readerror(ctx
, NULL
, 0);
980 ps_root_getauthrdm(struct dhcpcd_ctx
*ctx
, uint64_t *rdm
)
983 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_AUTH_MONORDM
, 0,
984 rdm
, sizeof(*rdm
))== -1)
986 return (int)ps_root_readerror(ctx
, rdm
, sizeof(*rdm
));
992 ps_root_dev_initialized(struct dhcpcd_ctx
*ctx
, const char *ifname
)
995 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_INITTED
, 0,
996 ifname
, strlen(ifname
) + 1)== -1)
998 return (int)ps_root_readerror(ctx
, NULL
, 0);
1002 ps_root_dev_listening(struct dhcpcd_ctx
* ctx
)
1005 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_LISTENING
, 0, NULL
, 0)== -1)
1007 return (int)ps_root_readerror(ctx
, NULL
, 0);