From 568bddef260b4020001f5b3c608d079ba7622612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Mon, 16 Jul 2018 13:58:07 +0000 Subject: [PATCH] Handle groups in setruid(1) as well --- setruid.1 | 14 +++++++++----- setruid.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/setruid.1 b/setruid.1 index 9218f39..246d3f2 100644 --- a/setruid.1 +++ b/setruid.1 @@ -1,18 +1,22 @@ -.Dd Jul 11, 2018 +.Dd Jul 16, 2018 .Dt setruid 1 .Os .Sh NAME .Nm setruid -.Nd set the real UID for a command +.Nd set the real UID and GID for a command .Sh SYNOPSIS .Nm +.Ar username Ns Op : Ns Ar group .Ar command .Op Ar arguments .Sh DESCRIPTION .Nm -sets the real UID while keeping the effective UID the same. It is indended for -simple servers that need to bind on a low port and drop privileges by setting -effective UID to real UID. +sets the real UID and GID while keeping the effective UID and GID the same. It +is indended for simple servers that need to bind on a low port and drop +privileges by setting effective UID to real UID. +.Pp +By default the real GID of the process is set to the default group of the given +user, but this can be overridden by passing the group argument. .Pp .Nm executes the given command as the same process. diff --git a/setruid.c b/setruid.c index 96a87d8..5892c0b 100644 --- a/setruid.c +++ b/setruid.c @@ -1,17 +1,34 @@ #define _BSD_SOURCE #include +#include #include +#include +#include #include #include #include int main(int argc, char **argv) { if(argc < 3) { - fprintf(stderr, "Usage: %s username command [arguments]\n", argv[0]); + fprintf(stderr, "Usage: %s username[:group] command [arguments]\n", argv[0]); return 1; } - const char *username = argv[1]; + char *username_group = strdup(argv[1]); + if(username_group == NULL) { + perror("strdup"); + return 1; + } + char *colon_position, *username, *group; + if((colon_position = strchr(username_group, ':')) != NULL) { + *colon_position = 0; + username = username_group; + group = colon_position + 1; + } else { + username = username_group; + group = NULL; + } + errno = 0; struct passwd *passwd_entry = getpwnam(username); if(passwd_entry == NULL) { @@ -21,8 +38,28 @@ int main(int argc, char **argv) { uid_t ruid = passwd_entry->pw_uid; + uid_t rgid; + + if(group != NULL) { + errno = 0; + struct group *group_entry = getgrnam(group); + if(group_entry == NULL) { + perror("getgrnam"); + return 1; + } + rgid = group_entry->gr_gid; + } else { + rgid = passwd_entry->pw_gid; + } + + free(username_group); + if(setreuid(ruid, -1) != 0) { - perror("getpwnam"); + perror("setreuid"); + return 1; + } + if(setregid(rgid, -1) != 0) { + perror("setregid"); return 1; }