]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Implement some process management
authorRoy Marples <roy@marples.name>
Wed, 17 Mar 2021 15:03:52 +0000 (15:03 +0000)
committerRoy Marples <roy@marples.name>
Wed, 17 Mar 2021 15:03:52 +0000 (15:03 +0000)
This also allows us to wait until all processes have exited to
avoid a fast restart which complains addresses are in use.

src/dhcpcd.c
src/dhcpcd.h
src/if-bsd.c
src/privsep-bpf.c
src/privsep-bsd.c
src/privsep-control.c
src/privsep-inet.c
src/privsep-root.c
src/privsep-root.h
src/privsep.c
src/privsep.h

index eae6e20b3aa83da20b22d3ebb90f74e17c31bdf6..3f4d41fed6d2523821286af32df4f55ed267da33 100644 (file)
@@ -1409,7 +1409,7 @@ dhcpcd_renew(struct dhcpcd_ctx *ctx)
 
 #ifdef USE_SIGNALS
 #define sigmsg "received %s, %s"
-static void
+void
 dhcpcd_signal_cb(int sig, void *arg)
 {
        struct dhcpcd_ctx *ctx = arg;
@@ -1468,8 +1468,12 @@ dhcpcd_signal_cb(int sig, void *arg)
                        logerr("logopen");
                return;
        case SIGCHLD:
+#ifdef PRIVSEP
+               ps_root_signalcb(sig, ctx);
+#else
                while (waitpid(-1, NULL, WNOHANG) > 0)
                        ;
+#endif
                return;
        default:
                logerrx("received signal %d but don't know what to do with it",
@@ -1918,8 +1922,7 @@ main(int argc, char **argv, char **envp)
        ctx.dhcp6_wfd = -1;
 #endif
 #ifdef PRIVSEP
-       ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1;
-       ctx.ps_inet_fd = ctx.ps_control_fd = -1;
+       ctx.ps_log_fd = -1;
        TAILQ_INIT(&ctx.ps_processes);
 #endif
 
@@ -2307,9 +2310,9 @@ printpidfile:
        if (!(ctx.options & DHCPCD_DAEMONISE))
                goto start_manager;
 
-       if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 ||
+       if (xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, fork_fd) == -1 ||
            (ctx.stderr_valid &&
-           xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1))
+           xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, stderr_fd) == -1))
        {
                logerr("socketpair");
                goto exit_failure;
@@ -2639,10 +2642,22 @@ exit1:
 #endif
        if (ctx.script != dhcpcd_default_script)
                free(ctx.script);
-       if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
+#ifdef PRIVSEP
+       if (ps_stopwait(&ctx) != EXIT_SUCCESS)
+               i = EXIT_FAILURE;
+#endif
+       if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) {
                loginfox(PACKAGE " exited");
+
+#ifdef PRIVSEP
+               /* Sleep some for the exited log entry to be written. */
+               struct timespec ts = { .tv_nsec = 10 };
+               nanosleep(&ts, NULL);
+#endif
+       }
 #ifdef PRIVSEP
-       ps_root_stop(&ctx);
+       if (ps_root_stop(&ctx) == -1)
+               i = EXIT_FAILURE;
        eloop_free(ctx.ps_eloop);
 #endif
        eloop_free(ctx.eloop);
index d7fb8164574d4d8fd12586c44fa60cca9e3cf950..1c4a401f09a40fedc80324336910dc230ade66c0 100644 (file)
@@ -198,17 +198,14 @@ struct dhcpcd_ctx {
 
 #ifdef PRIVSEP
        struct passwd *ps_user; /* struct passwd for privsep user */
-       pid_t ps_root_pid;
-       int ps_root_fd;         /* Privileged Proxy commands */
+       struct ps_process_head ps_processes;    /* List of spawned processes */
+       struct ps_process *ps_root;
+       struct ps_process *ps_inet;
+       struct ps_process *ps_ctl;
+       int ps_data_fd;         /* data returned from processes */
        int ps_log_fd;          /* chroot logging */
-       int ps_data_fd;         /* Data from root spawned processes */
+       int ps_log_root_fd;     /* outside chroot log reader */
        struct eloop *ps_eloop; /* eloop for polling root data */
-       struct ps_process_head ps_processes;    /* List of spawned processes */
-       pid_t ps_inet_pid;
-       int ps_inet_fd;         /* Network Proxy commands and data */
-       pid_t ps_control_pid;
-       int ps_control_fd;      /* Control Proxy - generic listener */
-       int ps_control_data_fd; /* Control Proxy - data query */
        struct fd_list *ps_control;             /* Queue for the above */
        struct fd_list *ps_control_client;      /* Queue for the above */
 #endif
@@ -270,6 +267,8 @@ int dhcpcd_ifafwaiting(const struct interface *);
 int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
 void dhcpcd_daemonise(struct dhcpcd_ctx *);
 
+void dhcpcd_signal_cb(int, void *);
+
 void dhcpcd_linkoverflow(struct dhcpcd_ctx *);
 int dhcpcd_handleargs(struct dhcpcd_ctx *, struct fd_list *, int, char **);
 void dhcpcd_handlecarrier(struct interface *, int, unsigned int);
index e5ffe500655fb795fc9fd1a3c1e1242d609d92c8..17802b383b94d437b2bd6a0a6885d48d8176ac3b 100644 (file)
@@ -1246,8 +1246,8 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
 
        /* Ignore messages from ourself. */
 #ifdef PRIVSEP
-       if (ctx->ps_root_pid != 0) {
-               if (rtm->rtm_pid == ctx->ps_root_pid)
+       if (ctx->ps_root != NULL) {
+               if (rtm->rtm_pid == ctx->ps_root->psp_pid)
                        return 0;
        }
 #endif
@@ -1298,8 +1298,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
         * We need to process address flag changes though. */
        if (ifam->ifam_type == RTM_DELADDR) {
 #ifdef PRIVSEP
-               if (ctx->ps_root_pid != 0) {
-                       if (ifam->ifam_pid == ctx->ps_root_pid)
+               if (ctx->ps_root != NULL) {
+                       if (ifam->ifam_pid == ctx->ps_root->psp_pid)
                                return 0;
                } else
 #endif
index f0088568466c9018fc2b616c787bfdb2d857895b..b513d49e9b4073c745a1d21301413c461a34f2f8 100644 (file)
@@ -144,9 +144,8 @@ ps_bpf_recvmsg(void *arg, unsigned short events)
 }
 
 static int
-ps_bpf_start_bpf(void *arg)
+ps_bpf_start_bpf(struct ps_process *psp)
 {
-       struct ps_process *psp = arg;
        struct dhcpcd_ctx *ctx = psp->psp_ctx;
        char *addr;
        struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
@@ -187,6 +186,8 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
        pid_t start;
        struct iovec *iov = msg->msg_iov;
        struct interface *ifp;
+       struct in_addr *ia = &psm->ps_id.psi_addr.psa_in_addr;
+       const char *addr;
 
        cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
        psp = ps_findprocess(ctx, &psm->ps_id);
@@ -244,11 +245,16 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                break;
        }
 
-       start = ps_dostart(ctx,
-           &psp->psp_pid, &psp->psp_fd,
-           ps_bpf_recvmsg, NULL, psp,
-           ps_bpf_start_bpf, NULL,
-           PSF_DROPPRIVS);
+       if (ia->s_addr == INADDR_ANY)
+               addr = NULL;
+       else
+               addr = inet_ntoa(*ia);
+       snprintf(psp->psp_name, sizeof(psp->psp_name), "BPF %s%s%s",
+           psp->psp_protostr,
+           addr != NULL ? " " : "", addr != NULL ? addr : "");
+
+       start = ps_startprocess(psp, ps_bpf_recvmsg, NULL,
+           ps_bpf_start_bpf, NULL, PSF_DROPPRIVS);
        switch (start) {
        case -1:
                ps_freeprocess(psp);
@@ -257,8 +263,8 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                ps_entersandbox("stdio", NULL);
                break;
        default:
-               logdebugx("%s: spawned BPF %s on PID %d",
-                   psp->psp_ifname, psp->psp_protostr, start);
+               logdebugx("%s: spawned %s on PID %d",
+                   psp->psp_ifname, psp->psp_name, psp->psp_pid);
                break;
        }
        return start;
@@ -322,7 +328,7 @@ ps_bpf_send(const struct interface *ifp, const struct in_addr *ia,
        if (ia != NULL)
                psm.ps_id.psi_addr.psa_in_addr = *ia;
 
-       return ps_sendpsmdata(ctx, ctx->ps_root_fd, &psm, data, len);
+       return ps_sendpsmdata(ctx, ctx->ps_root->psp_fd, &psm, data, len);
 }
 
 #ifdef ARP
index 91c54488235cbe0b778d36f1e7d367f6ac4179dd..2ca26a53a826b77f486708f0caf043eab919fd76 100644 (file)
@@ -205,7 +205,7 @@ ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request,
     void *data, size_t len)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, domain,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, domain,
            request, data, len) == -1)
                return -1;
        return ps_root_readerror(ctx, data, len);
