1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)su.c 5.10 (Berkeley) 10/18/88"; 26 #endif /* not lint */ 27 28 #include <sys/param.h> 29 #include <sys/time.h> 30 #include <sys/resource.h> 31 #include <syslog.h> 32 #include <stdio.h> 33 #include <pwd.h> 34 #include <grp.h> 35 36 main(argc, argv) 37 int argc; 38 char **argv; 39 { 40 extern char **environ; 41 extern int errno, optind; 42 register struct passwd *pwd; 43 register char *p, **g; 44 struct group *gr; 45 uid_t ruid, getuid(); 46 int asme, ch, fulllogin, fastlogin, prio; 47 enum { UNSET, YES, NO } iscsh = UNSET; 48 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 49 char namebuf[50], shellbuf[MAXPATHLEN]; 50 char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy(); 51 52 np = &nargv[3]; 53 *np-- = NULL; 54 asme = fulllogin = fastlogin = 0; 55 while ((ch = getopt(argc, argv, "-flm")) != EOF) 56 switch((char)ch) { 57 case 'f': 58 fastlogin = 1; 59 break; 60 case '-': 61 case 'l': 62 fulllogin = 1; 63 break; 64 case 'm': 65 asme = 1; 66 break; 67 case '?': 68 default: 69 fprintf(stderr, "usage: su [-flm] [login]\n"); 70 exit(1); 71 } 72 argv += optind; 73 74 errno = 0; 75 prio = getpriority(PRIO_PROCESS, 0); 76 if (errno) 77 prio = 0; 78 (void)setpriority(PRIO_PROCESS, 0, -2); 79 80 /* get current login name and shell */ 81 if ((pwd = getpwuid(ruid = getuid())) == NULL) { 82 fprintf(stderr, "su: who are you?\n"); 83 exit(1); 84 } 85 username = strcpy(namebuf, pwd->pw_name); 86 if (asme) 87 if (pwd->pw_shell && *pwd->pw_shell) 88 shell = strcpy(shellbuf, pwd->pw_shell); 89 else { 90 shell = "/bin/sh"; 91 iscsh = NO; 92 } 93 94 /* get target login information */ 95 user = *argv ? *argv : "root"; 96 if ((pwd = getpwnam(user)) == NULL) { 97 fprintf(stderr, "su: unknown login %s\n", user); 98 exit(1); 99 } 100 101 /* only allow those in group zero to su to root. */ 102 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) 103 for (g = gr->gr_mem;; ++g) { 104 if (!*g) { 105 fprintf(stderr, "su: you are not in the correct group to su %s.\n", user); 106 exit(1); 107 } 108 if (!strcmp(username, *g)) 109 break; 110 } 111 112 /* if target requires a password, verify it */ 113 if (ruid && *pwd->pw_passwd) { 114 p = getpass("Password:"); 115 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 116 fprintf(stderr, "Sorry\n"); 117 if (pwd->pw_uid == 0) 118 syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2)); 119 exit(1); 120 } 121 } 122 123 /* if not asme or target's shell isn't standard, use it */ 124 if (!asme || !chshell(pwd->pw_shell)) 125 if (pwd->pw_shell && *pwd->pw_shell) { 126 shell = pwd->pw_shell; 127 iscsh = UNSET; 128 } else { 129 shell = "/bin/sh"; 130 iscsh = NO; 131 } 132 133 /* if we're forking a csh, we want to slightly muck the args */ 134 if (iscsh == UNSET) { 135 if (p = rindex(shell, '/')) 136 ++p; 137 else 138 p = shell; 139 iscsh = strcmp(p, "csh") ? NO : YES; 140 } 141 142 /* set permissions */ 143 if (setgid(pwd->pw_gid) < 0) { 144 perror("su: setgid"); 145 exit(1); 146 } 147 if (initgroups(user, pwd->pw_gid)) { 148 fprintf(stderr, "su: initgroups failed\n"); 149 exit(1); 150 } 151 if (setuid(pwd->pw_uid) < 0) { 152 perror("su: setuid"); 153 exit(1); 154 } 155 156 if (!asme) { 157 if (fulllogin) { 158 p = getenv("TERM"); 159 cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin"; 160 cleanenv[1] = NULL; 161 environ = cleanenv; 162 (void)setenv("TERM", p, 1); 163 if (chdir(pwd->pw_dir) < 0) { 164 fprintf(stderr, "su: no directory\n"); 165 exit(1); 166 } 167 } 168 if (fulllogin || pwd->pw_uid) 169 (void)setenv("USER", pwd->pw_name, 1); 170 (void)setenv("HOME", pwd->pw_dir, 1); 171 (void)setenv("SHELL", shell, 1); 172 } 173 174 if (iscsh == YES) { 175 if (fastlogin) 176 *np-- = "-f"; 177 if (asme) 178 *np-- = "-m"; 179 } 180 181 /* csh strips the first character... */ 182 *np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su"; 183 184 if (pwd->pw_uid == 0) 185 syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s", 186 username, ttyname(2)); 187 188 (void)setpriority(PRIO_PROCESS, 0, prio); 189 190 execv(shell, np); 191 fprintf(stderr, "su: no shell.\n"); 192 exit(1); 193 } 194 195 chshell(sh) 196 char *sh; 197 { 198 char *cp, *getusershell(); 199 200 while ((cp = getusershell()) != NULL) 201 if (!strcmp(cp, sh)) 202 return(1); 203 return(0); 204 } 205