master xplshn/aruu / cmd / xsi / su.c
  1/* See LICENSE file for copyright and license details. */
  2#include "config.h"
  3#include "passwd.h"
  4#include "util.h"
  5
  6#include <errno.h>
  7#include <grp.h>
  8#include <pwd.h>
  9#include <stdio.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <sys/types.h>
 13#include <unistd.h>
 14
 15extern char **environ;
 16
 17#ifndef ENV_PATH_SHELL
 18#define ENV_PATH_SHELL "/bin/sh"
 19#endif
 20
 21static int lflag = 0;
 22static int pflag = 0;
 23
 24static void
 25usage(void)
 26{
 27  eprintf("usage: %s [-lp] [username]\n", argv0);
 28}
 29
 30// ?man su: run a command with substitute user and group id
 31// ?man arguments: [username]
 32// ?man run a shell or command as the named user. defaults to root
 33int
 34main(int argc, char *argv[])
 35{
 36  char          *usr, *pass;
 37  char          *shell, *envshell, *term;
 38  struct passwd *pw;
 39  char          *newargv[3];
 40  uid_t          uid;
 41
 42  ARGBEGIN
 43  {
 44    case 'l':
 45      // ?man -l: make the shell a login shell
 46      lflag = 1;
 47      break;
 48    case 'p':
 49      // ?man -p: preserve the current environment
 50      pflag = 1;
 51      break;
 52    default:
 53      usage();
 54  }
 55  ARGEND
 56
 57  if (argc > 1)
 58    usage();
 59  usr = argc > 0 ? argv[0] : "root";
 60
 61  errno = 0;
 62  pw    = getpwnam(usr);
 63  if (!pw) {
 64    if (errno)
 65      eprintf("getpwnam: %s:", usr);
 66    else
 67      eprintf("who are you?\n");
 68  }
 69
 70  uid = getuid();
 71  if (uid) {
 72    pass = getpass("Password: ");
 73    if (!pass)
 74      eprintf("getpass:");
 75    if (pw_check(pw, pass) <= 0)
 76      exit(1);
 77    explicit_bzero(pass, strlen(pass));
 78  }
 79
 80  if (initgroups(usr, pw->pw_gid) < 0)
 81    eprintf("initgroups:");
 82  if (setgid(pw->pw_gid) < 0)
 83    eprintf("setgid:");
 84  if (setuid(pw->pw_uid) < 0)
 85    eprintf("setuid:");
 86
 87  shell = pw->pw_shell[0] == '\0' ? ENV_PATH_SHELL : pw->pw_shell;
 88  if (lflag) {
 89    term = getenv("TERM");
 90    clearenv();
 91    setenv("HOME", pw->pw_dir, 1);
 92    setenv("SHELL", shell, 1);
 93    setenv("USER", pw->pw_name, 1);
 94    setenv("LOGNAME", pw->pw_name, 1);
 95    setenv("TERM", term ? term : "dumb", 1);
 96    setenv("PATH", ENV_PATH, 1);
 97    if (chdir(pw->pw_dir) < 0)
 98      eprintf("chdir %s:", pw->pw_dir);
 99    newargv[0] = shell;
100    newargv[1] = "-l";
101    newargv[2] = NULL;
102  } else {
103    if (pflag) {
104      envshell = getenv("SHELL");
105      if (envshell && envshell[0] != '\0')
106        shell = envshell;
107    } else {
108      setenv("HOME", pw->pw_dir, 1);
109      setenv("SHELL", shell, 1);
110      if (strcmp(pw->pw_name, "root") != 0) {
111        setenv("USER", pw->pw_name, 1);
112        setenv("LOGNAME", pw->pw_name, 1);
113      }
114    }
115    newargv[0] = shell;
116    newargv[1] = NULL;
117  }
118  execve(shell, newargv, environ);
119  weprintf("execve %s:", shell);
120  return (errno == ENOENT) ? 127 : 126;
121}