@@ -231,7 +231,7 @@ ssize_t
 ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_ROUTE, 0, data, len) == -1)
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_ROUTE, 0, data, len) == -1)
                return -1;
        return ps_root_readerror(ctx, data, len);
 }
index f216609b10cc5564de763bbae0e6e35fd444921f..0e50e9eaa08a7a104b98068ef814cfa0a6f9c642 100644 (file)
@@ -37,9 +37,9 @@
 #include "privsep.h"
 
 static int
-ps_ctl_startcb(void *arg)
+ps_ctl_startcb(struct ps_process *psp)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct dhcpcd_ctx *ctx = psp->psp_ctx;
        sa_family_t af;
 
        if (ctx->options & DHCPCD_MANAGER) {
@@ -60,8 +60,6 @@ ps_ctl_startcb(void *arg)
                        af = AF_UNSPEC;
        }
 
-       ctx->ps_control_pid = getpid();
-
        return control_start(ctx,
            ctx->options & DHCPCD_MANAGER ? NULL : *ctx->ifv, af);
 }
@@ -76,18 +74,17 @@ ps_ctl_recvmsgcb(void *arg, struct ps_msghdr *psm, __unused struct msghdr *msg)
                return -1;
        }
 
-       if (ctx->ps_control_client != NULL)
-               ctx->ps_control_client = NULL;
+       ctx->ps_control_client = NULL;
        return 0;
 }
 
 static void
 ps_ctl_recvmsg(void *arg, unsigned short events)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct ps_process *psp = arg;
 
-       if (ps_recvpsmsg(ctx, ctx->ps_control_fd, events,
-           ps_ctl_recvmsgcb, ctx) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
+           ps_ctl_recvmsgcb, psp->psp_ctx) == -1)
                logerr(__func__);
 }
 
@@ -145,14 +142,14 @@ ps_ctl_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
                        logerrx("%s: cannot handle another client", __func__);
                        return 0;
                }
-               fd = control_new(ctx, ctx->ps_control_data_fd, fd_flags);
+               fd = control_new(ctx, ctx->ps_ctl->psp_work_fd, fd_flags);
                if (fd == NULL)
                        return -1;
                ctx->ps_control_client = fd;
                control_recvdata(fd, iov->iov_base, iov->iov_len);
                break;
        case PS_CTL_EOF:
-               control_free(ctx->ps_control_client);
+               ctx->ps_control_client = NULL;
                break;
        default:
                errno = ENOTSUP;
@@ -164,10 +161,10 @@ ps_ctl_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 static void
 ps_ctl_dodispatch(void *arg, unsigned short events)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct ps_process *psp = arg;
 
-       if (ps_recvpsmsg(ctx, ctx->ps_control_fd, events,
-           ps_ctl_dispatch, ctx) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
+           ps_ctl_dispatch, psp->psp_ctx) == -1)
                logerr(__func__);
 }
 
@@ -181,8 +178,9 @@ ps_ctl_recv(void *arg, unsigned short events)
        if (!(events & ELE_READ))
                logerrx("%s: unexpected event 0x%04x", __func__, events);
 
-       errno = 0;
-       len = read(ctx->ps_control_data_fd, buf, sizeof(buf));
+       len = read(ctx->ps_ctl->psp_work_fd, buf, sizeof(buf));
+       if (len == 0)
+               return;
        if (len == -1) {
                logerr("%s: read", __func__);
                eloop_exit(ctx->eloop, EXIT_FAILURE);
@@ -227,6 +225,11 @@ ps_ctl_listen(void *arg, unsigned short events)
 pid_t
 ps_ctl_start(struct dhcpcd_ctx *ctx)
 {
+       struct ps_id id = {
+               .psi_ifindex = 0,
+               .psi_cmd = PS_CTL,
+       };
+       struct ps_process *psp;
        int data_fd[2], listen_fd[2];
        pid_t pid;
 
@@ -239,15 +242,15 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
                return -1;
 #endif
 
-       pid = ps_dostart(ctx, &ctx->ps_control_pid, &ctx->ps_control_fd,
-           ps_ctl_recvmsg, ps_ctl_dodispatch, ctx,
-           ps_ctl_startcb, NULL,
-           PSF_DROPPRIVS);
+       psp = ctx->ps_ctl = ps_newprocess(ctx, &id);
+       strlcpy(psp->psp_name, "control proxy", sizeof(psp->psp_name));
+       pid = ps_startprocess(psp, ps_ctl_recvmsg, ps_ctl_dodispatch,
+           ps_ctl_startcb, NULL, PSF_DROPPRIVS);
 
        if (pid == -1)
                return -1;
        else if (pid != 0) {
-               ctx->ps_control_data_fd = data_fd[1];
+               psp->psp_work_fd = data_fd[1];
                close(data_fd[0]);
                ctx->ps_control = control_new(ctx,
                    listen_fd[1], FD_SENDLEN | FD_LISTEN);
@@ -257,14 +260,13 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
                return pid;
        }
 
-       ctx->ps_control_data_fd = data_fd[0];
+       psp->psp_work_fd = data_fd[0];
        close(data_fd[1]);
-       if (eloop_event_add(ctx->eloop, ctx->ps_control_data_fd, ELE_READ,
+       if (eloop_event_add(ctx->eloop, psp->psp_work_fd, ELE_READ,
            ps_ctl_recv, ctx) == -1)
                return -1;
 
-       ctx->ps_control = control_new(ctx,
-           listen_fd[0], 0);
+       ctx->ps_control = control_new(ctx, listen_fd[0], 0);
        close(listen_fd[1]);
        if (ctx->ps_control == NULL)
                return -1;
@@ -280,7 +282,7 @@ int
 ps_ctl_stop(struct dhcpcd_ctx *ctx)
 {
 
-       return ps_dostop(ctx, &ctx->ps_control_pid, &ctx->ps_control_fd);
+       return ps_stopprocess(ctx->ps_ctl);
 }
 
 ssize_t
@@ -291,7 +293,7 @@ ps_ctl_sendargs(struct fd_list *fd, void *data, size_t len)
        if (ctx->ps_control_client != NULL && ctx->ps_control_client != fd)
                logerrx("%s: cannot deal with another client", __func__);
        ctx->ps_control_client = fd;
-       return ps_sendcmd(ctx, ctx->ps_control_fd, PS_CTL,
+       return ps_sendcmd(ctx, ctx->ps_ctl->psp_fd, PS_CTL,
            fd->flags & FD_UNPRIV ? PS_CTL_UNPRIV : PS_CTL_PRIV,
            data, len);
 }
@@ -301,5 +303,5 @@ ps_ctl_sendeof(struct fd_list *fd)
 {
        struct dhcpcd_ctx *ctx = fd->ctx;
 
-       return ps_sendcmd(ctx, ctx->ps_control_fd, PS_CTL_EOF, 0, NULL, 0);
+       return ps_sendcmd(ctx, ctx->ps_ctl->psp_fd, PS_CTL_EOF, 0, NULL, 0);
 }
index fc7da095df2b88f5b5abdb6183ab385f179320be..2ad2ab18131435f3e790d0d04a0f93d9fca12ad8 100644 (file)
@@ -54,7 +54,7 @@ ps_inet_recvbootp(void *arg, unsigned short events)
        struct dhcpcd_ctx *ctx = arg;
 
        if (ps_recvmsg(ctx, ctx->udp_rfd, events,
-           PS_BOOTP, ctx->ps_inet_fd) == -1)
+           PS_BOOTP, ctx->ps_inet->psp_fd) == -1)
                logerr(__func__);
 }
 #endif
@@ -69,13 +69,13 @@ ps_inet_recvra(void *arg, unsigned short events)
        struct dhcpcd_ctx *ctx = ifp->ctx;
 
        if (ps_recvmsg(ctx, state->nd_fd, events,
-           PS_ND, ctx->ps_inet_fd) == -1)
+           PS_ND, ctx->ps_inet->psp_fd) == -1)
                logerr(__func__);
 #else
        struct dhcpcd_ctx *ctx = arg;
 
        if (ps_recvmsg(ctx, ctx->nd_fd, events,
-           PS_ND, ctx->ps_inet_fd) == -1)
+           PS_ND, ctx->ps_inet->psp_fd) == -1)
                logerr(__func__);
 #endif
 }
