1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)su.c 5.20 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/time.h> 20 #include <sys/resource.h> 21 #include <syslog.h> 22 #include <stdio.h> 23 #include <pwd.h> 24 #include <grp.h> 25 #include <string.h> 26 #include <unistd.h> 27 #include "pathnames.h" 28 29 #ifdef KERBEROS 30 #include <kerberosIV/des.h> 31 #include <kerberosIV/krb.h> 32 #include <netdb.h> 33 34 #define ARGSTR "-Kflm" 35 36 int use_kerberos = 1; 37 #else 38 #define ARGSTR "-flm" 39 #endif 40 41 main(argc, argv) 42 int argc; 43 char **argv; 44 { 45 extern char **environ; 46 extern int errno, optind; 47 register struct passwd *pwd; 48 register char *p, **g; 49 struct group *gr; 50 uid_t ruid, getuid(); 51 int asme, ch, asthem, fastlogin, prio; 52 enum { UNSET, YES, NO } iscsh = UNSET; 53 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 54 char shellbuf[MAXPATHLEN]; 55 char *crypt(), *getpass(), *getenv(), *getlogin(), *mytty(); 56 57 np = &nargv[3]; 58 *np-- = NULL; 59 asme = asthem = fastlogin = 0; 60 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 61 switch((char)ch) { 62 #ifdef KERBEROS 63 case 'K': 64 use_kerberos = 0; 65 break; 66 #endif 67 case 'f': 68 fastlogin = 1; 69 break; 70 case '-': 71 case 'l': 72 asme = 0; 73 asthem = 1; 74 break; 75 case 'm': 76 asme = 1; 77 asthem = 0; 78 break; 79 case '?': 80 default: 81 (void)fprintf(stderr, "usage: su [%s] [login]\n", 82 ARGSTR); 83 exit(1); 84 } 85 argv += optind; 86 87 errno = 0; 88 prio = getpriority(PRIO_PROCESS, 0); 89 if (errno) 90 prio = 0; 91 (void)setpriority(PRIO_PROCESS, 0, -2); 92 93 /* get current login name and shell */ 94 if ((pwd = getpwuid(ruid = getuid())) == NULL) { 95 fprintf(stderr, "su: who are you?\n"); 96 exit(1); 97 } 98 username = strdup(pwd->pw_name); 99 if (asme) 100 if (pwd->pw_shell && *pwd->pw_shell) 101 shell = strcpy(shellbuf, pwd->pw_shell); 102 else { 103 shell = _PATH_BSHELL; 104 iscsh = NO; 105 } 106 107 /* get target login information, default to root */ 108 user = *argv ? *argv : "root"; 109 if ((pwd = getpwnam(user)) == NULL) { 110 fprintf(stderr, "su: unknown login %s\n", user); 111 exit(1); 112 } 113 114 /* only allow those in group zero to su to root. */ 115 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) 116 for (g = gr->gr_mem;; ++g) { 117 if (!*g) { 118 (void)fprintf(stderr, 119 "su: you are not in the correct group to su %s.\n", user); 120 exit(1); 121 } 122 if (!strcmp(username, *g)) 123 break; 124 } 125 openlog("su", LOG_CONS, 0); 126 127 if (ruid) { 128 #ifdef KERBEROS 129 if (!use_kerberos || kerberos(username, user, pwd->pw_uid)) 130 #endif 131 /* if target requires a password, verify it */ 132 if (*pwd->pw_passwd) { 133 p = getpass("Password:"); 134 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 135 fprintf(stderr, "Sorry\n"); 136 if (pwd->pw_uid == 0) 137 syslog(LOG_AUTH|LOG_CRIT, 138 "BAD SU %s on %s", username, 139 mytty()); 140 exit(1); 141 } 142 } 143 } 144 145 if (asme) { 146 /* if asme and non-standard target shell, must be root */ 147 if (!chshell(pwd->pw_shell) && ruid) { 148 (void)fprintf(stderr, "su: permission denied.\n"); 149 exit(1); 150 } 151 } else if (pwd->pw_shell && *pwd->pw_shell) { 152 shell = pwd->pw_shell; 153 iscsh = UNSET; 154 } else { 155 shell = _PATH_BSHELL; 156 iscsh = NO; 157 } 158 159 /* if we're forking a csh, we want to slightly muck the args */ 160 if (iscsh == UNSET) { 161 if (p = rindex(shell, '/')) 162 ++p; 163 else 164 p = shell; 165 iscsh = strcmp(p, "csh") ? NO : YES; 166 } 167 168 /* set permissions */ 169 if (setgid(pwd->pw_gid) < 0) { 170 perror("su: setgid"); 171 exit(1); 172 } 173 if (initgroups(user, pwd->pw_gid)) { 174 (void)fprintf(stderr, "su: initgroups failed.\n"); 175 exit(1); 176 } 177 if (setuid(pwd->pw_uid) < 0) { 178 perror("su: setuid"); 179 exit(1); 180 } 181 182 if (!asme) { 183 if (asthem) { 184 p = getenv("TERM"); 185 cleanenv[0] = _PATH_SEARCHPATH; 186 cleanenv[1] = NULL; 187 environ = cleanenv; 188 (void)setenv("TERM", p, 1); 189 if (chdir(pwd->pw_dir) < 0) { 190 fprintf(stderr, "su: no directory\n"); 191 exit(1); 192 } 193 } 194 if (asthem || pwd->pw_uid) 195 (void)setenv("USER", pwd->pw_name, 1); 196 (void)setenv("HOME", pwd->pw_dir, 1); 197 (void)setenv("SHELL", shell, 1); 198 } 199 200 if (iscsh == YES) { 201 if (fastlogin) 202 *np-- = "-f"; 203 if (asme) 204 *np-- = "-m"; 205 } 206 207 /* csh strips the first character... */ 208 *np = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 209 210 if (pwd->pw_uid == 0) 211 syslog(LOG_NOTICE|LOG_AUTH, "%s on %s", username, mytty()); 212 213 (void)setpriority(PRIO_PROCESS, 0, prio); 214 215 execv(shell, np); 216 (void)fprintf(stderr, "su: %s not found.\n", shell); 217 exit(1); 218 } 219 220 chshell(sh) 221 char *sh; 222 { 223 register char *cp; 224 char *getusershell(); 225 226 while ((cp = getusershell()) != NULL) 227 if (!strcmp(cp, sh)) 228 return(1); 229 return(0); 230 } 231 232 char * 233 mytty() 234 { 235 char *p, *ttyname(); 236 237 return((p = ttyname(STDERR_FILENO)) ? p : "UNKNOWN TTY"); 238 } 239 240 #ifdef KERBEROS 241 kerberos(username, user, uid) 242 char *username, *user; 243 int uid; 244 { 245 extern char *krb_err_txt[]; 246 KTEXT_ST ticket; 247 AUTH_DAT authdata; 248 struct hostent *hp; 249 register char *p; 250 int kerno; 251 u_long faddr; 252 char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN], pw_buf[_PASSWORD_LEN]; 253 char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; 254 char *mytty(); 255 256 if (krb_get_lrealm(lrealm, 1) != KSUCCESS) { 257 (void)fprintf(stderr, "su: couldn't get local realm.\n"); 258 return(1); 259 } 260 if (koktologin(username, lrealm, user) && !uid) { 261 (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user); 262 return(1); 263 } 264 (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid()); 265 /* setuid(uid); */ 266 267 if (read_pw_string(pw_buf, sizeof(pw_buf) - 1, 268 "Kerberos password: ", 0)) { 269 (void)fprintf(stderr, "su: error reading password.\n"); 270 return(1); 271 } 272 273 (void)setenv("KRBTKFILE", krbtkfile, 1); 274 /* short lifetime for root tickets */ 275 if (setuid(0) < 0) { 276 perror("su: setuid"); 277 return(1); 278 } 279 (void)unlink(krbtkfile); 280 /* POLICY: short ticket lifetime for root */ 281 kerno = krb_get_pw_in_tkt(username, (uid == 0 ? "root" : ""), lrealm, 282 "krbtgt", lrealm, (uid == 0 ? 2 : DEFAULT_TKT_LIFE), pw_buf); 283 284 bzero(pw_buf, sizeof(pw_buf)); 285 286 if (kerno != KSUCCESS) { 287 if (kerno == KDC_PR_UNKNOWN) 288 return(1); 289 (void)printf("su: unable to su: %s\n", krb_err_txt[kerno]); 290 syslog(LOG_NOTICE|LOG_AUTH, 291 "su: BAD Kerberos SU: %s on %s: %s", username, mytty(), 292 krb_err_txt[kerno]); 293 return(1); 294 } 295 296 if (chown(krbtkfile, uid, -1) < 0) { 297 perror("su: chown:"); 298 (void)unlink(krbtkfile); 299 return(1); 300 } 301 302 (void)setpriority(PRIO_PROCESS, 0, -2); 303 304 if (gethostname(hostname, sizeof(hostname)) == -1) { 305 perror("su: hostname"); 306 dest_tkt(); 307 return(1); 308 } 309 310 (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost)); 311 savehost[sizeof(savehost) - 1] = '\0'; 312 313 kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); 314 315 if (kerno == KDC_PR_UNKNOWN) { 316 (void)printf("Warning: tgt not verified.\n"); 317 syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s, tgt not verified", 318 username, mytty()); 319 } else if (kerno != KSUCCESS) { 320 (void)printf("Unable to use tgt: %s\n", krb_err_txt[kerno]); 321 syslog(LOG_NOTICE|LOG_AUTH, "su: failed su: %s on %s: %s", 322 username, mytty(), krb_err_txt[kerno]); 323 dest_tkt(); 324 return(1); 325 } else { 326 if (!(hp = gethostbyname(hostname))) { 327 (void)printf("su: can't get addr of %s\n", hostname); 328 dest_tkt(); 329 return(1); 330 } 331 (void)bcopy((char *)hp->h_addr, (char *)&faddr, sizeof(faddr)); 332 333 if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, 334 &authdata, "")) != KSUCCESS) { 335 (void)printf("su: unable to verify rcmd ticket: %s\n", 336 krb_err_txt[kerno]); 337 syslog(LOG_NOTICE|LOG_AUTH, 338 "su: failed su: %s on %s: %s", username, 339 mytty(), krb_err_txt[kerno]); 340 dest_tkt(); 341 return(1); 342 } 343 } 344 return(0); 345 } 346 347 koktologin(name, realm, toname) 348 char *name, *realm, *toname; 349 { 350 register AUTH_DAT *kdata; 351 AUTH_DAT kdata_st; 352 353 kdata = &kdata_st; 354 bzero((caddr_t) kdata, sizeof(*kdata)); 355 (void)strcpy(kdata->pname, name); 356 (void)strcpy(kdata->pinst, 357 ((strcmp(toname, "root") == 0) ? "root" : "")); 358 (void)strcpy(kdata->prealm, realm); 359 return(kuserok(kdata, toname)); 360 } 361 #endif 362