Compare commits

...

5 Commits

Author SHA1 Message Date
6c929ad26d fixed auth tries
open and close the pam context between each authentication attempt to prevent
errors with consecutive authentications, this is a hack but I don't know a
better way.
2021-04-15 14:56:28 +02:00
c21ca28ae9 remove unused stuff
removed commented execvpe() implem.
removed some FIXME and TODO comments
checked error value in one case
moved up auth() a couple of lines
2021-04-15 14:43:41 +02:00
fe9d88e7f9 env flag
implemented -e flag:
it copies the elements of env that we want to keep, clears the environment and
sets it to only the saved and default elements.

also removed the code for copying the environment and allocating a new one
2021-04-04 19:34:10 +02:00
5412a3785e change env
us now changes the environment variables listed in TODO before executing the
command, also added but commented out a version where the env gets copied and
the execution happens trough the musl implementation of execvpe(3)
2021-04-04 12:42:03 +02:00
72c217d74a reverted to the old exec way
this branch will contain a version of us which doesn't use a subshell as
a proxy but directly applies the privilege escalation to the command
2021-04-03 18:03:13 +02:00
2 changed files with 119 additions and 40 deletions

11
TODO
View File

@ -4,4 +4,13 @@
* SHELL -> to the target user's SHELL
* HOME -> to the target user's HOME
- Reconsider executing programs in a subshell
- fork before exec, that is because processes might try to kill us or the
command but since they may run under elevated privileges they will get
permission denied error. If we remain the parent processes, unprivileged
proceses can send signals to us and we will relay them to our children
running at the same privilege as us. This is useful when:
- The child command hangs and we want to cose it, kinda
problematic but we could run kill with us as well
- The parent shell dies and children need to be killed, then
since one of their children (us) has higher privileges
they can't kill us and we would end up as zombies

148
us.c
View File