@@ -88,7 +88,7 @@ ps_inet_recvdhcp6(void *arg, unsigned short events)
        struct dhcpcd_ctx *ctx = arg;
 
        if (ps_recvmsg(ctx, ctx->dhcp6_rfd, events,
-           PS_DHCP6, ctx->ps_inet_fd) == -1)
+           PS_DHCP6, ctx->ps_inet->psp_fd) == -1)
                logerr(__func__);
 }
 #endif
@@ -116,16 +116,16 @@ ps_inet_canstart(const struct dhcpcd_ctx *ctx)
 }
 
 static int
-ps_inet_startcb(void *arg)
+ps_inet_startcb(struct ps_process *psp)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct dhcpcd_ctx *ctx = psp->psp_ctx;
        int ret = 0;
 
        if (ctx->options & DHCPCD_MANAGER)
                setproctitle("[network proxy]");
        else
                setproctitle("[network proxy] %s%s%s",
-                   ctx->ifv[0],
+                   ctx->ifc != 0 ? ctx->ifv[0] : "",
                    ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
                    ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
 
@@ -305,10 +305,10 @@ dosend:
 static void
 ps_inet_recvmsg(void *arg, unsigned short events)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct ps_process *psp = arg;
 
        /* Receive shutdown */
-       if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, events, NULL, NULL) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
                logerr(__func__);
 }
 
@@ -343,22 +343,30 @@ ps_inet_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 static void
 ps_inet_dodispatch(void *arg, unsigned short events)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct ps_process *psp = arg;
 
-       if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, events,
-           ps_inet_dispatch, ctx) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
+           ps_inet_dispatch, psp->psp_ctx) == -1)
                logerr(__func__);
 }
 
 pid_t
 ps_inet_start(struct dhcpcd_ctx *ctx)
 {
+       struct ps_id id = {
+               .psi_ifindex = 0,
+               .psi_cmd = PS_INET,
+       };
+       struct ps_process *psp;
        pid_t pid;
 
-       pid = ps_dostart(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd,
-           ps_inet_recvmsg, ps_inet_dodispatch, ctx,
-           ps_inet_startcb, NULL,
-           PSF_DROPPRIVS);
+       psp = ctx->ps_inet = ps_newprocess(ctx, &id);
+       if (psp == NULL)
+               return -1;
+
+       strlcpy(psp->psp_name, "network proxy", sizeof(psp->psp_name));
+       pid = ps_startprocess(psp, ps_inet_recvmsg, ps_inet_dodispatch,
+           ps_inet_startcb, NULL, PSF_DROPPRIVS);
 
        if (pid == 0)
                ps_entersandbox("stdio", NULL);
@@ -370,7 +378,7 @@ int
 ps_inet_stop(struct dhcpcd_ctx *ctx)
 {
 
-       return ps_dostop(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd);
+       return ps_stopprocess(ctx->ps_inet);
 }
 
 #ifdef INET
@@ -385,14 +393,13 @@ ps_inet_recvinbootp(void *arg, unsigned short events)
 }
 
 static int
-ps_inet_listenin(void *arg)
+ps_inet_listenin(struct ps_process *psp)
 {
-       struct ps_process *psp = arg;
        struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
        char buf[INET_ADDRSTRLEN];
 
        inet_ntop(AF_INET, ia, buf, sizeof(buf));
-       setproctitle("[network proxy] %s", buf);
+       setproctitle("[%s proxy] %s", psp->psp_protostr, buf);
 
        psp->psp_work_fd = dhcp_openudp(ia);
        if (psp->psp_work_fd == -1) {
@@ -413,8 +420,6 @@ ps_inet_listenin(void *arg)
                logerr("%s: eloop_event_add DHCP", __func__);
                return -1;
        }
-
-       logdebugx("spawned listener %s on PID %d", buf, getpid());
        return 0;
 }
 #endif
@@ -431,9 +436,8 @@ ps_inet_recvin6nd(void *arg)
 }
 
 static int
-ps_inet_listennd(void *arg)
+ps_inet_listennd(struct ps_process *psp)
 {
-       struct ps_process *psp = arg;
 
        setproctitle("[ND network proxy]");
 
@@ -456,8 +460,6 @@ ps_inet_listennd(void *arg)
                logerr(__func__);
                return -1;
        }
-
-       logdebugx("spawned ND listener on PID %d", getpid());
        return 0;
 }
 #endif
@@ -474,14 +476,13 @@ ps_inet_recvin6dhcp6(void *arg, unsigned short events)
 }
 
 static int
-ps_inet_listenin6(void *arg)
+ps_inet_listenin6(struct ps_process *psp)
 {
-       struct ps_process *psp = arg;
        struct in6_addr *ia = &psp->psp_id.psi_addr.psa_in6_addr;
        char buf[INET6_ADDRSTRLEN];
 
        inet_ntop(AF_INET6, ia, buf, sizeof(buf));
-       setproctitle("[network proxy] %s", buf);
+       setproctitle("[%s proxy] %s", psp->psp_protostr, buf);
 
        psp->psp_work_fd = dhcp6_openudp(psp->psp_id.psi_ifindex, ia);
        if (psp->psp_work_fd == -1) {
@@ -502,8 +503,6 @@ ps_inet_listenin6(void *arg)
                logerr("%s: eloop_event_add DHCP", __func__);
                return -1;
        }
-
-       logdebugx("spawned listener %s on PID %d", buf, getpid());
        return 0;
 }
 #endif
@@ -523,8 +522,11 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
 {
        uint16_t cmd;
        struct ps_process *psp;
-       int (*start_func)(void *);
+       int (*start_func)(struct ps_process *);
        pid_t start;
+       struct ps_addr *psa = &psm->ps_id.psi_addr;
+       void *ia;
+       char buf[INET_MAX_ADDRSTRLEN];
 
        cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
        if (cmd == psm->ps_cmd)
@@ -541,21 +543,40 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                return 0;
        }
 
+       if (!(psm->ps_cmd & PS_START)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (psp != NULL)
+               return 1;
+
+       psp = ps_newprocess(ctx, &psm->ps_id);
+       if (psp == NULL)
+               return -1;
+
+
        switch (cmd) {
 #ifdef INET
        case PS_BOOTP:
                start_func = ps_inet_listenin;
+               psp->psp_protostr = "BOOTP";
+               ia = &psa->psa_in_addr;
                break;
 #endif
 #ifdef INET6
 #ifdef __sun
        case PS_ND:
                start_func = ps_inet_listennd;
+               psp->psp_protostr = "ND";
+               ia = &psa->psa_in6_addr;
                break;
 #endif
 #ifdef DHCP6
        case PS_DHCP6:
                start_func = ps_inet_listenin6;
+               psp->psp_protostr = "DHCP6";
+               ia = &psa->psa_in6_addr;
                break;
 #endif
 #endif
@@ -565,23 +586,11 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                return -1;
        }
 
-       if (!(psm->ps_cmd & PS_START)) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       if (psp != NULL)
-               return 1;
-
-       psp = ps_newprocess(ctx, &psm->ps_id);
-       if (psp == NULL)
-               return -1;
-
-       start = ps_dostart(ctx,
-           &psp->psp_pid, &psp->psp_fd,
-           ps_inet_recvmsgpsp, NULL, psp,
-           start_func, NULL,
-           PSF_DROPPRIVS);
+       snprintf(psp->psp_name, sizeof(psp->psp_name),
+           "%s proxy %s", psp->psp_protostr,
+           inet_ntop(psa->psa_family, ia, buf, sizeof(buf)));
+       start = ps_startprocess(psp, ps_inet_recvmsgpsp, NULL,
+           start_func, NULL, PSF_DROPPRIVS);
        switch (start) {
        case -1:
                ps_freeprocess(psp);
@@ -590,6 +599,8 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                ps_entersandbox("stdio", NULL);
                break;
        default:
+               logdebugx("%s: spawned %s on PID %d",
+                   psp->psp_ifname, psp->psp_name, psp->psp_pid);
                break;
        }
        return start;
@@ -606,11 +617,12 @@ ps_inet_in_docmd(struct ipv4_addr *ia, uint16_t cmd, const struct msghdr *msg)
                .ps_id = {
                        .psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
                        .psi_ifindex = ia->iface->index,
+                       .psi_addr.psa_family = AF_INET,
                        .psi_addr.psa_in_addr = ia->addr,
                },
        };
 
