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.12 (Berkeley) 03/05/89"; 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 #include "pathnames.h" 36 37 main(argc, argv) 38 int argc; 39 char **argv; 40 { 41 extern char **environ; 42 extern int errno, optind; 43 register struct passwd *pwd; 44 register char *p, **g; 45 struct group *gr; 46 uid_t ruid, getuid(); 47 int asme, ch, fulllogin, fastlogin, prio; 48 enum { UNSET, YES, NO } iscsh = UNSET; 49 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 50 char namebuf[50], shellbuf[MAXPATHLEN]; 51 char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy(); 52 53 np = &nargv[3]; 54 *np-- = NULL; 55 asme = fulllogin = fastlogin = 0; 56 while ((ch = getopt(argc, argv, "-flm")) != EOF) 57 switch((char)ch) { 58 case 'f': 59 fastlogin = 1; 60 break; 61 case '-': 62 case 'l': 63 fulllogin = 1; 64 break; 65 case 'm': 66 asme = 1; 67 break; 68 case '?': 69 default: 70 fprintf(stderr, "usage: su [-flm] [login]\n"); 71 exit(1); 72 } 73 argv += optind; 74 75 errno = 0; 76 prio = getpriority(PRIO_PROCESS, 0); 77 if (errno) 78 prio = 0; 79 (void)setpriority(PRIO_PROCESS, 0, -2); 80 81 /* get current login name and shell */ 82 if ((pwd = getpwuid(ruid = getuid())) == NULL) { 83 fprintf(stderr, "su: who are you?\n"); 84 exit(1); 85 } 86 username = strcpy(namebuf, pwd->pw_name); 87 if (asme) 88 if (pwd->pw_shell && *pwd->pw_shell) 89 shell = strcpy(shellbuf, pwd->pw_shell); 90 else { 91 shell = _PATH_BSHELL; 92 iscsh = NO; 93 } 94 95 /* get target login information */ 96 user = *argv ? *argv : "root"; 97 if ((pwd = getpwnam(user)) == NULL) { 98 fprintf(stderr, "su: unknown login %s\n", user); 99 exit(1); 100 } 101 102 /* only allow those in group zero to su to root. */ 103 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) 104 for (g = gr->gr_mem;; ++g) { 105 if (!*g) { 106 fprintf(stderr, "su: you are not in the correct group to su %s.\n", user); 107 exit(1); 108 } 109 if (!strcmp(username, *g)) 110 break; 111 } 112 113 /* if target requires a password, verify it */ 114 if (ruid && *pwd->pw_passwd) { 115 p = getpass("Password:"); 116 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 117 fprintf(stderr, "Sorry\n"); 118 if (pwd->pw_uid == 0) 119 syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2)); 120 exit(1); 121 } 122 } 123 124 if (asme) { 125 /* if asme and non-standard target shell, must be root */ 126 if (!chshell(pwd->pw_shell) && ruid) { 127 fprintf(stderr, "su: Permission denied.\n"); 128 exit(1); 129 } 130 } 131 else if (pwd->pw_shell && *pwd->pw_shell) { 132 shell = pwd->pw_shell; 133 iscsh = UNSET; 134 } else { 135 shell = _PATH_BSHELL; 136 iscsh = NO; 137 } 138 139 /* if we're forking a csh, we want to slightly muck the args */ 140 if (iscsh == UNSET) { 141 if (p = rindex(shell, '/')) 142 ++p; 143 else 144 p = shell; 145 iscsh = strcmp(p, "csh") ? NO : YES; 146 } 147 148 /* set permissions */ 149 if (setgid(pwd->pw_gid) < 0) { 150 perror("su: setgid"); 151 exit(1); 152 } 153 if (initgroups(user, pwd->pw_gid)) { 154 fprintf(stderr, "su: initgroups failed\n"); 155 exit(1); 156 } 157 if (setuid(pwd->pw_uid) < 0) { 158 perror("su: setuid"); 159 exit(1); 160 } 161 162 if (!asme) { 163 if (fulllogin) { 164 p = getenv("TERM"); 165 cleanenv[0] = _PATH_SEARCHPATH; 166 cleanenv[1] = NULL; 167 environ = cleanenv; 168 (void)setenv("TERM", p, 1); 169 if (chdir(pwd->pw_dir) < 0) { 170 fprintf(stderr, "su: no directory\n"); 171 exit(1); 172 } 173 } 174 if (fulllogin || pwd->pw_uid) 175 (void)setenv("USER", pwd->pw_name, 1); 176 (void)setenv("HOME", pwd->pw_dir, 1); 177 (void)setenv("SHELL", shell, 1); 178 } 179 180 if (iscsh == YES) { 181 if (fastlogin) 182 *np-- = "-f"; 183 if (asme) 184 *np-- = "-m"; 185 } 186 187 /* csh strips the first character... */ 188 *np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su"; 189 190 if (pwd->pw_uid == 0) 191 syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s", 192 username, ttyname(2)); 193 194 (void)setpriority(PRIO_PROCESS, 0, prio); 195 196 execv(shell, np); 197 fprintf(stderr, "su: no shell.\n"); 198 exit(1); 199 } 200 201 chshell(sh) 202 char *sh; 203 { 204 char *cp, *getusershell(); 205 206 while ((cp = getusershell()) != NULL) 207 if (!strcmp(cp, sh)) 208 return(1); 209 return(0); 210 } 211