summaryrefslogtreecommitdiffstats
path: root/src/privsep.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-01-21 16:17:18 +0000
committerRoy Marples <roy@marples.name>2020-01-21 16:17:18 +0000
commit67a805408331eeaaff5d9b00196d50f93cca42f8 (patch)
tree6f7cc694770aa6830d5accf0f12a1c884eb4b9f2 /src/privsep.c
parent18043c2fba9868086534f99b072a7ef7f53a547f (diff)
downloaddhcpcd-67a805408331eeaaff5d9b00196d50f93cca42f8.tar.xz
privsep: chroot the master process
This means that the privileged actioneer process needs to cleanup sockets and pidfile. It also has some reliance on how dhcpcd is started to create a decent chroot area AND copy the configuration file to it.
Diffstat (limited to 'src/privsep.c')
-rw-r--r--src/privsep.c94
1 files changed, 43 insertions, 51 deletions
diff --git a/src/privsep.c b/src/privsep.c
index 8fe7256a..e9ec25f2 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -72,7 +72,6 @@ int
ps_init(struct dhcpcd_ctx *ctx)
{
struct passwd *pw;
- gid_t gid = (gid_t)-1;
errno = 0;
if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
@@ -86,16 +85,39 @@ ps_init(struct dhcpcd_ctx *ctx)
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;
}
@@ -106,26 +128,10 @@ ps_dostart(struct dhcpcd_ctx *ctx,
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");
@@ -199,25 +205,8 @@ ps_dostart(struct dhcpcd_ctx *ctx,
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;
@@ -294,7 +283,7 @@ ps_start(struct dhcpcd_ctx *ctx)
/* 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:
@@ -307,11 +296,7 @@ ps_start(struct dhcpcd_ctx *ctx)
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;
}
@@ -320,12 +305,19 @@ ps_stop(struct dhcpcd_ctx *ctx)
{
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;