-       return ps_sendpsmmsg(ctx, ctx->ps_root_fd, &psm, msg);
+       return ps_sendpsmmsg(ctx, ctx->ps_root->psp_fd, &psm, msg);
 }
 
 ssize_t
@@ -630,8 +642,9 @@ ps_inet_closebootp(struct ipv4_addr *ia)
 ssize_t
 ps_inet_sendbootp(struct interface *ifp, const struct msghdr *msg)
 {
+       struct dhcpcd_ctx *ctx = ifp->ctx;
 
-       return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_BOOTP, 0, msg);
+       return ps_sendmsg(ctx, ctx->ps_root->psp_fd, PS_BOOTP, 0, msg);
 }
 #endif /* INET */
 
@@ -646,10 +659,11 @@ ps_inet_ifp_docmd(struct interface *ifp, uint16_t cmd, const struct msghdr *msg)
                .ps_id = {
                        .psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
                        .psi_ifindex = ifp->index,
+                       .psi_addr.psa_family = AF_INET6,
                },
        };
 
-       return ps_sendpsmmsg(ctx, ctx->ps_root_fd, &psm, msg);
+       return ps_sendpsmmsg(ctx, ctx->ps_root->psp_fd, &psm, msg);
 }
 
 ssize_t
@@ -676,8 +690,9 @@ ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
 ssize_t
 ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
 {
+       struct dhcpcd_ctx *ctx = ifp->ctx;
 
-       return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_ND, 0, msg);
+       return ps_sendmsg(ctx, ctx->ps_root->psp_fd, PS_ND, 0, msg);
 }
 #endif
 
@@ -691,11 +706,12 @@ ps_inet_in6_docmd(struct ipv6_addr *ia, uint16_t cmd, const struct msghdr *msg)
                .ps_id = {
                        .psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
                        .psi_ifindex = ia->iface->index,
+                       .psi_addr.psa_family = AF_INET6,
                        .psi_addr.psa_in6_addr = ia->addr,
                },
        };
 
-       return ps_sendpsmmsg(ctx, ctx->ps_root_fd, &psm, msg);
+       return ps_sendpsmmsg(ctx, ctx->ps_root->psp_fd, &psm, msg);
 }
 
 ssize_t
@@ -715,8 +731,9 @@ ps_inet_closedhcp6(struct ipv6_addr *ia)
 ssize_t
 ps_inet_senddhcp6(struct interface *ifp, const struct msghdr *msg)
 {
+       struct dhcpcd_ctx *ctx = ifp->ctx;
 
-       return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_DHCP6, 0, msg);
+       return ps_sendmsg(ctx, ctx->ps_root->psp_fd, PS_DHCP6, 0, msg);
 }
 #endif /* DHCP6 */
 #endif /* INET6 */
index c04cf2215e77e5137a4af308d6f775689b8efc00..b7c737e3b6f2d460236881519108c656b0245434 100644 (file)
@@ -97,7 +97,7 @@ ps_root_readerrorcb(void *arg, unsigned short events)
                goto out;                       \
        } while (0 /* CONSTCOND */)
 
-       len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
+       len = readv(ctx->ps_root->psp_fd, iov, __arraycount(iov));
        if (len == -1)
                PSR_ERROR(errno);
        else if ((size_t)len < sizeof(*psr_error))
@@ -116,12 +116,13 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
            .psr_data = data, .psr_datalen = len,
        };
 
-       if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd, ELE_READ,
+       if (eloop_event_add(ctx->ps_eloop, ctx->ps_root->psp_fd, ELE_READ,
            ps_root_readerrorcb, &psr_ctx) == -1)
                return -1;
 
        eloop_enter(ctx->ps_eloop);
        eloop_start(ctx->ps_eloop, &ctx->sigset);
+       eloop_event_delete(ctx->ps_eloop, ctx->ps_root->psp_fd);
 
        errno = psr_ctx.psr_error.psr_errno;
        return psr_ctx.psr_error.psr_result;
@@ -144,7 +145,8 @@ ps_root_mreaderrorcb(void *arg, unsigned short events)
        if (events != ELE_READ)
                logerrx("%s: unexpected event 0x%04x", __func__, events);
 
-       len = recv(ctx->ps_root_fd, psr_error, sizeof(*psr_error), MSG_PEEK);
+       len = recv(ctx->ps_root->psp_fd,
+           psr_error, sizeof(*psr_error), MSG_PEEK);
        if (len == -1)
                PSR_ERROR(errno);
        else if ((size_t)len < sizeof(*psr_error))
@@ -161,7 +163,7 @@ ps_root_mreaderrorcb(void *arg, unsigned short events)
                iov[1].iov_len = psr_ctx->psr_datalen;
        }
 
-       len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
+       len = readv(ctx->ps_root->psp_fd, iov, __arraycount(iov));
        if (len == -1)
                PSR_ERROR(errno);
        else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen)
@@ -185,6 +187,7 @@ ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
 
        eloop_enter(ctx->ps_eloop);
        eloop_start(ctx->ps_eloop, &ctx->sigset);
+       eloop_event_delete(ctx->ps_eloop, ctx->ps_root->psp_fd);
 
        errno = psr_ctx.psr_error.psr_errno;
        *data = psr_ctx.psr_data;
@@ -211,7 +214,7 @@ ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
        logdebugx("%s: result %zd errno %d", __func__, result, errno);
 #endif
 
-       return writev(ctx->ps_root_fd, iov, __arraycount(iov));
+       return writev(ctx->ps_root->psp_fd, iov, __arraycount(iov));
 }
 
 static ssize_t
@@ -276,6 +279,7 @@ ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
        pid = script_exec(argv, ctx->script_env);
        if (pid == -1)
                return -1;
+
        /* Wait for the script to finish */
        while (waitpid(pid, &status, 0) == -1) {
                if (errno != EINTR) {
@@ -475,12 +479,13 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 
        if (psp != NULL) {
                if (psm->ps_cmd & PS_STOP) {
-                       int ret = ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
-
-                       ps_freeprocess(psp);
-                       return ret;
+                       return ps_stopprocess(psp);
                } else if (psm->ps_cmd & PS_START) {
                        /* Process has already started .... */
+                       logdebugx("%s%sprocess %s already started on pid %d",
+                           psp->psp_ifname,
+                           psp->psp_ifname[0] != '\0' ? ": " : "",
+                           psp->psp_name, psp->psp_pid);
                        return 0;
                }
 
@@ -488,9 +493,6 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
                if (err == -1) {
                        logerr("%s: failed to send message to pid %d",
                            __func__, psp->psp_pid);
-                       shutdown(psp->psp_fd, SHUT_RDWR);
-                       close(psp->psp_fd);
-                       psp->psp_fd = -1;
                        ps_freeprocess(psp);
                }
                return 0;
@@ -538,6 +540,14 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
        case PS_SCRIPT:
                err = ps_root_run_script(ctx, data, len);
                break;
+       case PS_STOPPROCS:
+               ctx->options |= DHCPCD_EXITING;
+               TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+                       if (psp != ctx->ps_root)
+                               ps_stopprocess(psp);
+               }
+               err = ps_stopwait(ctx);
+               break;
        case PS_UNLINK:
                if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
                        err = -1;
@@ -613,10 +623,10 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 static void
 ps_root_recvmsg(void *arg, unsigned short events)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct ps_process *psp = arg;
 
-       if (ps_recvpsmsg(ctx, ctx->ps_root_fd, events,
-           ps_root_recvmsgcb, ctx) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
+           ps_root_recvmsgcb, psp->psp_ctx) == -1)
                logerr(__func__);
 }
 
