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