aboutgitcodebugslistschat
path: root/conf.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2022-05-18 19:10:45 +0200
committerStefano Brivio <sbrivio@redhat.com>2022-05-19 16:27:20 +0200
commita951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6 (patch)
tree83c88879af000c010bed7273f7518d4fc4c235b4 /conf.c
parentc318ffcb4c932752cd1f48bf5d1b0268f58895bd (diff)
downloadpasst-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar.gz
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar.bz2
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar.lz
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar.xz
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.tar.zst
passt-a951e0b9efcbb64ca8b1d7c62c6c27a4498d21d6.zip
conf: Add --runas option, changing to given UID and GID if started as root
On some systems, user and group "nobody" might not be available. The new --runas option allows to override the default "nobody" choice if started as root. Now that we allow this, drop the initgroups() call that was used to add any additional groups for the given user, as that might now grant unnecessarily broad permissions. For instance, several distributions have a "kvm" group to allow regular user access to /dev/kvm, and we don't need that in passt or pasta. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'conf.c')
-rw-r--r--conf.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/conf.c b/conf.c
index 0baf4fa..ddad9a3 100644
--- a/conf.c
+++ b/conf.c
@@ -22,6 +22,8 @@
#include <sys/stat.h>
#include <libgen.h>
#include <limits.h>
+#include <grp.h>
+#include <pwd.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
@@ -614,6 +616,9 @@ 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( " default: drop to user \"nobody\"");
info( " -h, --help Display this help message and exit");
if (strstr(name, "pasta")) {
@@ -838,6 +843,57 @@ dns6:
}
/**
+ * conf_runas() - Handle --runas: look up desired UID and GID
+ * @opt: Passed option value
+ * @uid: User ID, set on return if valid
+ * @gid: Group ID, set on return if valid
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int conf_runas(const char *opt, unsigned int *uid, unsigned int *gid)
+{
+ char ubuf[LOGIN_NAME_MAX], gbuf[LOGIN_NAME_MAX], *endptr;
+ struct passwd *pw;
+ struct group *gr;
+
+ /* NOLINTNEXTLINE(cert-err34-c): 2 if conversion succeeds */
+ if (sscanf(opt, "%u:%u", uid, gid) == 2 && uid && gid)
+ return 0;
+
+ *uid = strtol(opt, &endptr, 0);
+ if (!*endptr && (*gid = *uid))
+ return 0;
+
+#ifdef GLIBC_NO_STATIC_NSS
+ (void)ubuf;
+ (void)gbuf;
+ (void)pw;
+
+ return -EINVAL;
+#else
+ /* NOLINTNEXTLINE(cert-err34-c): 2 if conversion succeeds */
+ if (sscanf(opt, "%" STR(LOGIN_NAME_MAX) "[^:]:"
+ "%" STR(LOGIN_NAME_MAX) "s", ubuf, gbuf) == 2) {
+ pw = getpwnam(ubuf);
+ if (!pw || !(*uid = pw->pw_uid))
+ return -ENOENT;
+
+ gr = getgrnam(gbuf);
+ if (!gr || !(*gid = gr->gr_gid))
+ return -ENOENT;
+
+ return 0;
+ }
+
+ pw = getpwnam(ubuf);
+ if (!pw || !(*uid = pw->pw_uid) || !(*gid = pw->pw_gid))
+ return -ENOENT;
+
+ return 0;
+#endif /* !GLIBC_NO_STATIC_NSS */
+}
+
+/**
* conf() - Process command-line arguments and set configuration
* @c: Execution context
* @argc: Argument count
@@ -889,6 +945,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"dns-forward", required_argument, NULL, 9 },
{"no-netns-quit", no_argument, NULL, 10 },
{"trace", no_argument, NULL, 11 },
+ {"runas", required_argument, NULL, 12 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -1032,6 +1089,17 @@ void conf(struct ctx *c, int argc, char **argv)
c->trace = c->debug = c->foreground = 1;
break;
+ case 12:
+ if (c->uid || c->gid) {
+ err("Multiple --runas options given");
+ usage(argv[0]);
+ }
+
+ if (conf_runas(optarg, &c->uid, &c->gid)) {
+ err("Invalid --runas option: %s", optarg);
+ usage(argv[0]);
+ }
+ break;
case 'd':
if (c->debug) {
err("Multiple --debug options given");
@@ -1298,6 +1366,8 @@ void conf(struct ctx *c, int argc, char **argv)
}
} while (name != -1);
+ check_root(c);
+
if (c->mode == MODE_PASTA && optind + 1 == argc) {
ret = conf_ns_opt(c, nsdir, userns, argv[optind]);
if (ret == -ENOENT)