From: Roy Marples Date: Tue, 14 Jul 2026 14:01:47 +0000 (+0100) Subject: Fix the control socket for dhcpcd-ui X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=90b239e1e847b71e5fca84d805edbcebcfa4a3ac;p=thirdparty%2Fdhcpcd.git Fix the control socket for dhcpcd-ui Add --isprivileged to return either true or false so the caller can work this out as we now just have the one socket. Bump version for this. --- diff --git a/src/control.c b/src/control.c index 8afc4f62..473d6f37 100644 --- a/src/control.c +++ b/src/control.c @@ -133,7 +133,7 @@ getpeereid(int fd, uid_t *uid, gid_t *gid) } #endif -static int +static ssize_t control_handle_read(struct fd_list *fd) { uid_t uid; @@ -153,7 +153,7 @@ control_handle_read(struct fd_list *fd) if (bytes == -1) logerr(__func__); if (bytes == -1 || bytes == 0) - return (int)bytes; + return bytes; if (getpeereid(fd->fd, &uid, &gid) == -1) { logerr("%s: getpeereid", __func__); @@ -177,12 +177,14 @@ control_handle_read(struct fd_list *fd) fd->flags |= FD_SENDLEN; perr = ps_ctl_handleargs(fd, buf, (size_t)bytes); fd->flags &= ~FD_SENDLEN; + if (!(fd->flags & FD_LISTEN)) + fd->flags |= FD_COMMAND; if (perr == -1) { logerr(__func__); return 0; } iov[0].iov_len = (size_t)bytes; - if (perr == 1 && ps_ctl_sendmsg(fd, &msg) == -1) { + if (perr == 0 && ps_ctl_sendmsg(fd, &msg) == -1) { logerr(__func__); return -1; } @@ -202,28 +204,30 @@ control_handle_read(struct fd_list *fd) return control_recvmsg(fd, &msg, (size_t)bytes); } -static int +static ssize_t control_handle_write(struct fd_list *fd) { struct iovec iov[2]; - int iov_len; + struct msghdr msg = { .msg_iov = iov }; struct fd_data *data; + ssize_t len; data = TAILQ_FIRST(&fd->queue); if (data->data_flags & FD_SENDLEN) { iov[0].iov_base = &data->data_len; - iov[0].iov_len = sizeof(size_t); + iov[0].iov_len = sizeof(data->data_len); iov[1].iov_base = data->data; iov[1].iov_len = data->data_len; - iov_len = 2; + msg.msg_iovlen = 2; } else { iov[0].iov_base = data->data; iov[0].iov_len = data->data_len; - iov_len = 1; + msg.msg_iovlen = 1; } - if (writev(fd->fd, iov, iov_len) == -1) { + len = sendmsg(fd->fd, &msg, 0); + if (len == -1) { if (errno != EPIPE && errno != ENOTCONN) { // We don't get ELE_HANGUP for some reason logerr("%s: write", __func__); @@ -242,20 +246,23 @@ control_handle_write(struct fd_list *fd) #endif if (TAILQ_FIRST(&fd->queue) != NULL) - return 0; + return len; /* Done sending data, stop watching write to fd */ if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ, control_handle_data, fd) == -1) logerr("%s: eloop_event_add", __func__); - return 0; + return len; } static void control_handle_data(void *arg, unsigned short events) { struct fd_list *fd = arg; - int err; + ssize_t err; + + if (events & ELE_HANGUP) + goto hangup; if (!(events & (ELE_READ | ELE_WRITE | ELE_HANGUP))) logerrx("%s: unexpected event 0x%04x", __func__, events); @@ -270,8 +277,6 @@ control_handle_data(void *arg, unsigned short events) if ((err == -1 && errno != EPERM) || err == 0) goto hangup; } - if (events & ELE_HANGUP) - goto hangup; return; @@ -339,6 +344,8 @@ control_recvmsg(struct fd_list *fd, struct msghdr *msg, size_t len) if (errno != EINTR && errno != EAGAIN && errno != EPERM) return -1; } + if (!(fd->flags & FD_LISTEN)) + fd->flags |= FD_COMMAND; } return 1; @@ -412,7 +419,6 @@ control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags, else #endif fd_flags |= FD_SENDLEN; - l = control_new(ctx, fd, fd_flags); if (l == NULL) goto error; @@ -618,7 +624,7 @@ control_send(struct dhcpcd_ctx *ctx, int argc, char *const *argv) } int -control_queue(struct fd_list *fd, void *data, size_t data_len) +control_queue(struct fd_list *fd, const void *data, size_t data_len) { struct fd_data *d; unsigned short events; diff --git a/src/control.h b/src/control.h index 85086025..fd8d64b7 100644 --- a/src/control.h +++ b/src/control.h @@ -66,8 +66,9 @@ struct fd_list { TAILQ_HEAD(fd_list_head, fd_list); #define FD_LISTEN 0x01U -#define FD_PRIV 0x02U -#define FD_SENDLEN 0x04U +#define FD_COMMAND 0x02U +#define FD_PRIV 0x04U +#define FD_SENDLEN 0x08U int control_start(struct dhcpcd_ctx *, const char *, sa_family_t); int control_stop(struct dhcpcd_ctx *); @@ -77,7 +78,7 @@ struct fd_list *control_find(struct dhcpcd_ctx *, int); struct fd_list *control_new(struct dhcpcd_ctx *, int, unsigned int); void control_free(struct fd_list *); void control_delete(struct fd_list *); -int control_queue(struct fd_list *, void *, size_t); +int control_queue(struct fd_list *, const void *, size_t); int control_recvmsg(struct fd_list *, struct msghdr *, size_t); int control_user_ispriv(struct dhcpcd_ctx *ctx, uid_t uid, gid_t gid); #endif diff --git a/src/defs.h b/src/defs.h index d21a8fae..61f80579 100644 --- a/src/defs.h +++ b/src/defs.h @@ -29,7 +29,7 @@ #define DEFS_H #define PACKAGE "dhcpcd" -#define VERSION "10.3.2" +#define VERSION "10.5.0" #ifndef PRIVSEP_USER #define PRIVSEP_USER "_" PACKAGE diff --git a/src/dhcpcd.c b/src/dhcpcd.c index f45c4f38..d3b2bbea 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -1587,24 +1587,6 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, int argc, size_t len, l, nifaces; char *tmp, *p; - /* Special commands for our control socket - * as the other end should be blocking until it gets the - * expected reply we should be safely able just to change the - * write callback on the fd */ - /* Make any change here in privsep-control.c as well. */ - if (strcmp(*argv, "--version") == 0) { - return control_queue(fd, UNCONST(VERSION), strlen(VERSION) + 1); - } else if (strcmp(*argv, "--getconfigfile") == 0) { - return control_queue(fd, UNCONST(fd->ctx->cffile), - strlen(fd->ctx->cffile) + 1); - } else if (strcmp(*argv, "--getinterfaces") == 0) { - oifind = argc = 0; - goto dumplease; - } else if (strcmp(*argv, "--listen") == 0) { - fd->flags |= FD_LISTEN; - return 0; - } - /* Log the command */ len = 1; for (opt = 0; opt < argc; opt++) @@ -1624,6 +1606,27 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, int argc, loginfox("control command: %s", tmp); free(tmp); + /* Special commands for our control socket + * as the other end should be blocking until it gets the + * expected reply we should be safely able just to change the + * write callback on the fd */ + /* Make any change here in privsep-control.c as well. */ + if (strcmp(*argv, "--version") == 0) { + return control_queue(fd, VERSION, strlen(VERSION) + 1); + } else if (strcmp(*argv, "--getconfigfile") == 0) { + return control_queue(fd, fd->ctx->cffile, + strlen(fd->ctx->cffile) + 1); + } else if (strcmp(*argv, "--getinterfaces") == 0) { + oifind = argc = 0; + goto dumplease; + } else if (strcmp(*argv, "--isprivileged") == 0) { + const char *ret = fd->flags & FD_PRIV ? "true" : "false"; + return control_queue(fd, ret, strlen(ret) + 1); + } else if (strcmp(*argv, "--listen") == 0) { + fd->flags |= FD_LISTEN; + return 0; + } + optind = 0; oi = 0; opts = 0; @@ -1682,8 +1685,10 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, int argc, nifaces += (size_t)opt; } } - if (write(fd->fd, &nifaces, sizeof(nifaces)) != sizeof(nifaces)) + fd->flags &= ~FD_SENDLEN; + if (control_queue(fd, &nifaces, sizeof(nifaces)) == -1) goto dumperr; + fd->flags |= FD_SENDLEN; TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (!ifp->active) continue; diff --git a/src/privsep-control.c b/src/privsep-control.c index cb27de1b..468270b8 100644 --- a/src/privsep-control.c +++ b/src/privsep-control.c @@ -83,19 +83,26 @@ ps_ctl_recvmsg(void *arg, unsigned short events) ssize_t ps_ctl_handleargs(struct fd_list *fd, char *data, size_t len) { + int err; + /* Make any change here in dhcpcd.c as well. */ if (strncmp(data, "--version", MIN(strlen("--version"), len)) == 0) { - return control_queue(fd, UNCONST(VERSION), strlen(VERSION) + 1); + err = control_queue(fd, UNCONST(VERSION), strlen(VERSION) + 1); + return err == -1 ? -1 : 1; } else if (strncmp(data, "--getconfigfile", MIN(strlen("--getconfigfile"), len)) == 0) { - return control_queue(fd, UNCONST(fd->ctx->cffile), + err = control_queue(fd, UNCONST(fd->ctx->cffile), strlen(fd->ctx->cffile) + 1); + return err == -1 ? -1 : 1; + } else if (strcmp(data, "--isprivileged") == 0) { + const char *ret = fd->flags & FD_PRIV ? "true" : "false"; + return control_queue(fd, ret, strlen(ret) + 1); } else if (strncmp(data, "--listen", MIN(strlen("--listen"), len)) == 0) { fd->flags |= FD_LISTEN; - return 0; + return 1; } - return 1; + return 0; } static ssize_t @@ -141,10 +148,19 @@ ps_ctl_dodispatch(void *arg, unsigned short events) static void ps_ctl_recv(void *arg, unsigned short events) { - char buf[BUFSIZ]; struct dhcpcd_ctx *ctx = arg; - ssize_t len; - struct fd_list *fd; + char buf[BUFSIZ]; + struct iovec iov[] = { { + .iov_base = buf, + .iov_len = sizeof(buf), + } }; + struct msghdr msg = { + .msg_iov = iov, + .msg_iovlen = __arraycount(iov), + }; + ssize_t msglen; + int fd; + struct fd_list *fdl; if (events & ELE_HANGUP) { hangup: @@ -152,22 +168,23 @@ ps_ctl_recv(void *arg, unsigned short events) return; } - if (!(events & ELE_READ)) { + if (!(events & ELE_READ)) logerrx("%s: unexpected event 0x%04x", __func__, events); - return; - } - len = read(ctx->ps_ctl->psp_work_fd, buf, sizeof(buf)); - if (len == -1) { - logerr("%s: read", __func__); - return; - } else if (len == 0) + fd = ctx->ps_ctl->psp_work_fd; + msglen = recvmsg(fd, &msg, 0); + if (msglen == 0) goto hangup; + if (msglen == -1) { + logerr("%s: read", __func__); + eloop_exit(ctx->eloop, EXIT_FAILURE); + } - TAILQ_FOREACH(fd, &ctx->control_fds, next) { - if (fd->flags & FD_LISTEN) + /* Send to our command controls */ + TAILQ_FOREACH(fdl, &ctx->control_fds, next) { + if (!(fdl->flags & FD_COMMAND)) continue; - if (control_queue(fd, buf, (size_t)len) == -1) + if (control_queue(fdl, buf, (size_t)msglen) == -1) logerr("%s: control_queue", __func__); } } @@ -176,9 +193,10 @@ static void ps_ctl_listen(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - char buf[BUFSIZ]; ssize_t len; - struct fd_list *fd; + size_t msglen; + int fd; + struct fd_list *fdl; if (events & ELE_HANGUP) { hangup: @@ -189,22 +207,40 @@ ps_ctl_listen(void *arg, unsigned short events) if (!(events & ELE_READ)) logerrx("%s: unexpected event 0x%04x", __func__, events); - len = read(ctx->ps_control->fd, buf, sizeof(buf)); - if (len == -1) { - logerr("%s: read", __func__); - eloop_exit(ctx->eloop, EXIT_FAILURE); - return; + fd = ctx->ps_control->fd; + len = read(fd, &msglen, sizeof(msglen)); + if (len == 0) + goto hangup; + if (len != sizeof(msglen)) { + logerr("%s: read len", __func__); + goto err; } + + if (ps_bufalloc(ctx, msglen) == -1) { + logerr("%s: realloc", __func__); + goto err; + } + + len = read(fd, ctx->ps_buf, msglen); if (len == 0) goto hangup; + if ((size_t)len != msglen) { + logerr("%s: read", __func__); + goto err; + } /* Send to our listeners */ - TAILQ_FOREACH(fd, &ctx->control_fds, next) { - if (fd == ctx->ps_control || !(fd->flags & FD_LISTEN)) + TAILQ_FOREACH(fdl, &ctx->control_fds, next) { + if (!(fdl->flags & FD_LISTEN)) continue; - if (control_queue(fd, buf, (size_t)len) == -1) + if (control_queue(fdl, ctx->ps_buf, msglen) == -1) logerr("%s: control_queue", __func__); } + + return; + +err: + eloop_exit(ctx->eloop, EXIT_FAILURE); } pid_t @@ -220,8 +256,10 @@ ps_ctl_start(struct dhcpcd_ctx *ctx) if_closesockets(ctx); - if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, work_fd) == -1 || - xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1) + if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, work_fd) == + -1 || + xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, listen_fd) == + -1) return -1; #ifdef PRIVSEP_RIGHTS if (ps_rights_limit_fdpair(work_fd) == -1 || @@ -255,7 +293,7 @@ ps_ctl_start(struct dhcpcd_ctx *ctx) ctx) == -1) return -1; - ctx->ps_control = control_new(ctx, listen_fd[1], FD_LISTEN); + ctx->ps_control = control_new(ctx, listen_fd[1], 0); if (ctx->ps_control == NULL) return -1; if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, ELE_READ,