diff options
Diffstat (limited to 'src/appl')
-rw-r--r-- | src/appl/bsd/ChangeLog | 78 | ||||
-rw-r--r-- | src/appl/bsd/Makefile.in | 4 | ||||
-rw-r--r-- | src/appl/bsd/configure.in | 56 | ||||
-rw-r--r-- | src/appl/bsd/forward.c | 15 | ||||
-rw-r--r-- | src/appl/bsd/krcp.c | 48 | ||||
-rw-r--r-- | src/appl/bsd/krlogin.c | 9 | ||||
-rw-r--r-- | src/appl/bsd/krlogind.c | 37 | ||||
-rw-r--r-- | src/appl/bsd/krsh.c | 5 | ||||
-rw-r--r-- | src/appl/bsd/krshd.c | 16 | ||||
-rw-r--r-- | src/appl/bsd/login.c | 1831 | ||||
-rw-r--r-- | src/appl/bsd/loginpaths.h | 6 | ||||
-rw-r--r-- | src/appl/bsd/rlogin.M | 34 | ||||
-rw-r--r-- | src/appl/bsd/rsh.M | 37 |
13 files changed, 1547 insertions, 629 deletions
diff --git a/src/appl/bsd/ChangeLog b/src/appl/bsd/ChangeLog index 93148ff5b..21e8a1277 100644 --- a/src/appl/bsd/ChangeLog +++ b/src/appl/bsd/ChangeLog @@ -1,14 +1,81 @@ Mon Apr 29 17:02:44 1996 Ken Raeburn <raeburn@cygnus.com> + Merge with Cygnus sources, changes from Mark Eichin, Marc + Horowitz, Chris Provenzano and me: + * Makefile.in (install): Install correct set of man pages, and check for failures. * kshd.M, klogind.M: Renamed from kr*.M versions. - - Wed Sep 13 23:19:17 1995 Mark Eichin <eichin@cygnus.com> - * login.M: New file. Man page for login with some description of new features. + * rlogin.M: Remove references to using program with target + hostname as argv[0]. + * rsh.M: Ditto. Also document -f, -F, -x options. + + * login.c: Massive changes. Split much functionality out of main + and into separate file sections: terminal flag settings, Kerberos + 4 and 5 support, UNIX password support, mail check, signal handler + handling, some other support routines. Revamp controlling tty and + process group handling. For AFS configuration, use setpag and run + aklog. Try validating password using krb5. Always set tty flags, + not just for rlogin session. When validating tickets, treat an + existing key file that doesn't contain the key we think we want + (possibly because DNS was spoofed) as an error condition. + * Makefile.in (LOGINLIBS): List libkrb524.a here. + (LIBOBJS): Not here. + (login.krb5): Reverse the order of LIBOBJS and LOGINLIBS. + * configure.in: Check for --with-afs. Add AFS libs and define + SETPAG if supplied. + + * login.c (KRB5_GET_TICKETS, KRB4_GET_TICKETS, KRB_RUN_AKLOG): new + macros selecting single signon options. krb5.conf profile support + for control over authentication options, above the compile time + selection. + (conf_affirmative): new function, recognize yes/no in profile + value. + (login_get_kconf): new function, look for all [login] flags and + set them in appropriate globals (via login_conf_set array.) + (main, sleepexit, destroy_tickets): Check the new login_* flags. + (main): rename KRB4_USE_524 to KRB4_CONVERT. + + * configure.in: Added checks for tcsetpgrp, tcgetpgrp, setpgid. + * krlogind.c (control): Use tcgetpgrp if it's available. + + * loginpaths.h (RPATH, LPATH, LPATH_root): Define HP/UX 9.04 + versions, conditionalized on __hpux and !hpux. + + * login.c and configure.in: instead of checking _IBMR2 and + __sgi__, write configure tests to check for the existence of + /etc/environment and /etc/TIMEZONE files, respectively. + + * forward.c (rd_and_store_for_creds) : If chown fails then only + pass failure back if owner is different than intended owner. This + is to make rsh.exp test work without requiring root privlidges. + + * login.c (main): Don't set TERM to an empty value. + (stypeof) [__hpux]: Return null if unknown. + + * krlogin.c (catchild): remove hp/ux kludge because of aclocal.m4 fix. + (speeds): test __hpux for hpux speed list. + (main): test __hpux for use of FIOSSAIOSTAT and FIOSSAIOOWN + (USE_TERMIO): test __hpux for bsdtty/ptyio headers. + * krlogind.c: test __hpux for bsdtty/ptyio headers. + (doit): test __hpux for use of setpgrp2. + * krcp.c (main): test __hpux as well for remsh vs. rsh. + + * krcp.c (des_write): Make sure the buffer for the encrypted data + is large enough. Only return an error in malloc fails. + + * krsh.c (main): Always turn on anyport -A option. + + * krlogind.c (ptsname): Declare if it's going to be used. + + * krshd.c (main): Use basename of argv[0] for progname. + + * login.c (dofork): On linux, TIOCNOTTY causes us to die on a + SIGHUP, so don't even try it. + Sun Apr 21 12:52:35 1996 Richard Basch <basch@lehman.com> * krshd.c: If checksumming is required & ALWAYS_V5_KUSEROK is @@ -294,13 +361,14 @@ Fri Jan 19 10:45:29 1996 Sam Hartman <hartmans@tertius.mit.edu> (recvauth): Fix accidental memory leak with authenticator and fix include correct username in checksum - * kcmd.c: Send authenticator with checksum of command line and remote user. + * kcmd.c: Send authenticator with checksum of command line and + remote user. * krlogin.c (des_read): Return 0 or -1 on close/error respectively. Wed Jan 17 15:14:33 1996 Sam Hartman <hartmans@tertius.mit.edu> - * krlogin.c ((reader): Use select to find out-of-band data, not signals. + * krlogin.c (reader): Use select to find out-of-band data, not signals. (oob): No longer a signal handler; just a function. (writer): get rid of copytochild setup as sigurg no longer needed (main): Don't block SIGURG diff --git a/src/appl/bsd/Makefile.in b/src/appl/bsd/Makefile.in index de249d94e..013f0d487 100644 --- a/src/appl/bsd/Makefile.in +++ b/src/appl/bsd/Makefile.in @@ -3,7 +3,7 @@ LOCALINCLUDE=-I$(SRCTOP)/include/kerberosIV SETENVSRC=@SETENVSRC@ SETENVOBJ=@SETENVOBJ@ -LOGINLIBS = @LOGINLIBS@ +LOGINLIBS = ../../krb524/libkrb524.a @LOGINLIBS@ LIBOBJS=@LIBOBJS@ LOCAL_LIBRARIES=-lpty @@ -71,7 +71,7 @@ install:: # referenced by klogind. # login.krb5: login.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS) - $(LD) $(LDFLAGS) $(LDARGS) -o login.krb5 login.o $(SETENVOBJ) $(LIBOBJS) $(LIBS) $(LOGINLIBS) + $(LD) $(LDFLAGS) $(LDARGS) -o login.krb5 login.o $(SETENVOBJ) $(LIBOBJS) $(LOGINLIBS) $(LIBS) install:: $(INSTALL_PROGRAM) login.krb5 $(DESTDIR)$(SERVER_BINDIR)/login.krb5 diff --git a/src/appl/bsd/configure.in b/src/appl/bsd/configure.in index 1792fa404..cb7ae23f5 100644 --- a/src/appl/bsd/configure.in +++ b/src/appl/bsd/configure.in @@ -1,5 +1,14 @@ AC_INIT(krlogind.c) CONFIG_RULES +LOGINLIBS= +AC_ARG_WITH([afs], +[ --without-afs don't have afs libraries to build against (default) + --with-afs=AFSDIR use preinstalled AFS library tree], +,with_afs=no)dnl +if test $with_afs != no; then + AC_DEFINE(SETPAG) + LOGINLIBS="$LOGINLIBS -L$with_afs/lib -L$with_afs/lib/afs -lauth -lsys -lrx -llwp" +fi AC_PROG_INSTALL dnl dbm libs for use of an_to_ln AC_CHECK_LIB(util,main) @@ -7,11 +16,10 @@ USE_ANAME AC_CHECK_LIB(crypt,crypt) dnl dnl AIX has them all; SCO might too -LOGINLIBS= AC_CHECK_LIB(odm,main, AC_CHECK_LIB(s,main, AC_CHECK_LIB(cfg,main, - LOGINLIBS="-lodm -ls -lcfg" + LOGINLIBS="$LOGINLIBS -lodm -ls -lcfg" ))) dnl dnl Make our operating system-specific security checks and definitions for @@ -53,6 +61,9 @@ AC_FUNC_CHECK(grantpt,AC_DEFINE(HAVE_GRANTPT)) AC_FUNC_CHECK(openpty,AC_DEFINE(HAVE_OPENPTY)) AC_FUNC_CHECK(setlogin,AC_DEFINE(HAVE_SETLOGIN)) AC_FUNC_CHECK(logwtmp,AC_DEFINE(HAVE_LOGWTMP)) +AC_FUNC_CHECK(tcgetpgrp,AC_DEFINE(HAVE_TCGETPGRP)) +AC_FUNC_CHECK(tcsetpgrp,AC_DEFINE(HAVE_TCSETPGRP)) +AC_FUNC_CHECK(setpgid,AC_DEFINE(HAVE_SETPGID)) AC_CHECK_HEADERS(unistd.h stdlib.h string.h sys/filio.h sys/sockio.h ) AC_CHECK_HEADERS(sys/label.h sys/tty.h ttyent.h lastlog.h sys/select.h ) AC_CHECK_HEADERS(sys/ptyvar.h utmp.h utmpx.h sys/time.h) @@ -161,6 +172,47 @@ if test $krb5_cv_shadow_pwd = yes; then AC_DEFINE(HAVE_SHADOW) fi dnl +dnl +AC_MSG_CHECKING([/etc/environment]) +AC_CACHE_VAL(krb5_cv_etc_environment, +[AC_C_CROSS +if test $ac_cv_c_cross = yes; then +errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling +)dnl +AC_MSG_ERROR(Cannot check for file existence when cross compiling) +else +if test -r /etc/environment; then +krb5_cv_etc_environment=yes +else +krb5_cv_etc_environment=no +fi +fi]) +AC_MSG_RESULT($krb5_cv_etc_environment) +if test $krb5_cv_etc_environment = yes; then +AC_DEFINE(HAVE_ETC_ENVIRONMENT) +fi +dnl +dnl +AC_MSG_CHECKING([/etc/TIMEZONE]) +AC_CACHE_VAL(krb5_cv_etc_timezone, +[AC_C_CROSS +if test $ac_cv_c_cross = yes; then +errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling +)dnl +AC_MSG_ERROR(Cannot check for file existence when cross compiling) +else +if test -r /etc/TIMEZONE; then +krb5_cv_etc_timezone=yes +else +krb5_cv_etc_timezone=no +fi +fi]) +AC_MSG_RESULT($krb5_cv_etc_timezone) +if test $krb5_cv_etc_timezone = yes; then +AC_DEFINE(HAVE_ETC_TIMEZONE) +fi +dnl +dnl KRB5_CHECK_PROTOS dnl ADD_DEF(-DKERBEROS) diff --git a/src/appl/bsd/forward.c b/src/appl/bsd/forward.c index 8c74eb2e4..54594b9b9 100644 --- a/src/appl/bsd/forward.c +++ b/src/appl/bsd/forward.c @@ -23,6 +23,8 @@ #include <stdio.h> #include <pwd.h> #include <netdb.h> +#include <sys/types.h> +#include <sys/stat.h> #include "k5-int.h" @@ -65,7 +67,18 @@ rd_and_store_for_creds(context, auth_context, inbuf, ticket, lusername, ccache) if (retval = krb5_cc_store_cred(context, *ccache, *creds)) goto cleanup; - retval = chown(ccname+5, pwd->pw_uid, -1); + if (retval = chown(ccname+5, pwd->pw_uid, -1)) { + /* + * If the file owner is the same as the user id then return ok. + * This is for testing only --proven + */ + struct stat statbuf; + + if (stat(ccname + 5, & statbuf) == 0) { + if (statbuf.st_uid == pwd->pw_uid) + retval = 0; + } + } cleanup: krb5_free_creds(context, *creds); diff --git a/src/appl/bsd/krcp.c b/src/appl/bsd/krcp.c index 32a6eb1a8..36ad114ce 100644 --- a/src/appl/bsd/krcp.c +++ b/src/appl/bsd/krcp.c @@ -381,7 +381,7 @@ int main(argc, argv) suser = pwd->pw_name; else if (!okname(suser)) continue; -#ifdef hpux +#if defined(hpux) || defined(__hpux) (void) sprintf(buf, "remsh %s -l %s -n %s %s '%s%s%s:%s'", #else (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s%s%s:%s'", @@ -391,7 +391,7 @@ int main(argc, argv) tuser ? "@" : "", thost, targ); } else -#ifdef hpux +#if defined(hpux) || defined(__hpux) (void) sprintf(buf, "remsh %s -n %s %s '%s%s%s:%s'", #else (void) sprintf(buf, "rsh %s -n %s %s '%s%s%s:%s'", @@ -1125,7 +1125,7 @@ struct buffer *allocbuf(bp, fd, blksize) size = roundup(stb.st_blksize, blksize); #endif - size = blksize; + size = blksize; if (bp->cnt < size) { if (bp->buf != 0) free(bp->buf); @@ -1413,33 +1413,41 @@ int des_read(fd, buf, len) } - int des_write(fd, buf, len) int fd; char *buf; int len; { + static krb5_data des_write_buf; + static int des_write_maxsize; unsigned char len_buf[4]; -/* Note that rcp depends on the same - * file descriptor being both input and output to the remote - * side. This is bogus, especially when rcp - * is being run by a rsh that pipes. Fix it here because - * it would require significantly more work in other places. --hartmans 1/96*/ + + /* + * Note that rcp depends on the same file descriptor being both + * input and output to the remote side. This is bogus, especially + * when rcp is being run by a rsh that pipes. Fix it here because it + * would require significantly more work in other places. --hartmans 1/96 + */ if (fd == 0) fd = 1; if (!encryptflag) return(krb5_net_write(bsd_context, fd, buf, len)); - desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry); - if (desoutbuf.length > (int) sizeof(des_outbuf)){ - return(-1); + des_write_buf.length = krb5_encrypt_size(len,eblock.crypto_entry); + + if (des_write_buf.length > des_write_maxsize) { + if (des_write_buf.data) + free(des_write_buf.data); + des_write_maxsize = des_write_buf.length; + if ((des_write_buf.data = malloc(des_write_maxsize)) == NULL) { + des_write_maxsize = 0; + return(-1); + } } - if (( krb5_encrypt(bsd_context, (krb5_pointer)buf, - desoutbuf.data, - len, - &eblock, - 0))){ + + if ((krb5_encrypt(bsd_context, (krb5_pointer)buf, des_write_buf.data, + len, &eblock, 0))) { return(-1); } @@ -1447,11 +1455,11 @@ int des_write(fd, buf, len) len_buf[1] = (len & 0xff0000) >> 16; len_buf[2] = (len & 0xff00) >> 8; len_buf[3] = (len & 0xff); - (void) write(fd, len_buf, 4); - if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){ + if ((write(fd, len_buf, 4) != 4) || (write(fd, des_write_buf.data, + des_write_buf.length) != des_write_buf.length)) { return(-1); } - else return(len); + return(len); } #endif /* KERBEROS */ diff --git a/src/appl/bsd/krlogin.c b/src/appl/bsd/krlogin.c index e8b205da8..831806c62 100644 --- a/src/appl/bsd/krlogin.c +++ b/src/appl/bsd/krlogin.c @@ -192,7 +192,7 @@ int flowcontrol; /* Since emacs can alter the the original characteristics */ int confirm = 0; /* ask if ~. is given before dying. */ int litout; -#ifdef hpux +#if defined(hpux) || defined(__hpux) char *speeds[] = { "0", "50", "75", "110", "134", "150", "200", "300", "600", "900", "1200", "1800", "2400", "3600", "4800", "7200", "9600", @@ -674,7 +674,7 @@ char deferase, defkill; #ifdef USE_TERMIO char defvtim, defvmin; -#ifdef hpux +#if defined(hpux) || defined(__hpux) #include <sys/bsdtty.h> #include <sys/ptyio.h> #endif @@ -952,12 +952,7 @@ int signo; if (pid < 0 || (pid == child && !WIFSTOPPED(status))) done(status); #else -#if defined(hpux) - /* I think this one is wrong: XXX -- [eichin:19940727.1853EST] */ - if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status.w_stopval)))) -#else if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status)))) -#endif done((int)(status.w_termsig | status.w_retcode)); #endif goto again; diff --git a/src/appl/bsd/krlogind.c b/src/appl/bsd/krlogind.c index 26fb2cd21..0a44c8deb 100644 --- a/src/appl/bsd/krlogind.c +++ b/src/appl/bsd/krlogind.c @@ -129,7 +129,7 @@ char copyright[] = #include <signal.h> -#ifdef hpux +#if defined(hpux) || defined(__hpux) #include <sys/ptyio.h> #endif #ifdef sysvimp @@ -181,11 +181,15 @@ char copyright[] = #include <sys/filio.h> #endif - #ifndef HAVE_KILLPG #define killpg(pid, sig) kill(-(pid), (sig)) #endif +#ifdef HAVE_PTSNAME +/* HP/UX 9.04 has but does not declare ptsname. */ +extern char *ptsname (); +#endif + #ifdef NO_WINSIZE struct winsize { unsigned short ws_row, ws_col; @@ -325,7 +329,7 @@ int main(argc, argv) progname = *argv; -pty_init(); + pty_init(); #ifndef LOG_NDELAY #define LOG_NDELAY 0 @@ -342,7 +346,6 @@ pty_init(); openlog(progname, LOG_PID | LOG_NDELAY, LOG_AUTH); #endif /* 4.2 syslog */ - /* Analyse parameters. */ opterr = 0; while ((ch = getopt(argc, argv, ARGSTR)) != EOF) @@ -619,7 +622,7 @@ int syncpipe[2]; new_termio.c_lflag |= (ICANON|ECHO|ISIG|IEXTEN); new_termio.c_iflag|= (IXON|IXANY|BRKINT|INLCR|ICRNL); #endif /*Do we need binary stream?*/ -new_termio.c_iflag &= ~(ISTRIP); + new_termio.c_iflag &= ~(ISTRIP); /* new_termio.c_iflag = 0; */ /* new_termio.c_oflag = 0; */ new_termio.c_cc[VMIN] = 1; @@ -821,7 +824,7 @@ int control(pty, cp, n) int n; { struct winsize w; - int pgrp; + int pgrp, got_pgrp; if (n < (int) 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') return (0); @@ -833,7 +836,13 @@ int control(pty, cp, n) w.ws_xpixel = ntohs(w.ws_xpixel); w.ws_ypixel = ntohs(w.ws_ypixel); (void)ioctl(pty, TIOCSWINSZ, &w); - if (ioctl(pty, TIOCGPGRP, &pgrp) >= 0) +#ifdef HAVE_TCGETPGRP + pgrp = tcgetpgrp (pty); + got_pgrp = pgrp != -1; +#else + got_pgrp = ioctl(pty, TIOCGPGRP, &pgrp) >= 0; +#endif + if (got_pgrp) (void) killpg(pgrp, SIGWINCH); #endif return (4+sizeof (w)); @@ -855,14 +864,14 @@ void protocol(f, p) struct sigaction sa; #endif #ifdef TIOCPKT - register tiocpkt_on = 0; - int on = 1; + register tiocpkt_on = 0; + int on = 1; #endif #if defined(TIOCPKT) && !defined(__svr4__) || defined(solaris20) - /* if system has TIOCPKT, try to turn it on. Some drivers + /* if system has TIOCPKT, try to turn it on. Some drivers * may not support it. Save flag for later. - */ + */ if ( ioctl(p, TIOCPKT, &on) < 0) tiocpkt_on = 0; else tiocpkt_on = 1; @@ -964,7 +973,7 @@ void protocol(f, p) else if (pcc <= 0) break; #ifdef TIOCPKT - else if (tiocpkt_on) { + else if (tiocpkt_on) { if (pibuf[0] == 0) pbp++, pcc--; else { @@ -974,7 +983,7 @@ void protocol(f, p) } pcc = 0; } - } + } #endif } if (FD_ISSET(f, &obits) && pcc > 0) { @@ -1444,7 +1453,7 @@ recvauth(valid_checksum) &auth_sys, /* which authentication system*/ &v4_kdata, v4_schedule, v4_version))) { - if (auth_sys == KRB5_RECVAUTH_V5) { + if (auth_sys == KRB5_RECVAUTH_V5) { /* * clean up before exiting */ diff --git a/src/appl/bsd/krsh.c b/src/appl/bsd/krsh.c index 88c630e23..0a59cb3dd 100644 --- a/src/appl/bsd/krsh.c +++ b/src/appl/bsd/krsh.c @@ -142,7 +142,7 @@ main(argc, argv0) #ifdef KERBEROS krb5_flags authopts; krb5_error_code status; - int fflag = 0, Fflag = 0, Aflag = 0; + int fflag = 0, Fflag = 0; #endif /* KERBEROS */ int debug_port = 0; @@ -226,7 +226,6 @@ main(argc, argv0) goto another; } if (argc > 0 && !strncmp(*argv, "-A", 2)) { - Aflag++; argv++, argc--; goto another; } @@ -355,7 +354,7 @@ main(argc, argv0) (struct sockaddr_in *) 0, (struct sockaddr_in *) 0, authopts, - Aflag); /* Any port #? */ + 1); /* Always set anyport, there is no need not to. --proven */ if (status) { /* check NO_TKT_FILE or equivalent... */ fprintf(stderr, diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c index b3e265692..64b1b2974 100644 --- a/src/appl/bsd/krshd.c +++ b/src/appl/bsd/krshd.c @@ -263,7 +263,8 @@ int main(argc, argv) secflag = sysconf(_SC_CRAY_SECURE_SYS); #endif - progname = *argv; + progname = strrchr (*argv, '/'); + progname = progname ? progname + 1 : *argv; #ifndef LOG_ODELAY /* 4.2 syslog */ openlog(progname, LOG_PID); @@ -415,8 +416,7 @@ int main(argc, argv) if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof (on)) < 0) - syslog(LOG_WARNING, - "setsockopt (SO_KEEPALIVE): %m"); + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); #if defined(BSD) && BSD+0 >= 43 linger.l_onoff = 1; linger.l_linger = 60; /* XXX */ @@ -1288,12 +1288,12 @@ if(port) int i; char *buf = (char *)malloc(strlen(getenv("KRB5CCNAME")) +strlen("KRB5CCNAME=")+1); - if (buf) { - sprintf(buf, "KRB5CCNAME=%s",getenv("KRB5CCNAME")); + if (buf) { + sprintf(buf, "KRB5CCNAME=%s",getenv("KRB5CCNAME")); - for (i = 0; envinit[i]; i++); - envinit[i] =buf; - } + for (i = 0; envinit[i]; i++); + envinit[i] =buf; + } } /* If we do anything else, make sure there is space in the array. */ diff --git a/src/appl/bsd/login.c b/src/appl/bsd/login.c index d1e98e23a..778d73d4e 100644 --- a/src/appl/bsd/login.c +++ b/src/appl/bsd/login.c @@ -27,19 +27,51 @@ char copyright[] = /* based on @(#)login.c 5.25 (Berkeley) 1/6/89 */ +/* While the code may be compiled with some of these options turned off, + the default will be to turn them *all* on if v4 compatibility is + available, and allow them to be configured via krb5.conf. */ +/* The configuration is of the form + [login] + # login stanza + krb5_get_tickets = 1 + # use password to get v5 tickets + krb4_get_tickets = 1 + # use password to get v4 tickets + krb4_convert = 1 + # use kerberos conversion daemon to get v4 tickets + krb_run_aklog = 1 + # attempt to run aklog + aklog_path = $(prefix)/bin/aklog + # where to find it [not yet implemented] + accept_passwd = 0 + # don't accept plaintext passwords [not yet implemented] +*/ +#define KRB5_GET_TICKETS +int login_krb5_get_tickets = 1; +#ifdef KRB5_KRB4_COMPAT +#define KRB4_GET_TICKETS +int login_krb4_get_tickets = 1; +#define KRB4_CONVERT +int login_krb4_convert = 1; +#define KRB_RUN_AKLOG +int login_krb_run_aklog = 1; +#endif /* KRB5_KRB4_COMPAT */ +int login_accept_passwd = 0; + /* * login [ name ] * login -r hostname (for rlogind) * login -h hostname (for telnetd, etc.) - * login -f name (for pre-authenticated login: datakit, xterm, etc.) + * login -f name (for pre-authenticated login: datakit, xterm, etc., + * does not allow preauthenticated login as root) * login -F name (for pre-authenticated login: datakit, xterm, etc., * allows preauthenticated login as root) * login -e name (for pre-authenticated encrypted, must do term * negotiation) - * ifdef KRB4 + * ifdef KRB4_KLOGIN * login -k hostname (for Kerberos V4 rlogind with password access) * login -K hostname (for Kerberos V4 rlogind with restricted access) - * endif KRB4 + * endif KRB4_KLOGIN * * only one of: -r -f -e -k -K -F * only one of: -r -h -k -K @@ -68,6 +100,8 @@ char copyright[] = #include <utmp.h> #include <signal.h> +#include <assert.h> + #ifdef HAVE_LASTLOG_H #include <lastlog.h> #endif @@ -87,13 +121,54 @@ char copyright[] = #include <stdio.h> #include <grp.h> #include <pwd.h> -#include <setjmp.h> #include <string.h> +#include <setjmp.h> +#ifndef POSIX_SETJMP +#undef sigjmp_buf +#undef sigsetjmp +#undef siglongjmp +#define sigjmp_buf jmp_buf +#define sigsetjmp(j,s) setjmp(j) +#define siglongjmp longjmp +#endif + +#ifdef POSIX_SIGNALS +typedef struct sigaction handler; +#define handler_init(H,F) (sigemptyset(&(H).sa_mask), \ + (H).sa_flags=0, \ + (H).sa_handler=(F)) +#define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD) +#define handler_set(S,OLD) sigaction(S, &OLD, NULL) +#else +typedef sigtype (*handler)(); +#define handler_init(H,F) ((H) = (F)) +#define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW))) +#define handler_set(S,OLD) (signal ((S), (OLD))) +#endif + + #ifdef HAVE_SHADOW #include <shadow.h> #endif +#ifdef KRB5_GET_TICKETS +/* #include "krb5.h" */ +/* need k5-int.h to get ->profile from krb5_context */ +#include "k5-int.h" +#include "osconf.h" +#endif /* KRB5_GET_TICKETS */ + +#ifdef KRB4_KLOGIN +/* support for running under v4 klogind, -k -K flags */ +#define KRB4 +#endif + +#ifdef KRB4_GET_TICKETS +/* support for prompting for v4 initial tickets */ +#define KRB4 +#endif + #ifdef KRB4 #include <krb.h> #include <netdb.h> @@ -106,6 +181,12 @@ char copyright[] = #endif /* BIND_HACK */ #endif /* KRB4 */ +#ifndef __STDC__ +#ifndef volatile +#define volatile +#endif +#endif + #include "loginpaths.h" #ifdef POSIX_TERMIOS @@ -144,15 +225,6 @@ char copyright[] = #define QUOTAWARN "/usr/ucb/quota" /* warn user about quotas */ #endif -#define PROTOTYPE_DIR "/usr/athena/lib/prototype_tmpuser" -#define TEMP_DIR_PERM 0711 - -#define NOATTACH "/etc/noattach" -#define NOCREATE "/etc/nocreate" -#define NOREMOTE "/etc/noremote" -#define REGISTER "/usr/etc/go_register" -#define GET_MOTD "/bin/athena/get_message" - #ifndef NO_UT_HOST #ifndef UT_HOSTSIZE /* linux defines it directly in <utmp.h> */ @@ -164,6 +236,11 @@ char copyright[] = #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) #endif +#ifndef HAVE_SETPRIORITY +/* if we don't have it, punt it cleanly */ +#define setpriority(which,who,prio) +#endif /* HAVE_SETPRIORITY */ + #define MAXENVIRON 32 /* @@ -172,44 +249,23 @@ char copyright[] = */ int timeout = 300; -struct passwd *pwd; -#ifdef HAVE_SHADOW -struct spwd *spwd; -#endif - char term[64], *hostname, *username; -#ifndef POSIX_TERMIOS -struct sgttyb sgttyb; -struct tchars tc = { - CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK -}; -struct ltchars ltc = { - CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT -}; -#endif +extern int errno; -#ifdef KRB4 +#ifdef KRB4_GET_TICKETS #define KRB_ENVIRON "KRBTKFILE" /* Ticket file environment variable */ #define KRB_TK_DIR "/tmp/tkt_" /* Where to put the ticket */ #define MAXPWSIZE 128 /* Biggest string accepted for KRB4 passsword */ - -AUTH_DAT *kdata = (AUTH_DAT *) NULL; -KTEXT ticket = (KTEXT) NULL; -char tkfile[MAXPATHLEN]; -int krbflag = 0; /* set if tickets have been obtained */ -#ifdef SETPAG -int pagflag = 0; /* true if setpag() has been called */ -#endif /* SETPAG */ -#endif /* KRB4 */ +#endif /* KRB4_GET_TICKETS */ char *getenv(); void dofork(); int doremotelogin(), do_krb_login(), rootterm(); -void lgetstr(), doremoteterm(), getloginname(), checknologin(), sleepexit(); -void dolastlog(), motd(); +void lgetstr(), getloginname(), checknologin(), sleepexit(); +void dolastlog(), motd(), check_mail(); #ifndef HAVE_STRSAVE char * strsave(); @@ -218,6 +274,783 @@ char * strsave(); typedef krb5_sigtype sigtype; +#ifndef HAVE_INITGROUPS +static int initgroups(char* name, gid_t basegid) { + gid_t others[NGROUPS_MAX+1]; + int ngrps; + + others[0] = basegid; + ngrps = getgroups(NGROUPS_MAX, others+1); + return setgroups(ngrps+1, others); +} +#endif + +#ifdef KRB5_GET_TICKETS +static struct login_confs { + char *flagname; + int *flag; +} login_conf_set[] = { + "krb5_get_tickets", &login_krb5_get_tickets, +#ifdef KRB5_KRB4_COMPAT + "krb4_get_tickets", &login_krb4_get_tickets, + "krb4_convert", &login_krb4_convert, + "krb4_run_aklog", &login_krb_run_aklog, +#endif /* KRB5_KRB4_COMPAT */ +}; +static char *conf_yes[] = { + "y", "yes", "true", "t", "1", "on", + 0 +}; +static char *conf_no[] = { + "n", "no", "false", "nil", "0", "off", + 0 +}; +/* 1 = true, 0 = false, -1 = ambiguous */ +static int conf_affirmative(s) + char *s; +{ + char **p; + for(p=conf_yes; *p; p++) { + if (!strcasecmp(*p,s)) + return 1; + } + for(p=conf_no; *p; p++) { + if (!strcasecmp(*p,s)) + return 0; + } + /* ambiguous */ + return -1; +} +#endif /* KRB5_GET_TICKETS */ + +#ifdef KRB5_GET_TICKETS +krb5_data tgtname = { + 0, + KRB5_TGS_NAME_SIZE, + KRB5_TGS_NAME +}; +#endif + +#ifdef KRB5_GET_TICKETS +/* get flags (listed above) from the profile */ +void login_get_kconf(k) + krb5_context k; +{ + int i, max_i; + const char* kconf_names[3]; + char **kconf_val; + int retval; + + max_i = sizeof(login_conf_set)/sizeof(struct login_confs); + for (i = 0; i<max_i; i++) { + kconf_names[0] = "login"; + kconf_names[1] = login_conf_set[i].flagname; + kconf_names[2] = 0; + retval = profile_get_values(k->profile, + kconf_names, &kconf_val); + if (retval) { + /* ignore most (all?) errors */ + } else if (kconf_val) { + switch(conf_affirmative(*kconf_val)) { + case 1: + *login_conf_set[i].flag = 1; + break; + case 0: + *login_conf_set[i].flag = 0; + break; + default: + case -1: + com_err("login/kconf", 0, + "invalid flag value %s for flag %s", + *kconf_val, kconf_names[1]); + break; + } + } + } +} +#endif /* KRB5_GET_TICKETS */ + + +/* UNIX password support */ + +struct passwd *pwd; +static char *salt; + +#ifdef HAVE_SHADOW +struct spwd *spwd; +#endif + +void lookup_user (name) + char *name; +{ + pwd = getpwnam (name); + salt = pwd ? pwd->pw_passwd : "xx"; +#ifdef HAVE_SHADOW + spwd = getspnam (name); + if (spwd) + salt = spwd->sp_pwdp; +#endif +} + +int unix_needs_passwd () +{ +#ifdef HAVE_SHADOW + if (spwd) + return spwd->sp_pwdp[0] != 0; +#endif + if (pwd) + return pwd->pw_passwd[0] != 0; + return 1; +} + +int unix_passwd_okay (pass) + char *pass; +{ + char user_pwcopy[9], *namep; + char *crypt (); + + assert (pwd != 0); + + /* copy the first 8 chars of the password for unix crypt */ + strncpy(user_pwcopy, pass, sizeof(user_pwcopy)); + user_pwcopy[8]='\0'; + namep = crypt(user_pwcopy, salt); + memset (user_pwcopy, 0, sizeof(user_pwcopy)); + /* ... and wipe the copy now that we have the string */ + + /* verify the local password string */ +#ifdef HAVE_SHADOW + if (spwd) + return !strcmp(namep, spwd->sp_pwdp); +#endif + return !strcmp (namep, pwd->pw_passwd); +} + +/* Kerberos support */ +#ifdef KRB5_GET_TICKETS +krb5_context kcontext; +krb5_ccache ccache; +static int got_v5_tickets, got_v4_tickets; +char ccfile[MAXPATHLEN+6]; /* FILE:path+\0 */ +int krbflag; /* set if tickets have been obtained */ + +#ifdef KRB4_GET_TICKETS +AUTH_DAT *kdata = (AUTH_DAT *) NULL; +KTEXT ticket = (KTEXT) NULL; +char tkfile[MAXPATHLEN]; +char realm[REALM_SZ]; +#endif + +void k_init (ttyn) + char *ttyn; +{ + krb5_init_context(&kcontext); + krb5_init_ets(kcontext); + login_get_kconf(kcontext); + + /* Set up the credential cache environment variable */ + if (!getenv(KRB5_ENV_CCNAME)) { + sprintf(ccfile, "FILE:/tmp/krb5cc_%s", strrchr(ttyn, '/')+1); + setenv(KRB5_ENV_CCNAME, ccfile, 1); + unlink(ccfile+strlen("FILE:")); + } else { + /* note it correctly */ + strcpy(ccfile, getenv(KRB5_ENV_CCNAME)); + } + +#ifdef KRB4_GET_TICKETS + if (krb_get_lrealm(realm, 1) != KSUCCESS) { + strncpy(realm, KRB_REALM, sizeof(realm)); + } + if (login_krb4_get_tickets) { + /* Set up the ticket file environment variable */ + strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile)); + strncat(tkfile, strrchr(ttyn, '/')+1, + sizeof(tkfile) - strlen(tkfile)); + (void) unlink (tkfile); + setenv(KRB_ENVIRON, tkfile, 1); + } +#endif + +#ifdef BIND_HACK + /* Set name server timeout to be reasonable, + so that people don't take 5 minutes to + log in. Can you say abstraction violation? */ + _res.retrans = 1; +#endif /* BIND_HACK */ +} + +int k5_get_password (user_pwstring, pwsize) + char *user_pwstring; +{ + krb5_error_code code; + char prompt[255]; + sprintf(prompt,"Password for %s: ", username); + + /* reduce opportunities to be swapped out */ + code = krb5_read_password(kcontext, prompt, 0, user_pwstring, &pwsize); + if (code || pwsize == 0) { + fprintf(stderr, "Error while reading password for '%s'\n", username); + /* reading password failed... */ + return 0; + } + if (pwsize == 0) { + fprintf(stderr, "No password read\n"); + /* reading password failed... */ + return 0; + } + return 1; +} + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ +int krb5_options = 0; +krb5_deltat krb5_ticket_lifetime = KRB5_DEFAULT_LIFE; + +int try_krb5 (me_p, pass) + krb5_principal *me_p; + char *pass; +{ + krb5_error_code code; + krb5_principal server, me; + krb5_creds my_creds; + krb5_timestamp now; + krb5_deltat lifetime = krb5_ticket_lifetime; + + /* set up credential cache -- obeying KRB5_ENV_CCNAME + set earlier */ + /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */ + if (code = krb5_cc_default(kcontext, &ccache)) { + com_err("login", code, "while getting default ccache"); + return 0; + } + /* setup code from v5 kinit */ + memset((char *)&my_creds, 0, sizeof(my_creds)); + + code = krb5_parse_name (kcontext, username, &me); + if (code) { + com_err ("login", code, "when parsing name %s",username); + return 0; + } + *me_p = my_creds.client = me; + + code = krb5_cc_initialize (kcontext, ccache, me); + if (code) { + com_err ("login", code, + "when initializing cache"); + return 0; + } + + code = krb5_build_principal_ext(kcontext, &server, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + tgtname.length, tgtname.data, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + 0); + if (code) { + com_err("login", code, + "while building server name"); + goto nuke_ccache; + } + + my_creds.server = server; + code = krb5_timeofday(kcontext, &now); + if (code) { + com_err("login", code, + "while getting time of day"); + goto nuke_ccache; + } + my_creds.times.starttime = 0; /* start timer when + request gets to KDC */ + my_creds.times.endtime = now + lifetime; + my_creds.times.renew_till = 0; + + code = krb5_get_in_tkt_with_password(kcontext, krb5_options, + 0, NULL, 0 /*preauth*/, + pass, + ccache, + &my_creds, 0); + + if (code) { + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) + fprintf (stderr, + "%s: Kerberos password incorrect\n", + username); + else + com_err ("login", code, + "while getting initial credentials"); + nuke_ccache: + krb5_cc_destroy (kcontext, ccache); + return 0; + } else { + /* get_name pulls out just the name not the + type */ + strcpy(ccfile, krb5_cc_get_name(kcontext, ccache)); + (void) chown(ccfile, pwd->pw_uid, pwd->pw_gid); + krbflag = got_v5_tickets = 1; + return 1; + } +} + +int have_v5_tickets (me) + krb5_principal *me; +{ + if (krb5_cc_default (kcontext, &ccache)) + return 0; + if (krb5_cc_get_principal (kcontext, ccache, me)) { + krb5_cc_close (kcontext, ccache); + return 0; + } + krbflag = 1; + return 1; +} + +#ifdef KRB4_CONVERT +try_convert524 (kcontext, me) + krb5_context kcontext; + krb5_principal me; +{ + krb5_principal kpcserver; + krb5_error_code kpccode; + int kpcval; + krb5_creds increds, *v5creds; + CREDENTIALS v4creds; + + if (!got_v5_tickets) + return 0; + + /* or do this directly with krb524_convert_creds_kdc */ + krb524_init_ets(kcontext); + /* cc->ccache, already set up */ + /* client->me, already set up */ + if ((kpccode = krb5_build_principal(kcontext, + &kpcserver, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + "krbtgt", + krb5_princ_realm(kcontext, me)->data, + NULL))) { + com_err("login/v4", kpccode, + "while creating service principal name"); + return 0; + } + + memset((char *) &increds, 0, sizeof(increds)); + increds.client = me; + increds.server = kpcserver; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((kpccode = krb5_get_credentials(kcontext, 0, + ccache, + &increds, + &v5creds))) { + com_err("login/v4", kpccode, + "getting V5 credentials"); + return 0; + } + if ((kpccode = krb524_convert_creds_kdc(kcontext, + v5creds, + &v4creds))) { + com_err("login/v4", kpccode, + "converting to V4 credentials"); + return 0; + } + /* this is stolen from the v4 kinit */ + /* initialize ticket cache */ + if ((kpcval = in_tkt(v4creds.pname,v4creds.pinst) + != KSUCCESS)) { + com_err("login/v4", kpcval, + "trying to create the V4 ticket file"); + return 0; + } + /* stash ticket, session key, etc. for future use */ + if ((kpcval = krb_save_credentials(v4creds.service, + v4creds.instance, + v4creds.realm, + v4creds.session, + v4creds.lifetime, + v4creds.kvno, + &(v4creds.ticket_st), + v4creds.issue_date))) { + com_err("login/v4", kpcval, + "trying to save the V4 ticket"); + return 0; + } + got_v4_tickets = 1; + strcpy(tkfile, tkt_string()); + (void) chown(tkfile, pwd->pw_uid, pwd->pw_gid); + return 1; +} +#endif + +#ifdef KRB4_GET_TICKETS +try_krb4 (me, user_pwstring) + krb5_principal me; + char *user_pwstring; +{ + int krbval, kpass_ok = 0; + + krbval = krb_get_pw_in_tkt(username, "", realm, + "krbtgt", realm, + DEFAULT_TKT_LIFE, + user_pwstring); + + switch (krbval) { + case INTK_OK: + kpass_ok = 1; + krbflag = 1; + strcpy(tkfile, tkt_string()); + (void) chown(tkfile, pwd->pw_uid, pwd->pw_gid); + break; + /* These errors should be silent */ + /* So the Kerberos database can't be probed */ + case KDC_NULL_KEY: + case KDC_PR_UNKNOWN: + case INTK_BADPW: + case KDC_PR_N_UNIQUE: + case -1: + break; +#if 0 /* I want to see where INTK_W_NOTALL comes from before letting + kpass_ok be set in that case. KR */ + /* These should be printed but are not fatal */ + case INTK_W_NOTALL: + krbflag = 1; + kpass_ok = 1; + fprintf(stderr, "Kerberos error: %s\n", + krb_get_err_text(krbval)); + break; +#endif + default: + fprintf(stderr, "Kerberos error: %s\n", + krb_get_err_text(krbval)); + break; + } + got_v4_tickets = kpass_ok; + return kpass_ok; +} +#endif /* KRB4_GET_TICKETS */ + +/* Kerberos ticket-handling routines */ + +#ifdef KRB4_GET_TICKETS +/* call already conditionalized on login_krb4_get_tickets */ +/* + * Verify the Kerberos ticket-granting ticket just retrieved for the + * user. If the Kerberos server doesn't respond, assume the user is + * trying to fake us out (since we DID just get a TGT from what is + * supposedly our KDC). If the rcmd.<host> service is unknown (i.e., + * the local srvtab doesn't have it), let her in. + * + * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ +int verify_krb_v4_tgt (realm) + char *realm; +{ + char hostname[MAXHOSTNAMELEN], phost[BUFSIZ]; + struct hostent *hp; + KTEXT_ST ticket; + AUTH_DAT authdata; + unsigned long addr; + static /*const*/ char rcmd[] = "rcmd"; + char key[8]; + int krbval, retval, have_keys; + + if (gethostname(hostname, sizeof(hostname)) == -1) { + perror ("cannot retrieve local hostname"); + return -1; + } + strncpy (phost, krb_get_phost (hostname), sizeof (phost)); + phost[sizeof(phost)-1] = 0; + hp = gethostbyname (hostname); + if (!hp) { + perror ("cannot retrieve local host address"); + return -1; + } + memcpy ((char *) &addr, (char *)hp->h_addr, sizeof (addr)); + /* Do we have rcmd.<host> keys? */ +#if 0 /* Be paranoid. If srvtab exists, assume it must contain the + right key. */ + have_keys = read_service_key (rcmd, phost, realm, 0, KEYFILE, key) + ? 0 : 1; + memset (key, 0, sizeof (key)); +#else + have_keys = 0 == access (KEYFILE, F_OK); +#endif + krbval = krb_mk_req (&ticket, rcmd, phost, realm, 0); + if (krbval == KDC_PR_UNKNOWN) { + /* + * Our rcmd.<host> principal isn't known -- just assume valid + * for now? This is one case that the user _could_ fake out. + */ + if (have_keys) + return -1; + else + return 0; + } + else if (krbval != KSUCCESS) { + printf ("Unable to verify Kerberos TGT: %s\n", + krb_get_err_text(krbval)); +#ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s", + krb_get_err_text(krbval)); +#endif + return -1; + } + /* got ticket, try to use it */ + krbval = krb_rd_req (&ticket, rcmd, phost, addr, &authdata, ""); + if (krbval != KSUCCESS) { + if (krbval == RD_AP_UNDEC && !have_keys) + retval = 0; + else { + retval = -1; + printf ("Unable to verify `rcmd' ticket: %s\n", + krb_get_err_text(krbval)); + } +#ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n", + krb_get_err_text(krbval), + retval + ? "srvtab found, assuming failure" + : "no srvtab found, assuming success"); +#endif + goto EGRESS; + } + /* + * The rcmd.<host> ticket has been received _and_ verified. + */ + retval = 1; + /* do cleanup and return */ +EGRESS: + memset (&ticket, 0, sizeof (ticket)); + memset (&authdata, 0, sizeof (authdata)); + return retval; +} +#endif /* KRB4_GET_TICKETS */ + +/* call already conditionalized on login_krb5_get_tickets */ +/* + * Verify the Kerberos ticket-granting ticket just retrieved for the + * user. If the Kerberos server doesn't respond, assume the user is + * trying to fake us out (since we DID just get a TGT from what is + * supposedly our KDC). If the host/<host> service is unknown (i.e., + * the local keytab doesn't have it), let her in. + * + * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ +int verify_krb_v5_tgt (c, realm) + krb5_context c; + char *realm; +{ + char phost[BUFSIZ]; + krb5_ccache ccdef; + int retval, have_keys; + krb5_principal princ; + krb5_keyblock *kb = 0; + krb5_error_code krbval; + krb5_data packet; + krb5_auth_context auth_context = NULL; + krb5_ticket *ticket = NULL; + + /* XXX This is to work around a library bug. I'm not sure if it's + been fixed for beta-6, so leave this in for now. Remove it (and + fix the bug if necessary) after beta-6 ships. */ + sleep(2); + + /* get the server principal for the local host */ + /* (use defaults of "host" and canonicalized local name) */ + krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ); + if (krbval) { + com_err ("login", krbval, "constructing local service name"); + return -1; + } + + /* since krb5_sname_to_principal has done the work for us, just + extract the name directly */ + strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ); + + /* Do we have host/<host> keys? */ + /* (use default keytab, kvno IGNORE_VNO to get the first match, + and enctype is currently ignored anyhow.) */ + krbval = krb5_kt_read_service_key (c, NULL, princ, 0, ENCTYPE_DES_CBC_CRC, &kb); + if (kb) + krb5_free_keyblock (c, kb); + /* any failure means we don't have keys at all. */ + have_keys = krbval ? 0 : 1; + + /* set up credential cache -- obeying KRB5_ENV_CCNAME set earlier */ + /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */ + if (krbval = krb5_cc_default(c, &ccdef)) { + com_err("login", krbval, "while getting default ccache"); + return -1; + } + /* talk to the kdc and construct the ticket */ + krbval = krb5_mk_req(c, &auth_context, 0, "host", phost, + 0, ccdef, &packet); + /* wipe the auth context for mk_req */ + if (auth_context) { + krb5_auth_con_free(c, auth_context); + auth_context = NULL; + } + if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { + /* we have a service key, so something should be + in the database, therefore this error packet could + have come from an attacker. */ + if (have_keys) { retval = -1; goto EGRESS; } + /* but if it is unknown and we've got no key, we don't + have any security anyhow, so it is ok. */ + else { retval = 0; goto EGRESS; } + } + else if (krbval) { + com_err("login", krbval, + "Unable to verify Kerberos V5 TGT: %s", phost); +#ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "Kerberos V5 TGT bad: %s", + error_message(krbval)); +#endif + retval = -1; + goto EGRESS; + } + /* got ticket, try to use it */ + krbval = krb5_rd_req(c, &auth_context, &packet, + princ, NULL, NULL, &ticket); + if (krbval) { + if (!have_keys) + /* The krb5 errors aren't specified well, but I think + these values cover the cases we expect. */ + switch (krbval) { + /* no keytab */ + case ENOENT: + /* keytab found, missing entry */ +#if 0 /* Don't depend on the nameserver for security. Assume that if + we have a keytab, it must contain the right host/FQDN key. */ + case KRB5_KT_NOTFOUND: +#endif + retval = 0; + break; + default: + /* unexpected error: fail */ + retval = -1; + break; + } + else + /* Any error here is bad. */ + retval = -1; + com_err("login", krbval, "Unable to verify host ticket"); +#ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "can't verify v5 ticket: %s; %s\n", + error_message(krbval), + retval + ? "keytab found, assuming failure" + : "no keytab found, assuming success"); +#endif + goto EGRESS; + } + /* + * The host/<host> ticket has been received _and_ verified. + */ + retval = 1; + /* do cleanup and return */ +EGRESS: + if (auth_context) krb5_auth_con_free(c, auth_context); + krb5_free_principal(c, princ); + /* possibly ticket and packet need freeing here as well */ + /* memset (&ticket, 0, sizeof (ticket)); */ + return retval; +} + +destroy_tickets() +{ + krb5_context c; + krb5_ccache cache; + + if (login_krb5_get_tickets) { + krb5_init_context(&c); + + if(!krb5_cc_default(c, &cache)) + krb5_cc_destroy (c, cache); + } +#ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets) + dest_tkt(); +#endif /* KRB4_GET_TICKETS */ +} + +#endif /* KRB5_GET_TICKETS */ + +/* AFS support routines */ +#ifdef SETPAG + +int pagflag = 0; /* true if setpag() has been called */ + +static sigjmp_buf setpag_buf; + +static sigtype sigsys () +{ + siglongjmp(setpag_buf, 1); +} + +static int try_afscall () +{ + handler sa, osa; + volatile int retval = 0; + + (void) &retval; + handler_init (sa, sigsys); + handler_swap (SIGSYS, sa, osa); + if (sigsetjmp(setpag_buf, 1) == 0) { + setpag (); + retval = 1; + } + handler_set (SIGSYS, osa); + return retval; +} + +/* This doesn't seem to be declared in the AFS header files. */ +extern ktc_ForgetAllTokens (), setpag (); + +#define try_setpag() try_afscall(setpag) +#define try_unlog() try_afscall(ktc_ForgetAllTokens) +#endif /* SETPAG */ + +void +afs_login () +{ +#ifdef KRB4_GET_TICKETS +#ifdef SETPAG + if (login_krb4_get_tickets && pwd->pw_uid) { + /* Only reset the pag for non-root users. */ + /* This allows root to become anything. */ + pagflag = try_setpag (); + } +#endif +#endif /* KRB4_GET_TICKETS */ +#ifdef KRB_RUN_AKLOG + if (got_v4_tickets && login_krb_run_aklog) { + /* KPROGDIR is $(prefix)/bin */ + char aklog_path[MAXPATHLEN]; + struct stat st; + /* construct the name */ + /* get this from profile later */ + strcpy (aklog_path, KPROGDIR); + strcat (aklog_path, "/aklog"); + /* only run it if we can find it */ + if (stat (aklog_path, &st) == 0) { + system(aklog_path); + } + } +#endif /* KRB_RUN_AKLOG */ +} + +void +afs_cleanup () +{ +#ifdef SETPAG + if (pagflag) + try_unlog (); +#endif +} + +/* Main routines */ #define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag || fflag || Fflag ) { \ fprintf(stderr, \ "login: only one of -r, -k, -K, -e, -F, and -f allowed.\n"); \ @@ -230,16 +1063,54 @@ typedef krb5_sigtype sigtype; exit(1);\ } -#ifndef HAVE_INITGROUPS -int initgroups(char* name, gid_t basegid) { - gid_t others[NGROUPS_MAX+1]; - int ngrps; - - others[0] = basegid; - ngrps = getgroups(NGROUPS_MAX, others+1); - return setgroups(ngrps+1, others); +static void +read_env_vars_from_file (filename) + char *filename; +{ + FILE *fp; + char *p, *eq; + char tbuf[MAXPATHLEN+2]; + + if ((fp = fopen("/etc/environment", "r")) != NULL) { + while (fgets(tbuf, sizeof(tbuf), fp)) { + if (tbuf[0] == '#') + continue; + eq = strchr(tbuf, '='); + if (eq == 0) + continue; + p = strchr (tbuf, '\n'); + if (p) + *p = 0; + *eq++ = 0; + /* Don't override, in case -p was used. */ + setenv (tbuf, eq, 0); + } + fclose(fp); + } } + +static void +log_repeated_failures (tty, hostname) + char *tty, *hostname; +{ + if (hostname) { +#ifdef UT_HOSTSIZE + syslog(LOG_ERR, + "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", + tty, UT_HOSTSIZE, hostname, UT_NAMESIZE, + username); +#else + syslog(LOG_ERR, + "REPEATED LOGIN FAILURES ON %s FROM %s, %.*s", + tty, hostname, UT_NAMESIZE, + username); #endif + } + else + syslog(LOG_ERR, + "REPEATED LOGIN FAILURES ON %s, %.*s", + tty, UT_NAMESIZE, username); +} int main(argc, argv) int argc; @@ -248,46 +1119,34 @@ int main(argc, argv) extern int optind; extern char *optarg, **environ; struct group *gr; - register int ch, i; - register char *p; + int ch; + char *p; int fflag, hflag, pflag, rflag, Fflag, cnt; int kflag, Kflag, eflag; int quietlog, passwd_req, ioctlval; sigtype timedout(); - char *domain, *salt, **envinit, *ttyn, *tty; + char *domain, **envinit, *ttyn, *tty; char tbuf[MAXPATHLEN + 2]; char *ttyname(), *stypeof(), *crypt(), *getpass(); time_t login_time; + int retval; +#ifdef KRB5_GET_TICKETS + krb5_principal me; +#endif /* KRB5_GET_TICKETS */ char *ccname = 0; /* name of forwarded cache */ -int retval; - + char *tz = 0; + off_t lseek(); -#ifdef POSIX_TERMIOS - struct termios tc; -#endif -#ifdef POSIX_SIGNALS - struct sigaction sa; -#endif + handler sa; -#ifdef POSIX_SIGNALS - (void)sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = timedout; - (void)sigaction(SIGALRM, &sa, (struct sigaction *)0); -#else - (void)signal(SIGALRM, timedout); -#endif + handler_init (sa, timedout); + handler_set (SIGALRM, sa); (void)alarm((u_int)timeout); -#ifdef POSIX_SIGNALS - sa.sa_handler = SIG_IGN; - (void)sigaction(SIGALRM, &sa, (struct sigaction *)0); -#else - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); -#endif -#ifdef HAVE_SETPRIORITY - (void)setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); -#endif + + handler_init (sa, SIG_IGN); + handler_set (SIGQUIT, sa); + handler_set (SIGINT, sa); + setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); #ifdef OQUOTA (void)quota(Q_SETUID, 0, 0, 0); #endif @@ -356,7 +1215,7 @@ int retval; *p = '\0'; hostname = optarg; break; -#ifdef KRB4 +#ifdef KRB4_KLOGIN case 'k': case 'K': EXCL_AUTH_TEST; @@ -382,7 +1241,7 @@ int retval; *p = '\0'; hostname = optarg; break; -#endif /* KRB4 */ +#endif /* KRB4_KLOGIN */ case 'e': EXCL_AUTH_TEST; if (getuid()) { @@ -422,85 +1281,14 @@ int retval; #endif (void)fcntl(0, F_SETFL, ioctlval); -#ifdef POSIX_TERMIOS - (void)tcgetattr(0, &tc); -#else - (void)ioctl(0, TIOCGETP, (char *)&sgttyb); -#endif - /* * If talking to an rlogin process, propagate the terminal type and * baud rate across the network. */ if (eflag) lgetstr(term, sizeof(term), "Terminal type"); -#ifdef POSIX_TERMIOS - if (rflag || kflag || Kflag || eflag) - doremoteterm(&tc); - tc.c_cc[VMIN] = 1; - tc.c_cc[VTIME] = 0; -#ifndef NO_INIT_CC - tc.c_cc[VERASE] = CERASE; - tc.c_cc[VKILL] = CKILL; - tc.c_cc[VEOF] = CEOF; - tc.c_cc[VINTR] = CINTR; - tc.c_cc[VQUIT] = CQUIT; - tc.c_cc[VSTART] = CSTART; - tc.c_cc[VSTOP] = CSTOP; -#ifndef CNUL -#define CNUL CEOL -#endif - tc.c_cc[VEOL] = CNUL; - /* The following are common extensions to POSIX */ -#ifdef VEOL2 - tc.c_cc[VEOL2] = CNUL; -#endif -#ifdef VSUSP -#if !defined(CSUSP) && defined(CSWTCH) -#define CSUSP CSWTCH -#endif - tc.c_cc[VSUSP] = CSUSP; -#endif -#ifdef VDSUSP - tc.c_cc[VDSUSP] = CDSUSP; -#endif -#ifdef VLNEXT - tc.c_cc[VLNEXT] = CLNEXT; -#endif -#ifdef VREPRINT - tc.c_cc[VREPRINT] = CRPRNT; -#endif -#ifdef VDISCRD - tc.c_cc[VDISCRD] = CFLUSH; -#endif -#ifdef VDISCARD -#ifndef CDISCARD -#define CDISCARD CFLUSH -#endif - tc.c_cc[VDISCARD] = CDISCARD; -#endif -#ifdef VWERSE - tc.c_cc[VWERSE] = CWERASE; -#endif -#ifdef VWERASE - tc.c_cc[VWERASE] = CWERASE; -#endif -#ifdef VSTATUS -#ifdef CSTATUS - tc.c_cc[VSTATUS] = CSTATUS; -#endif /* CSTATUS */ -#endif /* VSTATUS */ -#endif /* NO_INIT_CC */ - tcsetattr(0, TCSANOW, &tc); -#else - if (rflag || kflag || Kflag || eflag) - doremoteterm(&sgttyb); - sgttyb.sg_erase = CERASE; - sgttyb.sg_kill = CKILL; - (void)ioctl(0, TIOCSLTC, (char *)<c); - (void)ioctl(0, TIOCSETC, (char *)&tc); - (void)ioctl(0, TIOCSETP, (char *)&sgttyb); -#endif + term_init (rflag || kflag || Kflag || eflag); + for (cnt = getdtablesize(); cnt > 2; cnt--) (void) close(cnt); @@ -520,36 +1308,35 @@ int retval; openlog("login", LOG_ODELAY, LOG_AUTH); #endif /* 4.2 syslog */ +/******* begin askpw *******/ + /* overall: + ask for username if we don't have it already + look it up in local pw or shadow file (to get crypt string) + ask for password + try and get v4, v5 tickets with it + try and use the tickets against the local srvtab + if the password matches, always let them in + if the ticket decrypts, let them in. + v5 needs to work, does v4? + */ + +#ifdef KRB5_GET_TICKETS + k_init (ttyn); +#endif + for (cnt = 0;; username = NULL) { -#ifdef KRB4 - char pp[9], pp2[MAXPWSIZE], *namep; - int krbval; - char realm[REALM_SZ]; +#ifdef KRB5_GET_TICKETS int kpass_ok,lpass_ok; -#ifdef NOENCRYPTION -#define read_long_pw_string placebo_read_pw_string -#else -#define read_long_pw_string des_read_pw_string -#endif - int read_long_pw_string(); -#endif /* KRB4 */ -#if defined(TIOCSETD)&&(!defined(POSIX_TERMIOS)) - ioctlval = 0; - (void)ioctl(0, TIOCSETD, (char *)&ioctlval); -#endif + char user_pwstring[MAXPWSIZE]; + /* variables from v5 kinit */ +#endif /* KRB5_GET_TICKETS */ + if (username == NULL) { fflag = Fflag = 0; getloginname(); } - if ((pwd = getpwnam(username))) - salt = pwd->pw_passwd; - else - salt = "xx"; -#ifdef HAVE_SHADOW - if (spwd = getspnam(username)) - salt = spwd->sp_pwdp; -#endif + lookup_user (username); /* sets pwd */ /* if user not super-user, check for disabled logins */ if (pwd == NULL || pwd->pw_uid) @@ -580,96 +1367,56 @@ int retval; * If no remote login authentication and a password exists * for this user, prompt for one and verify it. */ - if (!passwd_req) break; -#ifdef HAVE_SHADOW - if (spwd) { - if (!*(spwd->sp_pwdp)) break; - } else -#endif - if (pwd && !*(pwd->pw_passwd)) - break; + if (!passwd_req) + break; -#ifdef KRB4 + if (! unix_needs_passwd ()) + break; + + /* we have several sets of code: + 1) get v5 tickets alone -DKRB5_GET_TICKETS + 2) get v4 tickets alone [** don't! only get them *with* v5 **] + 3) get both tickets -DKRB5_GET_TICKETS -DKRB4_GET_TICKETS + 3a) use krb524 calls to get the v4 tickets -DKRB4_CONVERT plus (3). + 4) get no tickets and use the password file (none of thes defined.) + + Likewise we need to (optionally?) test these tickets against local srvtabs. + */ +#ifdef KRB5_GET_TICKETS + if (login_krb5_get_tickets) { + /* rename these to something more verbose */ kpass_ok = 0; lpass_ok = 0; -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET); -#endif - if (read_long_pw_string(pp2, sizeof(pp2)-1, "Password: ", 0)) { - /* reading password failed... */ -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); -#endif + setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET); + if (! k5_get_password (user_pwstring, sizeof (user_pwstring))) { goto bad_login; } - if (!pwd) /* avoid doing useless work */ - goto bad_login; - /* Modifications for Kerberos authentication -- asp */ - (void) strncpy(pp, pp2, sizeof(pp)); - pp[8]='\0'; - namep = crypt(pp, salt); - memset (pp, 0, sizeof(pp)); /* To the best of my recollection, Senator... */ + /* now that we have the password, we've obscured things + sufficiently, and can avoid trying tickets */ + if (!pwd) + goto bad_login; + + lpass_ok = unix_passwd_okay (user_pwstring); -#ifdef HAVE_SHADOW - if (spwd) - lpass_ok = !strcmp(namep, spwd->sp_pwdp); - else -#endif - lpass_ok = !strcmp (namep, pwd->pw_passwd); - if (pwd->pw_uid != 0) { /* Don't get tickets for root */ + try_krb5 (&me, user_pwstring); - if (krb_get_lrealm(realm, 1) != KSUCCESS) { - (void) strncpy(realm, KRB_REALM, sizeof(realm)); - } -#ifdef BIND_HACK - /* Set name server timeout to be reasonable, - so that people don't take 5 minutes to - log in. Can you say abstraction violation? */ - _res.retrans = 1; -#endif /* BIND_HACK */ +#ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets + && (!got_v5_tickets + || !login_krb4_convert)) + try_krb4 (me, user_pwstring); +#endif + krbflag = got_v5_tickets || got_v4_tickets; + memset (user_pwstring, 0, sizeof(user_pwstring)); + /* password wiped, so we can relax */ + setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); - krbval = krb_get_pw_in_tkt(username, "", realm, "krbtgt", - realm, DEFAULT_TKT_LIFE, pp2); - memset (pp2, 0, sizeof(pp2)); -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); -#endif - switch (krbval) { - case INTK_OK: - kpass_ok = 1; - krbflag = 1; - strcpy(tkfile, tkt_string()); - (void) chown(tkfile, pwd->pw_uid, pwd->pw_gid); - break; - - /* These errors should be silent */ - /* So the Kerberos database can't be probed */ - case KDC_NULL_KEY: - case KDC_PR_UNKNOWN: - case INTK_BADPW: - case KDC_PR_N_UNIQUE: - case -1: - break; - /* These should be printed but are not fatal */ - case INTK_W_NOTALL: - krbflag = 1; - kpass_ok = 1; - fprintf(stderr, "Kerberos error: %s\n", - krb_err_txt[krbval]); - break; - default: - fprintf(stderr, "Kerberos error: %s\n", - krb_err_txt[krbval]); - break; - } } else { - (void) memset (pp2, 0, sizeof(pp2)); -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); -#endif + memset (user_pwstring, 0, sizeof(user_pwstring)); + setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); } /* Policy: If local password is good, user is good. @@ -682,52 +1429,41 @@ int retval; if (kpass_ok) */ if (lpass_ok) - break; -bad_login: - if (krbflag) - dest_tkt(); /* clean up tickets if login fails */ -#else /* !KRB4 */ -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET); -#endif - p = crypt(getpass("Password:"), salt); -#ifdef HAVE_SETPRIORITY - (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); -#endif -#ifdef HAVE_SHADOW - if (spwd && !strcmp(p, spwd->sp_pwdp)) - break; - else -#endif - if (pwd && !strcmp(p, pwd->pw_passwd)) break; -#endif /* KRB4 */ + if (got_v5_tickets + && verify_krb_v5_tgt(kcontext, realm) != -1) + break; /* we're ok */ +#ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets) { + if (got_v4_tickets + && ! got_v5_tickets + && verify_krb_v4_tgt(realm) != -1) + break; /* we're ok */ + } +#endif /* KRB4_GET_TICKETS */ + bad_login: + setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); + if (krbflag) + destroy_tickets(); /* clean up tickets if login fails */ + } +#endif /* KRB5_GET_TICKETS */ +#ifdef OLD_PASSWD + p = getpass ("Password:"); + /* conventional password only */ + if (unix_passwd_okay (p)) + break; +#endif /* OLD_PASSWD */ printf("Login incorrect\n"); if (++cnt >= 5) { - if (hostname) -#ifdef UT_HOSTSIZE - syslog(LOG_ERR, - "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", - tty, UT_HOSTSIZE, hostname, UT_NAMESIZE, - username); -#else - syslog(LOG_ERR, - "REPEATED LOGIN FAILURES ON %s FROM %s, %.*s", - tty, hostname, UT_NAMESIZE, - username); -#endif - else - syslog(LOG_ERR, - "REPEATED LOGIN FAILURES ON %s, %.*s", - tty, UT_NAMESIZE, username); + log_repeated_failures (tty, hostname); /* irix has no tichpcl */ #ifdef TIOCHPCL (void)ioctl(0, TIOCHPCL, (char *)0); #endif sleepexit(1); } - } + } /* end of password retry loop */ /* committed to login -- turn off timeout */ (void)alarm((u_int)0); @@ -770,7 +1506,6 @@ bad_login: sleepexit(0); } #endif - if (chdir(pwd->pw_dir) < 0) { printf("No directory %s!\n", pwd->pw_dir); if (chdir("/")) @@ -801,17 +1536,26 @@ bad_login: (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); (void)chmod(ttyn, 0620); -#ifdef KRB4 -#ifdef SETPAG - if (pwd->pw_uid) { - /* Only reset the pag for non-root users. */ - /* This allows root to become anything. */ - pagflag = 1; - setpag(); + +#ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets && login_krb4_convert && !got_v4_tickets) { + + /* Maybe telnetd got tickets for us? */ + if (!got_v5_tickets && have_v5_tickets (&me)) + got_v5_tickets = 1; + + if (got_v5_tickets) + try_convert524 (kcontext, me); + } #endif - /* Fork so that we can call kdestroy */ - dofork(); + +#ifdef KRB5_GET_TICKETS + if (login_krb4_get_tickets || login_krb5_get_tickets) { + /* Fork so that we can call kdestroy */ + dofork(); + } +#endif /* KRB4_GET_TICKETS */ /* If the user's shell does not do job control we should put it in a different process group than than us, and set the tty process group @@ -819,25 +1563,48 @@ bad_login: telnetd or rlogind if they don't properly detach from their controlling tty, which is the case (under SunOS at least.) */ - { int p = getpid(); - if (setpgrp(p,p) < 0) perror("login.krb5: setpgrp"); - if (ioctl(0, TIOCSPGRP, &p) < 0) perror("login.krb5: tiocspgrp"); - } - -/* SunOS has an ioctl which can set the controlling tty and make sure - that no other process also has it. That's exactly what we want to - do for the shell we are about to exec, since it is the documented - way to avoid the problem noted just above. */ + { + int p = getpid(); + struct sigaction sa, osa; -#ifdef sun -#ifdef TIOCSCTTY - { if (setsid() < 0) perror("login.krb5: setsid"); - if (ioctl(0, TIOCSCTTY, 1) < 0) perror("login.krb5: tiocsctty"); - } + /* this will set the PGID to the PID. */ +#ifdef HAVE_SETPGID + if (setpgid(p,p) < 0) perror("login.krb5: setpgid"); +#else +#ifdef SETPGRP_TWOARG + if (setpgrp(p,p) < 0) perror("login.krb5: setpgrp"); +#else + if (setpgrp() < 0) perror("login.krb5: setpgrp"); #endif #endif -#endif /* KRB4 */ + /* This will cause SIGTTOU to be ignored for the duration + of the TIOCSPGRP. If this is not done, and the parent's + process group is the foreground pgrp of the tty, then + this will suspend the child, which is bad. */ + + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + sigemptyset(&(sa.sa_mask)); + + if (sigaction(SIGTTOU, &sa, &osa)) + perror("login.krb5: sigaction(SIGTTOU, SIG_IGN)"); + + /* This will set the foreground process group of the + controlling terminal to this process group (containing + only this process). */ +#ifdef HAVE_TCSETPGRP + if (tcsetpgrp(0, p) < 0) perror("login.krb5: tcsetpgrp"); +#else + if (ioctl(0, TIOCSPGRP, &p) < 0) perror("login.krb5: tiocspgrp"); +#endif + + /* This will reset the SIGTTOU handler */ + + if (sigaction(SIGTTOU, &osa, NULL)) + perror("login.krb5: sigaction(SIGTTOU, [old handler])"); + } + (void)setgid((gid_t) pwd->pw_gid); (void) initgroups(username, pwd->pw_gid); @@ -872,69 +1639,41 @@ bad_login: pwd->pw_shell = BSHELL; #if defined(NTTYDISC) && defined(TIOCSETD) /* turn on new line discipline for the csh */ - else if (!strcmp(pwd->pw_shell, "/bin/csh")) { + if (!strcmp(pwd->pw_shell, "/bin/csh")) { ioctlval = NTTYDISC; (void)ioctl(0, TIOCSETD, (char *)&ioctlval); } #endif ccname = getenv("KRB5CCNAME"); /* save cache */ + tz = getenv("TZ"); /* and time zone */ /* destroy environment unless user has requested preservation */ - envinit = (char **)malloc(MAXENVIRON * sizeof(char *)); - if (envinit == 0) { + if (!pflag) { + envinit = (char **)malloc(MAXENVIRON * sizeof(char *)); + if (envinit == 0) { fprintf(stderr, "Can't malloc empty environment.\n"); sleepexit(1); + } + envinit[0] = NULL; + environ = envinit; } - if (!pflag) - environ = envinit; - i = 0; + setenv ("LOGNAME", pwd->pw_name, 1); + setenv ("LOGIN", pwd->pw_name, 1); -#ifdef _IBMR2 - { - FILE *fp; - if ((fp = fopen("/etc/environment", "r")) != NULL) { - while(fgets(tbuf, sizeof(tbuf), fp)) { - if ((tbuf[0] == '#') || (strchr(tbuf, '=') == 0)) - continue; - for (p = tbuf; *p; p++) - if (*p == '\n') { - *p = '\0'; - break; - } - envinit[i++] = strsave(tbuf); - } - fclose(fp); - } - } -#endif -/* Set login timezone for date information (PDG) */ -#ifdef __sgi__ - { - FILE *fp; - if ((fp = fopen("/etc/TIMEZONE", "r")) != NULL) { - while(fgets(tbuf, sizeof(tbuf), fp)) { - if ((tbuf[0] == '#') || (strchr(tbuf, '=') == 0)) - continue; - for (p = tbuf; *p; p++) - if (*p == '\n') { - *p = '\0'; - break; - } - envinit[i++] = strsave(tbuf); - } - fclose(fp); - } - } + /* read the /etc/environment file on AIX */ +#ifdef HAVE_ETC_ENVIRONMENT + read_env_vars_from_file ("/etc/environment"); #endif - sprintf(tbuf,"LOGNAME=%s",pwd->pw_name); - envinit[i++] = strsave(tbuf); - sprintf(tbuf,"LOGIN=%s",pwd->pw_name); - envinit[i++] = strsave(tbuf); - - envinit[i++] = NULL; + /* Set login timezone for date information (sgi PDG) */ +#ifdef HAVE_ETC_TIMEZONE + read_env_vars_from_file ("/etc/TIMEZONE"); +#else + if (tz) + setenv ("TZ", tz, 0); +#endif if (ccname) setenv("KRB5CCNAME", ccname, 0); @@ -946,24 +1685,24 @@ bad_login: if (term[0] == '\0') (void) strncpy(term, stypeof(tty), sizeof(term)); - (void)setenv("TERM", term, 0); -#ifdef KRB4 + if (term[0]) + (void)setenv("TERM", term, 0); +#ifdef KRB4_GET_TICKETS /* tkfile[0] is only set if we got tickets above */ - if (tkfile[0]) + if (login_krb4_get_tickets && tkfile[0]) (void) setenv(KRB_ENVIRON, tkfile, 1); -#endif /* KRB4 */ - -#if 0 - strcpy(wgfile, "/tmp/wg.XXXXXX"); - mktemp(wgfile); - setenv("WGFILE", wgfile, 0); -#endif +#endif /* KRB4_GET_TICKETS */ +#ifdef KRB5_GET_TICKETS + /* ccfile[0] is only set if we got tickets above */ + if (login_krb5_get_tickets && ccfile[0]) + (void) setenv(KRB5_ENV_CCNAME, ccfile, 1); +#endif /* KRB5_GET_TICKETS */ if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); if (pwd->pw_uid == 0) if (hostname) -#ifdef KRB4 +#ifdef KRB4_KLOGIN if (kdata) { /* @*$&@#*($)#@$ syslog doesn't handle very many arguments */ @@ -983,7 +1722,7 @@ bad_login: #endif syslog(LOG_NOTICE, "%s", buf); } else { -#endif /* KRB4 */ +#endif /* KRB4_KLOGIN */ #ifdef UT_HOSTSIZE syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", tty, UT_HOSTSIZE, hostname); @@ -991,7 +1730,7 @@ bad_login: syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s", tty, hostname); #endif -#ifdef KRB4 +#ifdef KRB4_KLOGIN } else if (kdata) { @@ -1001,43 +1740,30 @@ bad_login: kdata->pname, kdata->pinst, kdata->prealm); } -#endif /* KRB4 */ +#endif /* KRB4_KLOGIN */ else syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); - if (!quietlog) { - struct stat st; + afs_login (); -#ifdef KRB4 + if (!quietlog) { +#ifdef KRB4_KLOGIN if (!krbflag && !fflag && !Fflag && !eflag ) printf("\nWarning: No Kerberos tickets obtained.\n\n"); -#endif /* KRB4 */ -#ifndef NO_MOTD - motd(); -#endif - (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); - if (stat(tbuf, &st) == 0 && st.st_size != 0) - printf("You have %smail.\n", - (st.st_mtime > st.st_atime) ? "new " : ""); +#endif /* KRB4_KLOGIN */ + motd (); + check_mail (); } #ifndef OQUOTA if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN); #endif -#ifdef POSIX_SIGNALS - sa.sa_handler = SIG_DFL; - (void)sigaction(SIGALRM, &sa, (struct sigaction *)0); - (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0); - (void)sigaction(SIGINT, &sa, (struct sigaction *)0); - - sa.sa_handler = SIG_IGN; - (void)sigaction(SIGTSTP, &sa, (struct sigaction *)0); -#else - (void)signal(SIGALRM, SIG_DFL); - (void)signal(SIGQUIT, SIG_DFL); - (void)signal(SIGINT, SIG_DFL); - (void)signal(SIGTSTP, SIG_IGN); -#endif + handler_init (sa, SIG_DFL); + handler_set (SIGALRM, sa); + handler_set (SIGQUIT, sa); + handler_set (SIGINT, sa); + handler_init (sa, SIG_IGN); + handler_set (SIGTSTP, sa); tbuf[0] = '-'; (void) strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? @@ -1048,6 +1774,150 @@ bad_login: exit(0); } +char *speeds[] = { + "0", "50", "75", "110", "134", "150", "200", "300", "600", + "1200", "1800", "2400", "4800", "9600", "19200", "38400", +}; +#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) + +#ifdef POSIX_TERMIOS +/* this must be in sync with the list above */ +speed_t b_speeds[] = { + B0, B50, B75, B110, B134, B150, B200, B300, B600, + B1200, B1800, B2400, B4800, B9600, B19200, B38400, +}; +#endif + +term_init (do_rlogin) +{ + int line_speed = -1; + + if (do_rlogin) { + register char *cp = strchr(term, '/'), **cpp; + char *speed; + + if (cp) { + *cp++ = '\0'; + speed = cp; + cp = strchr(speed, '/'); + if (cp) + *cp++ = '\0'; + for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) + if (strcmp(*cpp, speed) == 0) { + line_speed = cpp-speeds; + break; + } + } + } +#ifdef POSIX_TERMIOS + { + struct termios tc; + + (void)tcgetattr(0, &tc); + if (line_speed != -1) { + cfsetispeed(&tc, b_speeds[line_speed]); + cfsetospeed(&tc, b_speeds[line_speed]); + } + tc.c_cc[VMIN] = 1; + tc.c_cc[VTIME] = 0; +#ifndef NO_INIT_CC + tc.c_cc[VERASE] = CERASE; + tc.c_cc[VKILL] = CKILL; + tc.c_cc[VEOF] = CEOF; + tc.c_cc[VINTR] = CINTR; + tc.c_cc[VQUIT] = CQUIT; + tc.c_cc[VSTART] = CSTART; + tc.c_cc[VSTOP] = CSTOP; +#ifndef CNUL +#define CNUL CEOL +#endif + tc.c_cc[VEOL] = CNUL; + /* The following are common extensions to POSIX */ +#ifdef VEOL2 + tc.c_cc[VEOL2] = CNUL; +#endif +#ifdef VSUSP +#if !defined(CSUSP) && defined(CSWTCH) +#define CSUSP CSWTCH +#endif + tc.c_cc[VSUSP] = CSUSP; +#endif +#ifdef VDSUSP + tc.c_cc[VDSUSP] = CDSUSP; +#endif +#ifdef VLNEXT + tc.c_cc[VLNEXT] = CLNEXT; +#endif +#ifdef VREPRINT + tc.c_cc[VREPRINT] = CRPRNT; +#endif +#ifdef VDISCRD + tc.c_cc[VDISCRD] = CFLUSH; +#endif +#ifdef VDISCARD +#ifndef CDISCARD +#define CDISCARD CFLUSH +#endif + tc.c_cc[VDISCARD] = CDISCARD; +#endif +#ifdef VWERSE + tc.c_cc[VWERSE] = CWERASE; +#endif +#ifdef VWERASE + tc.c_cc[VWERASE] = CWERASE; +#endif +#if defined (VSTATUS) && defined (CSTATUS) + tc.c_cc[VSTATUS] = CSTATUS; +#endif /* VSTATUS && CSTATUS */ +#endif /* NO_INIT_CC */ + /* set all standard echo, edit, and job control options */ + /* but leave any extensions */ + tc.c_lflag |= ECHO|ECHOE|ECHOK|ICANON|ISIG|IEXTEN; + tc.c_lflag &= ~(NOFLSH|TOSTOP); +#ifdef ECHOCTL + /* Not POSIX, but if we have it, we probably want it */ + tc.c_lflag |= ECHOCTL; +#endif +#ifdef ECHOKE + /* Not POSIX, but if we have it, we probably want it */ + tc.c_lflag |= ECHOKE; +#endif + tc.c_iflag |= ICRNL|BRKINT; + tc.c_oflag |= ONLCR|OPOST|TAB3; + tcsetattr(0, TCSANOW, &tc); + } + +#else /* not POSIX_TERMIOS */ + + { + struct sgttyb sgttyb; + static struct tchars tc = { + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK + }; + static struct ltchars ltc = { + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT + }; + + (void) ioctl(0, TIOCGETP, (char *)&sgttyb); + if (line_speed != -1) + sgttyb.sg_ispeed = sgttyb.sg_ospeed = line_speed; + sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS; + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; + (void)ioctl(0, TIOCSLTC, (char *)<c); + (void)ioctl(0, TIOCSETC, (char *)&tc); + (void)ioctl(0, TIOCSETP, (char *)&sgttyb); +#if defined(TIOCSETD) + { + int ioctlval; + ioctlval = 0; + (void)ioctl(0, TIOCSETD, (char *)&ioctlval); + } +#endif + } +#endif +} + void getloginname() { register int ch; @@ -1096,58 +1966,42 @@ int rootterm(tty) #endif /* HAVE_TTYENT_H */ } -#ifdef POSIX_SETJMP +#ifndef NO_MOTD sigjmp_buf motdinterrupt; -#else -jmp_buf motdinterrupt; -#endif +sigtype +sigint() +{ + siglongjmp(motdinterrupt, 1); +} void motd() { register int fd, nchars; char tbuf[8192]; - sigtype sigint(); -#ifdef POSIX_SIGNALS - struct sigaction sa, osa; -#else - sigtype (*oldint)(); -#endif + handler sa, osa; if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) return; -#ifdef POSIX_SIGNALS - (void)sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = sigint; - (void)sigaction(SIGINT, &sa, &osa); -#else - oldint = signal(SIGINT, sigint); -#endif -#ifdef POSIX_SETJMP + handler_init (sa, sigint); + handler_swap (SIGINT, sa, osa); if (sigsetjmp(motdinterrupt, 1) == 0) while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); -#else - if (setjmp(motdinterrupt) == 0) - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); -#endif -#ifdef POSIX_SIGNALS - (void)sigaction(SIGINT, &osa, (struct sigaction *)0); -#else - (void)signal(SIGINT, oldint); -#endif + handler_set (SIGINT, osa); (void)close(fd); } - -sigtype -sigint() -{ -#ifdef POSIX_SETJMP - siglongjmp(motdinterrupt, 1); #else - longjmp(motdinterrupt, 1); +void motd () { } #endif + +void check_mail () +{ + char tbuf[MAXPATHLEN+2]; + struct stat st; + (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); } void checknologin() @@ -1199,7 +2053,11 @@ void dolastlog(quiet, tty) } #undef UNKNOWN +#ifdef __hpux +#define UNKNOWN 0 +#else #define UNKNOWN "su" +#endif char * stypeof(ttyid) @@ -1230,7 +2088,7 @@ int doremotelogin(host) return(ruserok(host, (pwd->pw_uid == 0), rusername, username)); } -#ifdef KRB4 +#ifdef KRB4_KLOGIN int do_krb_login(host, strict) char *host; int strict; @@ -1276,7 +2134,7 @@ int do_krb_login(host, strict) instance, &sin, (struct sockaddr_in *)0, kdata, "", (bit_64 *) 0, version))) { - printf("Kerberos rlogin failed: %s\r\n",krb_err_txt[rc]); + printf("Kerberos rlogin failed: %s\r\n",krb_get_err_text(rc)); if (strict) { paranoid: /* @@ -1322,7 +2180,7 @@ paranoid: } return(0); } -#endif /* KRB4 */ +#endif /* KRB4_KLOGIN */ void lgetstr(buf, cnt, err) char *buf, *err; @@ -1344,79 +2202,19 @@ void lgetstr(buf, cnt, err) } while (ch); } -char *speeds[] = { - "0", "50", "75", "110", "134", "150", "200", "300", "600", - "1200", "1800", "2400", "4800", "9600", "19200", "38400", -}; -#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) - -#ifdef POSIX_TERMIOS -/* this must be in sync with the list above */ -speed_t b_speeds[] = { - B0, B50, B75, B110, B134, B150, B200, B300, B600, - B1200, B1800, B2400, B4800, B9600, B19200, B38400, -}; -#endif - -void doremoteterm(tp) -#ifdef POSIX_TERMIOS - struct termios *tp; -#else - struct sgttyb *tp; -#endif -{ - register char *cp = strchr(term, '/'), **cpp; - char *speed; - - if (cp) { - *cp++ = '\0'; - speed = cp; - cp = strchr(speed, '/'); - if (cp) - *cp++ = '\0'; - for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) - if (strcmp(*cpp, speed) == 0) { -#ifdef POSIX_TERMIOS - cfsetispeed(tp, b_speeds[cpp-speeds]); - cfsetospeed(tp, b_speeds[cpp-speeds]); -#else - tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; -#endif - break; - } - } -#ifdef POSIX_TERMIOS - /* set all standard echo, edit, and job control options */ - /* but leave any extensions */ - tp->c_lflag |= ECHO|ECHOE|ECHOK|ICANON|ISIG|IEXTEN; - tp->c_lflag &= ~(NOFLSH|TOSTOP); -#ifdef ECHOCTL - /* Not POSIX, but if we have it, we probably want it */ - tp->c_lflag |= ECHOCTL; -#endif -#ifdef ECHOKE - /* Not POSIX, but if we have it, we probably want it */ - tp->c_lflag |= ECHOKE; -#endif - tp->c_iflag |= ICRNL|BRKINT; - tp->c_oflag |= ONLCR|OPOST|TAB3; -#else /* !POSIX_TERMIOS */ - tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; -#endif -} - void sleepexit(eval) int eval; { -#ifdef KRB4 - if (krbflag) - (void) dest_tkt(); -#endif /* KRB4 */ +#ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets && krbflag) + (void) destroy_tickets(); +#endif /* KRB4_GET_TICKETS */ sleep((u_int)5); exit(eval); } -#ifdef KRB4 +#ifdef KRB4_GET_TICKETS +/* call already conditionalized on login_krb4_get_tickets */ /* * This routine handles cleanup stuff, and the like. * It exits only in the child process. @@ -1431,10 +2229,15 @@ dofork() update_ref_count(1); #endif if(!(child=fork())) - return; /* Child process */ + return; /* Child process returns */ + + /* The parent continues here */ { /* Try and get rid of our controlling tty. On SunOS, this may or may not work depending on if our parent did a setsid before exec-ing us. */ +#ifndef __linux__ + /* On linux, TIOCNOTTY causes us to die on a + SIGHUP, so don't even try it. */ #ifdef TIOCNOTTY { int fd; if ((fd = open("/dev/tty", O_RDWR)) >= 0) { @@ -1443,10 +2246,15 @@ dofork() } } #endif +#endif /* __linux__ */ #ifdef HAVE_SETSID (void)setsid(); #endif +#ifdef SETPGRP_TWOARG (void)setpgrp(0, 0); +#else + (void)setpgrp(); +#endif } /* Setup stuff? This would be things we could do in parallel with login */ @@ -1464,12 +2272,9 @@ dofork() #endif /* Cleanup stuff */ - /* Run dest_tkt to destroy tickets */ - (void) dest_tkt(); /* If this fails, we lose quietly */ -#ifdef SETPAG - if (pagflag) - ktc_ForgetAllTokens(); -#endif + /* Run destroy_tickets to destroy tickets */ + (void) destroy_tickets(); /* If this fails, we lose quietly */ + afs_cleanup (); #ifdef _IBMR2 update_ref_count(-1); #endif @@ -1477,7 +2282,7 @@ dofork() /* Leave */ exit(0); } -#endif /* KRB4 */ +#endif /* KRB4_GET_TICKETS */ #ifndef HAVE_STRSAVE diff --git a/src/appl/bsd/loginpaths.h b/src/appl/bsd/loginpaths.h index a07b40c2a..2f2de0bb8 100644 --- a/src/appl/bsd/loginpaths.h +++ b/src/appl/bsd/loginpaths.h @@ -20,6 +20,12 @@ /* hpux 8, both hppa and s300 */ #define LPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin" #define RPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin" +#else +#ifdef __hpux /* 9.04 */ +#define LPATH_root ":/bin:/usr/bin:/etc" +#define LPATH "/bin:/usr/bin" +#define RPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin" +#endif #endif #ifdef NeXT diff --git a/src/appl/bsd/rlogin.M b/src/appl/bsd/rlogin.M index b7e8765f3..d3774d585 100644 --- a/src/appl/bsd/rlogin.M +++ b/src/appl/bsd/rlogin.M @@ -54,38 +54,6 @@ realm ] [ .B \-l username ] .PP -.br -rhost [ -\fB\-e\fR\fIc\fR -] [ -.B \-8 -] [ -.B \-c -] [ -.B \-a -] [ -.B \-f -] [ -.B \-F -] [ -.B \-t -termtype ] [ -.B \-n -] [ -.B \-7 -] [ -.B \-d -] [ -.B \-k -realm ] [ -.B \-x -] [ -.B \-noflow -] [ -.B \-L -] [ -.B \-l -username ] .SH DESCRIPTION .I Rlogin connects your terminal on the current local host system @@ -213,8 +181,6 @@ significantly increases CPU utilization. rsh(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3), rlogin(1) [UCB version] .SH FILES -/usr/hosts/* for \fIrhost\fP version of the command -.br \&.k5login in the user's home directory .SH BUGS More of the environment should be propagated. diff --git a/src/appl/bsd/rsh.M b/src/appl/bsd/rsh.M index 95ddfd0f1..d073832b5 100644 --- a/src/appl/bsd/rsh.M +++ b/src/appl/bsd/rsh.M @@ -33,20 +33,10 @@ username ] [ .B \-k realm ] [ -.B \-A -] command -.br -host -[ -.B \-l -username +.B \-f | \-F ] [ -.B \-n -] [ -.B \-d +.B \-x ] [ -.B \-k -realm ] [ .B \-A ] command .SH DESCRIPTION @@ -79,6 +69,21 @@ account name using the aname -> lname mapping rules (see \fIkrb5_anadd(8)\fP for more details). .PP The +.B \-x +option causes the network session traffic to be encrypted. +.PP +The +.B \-f +and +.B \-F +options cause Kerberos credentials to be forwarded to the remote machine for +use by the specified \fIcommand\fR. They will be removed when \fIcommand\fR +finishes. If +.B \-F +is used, the forwarded credentials are themselves forwardable to other +machines. +.PP +The .B \-k \fIrealm\fP option causes .I rsh @@ -129,18 +134,10 @@ appends .I remotefile to .I otherremotefile. -.PP -The host names for local machines are also commands in the directory -/usr/hosts; if you put this directory in your search path -then the -.B rsh -on the command line can be omitted. .SH FILES .ta 2i /etc/hosts .br -/usr/hosts/* -.br \&.k5login in the user's home directory .DT .SH SEE ALSO |