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.23 (Berkeley) 11/06/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(), *ontty(); 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 openlog("su", LOG_CONS, 0); 93 94 /* get current login name and shell */ 95 ruid = getuid(); 96 username = getlogin(); 97 if (username == NULL || (pwd = getpwnam(username)) == NULL || 98 pwd->pw_uid != ruid) 99 pwd = getpwuid(ruid); 100 if (pwd == NULL) { 101 fprintf(stderr, "su: who are you?\n"); 102 exit(1); 103 } 104 username = strdup(pwd->pw_name); 105 if (asme) 106 if (pwd->pw_shell && *pwd->pw_shell) 107 shell = strcpy(shellbuf, pwd->pw_shell); 108 else { 109 shell = _PATH_BSHELL; 110 iscsh = NO; 111 } 112 113 /* get target login information, default to root */ 114 user = *argv ? *argv : "root"; 115 if ((pwd = getpwnam(user)) == NULL) { 116 fprintf(stderr, "su: unknown login %s\n", user); 117 exit(1); 118 } 119 120 /* only allow those in group zero to su to root. */ 121 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) 122 for (g = gr->gr_mem;; ++g) { 123 if (!*g) { 124 (void)fprintf(stderr, 125 "su: you are not in the correct group to su %s.\n", user); 126 exit(1); 127 } 128 if (!strcmp(username, *g)) 129 break; 130 } 131 132 if (ruid) { 133 #ifdef KERBEROS 134 if (!use_kerberos || kerberos(username, user, pwd->pw_uid)) 135 #endif 136 /* if target requires a password, verify it */ 137 if (*pwd->pw_passwd) { 138 p = getpass("Password:"); 139 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 140 fprintf(stderr, "Sorry\n"); 141 syslog(LOG_AUTH|LOG_WARNING, 142 "BAD SU %s to %s%s", username, 143 user, ontty()); 144 exit(1); 145 } 146 } 147 } 148 149 if (asme) { 150 /* if asme and non-standard target shell, must be root */ 151 if (!chshell(pwd->pw_shell) && ruid) { 152 (void)fprintf(stderr, 153 "su: permission denied (shell).\n"); 154 exit(1); 155 } 156 } else if (pwd->pw_shell && *pwd->pw_shell) { 157 shell = pwd->pw_shell; 158 iscsh = UNSET; 159 } else { 160 shell = _PATH_BSHELL; 161 iscsh = NO; 162 } 163 164 /* if we're forking a csh, we want to slightly muck the args */ 165 if (iscsh == UNSET) { 166 if (p = rindex(shell, '/')) 167 ++p; 168 else 169 p = shell; 170 iscsh = strcmp(p, "csh") ? NO : YES; 171 } 172 173 /* set permissions */ 174 if (setgid(pwd->pw_gid) < 0) { 175 perror("su: setgid"); 176 exit(1); 177 } 178 if (initgroups(user, pwd->pw_gid)) { 179 (void)fprintf(stderr, "su: initgroups failed.\n"); 180 exit(1); 181 } 182 if (setuid(pwd->pw_uid) < 0) { 183 perror("su: setuid"); 184 exit(1); 185 } 186 187 if (!asme) { 188 if (asthem) { 189 p = getenv("TERM"); 190 cleanenv[0] = _PATH_SEARCHPATH; 191 cleanenv[1] = NULL; 192 environ = cleanenv; 193 (void)setenv("TERM", p, 1); 194 if (chdir(pwd->pw_dir) < 0) { 195 fprintf(stderr, "su: no directory\n"); 196 exit(1); 197 } 198 } 199 if (asthem || pwd->pw_uid) 200 (void)setenv("USER", pwd->pw_name, 1); 201 (void)setenv("HOME", pwd->pw_dir, 1); 202 (void)setenv("SHELL", shell, 1); 203 } 204 205 if (iscsh == YES) { 206 if (fastlogin) 207 *np-- = "-f"; 208 if (asme) 209 *np-- = "-m"; 210 } 211 212 /* csh strips the first character... */ 213 *np = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 214 215 if (ruid != 0) 216 syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s", 217 username, user, ontty()); 218 219 (void)setpriority(PRIO_PROCESS, 0, prio); 220 221 execv(shell, np); 222 (void)fprintf(stderr, "su: %s not found.\n", shell); 223 exit(1); 224 } 225 226 chshell(sh) 227 char *sh; 228 { 229 register char *cp; 230 char *getusershell(); 231 232 while ((cp = getusershell()) != NULL) 233 if (!strcmp(cp, sh)) 234 return(1); 235 return(0); 236 } 237 238 char * 239 ontty() 240 { 241 char *p, *ttyname(); 242 static char buf[MAXPATHLEN + 4]; 243 244 buf[0] = 0; 245 if (p = ttyname(STDERR_FILENO)) 246 sprintf(buf, " on %s", p); 247 return (buf); 248 } 249 250 #ifdef KERBEROS 251 kerberos(username, user, uid) 252 char *username, *user; 253 int uid; 254 { 255 extern char *krb_err_txt[]; 256 KTEXT_ST ticket; 257 AUTH_DAT authdata; 258 struct hostent *hp; 259 register char *p; 260 int kerno; 261 u_long faddr; 262 char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN]; 263 char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; 264 char *ontty(); 265 266 if (krb_get_lrealm(lrealm, 1) != KSUCCESS) { 267 (void)fprintf(stderr, "su: couldn't get local realm.\n"); 268 return(1); 269 } 270 if (koktologin(username, lrealm, user) && !uid) { 271 (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user); 272 return(1); 273 } 274 (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid()); 275 276 (void)setenv("KRBTKFILE", krbtkfile, 1); 277 /* 278 * Set real as well as effective ID to 0 for the moment, 279 * to make the kerberos library do the right thing. 280 */ 281 if (setuid(0) < 0) { 282 perror("su: setuid"); 283 return(1); 284 } 285 (void)unlink(krbtkfile); 286 287 /* 288 * Little trick here -- if we are su'ing to root, 289 * we need to get a ticket for "xxx.root", where xxx represents 290 * the name of the person su'ing. Otherwise (non-root case), 291 * we need to get a ticket for "yyy.", where yyy represents 292 * the name of the person being su'd to, and the instance is null 293 * 294 * We should have a way to set the ticket lifetime, 295 * with a system default for root. 296 */ 297 kerno = krb_get_pw_in_tkt((uid == 0 ? username : user), 298 (uid == 0 ? "root" : ""), lrealm, 299 "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0); 300 301 if (kerno != KSUCCESS) { 302 if (kerno == KDC_PR_UNKNOWN) { 303 fprintf(stderr, "principal unknown: %s.%s@%s\n", 304 (uid == 0 ? username : user), 305 (uid == 0 ? "root" : ""), lrealm); 306 return(1); 307 } 308 (void)printf("su: unable to su: %s\n", krb_err_txt[kerno]); 309 syslog(LOG_NOTICE|LOG_AUTH, 310 "su: BAD Kerberos SU: %s to %s%s: %s", 311 username, user, ontty(), krb_err_txt[kerno]); 312 return(1); 313 } 314 315 if (chown(krbtkfile, uid, -1) < 0) { 316 perror("su: chown:"); 317 (void)unlink(krbtkfile); 318 return(1); 319 } 320 321 (void)setpriority(PRIO_PROCESS, 0, -2); 322 323 if (gethostname(hostname, sizeof(hostname)) == -1) { 324 perror("su: hostname"); 325 dest_tkt(); 326 return(1); 327 } 328 329 (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost)); 330 savehost[sizeof(savehost) - 1] = '\0'; 331 332 kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); 333 334 if (kerno == KDC_PR_UNKNOWN) { 335 (void)printf("Warning: tgt not verified.\n"); 336 syslog(LOG_NOTICE|LOG_AUTH, 337 "su: %s to %s%s, TGT not verified", 338 username, user, ontty()); 339 } else if (kerno != KSUCCESS) { 340 (void)printf("Unable to use TGT: %s\n", krb_err_txt[kerno]); 341 syslog(LOG_NOTICE|LOG_AUTH, "su: failed su: %s to %s%s: %s", 342 username, user, ontty(), krb_err_txt[kerno]); 343 dest_tkt(); 344 return(1); 345 } else { 346 if (!(hp = gethostbyname(hostname))) { 347 (void)printf("su: can't get addr of %s\n", hostname); 348 dest_tkt(); 349 return(1); 350 } 351 (void)bcopy((char *)hp->h_addr, (char *)&faddr, sizeof(faddr)); 352 353 if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, 354 &authdata, "")) != KSUCCESS) { 355 (void)printf("su: unable to verify rcmd ticket: %s\n", 356 krb_err_txt[kerno]); 357 syslog(LOG_NOTICE|LOG_AUTH, 358 "su: failed su: %s to %s%s: %s", username, 359 ontty(), user, krb_err_txt[kerno]); 360 dest_tkt(); 361 return(1); 362 } 363 } 364 return(0); 365 } 366 367 koktologin(name, realm, toname) 368 char *name, *realm, *toname; 369 { 370 register AUTH_DAT *kdata; 371 AUTH_DAT kdata_st; 372 373 kdata = &kdata_st; 374 bzero((caddr_t) kdata, sizeof(*kdata)); 375 (void)strcpy(kdata->pname, name); 376 (void)strcpy(kdata->pinst, 377 ((strcmp(toname, "root") == 0) ? "root" : "")); 378 (void)strcpy(kdata->prealm, realm); 379 return(kuserok(kdata, toname)); 380 } 381 #endif 382