Compare commits

...

5 Commits

Author SHA1 Message Date
Alessandro Mauri 6c929ad26d fixed auth tries 3 years ago
Alessandro Mauri c21ca28ae9 remove unused stuff 3 years ago
Alessandro Mauri fe9d88e7f9 env flag 3 years ago
Alessandro Mauri 5412a3785e change env 3 years ago
Alessandro Mauri 72c217d74a reverted to the old exec way 3 years ago
  1. 11
      TODO
  2. 148
      us.c

11
TODO

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

@ -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);
}
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);
}
memset(command, 0, size + 1);
for (optind = popind; optind < argc; optind++) {
strcat(command, argv[optind]);
strcat(command, " ");
c_argv[0] = strdup(shell);
if (!c_argv[0]) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
exit(errno);
}
}
c_argv[c_argc] = NULL;
struct env_elem {
char *name;
char *value;
};
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
}
/* Authenticate */
if (authenticate(uname) != PAM_SUCCESS)
exit(EXIT_FAILURE);
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;
}
}
// TODO: clean up env
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

Loading…
Cancel
Save