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
This commit is contained in:
parent
981fed3499
commit
1c75e7dd3c
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…
Reference in New Issue
Block a user