1*36660Skfall /* 2*36660Skfall * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $ 3*36660Skfall * $Author: jtkohl $ 4*36660Skfall */ 5*36660Skfall 6*36660Skfall /* 7*36660Skfall * Copyright (c) 1988 The Regents of the University of California. 8*36660Skfall * All rights reserved. 9*36660Skfall * 10*36660Skfall * Redistribution and use in source and binary forms are permitted 11*36660Skfall * provided that the above copyright notice and this paragraph are 12*36660Skfall * duplicated in all such forms and that any documentation, 13*36660Skfall * advertising materials, and other materials related to such 14*36660Skfall * distribution and use acknowledge that the software was developed 15*36660Skfall * by the University of California, Berkeley. The name of the 16*36660Skfall * University may not be used to endorse or promote products derived 17*36660Skfall * from this software without specific prior written permission. 18*36660Skfall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 19*36660Skfall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 20*36660Skfall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21*36660Skfall */ 22*36660Skfall 23*36660Skfall /* 24*36660Skfall * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute 25*36660Skfall * of Technology. For copying and distribution information, please see 26*36660Skfall * the file <mit-copyright.h>. 27*36660Skfall */ 28*36660Skfall 29*36660Skfall #ifndef lint 30*36660Skfall static char rcsid_ksu_c[] = 31*36660Skfall "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $"; 32*36660Skfall #endif lint 33*36660Skfall 34*36660Skfall #ifndef lint 35*36660Skfall char copyright[] = 36*36660Skfall "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 37*36660Skfall All rights reserved.\n"; 38*36660Skfall #endif /* not lint */ 39*36660Skfall 40*36660Skfall #ifndef lint 41*36660Skfall static char sccsid[] = "@(#)su.c 5.11 (Berkeley) 12/7/88"; 42*36660Skfall #endif /* not lint */ 43*36660Skfall 44*36660Skfall #include <mit-copyright.h> 45*36660Skfall #include <sys/param.h> 46*36660Skfall #include <sys/time.h> 47*36660Skfall #include <sys/resource.h> 48*36660Skfall #include <syslog.h> 49*36660Skfall #include <stdio.h> 50*36660Skfall #include <pwd.h> 51*36660Skfall #include <grp.h> 52*36660Skfall #include <krb.h> 53*36660Skfall #include <netdb.h> 54*36660Skfall #include <sys/ioctl.h> 55*36660Skfall 56*36660Skfall #ifndef LOG_AUTH 57*36660Skfall #define LOG_AUTH 0 58*36660Skfall #endif /* LOG_AUTH */ 59*36660Skfall 60*36660Skfall /* for Ultrix and friends ... */ 61*36660Skfall #ifndef MAXHOSTNAMELEN 62*36660Skfall #define MAXHOSTNAMELEN 64 63*36660Skfall #endif 64*36660Skfall 65*36660Skfall extern char *krb_err_txt[]; 66*36660Skfall int kerno; 67*36660Skfall char lrealm[REALM_SZ]; 68*36660Skfall char krbtkfile[128]; 69*36660Skfall 70*36660Skfall #define MAXPWSIZE 128 /* Biggest string we accept for a password 71*36660Skfall (includes space for null terminator) */ 72*36660Skfall 73*36660Skfall main(argc, argv) 74*36660Skfall int argc; 75*36660Skfall char **argv; 76*36660Skfall { 77*36660Skfall extern char **environ; 78*36660Skfall extern int errno, optind; 79*36660Skfall register struct passwd *pwd; 80*36660Skfall register char *p, **g; 81*36660Skfall struct group *gr; 82*36660Skfall uid_t ruid, getuid(); 83*36660Skfall #ifdef NO_GETUSERSHELL 84*36660Skfall int ch, fulllogin, fastlogin, prio; 85*36660Skfall #else 86*36660Skfall int asme, ch, fulllogin, fastlogin, prio; 87*36660Skfall #endif /* NO_GETUSERSHELL */ 88*36660Skfall enum { UNSET, YES, NO } iscsh = UNSET; 89*36660Skfall char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 90*36660Skfall char namebuf[50], shellbuf[MAXPATHLEN]; 91*36660Skfall char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy(); 92*36660Skfall #ifdef NOENCRYPTION 93*36660Skfall #define read_long_pw_string placebo_read_pw_string 94*36660Skfall #else 95*36660Skfall #define read_long_pw_string des_read_pw_string 96*36660Skfall #endif 97*36660Skfall int read_long_pw_string(); 98*36660Skfall char pw_buf[MAXPWSIZE]; 99*36660Skfall char *mytty; 100*36660Skfall 101*36660Skfall mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)"; 102*36660Skfall 103*36660Skfall np = &nargv[3]; 104*36660Skfall *np-- = NULL; 105*36660Skfall #ifdef NO_GETUSERSHELL 106*36660Skfall fulllogin = fastlogin = 0; 107*36660Skfall #define GETOPTARG "-flm" 108*36660Skfall #else 109*36660Skfall asme = fulllogin = fastlogin = 0; 110*36660Skfall #define GETOPTARG "-fl" 111*36660Skfall #endif 112*36660Skfall while ((ch = getopt(argc, argv, GETOPTARG)) != EOF) 113*36660Skfall switch((char)ch) { 114*36660Skfall case 'f': 115*36660Skfall fastlogin = 1; 116*36660Skfall break; 117*36660Skfall case '-': 118*36660Skfall case 'l': 119*36660Skfall fulllogin = 1; 120*36660Skfall break; 121*36660Skfall #ifndef NO_GETUSERSHELL 122*36660Skfall case 'm': 123*36660Skfall asme = 1; 124*36660Skfall break; 125*36660Skfall #endif 126*36660Skfall case '?': 127*36660Skfall default: 128*36660Skfall #ifdef NO_GETUSERSHELL 129*36660Skfall fprintf(stderr, "usage: ksu [-fl] [login]\n"); 130*36660Skfall #else 131*36660Skfall fprintf(stderr, "usage: ksu [-flm] [login]\n"); 132*36660Skfall #endif /* NO_GETUSERSHELL */ 133*36660Skfall exit(1); 134*36660Skfall } 135*36660Skfall argv += optind; 136*36660Skfall 137*36660Skfall errno = 0; 138*36660Skfall prio = getpriority(PRIO_PROCESS, 0); 139*36660Skfall if (errno) 140*36660Skfall prio = 0; 141*36660Skfall (void)setpriority(PRIO_PROCESS, 0, -2); 142*36660Skfall 143*36660Skfall /* get current login name and shell */ 144*36660Skfall if ((pwd = getpwuid(ruid = getuid())) == NULL) { 145*36660Skfall fprintf(stderr, "ksu: who are you?\n"); 146*36660Skfall exit(1); 147*36660Skfall } 148*36660Skfall username = strcpy(namebuf, pwd->pw_name); 149*36660Skfall #ifndef NO_GETUSERSHELL 150*36660Skfall if (asme) 151*36660Skfall if (pwd->pw_shell && *pwd->pw_shell) 152*36660Skfall shell = strcpy(shellbuf, pwd->pw_shell); 153*36660Skfall else { 154*36660Skfall shell = "/bin/sh"; 155*36660Skfall iscsh = NO; 156*36660Skfall } 157*36660Skfall #endif 158*36660Skfall 159*36660Skfall /* get target login information */ 160*36660Skfall user = *argv ? *argv : "root"; 161*36660Skfall if ((pwd = getpwnam(user)) == NULL) { 162*36660Skfall fprintf(stderr, "ksu: unknown login %s\n", user); 163*36660Skfall exit(1); 164*36660Skfall } 165*36660Skfall 166*36660Skfall /* 167*36660Skfall * Only allow those with kerberos root instances in the /.klogin 168*36660Skfall * file to su to root. 169*36660Skfall */ 170*36660Skfall if (pwd->pw_uid == 0) { 171*36660Skfall KTEXT_ST ticket; 172*36660Skfall AUTH_DAT authdata; 173*36660Skfall char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; 174*36660Skfall unsigned long faddr; 175*36660Skfall struct hostent *hp; 176*36660Skfall 177*36660Skfall /* First lets see if he has a chance! */ 178*36660Skfall if (krb_get_lrealm(lrealm, 1) != KSUCCESS) { 179*36660Skfall fprintf(stderr,"Unable to get local realm\n"); 180*36660Skfall exit(1); 181*36660Skfall } 182*36660Skfall if (koktologin(username, lrealm)) { 183*36660Skfall fprintf(stderr,"You are not allowed to ksu to root\n"); 184*36660Skfall exit(1); 185*36660Skfall } 186*36660Skfall sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid()); 187*36660Skfall setuid(0); /* so ticket file has good protection */ 188*36660Skfall if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1, 189*36660Skfall "Your root instance password: ", 0)) { 190*36660Skfall fprintf(stderr,"Error reading password.\n"); 191*36660Skfall exit(1); 192*36660Skfall } 193*36660Skfall p = pw_buf; 194*36660Skfall setenv("KRBTKFILE", krbtkfile, 1); 195*36660Skfall kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt", 196*36660Skfall lrealm, 2, p); 197*36660Skfall bzero(p, strlen(p)); 198*36660Skfall if (kerno != KSUCCESS) { 199*36660Skfall printf("Unable to ksu: %s\n", krb_err_txt[kerno]); 200*36660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s", 201*36660Skfall username, mytty, krb_err_txt[kerno]); 202*36660Skfall exit(1); 203*36660Skfall } 204*36660Skfall setpriority(PRIO_PROCESS, 0, -2); 205*36660Skfall /* 206*36660Skfall * Now use the ticket for something useful, to make sure 207*36660Skfall * it is valid. 208*36660Skfall */ 209*36660Skfall if (gethostname(hostname, sizeof(hostname)) == -1) { 210*36660Skfall perror("cannot retrieve hostname"); 211*36660Skfall dest_tkt(); 212*36660Skfall exit(1); 213*36660Skfall } 214*36660Skfall (void) strncpy(savehost, krb_get_phost(hostname), 215*36660Skfall sizeof(savehost)); 216*36660Skfall savehost[sizeof(savehost)-1] = 0; 217*36660Skfall 218*36660Skfall kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); 219*36660Skfall if (kerno == KDC_PR_UNKNOWN) { 220*36660Skfall printf("Warning: tgt not verified\n"); 221*36660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified", 222*36660Skfall username, mytty); 223*36660Skfall } else if (kerno != KSUCCESS) { 224*36660Skfall printf("Unable to use tgt: %s\n", krb_err_txt[kerno]); 225*36660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s", 226*36660Skfall username, mytty, krb_err_txt[kerno]); 227*36660Skfall dest_tkt(); 228*36660Skfall exit(1); 229*36660Skfall } else { 230*36660Skfall if (!(hp = gethostbyname(hostname))) { 231*36660Skfall printf("Unable to get address of %s\n",hostname); 232*36660Skfall dest_tkt(); 233*36660Skfall exit(1); 234*36660Skfall } 235*36660Skfall bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr)); 236*36660Skfall if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, 237*36660Skfall faddr, &authdata, "")) != KSUCCESS) { 238*36660Skfall printf("Unable to verify rcmd ticket: %s\n", 239*36660Skfall krb_err_txt[kerno]); 240*36660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s", 241*36660Skfall username, mytty, krb_err_txt[kerno]); 242*36660Skfall dest_tkt(); 243*36660Skfall exit(1); 244*36660Skfall } 245*36660Skfall } 246*36660Skfall printf("Don't forget to kdestroy before exiting the root shell.\n"); 247*36660Skfall } else 248*36660Skfall /* if target requires a password, verify it */ 249*36660Skfall if (ruid && *pwd->pw_passwd) { 250*36660Skfall p = getpass("Password:"); 251*36660Skfall if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 252*36660Skfall fprintf(stderr, "Sorry\n"); 253*36660Skfall if (pwd->pw_uid == 0) 254*36660Skfall syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty); 255*36660Skfall exit(1); 256*36660Skfall } 257*36660Skfall } 258*36660Skfall 259*36660Skfall #ifndef NO_GETUSERSHELL 260*36660Skfall if (asme) { 261*36660Skfall /* if asme and non-standard target shell, must be root */ 262*36660Skfall if (!chshell(pwd->pw_shell) && ruid) { 263*36660Skfall fprintf(stderr, "ksu: Permission denied.\n"); 264*36660Skfall dest_tkt(); 265*36660Skfall exit(1); 266*36660Skfall } 267*36660Skfall } 268*36660Skfall else 269*36660Skfall #endif 270*36660Skfall if (pwd->pw_shell && *pwd->pw_shell) { 271*36660Skfall shell = pwd->pw_shell; 272*36660Skfall iscsh = UNSET; 273*36660Skfall } else { 274*36660Skfall shell = "/bin/sh"; 275*36660Skfall iscsh = NO; 276*36660Skfall } 277*36660Skfall 278*36660Skfall /* if we're forking a csh, we want to slightly muck the args */ 279*36660Skfall if (iscsh == UNSET) { 280*36660Skfall if (p = rindex(shell, '/')) 281*36660Skfall ++p; 282*36660Skfall else 283*36660Skfall p = shell; 284*36660Skfall iscsh = strcmp(p, "csh") ? NO : YES; 285*36660Skfall } 286*36660Skfall 287*36660Skfall /* set permissions */ 288*36660Skfall if (setgid(pwd->pw_gid) < 0) { 289*36660Skfall perror("ksu: setgid"); 290*36660Skfall dest_tkt(); 291*36660Skfall exit(1); 292*36660Skfall } 293*36660Skfall if (initgroups(user, pwd->pw_gid)) { 294*36660Skfall fprintf(stderr, "ksu: initgroups failed\n"); 295*36660Skfall dest_tkt(); 296*36660Skfall exit(1); 297*36660Skfall } 298*36660Skfall if (setuid(pwd->pw_uid) < 0) { 299*36660Skfall perror("ksu: setuid"); 300*36660Skfall dest_tkt(); 301*36660Skfall exit(1); 302*36660Skfall } 303*36660Skfall 304*36660Skfall #ifndef NO_GETUSERSHELL 305*36660Skfall if (!asme) { 306*36660Skfall #endif 307*36660Skfall if (fulllogin) { 308*36660Skfall p = getenv("TERM"); 309*36660Skfall cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin"; 310*36660Skfall cleanenv[1] = NULL; 311*36660Skfall environ = cleanenv; 312*36660Skfall (void)setenv("TERM", p, 1); 313*36660Skfall if (chdir(pwd->pw_dir) < 0) { 314*36660Skfall fprintf(stderr, "ksu: no directory\n"); 315*36660Skfall dest_tkt(); 316*36660Skfall exit(1); 317*36660Skfall } 318*36660Skfall } 319*36660Skfall if (fulllogin || pwd->pw_uid) 320*36660Skfall (void)setenv("USER", pwd->pw_name, 1); 321*36660Skfall (void)setenv("HOME", pwd->pw_dir, 1); 322*36660Skfall (void)setenv("SHELL", shell, 1); 323*36660Skfall #ifndef NO_GETUSERSHELL 324*36660Skfall } 325*36660Skfall #endif 326*36660Skfall 327*36660Skfall if (iscsh == YES) { 328*36660Skfall if (fastlogin) 329*36660Skfall *np-- = "-f"; 330*36660Skfall #ifndef NO_GETUSERSHELL 331*36660Skfall if (asme) 332*36660Skfall *np-- = "-m"; 333*36660Skfall #endif 334*36660Skfall } 335*36660Skfall 336*36660Skfall /* csh strips the first character... */ 337*36660Skfall *np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu"; 338*36660Skfall 339*36660Skfall if (pwd->pw_uid == 0) 340*36660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s", 341*36660Skfall username, mytty); 342*36660Skfall 343*36660Skfall (void)setpriority(PRIO_PROCESS, 0, prio); 344*36660Skfall 345*36660Skfall execv(shell, np); 346*36660Skfall fprintf(stderr, "ksu: no shell.\n"); 347*36660Skfall dest_tkt(); 348*36660Skfall exit(1); 349*36660Skfall } 350*36660Skfall 351*36660Skfall #ifndef NO_GETUSERSHELL 352*36660Skfall chshell(sh) 353*36660Skfall char *sh; 354*36660Skfall { 355*36660Skfall char *cp, *getusershell(); 356*36660Skfall 357*36660Skfall while ((cp = getusershell()) != NULL) 358*36660Skfall if (!strcmp(cp, sh)) 359*36660Skfall return(1); 360*36660Skfall return(0); 361*36660Skfall } 362*36660Skfall #endif /* NO_GETUSERSHELL */ 363*36660Skfall 364*36660Skfall koktologin(name, realm) 365*36660Skfall char *name; 366*36660Skfall char *realm; 367*36660Skfall { 368*36660Skfall struct auth_dat kdata_st; 369*36660Skfall AUTH_DAT *kdata = &kdata_st; 370*36660Skfall /* Cons together an AUTH_DAT structure for kuserok */ 371*36660Skfall bzero((caddr_t) kdata, sizeof(*kdata)); 372*36660Skfall strcpy(kdata->pname, name); 373*36660Skfall strcpy(kdata->pinst, "root"); 374*36660Skfall strcpy(kdata->prealm, realm); 375*36660Skfall return (kuserok(kdata, "root")); 376*36660Skfall } 377