@@ -638,15 +648,15 @@ ps_root_handleinterface(void *arg, int action, const char *ifname)
                return -1;
        }
 
-       return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag,
-           ifname, strlen(ifname) + 1);
+       return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD,
+           flag, ifname, strlen(ifname) + 1);
 }
 #endif
 
 static int
-ps_root_startcb(void *arg)
+ps_root_startcb(struct ps_process *psp)
 {
-       struct dhcpcd_ctx *ctx = arg;
+       struct dhcpcd_ctx *ctx = psp->psp_ctx;
 
        if (ctx->options & DHCPCD_MANAGER)
                setproctitle("[privileged proxy]");
@@ -655,7 +665,6 @@ ps_root_startcb(void *arg)
                    ctx->ifv[0],
                    ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
                    ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
-       ctx->ps_root_pid = getpid();
        ctx->options |= DHCPCD_PRIVSEPROOT;
 
        /* Open network sockets for sending.
@@ -663,7 +672,7 @@ ps_root_startcb(void *arg)
         * but makes life very easy for unicasting DHCPv6 in non manager
         * mode as we no longer care about address selection.
         * We can't call shutdown SHUT_RD on the socket because it's
-        * not connectd. All we can do is try and set a zero sized
+        * not connected. All we can do is try and set a zero sized
         * receive buffer and just let it overflow.
         * Reading from it just to drain it is a waste of CPU time. */
 #ifdef INET
@@ -711,19 +720,57 @@ ps_root_startcb(void *arg)
            (DHCPCD_MANAGER | DHCPCD_DEV))
                dev_start(ctx, ps_root_handleinterface);
 #endif
-
        return 0;
 }
 
-static void
-ps_root_signalcb(int sig, __unused void *arg)
+void
+ps_root_signalcb(int sig, void *arg)
 {
+       struct dhcpcd_ctx *ctx = arg;
+       int status;
+       pid_t pid;
+       const char *ifname, *name;
+       struct ps_process *psp;
 
-       if (sig == SIGCHLD) {
-               while (waitpid(-1, NULL, WNOHANG) > 0)
-                       ;
+       if (sig != SIGCHLD)
                return;
+
+       while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+               psp = ps_findprocesspid(ctx, pid);
+               if (psp != NULL) {
+                       ifname = psp->psp_ifname;
+                       name = psp->psp_name;
+               } else {
+                       /* Ignore logging the double fork */
+                       if (ctx->options & DHCPCD_LAUNCHER)
+                               continue;
+                       ifname = "";
+                       name = "unknown process";
+               }
+
+               if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+                       logerrx("%s%s%s exited unexpectedly from PID %d,"
+                           " code=%d",
+                           ifname, ifname[0] != '\0' ? ": " : "",
+                           name, pid, WEXITSTATUS(status));
+               else if (WIFSIGNALED(status))
+                       logerrx("%s%s%s exited unexpectedly from PID %d,"
+                           " signal=%s",
+                           ifname, ifname[0] != '\0' ? ": " : "",
+                           name, pid, strsignal(WTERMSIG(status)));
+               else
+                       logdebugx("%s%s%s exited from PID %d",
+                           ifname, ifname[0] != '\0' ? ": " : "",
+                           name, pid);
+
+               if (psp != NULL)
+                       ps_freeprocess(psp);
        }
+
+       if (!(ctx->options & DHCPCD_EXITING))
+               return;
+       if (!(PS_WAITING_FOR_PROCESSES(ctx)))
+               eloop_exit(ctx->ps_eloop, EXIT_SUCCESS);
 }
 
 int (*handle_interface)(void *, int, const char *);
@@ -799,25 +846,29 @@ ps_root_log(void *arg, unsigned short events)
        if (events != ELE_READ)
                logerrx("%s: unexpected event 0x%04x", __func__, events);
 
-       /* OpenBSD reports connection reset when dhcpcd exits ... */
-       if (logreadfd(ctx->ps_log_fd) == -1 && errno != ECONNRESET)
+       if (logreadfd(ctx->ps_log_root_fd) == -1)
                logerr(__func__);
 }
 
 pid_t
 ps_root_start(struct dhcpcd_ctx *ctx)
 {
+       struct ps_id id = {
+               .psi_ifindex = 0,
+               .psi_cmd = PS_ROOT,
+       };
+       struct ps_process *psp;
        int logfd[2], datafd[2];
        pid_t pid;
 
-       if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, logfd) == -1)
+       if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, logfd) == -1)
                return -1;
 #ifdef PRIVSEP_RIGHTS
        if (ps_rights_limit_fdpair(logfd) == -1)
                return -1;
 #endif
 
-       if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, datafd) == -1)
+       if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
                return -1;
        if (ps_setbuf_fdpair(datafd) == -1)
                return -1;
@@ -826,16 +877,17 @@ ps_root_start(struct dhcpcd_ctx *ctx)
                return -1;
 #endif
 
-       pid = ps_dostart(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd,
-           ps_root_recvmsg, NULL, ctx,
-           ps_root_startcb, ps_root_signalcb, 0);
+       psp = ctx->ps_root = ps_newprocess(ctx, &id);
+       strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name));
+       pid = ps_startprocess(psp, ps_root_recvmsg, NULL,
+           ps_root_startcb, ps_root_signalcb, PSF_ELOOP);
 
        if (pid == 0) {
-               ctx->ps_log_fd = logfd[1];
-               if (eloop_event_add(ctx->eloop, ctx->ps_log_fd, ELE_READ,
+               ctx->ps_log_fd = logfd[0]; /* Keep open to pass to processes */
+               ctx->ps_log_root_fd = logfd[1];
+               if (eloop_event_add(ctx->eloop, ctx->ps_log_root_fd, ELE_READ,
                    ps_root_log, ctx) == -1)
                        return -1;
-               close(logfd[0]);
                ctx->ps_data_fd = datafd[1];
                close(datafd[0]);
                return 0;
@@ -849,14 +901,7 @@ ps_root_start(struct dhcpcd_ctx *ctx)
        close(datafd[1]);
        if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, ELE_READ,
            ps_root_dispatch, ctx) == -1)
-               return -1;
-
-       if ((ctx->ps_eloop = eloop_new()) == NULL)
-               return -1;
-
-       eloop_signal_set_cb(ctx->ps_eloop,
-           dhcpcd_signals, dhcpcd_signals_len,
-           ps_root_signalcb, ctx);
+               return 1;
 
        return pid;
 }
@@ -865,19 +910,43 @@ int
 ps_root_stop(struct dhcpcd_ctx *ctx)
 {
 
+       /* If we are the root process, ensure the log fd is fully drained. */
+       if (ctx->options & DHCPCD_PRIVSEPROOT && ctx->ps_log_fd != -1) {
+               do {
+                       ;
+               } while (logreadfd(ctx->ps_log_fd) != -1);
+       }
+
        if (!(ctx->options & DHCPCD_PRIVSEP) ||
            ctx->options & DHCPCD_FORKED ||
            ctx->eloop == NULL)
                return 0;
 
-       return ps_dostop(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd);
+       if (ps_stopprocess(ctx->ps_root) == -1)
+               return -1;
+       ctx->ps_root = NULL;
+       return ps_stopwait(ctx);
+}
+
+ssize_t
+ps_root_stopprocesses(struct dhcpcd_ctx *ctx)
+{
+
+       if (!(IN_PRIVSEP_SE(ctx)))
+               return 0;
+
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_STOPPROCS, 0,
+           NULL, 0) == -1)
+               return -1;
+       return ps_root_readerror(ctx, NULL, 0);
 }
 
 ssize_t
 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1)
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_SCRIPT,
+           0, data, len) == -1)
                return -1;
        return ps_root_readerror(ctx, NULL, 0);
 }
