su.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* su.c - switch user
  2. *
  3. * Copyright 2013 CE Strake <strake888@gmail.com>
  4. *
  5. * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html
  6. * TODO: log su attempts
  7. * TODO: suid support
  8. * Supports undocumented compatibility options: -m synonym for -p, - for -l
  9. USE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
  10. config SU
  11. bool "su"
  12. default y
  13. depends on TOYBOX_SHADOW
  14. help
  15. usage: su [-lp] [-u UID] [-g GID,...] [-s SHELL] [-c CMD] [USER [COMMAND...]]
  16. Switch user, prompting for password of new user when not run as root.
  17. With one argument, switch to USER and run user's shell from /etc/passwd.
  18. With no arguments, USER is root. If COMMAND line provided after USER,
  19. exec() it as new USER (bypassing shell). If -u or -g specified, first
  20. argument (if any) isn't USER (it's COMMAND).
  21. first argument is USER name to switch to (which must exist).
  22. Non-root users are prompted for new user's password.
  23. -s Shell to use (default is user's shell from /etc/passwd)
  24. -c Command line to pass to -s shell (ala sh -c "CMD")
  25. -l Reset environment as if new login.
  26. -u Switch to UID instead of USER
  27. -g Switch to GID (only root allowed, can be comma separated list)
  28. -p Preserve environment (except for $PATH and $IFS)
  29. */
  30. #define FOR_su
  31. #include "toys.h"
  32. GLOBALS(
  33. char *s;
  34. char *c;
  35. )
  36. void su_main()
  37. {
  38. char *name, *passhash = 0, **argu, **argv;
  39. struct passwd *up;
  40. struct spwd *shp;
  41. if (*toys.optargs && !strcmp("-", *toys.optargs)) {
  42. toys.optflags |= FLAG_l;
  43. toys.optargs++;
  44. }
  45. if (*toys.optargs) name = *(toys.optargs++);
  46. else name = "root";
  47. loggit(LOG_NOTICE, "%s->%s", getusername(geteuid()), name);
  48. if (!(shp = getspnam(name))) perror_exit("no '%s'", name);
  49. if (getuid()) {
  50. if (*shp->sp_pwdp != '$') goto deny;
  51. if (read_password(toybuf, sizeof(toybuf), "Password: ")) goto deny;
  52. passhash = crypt(toybuf, shp->sp_pwdp);
  53. memset(toybuf, 0, sizeof(toybuf));
  54. if (!passhash || strcmp(passhash, shp->sp_pwdp)) goto deny;
  55. }
  56. closelog();
  57. xsetuser(up = xgetpwnam(name));
  58. if (FLAG(m)||FLAG(p)) {
  59. unsetenv("IFS");
  60. setenv("PATH", _PATH_DEFPATH, 1);
  61. } else reset_env(up, FLAG(l));
  62. argv = argu = xmalloc(sizeof(char *)*(toys.optc + 4));
  63. *(argv++) = TT.s ? TT.s : up->pw_shell;
  64. loggit(LOG_NOTICE, "run %s", *argu);
  65. if (FLAG(l)) *(argv++) = "-l";
  66. if (FLAG(c)) {
  67. *(argv++) = "-c";
  68. *(argv++) = TT.c;
  69. }
  70. while ((*(argv++) = *(toys.optargs++)));
  71. xexec(argu);
  72. deny:
  73. syslog(LOG_NOTICE, "No.");
  74. puts("No.");
  75. toys.exitval = 1;
  76. }