return ctx->control_fd;
}
+static int
+control_unlink(struct dhcpcd_ctx *ctx, const char *file)
+{
+ int retval = 0;
+
+ errno = 0;
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP)
+ retval = (int)ps_root_unlink(ctx, file);
+ else
+#else
+ UNUSED(ctx);
+#endif
+ retval = unlink(file);
+
+ return retval == -1 && errno != ENOENT ? -1 : 0;
+}
+
int
control_stop(struct dhcpcd_ctx *ctx)
{
eloop_event_delete(ctx->eloop, ctx->control_fd);
close(ctx->control_fd);
ctx->control_fd = -1;
- if (unlink(ctx->control_sock) == -1 && errno != ENOENT)
+ if (control_unlink(ctx, ctx->control_sock) == -1)
retval = -1;
}
eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
close(ctx->control_unpriv_fd);
ctx->control_unpriv_fd = -1;
- if (unlink(UNPRIVSOCKET) == -1 && errno != ENOENT)
+ if (control_unlink(ctx, UNPRIVSOCKET) == -1)
retval = -1;
}
goto exit_failure;
}
+#ifdef PRIVSEP
+ if (ctx.options & DHCPCD_PRIVSEP && ps_dropprivs(&ctx) == -1) {
+ logerr("ps_dropprivs");
+ goto exit_failure;
+ }
+#endif
+
setproctitle("%s%s%s",
ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind],
ctx.options & DHCPCD_IPV4 ? " [ip4]" : "",
i = EXIT_FAILURE;
exit1:
+ if (control_stop(&ctx) == -1)
+ logerr("%s: control_stop", __func__);
#ifdef PRIVSEP
ps_stop(&ctx);
#endif
if (ifaddrs != NULL)
freeifaddrs(ifaddrs);
- if (control_stop(&ctx) == -1)
- logerr("%s: control_stop", __func__);
/* Free memory and close fd's */
if (ctx.ifaces) {
while ((ifp = TAILQ_FIRST(ctx.ifaces))) {
return status;
}
+static ssize_t
+ps_root_dounlink(void *data, size_t len)
+{
+ char *path = data;
+ size_t plen;
+
+ if (len < sizeof(plen)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memcpy(&plen, path, sizeof(plen));
+ path += sizeof(plen);
+ if (sizeof(plen) + plen > len) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return (ssize_t)unlink(path);
+}
+
static ssize_t
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_UNLINK:
+ err = ps_root_dounlink(data, len);
+ break;
default:
err = ps_root_os(psm, msg);
break;
#endif
return ps_root_readerror(ctx);
}
+
+ssize_t
+ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path)
+{
+ char buf[PATH_MAX], *p = buf;
+ size_t plen = strlen(path) + 1;
+ size_t len = sizeof(plen) + plen;
+
+ if (len > sizeof(buf)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ memcpy(p, &plen, sizeof(plen));
+ p += sizeof(plen);
+ memcpy(p, path, plen);
+
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, buf, len) == -1)
+ return -1;
+ return ps_root_readerror(ctx);
+}
ssize_t ps_root_readerror(struct dhcpcd_ctx *);
ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
+ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
#if defined(BSD) || defined(__sun)
ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
ps_init(struct dhcpcd_ctx *ctx)
{
struct passwd *pw;
- gid_t gid = (gid_t)-1;
errno = 0;
if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
return -1;
}
+ ctx->options |= DHCPCD_PRIVSEP;
+ return 0;
+}
- /* Change ownership of stuff we need to drop at exit. */
- if (chown(ctx->pidfile, pw->pw_uid, gid) == -1)
- logerr("chown `%s'", ctx->pidfile);
- if (chown(DBDIR, pw->pw_uid, gid) == -1)
- logerr("chown `%s'", DBDIR);
- if (chown(RUNDIR, pw->pw_uid, gid) == -1)
- logerr("chown `%s'", RUNDIR);
+int
+ps_dropprivs(struct dhcpcd_ctx *ctx)
+{
+ struct passwd *pw;
+
+ if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
+ if (errno == 0)
+ logerrx("no such user %s", PRIVSEP_USER);
+ else
+ logerr("getpwnam");
+ return -1;
+ }
+
+ if (!(ctx->options & DHCPCD_FORKED))
+ logdebugx("chrooting to `%s'", pw->pw_dir);
+
+ if (chroot(pw->pw_dir) == -1)
+ logerr("%s: chroot `%s'", __func__, pw->pw_dir);
+ if (chdir("/") == -1)
+ logerr("%s: chdir `/'", __func__);
+
+ if (setgroups(1, &pw->pw_gid) == -1 ||
+ setgid(pw->pw_gid) == -1 ||
+ setuid(pw->pw_uid) == -1)
+ {
+ logerr("failed to drop privileges");
+ return -1;
+ }
- ctx->options |= DHCPCD_PRIVSEP;
return 0;
}
void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *),
unsigned int flags)
{
- struct passwd *pw;
int stype;
int fd[2];
pid_t pid;
- if (flags & PSF_DROPPRIVS) {
- errno = 0;
- if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
- if (errno == 0)
- logerrx("no such user %s", PRIVSEP_USER);
- else
- logerr("getpwnam");
- return -1;
- }
- } else
- pw = NULL;
-
- if (priv_fd == NULL)
- goto dropprivs;
-
stype = SOCK_CLOEXEC | SOCK_NONBLOCK;
if (socketpair(AF_UNIX, SOCK_DGRAM | stype, 0, fd) == -1) {
logerr("socketpair");
freopen(_PATH_DEVNULL, "w", stdout);
freopen(_PATH_DEVNULL, "w", stderr);
- if (pw == NULL)
- return 0;
-
- if (!(flags & PSF_DROPPRIVS)) {
- if (chdir(pw->pw_dir) == -1)
- logerr("%s: chdir `%s'", __func__, pw->pw_dir);
- return 0;
- }
-
- if (chroot(pw->pw_dir) == -1)
- logerr("%s: chroot `%s'", __func__, pw->pw_dir);
- if (chdir("/") == -1)
- logerr("%s: chdir `/'", __func__);
-
-dropprivs:
- if (setgroups(1, &pw->pw_gid) == -1 ||
- setgid(pw->pw_gid) == -1 ||
- setuid(pw->pw_uid) == -1)
- logerr("failed to drop privileges");
+ if (flags & PSF_DROPPRIVS)
+ ps_dropprivs(ctx);
return 0;
/* No point in spawning the generic network listener if we're
* not going to use it. */
if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_IPV6RS)))
- goto dropprivs;
+ goto started;
switch (pid = ps_inet_start(ctx)) {
case -1:
logdebugx("spawned network proxy on PID %d", pid);
}
-dropprivs:
- /* Drop privs now. */
- ps_dostart(ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- PSF_DROPPRIVS);
-
+started:
return 1;
}
{
int r, ret = 0;
- if (ctx->options & DHCPCD_FORKED || ctx->eloop == NULL)
+ if (!(ctx->options & DHCPCD_PRIVSEP) ||
+ ctx->options & DHCPCD_FORKED ||
+ ctx->eloop == NULL)
return 0;
r = ps_inet_stop(ctx);
if (r != 0)
ret = r;
+
+ /* We've been chrooted, so we need to tell the
+ * priviledged actioneer to remove the pidfile. */
+ ps_root_unlink(ctx, ctx->pidfile);
+
r = ps_root_stop(ctx);
if (r != 0)
ret = r;
#define PS_BPF_ARP_ADDR 0x06
#define PS_IOCTL 0x10
-#define PS_SCRIPT 0x11
-#define PS_IOCTLLINK 0x12
-#define PS_IOCTL6 0x13
-#define PS_ROUTE 0x14 /* Also used for NETLINK */
-#define PS_WRITEPATHUINT 0x15
+#define PS_ROUTE 0x11 /* Also used for NETLINK */
+#define PS_SCRIPT 0x12
+#define PS_UNLINK 0x13
+
+/* BSD Commands */
+#define PS_IOCTLLINK 0x14
+#define PS_IOCTL6 0x15
+
+/* Linux commands */
+#define PS_WRITEPATHUINT 0x16
#define PS_DELETE 0x20
#define PS_START 0x40
#endif
int ps_init(struct dhcpcd_ctx *);
+int ps_dropprivs(struct dhcpcd_ctx *);
int ps_start(struct dhcpcd_ctx *);
int ps_stop(struct dhcpcd_ctx *);
pid_t *priv_pid, int *priv_fd,
void (*recv_msg)(void *), void (*recv_unpriv_msg),
void *recv_ctx, int (*callback)(void *), void (*)(int, void *),
- unsigned int flags);
+ unsigned int);
int ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd);
struct ps_process *ps_findprocess(struct dhcpcd_ctx *, struct ps_id *);