1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2021 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/socket.h>
53 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
57 control_queue_free(struct fd_list *fd)
61 while ((fdp = TAILQ_FIRST(&fd->queue))) {
62 TAILQ_REMOVE(&fd->queue, fdp, next);
63 if (fdp->data_size != 0)
69 while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
70 TAILQ_REMOVE(&fd->free_queue, fdp, next);
71 if (fdp->data_size != 0)
79 control_free(struct fd_list *fd)
83 if (fd->ctx->ps_control_client == fd)
84 fd->ctx->ps_control_client = NULL;
87 if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1)
89 TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
90 control_queue_free(fd);
95 control_delete(struct fd_list *fd)
99 if (IN_PRIVSEP_SE(fd->ctx))
103 eloop_event_delete(fd->ctx->eloop, fd->fd);
109 control_handle_data(void *arg)
111 struct fd_list *fd = arg;
115 bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
117 if (bytes == -1 || bytes == 0) {
118 /* Control was closed or there was an error.
119 * Remove it from our list. */
125 if (IN_PRIVSEP(fd->ctx)) {
128 fd->flags |= FD_SENDLEN;
129 err = ps_ctl_handleargs(fd, buffer, (size_t)bytes);
130 fd->flags &= ~FD_SENDLEN;
136 ps_ctl_sendargs(fd, buffer, (size_t)bytes) == -1) {
144 control_recvdata(fd, buffer, (size_t)bytes);
148 control_recvdata(struct fd_list *fd, char *data, size_t len)
151 char *argvp[255], **ap;
154 /* Each command is \n terminated
155 * Each argument is NULL separated */
165 e = memchr(p, '\0', len);
168 logerrx("%s: no terminator", __func__);
171 if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
173 logerrx("%s: no arg buffer", __func__);
179 len -= (size_t)(e - p);
182 if (*(--e) == '\n') {
188 logerrx("%s: no args", __func__);
192 if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
194 if (errno != EINTR && errno != EAGAIN) {
203 control_new(struct dhcpcd_ctx *ctx, int fd, unsigned int flags)
207 l = malloc(sizeof(*l));
214 TAILQ_INIT(&l->queue);
216 TAILQ_INIT(&l->free_queue);
218 TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
223 control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
225 struct sockaddr_un run;
231 if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
233 if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
234 fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
236 if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
237 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
241 if (IN_PRIVSEP(ctx) && !IN_PRIVSEP_SE(ctx))
245 fd_flags |= FD_SENDLEN;
247 l = control_new(ctx, fd, fd_flags);
251 if (eloop_event_add(ctx->eloop, l->fd, control_handle_data, l) == -1)
262 control_handle(void *arg)
264 struct dhcpcd_ctx *ctx = arg;
266 control_handle1(ctx, ctx->control_fd, 0);
270 control_handle_unpriv(void *arg)
272 struct dhcpcd_ctx *ctx = arg;
274 control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
278 make_path(char *path, size_t len, const char *ifname, sa_family_t family,
296 sunpriv = ifname ? ".unpriv" : "unpriv.";
299 return snprintf(path, len, CONTROLSOCKET,
300 ifname ? ifname : "", ifname ? per : "",
301 sunpriv, ifname ? "." : "");
305 make_sock(struct sockaddr_un *sa, const char *ifname, sa_family_t family,
310 if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0)) == -1)
312 memset(sa, 0, sizeof(*sa));
313 sa->sun_family = AF_UNIX;
314 make_path(sa->sun_path, sizeof(sa->sun_path), ifname, family, unpriv);
318 #define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
319 #define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
322 control_start1(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family,
325 struct sockaddr_un sa;
329 fd = make_sock(&sa, ifname, family, (fmode & S_UNPRIV) == S_UNPRIV);
333 len = (socklen_t)SUN_LEN(&sa);
335 if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
336 chmod(sa.sun_path, fmode) == -1 ||
337 (ctx->control_group &&
338 chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
339 listen(fd, sizeof(ctx->control_fds)) == -1)
346 #ifdef PRIVSEP_RIGHTS
347 if (IN_PRIVSEP(ctx) && ps_rights_limit_fd_fctnl(fd) == -1) {
354 if ((fmode & S_UNPRIV) == S_UNPRIV)
355 strlcpy(ctx->control_sock_unpriv, sa.sun_path,
356 sizeof(ctx->control_sock_unpriv));
358 strlcpy(ctx->control_sock, sa.sun_path,
359 sizeof(ctx->control_sock));
364 control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family)
369 if (IN_PRIVSEP_SE(ctx)) {
370 make_path(ctx->control_sock, sizeof(ctx->control_sock),
371 ifname, family, false);
372 make_path(ctx->control_sock_unpriv,
373 sizeof(ctx->control_sock_unpriv),
374 ifname, family, true);
379 if ((fd = control_start1(ctx, ifname, family, S_PRIV)) == -1)
382 ctx->control_fd = fd;
383 eloop_event_add(ctx->eloop, fd, control_handle, ctx);
385 if ((fd = control_start1(ctx, ifname, family, S_UNPRIV)) != -1) {
386 ctx->control_unpriv_fd = fd;
387 eloop_event_add(ctx->eloop, fd, control_handle_unpriv, ctx);
389 return ctx->control_fd;
393 control_unlink(struct dhcpcd_ctx *ctx, const char *file)
400 retval = (int)ps_root_unlink(ctx, file);
405 retval = unlink(file);
407 return retval == -1 && errno != ENOENT ? -1 : 0;
411 control_stop(struct dhcpcd_ctx *ctx)
416 while ((l = TAILQ_FIRST(&ctx->control_fds)) != NULL) {
421 if (IN_PRIVSEP_SE(ctx)) {
422 if (ps_root_unlink(ctx, ctx->control_sock) == -1)
424 if (ps_root_unlink(ctx, ctx->control_sock_unpriv) == -1)
427 } else if (ctx->options & DHCPCD_FORKED)
431 if (ctx->control_fd != -1) {
432 eloop_event_delete(ctx->eloop, ctx->control_fd);
433 close(ctx->control_fd);
434 ctx->control_fd = -1;
435 if (control_unlink(ctx, ctx->control_sock) == -1)
439 if (ctx->control_unpriv_fd != -1) {
440 eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
441 close(ctx->control_unpriv_fd);
442 ctx->control_unpriv_fd = -1;
443 if (control_unlink(ctx, ctx->control_sock_unpriv) == -1)
451 control_open(const char *ifname, sa_family_t family, bool unpriv)
453 struct sockaddr_un sa;
456 if ((fd = make_sock(&sa, ifname, family, unpriv)) != -1) {
459 len = (socklen_t)SUN_LEN(&sa);
460 if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
469 control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
480 for (i = 0; i < argc; i++) {
481 l = strlen(argv[i]) + 1;
482 if (len + l > sizeof(buffer)) {
486 memcpy(buffer + len, argv[i], l);
489 return write(ctx->control_fd, buffer, len);
493 control_writeone(void *arg)
498 struct fd_data *data;
501 data = TAILQ_FIRST(&fd->queue);
503 if (data->data_flags & FD_SENDLEN) {
504 iov[0].iov_base = &data->data_len;
505 iov[0].iov_len = sizeof(size_t);
506 iov[1].iov_base = data->data;
507 iov[1].iov_len = data->data_len;
510 iov[0].iov_base = data->data;
511 iov[0].iov_len = data->data_len;
515 if (writev(fd->fd, iov, iov_len) == -1) {
516 logerr("%s: write", __func__);
521 TAILQ_REMOVE(&fd->queue, data, next);
523 TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
525 if (data->data_size != 0)
530 if (TAILQ_FIRST(&fd->queue) != NULL)
533 if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1)
536 if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) {
537 if (ps_ctl_sendeof(fd) == -1)
545 control_queue(struct fd_list *fd, void *data, size_t data_len)
558 TAILQ_FOREACH(df, &fd->free_queue, next) {
559 if (d == NULL || d->data_size < df->data_size) {
561 if (d->data_size <= data_len)
566 TAILQ_REMOVE(&fd->free_queue, d, next);
570 d = calloc(1, sizeof(*d));
575 if (d->data_size == 0)
577 if (d->data_size < data_len) {
578 void *nbuf = realloc(d->data, data_len);
585 d->data_size = data_len;
587 memcpy(d->data, data, data_len);
588 d->data_len = data_len;
589 d->data_flags = fd->flags & FD_SENDLEN;
591 TAILQ_INSERT_TAIL(&fd->queue, d, next);
592 eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd);