136660Skfall /* 236660Skfall * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $ 336660Skfall * $Author: jtkohl $ 436660Skfall */ 536660Skfall 636660Skfall /* 736660Skfall * Copyright (c) 1988 The Regents of the University of California. 836660Skfall * All rights reserved. 936660Skfall * 1036660Skfall * Redistribution and use in source and binary forms are permitted 1136660Skfall * provided that the above copyright notice and this paragraph are 1236660Skfall * duplicated in all such forms and that any documentation, 1336660Skfall * advertising materials, and other materials related to such 1436660Skfall * distribution and use acknowledge that the software was developed 1536660Skfall * by the University of California, Berkeley. The name of the 1636660Skfall * University may not be used to endorse or promote products derived 1736660Skfall * from this software without specific prior written permission. 1836660Skfall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1936660Skfall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 2036660Skfall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2136660Skfall */ 2236660Skfall 2336660Skfall /* 2436660Skfall * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute 2536660Skfall * of Technology. For copying and distribution information, please see 2636660Skfall * the file <mit-copyright.h>. 2736660Skfall */ 2836660Skfall 2936660Skfall #ifndef lint 3036660Skfall static char rcsid_ksu_c[] = 3136660Skfall "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $"; 3236660Skfall #endif lint 3336660Skfall 3436660Skfall #ifndef lint 3536660Skfall char copyright[] = 3636660Skfall "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 3736660Skfall All rights reserved.\n"; 3836660Skfall #endif /* not lint */ 3936660Skfall 4036660Skfall #ifndef lint 4136660Skfall static char sccsid[] = "@(#)su.c 5.11 (Berkeley) 12/7/88"; 4236660Skfall #endif /* not lint */ 4336660Skfall 44*38035Skfall #include <kerberos/mit-copyright.h> 4536660Skfall #include <sys/param.h> 4636660Skfall #include <sys/time.h> 4736660Skfall #include <sys/resource.h> 4836660Skfall #include <syslog.h> 4936660Skfall #include <stdio.h> 5036660Skfall #include <pwd.h> 5136660Skfall #include <grp.h> 52*38035Skfall #include <kerberos/krb.h> 5336660Skfall #include <netdb.h> 5436660Skfall #include <sys/ioctl.h> 5536660Skfall 5636660Skfall #ifndef LOG_AUTH 5736660Skfall #define LOG_AUTH 0 5836660Skfall #endif /* LOG_AUTH */ 5936660Skfall 6036660Skfall /* for Ultrix and friends ... */ 6136660Skfall #ifndef MAXHOSTNAMELEN 6236660Skfall #define MAXHOSTNAMELEN 64 6336660Skfall #endif 6436660Skfall 6536660Skfall extern char *krb_err_txt[]; 6636660Skfall int kerno; 6736660Skfall char lrealm[REALM_SZ]; 6836660Skfall char krbtkfile[128]; 6936660Skfall 7036660Skfall #define MAXPWSIZE 128 /* Biggest string we accept for a password 7136660Skfall (includes space for null terminator) */ 7236660Skfall 7336660Skfall main(argc, argv) 7436660Skfall int argc; 7536660Skfall char **argv; 7636660Skfall { 7736660Skfall extern char **environ; 7836660Skfall extern int errno, optind; 7936660Skfall register struct passwd *pwd; 8036660Skfall register char *p, **g; 8136660Skfall struct group *gr; 8236660Skfall uid_t ruid, getuid(); 8336660Skfall #ifdef NO_GETUSERSHELL 8436660Skfall int ch, fulllogin, fastlogin, prio; 8536660Skfall #else 8636660Skfall int asme, ch, fulllogin, fastlogin, prio; 8736660Skfall #endif /* NO_GETUSERSHELL */ 8836660Skfall enum { UNSET, YES, NO } iscsh = UNSET; 8936660Skfall char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 9036660Skfall char namebuf[50], shellbuf[MAXPATHLEN]; 9136660Skfall char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy(); 9236660Skfall #ifdef NOENCRYPTION 9336660Skfall #define read_long_pw_string placebo_read_pw_string 9436660Skfall #else 9536660Skfall #define read_long_pw_string des_read_pw_string 9636660Skfall #endif 9736660Skfall int read_long_pw_string(); 9836660Skfall char pw_buf[MAXPWSIZE]; 9936660Skfall char *mytty; 10036660Skfall 10136660Skfall mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)"; 10236660Skfall 10336660Skfall np = &nargv[3]; 10436660Skfall *np-- = NULL; 10536660Skfall #ifdef NO_GETUSERSHELL 10636660Skfall fulllogin = fastlogin = 0; 10736660Skfall #define GETOPTARG "-flm" 10836660Skfall #else 10936660Skfall asme = fulllogin = fastlogin = 0; 11036660Skfall #define GETOPTARG "-fl" 11136660Skfall #endif 11236660Skfall while ((ch = getopt(argc, argv, GETOPTARG)) != EOF) 11336660Skfall switch((char)ch) { 11436660Skfall case 'f': 11536660Skfall fastlogin = 1; 11636660Skfall break; 11736660Skfall case '-': 11836660Skfall case 'l': 11936660Skfall fulllogin = 1; 12036660Skfall break; 12136660Skfall #ifndef NO_GETUSERSHELL 12236660Skfall case 'm': 12336660Skfall asme = 1; 12436660Skfall break; 12536660Skfall #endif 12636660Skfall case '?': 12736660Skfall default: 12836660Skfall #ifdef NO_GETUSERSHELL 12936660Skfall fprintf(stderr, "usage: ksu [-fl] [login]\n"); 13036660Skfall #else 13136660Skfall fprintf(stderr, "usage: ksu [-flm] [login]\n"); 13236660Skfall #endif /* NO_GETUSERSHELL */ 13336660Skfall exit(1); 13436660Skfall } 13536660Skfall argv += optind; 13636660Skfall 13736660Skfall errno = 0; 13836660Skfall prio = getpriority(PRIO_PROCESS, 0); 13936660Skfall if (errno) 14036660Skfall prio = 0; 14136660Skfall (void)setpriority(PRIO_PROCESS, 0, -2); 14236660Skfall 14336660Skfall /* get current login name and shell */ 14436660Skfall if ((pwd = getpwuid(ruid = getuid())) == NULL) { 14536660Skfall fprintf(stderr, "ksu: who are you?\n"); 14636660Skfall exit(1); 14736660Skfall } 14836660Skfall username = strcpy(namebuf, pwd->pw_name); 14936660Skfall #ifndef NO_GETUSERSHELL 15036660Skfall if (asme) 15136660Skfall if (pwd->pw_shell && *pwd->pw_shell) 15236660Skfall shell = strcpy(shellbuf, pwd->pw_shell); 15336660Skfall else { 15436660Skfall shell = "/bin/sh"; 15536660Skfall iscsh = NO; 15636660Skfall } 15736660Skfall #endif 15836660Skfall 15936660Skfall /* get target login information */ 16036660Skfall user = *argv ? *argv : "root"; 16136660Skfall if ((pwd = getpwnam(user)) == NULL) { 16236660Skfall fprintf(stderr, "ksu: unknown login %s\n", user); 16336660Skfall exit(1); 16436660Skfall } 16536660Skfall 16636660Skfall /* 16736660Skfall * Only allow those with kerberos root instances in the /.klogin 16836660Skfall * file to su to root. 16936660Skfall */ 17036660Skfall if (pwd->pw_uid == 0) { 17136660Skfall KTEXT_ST ticket; 17236660Skfall AUTH_DAT authdata; 17336660Skfall char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; 17436660Skfall unsigned long faddr; 17536660Skfall struct hostent *hp; 17636660Skfall 17736660Skfall /* First lets see if he has a chance! */ 17836660Skfall if (krb_get_lrealm(lrealm, 1) != KSUCCESS) { 17936660Skfall fprintf(stderr,"Unable to get local realm\n"); 18036660Skfall exit(1); 18136660Skfall } 18236660Skfall if (koktologin(username, lrealm)) { 18336660Skfall fprintf(stderr,"You are not allowed to ksu to root\n"); 18436660Skfall exit(1); 18536660Skfall } 18636660Skfall sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid()); 18736660Skfall setuid(0); /* so ticket file has good protection */ 18836660Skfall if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1, 18936660Skfall "Your root instance password: ", 0)) { 19036660Skfall fprintf(stderr,"Error reading password.\n"); 19136660Skfall exit(1); 19236660Skfall } 19336660Skfall p = pw_buf; 19436660Skfall setenv("KRBTKFILE", krbtkfile, 1); 19536660Skfall kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt", 19636660Skfall lrealm, 2, p); 19736660Skfall bzero(p, strlen(p)); 19836660Skfall if (kerno != KSUCCESS) { 19936660Skfall printf("Unable to ksu: %s\n", krb_err_txt[kerno]); 20036660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s", 20136660Skfall username, mytty, krb_err_txt[kerno]); 20236660Skfall exit(1); 20336660Skfall } 20436660Skfall setpriority(PRIO_PROCESS, 0, -2); 20536660Skfall /* 20636660Skfall * Now use the ticket for something useful, to make sure 20736660Skfall * it is valid. 20836660Skfall */ 20936660Skfall if (gethostname(hostname, sizeof(hostname)) == -1) { 21036660Skfall perror("cannot retrieve hostname"); 21136660Skfall dest_tkt(); 21236660Skfall exit(1); 21336660Skfall } 21436660Skfall (void) strncpy(savehost, krb_get_phost(hostname), 21536660Skfall sizeof(savehost)); 21636660Skfall savehost[sizeof(savehost)-1] = 0; 21736660Skfall 21836660Skfall kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); 21936660Skfall if (kerno == KDC_PR_UNKNOWN) { 22036660Skfall printf("Warning: tgt not verified\n"); 22136660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified", 22236660Skfall username, mytty); 22336660Skfall } else if (kerno != KSUCCESS) { 22436660Skfall printf("Unable to use tgt: %s\n", krb_err_txt[kerno]); 22536660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s", 22636660Skfall username, mytty, krb_err_txt[kerno]); 22736660Skfall dest_tkt(); 22836660Skfall exit(1); 22936660Skfall } else { 23036660Skfall if (!(hp = gethostbyname(hostname))) { 23136660Skfall printf("Unable to get address of %s\n",hostname); 23236660Skfall dest_tkt(); 23336660Skfall exit(1); 23436660Skfall } 23536660Skfall bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr)); 23636660Skfall if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, 23736660Skfall faddr, &authdata, "")) != KSUCCESS) { 23836660Skfall printf("Unable to verify rcmd ticket: %s\n", 23936660Skfall krb_err_txt[kerno]); 24036660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s", 24136660Skfall username, mytty, krb_err_txt[kerno]); 24236660Skfall dest_tkt(); 24336660Skfall exit(1); 24436660Skfall } 24536660Skfall } 24636660Skfall printf("Don't forget to kdestroy before exiting the root shell.\n"); 24736660Skfall } else 24836660Skfall /* if target requires a password, verify it */ 24936660Skfall if (ruid && *pwd->pw_passwd) { 25036660Skfall p = getpass("Password:"); 25136660Skfall if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 25236660Skfall fprintf(stderr, "Sorry\n"); 25336660Skfall if (pwd->pw_uid == 0) 25436660Skfall syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty); 25536660Skfall exit(1); 25636660Skfall } 25736660Skfall } 25836660Skfall 25936660Skfall #ifndef NO_GETUSERSHELL 26036660Skfall if (asme) { 26136660Skfall /* if asme and non-standard target shell, must be root */ 26236660Skfall if (!chshell(pwd->pw_shell) && ruid) { 26336660Skfall fprintf(stderr, "ksu: Permission denied.\n"); 26436660Skfall dest_tkt(); 26536660Skfall exit(1); 26636660Skfall } 26736660Skfall } 26836660Skfall else 26936660Skfall #endif 27036660Skfall if (pwd->pw_shell && *pwd->pw_shell) { 27136660Skfall shell = pwd->pw_shell; 27236660Skfall iscsh = UNSET; 27336660Skfall } else { 27436660Skfall shell = "/bin/sh"; 27536660Skfall iscsh = NO; 27636660Skfall } 27736660Skfall 27836660Skfall /* if we're forking a csh, we want to slightly muck the args */ 27936660Skfall if (iscsh == UNSET) { 28036660Skfall if (p = rindex(shell, '/')) 28136660Skfall ++p; 28236660Skfall else 28336660Skfall p = shell; 28436660Skfall iscsh = strcmp(p, "csh") ? NO : YES; 28536660Skfall } 28636660Skfall 28736660Skfall /* set permissions */ 28836660Skfall if (setgid(pwd->pw_gid) < 0) { 28936660Skfall perror("ksu: setgid"); 29036660Skfall dest_tkt(); 29136660Skfall exit(1); 29236660Skfall } 29336660Skfall if (initgroups(user, pwd->pw_gid)) { 29436660Skfall fprintf(stderr, "ksu: initgroups failed\n"); 29536660Skfall dest_tkt(); 29636660Skfall exit(1); 29736660Skfall } 29836660Skfall if (setuid(pwd->pw_uid) < 0) { 29936660Skfall perror("ksu: setuid"); 30036660Skfall dest_tkt(); 30136660Skfall exit(1); 30236660Skfall } 30336660Skfall 30436660Skfall #ifndef NO_GETUSERSHELL 30536660Skfall if (!asme) { 30636660Skfall #endif 30736660Skfall if (fulllogin) { 30836660Skfall p = getenv("TERM"); 30936660Skfall cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin"; 31036660Skfall cleanenv[1] = NULL; 31136660Skfall environ = cleanenv; 31236660Skfall (void)setenv("TERM", p, 1); 31336660Skfall if (chdir(pwd->pw_dir) < 0) { 31436660Skfall fprintf(stderr, "ksu: no directory\n"); 31536660Skfall dest_tkt(); 31636660Skfall exit(1); 31736660Skfall } 31836660Skfall } 31936660Skfall if (fulllogin || pwd->pw_uid) 32036660Skfall (void)setenv("USER", pwd->pw_name, 1); 32136660Skfall (void)setenv("HOME", pwd->pw_dir, 1); 32236660Skfall (void)setenv("SHELL", shell, 1); 32336660Skfall #ifndef NO_GETUSERSHELL 32436660Skfall } 32536660Skfall #endif 32636660Skfall 32736660Skfall if (iscsh == YES) { 32836660Skfall if (fastlogin) 32936660Skfall *np-- = "-f"; 33036660Skfall #ifndef NO_GETUSERSHELL 33136660Skfall if (asme) 33236660Skfall *np-- = "-m"; 33336660Skfall #endif 33436660Skfall } 33536660Skfall 33636660Skfall /* csh strips the first character... */ 33736660Skfall *np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu"; 33836660Skfall 33936660Skfall if (pwd->pw_uid == 0) 34036660Skfall syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s", 34136660Skfall username, mytty); 34236660Skfall 34336660Skfall (void)setpriority(PRIO_PROCESS, 0, prio); 34436660Skfall 34536660Skfall execv(shell, np); 34636660Skfall fprintf(stderr, "ksu: no shell.\n"); 34736660Skfall dest_tkt(); 34836660Skfall exit(1); 34936660Skfall } 35036660Skfall 35136660Skfall #ifndef NO_GETUSERSHELL 35236660Skfall chshell(sh) 35336660Skfall char *sh; 35436660Skfall { 35536660Skfall char *cp, *getusershell(); 35636660Skfall 35736660Skfall while ((cp = getusershell()) != NULL) 35836660Skfall if (!strcmp(cp, sh)) 35936660Skfall return(1); 36036660Skfall return(0); 36136660Skfall } 36236660Skfall #endif /* NO_GETUSERSHELL */ 36336660Skfall 36436660Skfall koktologin(name, realm) 36536660Skfall char *name; 36636660Skfall char *realm; 36736660Skfall { 36836660Skfall struct auth_dat kdata_st; 36936660Skfall AUTH_DAT *kdata = &kdata_st; 37036660Skfall /* Cons together an AUTH_DAT structure for kuserok */ 37136660Skfall bzero((caddr_t) kdata, sizeof(*kdata)); 37236660Skfall strcpy(kdata->pname, name); 37336660Skfall strcpy(kdata->pinst, "root"); 37436660Skfall strcpy(kdata->prealm, realm); 37536660Skfall return (kuserok(kdata, "root")); 37636660Skfall } 377