privsep has never worked on Sun.
To be fair, it's not any better because all processes
run as root, outside a chroot and without limits.
So why do this?
So we can eventually remove all non privsep code from dhcpcd, to
reduce complexity and provide a more secure platform for other OS.
echo "SRCS+= auth.c" >>$CONFIG_MK
fi
-if [ -z "$PRIVSEP" ]; then
- # privilege separation works fine .... except on Solaris
- case "$OS" in
- solaris*|sunos*) PRIVSEP=no;;
- *) PRIVSEP=yes;;
- esac
-fi
-
-if [ "$PRIVSEP" = yes ]; then
+if [ -z "$PRIVSEP" ] || [ "$PRIVSEP" = yes ]; then
echo "Enabling Privilege Separation"
# Try and work out system user
*/
/* Stop sunos headers including the system queue ... */
+#if 1
+#include "queue.h"
+#endif
+
#include <sys/ioctl.h>
#include <sys/mac.h>
#include <sys/pfmod.h>
#include <stropts.h>
#include <unistd.h>
-#include "queue.h"
-
/* Private libsocket interface we can hook into to get
* a better getifaddrs(3).
* From libsocket_priv.h, which is not always distributed so is here. */
#ifdef __sun
int
-ipv6nd_openif(struct interface *ifp)
+ipv6nd_openif(unsigned int ifindex)
{
int fd;
struct ipv6_mreq mreq = {
.ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
- .ipv6mr_interface = ifp->index
+ .ipv6mr_interface = ifindex,
};
- struct rs_state *state = RS_STATE(ifp);
- uint_t ifindex = ifp->index;
-
- if (state->nd_fd != -1)
- return state->nd_fd;
fd = ipv6nd_open(true);
if (fd == -1)
return -1;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &ifindex,
- sizeof(ifindex)) == -1) {
- close(fd);
- return -1;
- }
+ sizeof(ifindex)) == -1)
+ goto err;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
- sizeof(mreq)) == -1) {
- close(fd);
- return -1;
- }
+ sizeof(mreq)) == -1)
+ goto err;
- if (eloop_event_add(ifp->ctx->eloop, fd, ELE_READ, ipv6nd_handledata,
- ifp) == -1) {
- close(fd);
- return -1;
- }
-
- state->nd_fd = fd;
return fd;
+
+err:
+ close(fd);
+ return -1;
}
#endif
#endif
#ifdef __sun
if (state->nd_fd == -1) {
- if (ipv6nd_openif(ifp) == -1) {
+ state->nd_fd = ipv6nd_openif(ifp->index);
+ if (state->nd_fd == -1) {
+ logerr(__func__);
+ return;
+ }
+ if (eloop_event_add(ifp->ctx->eloop, state->nd_fd, ELE_READ,
+ ipv6nd_handledata, ifp) == -1) {
logerr(__func__);
+ close(state->nd_fd);
+ state->nd_fd = -1;
return;
}
}
}
#ifdef __sun
state->nd_fd = -1;
+#ifdef PRIVSEP
+ if (IN_PRIVSEP(ifp->ctx) && ps_inet_opennd(ifp) == -1) {
+ logerr("%s: ps_inet_opennd", ifp->name);
+ return;
+ }
+#endif
#endif
}
int ipv6nd_open(bool);
#ifdef __sun
-int ipv6nd_openif(struct interface *);
+int ipv6nd_openif(unsigned int);
#endif
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
int ipv6nd_rtpref(uint8_t);
psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
#ifdef DEBUG_FD
- logdebugx("pid %d bpf_fd=%d", getpid(), psp->psp_bpf->bpf_fd);
+ logdebugx("pid %ld bpf_fd=%d", (long)getpid(), psp->psp_bpf->bpf_fd);
#endif
if (psp->psp_bpf == NULL)
logerr("%s: bpf_open", __func__);
ps_entersandbox("stdio", NULL);
break;
default:
- logdebugx("%s: spawned %s on PID %d", psp->psp_ifname,
- psp->psp_name, psp->psp_pid);
+ logdebugx("%s: spawned %s on PID %ld", psp->psp_ifname,
+ psp->psp_name, (long)psp->psp_pid);
break;
}
return start;
ps_inet_recvra(void *arg, unsigned short events)
{
#ifdef __sun
- struct interface *ifp = arg;
- struct rs_state *state = RS_STATE(ifp);
- struct dhcpcd_ctx *ctx = ifp->ctx;
+ struct ps_process *psp = arg;
- if (ps_recvmsg(state->nd_fd, events, PS_ND, ctx->ps_inet->psp_fd) == -1)
+ if (ps_recvmsg(psp->psp_work_fd, events, PS_ND,
+ psp->psp_ctx->ps_data_fd) == -1)
logerr(__func__);
#else
struct dhcpcd_ctx *ctx = arg;
#endif
#if defined(INET6) && defined(__sun)
-static void
-ps_inet_recvin6nd(void *arg)
-{
- struct ps_process *psp = arg;
-
- if (ps_recvmsg(psp->psp_work_fd, PS_ND, psp->psp_ctx->ps_data_fd) == -1)
- logerr(__func__);
-}
-
static int
ps_inet_listennd(struct ps_process *psp)
{
#ifdef HAVE_SETPROCTITLE
- setproctitle("[ND network proxy]");
+ setproctitle("[%s proxy] %s", psp->psp_protostr, psp->psp_ifname);
#endif
- psp->psp_work_fd = ipv6nd_open(&psp->psp_ifp);
+ psp->psp_work_fd = ipv6nd_openif(psp->psp_ifindex);
if (psp->psp_work_fd == -1) {
logerr(__func__);
return -1;
}
#endif
- if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd,
- ps_inet_recvin6nd, psp) == -1) {
+ if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, ELE_READ,
+ ps_inet_recvra, psp) == -1) {
logerr(__func__);
return -1;
}
}
#endif
+static ssize_t
+ps_inet_recvmsgpspcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
+{
+ struct ps_process *psp = arg;
+
+#ifdef PRIVSEP_DEBUG
+ logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
+#endif
+
+ switch (psm->ps_cmd) {
+ case PS_ND:
+ if (!ps_inet_validnd(msg))
+ return -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return sendmsg(psp->psp_work_fd, msg, 0);
+}
+
static void
ps_inet_recvmsgpsp(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
/* Receive shutdown. */
- if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
+ if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
+ ps_inet_recvmsgpspcb, psp) == -1)
logerr(__func__);
}
int (*start_func)(struct ps_process *);
pid_t start;
struct ps_addr *psa = &psm->ps_id.psi_addr;
- void *ia;
+ void *ia = NULL;
char buf[INET_MAX_ADDRSTRLEN];
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
case PS_ND:
start_func = ps_inet_listennd;
psp->psp_protostr = "ND";
- ia = &psa->psa_in6_addr;
break;
#endif
#ifdef DHCP6
return -1;
}
- snprintf(psp->psp_name, sizeof(psp->psp_name), "%s proxy %s",
- psp->psp_protostr,
- inet_ntop(psa->psa_family, ia, buf, sizeof(buf)));
+ snprintf(psp->psp_name, sizeof(psp->psp_name), "%s proxy%s%s",
+ psp->psp_protostr, ia != NULL ? " " : "",
+ ia != NULL ? inet_ntop(psa->psa_family, ia, buf, sizeof(buf)) : "");
start = ps_startprocess(psp, ps_inet_recvmsgpsp, NULL, start_func,
PSF_DROPPRIVS);
switch (start) {
ps_entersandbox("stdio", NULL);
break;
default:
- logdebugx("%s: spawned %s on PID %d", psp->psp_ifname,
- psp->psp_name, psp->psp_pid);
+ logdebugx("%s: spawned %s on PID %ld", psp->psp_ifname,
+ psp->psp_name, (long)psp->psp_pid);
break;
}
return start;
return ps_stopprocess(psp);
} else if (psm->ps_cmd & PS_START) {
/* Process has already started .... */
- logdebugx("%s%sprocess %s already started on pid %d",
+ logdebugx("%s%sprocess %s already started on pid %ld",
psp->psp_ifname,
psp->psp_ifname[0] != '\0' ? ": " : "",
- psp->psp_name, psp->psp_pid);
+ psp->psp_name, (long)psp->psp_pid);
return 0;
}
err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
if (err == -1) {
- logerr("%s: failed to send message to pid %d", __func__,
- psp->psp_pid);
+ logerr("%s: failed to send message to pid %ld",
+ __func__, (long)psp->psp_pid);
ps_freeprocess(psp);
}
return 0;
logerr("%s: setsockopt SO_RCVBUF DHCP", __func__);
}
#endif
-#ifdef INET6
+#if defined(INET6) && !defined(__sun)
if (ctx->options & DHCPCD_IPV6) {
int buflen = 1;
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
- logerrx("%s%s%s exited unexpectedly from PID %d,"
+ logerrx("%s%s%s exited unexpectedly from PID %ld,"
" code=%d",
- ifname, ifname[0] != '\0' ? ": " : "", name, pid,
- WEXITSTATUS(status));
+ ifname, ifname[0] != '\0' ? ": " : "", name,
+ (long)pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
- logerrx("%s%s%s exited unexpectedly from PID %d,"
+ logerrx("%s%s%s exited unexpectedly from PID %ld,"
" signal=%s",
- ifname, ifname[0] != '\0' ? ": " : "", name, pid,
- strsignal(WTERMSIG(status)));
+ ifname, ifname[0] != '\0' ? ": " : "", name,
+ (long)pid, strsignal(WTERMSIG(status)));
else
- logdebugx("%s%s%s exited from PID %d", ifname,
- ifname[0] != '\0' ? ": " : "", name, pid);
+ logdebugx("%s%s%s exited from PID %ld", ifname,
+ ifname[0] != '\0' ? ": " : "", name, (long)pid);
if (psp != NULL)
ps_freeprocess(psp);
ctx->udp_wfd = -1;
}
#endif
-#ifdef INET6
+#if defined(INET6) && !defined(__sun)
if (ctx->nd_fd != -1) {
close(ctx->nd_fd);
ctx->nd_fd = -1;
* So we just log the intent to exit.
* Even sending this will be a race to exit. */
if (psp) {
- logdebugx("%s%s%s will exit from PID %d", psp->psp_ifname,
+ logdebugx("%s%s%s will exit from PID %ld", psp->psp_ifname,
psp->psp_ifname[0] != '\0' ? ": " : "", psp->psp_name,
- psp->psp_pid);
+ (long)psp->psp_pid);
if (ps_stopprocess(psp) == -1)
return -1;
#include "if.h"
-#if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(__linux__))
+#if defined(PRIVSEP) && \
+ (defined(HAVE_CAPSICUM) || defined(__linux__) || defined(__sun))
#define PRIVSEP_GETIFADDRS
#endif
#include "logerr.h"
#include "privsep.h"
-#warning Solaris privsep should compile but wont work,
-#warning no DLPI support, ioctl support need rework
+#warning Solaris privsep should compile and work, but there is no
+#warning chroot support, dropping to dhcpcd user support,
+#warning no DLPI support, no ioctl validation, etc
/* We should implement privileges(5) as well.
* https://illumos.org/man/5/privileges */
}
ssize_t
-ps_root_os(struct ps_msghdr *psm, struct msghdr *msg, void **rdata,
- size_t *rlen, __unused bool *free_rdata)
+ps_root_os(__unused struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
+ struct msghdr *msg, void **rdata, size_t *rlen, __unused bool *free_rdata)
{
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
switch (psm->ps_cmd) {
case PS_IOCTL6:
err = ps_root_doioctl6(psm->ps_flags, data, len);
+ break;
case PS_ROUTE:
return ps_root_doroute(data, len);
default:
if (ctx->options & DHCPCD_LAUNCHER)
#ifdef ASAN
logwarnx("not chrooting as compiled for ASAN");
+#elif defined(__sun)
+ /* libdpli complains */
+ logwarnx("not chrooting on sun");
#else
logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir);
if (chdir("/") == -1)
logerr("%s: chdir: /", __func__);
+#ifdef __sun
+#warning not dropping any privileges on this platform .... eek!
+#else
if ((setgroups(1, &pw->pw_gid) == -1 || setgid(pw->pw_gid) == -1 ||
setuid(pw->pw_uid) == -1) &&
(errno != EPERM || ctx->options & DHCPCD_FORKED)) {
logerr("failed to drop privileges");
return -1;
}
+#endif
struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
+#ifndef __sun /* RLIMIT_NOFILE and ppoll don't mix */
/* Prohibit new files, sockets, etc
* The control proxy *does* need to create new fd's via accept(2). */
if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) {
if (setrlimit(RLIMIT_NOFILE, &rzero) == -1)
logerr("setrlimit RLIMIT_NOFILE");
}
+#endif
#define DHC_NOCHKIO (DHCPCD_STARTED | DHCPCD_DAEMONISE)
/* Prohibit writing to files.
case 0:
return 0;
default:
- logdebugx("spawned privileged proxy on PID %d", pid);
+ logdebugx("spawned privileged proxy on PID %ld", (long)pid);
}
/* No point in spawning the generic network listener if we're
case 0:
return 0;
default:
- logdebugx("spawned network proxy on PID %d", pid);
+ logdebugx("spawned network proxy on PID %ld", (long)pid);
}
started_net:
case 0:
return 0;
default:
- logdebugx("spawned controller proxy on PID %d", pid);
+ logdebugx("spawned controller proxy on PID %ld",
+ (long)pid);
}
}
return ps_seccomp_enter();
#else
if (sandbox != NULL)
+#ifdef __sun
+ *sandbox = "none";
+#else
*sandbox = "posix resource limited";
+#endif
return 0;
#endif
}
psp->psp_pfd = -1;
#endif
- if (!(ctx->options & DHCPCD_MANAGER))
- strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_ifname));
+ if (psid->psi_ifindex != 0) {
+ psp->psp_ifindex = psid->psi_ifindex;
+ if_indextoname(psid->psi_ifindex, psp->psp_ifname);
+ } else {
+ if (!(ctx->options & DHCPCD_MANAGER) && ctx->ifc != 0)
+ strlcpy(psp->psp_ifname, ctx->ifv[0],
+ sizeof(psp->psp_ifname));
+ }
TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next);
return psp;
}