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
;
358 if (getifaddrs(&ifaddrs
) == -1)
360 if (ifaddrs
== NULL
) {
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
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
));
384 * On BSD we need to carry ifa_data so we can access
385 * if_data->ifi_link_state
387 if (ifa
->ifa_addr
!= NULL
&&
388 ifa
->ifa_addr
->sa_family
== AF_LINK
)
389 len
+= ALIGN(sizeof(struct if_data
));
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 memcpy(buf
, ifa
, sizeof(*ifa
));
406 buf
+= ALIGN(sizeof(*ifa
));
408 strlcpy((char *)buf
, ifa
->ifa_name
, IFNAMSIZ
);
409 buf
+= ALIGN(IFNAMSIZ
);
411 buf
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
413 #define COPYINSA(addr) \
415 if ((addr) != NULL) \
416 salen = sa_len((addr)); \
420 memcpy(sap, &salen, sizeof(salen)); \
421 memcpy(buf, (addr), salen); \
422 buf += ALIGN(salen); \
424 sap += sizeof(salen); \
425 } while (0 /*CONSTCOND */)
427 COPYINSA(ifa
->ifa_addr
);
428 COPYINSA(ifa
->ifa_netmask
);
429 COPYINSA(ifa
->ifa_broadaddr
);
432 if (ifa
->ifa_addr
!= NULL
&&
433 ifa
->ifa_addr
->sa_family
== AF_LINK
)
435 salen
= (socklen_t
)sizeof(struct if_data
);
436 memcpy(buf
, ifa
->ifa_data
, salen
);
441 memcpy(sap
, &salen
, sizeof(salen
));
444 freeifaddrs(ifaddrs
);
450 ps_root_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
452 struct dhcpcd_ctx
*ctx
= arg
;
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
];
461 bool free_rdata
= false;
463 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
464 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
467 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
471 if (psm
->ps_cmd
& PS_STOP
) {
472 int ret
= ps_dostop(ctx
, &psp
->psp_pid
, &psp
->psp_fd
);
476 } else if (psm
->ps_cmd
& PS_START
) {
477 /* Process has already started .... */
481 err
= ps_sendpsmmsg(ctx
, psp
->psp_fd
, psm
, msg
);
483 logerr("%s: failed to send message to pid %d",
484 __func__
, psp
->psp_pid
);
485 shutdown(psp
->psp_fd
, SHUT_RDWR
);
493 if (psm
->ps_cmd
& PS_STOP
&& psp
== NULL
)
499 case PS_BPF_ARP
: /* FALLTHROUGH */
502 return ps_bpf_cmd(ctx
, psm
, msg
);
506 return ps_inet_cmd(ctx
, psm
, msg
);
510 case PS_DHCP6
: /* FALLTHROUGH */
513 return ps_inet_cmd(ctx
, psm
, msg
);
519 assert(msg
->msg_iovlen
== 0 || msg
->msg_iovlen
== 1);
524 switch (psm
->ps_cmd
) {
526 err
= ps_root_doioctl(psm
->ps_flags
, data
, len
);
533 err
= ps_root_run_script(ctx
, data
, len
);
536 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
543 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
547 err
= readfile(data
, buf
, sizeof(buf
));
554 err
= ps_root_dowritefile(ctx
, (mode_t
)psm
->ps_flags
,
558 err
= filemtime(data
, &mtime
);
561 rlen
= sizeof(mtime
);
565 case PS_AUTH_MONORDM
:
566 err
= ps_root_monordm(data
, len
);
573 #ifdef PRIVSEP_GETIFADDRS
575 err
= ps_root_dogetifaddrs(&rdata
, &rlen
);
579 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
580 case PS_IP6FORWARDING
:
581 err
= ip6_forwarding(data
);
586 err
= dev_initialised(ctx
, data
);
588 case PS_DEV_LISTENING
:
589 err
= dev_listening(ctx
);
593 err
= ps_root_os(psm
, msg
, &rdata
, &rlen
);
597 err
= ps_root_writeerror(ctx
, err
, rlen
!= 0 ? rdata
: 0, rlen
);
603 /* Receive from state engine, do an action. */
605 ps_root_recvmsg(void *arg
)
607 struct dhcpcd_ctx
*ctx
= arg
;
609 if (ps_recvpsmsg(ctx
, ctx
->ps_root_fd
, ps_root_recvmsgcb
, ctx
) == -1)
615 ps_root_handleinterface(void *arg
, int action
, const char *ifname
)
617 struct dhcpcd_ctx
*ctx
= arg
;
621 flag
= PS_DEV_IFADDED
;
622 else if (action
== -1)
623 flag
= PS_DEV_IFREMOVED
;
624 else if (action
== 0)
625 flag
= PS_DEV_IFUPDATED
;
631 return (int)ps_sendcmd(ctx
, ctx
->ps_data_fd
, PS_DEV_IFCMD
, flag
,
632 ifname
, strlen(ifname
) + 1);
637 ps_root_startcb(void *arg
)
639 struct dhcpcd_ctx
*ctx
= arg
;
641 if (ctx
->options
& DHCPCD_MASTER
)
642 setproctitle("[privileged actioneer]");
644 setproctitle("[privileged actioneer] %s%s%s",
646 ctx
->options
& DHCPCD_IPV4
? " [ip4]" : "",
647 ctx
->options
& DHCPCD_IPV6
? " [ip6]" : "");
648 ctx
->ps_root_pid
= getpid();
649 ctx
->options
|= DHCPCD_PRIVSEPROOT
;
651 /* Open network sockets for sending.
652 * This is a small bit wasteful for non sandboxed OS's
653 * but makes life very easy for unicasting DHCPv6 in non master
654 * mode as we no longer care about address selection.
655 * We can't call shutdown SHUT_RD on the socket because it's
656 * not connectd. All we can do is try and set a zero sized
657 * receive buffer and just let it overflow.
658 * Reading from it just to drain it is a waste of CPU time. */
660 if (ctx
->options
& DHCPCD_IPV4
) {
663 ctx
->udp_wfd
= xsocket(PF_INET
,
664 SOCK_RAW
| SOCK_CXNB
, IPPROTO_UDP
);
665 if (ctx
->udp_wfd
== -1)
666 logerr("%s: dhcp_openraw", __func__
);
667 else if (setsockopt(ctx
->udp_wfd
, SOL_SOCKET
, SO_RCVBUF
,
668 &buflen
, sizeof(buflen
)) == -1)
669 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__
);
673 if (ctx
->options
& DHCPCD_IPV6
) {
676 ctx
->nd_fd
= ipv6nd_open(false);
677 if (ctx
->nd_fd
== -1)
678 logerr("%s: ipv6nd_open", __func__
);
679 else if (setsockopt(ctx
->nd_fd
, SOL_SOCKET
, SO_RCVBUF
,
680 &buflen
, sizeof(buflen
)) == -1)
681 logerr("%s: setsockopt SO_RCVBUF ND", __func__
);
685 if (ctx
->options
& DHCPCD_IPV6
) {
688 ctx
->dhcp6_wfd
= dhcp6_openraw();
689 if (ctx
->dhcp6_wfd
== -1)
690 logerr("%s: dhcp6_openraw", __func__
);
691 else if (setsockopt(ctx
->dhcp6_wfd
, SOL_SOCKET
, SO_RCVBUF
,
692 &buflen
, sizeof(buflen
)) == -1)
693 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__
);
698 /* Start any dev listening plugin which may want to
699 * change the interface name provided by the kernel */
700 if ((ctx
->options
& (DHCPCD_MASTER
| DHCPCD_DEV
)) ==
701 (DHCPCD_MASTER
| DHCPCD_DEV
))
702 dev_start(ctx
, ps_root_handleinterface
);
709 ps_root_signalcb(int sig
, __unused
void *arg
)
712 if (sig
== SIGCHLD
) {
713 while (waitpid(-1, NULL
, WNOHANG
) > 0)
719 int (*handle_interface
)(void *, int, const char *);
723 ps_root_devcb(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
726 struct iovec
*iov
= msg
->msg_iov
;
728 if (msg
->msg_iovlen
!= 1) {
733 switch(psm
->ps_flags
) {
737 case PS_DEV_IFREMOVED
:
740 case PS_DEV_IFUPDATED
:
748 return dhcpcd_handleinterface(ctx
, action
, iov
->iov_base
);
753 ps_root_dispatchcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
755 struct dhcpcd_ctx
*ctx
= arg
;
758 switch(psm
->ps_cmd
) {
761 err
= ps_root_devcb(ctx
, psm
, msg
);
766 err
= ps_bpf_dispatch(ctx
, psm
, msg
);
767 if (err
== -1 && errno
== ENOTSUP
)
769 err
= ps_inet_dispatch(ctx
, psm
, msg
);
775 ps_root_dispatch(void *arg
)
777 struct dhcpcd_ctx
*ctx
= arg
;
779 if (ps_recvpsmsg(ctx
, ctx
->ps_data_fd
, ps_root_dispatchcb
, ctx
) == -1)
784 ps_root_start(struct dhcpcd_ctx
*ctx
)
789 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CXNB
, 0, fd
) == -1)
791 if (ps_setbuf_fdpair(fd
) == -1)
793 #ifdef PRIVSEP_RIGHTS
794 if (ps_rights_limit_fdpair(fd
) == -1)
798 pid
= ps_dostart(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
,
799 ps_root_recvmsg
, NULL
, ctx
,
800 ps_root_startcb
, ps_root_signalcb
, 0);
803 ctx
->ps_data_fd
= fd
[1];
806 } else if (pid
== -1)
809 ctx
->ps_data_fd
= fd
[0];
811 if (eloop_event_add(ctx
->eloop
, ctx
->ps_data_fd
,
812 ps_root_dispatch
, ctx
) == -1)
815 if ((ctx
->ps_eloop
= eloop_new()) == NULL
)
818 eloop_signal_set_cb(ctx
->ps_eloop
,
819 dhcpcd_signals
, dhcpcd_signals_len
,
820 ps_root_signalcb
, ctx
);
826 ps_root_stop(struct dhcpcd_ctx
*ctx
)
829 return ps_dostop(ctx
, &ctx
->ps_root_pid
, &ctx
->ps_root_fd
);
833 ps_root_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
836 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_SCRIPT
, 0, data
, len
) == -1)
838 return ps_root_readerror(ctx
, NULL
, 0);
842 ps_root_ioctl(struct dhcpcd_ctx
*ctx
, ioctl_request_t req
, void *data
,
845 #ifdef IOCTL_REQUEST_TYPE
846 unsigned long ulreq
= 0;
848 memcpy(&ulreq
, &req
, sizeof(req
));
849 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, ulreq
, data
, len
) == -1)
852 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IOCTL
, req
, data
, len
) == -1)
855 return ps_root_readerror(ctx
, data
, len
);
859 ps_root_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
862 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_UNLINK
, 0,
863 file
, strlen(file
) + 1) == -1)
865 return ps_root_readerror(ctx
, NULL
, 0);
869 ps_root_readfile(struct dhcpcd_ctx
*ctx
, const char *file
,
870 void *data
, size_t len
)
872 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_READFILE
, 0,
873 file
, strlen(file
) + 1) == -1)
875 return ps_root_readerror(ctx
, data
, len
);
879 ps_root_writefile(struct dhcpcd_ctx
*ctx
, const char *file
, mode_t mode
,
880 const void *data
, size_t len
)
885 flen
= strlcpy(buf
, file
, sizeof(buf
));
887 if (flen
> sizeof(buf
) || flen
+ len
> sizeof(buf
)) {
891 memcpy(buf
+ flen
, data
, len
);
893 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_WRITEFILE
, mode
,
894 buf
, flen
+ len
) == -1)
896 return ps_root_readerror(ctx
, NULL
, 0);
900 ps_root_filemtime(struct dhcpcd_ctx
*ctx
, const char *file
, time_t *time
)
903 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_FILEMTIME
, 0,
904 file
, strlen(file
) + 1) == -1)
906 return ps_root_readerror(ctx
, time
, sizeof(*time
));
909 #ifdef PRIVSEP_GETIFADDRS
911 ps_root_getifaddrs(struct dhcpcd_ctx
*ctx
, struct ifaddrs
**ifahead
)
920 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
,
921 PS_GETIFADDRS
, 0, NULL
, 0) == -1)
923 err
= ps_root_mreaderror(ctx
, &buf
, &len
);
928 /* Should be impossible - lo0 will always exist. */
935 *ifahead
= (struct ifaddrs
*)(void *)bp
;
936 for (ifa
= *ifahead
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
937 if (len
< ALIGN(sizeof(*ifa
)) +
938 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
))
940 bp
+= ALIGN(sizeof(*ifa
));
942 bp
+= ALIGN(IFNAMSIZ
);
944 bp
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
945 len
-= ALIGN(sizeof(*ifa
)) +
946 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
);
948 #define COPYOUTSA(addr) \
950 memcpy(&salen, sap, sizeof(salen)); \
954 (addr) = (struct sockaddr *)bp; \
955 bp += ALIGN(salen); \
956 len -= ALIGN(salen); \
958 sap += sizeof(salen); \
959 } while (0 /* CONSTCOND */)
961 COPYOUTSA(ifa
->ifa_addr
);
962 COPYOUTSA(ifa
->ifa_netmask
);
963 COPYOUTSA(ifa
->ifa_broadaddr
);
965 memcpy(&salen
, sap
, sizeof(salen
));
973 ifa
->ifa_data
= NULL
;
976 ifa
->ifa_next
= (struct ifaddrs
*)(void *)bp
;
978 ifa
->ifa_next
= NULL
;
990 #if defined(__linux__) || defined(HAVE_PLEDGE)
992 ps_root_ip6forwarding(struct dhcpcd_ctx
*ctx
, const char *ifname
)
995 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_IP6FORWARDING
, 0,
996 ifname
, ifname
!= NULL
? strlen(ifname
) + 1 : 0) == -1)
998 return ps_root_readerror(ctx
, NULL
, 0);
1004 ps_root_getauthrdm(struct dhcpcd_ctx
*ctx
, uint64_t *rdm
)
1007 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_AUTH_MONORDM
, 0,
1008 rdm
, sizeof(*rdm
))== -1)
1010 return (int)ps_root_readerror(ctx
, rdm
, sizeof(*rdm
));
1016 ps_root_dev_initialised(struct dhcpcd_ctx
*ctx
, const char *ifname
)
1019 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_INITTED
, 0,
1020 ifname
, strlen(ifname
) + 1)== -1)
1022 return (int)ps_root_readerror(ctx
, NULL
, 0);
1026 ps_root_dev_listening(struct dhcpcd_ctx
* ctx
)
1029 if (ps_sendcmd(ctx
, ctx
->ps_root_fd
, PS_DEV_LISTENING
, 0, NULL
, 0)== -1)
1031 return (int)ps_root_readerror(ctx
, NULL
, 0);