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