working permissions

fixed problem where only euid and egid were set so programs complained, now
us correctly sets e/ruid, e/rgid and groups list to match the wanted user
noproxy
Alessandro Mauri 3 years ago
parent 981fed3499
commit 1c75e7dd3c
  1. 109
      us.c

109
us.c

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include <sys/types.h>
#include <stdio.h>
@ -7,11 +8,13 @@
#include <errno.h>
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include <grp.h>
#include <security/pam_appl.h>
#include <security/pam_misc.h>
static void usage (void);
static int perm_set (uid_t, gid_t);
static int perm_set (const char *, const char *);
// FIXME: misc_conv is a separate library, should stick to plain PAM
static struct pam_conv conv = {misc_conv, NULL};
@ -25,7 +28,7 @@ int main (int argc, char *argv[])
}
uid_t ruid = getuid();
gid_t rgid = getgid();
// gid_t rgid = getgid();
struct passwd *pw = getpwuid(ruid);
if (!pw) {
fprintf(stderr, "getpwid: %s\n", strerror(errno));
@ -77,7 +80,7 @@ int main (int argc, char *argv[])
errno = 0;
/* Set permissions */
if (perm_set(0, 0) == -1) { // 0 = root
if (perm_set(NULL, NULL) == -1) { // 0 = root
fprintf(stderr, "perm_set: %s\n", strerror(errno));
goto fail_end;
}
@ -86,11 +89,13 @@ int main (int argc, char *argv[])
if (execvp(*c_argv, c_argv) == -1) // execvp searches in path
fprintf(stderr, "execv: %s\n", strerror(errno));
/* If exec fails reset the permissions */
if (perm_set(ruid, rgid) == -1) { // 0 = root
/* We may no longer have permission to reset the permissions
// If exec fails reset the permissions
if (perm_set(pw->pw_name, NULL) == -1) { // 0 = root
fprintf(stderr, "perm_set: %s\n", strerror(errno));
goto fail_end;
}
} */
/* Cleanup and return */
fail_end:
@ -115,23 +120,79 @@ static inline void usage (void)
printf("usage: us [command]\n");
}
static int perm_set (uid_t uid, gid_t gid)
static int perm_set (const char *user, const char *group)
{
// FIXME: This doesn't change the uid and gid, it only changes the
// e(ffective)uid and egid keeping the original gid, uid and groups list
// to make it work like sudo, the uid gid and groups list must be all
// set to 0 (or the corresponding value for other users).
// An option could be to add an argument to keep the groups list,
// another to change only the euid/egid.
// For more information run:
// $ sudo id
// and check the output
int err = 0;
// FIXME: using setresuid() and setresgid() is preferred
if ((err = seteuid(uid)) == -1)
return err;
else if ((err = setegid(gid)) == -1)
return err;
// FIXME: to set the group list use initgroups()
return err;
if (!user)
user = "root";
struct passwd *pw;
struct group *gr;
uid_t uid;
gid_t gid;
long uid_l, gid_l;
errno = 0;
if (user[0] != '#') {
pw = getpwnam(user);
} else {
uid_l = strtol(&user[1], NULL, 10);
if (uid_l < 0 || errno) {
errno = errno ? errno : EINVAL;
return -1;
}
pw = getpwuid((uid_t)uid_l);
}
if (!pw) {
if (!errno)
errno = EINVAL;
return -1;
}
uid = pw->pw_uid;
gid = pw->pw_gid;
if (group) {
if (group[0] != '#') {
gr = getgrnam(group);
} else {
gid_l = strtol(&group[1], NULL, 10);
if (gid_l < 0 || errno) {
errno = errno ? errno : EINVAL;
return -1;
}
gr = getgrgid((gid_t)gid_l);
}
if (!gr) {
if (!errno)
errno = EINVAL;
return -1;
}
gid = gr->gr_gid;
}
/* Set permissions, setting group perms first because in the case of
* dropping from higher permissions setting the uid first results in
* an error */
int err;
/* Non POSIX but implemented in most systems anyways */
err = initgroups(pw->pw_name, pw->pw_gid);
if (err == -1) {
printf("initgroups failed\n");
return -1;
}
// FIXME: ideally when failing reset the permissions
if (setregid(gid, gid) == -1) {
printf("setregid failed\n");
return -1;
}
if (setreuid(uid, uid) == -1) {
printf("setreuid failed\n");
return -1;
}
return 0;
}

Loading…
Cancel
Save