diff options
Diffstat (limited to 'toys/lsb')
-rw-r--r-- | toys/lsb/su.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/toys/lsb/su.c b/toys/lsb/su.c new file mode 100644 index 00000000..52d20244 --- /dev/null +++ b/toys/lsb/su.c @@ -0,0 +1,97 @@ +/* su.c - switch user + * + * Copyright 2013 CE Strake <strake888@gmail.com> + * + * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html + * TODO: log su attempts + +USE_SU(NEWTOY(su, "lmpc:s:", TOYFLAG_BIN|TOYFLAG_ROOTONLY)) + +config SU + bool "su" + default y + help + usage: su [-lmp] [-c CMD] [-s SHELL] [USER [ARGS...]] + + Switch to user (or root) and run shell (with optional command line). + + -s shell to use + -c command to pass to shell with -c + -l login shell + -(m|p) preserve environment +*/ + +#define FOR_su +#include "toys.h" + +GLOBALS( + char *s; + char *c; +) + +static char *snapshot_env(char *name) +{ + char *s = getenv(name); + + if (s) return xmsprintf("%s=%s", name, s); + + return 0; +} + +void su_main() +{ + char *name, *passhash = 0, **argu, **argv; + struct passwd *up; + struct spwd *shp; + + if (*toys.optargs && !strcmp("-", *toys.optargs)) { + toys.optflags |= FLAG_l; + toys.optargs++; + } + + if (*toys.optargs) name = *(toys.optargs++); + else name = "root"; + + if (!(shp = getspnam(name))) perror_exit("no '%s'", name); + if (*shp->sp_pwdp != '$') goto deny; + if (read_password(toybuf, sizeof(toybuf), "Password: ")) goto deny; + passhash = crypt(toybuf, shp->sp_pwdp); + memset(toybuf, 0, sizeof(toybuf)); + if (!passhash || strcmp(passhash, shp->sp_pwdp)) goto deny; + + up = xgetpwnam(name); + xsetuid(up->pw_uid); + + argv = argu = xmalloc(sizeof(char *)*(toys.optc + 4)); + *(argv++) = TT.s ? TT.s : up->pw_shell; + + if (toys.optflags & FLAG_l) { + int i; + char *stuff[] = {snapshot_env("TERM"), snapshot_env("DISPLAY"), + snapshot_env("COLORTERM"), snapshot_env("XAUTHORITY")}; + + clearenv(); + for (i=0; i < sizeof(stuff)/sizeof(char *); i++) putenv(stuff[i]); + *(argv++) = "-l"; + xchdir(up->pw_dir); + } else unsetenv("IFS"); + setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); + if (!(toys.optflags & (FLAG_m|FLAG_p))) { + setenv("HOME", up->pw_dir, 1); + setenv("SHELL", up->pw_shell, 1); + setenv("USER", up->pw_name, 1); + setenv("LOGNAME", up->pw_name, 1); + } else unsetenv("IFS"); + + if (toys.optflags & FLAG_c) { + *(argv++) = "-c"; + *(argv++) = TT.c; + } + while ((*(argv++) = *(toys.optargs++))); + xexec(argu); + perror_exit("can't exec %s", *argu); + +deny: + puts("No."); + toys.exitval = 1; +} |