@@ -886,14 +955,15 @@ ssize_t
 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
     size_t len)
 {
+       int fd = ctx->ps_root->psp_fd;
 #ifdef IOCTL_REQUEST_TYPE
        unsigned long ulreq = 0;
 
        memcpy(&ulreq, &req, sizeof(req));
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1)
+       if (ps_sendcmd(ctx, fd, PS_IOCTL, ulreq, data, len) == -1)
                return -1;
 #else
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1)
+       if (ps_sendcmd(ctx, fd, PS_IOCTL, req, data, len) == -1)
                return -1;
 #endif
        return ps_root_readerror(ctx, data, len);
@@ -903,7 +973,7 @@ ssize_t
 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_UNLINK, 0,
            file, strlen(file) + 1) == -1)
                return -1;
        return ps_root_readerror(ctx, NULL, 0);
@@ -913,7 +983,7 @@ ssize_t
 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
     void *data, size_t len)
 {
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_READFILE, 0,
            file, strlen(file) + 1) == -1)
                return -1;
        return ps_root_readerror(ctx, data, len);
@@ -934,7 +1004,7 @@ ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
        }
        memcpy(buf + flen, data, len);
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_WRITEFILE, mode,
            buf, flen + len) == -1)
                return -1;
        return ps_root_readerror(ctx, NULL, 0);
@@ -944,7 +1014,7 @@ ssize_t
 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_FILEMTIME, 0,
            file, strlen(file) + 1) == -1)
                return -1;
        return ps_root_readerror(ctx, time, sizeof(*time));
@@ -954,7 +1024,8 @@ ssize_t
 ps_root_logreopen(struct dhcpcd_ctx *ctx)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_LOGREOPEN, 0, NULL, 0) == -1)
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_LOGREOPEN, 0,
+           NULL, 0) == -1)
                return -1;
        return ps_root_readerror(ctx, NULL, 0);
 }
@@ -970,7 +1041,7 @@ ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
        size_t len;
        ssize_t err;
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd,
            PS_GETIFADDRS, 0, NULL, 0) == -1)
                return -1;
        err = ps_root_mreaderror(ctx, &buf, &len);
@@ -1045,7 +1116,7 @@ ssize_t
 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_IP6FORWARDING, 0,
            ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1)
                return -1;
        return ps_root_readerror(ctx, NULL, 0);
@@ -1057,7 +1128,7 @@ int
 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_AUTH_MONORDM, 0,
            rdm, sizeof(*rdm))== -1)
                return -1;
        return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm));
@@ -1069,7 +1140,7 @@ int
 ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0,
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_DEV_INITTED, 0,
            ifname, strlen(ifname) + 1)== -1)
                return -1;
        return (int)ps_root_readerror(ctx, NULL, 0);
@@ -1079,7 +1150,8 @@ int
 ps_root_dev_listening(struct dhcpcd_ctx * ctx)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1)
+       if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_DEV_LISTENING,
+           0, NULL, 0) == -1)
                return -1;
        return (int)ps_root_readerror(ctx, NULL, 0);
 }
index 7fdd9f69f212795e5e73963a86ae0252bad3fa73..a54696c30772bcec146feefbf44c9453db08ac9e 100644 (file)
@@ -37,6 +37,7 @@
 
 pid_t ps_root_start(struct dhcpcd_ctx *ctx);
 int ps_root_stop(struct dhcpcd_ctx *ctx);
+void ps_root_signalcb(int, void *);
 
 ssize_t ps_root_readerror(struct dhcpcd_ctx *, void *, size_t);
 ssize_t ps_root_mreaderror(struct dhcpcd_ctx *, void **, size_t *);
@@ -49,6 +50,7 @@ ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
     const void *, size_t);
 ssize_t ps_root_logreopen(struct dhcpcd_ctx *);
 ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
+ssize_t ps_root_stopprocesses(struct dhcpcd_ctx *);
 int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *);
 #ifdef PRIVSEP_GETIFADDRS
 int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
index 0a9f93bfaf39574ea94f222a46cb41550ea7d8b2..25c5fa429e61af6fe815cd4576d782e374a3d176 100644 (file)
@@ -114,6 +114,7 @@ ps_init(struct dhcpcd_ctx *ctx)
 static int
 ps_dropprivs(struct dhcpcd_ctx *ctx)
 {
+       return 0;
        struct passwd *pw = ctx->ps_user;
 
        if (ctx->options & DHCPCD_LAUNCHER)
@@ -135,7 +136,7 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
 
        struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
 
-       if (ctx->ps_control_pid != getpid()) {
+       if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) {
                /* Prohibit new files, sockets, etc */
 #if (defined(__linux__) || defined(__sun) || defined(__OpenBSD__)) && \
     !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
@@ -318,17 +319,17 @@ ps_rights_limit_stdio(struct dhcpcd_ctx *ctx)
 #endif
 
 pid_t
-ps_dostart(struct dhcpcd_ctx *ctx,
-    pid_t *priv_pid, int *priv_fd,
+ps_startprocess(struct ps_process *psp,
     void (*recv_msg)(void *, unsigned short),
     void (*recv_unpriv_msg)(void *, unsigned short),
-    void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *),
+    int (*callback)(struct ps_process *), void (*signal_cb)(int, void *),
     unsigned int flags)
 {
+       struct dhcpcd_ctx *ctx = psp->psp_ctx;
        int fd[2];
        pid_t pid;
 
-       if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) {
+       if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, fd) == -1) {
                logerr("%s: socketpair", __func__);
                return -1;
        }
@@ -348,32 +349,30 @@ ps_dostart(struct dhcpcd_ctx *ctx,
                logerr("fork");
                return -1;
        case 0:
-               *priv_fd = fd[1];
+               psp->psp_pid = getpid();
+               psp->psp_fd = fd[1];
                close(fd[0]);
                break;
        default:
-               *priv_pid = pid;
-               *priv_fd = fd[0];
+               psp->psp_pid = pid;
+               psp->psp_fd = fd[0];
                close(fd[1]);
                if (recv_unpriv_msg == NULL)
                        ;
-               else if (eloop_event_add(ctx->eloop, *priv_fd, ELE_READ,
-                   recv_unpriv_msg, recv_ctx) == -1)
+               else if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
+                   recv_unpriv_msg, psp) == -1)
                {
-                       logerr("%s: eloop_event_add", __func__);
+                       logerr("%s: eloop_event_add fd %d",
+                           __func__, psp->psp_fd);
                        return -1;
                }
                return pid;
        }
 
        ctx->options |= DHCPCD_FORKED;
-       if (ctx->fork_fd != -1) {
-               close(ctx->fork_fd);
-               ctx->fork_fd = -1;
-       }
-       pidfile_clean();
-
-       eloop_clear(ctx->eloop, loggetfd(), -1);
+       if (ctx->ps_log_fd != -1)
+               logsetfd(ctx->ps_log_fd);
+       eloop_clear(ctx->eloop, -1);
        eloop_forked(ctx->eloop);
        eloop_signal_set_cb(ctx->eloop,
            dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx);
@@ -383,16 +382,31 @@ ps_dostart(struct dhcpcd_ctx *ctx,
                goto errexit;
        }
 
-       /* We are not root */
-       if (priv_fd != &ctx->ps_root_fd) {
-               ps_freeprocesses(ctx, recv_ctx);
-               if (ctx->ps_root_fd != -1) {
-                       close(ctx->ps_root_fd);
-                       ctx->ps_root_fd = -1;
-               }
+       if (ctx->fork_fd != -1) {
+               /* Already removed from eloop thanks to above clear. */
+               close(ctx->fork_fd);
+               ctx->fork_fd = -1;
+       }
 
+       /* This process has no need of the blocking inner eloop. */
+       if (!(flags & PSF_ELOOP)) {
+               eloop_free(ctx->ps_eloop);
+               ctx->ps_eloop = NULL;
+       } else
+               eloop_forked(ctx->ps_eloop);
+
+       pidfile_clean();
+       ps_freeprocesses(ctx, psp);
+
+       if (ctx->ps_root != psp) {
+               ctx->options &= ~DHCPCD_PRIVSEPROOT;
+               ctx->ps_root = NULL;
+               if (ctx->ps_log_root_fd != -1) {
+                       /* Already removed from eloop thanks to above clear. */
+                       close(ctx->ps_log_root_fd);
+                       ctx->ps_log_root_fd = -1;
+               }
 #ifdef PRIVSEP_RIGHTS
-               /* We cannot limit the root process in any way. */
                if (ps_rights_limit_stdio(ctx) == -1) {
                        logerr("ps_rights_limit_stdio");
                        goto errexit;
@@ -400,19 +414,26 @@ ps_dostart(struct dhcpcd_ctx *ctx,
 #endif
        }
 
-       if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) {
-               close(ctx->ps_inet_fd);
-               ctx->ps_inet_fd = -1;
-       }
+       if (ctx->ps_inet != psp)
+               ctx->ps_inet = NULL;
+       if (ctx->ps_ctl != psp)
+               ctx->ps_ctl = NULL;
+
+#if 0
+       char buf[1024];
+       errno = 0;
+       ssize_t xx = recv(psp->psp_fd, buf, sizeof(buf), MSG_PEEK);
+       logerr("pid %d test fd %d recv peek %zd", getpid(), psp->psp_fd, xx);
+#endif
 
-       if (eloop_event_add(ctx->eloop, *priv_fd, ELE_READ,
-           recv_msg, recv_ctx) == -1)
+       if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
+           recv_msg, psp) == -1)
        {
-               logerr("%s: eloop_event_add", __func__);
+               logerr("%d %s: eloop_event_add XX fd %d", getpid(), __func__, psp->psp_fd);
                goto errexit;
        }
 
