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