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}