-       if (callback(recv_ctx) == -1)
+       if (callback(psp) == -1)
                goto errexit;
 
        if (flags & PSF_DROPPRIVS)
@@ -421,38 +442,57 @@ ps_dostart(struct dhcpcd_ctx *ctx,
        return 0;
 
 errexit:
-       /* Failure to start root or inet processes is fatal. */
-       if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd)
-               (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0);
-       shutdown(*priv_fd, SHUT_RDWR);
-       *priv_fd = -1;
+       if (psp->psp_fd != -1) {
+               close(psp->psp_fd);
+               psp->psp_fd = -1;
+       }
        eloop_exit(ctx->eloop, EXIT_FAILURE);
        return -1;
 }
 
+void
+ps_process_timeout(void *arg)
+{
+       struct dhcpcd_ctx *ctx = arg;
+
+       logerrx("%s: timed out", __func__);
+       eloop_exit(ctx->eloop, EXIT_FAILURE);
+}
+
 int
-ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd)
+ps_stopprocess(struct ps_process *psp)
 {
        int err = 0;
 
+       if (psp == NULL)
+               return 0;
+
 #ifdef PRIVSEP_DEBUG
-       logdebugx("%s: pid=%d fd=%d", __func__, *pid, *fd);
+       logdebugx("%s: me=%d pid=%d fd=%d %s", __func__,
+           getpid(), psp->psp_pid, psp->psp_fd, psp->psp_name);
 #endif
 
-       if (*fd != -1) {
-               eloop_event_delete(ctx->eloop, *fd);
-               if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1) {
+       if (psp->psp_fd != -1) {
+               eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd);
+#if 0
+               if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_STOP, 0,
+                   NULL, 0) == -1)
+               {
+                       logerr("%d %d %s %s", getpid(), psp->psp_pid, psp->psp_name, __func__);
+                       err = -1;
+               }
+               shutdown(psp->psp_fd, SHUT_WR);
+#else
+               if (shutdown(psp->psp_fd, SHUT_WR) == -1) {
                        logerr(__func__);
                        err = -1;
                }
-               (void)shutdown(*fd, SHUT_RDWR);
-               close(*fd);
-               *fd = -1;
+#endif
+               psp->psp_fd = -1;
        }
 
        /* Don't wait for the process as it may not respond to the shutdown
         * request. We'll reap the process on receipt of SIGCHLD. */
-       *pid = 0;
        return err;
 }
 
@@ -463,6 +503,13 @@ ps_start(struct dhcpcd_ctx *ctx)
 
        TAILQ_INIT(&ctx->ps_processes);
 
+       /* We need an inner eloop to block with. */
+       if ((ctx->ps_eloop = eloop_new()) == NULL)
+               return -1;
+       eloop_signal_set_cb(ctx->ps_eloop,
+           dhcpcd_signals, dhcpcd_signals_len,
+           dhcpcd_signal_cb, ctx);
+
        switch (pid = ps_root_start(ctx)) {
        case -1:
                logerr("ps_root_start");
@@ -553,7 +600,7 @@ ps_managersandbox(struct dhcpcd_ctx *ctx, const char *_pledge)
         * If it cannot be opened before chrooting then syslog(3) will fail.
         * openlog(3) does not return an error which doubly sucks.
         */
-       if (ctx->ps_root_fd == -1) {
+       if (ctx->ps_root == NULL) {
                unsigned int logopts = loggetopts();
 
                logopts &= ~LOGERR_LOG;
@@ -602,35 +649,85 @@ ps_stop(struct dhcpcd_ctx *ctx)
            ctx->eloop == NULL)
                return 0;
 
-       r = ps_ctl_stop(ctx);
-       if (r != 0)
-               ret = r;
+       if (ctx->ps_ctl != NULL) {
+               r = ps_ctl_stop(ctx);
+               if (r != 0)
+                       ret = r;
+       }
 
-       r = ps_inet_stop(ctx);
-       if (r != 0)
-               ret = r;
+       if (ctx->ps_inet != NULL) {
+               r = ps_inet_stop(ctx);
+               if (r != 0)
+                       ret = r;
+       }
 
-       /* We've been chrooted, so we need to tell the
-        * privileged proxy to remove the pidfile. */
-       if (ps_root_unlink(ctx, ctx->pidfile) == -1)
-               ret = -1;
+       if (ctx->ps_root != NULL) {
+               if (ps_root_stopprocesses(ctx) == -1)
+                       ret = -1;
+       }
 
        return ret;
 }
 
+int
+ps_stopwait(struct dhcpcd_ctx *ctx)
+{
+       int error = EXIT_SUCCESS;
+
+       if (ctx->ps_eloop != NULL && PS_WAITING_FOR_PROCESSES(ctx)) {
+               int waited;
+
+               ctx->options |= DHCPCD_EXITING;
+               if (eloop_timeout_add_sec(ctx->ps_eloop, PS_PROCESS_TIMEOUT,
+                   ps_process_timeout, ctx) == -1)
+                       logerr("%s: eloop_timeout_add_sec", __func__);
+               eloop_enter(ctx->ps_eloop);
+               waited = eloop_start(ctx->ps_eloop, &ctx->sigset);
+               if (waited != EXIT_SUCCESS) {
+                       logerr("%s: eloop_start", __func__);
+                       error = waited;
+               }
+               eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx);
+       }
+
+       if (IN_PRIVSEP_SE(ctx) && ctx->ps_root != NULL) {
+               struct ps_process *psp = ctx->ps_root;
+
+               if (ps_root_unlink(ctx, ctx->pidfile) == -1)
+                       logerr("%s: ps_root_unlink", __func__);
+
+               /* We cannot log the root process exited before we
+                * log dhcpcd exits because the latter requires the former.
+                * So we just log the intent to exit. */
+               logdebugx("%s%s%s will exit from PID %d",
+                   psp->psp_ifname,
+                   psp->psp_ifname[0] != '\0' ? ": " : "",
+                   psp->psp_name, psp->psp_pid);
+       }
+
+       return error;
+}
+
 void
 ps_freeprocess(struct ps_process *psp)
 {
+       struct dhcpcd_ctx *ctx = psp->psp_ctx;
 
-       TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next);
+       TAILQ_REMOVE(&ctx->ps_processes, psp, next);
        if (psp->psp_fd != -1) {
-               eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd);
+               eloop_event_delete(ctx->eloop, psp->psp_fd);
                close(psp->psp_fd);
        }
        if (psp->psp_work_fd != -1) {
-               eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd);
+               eloop_event_delete(ctx->eloop, psp->psp_work_fd);
                close(psp->psp_work_fd);
        }
+       if (ctx->ps_root == psp)
+               ctx->ps_root = NULL;
+       if (ctx->ps_inet == psp)
+               ctx->ps_inet = NULL;
+       if (ctx->ps_ctl == psp)
+               ctx->ps_ctl = NULL;
 #ifdef INET
        if (psp->psp_bpf != NULL)
                bpf_close(psp->psp_bpf);
