xref: /dflybsd-src/contrib/dhcpcd/src/privsep-root.c (revision 6a6d63c5317abf314a78f8c8300ef73c2bc0c39e)
16e63cc1fSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
26e63cc1fSRoy Marples /*
30a68f8d2SRoy Marples  * Privilege Separation for dhcpcd, privileged proxy
480aa9461SRoy Marples  * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
56e63cc1fSRoy Marples  * All rights reserved
66e63cc1fSRoy Marples 
76e63cc1fSRoy Marples  * Redistribution and use in source and binary forms, with or without
86e63cc1fSRoy Marples  * modification, are permitted provided that the following conditions
96e63cc1fSRoy Marples  * are met:
106e63cc1fSRoy Marples  * 1. Redistributions of source code must retain the above copyright
116e63cc1fSRoy Marples  *    notice, this list of conditions and the following disclaimer.
126e63cc1fSRoy Marples  * 2. Redistributions in binary form must reproduce the above copyright
136e63cc1fSRoy Marples  *    notice, this list of conditions and the following disclaimer in the
146e63cc1fSRoy Marples  *    documentation and/or other materials provided with the distribution.
156e63cc1fSRoy Marples  *
166e63cc1fSRoy Marples  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
176e63cc1fSRoy Marples  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
186e63cc1fSRoy Marples  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
196e63cc1fSRoy Marples  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
206e63cc1fSRoy Marples  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
216e63cc1fSRoy Marples  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
226e63cc1fSRoy Marples  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
236e63cc1fSRoy Marples  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
246e63cc1fSRoy Marples  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
256e63cc1fSRoy Marples  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
266e63cc1fSRoy Marples  * SUCH DAMAGE.
276e63cc1fSRoy Marples  */
286e63cc1fSRoy Marples 
296e63cc1fSRoy Marples #include <sys/ioctl.h>
306e63cc1fSRoy Marples #include <sys/socket.h>
316e63cc1fSRoy Marples #include <sys/stat.h>
326e63cc1fSRoy Marples #include <sys/time.h>
336e63cc1fSRoy Marples #include <sys/types.h>
346e63cc1fSRoy Marples #include <sys/wait.h>
356e63cc1fSRoy Marples 
366e63cc1fSRoy Marples #include <assert.h>
376e63cc1fSRoy Marples #include <errno.h>
386e63cc1fSRoy Marples #include <fcntl.h>
396e63cc1fSRoy Marples #include <pwd.h>
406e63cc1fSRoy Marples #include <signal.h>
41d4fb1e02SRoy Marples #include <stddef.h>
426e63cc1fSRoy Marples #include <stdlib.h>
436e63cc1fSRoy Marples #include <string.h>
446e63cc1fSRoy Marples #include <unistd.h>
456e63cc1fSRoy Marples 
46acd7a309SRoy Marples #include "auth.h"
476e63cc1fSRoy Marples #include "common.h"
48d4fb1e02SRoy Marples #include "dev.h"
496e63cc1fSRoy Marples #include "dhcpcd.h"
50d4fb1e02SRoy Marples #include "dhcp6.h"
516e63cc1fSRoy Marples #include "eloop.h"
526e63cc1fSRoy Marples #include "if.h"
53d4fb1e02SRoy Marples #include "ipv6nd.h"
546e63cc1fSRoy Marples #include "logerr.h"
556e63cc1fSRoy Marples #include "privsep.h"
56d4fb1e02SRoy Marples #include "sa.h"
576e63cc1fSRoy Marples #include "script.h"
586e63cc1fSRoy Marples 
596e63cc1fSRoy Marples __CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long));
606e63cc1fSRoy Marples 
616e63cc1fSRoy Marples struct psr_error
626e63cc1fSRoy Marples {
636e63cc1fSRoy Marples 	ssize_t psr_result;
646e63cc1fSRoy Marples 	int psr_errno;
656e63cc1fSRoy Marples 	char psr_pad[sizeof(ssize_t) - sizeof(int)];
66d4fb1e02SRoy Marples 	size_t psr_datalen;
676e63cc1fSRoy Marples };
686e63cc1fSRoy Marples 
696e63cc1fSRoy Marples struct psr_ctx {
706e63cc1fSRoy Marples 	struct dhcpcd_ctx *psr_ctx;
716e63cc1fSRoy Marples 	struct psr_error psr_error;
72d4fb1e02SRoy Marples 	size_t psr_datalen;
73d4fb1e02SRoy Marples 	void *psr_data;
746e63cc1fSRoy Marples };
756e63cc1fSRoy Marples 
766e63cc1fSRoy Marples static void
ps_root_readerrorcb(void * arg,unsigned short events)7780aa9461SRoy Marples ps_root_readerrorcb(void *arg, unsigned short events)
786e63cc1fSRoy Marples {
796e63cc1fSRoy Marples 	struct psr_ctx *psr_ctx = arg;
806e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
816e63cc1fSRoy Marples 	struct psr_error *psr_error = &psr_ctx->psr_error;
82d4fb1e02SRoy Marples 	struct iovec iov[] = {
83d4fb1e02SRoy Marples 		{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
84d4fb1e02SRoy Marples 		{ .iov_base = psr_ctx->psr_data,
85d4fb1e02SRoy Marples 		  .iov_len = psr_ctx->psr_datalen },
86d4fb1e02SRoy Marples 	};
876e63cc1fSRoy Marples 	ssize_t len;
886e63cc1fSRoy Marples 	int exit_code = EXIT_FAILURE;
896e63cc1fSRoy Marples 
9080aa9461SRoy Marples 	if (events != ELE_READ)
9180aa9461SRoy Marples 		logerrx("%s: unexpected event 0x%04x", __func__, events);
9280aa9461SRoy Marples 
93d4fb1e02SRoy Marples #define PSR_ERROR(e)				\
94d4fb1e02SRoy Marples 	do {					\
95d4fb1e02SRoy Marples 		psr_error->psr_result = -1;	\
96d4fb1e02SRoy Marples 		psr_error->psr_errno = (e);	\
97d4fb1e02SRoy Marples 		goto out;			\
98d4fb1e02SRoy Marples 	} while (0 /* CONSTCOND */)
99d4fb1e02SRoy Marples 
100f3744ac9SRoy Marples 	len = readv(PS_ROOT_FD(ctx), iov, __arraycount(iov));
101d4fb1e02SRoy Marples 	if (len == -1)
102d4fb1e02SRoy Marples 		PSR_ERROR(errno);
103d4fb1e02SRoy Marples 	else if ((size_t)len < sizeof(*psr_error))
104d4fb1e02SRoy Marples 		PSR_ERROR(EINVAL);
1056e63cc1fSRoy Marples 	exit_code = EXIT_SUCCESS;
1066e63cc1fSRoy Marples 
107d4fb1e02SRoy Marples out:
1086e63cc1fSRoy Marples 	eloop_exit(ctx->ps_eloop, exit_code);
1096e63cc1fSRoy Marples }
1106e63cc1fSRoy Marples 
1116e63cc1fSRoy Marples ssize_t
ps_root_readerror(struct dhcpcd_ctx * ctx,void * data,size_t len)112d4fb1e02SRoy Marples ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
1136e63cc1fSRoy Marples {
114d4fb1e02SRoy Marples 	struct psr_ctx psr_ctx = {
115d4fb1e02SRoy Marples 	    .psr_ctx = ctx,
116d4fb1e02SRoy Marples 	    .psr_data = data, .psr_datalen = len,
117d4fb1e02SRoy Marples 	};
118f3744ac9SRoy Marples 	int fd = PS_ROOT_FD(ctx);
1196e63cc1fSRoy Marples 
120f3744ac9SRoy Marples 	if (eloop_event_add(ctx->ps_eloop, fd, ELE_READ,
1216e63cc1fSRoy Marples 	    ps_root_readerrorcb, &psr_ctx) == -1)
1226e63cc1fSRoy Marples 		return -1;
1236e63cc1fSRoy Marples 
124acd7a309SRoy Marples 	eloop_enter(ctx->ps_eloop);
1256e63cc1fSRoy Marples 	eloop_start(ctx->ps_eloop, &ctx->sigset);
126f3744ac9SRoy Marples 	eloop_event_delete(ctx->ps_eloop, fd);
1276e63cc1fSRoy Marples 
1286e63cc1fSRoy Marples 	errno = psr_ctx.psr_error.psr_errno;
1296e63cc1fSRoy Marples 	return psr_ctx.psr_error.psr_result;
1306e63cc1fSRoy Marples }
1316e63cc1fSRoy Marples 
1327f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
133d4fb1e02SRoy Marples static void
ps_root_mreaderrorcb(void * arg,unsigned short events)13480aa9461SRoy Marples ps_root_mreaderrorcb(void *arg, unsigned short events)
135d4fb1e02SRoy Marples {
136d4fb1e02SRoy Marples 	struct psr_ctx *psr_ctx = arg;
137d4fb1e02SRoy Marples 	struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
138d4fb1e02SRoy Marples 	struct psr_error *psr_error = &psr_ctx->psr_error;
139d4fb1e02SRoy Marples 	struct iovec iov[] = {
140d4fb1e02SRoy Marples 		{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
141d4fb1e02SRoy Marples 		{ .iov_base = NULL, .iov_len = 0 },
142d4fb1e02SRoy Marples 	};
143d4fb1e02SRoy Marples 	ssize_t len;
144d4fb1e02SRoy Marples 	int exit_code = EXIT_FAILURE;
145d4fb1e02SRoy Marples 
14680aa9461SRoy Marples 	if (events != ELE_READ)
14780aa9461SRoy Marples 		logerrx("%s: unexpected event 0x%04x", __func__, events);
14880aa9461SRoy Marples 
149f3744ac9SRoy Marples 	len = recv(PS_ROOT_FD(ctx), psr_error, sizeof(*psr_error), MSG_PEEK);
150d4fb1e02SRoy Marples 	if (len == -1)
151d4fb1e02SRoy Marples 		PSR_ERROR(errno);
152d4fb1e02SRoy Marples 	else if ((size_t)len < sizeof(*psr_error))
153d4fb1e02SRoy Marples 		PSR_ERROR(EINVAL);
154d4fb1e02SRoy Marples 
1557f8103cdSRoy Marples 	if (psr_error->psr_datalen > SSIZE_MAX)
1567f8103cdSRoy Marples 		PSR_ERROR(ENOBUFS);
1577f8103cdSRoy Marples 	else if (psr_error->psr_datalen != 0) {
158d4fb1e02SRoy Marples 		psr_ctx->psr_data = malloc(psr_error->psr_datalen);
159d4fb1e02SRoy Marples 		if (psr_ctx->psr_data == NULL)
160d4fb1e02SRoy Marples 			PSR_ERROR(errno);
161d4fb1e02SRoy Marples 		psr_ctx->psr_datalen = psr_error->psr_datalen;
162d4fb1e02SRoy Marples 		iov[1].iov_base = psr_ctx->psr_data;
163d4fb1e02SRoy Marples 		iov[1].iov_len = psr_ctx->psr_datalen;
164d4fb1e02SRoy Marples 	}
165d4fb1e02SRoy Marples 
166f3744ac9SRoy Marples 	len = readv(PS_ROOT_FD(ctx), iov, __arraycount(iov));
167d4fb1e02SRoy Marples 	if (len == -1)
168d4fb1e02SRoy Marples 		PSR_ERROR(errno);
169d4fb1e02SRoy Marples 	else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen)
170d4fb1e02SRoy Marples 		PSR_ERROR(EINVAL);
171d4fb1e02SRoy Marples 	exit_code = EXIT_SUCCESS;
172d4fb1e02SRoy Marples 
173d4fb1e02SRoy Marples out:
174d4fb1e02SRoy Marples 	eloop_exit(ctx->ps_eloop, exit_code);
175d4fb1e02SRoy Marples }
176d4fb1e02SRoy Marples 
177d4fb1e02SRoy Marples ssize_t
ps_root_mreaderror(struct dhcpcd_ctx * ctx,void ** data,size_t * len)178d4fb1e02SRoy Marples ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
179d4fb1e02SRoy Marples {
180d4fb1e02SRoy Marples 	struct psr_ctx psr_ctx = {
181d4fb1e02SRoy Marples 	    .psr_ctx = ctx,
182d4fb1e02SRoy Marples 	};
183f3744ac9SRoy Marples 	int fd = PS_ROOT_FD(ctx);
184d4fb1e02SRoy Marples 
185f3744ac9SRoy Marples 	if (eloop_event_add(ctx->ps_eloop, fd, ELE_READ,
186d4fb1e02SRoy Marples 	    ps_root_mreaderrorcb, &psr_ctx) == -1)
187d4fb1e02SRoy Marples 		return -1;
188d4fb1e02SRoy Marples 
189acd7a309SRoy Marples 	eloop_enter(ctx->ps_eloop);
190d4fb1e02SRoy Marples 	eloop_start(ctx->ps_eloop, &ctx->sigset);
191f3744ac9SRoy Marples 	eloop_event_delete(ctx->ps_eloop, fd);
192d4fb1e02SRoy Marples 
193d4fb1e02SRoy Marples 	errno = psr_ctx.psr_error.psr_errno;
194d4fb1e02SRoy Marples 	*data = psr_ctx.psr_data;
195d4fb1e02SRoy Marples 	*len = psr_ctx.psr_datalen;
196d4fb1e02SRoy Marples 	return psr_ctx.psr_error.psr_result;
197d4fb1e02SRoy Marples }
198d4fb1e02SRoy Marples #endif
199d4fb1e02SRoy Marples 
2006e63cc1fSRoy Marples static ssize_t
ps_root_writeerror(struct dhcpcd_ctx * ctx,ssize_t result,void * data,size_t len)201d4fb1e02SRoy Marples ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
202d4fb1e02SRoy Marples     void *data, size_t len)
2036e63cc1fSRoy Marples {
2046e63cc1fSRoy Marples 	struct psr_error psr = {
2056e63cc1fSRoy Marples 		.psr_result = result,
2066e63cc1fSRoy Marples 		.psr_errno = errno,
207d4fb1e02SRoy Marples 		.psr_datalen = len,
208d4fb1e02SRoy Marples 	};
209d4fb1e02SRoy Marples 	struct iovec iov[] = {
210d4fb1e02SRoy Marples 		{ .iov_base = &psr, .iov_len = sizeof(psr) },
211d4fb1e02SRoy Marples 		{ .iov_base = data, .iov_len = len },
2126e63cc1fSRoy Marples 	};
21380aa9461SRoy Marples 	ssize_t err;
214f3744ac9SRoy Marples 	int fd = PS_ROOT_FD(ctx);
2156e63cc1fSRoy Marples 
2166e63cc1fSRoy Marples #ifdef PRIVSEP_DEBUG
2176e63cc1fSRoy Marples 	logdebugx("%s: result %zd errno %d", __func__, result, errno);
2186e63cc1fSRoy Marples #endif
2196e63cc1fSRoy Marples 
220f3744ac9SRoy Marples 	err = writev(fd, iov, __arraycount(iov));
22180aa9461SRoy Marples 
22280aa9461SRoy Marples 	/* Error sending the message? Try sending the error of sending. */
22380aa9461SRoy Marples 	if (err == -1) {
22480aa9461SRoy Marples 		logerr("%s: result=%zd, data=%p, len=%zu",
22580aa9461SRoy Marples 		    __func__, result, data, len);
22680aa9461SRoy Marples 		psr.psr_result = err;
22780aa9461SRoy Marples 		psr.psr_errno = errno;
22880aa9461SRoy Marples 		iov[1].iov_base = NULL;
22980aa9461SRoy Marples 		iov[1].iov_len = 0;
230f3744ac9SRoy Marples 		err = writev(fd, iov, __arraycount(iov));
23180aa9461SRoy Marples 	}
23280aa9461SRoy Marples 
23380aa9461SRoy Marples 	return err;
2346e63cc1fSRoy Marples }
2356e63cc1fSRoy Marples 
2366e63cc1fSRoy Marples static ssize_t
ps_root_doioctl(unsigned long req,void * data,size_t len)2376e63cc1fSRoy Marples ps_root_doioctl(unsigned long req, void *data, size_t len)
2386e63cc1fSRoy Marples {
2396e63cc1fSRoy Marples 	int s, err;
2406e63cc1fSRoy Marples 
241d4fb1e02SRoy Marples 	/* Only allow these ioctls */
242d4fb1e02SRoy Marples 	switch(req) {
243d4fb1e02SRoy Marples #ifdef SIOCAIFADDR
244d4fb1e02SRoy Marples 	case SIOCAIFADDR:	/* FALLTHROUGH */
245d4fb1e02SRoy Marples 	case SIOCDIFADDR:	/* FALLTHROUGH */
246d4fb1e02SRoy Marples #endif
247d4fb1e02SRoy Marples #ifdef SIOCSIFHWADDR
248d4fb1e02SRoy Marples 	case SIOCSIFHWADDR:	/* FALLTHROUGH */
249d4fb1e02SRoy Marples #endif
250d4fb1e02SRoy Marples #ifdef SIOCGIFPRIORITY
251d4fb1e02SRoy Marples 	case SIOCGIFPRIORITY:	/* FALLTHROUGH */
252d4fb1e02SRoy Marples #endif
253d4fb1e02SRoy Marples 	case SIOCSIFFLAGS:	/* FALLTHROUGH */
254d4fb1e02SRoy Marples 	case SIOCGIFMTU:	/* FALLTHROUGH */
255d4fb1e02SRoy Marples 	case SIOCSIFMTU:
256d4fb1e02SRoy Marples 		break;
257d4fb1e02SRoy Marples 	default:
258d4fb1e02SRoy Marples 		errno = EPERM;
259d4fb1e02SRoy Marples 		return -1;
260d4fb1e02SRoy Marples 	}
261d4fb1e02SRoy Marples 
262*54175cefSRoy Marples 	s = xsocket(PF_INET, SOCK_DGRAM, 0);
2636e63cc1fSRoy Marples 	if (s != -1)
2646e63cc1fSRoy Marples #ifdef IOCTL_REQUEST_TYPE
2656e63cc1fSRoy Marples 	{
2666e63cc1fSRoy Marples 		ioctl_request_t reqt;
2676e63cc1fSRoy Marples 
2686e63cc1fSRoy Marples 		memcpy(&reqt, &req, sizeof(reqt));
2696e63cc1fSRoy Marples 		err = ioctl(s, reqt, data, len);
2706e63cc1fSRoy Marples 	}
2716e63cc1fSRoy Marples #else
2726e63cc1fSRoy Marples 		err = ioctl(s, req, data, len);
2736e63cc1fSRoy Marples #endif
2746e63cc1fSRoy Marples 	else
2756e63cc1fSRoy Marples 		err = -1;
2766e63cc1fSRoy Marples 	if (s != -1)
2776e63cc1fSRoy Marples 		close(s);
2786e63cc1fSRoy Marples 	return err;
2796e63cc1fSRoy Marples }
2806e63cc1fSRoy Marples 
2816e63cc1fSRoy Marples static ssize_t
ps_root_run_script(struct dhcpcd_ctx * ctx,const void * data,size_t len)2826e63cc1fSRoy Marples ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
2836e63cc1fSRoy Marples {
2846e63cc1fSRoy Marples 	const char *envbuf = data;
285d4fb1e02SRoy Marples 	char * const argv[] = { ctx->script, NULL };
2866e63cc1fSRoy Marples 	pid_t pid;
2876e63cc1fSRoy Marples 	int status;
2886e63cc1fSRoy Marples 
2896e63cc1fSRoy Marples 	if (len == 0)
2906e63cc1fSRoy Marples 		return 0;
2916e63cc1fSRoy Marples 
2926e63cc1fSRoy Marples 	if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL)
2936e63cc1fSRoy Marples 		return -1;
2946e63cc1fSRoy Marples 
295280986e4SRoy Marples 	pid = script_exec(argv, ctx->script_env);
2966e63cc1fSRoy Marples 	if (pid == -1)
2976e63cc1fSRoy Marples 		return -1;
29880aa9461SRoy Marples 
2996e63cc1fSRoy Marples 	/* Wait for the script to finish */
3006e63cc1fSRoy Marples 	while (waitpid(pid, &status, 0) == -1) {
3016e63cc1fSRoy Marples 		if (errno != EINTR) {
3026e63cc1fSRoy Marples 			logerr(__func__);
3036e63cc1fSRoy Marples 			status = 0;
3046e63cc1fSRoy Marples 			break;
3056e63cc1fSRoy Marples 		}
3066e63cc1fSRoy Marples 	}
3076e63cc1fSRoy Marples 	return status;
3086e63cc1fSRoy Marples }
3096e63cc1fSRoy Marples 
310d4fb1e02SRoy Marples static bool
ps_root_validpath(const struct dhcpcd_ctx * ctx,uint16_t cmd,const char * path)311d4fb1e02SRoy Marples ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path)
3126e63cc1fSRoy Marples {
3136e63cc1fSRoy Marples 
314d4fb1e02SRoy Marples 	/* Avoid a previous directory attack to avoid /proc/../
315d4fb1e02SRoy Marples 	 * dhcpcd should never use a path with double dots. */
316d4fb1e02SRoy Marples 	if (strstr(path, "..") != NULL)
317d4fb1e02SRoy Marples 		return false;
318d4fb1e02SRoy Marples 
319d4fb1e02SRoy Marples 	if (cmd == PS_READFILE) {
3207f8103cdSRoy Marples #ifdef EMBEDDED_CONFIG
3217f8103cdSRoy Marples 		if (strcmp(ctx->cffile, EMBEDDED_CONFIG) == 0)
3227f8103cdSRoy Marples 			return true;
3237f8103cdSRoy Marples #endif
324d4fb1e02SRoy Marples 		if (strcmp(ctx->cffile, path) == 0)
325d4fb1e02SRoy Marples 			return true;
326d4fb1e02SRoy Marples 	}
327d4fb1e02SRoy Marples 	if (strncmp(DBDIR, path, strlen(DBDIR)) == 0)
328d4fb1e02SRoy Marples 		return true;
329d4fb1e02SRoy Marples 	if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0)
330d4fb1e02SRoy Marples 		return true;
331d4fb1e02SRoy Marples 
332d4fb1e02SRoy Marples #ifdef __linux__
333d4fb1e02SRoy Marples 	if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 ||
334d4fb1e02SRoy Marples 	    strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 ||
335d4fb1e02SRoy Marples 	    strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0)
336d4fb1e02SRoy Marples 		return true;
3376e63cc1fSRoy Marples #endif
3386e63cc1fSRoy Marples 
339d4fb1e02SRoy Marples 	errno = EPERM;
340d4fb1e02SRoy Marples 	return false;
3416e63cc1fSRoy Marples }
3426e63cc1fSRoy Marples 
3436e63cc1fSRoy Marples static ssize_t
ps_root_dowritefile(const struct dhcpcd_ctx * ctx,mode_t mode,void * data,size_t len)344d4fb1e02SRoy Marples ps_root_dowritefile(const struct dhcpcd_ctx *ctx,
345d4fb1e02SRoy Marples     mode_t mode, void *data, size_t len)
3466e63cc1fSRoy Marples {
347d4fb1e02SRoy Marples 	char *file = data, *nc;
3486e63cc1fSRoy Marples 
349d4fb1e02SRoy Marples 	nc = memchr(file, '\0', len);
350d4fb1e02SRoy Marples 	if (nc == NULL) {
3516e63cc1fSRoy Marples 		errno = EINVAL;
3526e63cc1fSRoy Marples 		return -1;
3536e63cc1fSRoy Marples 	}
3546e63cc1fSRoy Marples 
355d4fb1e02SRoy Marples 	if (!ps_root_validpath(ctx, PS_WRITEFILE, file))
3566e63cc1fSRoy Marples 		return -1;
357d4fb1e02SRoy Marples 	nc++;
358d4fb1e02SRoy Marples 	return writefile(file, mode, nc, len - (size_t)(nc - file));
3596e63cc1fSRoy Marples }
3606e63cc1fSRoy Marples 
361acd7a309SRoy Marples #ifdef AUTH
362acd7a309SRoy Marples static ssize_t
ps_root_monordm(uint64_t * rdm,size_t len)363acd7a309SRoy Marples ps_root_monordm(uint64_t *rdm, size_t len)
364acd7a309SRoy Marples {
365acd7a309SRoy Marples 
366acd7a309SRoy Marples 	if (len != sizeof(*rdm)) {
367acd7a309SRoy Marples 		errno = EINVAL;
368acd7a309SRoy Marples 		return -1;
369acd7a309SRoy Marples 	}
370acd7a309SRoy Marples 	return auth_get_rdm_monotonic(rdm);
371acd7a309SRoy Marples }
372acd7a309SRoy Marples #endif
373acd7a309SRoy Marples 
3747f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
375a0d9933aSRoy Marples #define	IFA_NADDRS	4
376d4fb1e02SRoy Marples static ssize_t
ps_root_dogetifaddrs(void ** rdata,size_t * rlen)377d4fb1e02SRoy Marples ps_root_dogetifaddrs(void **rdata, size_t *rlen)
378d4fb1e02SRoy Marples {
379a0d9933aSRoy Marples 	struct ifaddrs *ifaddrs, *ifa;
380d4fb1e02SRoy Marples 	size_t len;
381d4fb1e02SRoy Marples 	uint8_t *buf, *sap;
382d4fb1e02SRoy Marples 	socklen_t salen;
383d4fb1e02SRoy Marples 
384d4fb1e02SRoy Marples 	if (getifaddrs(&ifaddrs) == -1)
385d4fb1e02SRoy Marples 		return -1;
386d4fb1e02SRoy Marples 	if (ifaddrs == NULL) {
387d4fb1e02SRoy Marples 		*rdata = NULL;
388d4fb1e02SRoy Marples 		*rlen = 0;
389d4fb1e02SRoy Marples 		return 0;
390d4fb1e02SRoy Marples 	}
391d4fb1e02SRoy Marples 
392d4fb1e02SRoy Marples 	/* Work out the buffer length required.
393d4fb1e02SRoy Marples 	 * Ensure everything is aligned correctly, which does
394d4fb1e02SRoy Marples 	 * create a larger buffer than what is needed to send,
395d4fb1e02SRoy Marples 	 * but makes creating the same structure in the client
396d4fb1e02SRoy Marples 	 * much easier. */
397d4fb1e02SRoy Marples 	len = 0;
398d4fb1e02SRoy Marples 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
399d4fb1e02SRoy Marples 		len += ALIGN(sizeof(*ifa));
400d4fb1e02SRoy Marples 		len += ALIGN(IFNAMSIZ);
401d4fb1e02SRoy Marples 		len += ALIGN(sizeof(salen) * IFA_NADDRS);
402d4fb1e02SRoy Marples 		if (ifa->ifa_addr != NULL)
403d4fb1e02SRoy Marples 			len += ALIGN(sa_len(ifa->ifa_addr));
404d4fb1e02SRoy Marples 		if (ifa->ifa_netmask != NULL)
405d4fb1e02SRoy Marples 			len += ALIGN(sa_len(ifa->ifa_netmask));
406d4fb1e02SRoy Marples 		if (ifa->ifa_broadaddr != NULL)
407d4fb1e02SRoy Marples 			len += ALIGN(sa_len(ifa->ifa_broadaddr));
408a0d9933aSRoy Marples #ifdef BSD
409a0d9933aSRoy Marples 		/*
410a0d9933aSRoy Marples 		 * On BSD we need to carry ifa_data so we can access
411a0d9933aSRoy Marples 		 * if_data->ifi_link_state
412a0d9933aSRoy Marples 		 */
413a0d9933aSRoy Marples 		if (ifa->ifa_addr != NULL &&
414a0d9933aSRoy Marples 		    ifa->ifa_addr->sa_family == AF_LINK)
415a0d9933aSRoy Marples 			len += ALIGN(sizeof(struct if_data));
416a0d9933aSRoy Marples #endif
417d4fb1e02SRoy Marples 	}
418d4fb1e02SRoy Marples 
419d4fb1e02SRoy Marples 	/* Use calloc to set everything to zero.
420d4fb1e02SRoy Marples 	 * This satisfies memory sanitizers because don't write
421d4fb1e02SRoy Marples 	 * where we don't need to. */
422d4fb1e02SRoy Marples 	buf = calloc(1, len);
423d4fb1e02SRoy Marples 	if (buf == NULL) {
424d4fb1e02SRoy Marples 		freeifaddrs(ifaddrs);
4256e63cc1fSRoy Marples 		return -1;
4266e63cc1fSRoy Marples 	}
427d4fb1e02SRoy Marples 	*rdata = buf;
428d4fb1e02SRoy Marples 	*rlen = len;
429d4fb1e02SRoy Marples 
430d4fb1e02SRoy Marples 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
431d4fb1e02SRoy Marples 		memcpy(buf, ifa, sizeof(*ifa));
432d4fb1e02SRoy Marples 		buf += ALIGN(sizeof(*ifa));
433d4fb1e02SRoy Marples 
434d4fb1e02SRoy Marples 		strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ);
435d4fb1e02SRoy Marples 		buf += ALIGN(IFNAMSIZ);
436d4fb1e02SRoy Marples 		sap = buf;
437d4fb1e02SRoy Marples 		buf += ALIGN(sizeof(salen) * IFA_NADDRS);
438d4fb1e02SRoy Marples 
439d4fb1e02SRoy Marples #define	COPYINSA(addr)						\
440d4fb1e02SRoy Marples 	do {							\
441a0d9933aSRoy Marples 		if ((addr) != NULL)				\
442d4fb1e02SRoy Marples 			salen = sa_len((addr));			\
443a0d9933aSRoy Marples 		else						\
444a0d9933aSRoy Marples 			salen = 0;				\
445d4fb1e02SRoy Marples 		if (salen != 0) {				\
446d4fb1e02SRoy Marples 			memcpy(sap, &salen, sizeof(salen));	\
447d4fb1e02SRoy Marples 			memcpy(buf, (addr), salen);		\
448d4fb1e02SRoy Marples 			buf += ALIGN(salen);			\
449d4fb1e02SRoy Marples 		}						\
450d4fb1e02SRoy Marples 		sap += sizeof(salen);				\
451d4fb1e02SRoy Marples 	} while (0 /*CONSTCOND */)
452d4fb1e02SRoy Marples 
453d4fb1e02SRoy Marples 		COPYINSA(ifa->ifa_addr);
454d4fb1e02SRoy Marples 		COPYINSA(ifa->ifa_netmask);
455d4fb1e02SRoy Marples 		COPYINSA(ifa->ifa_broadaddr);
456a0d9933aSRoy Marples 
457a0d9933aSRoy Marples #ifdef BSD
458a0d9933aSRoy Marples 		if (ifa->ifa_addr != NULL &&
459a0d9933aSRoy Marples 		    ifa->ifa_addr->sa_family == AF_LINK)
460a0d9933aSRoy Marples 		{
461a0d9933aSRoy Marples 			salen = (socklen_t)sizeof(struct if_data);
462a0d9933aSRoy Marples 			memcpy(buf, ifa->ifa_data, salen);
463a0d9933aSRoy Marples 			buf += ALIGN(salen);
464a0d9933aSRoy Marples 		} else
465a0d9933aSRoy Marples #endif
466a0d9933aSRoy Marples 			salen = 0;
467a0d9933aSRoy Marples 		memcpy(sap, &salen, sizeof(salen));
4686e63cc1fSRoy Marples 	}
4696e63cc1fSRoy Marples 
470d4fb1e02SRoy Marples 	freeifaddrs(ifaddrs);
471d4fb1e02SRoy Marples 	return 0;
472d4fb1e02SRoy Marples }
473d4fb1e02SRoy Marples #endif
474d4fb1e02SRoy Marples 
4756e63cc1fSRoy Marples static ssize_t
ps_root_recvmsgcb(void * arg,struct ps_msghdr * psm,struct msghdr * msg)4766e63cc1fSRoy Marples ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
4776e63cc1fSRoy Marples {
4786e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = arg;
479d4fb1e02SRoy Marples 	uint16_t cmd;
4806e63cc1fSRoy Marples 	struct ps_process *psp;
4816e63cc1fSRoy Marples 	struct iovec *iov = msg->msg_iov;
482d4fb1e02SRoy Marples 	void *data = iov->iov_base, *rdata = NULL;
483d4fb1e02SRoy Marples 	size_t len = iov->iov_len, rlen = 0;
484d4fb1e02SRoy Marples 	uint8_t buf[PS_BUFLEN];
485d4fb1e02SRoy Marples 	time_t mtime;
4866e63cc1fSRoy Marples 	ssize_t err;
487d4fb1e02SRoy Marples 	bool free_rdata = false;
4886e63cc1fSRoy Marples 
489d4fb1e02SRoy Marples 	cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
4906e63cc1fSRoy Marples 	psp = ps_findprocess(ctx, &psm->ps_id);
4916e63cc1fSRoy Marples 
4926e63cc1fSRoy Marples #ifdef PRIVSEP_DEBUG
4936e63cc1fSRoy Marples 	logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
4946e63cc1fSRoy Marples #endif
4956e63cc1fSRoy Marples 
496d4fb1e02SRoy Marples 	if (psp != NULL) {
4976e63cc1fSRoy Marples 		if (psm->ps_cmd & PS_STOP) {
49880aa9461SRoy Marples 			return ps_stopprocess(psp);
499acd7a309SRoy Marples 		} else if (psm->ps_cmd & PS_START) {
500d4fb1e02SRoy Marples 			/* Process has already started .... */
50180aa9461SRoy Marples 			logdebugx("%s%sprocess %s already started on pid %d",
50280aa9461SRoy Marples 			    psp->psp_ifname,
50380aa9461SRoy Marples 			    psp->psp_ifname[0] != '\0' ? ": " : "",
50480aa9461SRoy Marples 			    psp->psp_name, psp->psp_pid);
505d4fb1e02SRoy Marples 			return 0;
5066e63cc1fSRoy Marples 		}
5076e63cc1fSRoy Marples 
508acd7a309SRoy Marples 		err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
509acd7a309SRoy Marples 		if (err == -1) {
510acd7a309SRoy Marples 			logerr("%s: failed to send message to pid %d",
511acd7a309SRoy Marples 			    __func__, psp->psp_pid);
512acd7a309SRoy Marples 			ps_freeprocess(psp);
513acd7a309SRoy Marples 		}
514acd7a309SRoy Marples 		return 0;
515acd7a309SRoy Marples 	}
516acd7a309SRoy Marples 
517d4fb1e02SRoy Marples 	if (psm->ps_cmd & PS_STOP && psp == NULL)
5186e63cc1fSRoy Marples 		return 0;
5196e63cc1fSRoy Marples 
5206e63cc1fSRoy Marples 	switch (cmd) {
5216e63cc1fSRoy Marples #ifdef INET
5226e63cc1fSRoy Marples #ifdef ARP
5236e63cc1fSRoy Marples 	case PS_BPF_ARP:	/* FALLTHROUGH */
5246e63cc1fSRoy Marples #endif
5256e63cc1fSRoy Marples 	case PS_BPF_BOOTP:
5266e63cc1fSRoy Marples 		return ps_bpf_cmd(ctx, psm, msg);
5276e63cc1fSRoy Marples #endif
5286e63cc1fSRoy Marples #ifdef INET
5296e63cc1fSRoy Marples 	case PS_BOOTP:
5306e63cc1fSRoy Marples 		return ps_inet_cmd(ctx, psm, msg);
5316e63cc1fSRoy Marples #endif
5326e63cc1fSRoy Marples #ifdef INET6
5336e63cc1fSRoy Marples #ifdef DHCP6
5346e63cc1fSRoy Marples 	case PS_DHCP6:	/* FALLTHROUGH */
5356e63cc1fSRoy Marples #endif
5366e63cc1fSRoy Marples 	case PS_ND:
5376e63cc1fSRoy Marples 		return ps_inet_cmd(ctx, psm, msg);
5386e63cc1fSRoy Marples #endif
5396e63cc1fSRoy Marples 	default:
5406e63cc1fSRoy Marples 		break;
5416e63cc1fSRoy Marples 	}
5426e63cc1fSRoy Marples 
543d4fb1e02SRoy Marples 	assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1);
5446e63cc1fSRoy Marples 
5456e63cc1fSRoy Marples 	/* Reset errno */
5466e63cc1fSRoy Marples 	errno = 0;
5476e63cc1fSRoy Marples 
5486e63cc1fSRoy Marples 	switch (psm->ps_cmd) {
5496e63cc1fSRoy Marples 	case PS_IOCTL:
5506e63cc1fSRoy Marples 		err = ps_root_doioctl(psm->ps_flags, data, len);
551d4fb1e02SRoy Marples 		if (err != -1) {
552d4fb1e02SRoy Marples 			rdata = data;
553d4fb1e02SRoy Marples 			rlen = len;
554d4fb1e02SRoy Marples 		}
5556e63cc1fSRoy Marples 		break;
5566e63cc1fSRoy Marples 	case PS_SCRIPT:
5576e63cc1fSRoy Marples 		err = ps_root_run_script(ctx, data, len);
5586e63cc1fSRoy Marples 		break;
55980aa9461SRoy Marples 	case PS_STOPPROCS:
56080aa9461SRoy Marples 		ctx->options |= DHCPCD_EXITING;
56180aa9461SRoy Marples 		TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
56280aa9461SRoy Marples 			if (psp != ctx->ps_root)
56380aa9461SRoy Marples 				ps_stopprocess(psp);
56480aa9461SRoy Marples 		}
56580aa9461SRoy Marples 		err = ps_stopwait(ctx);
56680aa9461SRoy Marples 		break;
5676e63cc1fSRoy Marples 	case PS_UNLINK:
568d4fb1e02SRoy Marples 		if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
569d4fb1e02SRoy Marples 			err = -1;
5706e63cc1fSRoy Marples 			break;
571d4fb1e02SRoy Marples 		}
572d4fb1e02SRoy Marples 		err = unlink(data);
573d4fb1e02SRoy Marples 		break;
574d4fb1e02SRoy Marples 	case PS_READFILE:
575d4fb1e02SRoy Marples 		if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
576d4fb1e02SRoy Marples 			err = -1;
577d4fb1e02SRoy Marples 			break;
578d4fb1e02SRoy Marples 		}
579d4fb1e02SRoy Marples 		err = readfile(data, buf, sizeof(buf));
580d4fb1e02SRoy Marples 		if (err != -1) {
581d4fb1e02SRoy Marples 			rdata = buf;
582d4fb1e02SRoy Marples 			rlen = (size_t)err;
583d4fb1e02SRoy Marples 		}
584d4fb1e02SRoy Marples 		break;
585d4fb1e02SRoy Marples 	case PS_WRITEFILE:
586d4fb1e02SRoy Marples 		err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags,
587d4fb1e02SRoy Marples 		    data, len);
588d4fb1e02SRoy Marples 		break;
589d4fb1e02SRoy Marples 	case PS_FILEMTIME:
590d4fb1e02SRoy Marples 		err = filemtime(data, &mtime);
591d4fb1e02SRoy Marples 		if (err != -1) {
592d4fb1e02SRoy Marples 			rdata = &mtime;
593d4fb1e02SRoy Marples 			rlen = sizeof(mtime);
594d4fb1e02SRoy Marples 		}
595d4fb1e02SRoy Marples 		break;
59639994b17SRoy Marples 	case PS_LOGREOPEN:
59739994b17SRoy Marples 		err = logopen(ctx->logfile);
59839994b17SRoy Marples 		break;
599acd7a309SRoy Marples #ifdef AUTH
600acd7a309SRoy Marples 	case PS_AUTH_MONORDM:
601acd7a309SRoy Marples 		err = ps_root_monordm(data, len);
602acd7a309SRoy Marples 		if (err != -1) {
603acd7a309SRoy Marples 			rdata = data;
604acd7a309SRoy Marples 			rlen = len;
605acd7a309SRoy Marples 		}
606acd7a309SRoy Marples 		break;
607acd7a309SRoy Marples #endif
6087f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
609d4fb1e02SRoy Marples 	case PS_GETIFADDRS:
610d4fb1e02SRoy Marples 		err = ps_root_dogetifaddrs(&rdata, &rlen);
611d4fb1e02SRoy Marples 		free_rdata = true;
612d4fb1e02SRoy Marples 		break;
613d4fb1e02SRoy Marples #endif
614d4fb1e02SRoy Marples #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
615d4fb1e02SRoy Marples 	case PS_IP6FORWARDING:
616d4fb1e02SRoy Marples 		 err = ip6_forwarding(data);
617d4fb1e02SRoy Marples 		 break;
618d4fb1e02SRoy Marples #endif
619d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
620d4fb1e02SRoy Marples 	case PS_DEV_INITTED:
621a0d9933aSRoy Marples 		err = dev_initialised(ctx, data);
622d4fb1e02SRoy Marples 		break;
623d4fb1e02SRoy Marples 	case PS_DEV_LISTENING:
624d4fb1e02SRoy Marples 		err = dev_listening(ctx);
625d4fb1e02SRoy Marples 		break;
626d4fb1e02SRoy Marples #endif
6276e63cc1fSRoy Marples 	default:
62880aa9461SRoy Marples 		err = ps_root_os(ctx, psm, msg, &rdata, &rlen, &free_rdata);
6296e63cc1fSRoy Marples 		break;
6306e63cc1fSRoy Marples 	}
6316e63cc1fSRoy Marples 
632d4fb1e02SRoy Marples 	err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen);
633d4fb1e02SRoy Marples 	if (free_rdata)
634d4fb1e02SRoy Marples 		free(rdata);
635d4fb1e02SRoy Marples 	return err;
6366e63cc1fSRoy Marples }
6376e63cc1fSRoy Marples 
6386e63cc1fSRoy Marples /* Receive from state engine, do an action. */
6396e63cc1fSRoy Marples static void
ps_root_recvmsg(void * arg,unsigned short events)64080aa9461SRoy Marples ps_root_recvmsg(void *arg, unsigned short events)
6416e63cc1fSRoy Marples {
64280aa9461SRoy Marples 	struct ps_process *psp = arg;
6436e63cc1fSRoy Marples 
64480aa9461SRoy Marples 	if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
64580aa9461SRoy Marples 	    ps_root_recvmsgcb, psp->psp_ctx) == -1)
6466e63cc1fSRoy Marples 		logerr(__func__);
6476e63cc1fSRoy Marples }
6486e63cc1fSRoy Marples 
649d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
650d4fb1e02SRoy Marples static int
ps_root_handleinterface(void * arg,int action,const char * ifname)651d4fb1e02SRoy Marples ps_root_handleinterface(void *arg, int action, const char *ifname)
652d4fb1e02SRoy Marples {
653d4fb1e02SRoy Marples 	struct dhcpcd_ctx *ctx = arg;
654d4fb1e02SRoy Marples 	unsigned long flag;
655d4fb1e02SRoy Marples 
656d4fb1e02SRoy Marples 	if (action == 1)
657d4fb1e02SRoy Marples 		flag = PS_DEV_IFADDED;
658d4fb1e02SRoy Marples 	else if (action == -1)
659d4fb1e02SRoy Marples 		flag = PS_DEV_IFREMOVED;
660d4fb1e02SRoy Marples 	else if (action == 0)
661d4fb1e02SRoy Marples 		flag = PS_DEV_IFUPDATED;
662d4fb1e02SRoy Marples 	else {
663d4fb1e02SRoy Marples 		errno = EINVAL;
664d4fb1e02SRoy Marples 		return -1;
665d4fb1e02SRoy Marples 	}
666d4fb1e02SRoy Marples 
66780aa9461SRoy Marples 	return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD,
66880aa9461SRoy Marples 	    flag, ifname, strlen(ifname) + 1);
669d4fb1e02SRoy Marples }
670d4fb1e02SRoy Marples #endif
671d4fb1e02SRoy Marples 
6726e63cc1fSRoy Marples static int
ps_root_startcb(struct ps_process * psp)67380aa9461SRoy Marples ps_root_startcb(struct ps_process *psp)
6746e63cc1fSRoy Marples {
67580aa9461SRoy Marples 	struct dhcpcd_ctx *ctx = psp->psp_ctx;
6766e63cc1fSRoy Marples 
6770a68f8d2SRoy Marples 	if (ctx->options & DHCPCD_MANAGER)
6780a68f8d2SRoy Marples 		setproctitle("[privileged proxy]");
679d4fb1e02SRoy Marples 	else
6800a68f8d2SRoy Marples 		setproctitle("[privileged proxy] %s%s%s",
681d4fb1e02SRoy Marples 		    ctx->ifv[0],
682d4fb1e02SRoy Marples 		    ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
683d4fb1e02SRoy Marples 		    ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
684d4fb1e02SRoy Marples 	ctx->options |= DHCPCD_PRIVSEPROOT;
685d4fb1e02SRoy Marples 
68680aa9461SRoy Marples 	if (if_opensockets(ctx) == -1)
68780aa9461SRoy Marples 		logerr("%s: if_opensockets", __func__);
68880aa9461SRoy Marples 
689d4fb1e02SRoy Marples 	/* Open network sockets for sending.
690d4fb1e02SRoy Marples 	 * This is a small bit wasteful for non sandboxed OS's
6910a68f8d2SRoy Marples 	 * but makes life very easy for unicasting DHCPv6 in non manager
692b8b69544SRoy Marples 	 * mode as we no longer care about address selection.
693b8b69544SRoy Marples 	 * We can't call shutdown SHUT_RD on the socket because it's
69480aa9461SRoy Marples 	 * not connected. All we can do is try and set a zero sized
695b8b69544SRoy Marples 	 * receive buffer and just let it overflow.
696b8b69544SRoy Marples 	 * Reading from it just to drain it is a waste of CPU time. */
697d4fb1e02SRoy Marples #ifdef INET
698acd7a309SRoy Marples 	if (ctx->options & DHCPCD_IPV4) {
699b8b69544SRoy Marples 		int buflen = 1;
700b8b69544SRoy Marples 
701acd7a309SRoy Marples 		ctx->udp_wfd = xsocket(PF_INET,
702acd7a309SRoy Marples 		    SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
703d4fb1e02SRoy Marples 		if (ctx->udp_wfd == -1)
704acd7a309SRoy Marples 			logerr("%s: dhcp_openraw", __func__);
705b8b69544SRoy Marples 		else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF,
706b8b69544SRoy Marples 		    &buflen, sizeof(buflen)) == -1)
707b8b69544SRoy Marples 			logerr("%s: setsockopt SO_RCVBUF DHCP", __func__);
708acd7a309SRoy Marples 	}
709d4fb1e02SRoy Marples #endif
710d4fb1e02SRoy Marples #ifdef INET6
711acd7a309SRoy Marples 	if (ctx->options & DHCPCD_IPV6) {
712b8b69544SRoy Marples 		int buflen = 1;
713b8b69544SRoy Marples 
714d4fb1e02SRoy Marples 		ctx->nd_fd = ipv6nd_open(false);
7157f8103cdSRoy Marples 		if (ctx->nd_fd == -1)
716acd7a309SRoy Marples 			logerr("%s: ipv6nd_open", __func__);
717b8b69544SRoy Marples 		else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF,
718b8b69544SRoy Marples 		    &buflen, sizeof(buflen)) == -1)
719b8b69544SRoy Marples 			logerr("%s: setsockopt SO_RCVBUF ND", __func__);
720acd7a309SRoy Marples 	}
721d4fb1e02SRoy Marples #endif
722d4fb1e02SRoy Marples #ifdef DHCP6
723acd7a309SRoy Marples 	if (ctx->options & DHCPCD_IPV6) {
724b8b69544SRoy Marples 		int buflen = 1;
725b8b69544SRoy Marples 
726d4fb1e02SRoy Marples 		ctx->dhcp6_wfd = dhcp6_openraw();
7277f8103cdSRoy Marples 		if (ctx->dhcp6_wfd == -1)
728acd7a309SRoy Marples 			logerr("%s: dhcp6_openraw", __func__);
729b8b69544SRoy Marples 		else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF,
730b8b69544SRoy Marples 		    &buflen, sizeof(buflen)) == -1)
731b8b69544SRoy Marples 			logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__);
732acd7a309SRoy Marples 	}
733d4fb1e02SRoy Marples #endif
734d4fb1e02SRoy Marples 
735d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
736d4fb1e02SRoy Marples 	/* Start any dev listening plugin which may want to
737d4fb1e02SRoy Marples 	 * change the interface name provided by the kernel */
7380a68f8d2SRoy Marples 	if ((ctx->options & (DHCPCD_MANAGER | DHCPCD_DEV)) ==
7390a68f8d2SRoy Marples 	    (DHCPCD_MANAGER | DHCPCD_DEV))
740d4fb1e02SRoy Marples 		dev_start(ctx, ps_root_handleinterface);
741d4fb1e02SRoy Marples #endif
742d4fb1e02SRoy Marples 
7436e63cc1fSRoy Marples 	return 0;
7446e63cc1fSRoy Marples }
7456e63cc1fSRoy Marples 
74680aa9461SRoy Marples void
ps_root_signalcb(int sig,void * arg)74780aa9461SRoy Marples ps_root_signalcb(int sig, void *arg)
7486e63cc1fSRoy Marples {
74980aa9461SRoy Marples 	struct dhcpcd_ctx *ctx = arg;
75080aa9461SRoy Marples 	int status;
75180aa9461SRoy Marples 	pid_t pid;
75280aa9461SRoy Marples 	const char *ifname, *name;
75380aa9461SRoy Marples 	struct ps_process *psp;
7546e63cc1fSRoy Marples 
75580aa9461SRoy Marples 	if (sig != SIGCHLD)
756acd7a309SRoy Marples 		return;
75780aa9461SRoy Marples 
75880aa9461SRoy Marples 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
75980aa9461SRoy Marples 		psp = ps_findprocesspid(ctx, pid);
76080aa9461SRoy Marples 		if (psp != NULL) {
76180aa9461SRoy Marples 			ifname = psp->psp_ifname;
76280aa9461SRoy Marples 			name = psp->psp_name;
76380aa9461SRoy Marples 		} else {
76480aa9461SRoy Marples 			/* Ignore logging the double fork */
76580aa9461SRoy Marples 			if (ctx->options & DHCPCD_LAUNCHER)
76680aa9461SRoy Marples 				continue;
76780aa9461SRoy Marples 			ifname = "";
76880aa9461SRoy Marples 			name = "unknown process";
769acd7a309SRoy Marples 		}
77080aa9461SRoy Marples 
77180aa9461SRoy Marples 		if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
77280aa9461SRoy Marples 			logerrx("%s%s%s exited unexpectedly from PID %d,"
77380aa9461SRoy Marples 			    " code=%d",
77480aa9461SRoy Marples 			    ifname, ifname[0] != '\0' ? ": " : "",
77580aa9461SRoy Marples 			    name, pid, WEXITSTATUS(status));
77680aa9461SRoy Marples 		else if (WIFSIGNALED(status))
77780aa9461SRoy Marples 			logerrx("%s%s%s exited unexpectedly from PID %d,"
77880aa9461SRoy Marples 			    " signal=%s",
77980aa9461SRoy Marples 			    ifname, ifname[0] != '\0' ? ": " : "",
78080aa9461SRoy Marples 			    name, pid, strsignal(WTERMSIG(status)));
78180aa9461SRoy Marples 		else
78280aa9461SRoy Marples 			logdebugx("%s%s%s exited from PID %d",
78380aa9461SRoy Marples 			    ifname, ifname[0] != '\0' ? ": " : "",
78480aa9461SRoy Marples 			    name, pid);
78580aa9461SRoy Marples 
78680aa9461SRoy Marples 		if (psp != NULL)
78780aa9461SRoy Marples 			ps_freeprocess(psp);
78880aa9461SRoy Marples 	}
78980aa9461SRoy Marples 
79080aa9461SRoy Marples 	if (!(ctx->options & DHCPCD_EXITING))
79180aa9461SRoy Marples 		return;
79280aa9461SRoy Marples 	if (!(ps_waitforprocs(ctx)))
79380aa9461SRoy Marples 		eloop_exit(ctx->ps_eloop, EXIT_SUCCESS);
7946e63cc1fSRoy Marples }
7956e63cc1fSRoy Marples 
796d4fb1e02SRoy Marples int (*handle_interface)(void *, int, const char *);
797d4fb1e02SRoy Marples 
798d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
799d4fb1e02SRoy Marples static ssize_t
ps_root_devcb(struct dhcpcd_ctx * ctx,struct ps_msghdr * psm,struct msghdr * msg)800d4fb1e02SRoy Marples ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
801d4fb1e02SRoy Marples {
802d4fb1e02SRoy Marples 	int action;
803d4fb1e02SRoy Marples 	struct iovec *iov = msg->msg_iov;
804d4fb1e02SRoy Marples 
805d4fb1e02SRoy Marples 	if (msg->msg_iovlen != 1) {
806d4fb1e02SRoy Marples 		errno = EINVAL;
807d4fb1e02SRoy Marples 		return -1;
808d4fb1e02SRoy Marples 	}
809d4fb1e02SRoy Marples 
810d4fb1e02SRoy Marples 	switch(psm->ps_flags) {
811d4fb1e02SRoy Marples 	case PS_DEV_IFADDED:
812d4fb1e02SRoy Marples 		action = 1;
813d4fb1e02SRoy Marples 		break;
814d4fb1e02SRoy Marples 	case PS_DEV_IFREMOVED:
815d4fb1e02SRoy Marples 		action = -1;
816d4fb1e02SRoy Marples 		break;
817d4fb1e02SRoy Marples 	case PS_DEV_IFUPDATED:
818d4fb1e02SRoy Marples 		action = 0;
819d4fb1e02SRoy Marples 		break;
820d4fb1e02SRoy Marples 	default:
821d4fb1e02SRoy Marples 		errno = EINVAL;
822d4fb1e02SRoy Marples 		return -1;
823d4fb1e02SRoy Marples 	}
824d4fb1e02SRoy Marples 
825d4fb1e02SRoy Marples 	return dhcpcd_handleinterface(ctx, action, iov->iov_base);
826d4fb1e02SRoy Marples }
827d4fb1e02SRoy Marples #endif
828d4fb1e02SRoy Marples 
8296e63cc1fSRoy Marples static ssize_t
ps_root_dispatchcb(void * arg,struct ps_msghdr * psm,struct msghdr * msg)8306e63cc1fSRoy Marples ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
8316e63cc1fSRoy Marples {
8326e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = arg;
8336e63cc1fSRoy Marples 	ssize_t err;
8346e63cc1fSRoy Marples 
835d4fb1e02SRoy Marples 	switch(psm->ps_cmd) {
836d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
837d4fb1e02SRoy Marples 	case PS_DEV_IFCMD:
838d4fb1e02SRoy Marples 		err = ps_root_devcb(ctx, psm, msg);
839d4fb1e02SRoy Marples 		break;
840d4fb1e02SRoy Marples #endif
841d4fb1e02SRoy Marples 	default:
842280986e4SRoy Marples #ifdef INET
8436e63cc1fSRoy Marples 		err = ps_bpf_dispatch(ctx, psm, msg);
8446e63cc1fSRoy Marples 		if (err == -1 && errno == ENOTSUP)
845280986e4SRoy Marples #endif
8466e63cc1fSRoy Marples 			err = ps_inet_dispatch(ctx, psm, msg);
847d4fb1e02SRoy Marples 	}
8486e63cc1fSRoy Marples 	return err;
8496e63cc1fSRoy Marples }
8506e63cc1fSRoy Marples 
8516e63cc1fSRoy Marples static void
ps_root_dispatch(void * arg,unsigned short events)85280aa9461SRoy Marples ps_root_dispatch(void *arg, unsigned short events)
8536e63cc1fSRoy Marples {
8546e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = arg;
8556e63cc1fSRoy Marples 
85680aa9461SRoy Marples 	if (ps_recvpsmsg(ctx, ctx->ps_data_fd, events,
85780aa9461SRoy Marples 	    ps_root_dispatchcb, ctx) == -1)
8586e63cc1fSRoy Marples 		logerr(__func__);
8596e63cc1fSRoy Marples }
8606e63cc1fSRoy Marples 
86139994b17SRoy Marples static void
ps_root_log(void * arg,unsigned short events)86280aa9461SRoy Marples ps_root_log(void *arg, unsigned short events)
86339994b17SRoy Marples {
86439994b17SRoy Marples 	struct dhcpcd_ctx *ctx = arg;
86539994b17SRoy Marples 
86680aa9461SRoy Marples 	if (events != ELE_READ)
86780aa9461SRoy Marples 		logerrx("%s: unexpected event 0x%04x", __func__, events);
86880aa9461SRoy Marples 
86980aa9461SRoy Marples 	if (logreadfd(ctx->ps_log_root_fd) == -1)
87039994b17SRoy Marples 		logerr(__func__);
87139994b17SRoy Marples }
87239994b17SRoy Marples 
8736e63cc1fSRoy Marples pid_t
ps_root_start(struct dhcpcd_ctx * ctx)8746e63cc1fSRoy Marples ps_root_start(struct dhcpcd_ctx *ctx)
8756e63cc1fSRoy Marples {
87680aa9461SRoy Marples 	struct ps_id id = {
87780aa9461SRoy Marples 		.psi_ifindex = 0,
87880aa9461SRoy Marples 		.psi_cmd = PS_ROOT,
87980aa9461SRoy Marples 	};
88080aa9461SRoy Marples 	struct ps_process *psp;
88139994b17SRoy Marples 	int logfd[2], datafd[2];
8826e63cc1fSRoy Marples 	pid_t pid;
8836e63cc1fSRoy Marples 
88480aa9461SRoy Marples 	if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, logfd) == -1)
8857f8103cdSRoy Marples 		return -1;
8867f8103cdSRoy Marples #ifdef PRIVSEP_RIGHTS
88739994b17SRoy Marples 	if (ps_rights_limit_fdpair(logfd) == -1)
88839994b17SRoy Marples 		return -1;
88939994b17SRoy Marples #endif
89039994b17SRoy Marples 
891*54175cefSRoy Marples 	if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
89239994b17SRoy Marples 		return -1;
89339994b17SRoy Marples 	if (ps_setbuf_fdpair(datafd) == -1)
89439994b17SRoy Marples 		return -1;
89539994b17SRoy Marples #ifdef PRIVSEP_RIGHTS
89639994b17SRoy Marples 	if (ps_rights_limit_fdpair(datafd) == -1)
8977f8103cdSRoy Marples 		return -1;
8987f8103cdSRoy Marples #endif
8996e63cc1fSRoy Marples 
90080aa9461SRoy Marples 	psp = ctx->ps_root = ps_newprocess(ctx, &id);
90180aa9461SRoy Marples 	strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name));
90280aa9461SRoy Marples 	pid = ps_startprocess(psp, ps_root_recvmsg, NULL,
90380aa9461SRoy Marples 	    ps_root_startcb, ps_root_signalcb, PSF_ELOOP);
9046e63cc1fSRoy Marples 
9056e63cc1fSRoy Marples 	if (pid == 0) {
90680aa9461SRoy Marples 		ctx->ps_log_fd = logfd[0]; /* Keep open to pass to processes */
90780aa9461SRoy Marples 		ctx->ps_log_root_fd = logfd[1];
90880aa9461SRoy Marples 		if (eloop_event_add(ctx->eloop, ctx->ps_log_root_fd, ELE_READ,
90939994b17SRoy Marples 		    ps_root_log, ctx) == -1)
91039994b17SRoy Marples 			return -1;
91139994b17SRoy Marples 		ctx->ps_data_fd = datafd[1];
91239994b17SRoy Marples 		close(datafd[0]);
9136e63cc1fSRoy Marples 		return 0;
9146e63cc1fSRoy Marples 	} else if (pid == -1)
9156e63cc1fSRoy Marples 		return -1;
9166e63cc1fSRoy Marples 
91739994b17SRoy Marples 	logsetfd(logfd[0]);
91839994b17SRoy Marples 	close(logfd[1]);
91939994b17SRoy Marples 
92039994b17SRoy Marples 	ctx->ps_data_fd = datafd[0];
92139994b17SRoy Marples 	close(datafd[1]);
92280aa9461SRoy Marples 	if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, ELE_READ,
9236e63cc1fSRoy Marples 	    ps_root_dispatch, ctx) == -1)
92480aa9461SRoy Marples 		return 1;
925d4fb1e02SRoy Marples 
9266e63cc1fSRoy Marples 	return pid;
9276e63cc1fSRoy Marples }
9286e63cc1fSRoy Marples 
929*54175cefSRoy Marples void
ps_root_close(struct dhcpcd_ctx * ctx)930*54175cefSRoy Marples ps_root_close(struct dhcpcd_ctx *ctx)
931*54175cefSRoy Marples {
932*54175cefSRoy Marples 
933*54175cefSRoy Marples 	if_closesockets(ctx);
934*54175cefSRoy Marples 
935*54175cefSRoy Marples #ifdef INET
936*54175cefSRoy Marples 	if (ctx->udp_wfd != -1) {
937*54175cefSRoy Marples 		close(ctx->udp_wfd);
938*54175cefSRoy Marples 		ctx->udp_wfd = -1;
939*54175cefSRoy Marples 	}
940*54175cefSRoy Marples #endif
941*54175cefSRoy Marples #ifdef INET6
942*54175cefSRoy Marples 	if (ctx->nd_fd != -1) {
943*54175cefSRoy Marples 		close(ctx->nd_fd);
944*54175cefSRoy Marples 		ctx->nd_fd = -1;
945*54175cefSRoy Marples 	}
946*54175cefSRoy Marples #endif
947*54175cefSRoy Marples #ifdef DHCP6
948*54175cefSRoy Marples 	if (ctx->dhcp6_wfd != -1) {
949*54175cefSRoy Marples 		close(ctx->dhcp6_wfd);
950*54175cefSRoy Marples 		ctx->dhcp6_wfd = -1;
951*54175cefSRoy Marples 	}
952*54175cefSRoy Marples #endif
953*54175cefSRoy Marples }
954*54175cefSRoy Marples 
9556e63cc1fSRoy Marples int
ps_root_stop(struct dhcpcd_ctx * ctx)9566e63cc1fSRoy Marples ps_root_stop(struct dhcpcd_ctx *ctx)
9576e63cc1fSRoy Marples {
95880aa9461SRoy Marples 	struct ps_process *psp = ctx->ps_root;
9596e63cc1fSRoy Marples 
96080aa9461SRoy Marples 	if (!(ctx->options & DHCPCD_PRIVSEP) ||
96180aa9461SRoy Marples 	    ctx->eloop == NULL)
96280aa9461SRoy Marples 		return 0;
96380aa9461SRoy Marples 
96480aa9461SRoy Marples 	/* If we are the root process then remove the pidfile */
96580aa9461SRoy Marples 	if (ctx->options & DHCPCD_PRIVSEPROOT &&
96680aa9461SRoy Marples 	    !(ctx->options & DHCPCD_TEST))
96780aa9461SRoy Marples 	{
96880aa9461SRoy Marples 		if (unlink(ctx->pidfile) == -1)
96980aa9461SRoy Marples 			logerr("%s: unlink: %s", __func__, ctx->pidfile);
97080aa9461SRoy Marples 	}
97180aa9461SRoy Marples 
97280aa9461SRoy Marples 	/* Only the manager process gets past this point. */
97380aa9461SRoy Marples 	if (ctx->options & DHCPCD_FORKED)
97480aa9461SRoy Marples 		return 0;
97580aa9461SRoy Marples 
97680aa9461SRoy Marples 	/* We cannot log the root process exited before we
97780aa9461SRoy Marples 	 * log dhcpcd exits because the latter requires the former.
97880aa9461SRoy Marples 	 * So we just log the intent to exit.
97980aa9461SRoy Marples 	 * Even sending this will be a race to exit. */
980f3744ac9SRoy Marples 	if (psp) {
98180aa9461SRoy Marples 		logdebugx("%s%s%s will exit from PID %d",
98280aa9461SRoy Marples 		    psp->psp_ifname,
98380aa9461SRoy Marples 		    psp->psp_ifname[0] != '\0' ? ": " : "",
98480aa9461SRoy Marples 		    psp->psp_name, psp->psp_pid);
98580aa9461SRoy Marples 
98680aa9461SRoy Marples 		if (ps_stopprocess(psp) == -1)
98780aa9461SRoy Marples 			return -1;
988f3744ac9SRoy Marples 	} /* else the root process has already exited :( */
98980aa9461SRoy Marples 
99080aa9461SRoy Marples 	return ps_stopwait(ctx);
99180aa9461SRoy Marples }
99280aa9461SRoy Marples 
99380aa9461SRoy Marples ssize_t
ps_root_stopprocesses(struct dhcpcd_ctx * ctx)99480aa9461SRoy Marples ps_root_stopprocesses(struct dhcpcd_ctx *ctx)
99580aa9461SRoy Marples {
99680aa9461SRoy Marples 
99780aa9461SRoy Marples 	if (!(IN_PRIVSEP_SE(ctx)))
99880aa9461SRoy Marples 		return 0;
99980aa9461SRoy Marples 
1000f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_STOPPROCS, 0,
100180aa9461SRoy Marples 	    NULL, 0) == -1)
100280aa9461SRoy Marples 		return -1;
100380aa9461SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
10046e63cc1fSRoy Marples }
10056e63cc1fSRoy Marples 
10066e63cc1fSRoy Marples ssize_t
ps_root_script(struct dhcpcd_ctx * ctx,const void * data,size_t len)1007d4fb1e02SRoy Marples ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
10086e63cc1fSRoy Marples {
10096e63cc1fSRoy Marples 
1010f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_SCRIPT,
101180aa9461SRoy Marples 	    0, data, len) == -1)
10126e63cc1fSRoy Marples 		return -1;
1013d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
10146e63cc1fSRoy Marples }
10156e63cc1fSRoy Marples 
10166e63cc1fSRoy Marples ssize_t
ps_root_ioctl(struct dhcpcd_ctx * ctx,ioctl_request_t req,void * data,size_t len)10176e63cc1fSRoy Marples ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
10186e63cc1fSRoy Marples     size_t len)
10196e63cc1fSRoy Marples {
1020f3744ac9SRoy Marples 	int fd = PS_ROOT_FD(ctx);
10216e63cc1fSRoy Marples #ifdef IOCTL_REQUEST_TYPE
10226e63cc1fSRoy Marples 	unsigned long ulreq = 0;
10236e63cc1fSRoy Marples 
10246e63cc1fSRoy Marples 	memcpy(&ulreq, &req, sizeof(req));
102580aa9461SRoy Marples 	if (ps_sendcmd(ctx, fd, PS_IOCTL, ulreq, data, len) == -1)
10266e63cc1fSRoy Marples 		return -1;
10276e63cc1fSRoy Marples #else
102880aa9461SRoy Marples 	if (ps_sendcmd(ctx, fd, PS_IOCTL, req, data, len) == -1)
10296e63cc1fSRoy Marples 		return -1;
10306e63cc1fSRoy Marples #endif
1031d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, data, len);
10326e63cc1fSRoy Marples }
10336e63cc1fSRoy Marples 
1034d4fb1e02SRoy Marples ssize_t
ps_root_unlink(struct dhcpcd_ctx * ctx,const char * file)1035d4fb1e02SRoy Marples ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
10366e63cc1fSRoy Marples {
10376e63cc1fSRoy Marples 
1038f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_UNLINK, 0,
1039d4fb1e02SRoy Marples 	    file, strlen(file) + 1) == -1)
1040d4fb1e02SRoy Marples 		return -1;
1041d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
1042d4fb1e02SRoy Marples }
1043d4fb1e02SRoy Marples 
1044d4fb1e02SRoy Marples ssize_t
ps_root_readfile(struct dhcpcd_ctx * ctx,const char * file,void * data,size_t len)1045d4fb1e02SRoy Marples ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
1046d4fb1e02SRoy Marples     void *data, size_t len)
1047d4fb1e02SRoy Marples {
1048f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_READFILE, 0,
1049d4fb1e02SRoy Marples 	    file, strlen(file) + 1) == -1)
1050d4fb1e02SRoy Marples 		return -1;
1051d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, data, len);
1052d4fb1e02SRoy Marples }
1053d4fb1e02SRoy Marples 
1054d4fb1e02SRoy Marples ssize_t
ps_root_writefile(struct dhcpcd_ctx * ctx,const char * file,mode_t mode,const void * data,size_t len)1055d4fb1e02SRoy Marples ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
1056d4fb1e02SRoy Marples     const void *data, size_t len)
1057d4fb1e02SRoy Marples {
1058d4fb1e02SRoy Marples 	char buf[PS_BUFLEN];
1059d4fb1e02SRoy Marples 	size_t flen;
1060d4fb1e02SRoy Marples 
1061d4fb1e02SRoy Marples 	flen = strlcpy(buf, file, sizeof(buf));
1062d4fb1e02SRoy Marples 	flen += 1;
1063d4fb1e02SRoy Marples 	if (flen > sizeof(buf) || flen + len > sizeof(buf)) {
10646e63cc1fSRoy Marples 		errno = ENOBUFS;
10656e63cc1fSRoy Marples 		return -1;
10666e63cc1fSRoy Marples 	}
1067d4fb1e02SRoy Marples 	memcpy(buf + flen, data, len);
10686e63cc1fSRoy Marples 
1069f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_WRITEFILE, mode,
1070d4fb1e02SRoy Marples 	    buf, flen + len) == -1)
10716e63cc1fSRoy Marples 		return -1;
1072d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
10736e63cc1fSRoy Marples }
10746e63cc1fSRoy Marples 
10756e63cc1fSRoy Marples ssize_t
ps_root_filemtime(struct dhcpcd_ctx * ctx,const char * file,time_t * time)1076d4fb1e02SRoy Marples ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
10776e63cc1fSRoy Marples {
10786e63cc1fSRoy Marples 
1079f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_FILEMTIME, 0,
1080d4fb1e02SRoy Marples 	    file, strlen(file) + 1) == -1)
1081d4fb1e02SRoy Marples 		return -1;
1082d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, time, sizeof(*time));
10836e63cc1fSRoy Marples }
1084d4fb1e02SRoy Marples 
108539994b17SRoy Marples ssize_t
ps_root_logreopen(struct dhcpcd_ctx * ctx)108639994b17SRoy Marples ps_root_logreopen(struct dhcpcd_ctx *ctx)
108739994b17SRoy Marples {
108839994b17SRoy Marples 
1089f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_LOGREOPEN, 0,
109080aa9461SRoy Marples 	    NULL, 0) == -1)
109139994b17SRoy Marples 		return -1;
109239994b17SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
109339994b17SRoy Marples }
109439994b17SRoy Marples 
10957f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
1096d4fb1e02SRoy Marples int
ps_root_getifaddrs(struct dhcpcd_ctx * ctx,struct ifaddrs ** ifahead)1097d4fb1e02SRoy Marples ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
1098d4fb1e02SRoy Marples {
1099d4fb1e02SRoy Marples 	struct ifaddrs *ifa;
1100d4fb1e02SRoy Marples 	void *buf = NULL;
1101d4fb1e02SRoy Marples 	char *bp, *sap;
1102d4fb1e02SRoy Marples 	socklen_t salen;
1103d4fb1e02SRoy Marples 	size_t len;
1104d4fb1e02SRoy Marples 	ssize_t err;
1105d4fb1e02SRoy Marples 
1106f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx),
1107d4fb1e02SRoy Marples 	    PS_GETIFADDRS, 0, NULL, 0) == -1)
1108d4fb1e02SRoy Marples 		return -1;
1109d4fb1e02SRoy Marples 	err = ps_root_mreaderror(ctx, &buf, &len);
1110d4fb1e02SRoy Marples 
1111d4fb1e02SRoy Marples 	if (err == -1)
1112d4fb1e02SRoy Marples 		return -1;
1113d4fb1e02SRoy Marples 
1114d4fb1e02SRoy Marples 	/* Should be impossible - lo0 will always exist. */
1115d4fb1e02SRoy Marples 	if (len == 0) {
1116d4fb1e02SRoy Marples 		*ifahead = NULL;
1117d4fb1e02SRoy Marples 		return 0;
1118d4fb1e02SRoy Marples 	}
1119d4fb1e02SRoy Marples 
1120d4fb1e02SRoy Marples 	bp = buf;
1121d4fb1e02SRoy Marples 	*ifahead = (struct ifaddrs *)(void *)bp;
11227f8103cdSRoy Marples 	for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) {
1123d4fb1e02SRoy Marples 		if (len < ALIGN(sizeof(*ifa)) +
1124d4fb1e02SRoy Marples 		    ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS))
1125d4fb1e02SRoy Marples 			goto err;
1126d4fb1e02SRoy Marples 		bp += ALIGN(sizeof(*ifa));
1127d4fb1e02SRoy Marples 		ifa->ifa_name = bp;
1128d4fb1e02SRoy Marples 		bp += ALIGN(IFNAMSIZ);
1129d4fb1e02SRoy Marples 		sap = bp;
1130d4fb1e02SRoy Marples 		bp += ALIGN(sizeof(salen) * IFA_NADDRS);
1131d4fb1e02SRoy Marples 		len -= ALIGN(sizeof(*ifa)) +
1132d4fb1e02SRoy Marples 		    ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS);
1133d4fb1e02SRoy Marples 
1134d4fb1e02SRoy Marples #define	COPYOUTSA(addr)							\
1135d4fb1e02SRoy Marples 	do {								\
1136d4fb1e02SRoy Marples 		memcpy(&salen, sap, sizeof(salen));			\
1137d4fb1e02SRoy Marples 		if (len < salen)					\
1138d4fb1e02SRoy Marples 			goto err;					\
1139d4fb1e02SRoy Marples 		if (salen != 0) {					\
114080aa9461SRoy Marples 			(addr) = (struct sockaddr *)(void *)bp;		\
1141d4fb1e02SRoy Marples 			bp += ALIGN(salen);				\
1142d4fb1e02SRoy Marples 			len -= ALIGN(salen);				\
1143d4fb1e02SRoy Marples 		}							\
1144d4fb1e02SRoy Marples 		sap += sizeof(salen);					\
1145d4fb1e02SRoy Marples 	} while (0 /* CONSTCOND */)
1146d4fb1e02SRoy Marples 
1147d4fb1e02SRoy Marples 		COPYOUTSA(ifa->ifa_addr);
1148d4fb1e02SRoy Marples 		COPYOUTSA(ifa->ifa_netmask);
1149d4fb1e02SRoy Marples 		COPYOUTSA(ifa->ifa_broadaddr);
1150a0d9933aSRoy Marples 
1151a0d9933aSRoy Marples 		memcpy(&salen, sap, sizeof(salen));
1152a0d9933aSRoy Marples 		if (len < salen)
1153a0d9933aSRoy Marples 			goto err;
1154a0d9933aSRoy Marples 		if (salen != 0) {
1155a0d9933aSRoy Marples 			ifa->ifa_data = bp;
1156a0d9933aSRoy Marples 			bp += ALIGN(salen);
1157a0d9933aSRoy Marples 			len -= ALIGN(salen);
1158a0d9933aSRoy Marples 		} else
1159a0d9933aSRoy Marples 			ifa->ifa_data = NULL;
1160a0d9933aSRoy Marples 
11617f8103cdSRoy Marples 		if (len != 0)
1162d4fb1e02SRoy Marples 			ifa->ifa_next = (struct ifaddrs *)(void *)bp;
11637f8103cdSRoy Marples 		else
1164d4fb1e02SRoy Marples 			ifa->ifa_next = NULL;
11657f8103cdSRoy Marples 	}
1166d4fb1e02SRoy Marples 	return 0;
1167d4fb1e02SRoy Marples 
1168d4fb1e02SRoy Marples err:
1169d4fb1e02SRoy Marples 	free(buf);
1170d4fb1e02SRoy Marples 	*ifahead = NULL;
1171d4fb1e02SRoy Marples 	errno = EINVAL;
1172d4fb1e02SRoy Marples 	return -1;
1173d4fb1e02SRoy Marples }
1174d4fb1e02SRoy Marples #endif
1175d4fb1e02SRoy Marples 
1176d4fb1e02SRoy Marples #if defined(__linux__) || defined(HAVE_PLEDGE)
1177d4fb1e02SRoy Marples ssize_t
ps_root_ip6forwarding(struct dhcpcd_ctx * ctx,const char * ifname)1178d4fb1e02SRoy Marples ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
1179d4fb1e02SRoy Marples {
1180d4fb1e02SRoy Marples 
1181f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IP6FORWARDING, 0,
1182d4fb1e02SRoy Marples 	    ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1)
1183d4fb1e02SRoy Marples 		return -1;
1184d4fb1e02SRoy Marples 	return ps_root_readerror(ctx, NULL, 0);
1185d4fb1e02SRoy Marples }
1186d4fb1e02SRoy Marples #endif
1187d4fb1e02SRoy Marples 
1188acd7a309SRoy Marples #ifdef AUTH
1189acd7a309SRoy Marples int
ps_root_getauthrdm(struct dhcpcd_ctx * ctx,uint64_t * rdm)1190acd7a309SRoy Marples ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm)
1191acd7a309SRoy Marples {
1192acd7a309SRoy Marples 
1193f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_AUTH_MONORDM, 0,
11947f8103cdSRoy Marples 	    rdm, sizeof(*rdm))== -1)
1195acd7a309SRoy Marples 		return -1;
1196acd7a309SRoy Marples 	return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm));
1197acd7a309SRoy Marples }
1198acd7a309SRoy Marples #endif
1199acd7a309SRoy Marples 
1200d4fb1e02SRoy Marples #ifdef PLUGIN_DEV
1201d4fb1e02SRoy Marples int
ps_root_dev_initialised(struct dhcpcd_ctx * ctx,const char * ifname)1202a0d9933aSRoy Marples ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname)
1203d4fb1e02SRoy Marples {
1204d4fb1e02SRoy Marples 
1205f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_DEV_INITTED, 0,
1206d4fb1e02SRoy Marples 	    ifname, strlen(ifname) + 1)== -1)
1207d4fb1e02SRoy Marples 		return -1;
1208d4fb1e02SRoy Marples 	return (int)ps_root_readerror(ctx, NULL, 0);
1209d4fb1e02SRoy Marples }
1210d4fb1e02SRoy Marples 
1211d4fb1e02SRoy Marples int
ps_root_dev_listening(struct dhcpcd_ctx * ctx)1212d4fb1e02SRoy Marples ps_root_dev_listening(struct dhcpcd_ctx * ctx)
1213d4fb1e02SRoy Marples {
1214d4fb1e02SRoy Marples 
1215f3744ac9SRoy Marples 	if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_DEV_LISTENING,
121680aa9461SRoy Marples 	    0, NULL, 0) == -1)
1217d4fb1e02SRoy Marples 		return -1;
1218d4fb1e02SRoy Marples 	return (int)ps_root_readerror(ctx, NULL, 0);
1219d4fb1e02SRoy Marples }
1220d4fb1e02SRoy Marples #endif
1221