commit: 95e28045eb665da2392be8cc38738ccc66db97d8
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Mon Dec 8 19:07:55 2025 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Mon Dec 8 19:07:55 2025 +0000
URL: https://gitweb.gentoo.org/proj/steve.git/commit/?id=95e28045
Support dropping privileges
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>
steve.cxx | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/steve.cxx b/steve.cxx
index cf0c063..3caf06f 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -27,6 +27,8 @@
#include <variant>
#include <getopt.h>
+#include <grp.h>
+#include <pwd.h>
#include <sys/poll.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -667,6 +669,29 @@ static void steve_handle_recheck(evutil_socket_t, short,
void *userdata) {
steve_wake_waiters(state);
}
+static bool steve_drop_privileges(const char *user) {
+ errno = 0;
+ struct passwd *pw = getpwnam(user);
+
+ if (!pw) {
+ if (errno != 0)
+ perror("getpwnam() failed");
+ else
+ std::print(stderr, "user {} not found\n", user);
+ } else if (chdir("/") == -1)
+ perror("chdir('/') failed");
+ else if (setgroups(0, nullptr) == -1)
+ perror("setgroups() failed");
+ else if (setgid(pw->pw_gid) == -1)
+ perror("setgid() failed");
+ else if (setuid(pw->pw_uid) == -1)
+ perror("setuid() failed");
+ else
+ return true;
+
+ return false;
+}
+
static constexpr char steve_usage[] =
"usage: {} [options]\n"
"\n"
@@ -678,6 +703,8 @@ static constexpr char steve_usage[] =
" do not serve tokens unless load is below
LOAD_AVG\n"
" --min-jobs=MIN_JOBS, -m MIN_JOBS\n"
" min. jobs to serve even if load average is
exceeded\n"
+" --user=USER, -u USER drop superuser privileges and switch to USER\n"
+" (and its primary group)\n"
" --verbose, -v enable verbose logging\n"
" --debug, -d enable FUSE debug output\n";
@@ -687,6 +714,7 @@ static const struct option steve_long_opts[] = {
{ "jobs", required_argument, 0, 'j' },
{ "load-average", required_argument, 0, 'l' },
{ "min-jobs", required_argument, 0, 'm' },
+ { "user", required_argument, 0, 'u' },
{ "verbose", no_argument, 0, 'v' },
{ "debug", no_argument, 0, 'd' },
{},
@@ -700,6 +728,7 @@ int main(int argc, char **argv)
int opt;
bool debug = false;
+ const char *user = nullptr;
while ((opt = getopt_long(argc, argv, steve_short_opts,
steve_long_opts, nullptr)) != -1) {
switch (opt) {
case 'h':
@@ -730,6 +759,9 @@ int main(int argc, char **argv)
return 1;
}
break;
+ case 'u':
+ user = optarg;
+ break;
case 'v':
state.verbose = true;
break;
@@ -779,6 +811,9 @@ int main(int argc, char **argv)
}
fd_guard cuse_fd_guard{cuse_fd};
+ if (user && !steve_drop_privileges(user))
+ return 1;
+
const char *dev_name = "DEVNAME=steve";
const char *dev_info_argv[] = { dev_name };
struct cuse_info ci{};