xref: /dflybsd-src/contrib/dhcpcd/src/control.c (revision 8fbc264d2bc2add66aefe4f4a7966c4364da1211)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * dhcpcd - DHCP client daemon
4  * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
5  * All rights reserved
6 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/uio.h>
32 #include <sys/un.h>
33 
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41 
42 #include "config.h"
43 #include "common.h"
44 #include "dhcpcd.h"
45 #include "control.h"
46 #include "eloop.h"
47 #include "if.h"
48 #include "logerr.h"
49 
50 #ifndef SUN_LEN
51 #define SUN_LEN(su) \
52             (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
53 #endif
54 
55 static void
56 control_queue_free(struct fd_list *fd)
57 {
58 	struct fd_data *fdp;
59 
60 	while ((fdp = TAILQ_FIRST(&fd->queue))) {
61 		TAILQ_REMOVE(&fd->queue, fdp, next);
62 		if (fdp->data_size != 0)
63 			free(fdp->data);
64 		free(fdp);
65 	}
66 	fd->queue_len = 0;
67 
68 #ifdef CTL_FREE_LIST
69 	while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
70 		TAILQ_REMOVE(&fd->free_queue, fdp, next);
71 		if (fdp->data_size != 0)
72 			free(fdp->data);
73 		free(fdp);
74 	}
75 #endif
76 }
77 
78 static void
79 control_delete(struct fd_list *fd)
80 {
81 
82 	TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
83 	eloop_event_delete(fd->ctx->eloop, fd->fd);
84 	close(fd->fd);
85 	control_queue_free(fd);
86 	free(fd);
87 }
88 
89 static void
90 control_handle_data(void *arg)
91 {
92 	struct fd_list *fd = arg;
93 	char buffer[1024], *e, *p, *argvp[255], **ap, *a;
94 	ssize_t bytes;
95 	size_t len;
96 	int argc;
97 
98 	bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
99 	if (bytes == -1 || bytes == 0) {
100 		/* Control was closed or there was an error.
101 		 * Remove it from our list. */
102 		control_delete(fd);
103 		return;
104 	}
105 	buffer[bytes] = '\0';
106 	p = buffer;
107 	e = buffer + bytes;
108 
109 	/* Each command is \n terminated
110 	 * Each argument is NULL separated */
111 	while (p < e) {
112 		argc = 0;
113 		ap = argvp;
114 		while (p < e) {
115 			argc++;
116 			if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
117 				errno = ENOBUFS;
118 				return;
119 			}
120 			a = *ap++ = p;
121 			len = strlen(p);
122 			p += len + 1;
123 			if (len && a[len - 1] == '\n') {
124 				a[len - 1] = '\0';
125 				break;
126 			}
127 		}
128 		*ap = NULL;
129 		if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
130 			logerr(__func__);
131 			if (errno != EINTR && errno != EAGAIN) {
132 				control_delete(fd);
133 				return;
134 			}
135 		}
136 	}
137 }
138 
139 static void
140 control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
141 {
142 	struct sockaddr_un run;
143 	socklen_t len;
144 	struct fd_list *l;
145 	int fd, flags;
146 
147 	len = sizeof(run);
148 	if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
149 		goto error;
150 	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
151 	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
152 		goto error;
153 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
154 	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
155 		goto error;
156 
157 	l = malloc(sizeof(*l));
158 	if (l == NULL)
159 		goto error;
160 
161 	l->ctx = ctx;
162 	l->fd = fd;
163 	l->flags = fd_flags;
164 	TAILQ_INIT(&l->queue);
165 	l->queue_len = 0;
166 #ifdef CTL_FREE_LIST
167 	TAILQ_INIT(&l->free_queue);
168 #endif
169 	TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
170 	eloop_event_add(ctx->eloop, l->fd, control_handle_data, l);
171 	return;
172 
173 error:
174 	logerr(__func__);
175 	if (fd != -1)
176 		close(fd);
177 }
178 
179 static void
180 control_handle(void *arg)
181 {
182 	struct dhcpcd_ctx *ctx = arg;
183 
184 	control_handle1(ctx, ctx->control_fd, 0);
185 }
186 
187 static void
188 control_handle_unpriv(void *arg)
189 {
190 	struct dhcpcd_ctx *ctx = arg;
191 
192 	control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
193 }
194 
195 static int
196 make_sock(struct sockaddr_un *sa, const char *ifname, sa_family_t family,
197     bool unpriv)
198 {
199 	int fd;
200 
201 	if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0)) == -1)
202 		return -1;
203 	memset(sa, 0, sizeof(*sa));
204 	sa->sun_family = AF_UNIX;
205 	if (unpriv)
206 		strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
207 	else {
208 		const char *per;
209 
210 		switch(family) {
211 		case AF_INET:
212 			per = "-4";
213 			break;
214 		case AF_INET6:
215 			per = "-6";
216 			break;
217 		default:
218 			per = "";
219 			break;
220 		}
221 		snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
222 		    ifname ? ifname : "", ifname ? per : "", ifname ? "." : "");
223 	}
224 	return fd;
225 }
226 
227 #define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
228 #define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
229 
230 static int
231 control_start1(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family,
232     mode_t fmode)
233 {
234 	struct sockaddr_un sa;
235 	int fd;
236 	socklen_t len;
237 
238 	fd = make_sock(&sa, ifname, family, (fmode & S_UNPRIV) == S_UNPRIV);
239 	if (fd == -1)
240 		return -1;
241 
242 	len = (socklen_t)SUN_LEN(&sa);
243 	unlink(sa.sun_path);
244 	if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
245 	    chmod(sa.sun_path, fmode) == -1 ||
246 	    (ctx->control_group &&
247 	    chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
248 	    listen(fd, sizeof(ctx->control_fds)) == -1)
249 	{
250 		close(fd);
251 		unlink(sa.sun_path);
252 		return -1;
253 	}
254 
255 	if ((fmode & S_UNPRIV) != S_UNPRIV)
256 		strlcpy(ctx->control_sock, sa.sun_path,
257 		    sizeof(ctx->control_sock));
258 	return fd;
259 }
260 
261 int
262 control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family)
263 {
264 	int fd;
265 
266 	if ((fd = control_start1(ctx, ifname, family, S_PRIV)) == -1)
267 		return -1;
268 
269 	ctx->control_fd = fd;
270 	eloop_event_add(ctx->eloop, fd, control_handle, ctx);
271 
272 	if (ifname == NULL &&
273 	    (fd = control_start1(ctx, NULL, AF_UNSPEC, S_UNPRIV)) != -1)
274 	{
275 		/* We must be in master mode, so create an unprivileged socket
276 		 * to allow normal users to learn the status of dhcpcd. */
277 		ctx->control_unpriv_fd = fd;
278 		eloop_event_add(ctx->eloop, fd, control_handle_unpriv, ctx);
279 	}
280 	return ctx->control_fd;
281 }
282 
283 static int
284 control_unlink(struct dhcpcd_ctx *ctx, const char *file)
285 {
286 	int retval = 0;
287 
288 	errno = 0;
289 #ifdef PRIVSEP
290 	if (ctx->options & DHCPCD_PRIVSEP)
291 		retval = (int)ps_root_unlink(ctx, file);
292 	else
293 #else
294 		UNUSED(ctx);
295 #endif
296 		retval = unlink(file);
297 
298 	return retval == -1 && errno != ENOENT ? -1 : 0;
299 }
300 
301 int
302 control_stop(struct dhcpcd_ctx *ctx)
303 {
304 	int retval = 0;
305 	struct fd_list *l;
306 
307 	if (ctx->options & DHCPCD_FORKED)
308 		return 0;
309 
310 	if (ctx->control_fd != -1) {
311 		eloop_event_delete(ctx->eloop, ctx->control_fd);
312 		close(ctx->control_fd);
313 		ctx->control_fd = -1;
314 		if (control_unlink(ctx, ctx->control_sock) == -1)
315 			retval = -1;
316 	}
317 
318 	if (ctx->control_unpriv_fd != -1) {
319 		eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
320 		close(ctx->control_unpriv_fd);
321 		ctx->control_unpriv_fd = -1;
322 		if (control_unlink(ctx, UNPRIVSOCKET) == -1)
323 			retval = -1;
324 	}
325 
326 	while ((l = TAILQ_FIRST(&ctx->control_fds))) {
327 		TAILQ_REMOVE(&ctx->control_fds, l, next);
328 		eloop_event_delete(ctx->eloop, l->fd);
329 		close(l->fd);
330 		control_queue_free(l);
331 		free(l);
332 	}
333 
334 	return retval;
335 }
336 
337 int
338 control_open(const char *ifname, sa_family_t family, bool unpriv)
339 {
340 	struct sockaddr_un sa;
341 	int fd;
342 
343 	if ((fd = make_sock(&sa, ifname, family, unpriv)) != -1) {
344 		socklen_t len;
345 
346 		len = (socklen_t)SUN_LEN(&sa);
347 		if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
348 			close(fd);
349 			fd = -1;
350 		}
351 	}
352 	return fd;
353 }
354 
355 ssize_t
356 control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
357 {
358 	char buffer[1024];
359 	int i;
360 	size_t len, l;
361 
362 	if (argc > 255) {
363 		errno = ENOBUFS;
364 		return -1;
365 	}
366 	len = 0;
367 	for (i = 0; i < argc; i++) {
368 		l = strlen(argv[i]) + 1;
369 		if (len + l > sizeof(buffer)) {
370 			errno = ENOBUFS;
371 			return -1;
372 		}
373 		memcpy(buffer + len, argv[i], l);
374 		len += l;
375 	}
376 	return write(ctx->control_fd, buffer, len);
377 }
378 
379 static void
380 control_writeone(void *arg)
381 {
382 	struct fd_list *fd;
383 	struct iovec iov[2];
384 	struct fd_data *data;
385 
386 	fd = arg;
387 	data = TAILQ_FIRST(&fd->queue);
388 	iov[0].iov_base = &data->data_len;
389 	iov[0].iov_len = sizeof(size_t);
390 	iov[1].iov_base = data->data;
391 	iov[1].iov_len = data->data_len;
392 	if (writev(fd->fd, iov, 2) == -1) {
393 		logerr(__func__);
394 		if (errno != EINTR && errno != EAGAIN)
395 			control_delete(fd);
396 		return;
397 	}
398 
399 	TAILQ_REMOVE(&fd->queue, data, next);
400 	fd->queue_len--;
401 #ifdef CTL_FREE_LIST
402 	TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
403 #else
404 	if (data->data_size != 0)
405 		free(data->data);
406 	free(data);
407 #endif
408 
409 	if (TAILQ_FIRST(&fd->queue) == NULL)
410 		eloop_event_remove_writecb(fd->ctx->eloop, fd->fd);
411 }
412 
413 int
414 control_queue(struct fd_list *fd, void *data, size_t data_len, bool fit)
415 {
416 	struct fd_data *d;
417 
418 	if (data_len == 0)
419 		return 0;
420 
421 #ifdef CTL_FREE_LIST
422 	struct fd_data *df;
423 
424 	d = NULL;
425 	TAILQ_FOREACH(df, &fd->free_queue, next) {
426 		if (!fit) {
427 			if (df->data_size == 0) {
428 				d = df;
429 				break;
430 			}
431 			continue;
432 		}
433 		if (d == NULL || d->data_size < df->data_size) {
434 			d = df;
435 			if (d->data_size <= data_len)
436 				break;
437 		}
438 	}
439 	if (d != NULL)
440 		TAILQ_REMOVE(&fd->free_queue, d, next);
441 	else
442 #endif
443 	{
444 		if (fd->queue_len == CONTROL_QUEUE_MAX) {
445 			errno = ENOBUFS;
446 			return -1;
447 		}
448 		fd->queue_len++;
449 		d = calloc(1, sizeof(*d));
450 		if (d == NULL)
451 			return -1;
452 	}
453 
454 	if (!fit) {
455 #ifdef CTL_FREE_LIST
456 		if (d->data_size != 0) {
457 			free(d->data);
458 			d->data_size = 0;
459 		}
460 #endif
461 		d->data = data;
462 		d->data_len = data_len;
463 		goto queue;
464 	}
465 
466 	if (d->data_size == 0)
467 		d->data = NULL;
468 	if (d->data_size < data_len) {
469 		void *nbuf = realloc(d->data, data_len);
470 		if (nbuf == NULL) {
471 			free(d->data);
472 			free(d);
473 			return -1;
474 		}
475 		d->data = nbuf;
476 		d->data_size = data_len;
477 	}
478 	memcpy(d->data, data, data_len);
479 	d->data_len = data_len;
480 
481 queue:
482 	TAILQ_INSERT_TAIL(&fd->queue, d, next);
483 	eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd);
484 	return 0;
485 }
486