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
main(argc,argv)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
chshell(sh)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
koktologin(name,realm)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