aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c5
-rw-r--r--passt.15
-rw-r--r--util.c29
-rw-r--r--util.h1
4 files changed, 33 insertions, 7 deletions
diff --git a/conf.c b/conf.c
index 0fe5266..545f61d 100644
--- a/conf.c
+++ b/conf.c
@@ -747,8 +747,8 @@ static void usage(const char *name)
info( " default: run in background if started from a TTY");
info( " -e, --stderr Log to stderr too");
info( " default: log to system logger only if started from a TTY");
- info( " --runas UID|UID:GID Use given UID, GID if started as root");
- info( " UID and GID can be numeric, or login and group names");
+ info( " --runas UID|UID:GID Run as given UID, GID, which can be");
+ info( " numeric, or login and group names");
info( " default: drop to user \"nobody\"");
info( " -h, --help Display this help message and exit");
@@ -1500,6 +1500,7 @@ void conf(struct ctx *c, int argc, char **argv)
} while (name != -1);
check_root(&uid, &gid);
+ drop_root(uid, gid);
if (c->mode == MODE_PASTA) {
if (*netns && optind != argc) {
diff --git a/passt.1 b/passt.1
index 61f0e4c..88cc879 100644
--- a/passt.1
+++ b/passt.1
@@ -104,9 +104,10 @@ terminal, and to both system logger and standard error otherwise.
.TP
.BR \-\-runas " " \fIUID\fR|\fIUID:GID\fR|\fILOGIN\fR|\fILOGIN:GROUP\fR
-If started as root, change to given UID and corresponding group if UID is given,
+Attempt to change to given UID and corresponding group if UID is given,
or to given UID and given GID if both are given. Alternatively, login name, or
-login name and group name can be passed.
+login name and group name can be passed. This requires privileges (either
+initial effective UID 0 or CAP_SETUID capability) to work.
Default is to change to user \fInobody\fR if started as root.
.TP
diff --git a/util.c b/util.c
index b2ccb3d..eb25c37 100644
--- a/util.c
+++ b/util.c
@@ -492,7 +492,13 @@ void check_root(uid_t *uid, gid_t *gid)
char buf[BUFSIZ];
int fd;
- if (getuid() && geteuid())
+ if (!*uid)
+ *uid = geteuid();
+
+ if (!*gid)
+ *gid = getegid();
+
+ if (*uid)
return;
if ((fd = open("/proc/self/uid_map", O_RDONLY | O_CLOEXEC)) < 0)
@@ -524,11 +530,28 @@ void check_root(uid_t *uid, gid_t *gid)
*uid = *gid = 65534;
#endif
}
+}
+
+/**
+ * drop_root() - Switch to given UID and GID
+ * @uid: User ID to switch to
+ * @gid: Group ID to switch to
+ */
+void drop_root(uid_t uid, gid_t gid)
+{
+ if (setgroups(0, NULL)) {
+ /* If we don't start with CAP_SETGID, this will EPERM */
+ if (errno != EPERM) {
+ err("Can't drop supplementary groups: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
- if (!setgroups(0, NULL) && !setgid(*gid) && !setuid(*uid))
+ if (!setgid(gid) && !setuid(uid))
return;
- fprintf(stderr, "Can't change user/group, exiting");
+ err("Can't change user/group, exiting");
exit(EXIT_FAILURE);
}
diff --git a/util.h b/util.h
index 58312fb..e2f686b 100644
--- a/util.h
+++ b/util.h
@@ -235,6 +235,7 @@ void procfs_scan_listen(struct ctx *c, uint8_t proto, int ip_version, int ns,
uint8_t *map, uint8_t *exclude);
void drop_caps(void);
void check_root(uid_t *uid, gid_t *gid);
+void drop_root(uid_t uid, gid_t gid);
int ns_enter(const struct ctx *c);
void write_pidfile(int fd, pid_t pid);
int __daemon(int pidfile_fd, int devnull_fd);