10f66f451Sopenharmony_ci/* su.c - switch user
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2013 CE Strake <strake888@gmail.com>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html
60f66f451Sopenharmony_ci * TODO: log su attempts
70f66f451Sopenharmony_ci * TODO: suid support
80f66f451Sopenharmony_ci * Supports undocumented compatibility options: -m synonym for -p, - for -l
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciUSE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
110f66f451Sopenharmony_ci
120f66f451Sopenharmony_ciconfig SU
130f66f451Sopenharmony_ci  bool "su"
140f66f451Sopenharmony_ci  default y
150f66f451Sopenharmony_ci  depends on TOYBOX_SHADOW
160f66f451Sopenharmony_ci  help
170f66f451Sopenharmony_ci    usage: su [-lp] [-u UID] [-g GID,...] [-s SHELL] [-c CMD] [USER [COMMAND...]]
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ci    Switch user, prompting for password of new user when not run as root.
200f66f451Sopenharmony_ci
210f66f451Sopenharmony_ci    With one argument, switch to USER and run user's shell from /etc/passwd.
220f66f451Sopenharmony_ci    With no arguments, USER is root. If COMMAND line provided after USER,
230f66f451Sopenharmony_ci    exec() it as new USER (bypassing shell). If -u or -g specified, first
240f66f451Sopenharmony_ci    argument (if any) isn't USER (it's COMMAND).
250f66f451Sopenharmony_ci
260f66f451Sopenharmony_ci    first argument is USER name to switch to (which must exist).
270f66f451Sopenharmony_ci    Non-root users are prompted for new user's password.
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci    -s	Shell to use (default is user's shell from /etc/passwd)
300f66f451Sopenharmony_ci    -c	Command line to pass to -s shell (ala sh -c "CMD")
310f66f451Sopenharmony_ci    -l	Reset environment as if new login.
320f66f451Sopenharmony_ci    -u	Switch to UID instead of USER
330f66f451Sopenharmony_ci    -g	Switch to GID (only root allowed, can be comma separated list)
340f66f451Sopenharmony_ci    -p	Preserve environment (except for $PATH and $IFS)
350f66f451Sopenharmony_ci*/
360f66f451Sopenharmony_ci
370f66f451Sopenharmony_ci#define FOR_su
380f66f451Sopenharmony_ci#include "toys.h"
390f66f451Sopenharmony_ci
400f66f451Sopenharmony_ciGLOBALS(
410f66f451Sopenharmony_ci  char *s;
420f66f451Sopenharmony_ci  char *c;
430f66f451Sopenharmony_ci)
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_civoid su_main()
460f66f451Sopenharmony_ci{
470f66f451Sopenharmony_ci  char *name, *passhash = 0, **argu, **argv;
480f66f451Sopenharmony_ci  struct passwd *up;
490f66f451Sopenharmony_ci  struct spwd *shp;
500f66f451Sopenharmony_ci
510f66f451Sopenharmony_ci  if (*toys.optargs && !strcmp("-", *toys.optargs)) {
520f66f451Sopenharmony_ci    toys.optflags |= FLAG_l;
530f66f451Sopenharmony_ci    toys.optargs++;
540f66f451Sopenharmony_ci  }
550f66f451Sopenharmony_ci
560f66f451Sopenharmony_ci  if (*toys.optargs) name = *(toys.optargs++);
570f66f451Sopenharmony_ci  else name = "root";
580f66f451Sopenharmony_ci
590f66f451Sopenharmony_ci  loggit(LOG_NOTICE, "%s->%s", getusername(geteuid()), name);
600f66f451Sopenharmony_ci
610f66f451Sopenharmony_ci  shp = getspnam(name);
620f66f451Sopenharmony_ci  if (getuid() && shp) {
630f66f451Sopenharmony_ci    if (*shp->sp_pwdp != '$') goto deny;
640f66f451Sopenharmony_ci    if (read_password(toybuf, sizeof(toybuf), "Password: ")) goto deny;
650f66f451Sopenharmony_ci    passhash = crypt(toybuf, shp->sp_pwdp);
660f66f451Sopenharmony_ci    memset(toybuf, 0, sizeof(toybuf));
670f66f451Sopenharmony_ci    if (!passhash || strcmp(passhash, shp->sp_pwdp)) goto deny;
680f66f451Sopenharmony_ci  }
690f66f451Sopenharmony_ci  closelog();
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_ci  xsetuser(up = xgetpwnam(name));
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_ci  if (FLAG(m)||FLAG(p)) {
740f66f451Sopenharmony_ci    unsetenv("IFS");
750f66f451Sopenharmony_ci    setenv("PATH", _PATH_DEFPATH, 1);
760f66f451Sopenharmony_ci  } else reset_env(up, FLAG(l));
770f66f451Sopenharmony_ci
780f66f451Sopenharmony_ci  argv = argu = xmalloc(sizeof(char *)*(toys.optc + 4));
790f66f451Sopenharmony_ci  *(argv++) = TT.s ? TT.s : up->pw_shell;
800f66f451Sopenharmony_ci  loggit(LOG_NOTICE, "run %s", *argu);
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci  if (FLAG(l)) *(argv++) = "-l";
830f66f451Sopenharmony_ci  if (FLAG(c)) {
840f66f451Sopenharmony_ci    *(argv++) = "-c";
850f66f451Sopenharmony_ci    *(argv++) = TT.c;
860f66f451Sopenharmony_ci  }
870f66f451Sopenharmony_ci  while ((*(argv++) = *(toys.optargs++)));
880f66f451Sopenharmony_ci  xexec(argu);
890f66f451Sopenharmony_ci
900f66f451Sopenharmony_cideny:
910f66f451Sopenharmony_ci  syslog(LOG_NOTICE, "No.");
920f66f451Sopenharmony_ci  puts("No.");
930f66f451Sopenharmony_ci  toys.exitval = 1;
940f66f451Sopenharmony_ci}
95