@@ -641,12 +738,23 @@ ps_freeprocess(struct ps_process *psp)
 static void
 ps_free(struct dhcpcd_ctx *ctx)
 {
-       struct ps_process *psp;
-       bool stop = ctx->ps_root_pid == getpid();
+       struct ps_process *ppsp, *psp;
+       bool stop;
+
+       if (ctx->ps_root != NULL)
+               ppsp = ctx->ps_root;
+       else if (ctx->ps_ctl != NULL)
+               ppsp = ctx->ps_ctl;
+       else
+               ppsp = NULL;
+       if (ppsp != NULL)
+               stop = ppsp->psp_pid == getpid();
+       else
+               stop = false;
 
        while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) {
-               if (stop)
-                       ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
+               if (stop && psp != ppsp)
+                       ps_stopprocess(psp);
                ps_freeprocess(psp);
        }
 }
@@ -739,7 +847,6 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd,
 
        len = writev(fd, iov, iovlen);
        if (len == -1) {
-               logerr(__func__);
                if (ctx->options & DHCPCD_FORKED &&
                    !(ctx->options & DHCPCD_PRIVSEPROOT))
                        eloop_exit(ctx->eloop, EXIT_FAILURE);
@@ -883,27 +990,24 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, unsigned short events,
        };
        ssize_t len;
 
-       if (events != ELE_READ)
+       if (!(events & ELE_READ))
                logerrx("%s: unexpected event 0x%04x", __func__, events);
 
        len = recvmsg(rfd, &msg, 0);
-
        if (len == -1)
                logerr("%s: recvmsg", __func__);
        if (len == -1 || len == 0) {
-               if (ctx->options & DHCPCD_FORKED &&
-                   !(ctx->options & DHCPCD_PRIVSEPROOT))
+               if (ctx->options & DHCPCD_FORKED)
                        eloop_exit(ctx->eloop,
-                           len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+                           len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
                return len;
        }
 
        iov[0].iov_len = (size_t)len;
        len = ps_sendcmdmsg(wfd, cmd, &msg);
        if (len == -1) {
-               logerr("ps_sendcmdmsg");
-               if (ctx->options & DHCPCD_FORKED &&
-                   !(ctx->options & DHCPCD_PRIVSEPROOT))
+               logerr("%s: ps_sendcmdmsg", __func__);
+               if (ctx->options & DHCPCD_FORKED)
                        eloop_exit(ctx->eloop, EXIT_FAILURE);
        }
        return len;
@@ -921,7 +1025,7 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
        struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 };
        bool stop = false;
 
-       if (events != ELE_READ)
+       if (!(events & ELE_READ))
                logerrx("%s: unexpected event 0x%04x", __func__, events);
 
        len = read(fd, &psm, sizeof(psm));
@@ -945,6 +1049,7 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
        }
 
        if (stop) {
+               ctx->options |= DHCPCD_EXITING;
 #ifdef PRIVSEP_DEBUG
                logdebugx("process %d stopping", getpid());
 #endif
@@ -980,6 +1085,19 @@ ps_findprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
        return NULL;
 }
 
+struct ps_process *
+ps_findprocesspid(struct dhcpcd_ctx *ctx, pid_t pid)
+{
+       struct ps_process *psp;
+
+       TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+               if (psp->psp_pid == pid)
+                       return psp;
+       }
+       errno = ESRCH;
+       return NULL;
+}
+
 struct ps_process *
 ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
 {
@@ -991,6 +1109,8 @@ ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
        psp->psp_ctx = ctx;
        memcpy(&psp->psp_id, psid, sizeof(psp->psp_id));
        psp->psp_work_fd = -1;
+       if (!(ctx->options & DHCPCD_MANAGER))
+               strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_name));
        TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next);
        return psp;
 }
index 57fa75159c8b9d05c461f45ac4175c8f02ad8501..57a562e49d4c6a24cae3829c94b6fdb447b2d387 100644 (file)
@@ -33,6 +33,7 @@
 
 /* Start flags */
 #define        PSF_DROPPRIVS           0x01
+#define        PSF_ELOOP               0x02
 
 /* Protocols */
 #define        PS_BOOTP                0x0001
 #define        PS_CTL                  0x0018
 #define        PS_CTL_EOF              0x0019
 #define        PS_LOGREOPEN            0x0020
+#define        PS_STOPPROCS            0x0021
+
+/* Domains */
+#define        PS_ROOT                 0x0101
+#define        PS_INET                 0x0102
+#define        PS_CONTROL              0x0103
 
 /* BSD Commands */
-#define        PS_IOCTLLINK            0x0101
-#define        PS_IOCTL6               0x0102
-#define        PS_IOCTLINDIRECT        0x0103
-#define        PS_IP6FORWARDING        0x0104
-#define        PS_GETIFADDRS           0x0105
-#define        PS_IFIGNOREGRP          0x0106
+#define        PS_IOCTLLINK            0x0201
+#define        PS_IOCTL6               0x0202
+#define        PS_IOCTLINDIRECT        0x0203
+#define        PS_IP6FORWARDING        0x0204
+#define        PS_GETIFADDRS           0x0205
+#define        PS_IFIGNOREGRP          0x0206
 
 /* Dev Commands */
 #define        PS_DEV_LISTENING        0x1001
                                 CMSG_SPACE(sizeof(struct in6_pktinfo) + \
                                            sizeof(int)))
 
+#define        PSP_NAMESIZE            16 + INET_MAX_ADDRSTRLEN
+
 /* Handy macro to work out if in the privsep engine or not. */
 #define        IN_PRIVSEP(ctx) \
        ((ctx)->options & DHCPCD_PRIVSEP)
 #define        IN_PRIVSEP_SE(ctx)      \
        (((ctx)->options & (DHCPCD_PRIVSEP | DHCPCD_FORKED)) == DHCPCD_PRIVSEP)
 
+#define        PS_PROCESS_TIMEOUT      5       /* seconds to stop all processes */
+
+/* We always have ourself as a process */
+#define        PS_WAITING_FOR_PROCESSES(_ctx)                          \
+       ((IN_PRIVSEP_SE((_ctx)) &&                              \
+         TAILQ_LAST(&(_ctx)->ps_processes, ps_process_head) != (_ctx)->ps_root) ||     \
+         (!IN_PRIVSEP_SE((_ctx)) &&                            \
+         TAILQ_FIRST(&(_ctx)->ps_processes) !=                 \
+         TAILQ_LAST(&(_ctx)->ps_processes, ps_process_head)))
+
 #if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
 #define PRIVSEP_RIGHTS
 #endif
@@ -154,6 +173,7 @@ struct ps_process {
        int psp_work_fd;
        unsigned int psp_ifindex;
        char psp_ifname[IF_NAMESIZE];
+       char psp_name[PSP_NAMESIZE];
        uint16_t psp_proto;
        const char *psp_protostr;
 
@@ -175,6 +195,7 @@ TAILQ_HEAD(ps_process_head, ps_process);
 int ps_init(struct dhcpcd_ctx *);
 int ps_start(struct dhcpcd_ctx *);
 int ps_stop(struct dhcpcd_ctx *);
+int ps_stopwait(struct dhcpcd_ctx *);
 int ps_entersandbox(const char *, const char **);
 int ps_managersandbox(struct dhcpcd_ctx *, const char *);
 
@@ -207,16 +228,16 @@ int ps_rights_limit_fdpair(int []);
 int ps_seccomp_enter(void);
 #endif
 
-pid_t ps_dostart(struct dhcpcd_ctx * ctx,
-    pid_t *priv_pid, int *priv_fd,
+pid_t ps_startprocess(struct ps_process *,
     void (*recv_msg)(void *, unsigned short),
     void (*recv_unpriv_msg)(void *, unsigned short),
-    void *recv_ctx, int (*callback)(void *), void (*)(int, void *),
+    int (*callback)(struct ps_process *), void (*)(int, void *),
     unsigned int);
-int ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd);
-
+int ps_stopprocess(struct ps_process *);
 struct ps_process *ps_findprocess(struct dhcpcd_ctx *, struct ps_id *);
+struct ps_process *ps_findprocesspid(struct dhcpcd_ctx *, pid_t);
 struct ps_process *ps_newprocess(struct dhcpcd_ctx *, struct ps_id *);
+void ps_process_timeout(void *);
 void ps_freeprocess(struct ps_process *);
 void ps_freeprocesses(struct dhcpcd_ctx *, struct ps_process *);
 #endif