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