Handle groups in setruid(1) as well

This commit is contained in:
Juhani Krekelä 2018-07-16 13:58:07 +00:00
parent 4ce7746cb5
commit 568bddef26
2 changed files with 49 additions and 8 deletions

View File

@ -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.

View File

@ -1,17 +1,34 @@
#define _BSD_SOURCE
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
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;
}