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 4 years ago
parent 981fed3499
commit 1c75e7dd3c
  1. 109
      us.c

109
us.c

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
@ -7,11 +8,13 @@
#include <errno.h> #include <errno.h>
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include <grp.h>
#include <security/pam_appl.h> #include <security/pam_appl.h>
#include <security/pam_misc.h> #include <security/pam_misc.h>
static void usage (void); 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 // FIXME: misc_conv is a separate library, should stick to plain PAM
static struct pam_conv conv = {misc_conv, NULL}; static struct pam_conv conv = {misc_conv, NULL};
@ -25,7 +28,7 @@ int main (int argc, char *argv[])
} }
uid_t ruid = getuid(); uid_t ruid = getuid();
gid_t rgid = getgid(); // gid_t rgid = getgid();
struct passwd *pw = getpwuid(ruid); struct passwd *pw = getpwuid(ruid);
if (!pw) { if (!pw) {
fprintf(stderr, "getpwid: %s\n", strerror(errno)); fprintf(stderr, "getpwid: %s\n", strerror(errno));
@ -77,7 +80,7 @@ int main (int argc, char *argv[])
errno = 0; errno = 0;
/* Set permissions */ /* 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)); fprintf(stderr, "perm_set: %s\n", strerror(errno));
goto fail_end; goto fail_end;
} }
@ -86,11 +89,13 @@ int main (int argc, char *argv[])
if (execvp(*c_argv, c_argv) == -1) // execvp searches in path if (execvp(*c_argv, c_argv) == -1) // execvp searches in path
fprintf(stderr, "execv: %s\n", strerror(errno)); 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)); fprintf(stderr, "perm_set: %s\n", strerror(errno));
goto fail_end; goto fail_end;
} } */
/* Cleanup and return */ /* Cleanup and return */
fail_end: fail_end:
@ -115,23 +120,79 @@ static inline void usage (void)
printf("usage: us [command]\n"); 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 if (!user)
// e(ffective)uid and egid keeping the original gid, uid and groups list user = "root";
// 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). struct passwd *pw;
// An option could be to add an argument to keep the groups list, struct group *gr;
// another to change only the euid/egid. uid_t uid;
// For more information run: gid_t gid;
// $ sudo id long uid_l, gid_l;
// and check the output
int err = 0; errno = 0;
// FIXME: using setresuid() and setresgid() is preferred if (user[0] != '#') {
if ((err = seteuid(uid)) == -1) pw = getpwnam(user);
return err; } else {
else if ((err = setegid(gid)) == -1) uid_l = strtol(&user[1], NULL, 10);
return err; if (uid_l < 0 || errno) {
// FIXME: to set the group list use initgroups() errno = errno ? errno : EINVAL;
return err; 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