@ -36,21 +36,22 @@ static int perm_set (struct passwd *, struct group *);
static int authenticate (const char *);
static struct passwd* user_to_passwd (const char *);
static struct group* group_to_grp (const char *);
//static int execvpe(const char *, char *const *, char *const *);
// FIXME: misc_conv is a separate library, should stick to plain PAM or make
// our own pam module
static struct pam_conv conv = {misc_conv, NULL};
extern char **environ;
int main (int argc, char *argv[])
{
// TODO: Add arguments
// FIXME: change the default program to execute SHELL
char *t_usr = "root", *t_grp = NULL;
struct passwd *t_pw;
struct group *t_gr;
int opt;
int shellflag = 0;
while ((opt = getopt(argc, argv, "A:u:g:C:s")) != -1) {
int opt, err;
int shellflag = 0, envflag = 0;
while ((opt = getopt(argc, argv, "A:u:g:C:se")) != -1) {
switch (opt) {
case 'A':
printf("-A is not yet implemented\n");
@ -69,6 +70,9 @@ int main (int argc, char *argv[])
case 's':
shellflag = 1;
break;
case 'e':
envflag = 1;
break;
case '?':
usage();
exit(EINVAL);
@ -87,6 +91,12 @@ int main (int argc, char *argv[])
}
uname = my_pw->pw_name;
/* Authenticate */
if (authenticate(uname) != PAM_SUCCESS)
exit(EXIT_FAILURE);
/* Get target user and group info */
t_pw = user_to_passwd(t_usr);
if (!t_pw) {
fprintf(stderr, "user_to_passwd: %s\n", strerror(errno));
@ -103,28 +113,86 @@ int main (int argc, char *argv[])
shell = "/bin/sh";
/* Set argc and argv */
char *command = NULL;
int size, popind = optind;
if (argc - optind) {
for (size = 0; optind < argc; optind++)
size += strlen(argv[optind]) + 1;
command = malloc(sizeof(char) * size + 1);
if (!command) {
int c_argc = argc - optind;
char **c_argv;
if (c_argc) {
c_argv = malloc(sizeof(char *) * (c_argc + 1));
if (!c_argv) {
fprintf(stderr, "malloc: %s\n", strerror(errno));
exit(errno);
}
memset(command, 0, size + 1);
for (optind = popind; optind < argc; optind++) {
strcat(command, argv[optind]);
strcat(command, " ");
for (int i = 0; optind < argc; optind++, i++) {
c_argv[i] = strdup(argv[optind]);
if (!c_argv[i]) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
exit(errno);
}
}
} else {
c_argc = 1;
c_argv = malloc(sizeof(char *) * (c_argc + 1));
if (!c_argv) {
fprintf(stderr, "malloc: %s\n", strerror(errno));
exit(errno);
}
c_argv[0] = strdup(shell);
if (!c_argv[0]) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
exit(errno);
}
}
c_argv[c_argc] = NULL;
/* Authenticate */
if (authenticate(uname) != PAM_SUCCESS)
exit(EXIT_FAILURE);
struct env_elem {
char *name;
char *value;
};
// TODO: clean up env
struct env_elem env_keep[] = {
{"PATH", NULL},
{"TERM", NULL},
{"EDITOR", NULL},
{"VISUAL", NULL},
{"DISPLAY", NULL},
{"XAUTHORITY", NULL},
{NULL, NULL}
};
struct env_elem env_mod[] = {
{"USER", t_pw->pw_name},
{"LOGNAME", t_pw->pw_name},
{"SHELL", t_pw->pw_shell},
{"HOME", t_pw->pw_dir},
{NULL, NULL}
};
if (envflag) { /* clear env */
for (int i = 0; env_keep[i].name; i++)
env_keep[i].value = strdup(getenv(env_keep[i].name));
environ = NULL; // in place of clearenv
}
for (int i = 0; env_mod[i].name; i++) {
err = setenv(env_mod[i].name, env_mod[i].value, 1);
if (err == -1) {
fprintf(stderr, "setenv: %s\n", strerror(errno));
goto fail_end;
}
}
if (envflag) {
for (int i = 0; env_keep[i].name; i++) {
if (env_keep[i].value) {
err = setenv(env_keep[i].name, env_keep[i].value, 1);
if (err == -1) {
fprintf(stderr, "setenv: %s\n", strerror(errno));
goto fail_end;
}
}
}
}
// do not override, we might be under more levels of 'us'
err = setenv("US_USER", my_pw->pw_name, 0);
errno = 0;
/* Set permissions */
@ -134,18 +202,16 @@ int main (int argc, char *argv[])
}
/* Execute the command */
int err;
if (command)
err = execl(shell, shell, "-c", command, (char *)NULL);
else
err = execl(shell, shell, (char *)NULL);
err = execvp(c_argv[0], c_argv);
if (err == -1)
fprintf(stderr, "execl: %s\n", strerror(errno));
/* Cleanup and return */
fail_end:
/* Free up the copied argv */
free(command);
for (int i=0; c_argv[i]; i++)
free(c_argv[i]);
free(c_argv);
return errno;
}
@ -159,7 +225,7 @@ static inline void usage (void)
// -c [file]: manually select config file
// something about environment
// something about non interactiveness
printf("usage: us [-s] [-u user] [-g group] command [args]\n");
printf("usage: us [-se] [-u user] [-g group] command [args]\n");
}
static int perm_set (struct passwd *pw, struct group *gr)
@ -189,7 +255,6 @@ static int perm_set (struct passwd *pw, struct group *gr)
return -1;
}
// FIXME: ideally when failing reset the permissions
if (setregid(gid, gid) == -1) {
printf("setregid failed\n");
return -1;
@ -207,24 +272,29 @@ static int authenticate (const char *uname)
{
pam_handle_t *pamh;
int pam_err, count = 0;
pam_err = pam_start("User Switcher", uname, &conv, &pamh);
if (pam_err != PAM_SUCCESS) {
fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, pam_err));
return pam_err;
}
do {
pam_err = pam_start("User Switcher", uname, &conv, &pamh);
if (pam_err != PAM_SUCCESS) {
fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, pam_err));
return pam_err;
}
pam_err = pam_authenticate(pamh, 0);
if (pam_err != PAM_SUCCESS)
if (pam_err == PAM_SUCCESS) {
pam_err = pam_acct_mgmt(pamh, 0);
}
if (pam_err != PAM_SUCCESS) {
printf("Auth failed: %s\n", pam_strerror(pamh, pam_err));
// FIXME: count gets ignored because authentication service has
// a set amount of retries giving an error:
// Have exhausted maximum number of retries for service
pam_end(pamh, pam_err);
}
count++;
} while (pam_err != PAM_SUCCESS && count < 4);
} while (pam_err != PAM_SUCCESS && count < 3);
if (pam_err != PAM_SUCCESS) {
fprintf(stderr, "better luck next time\n");
pam_end(pamh, pam_err);
return pam_err;
}
// FIXME: check again for the validity of the login for more security