}
#endif
-static int
+static ssize_t
control_handle_read(struct fd_list *fd)
{
uid_t uid;
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__);
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;
}
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__);
#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);
if ((err == -1 && errno != EPERM) || err == 0)
goto hangup;
}
- if (events & ELE_HANGUP)
- goto hangup;
return;
if (errno != EINTR && errno != EAGAIN && errno != EPERM)
return -1;
}
+ if (!(fd->flags & FD_LISTEN))
+ fd->flags |= FD_COMMAND;
}
return 1;
else
#endif
fd_flags |= FD_SENDLEN;
-
l = control_new(ctx, fd, fd_flags);
if (l == NULL)
goto error;
}
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;
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 *);
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
#define DEFS_H
#define PACKAGE "dhcpcd"
-#define VERSION "10.3.2"
+#define VERSION "10.5.0"
#ifndef PRIVSEP_USER
#define PRIVSEP_USER "_" PACKAGE
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++)
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;
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;
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
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:
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__);
}
}
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:
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
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 ||
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,