1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Privilege Separation for dhcpcd, privileged proxy
4 * Copyright (c) 2006-2023 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
, unsigned short events
)
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 if (events
!= ELE_READ
)
91 logerrx("%s: unexpected event 0x%04x", __func__
, events
);
93 #define PSR_ERROR(e) \
95 psr_error->psr_result = -1; \
96 psr_error->psr_errno = (e); \
98 } while (0 /* CONSTCOND */)
100 len
= readv(PS_ROOT_FD(ctx
), iov
, __arraycount(iov
));
103 else if ((size_t)len
< sizeof(*psr_error
))
105 exit_code
= EXIT_SUCCESS
;
108 eloop_exit(ctx
->ps_eloop
, exit_code
);
112 ps_root_readerror(struct dhcpcd_ctx
*ctx
, void *data
, size_t len
)
114 struct psr_ctx psr_ctx
= {
116 .psr_data
= data
, .psr_datalen
= len
,
118 int fd
= PS_ROOT_FD(ctx
);
120 if (eloop_event_add(ctx
->ps_eloop
, fd
, ELE_READ
,
121 ps_root_readerrorcb
, &psr_ctx
) == -1)
124 eloop_enter(ctx
->ps_eloop
);
125 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
126 eloop_event_delete(ctx
->ps_eloop
, fd
);
128 errno
= psr_ctx
.psr_error
.psr_errno
;
129 return psr_ctx
.psr_error
.psr_result
;
132 #ifdef PRIVSEP_GETIFADDRS
134 ps_root_mreaderrorcb(void *arg
, unsigned short events
)
136 struct psr_ctx
*psr_ctx
= arg
;
137 struct dhcpcd_ctx
*ctx
= psr_ctx
->psr_ctx
;
138 struct psr_error
*psr_error
= &psr_ctx
->psr_error
;
139 struct iovec iov
[] = {
140 { .iov_base
= psr_error
, .iov_len
= sizeof(*psr_error
) },
141 { .iov_base
= NULL
, .iov_len
= 0 },
144 int exit_code
= EXIT_FAILURE
;
146 if (events
!= ELE_READ
)
147 logerrx("%s: unexpected event 0x%04x", __func__
, events
);
149 len
= recv(PS_ROOT_FD(ctx
), 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(PS_ROOT_FD(ctx
), 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
= {
183 int fd
= PS_ROOT_FD(ctx
);
185 if (eloop_event_add(ctx
->ps_eloop
, fd
, ELE_READ
,
186 ps_root_mreaderrorcb
, &psr_ctx
) == -1)
189 eloop_enter(ctx
->ps_eloop
);
190 eloop_start(ctx
->ps_eloop
, &ctx
->sigset
);
191 eloop_event_delete(ctx
->ps_eloop
, fd
);
193 errno
= psr_ctx
.psr_error
.psr_errno
;
194 *data
= psr_ctx
.psr_data
;
195 *len
= psr_ctx
.psr_datalen
;
196 return psr_ctx
.psr_error
.psr_result
;
201 ps_root_writeerror(struct dhcpcd_ctx
*ctx
, ssize_t result
,
202 void *data
, size_t len
)
204 struct psr_error psr
= {
205 .psr_result
= result
,
209 struct iovec iov
[] = {
210 { .iov_base
= &psr
, .iov_len
= sizeof(psr
) },
211 { .iov_base
= data
, .iov_len
= len
},
214 int fd
= PS_ROOT_FD(ctx
);
217 logdebugx("%s: result %zd errno %d", __func__
, result
, errno
);
220 err
= writev(fd
, iov
, __arraycount(iov
));
222 /* Error sending the message? Try sending the error of sending. */
224 logerr("%s: result=%zd, data=%p, len=%zu",
225 __func__
, result
, data
, len
);
226 psr
.psr_result
= err
;
227 psr
.psr_errno
= errno
;
228 iov
[1].iov_base
= NULL
;
230 err
= writev(fd
, iov
, __arraycount(iov
));
237 ps_root_doioctl(unsigned long req
, void *data
, size_t len
)
241 /* Only allow these ioctls */
244 case SIOCAIFADDR
: /* FALLTHROUGH */
245 case SIOCDIFADDR
: /* FALLTHROUGH */
248 case SIOCSIFHWADDR
: /* FALLTHROUGH */
250 #ifdef SIOCGIFPRIORITY
251 case SIOCGIFPRIORITY
: /* FALLTHROUGH */
253 case SIOCSIFFLAGS
: /* FALLTHROUGH */
254 case SIOCGIFMTU
: /* FALLTHROUGH */
262 s
= xsocket(PF_INET
, SOCK_DGRAM
, 0);
264 #ifdef IOCTL_REQUEST_TYPE
266 ioctl_request_t reqt
;
268 memcpy(&reqt
, &req
, sizeof(reqt
));
269 err
= ioctl(s
, reqt
, data
, len
);
272 err
= ioctl(s
, req
, data
, len
);
282 ps_root_run_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
284 const char *envbuf
= data
;
285 char * const argv
[] = { ctx
->script
, NULL
};
292 if (script_buftoenv(ctx
, UNCONST(envbuf
), len
) == NULL
)
295 pid
= script_exec(argv
, ctx
->script_env
);
299 /* Wait for the script to finish */
300 while (waitpid(pid
, &status
, 0) == -1) {
301 if (errno
!= EINTR
) {
311 ps_root_validpath(const struct dhcpcd_ctx
*ctx
, uint16_t cmd
, const char *path
)
314 /* Avoid a previous directory attack to avoid /proc/../
315 * dhcpcd should never use a path with double dots. */
316 if (strstr(path
, "..") != NULL
)
319 if (cmd
== PS_READFILE
) {
320 #ifdef EMBEDDED_CONFIG
321 if (strcmp(ctx
->cffile
, EMBEDDED_CONFIG
) == 0)
324 if (strcmp(ctx
->cffile
, path
) == 0)
327 if (strncmp(DBDIR
, path
, strlen(DBDIR
)) == 0)
329 if (strncmp(RUNDIR
, path
, strlen(RUNDIR
)) == 0)
333 if (strncmp("/proc/net/", path
, strlen("/proc/net/")) == 0 ||
334 strncmp("/proc/sys/net/", path
, strlen("/proc/sys/net/")) == 0 ||
335 strncmp("/sys/class/net/", path
, strlen("/sys/class/net/")) == 0)
344 ps_root_dowritefile(const struct dhcpcd_ctx
*ctx
,
345 mode_t mode
, void *data
, size_t len
)
347 char *file
= data
, *nc
;
349 nc
= memchr(file
, '\0', len
);
355 if (!ps_root_validpath(ctx
, PS_WRITEFILE
, file
))
358 return writefile(file
, mode
, nc
, len
- (size_t)(nc
- file
));
363 ps_root_monordm(uint64_t *rdm
, size_t len
)
366 if (len
!= sizeof(*rdm
)) {
370 return auth_get_rdm_monotonic(rdm
);
374 #ifdef PRIVSEP_GETIFADDRS
377 ps_root_dogetifaddrs(void **rdata
, size_t *rlen
)
379 struct ifaddrs
*ifaddrs
, *ifa
;
384 if (getifaddrs(&ifaddrs
) == -1)
386 if (ifaddrs
== NULL
) {
392 /* Work out the buffer length required.
393 * Ensure everything is aligned correctly, which does
394 * create a larger buffer than what is needed to send,
395 * but makes creating the same structure in the client
398 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
399 len
+= ALIGN(sizeof(*ifa
));
400 len
+= ALIGN(IFNAMSIZ
);
401 len
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
402 if (ifa
->ifa_addr
!= NULL
)
403 len
+= ALIGN(sa_len(ifa
->ifa_addr
));
404 if (ifa
->ifa_netmask
!= NULL
)
405 len
+= ALIGN(sa_len(ifa
->ifa_netmask
));
406 if (ifa
->ifa_broadaddr
!= NULL
)
407 len
+= ALIGN(sa_len(ifa
->ifa_broadaddr
));
410 * On BSD we need to carry ifa_data so we can access
411 * if_data->ifi_link_state
413 if (ifa
->ifa_addr
!= NULL
&&
414 ifa
->ifa_addr
->sa_family
== AF_LINK
)
415 len
+= ALIGN(sizeof(struct if_data
));
419 /* Use calloc to set everything to zero.
420 * This satisfies memory sanitizers because don't write
421 * where we don't need to. */
422 buf
= calloc(1, len
);
424 freeifaddrs(ifaddrs
);
430 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
431 memcpy(buf
, ifa
, sizeof(*ifa
));
432 buf
+= ALIGN(sizeof(*ifa
));
434 strlcpy((char *)buf
, ifa
->ifa_name
, IFNAMSIZ
);
435 buf
+= ALIGN(IFNAMSIZ
);
437 buf
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
439 #define COPYINSA(addr) \
441 if ((addr) != NULL) \
442 salen = sa_len((addr)); \
446 memcpy(sap, &salen, sizeof(salen)); \
447 memcpy(buf, (addr), salen); \
448 buf += ALIGN(salen); \
450 sap += sizeof(salen); \
451 } while (0 /*CONSTCOND */)
453 COPYINSA(ifa
->ifa_addr
);
454 COPYINSA(ifa
->ifa_netmask
);
455 COPYINSA(ifa
->ifa_broadaddr
);
458 if (ifa
->ifa_addr
!= NULL
&&
459 ifa
->ifa_addr
->sa_family
== AF_LINK
)
461 salen
= (socklen_t
)sizeof(struct if_data
);
462 memcpy(buf
, ifa
->ifa_data
, salen
);
467 memcpy(sap
, &salen
, sizeof(salen
));
470 freeifaddrs(ifaddrs
);
476 ps_root_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
478 struct dhcpcd_ctx
*ctx
= arg
;
480 struct ps_process
*psp
;
481 struct iovec
*iov
= msg
->msg_iov
;
482 void *data
= iov
->iov_base
, *rdata
= NULL
;
483 size_t len
= iov
->iov_len
, rlen
= 0;
484 uint8_t buf
[PS_BUFLEN
];
487 bool free_rdata
= false;
489 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
490 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
493 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
497 if (psm
->ps_cmd
& PS_STOP
) {
498 return ps_stopprocess(psp
);
499 } else if (psm
->ps_cmd
& PS_START
) {
500 /* Process has already started .... */
501 logdebugx("%s%sprocess %s already started on pid %d",
503 psp
->psp_ifname
[0] != '\0' ? ": " : "",
504 psp
->psp_name
, psp
->psp_pid
);
508 err
= ps_sendpsmmsg(ctx
, psp
->psp_fd
, psm
, msg
);
510 logerr("%s: failed to send message to pid %d",
511 __func__
, psp
->psp_pid
);
517 if (psm
->ps_cmd
& PS_STOP
&& psp
== NULL
)
523 case PS_BPF_ARP
: /* FALLTHROUGH */
526 return ps_bpf_cmd(ctx
, psm
, msg
);
530 return ps_inet_cmd(ctx
, psm
, msg
);
534 case PS_DHCP6
: /* FALLTHROUGH */
537 return ps_inet_cmd(ctx
, psm
, msg
);
543 assert(msg
->msg_iovlen
== 0 || msg
->msg_iovlen
== 1);
548 switch (psm
->ps_cmd
) {
550 err
= ps_root_doioctl(psm
->ps_flags
, data
, len
);
557 err
= ps_root_run_script(ctx
, data
, len
);
560 ctx
->options
|= DHCPCD_EXITING
;
561 TAILQ_FOREACH(psp
, &ctx
->ps_processes
, next
) {
562 if (psp
!= ctx
->ps_root
)
565 err
= ps_stopwait(ctx
);
568 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
575 if (!ps_root_validpath(ctx
, psm
->ps_cmd
, data
)) {
579 err
= readfile(data
, buf
, sizeof(buf
));
586 err
= ps_root_dowritefile(ctx
, (mode_t
)psm
->ps_flags
,
590 err
= filemtime(data
, &mtime
);
593 rlen
= sizeof(mtime
);
597 err
= logopen(ctx
->logfile
);
600 case PS_AUTH_MONORDM
:
601 err
= ps_root_monordm(data
, len
);
608 #ifdef PRIVSEP_GETIFADDRS
610 err
= ps_root_dogetifaddrs(&rdata
, &rlen
);
614 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
615 case PS_IP6FORWARDING
:
616 err
= ip6_forwarding(data
);
621 err
= dev_initialised(ctx
, data
);
623 case PS_DEV_LISTENING
:
624 err
= dev_listening(ctx
);
628 err
= ps_root_os(ctx
, psm
, msg
, &rdata
, &rlen
, &free_rdata
);
632 err
= ps_root_writeerror(ctx
, err
, rlen
!= 0 ? rdata
: 0, rlen
);
638 /* Receive from state engine, do an action. */
640 ps_root_recvmsg(void *arg
, unsigned short events
)
642 struct ps_process
*psp
= arg
;
644 if (ps_recvpsmsg(psp
->psp_ctx
, psp
->psp_fd
, events
,
645 ps_root_recvmsgcb
, psp
->psp_ctx
) == -1)
651 ps_root_handleinterface(void *arg
, int action
, const char *ifname
)
653 struct dhcpcd_ctx
*ctx
= arg
;
657 flag
= PS_DEV_IFADDED
;
658 else if (action
== -1)
659 flag
= PS_DEV_IFREMOVED
;
660 else if (action
== 0)
661 flag
= PS_DEV_IFUPDATED
;
667 return (int)ps_sendcmd(ctx
, ctx
->ps_data_fd
, PS_DEV_IFCMD
,
668 flag
, ifname
, strlen(ifname
) + 1);
673 ps_root_startcb(struct ps_process
*psp
)
675 struct dhcpcd_ctx
*ctx
= psp
->psp_ctx
;
677 if (ctx
->options
& DHCPCD_MANAGER
)
678 setproctitle("[privileged proxy]");
680 setproctitle("[privileged proxy] %s%s%s",
682 ctx
->options
& DHCPCD_IPV4
? " [ip4]" : "",
683 ctx
->options
& DHCPCD_IPV6
? " [ip6]" : "");
684 ctx
->options
|= DHCPCD_PRIVSEPROOT
;
686 if (if_opensockets(ctx
) == -1)
687 logerr("%s: if_opensockets", __func__
);
689 /* Open network sockets for sending.
690 * This is a small bit wasteful for non sandboxed OS's
691 * but makes life very easy for unicasting DHCPv6 in non manager
692 * mode as we no longer care about address selection.
693 * We can't call shutdown SHUT_RD on the socket because it's
694 * not connected. All we can do is try and set a zero sized
695 * receive buffer and just let it overflow.
696 * Reading from it just to drain it is a waste of CPU time. */
698 if (ctx
->options
& DHCPCD_IPV4
) {
701 ctx
->udp_wfd
= xsocket(PF_INET
,
702 SOCK_RAW
| SOCK_CXNB
, IPPROTO_UDP
);
703 if (ctx
->udp_wfd
== -1)
704 logerr("%s: dhcp_openraw", __func__
);
705 else if (setsockopt(ctx
->udp_wfd
, SOL_SOCKET
, SO_RCVBUF
,
706 &buflen
, sizeof(buflen
)) == -1)
707 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__
);
711 if (ctx
->options
& DHCPCD_IPV6
) {
714 ctx
->nd_fd
= ipv6nd_open(false);
715 if (ctx
->nd_fd
== -1)
716 logerr("%s: ipv6nd_open", __func__
);
717 else if (setsockopt(ctx
->nd_fd
, SOL_SOCKET
, SO_RCVBUF
,
718 &buflen
, sizeof(buflen
)) == -1)
719 logerr("%s: setsockopt SO_RCVBUF ND", __func__
);
723 if (ctx
->options
& DHCPCD_IPV6
) {
726 ctx
->dhcp6_wfd
= dhcp6_openraw();
727 if (ctx
->dhcp6_wfd
== -1)
728 logerr("%s: dhcp6_openraw", __func__
);
729 else if (setsockopt(ctx
->dhcp6_wfd
, SOL_SOCKET
, SO_RCVBUF
,
730 &buflen
, sizeof(buflen
)) == -1)
731 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__
);
736 /* Start any dev listening plugin which may want to
737 * change the interface name provided by the kernel */
738 if ((ctx
->options
& (DHCPCD_MANAGER
| DHCPCD_DEV
)) ==
739 (DHCPCD_MANAGER
| DHCPCD_DEV
))
740 dev_start(ctx
, ps_root_handleinterface
);
747 ps_root_signalcb(int sig
, void *arg
)
749 struct dhcpcd_ctx
*ctx
= arg
;
752 const char *ifname
, *name
;
753 struct ps_process
*psp
;
758 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0) {
759 psp
= ps_findprocesspid(ctx
, pid
);
761 ifname
= psp
->psp_ifname
;
762 name
= psp
->psp_name
;
764 /* Ignore logging the double fork */
765 if (ctx
->options
& DHCPCD_LAUNCHER
)
768 name
= "unknown process";
771 if (WIFEXITED(status
) && WEXITSTATUS(status
) != 0)
772 logerrx("%s%s%s exited unexpectedly from PID %d,"
774 ifname
, ifname
[0] != '\0' ? ": " : "",
775 name
, pid
, WEXITSTATUS(status
));
776 else if (WIFSIGNALED(status
))
777 logerrx("%s%s%s exited unexpectedly from PID %d,"
779 ifname
, ifname
[0] != '\0' ? ": " : "",
780 name
, pid
, strsignal(WTERMSIG(status
)));
782 logdebugx("%s%s%s exited from PID %d",
783 ifname
, ifname
[0] != '\0' ? ": " : "",
790 if (!(ctx
->options
& DHCPCD_EXITING
))
792 if (!(ps_waitforprocs(ctx
)))
793 eloop_exit(ctx
->ps_eloop
, EXIT_SUCCESS
);
796 int (*handle_interface
)(void *, int, const char *);
800 ps_root_devcb(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
803 struct iovec
*iov
= msg
->msg_iov
;
805 if (msg
->msg_iovlen
!= 1) {
810 switch(psm
->ps_flags
) {
814 case PS_DEV_IFREMOVED
:
817 case PS_DEV_IFUPDATED
:
825 return dhcpcd_handleinterface(ctx
, action
, iov
->iov_base
);
830 ps_root_dispatchcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
832 struct dhcpcd_ctx
*ctx
= arg
;
835 switch(psm
->ps_cmd
) {
838 err
= ps_root_devcb(ctx
, psm
, msg
);
843 err
= ps_bpf_dispatch(ctx
, psm
, msg
);
844 if (err
== -1 && errno
== ENOTSUP
)
846 err
= ps_inet_dispatch(ctx
, psm
, msg
);
852 ps_root_dispatch(void *arg
, unsigned short events
)
854 struct dhcpcd_ctx
*ctx
= arg
;
856 if (ps_recvpsmsg(ctx
, ctx
->ps_data_fd
, events
,
857 ps_root_dispatchcb
, ctx
) == -1)
862 ps_root_log(void *arg
, unsigned short events
)
864 struct dhcpcd_ctx
*ctx
= arg
;
866 if (events
!= ELE_READ
)
867 logerrx("%s: unexpected event 0x%04x", __func__
, events
);
869 if (logreadfd(ctx
->ps_log_root_fd
) == -1)
874 ps_root_start(struct dhcpcd_ctx
*ctx
)
880 struct ps_process
*psp
;
881 int logfd
[2], datafd
[2];
884 if (xsocketpair(AF_UNIX
, SOCK_SEQPACKET
| SOCK_CXNB
, 0, logfd
) == -1)
886 #ifdef PRIVSEP_RIGHTS
887 if (ps_rights_limit_fdpair(logfd
) == -1)
891 if (xsocketpair(AF_UNIX
, SOCK_SEQPACKET
| SOCK_CXNB
, 0, datafd
) == -1)
893 if (ps_setbuf_fdpair(datafd
) == -1)
895 #ifdef PRIVSEP_RIGHTS
896 if (ps_rights_limit_fdpair(datafd
) == -1)
900 psp
= ctx
->ps_root
= ps_newprocess(ctx
, &id
);
901 strlcpy(psp
->psp_name
, "privileged proxy", sizeof(psp
->psp_name
));
902 pid
= ps_startprocess(psp
, ps_root_recvmsg
, NULL
,
903 ps_root_startcb
, ps_root_signalcb
, PSF_ELOOP
);
906 ctx
->ps_log_fd
= logfd
[0]; /* Keep open to pass to processes */
907 ctx
->ps_log_root_fd
= logfd
[1];
908 if (eloop_event_add(ctx
->eloop
, ctx
->ps_log_root_fd
, ELE_READ
,
909 ps_root_log
, ctx
) == -1)
911 ctx
->ps_data_fd
= datafd
[1];
914 } else if (pid
== -1)
920 ctx
->ps_data_fd
= datafd
[0];
922 if (eloop_event_add(ctx
->eloop
, ctx
->ps_data_fd
, ELE_READ
,
923 ps_root_dispatch
, ctx
) == -1)
930 ps_root_close(struct dhcpcd_ctx
*ctx
)
933 if_closesockets(ctx
);
936 if (ctx
->udp_wfd
!= -1) {
942 if (ctx
->nd_fd
!= -1) {
948 if (ctx
->dhcp6_wfd
!= -1) {
949 close(ctx
->dhcp6_wfd
);
956 ps_root_stop(struct dhcpcd_ctx
*ctx
)
958 struct ps_process
*psp
= ctx
->ps_root
;
960 if (!(ctx
->options
& DHCPCD_PRIVSEP
) ||
964 /* If we are the root process then remove the pidfile */
965 if (ctx
->options
& DHCPCD_PRIVSEPROOT
&&
966 !(ctx
->options
& DHCPCD_TEST
))
968 if (unlink(ctx
->pidfile
) == -1)
969 logerr("%s: unlink: %s", __func__
, ctx
->pidfile
);
972 /* Only the manager process gets past this point. */
973 if (ctx
->options
& DHCPCD_FORKED
)
976 /* We cannot log the root process exited before we
977 * log dhcpcd exits because the latter requires the former.
978 * So we just log the intent to exit.
979 * Even sending this will be a race to exit. */
981 logdebugx("%s%s%s will exit from PID %d",
983 psp
->psp_ifname
[0] != '\0' ? ": " : "",
984 psp
->psp_name
, psp
->psp_pid
);
986 if (ps_stopprocess(psp
) == -1)
988 } /* else the root process has already exited :( */
990 return ps_stopwait(ctx
);
994 ps_root_stopprocesses(struct dhcpcd_ctx
*ctx
)
997 if (!(IN_PRIVSEP_SE(ctx
)))
1000 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_STOPPROCS
, 0,
1003 return ps_root_readerror(ctx
, NULL
, 0);
1007 ps_root_script(struct dhcpcd_ctx
*ctx
, const void *data
, size_t len
)
1010 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_SCRIPT
,
1011 0, data
, len
) == -1)
1013 return ps_root_readerror(ctx
, NULL
, 0);
1017 ps_root_ioctl(struct dhcpcd_ctx
*ctx
, ioctl_request_t req
, void *data
,
1020 int fd
= PS_ROOT_FD(ctx
);
1021 #ifdef IOCTL_REQUEST_TYPE
1022 unsigned long ulreq
= 0;
1024 memcpy(&ulreq
, &req
, sizeof(req
));
1025 if (ps_sendcmd(ctx
, fd
, PS_IOCTL
, ulreq
, data
, len
) == -1)
1028 if (ps_sendcmd(ctx
, fd
, PS_IOCTL
, req
, data
, len
) == -1)
1031 return ps_root_readerror(ctx
, data
, len
);
1035 ps_root_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
1038 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_UNLINK
, 0,
1039 file
, strlen(file
) + 1) == -1)
1041 return ps_root_readerror(ctx
, NULL
, 0);
1045 ps_root_readfile(struct dhcpcd_ctx
*ctx
, const char *file
,
1046 void *data
, size_t len
)
1048 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_READFILE
, 0,
1049 file
, strlen(file
) + 1) == -1)
1051 return ps_root_readerror(ctx
, data
, len
);
1055 ps_root_writefile(struct dhcpcd_ctx
*ctx
, const char *file
, mode_t mode
,
1056 const void *data
, size_t len
)
1058 char buf
[PS_BUFLEN
];
1061 flen
= strlcpy(buf
, file
, sizeof(buf
));
1063 if (flen
> sizeof(buf
) || flen
+ len
> sizeof(buf
)) {
1067 memcpy(buf
+ flen
, data
, len
);
1069 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_WRITEFILE
, mode
,
1070 buf
, flen
+ len
) == -1)
1072 return ps_root_readerror(ctx
, NULL
, 0);
1076 ps_root_filemtime(struct dhcpcd_ctx
*ctx
, const char *file
, time_t *time
)
1079 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_FILEMTIME
, 0,
1080 file
, strlen(file
) + 1) == -1)
1082 return ps_root_readerror(ctx
, time
, sizeof(*time
));
1086 ps_root_logreopen(struct dhcpcd_ctx
*ctx
)
1089 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_LOGREOPEN
, 0,
1092 return ps_root_readerror(ctx
, NULL
, 0);
1095 #ifdef PRIVSEP_GETIFADDRS
1097 ps_root_getifaddrs(struct dhcpcd_ctx
*ctx
, struct ifaddrs
**ifahead
)
1099 struct ifaddrs
*ifa
;
1106 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
),
1107 PS_GETIFADDRS
, 0, NULL
, 0) == -1)
1109 err
= ps_root_mreaderror(ctx
, &buf
, &len
);
1114 /* Should be impossible - lo0 will always exist. */
1121 *ifahead
= (struct ifaddrs
*)(void *)bp
;
1122 for (ifa
= *ifahead
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1123 if (len
< ALIGN(sizeof(*ifa
)) +
1124 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
))
1126 bp
+= ALIGN(sizeof(*ifa
));
1128 bp
+= ALIGN(IFNAMSIZ
);
1130 bp
+= ALIGN(sizeof(salen
) * IFA_NADDRS
);
1131 len
-= ALIGN(sizeof(*ifa
)) +
1132 ALIGN(IFNAMSIZ
) + ALIGN(sizeof(salen
) * IFA_NADDRS
);
1134 #define COPYOUTSA(addr) \
1136 memcpy(&salen, sap, sizeof(salen)); \
1140 (addr) = (struct sockaddr *)(void *)bp; \
1141 bp += ALIGN(salen); \
1142 len -= ALIGN(salen); \
1144 sap += sizeof(salen); \
1145 } while (0 /* CONSTCOND */)
1147 COPYOUTSA(ifa
->ifa_addr
);
1148 COPYOUTSA(ifa
->ifa_netmask
);
1149 COPYOUTSA(ifa
->ifa_broadaddr
);
1151 memcpy(&salen
, sap
, sizeof(salen
));
1157 len
-= ALIGN(salen
);
1159 ifa
->ifa_data
= NULL
;
1162 ifa
->ifa_next
= (struct ifaddrs
*)(void *)bp
;
1164 ifa
->ifa_next
= NULL
;
1176 #if defined(__linux__) || defined(HAVE_PLEDGE)
1178 ps_root_ip6forwarding(struct dhcpcd_ctx
*ctx
, const char *ifname
)
1181 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_IP6FORWARDING
, 0,
1182 ifname
, ifname
!= NULL
? strlen(ifname
) + 1 : 0) == -1)
1184 return ps_root_readerror(ctx
, NULL
, 0);
1190 ps_root_getauthrdm(struct dhcpcd_ctx
*ctx
, uint64_t *rdm
)
1193 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_AUTH_MONORDM
, 0,
1194 rdm
, sizeof(*rdm
))== -1)
1196 return (int)ps_root_readerror(ctx
, rdm
, sizeof(*rdm
));
1202 ps_root_dev_initialised(struct dhcpcd_ctx
*ctx
, const char *ifname
)
1205 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_DEV_INITTED
, 0,
1206 ifname
, strlen(ifname
) + 1)== -1)
1208 return (int)ps_root_readerror(ctx
, NULL
, 0);
1212 ps_root_dev_listening(struct dhcpcd_ctx
* ctx
)
1215 if (ps_sendcmd(ctx
, PS_ROOT_FD(ctx
), PS_DEV_LISTENING
,
1218 return (int)ps_root_readerror(ctx
, NULL
, 0);