Lots of cleanup. V4/V5 compatibility recvauth moved to separate
authorTheodore Tso <tytso@mit.edu>
Fri, 24 Dec 1993 22:45:23 +0000 (22:45 +0000)
committerTheodore Tso <tytso@mit.edu>
Fri, 24 Dec 1993 22:45:23 +0000 (22:45 +0000)
library function.

Folded in rest of GZA's patches.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3278 dc483132-0cff-0310-8789-dd5450dbe970

src/appl/bsd/Imakefile
src/appl/bsd/kcmd.c
src/appl/bsd/krcp.c
src/appl/bsd/krlogind.c
src/appl/bsd/krsh.c
src/appl/bsd/krshd.c
src/appl/bsd/login.c
src/appl/bsd/logutil.c

index 995c1ad9f405ad2e55134d78a4702fbd93208612..10bfa37a34e818293f03d9b063813b886d2442a7 100644 (file)
@@ -74,8 +74,8 @@ Krb5InstallServerProgram(krshd)
 NormalProgramTarget(krlogind,krlogind.o logutil.o kcmd.o forward.o,$(DEPLIBS),$(LOCAL_LIBRARIES),$(K4LIB))
 Krb5InstallServerProgram(krlogind)
 
-NormalProgramTarget(login.krb,login.o logutil.o setenv.o,,,)
-InstallProgram(login.krb,$(SERVER_BINDIR))
+NormalProgramTarget(login.krb5,login.o logutil.o setenv.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+InstallProgram(login.krb5,$(SERVER_BINDIR))
 #endif
 
 DependTarget()
index 5e27f5cc0173acecb7fdb9005e934795930131eb..542a35857289b7f8d265ba5965d391d2f439ac85 100644 (file)
@@ -100,7 +100,7 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
     krb5_ap_rep_enc_part *rep_ret;
     krb5_checksum send_cksum;
     char *tmpstr = 0;
-    krb5_error *error;
+    krb5_error *error = 0;
     int sin_len;
     krb5_ccache cc;
     krb5_data outbuf;
@@ -139,14 +139,19 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
         fprintf(stderr,"kcmd: no memory\n");
         return(-1);
     }
-    if ((realm == NULL) || (realm[0] == '\0')) {
-       krb5_sname_to_principal(host_save,service,KRB5_NT_SRV_HST,
-                               &ret_cred->server);
-    }
-    else {
-        sprintf(tmpstr,"%s/%s@%s",service,host_save,realm);
-        krb5_parse_name(tmpstr,&ret_cred->server);
-    }
+    krb5_sname_to_principal(host_save,service,KRB5_NT_SRV_HST,
+                           &ret_cred->server);
+    if (realm && *realm) {
+       char *copyrealm;
+       krb5_data rdata;
+
+       rdata.length = strlen(realm);
+       rdata.data = (char *) malloc(rdata.length+1);
+       strcpy(rdata.data, realm);
+       
+       /* XXX we should free the old realm first */
+       krb5_princ_set_realm(ret_cred->server, &rdata);
+   }
 #ifdef sgi
     oldmask = sigignore(sigmask(SIGURG));
 #else
@@ -312,11 +317,17 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
                            &error,             /* No error return */
                            &rep_ret);
     if (status) {
-       printf("We have a sendauth error %d\n", error->error);
-       if (error->text.length) {
-           fprintf(stderr, "Text: %s\n", error->text.data);
+       printf("Couldn't authenticate to server: %s\n", error_message(status));
+       if (error) {
+           printf("Server returned error code %d (%s)\n", error->error,
+                  error_message(ERROR_TABLE_BASE_krb5 + error->error));
+           if (error->text.length) {
+               fprintf(stderr, "Error text sent from server: %s\n",
+                       error->text.data);
+           }
+           krb5_free_error(error);
+           error = 0;
        }
-       krb5_free_error(error);
     }  
     if (status) goto bad3;
     if (rep_ret && server_seqno) {
index ec0807a3913d33dc55bf13e118f8c57d5ac4189b..361574927b71f145cf1a47d50afd45f9fcd72672 100644 (file)
@@ -58,6 +58,7 @@ static char sccsid[] = "@(#)rcp.c     5.10 (Berkeley) 9/20/88";
 #include <ctype.h>
 #include <netdb.h>
 #include <errno.h>
+#include <string.h>
      
 #ifdef KERBEROS
 #include <krb5/krb5.h>
@@ -102,7 +103,7 @@ int encryptflag = 0;
 #endif /* KERBEROS */
 
 int    rem;
-char   *colon(), *index(), *rindex(), *strcpy();
+char   *colon();
 int    errs;
 krb5_sigtype   lostconn();
 int    errno;
@@ -273,7 +274,7 @@ main(argc, argv)
        /* Target machine is some remote machine */
        if (*targ == 0)
          targ = ".";
-       thost = index(argv[argc - 1], '@');
+       thost = strchr(argv[argc - 1], '@');
        if (thost) {
            *thost++ = 0;
            tuser = argv[argc - 1];
@@ -291,7 +292,7 @@ main(argc, argv)
                *src++ = 0;
                if (*src == 0)
                  src = ".";
-               host = index(argv[i], '@');
+               host = strchr(argv[i], '@');
                if (host) {
                    *host++ = 0;
                    suser = argv[i];
@@ -401,7 +402,7 @@ main(argc, argv)
                *src++ = 0;
                if (*src == 0)
                  src = ".";
-               host = index(argv[i], '@');
+               host = strchr(argv[i], '@');
                if (host) {
                    *host++ = 0;
                    suser = argv[i];
@@ -576,7 +577,7 @@ source(argc, argv)
            error("rcp: %s: not a plain file\n", name);
            continue;
        }
-       last = rindex(name, '/');
+       last = strrchr(name, '/');
        if (last == 0)
          last = name;
        else
@@ -653,7 +654,7 @@ rsource(name, statp)
        error("rcp: %s: %s\n", name, sys_errlist[errno]);
        return;
     }
-    last = rindex(name, '/');
+    last = strrchr(name, '/');
     if (last == 0)
       last = name;
     else
@@ -1086,7 +1087,6 @@ void send_auth()
     char *princ;          /* principal in credentials cache */
     krb5_ccache cc;
     krb5_creds creds;
-    krb5_principal sprinc;                /* principal of server */
     krb5_data reply, msg, princ_data;
     krb5_tkt_authent *authdat;
     krb5_error_code status;
@@ -1116,7 +1116,7 @@ void send_auth()
        krb5_cc_close(cc);
        exit(1);
     }
-    if (status = krb5_build_principal_ext(&sprinc,
+    if (status = krb5_build_principal_ext(&creds.server,
                                          krb5_princ_realm(creds.client)->length,
                                          krb5_princ_realm(creds.client)->data,
                                          6, "krbtgt",
@@ -1130,8 +1130,6 @@ void send_auth()
        exit(1);
     }
     
-    creds.server = sprinc;
-    
     /* Get TGT from credentials cache */
     if (status = krb5_get_credentials(KRB5_GC_CACHED, cc, &creds)){
        fprintf(stderr,
@@ -1142,10 +1140,6 @@ void send_auth()
     }
     krb5_cc_close(cc);
     
-    krb5_free_principal(sprinc);          /* creds.server is replaced
-                                            upon retrieval */
-    
-    
     princ_data.data = princ;
     princ_data.length = strlen(princ_data.data) + 1; /* include null 
                                                        terminator for
index d96abbd0192de83a9fb3add221a09f2a7bd311c0..fdd3a31dafcc43c051e85230f78f706dca147332 100644 (file)
@@ -91,9 +91,6 @@ static char sccsid[] = "@(#)rlogind.c 5.17 (Berkeley) 8/31/88";
  *   SERVE_V4 - Define this if v4 rlogin clients are also to be served.
  *   ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
  *              checked even for v4 clients (instead of .klogin).
- *   SERVE_NON_KRB - Define this if non-kerberized rlogin clients are 
- *              to be served. NOTE HOWEVER THAT THIS IS A SERIOUS
- *              SECURITY FLAW!
  *   LOG_ALL_LOGINS - Define this if you want to log all logins.
  *   LOG_OTHER_USERS - Define this if you want to log all principals
  *              that do not map onto the local user.
@@ -174,21 +171,23 @@ struct winsize {
 #include <krb5/crc-32.h>
 #include <krb5/mit-des.h>
 #include <krb5/los-proto.h>
+#include <kerberosIV/krb.h>
 
 #ifdef BUFSIZ
 #undef BUFSIZ
 #endif
 
-int V4 = 0;             /* set when v4 client detected. */
+int auth_sys = 0;      /* Which version of Kerberos used to authenticate */
+
+#define KRB5_RECVAUTH_V4       4
+#define KRB5_RECVAUTH_V5       5
+
 int non_privileged = 0; /* set when connection is seen to be from */
                        /* a non-privileged port */
-#ifdef SERVE_V4
-#include <kerberosIV/krb.h>
+
 AUTH_DAT       *v4_kdata;
-KTEXT          v4_ticket;
-Key_schedule schedule;
+Key_schedule v4_schedule;
 int v4_des_read(), v4_des_write();
-#endif
 
 #define BUFSIZ 5120
 
@@ -252,6 +251,16 @@ char       *malloc();
 #endif
 char   *progname;
 
+static int Pfd;
+
+#if (defined(_AIX) && defined(i386)) || defined(ibm032) || (defined(vax) && !defined(ultrix)) || (defined(SunOS) && SunOS > 40) || defined(solaris20)
+#define VHANG_FIRST
+#endif
+
+#if defined(ultrix)
+#define VHANG_LAST             /* vhangup must occur on close, not open */
+#endif
+
 void   fatal(), fatalperror(), doit(), usage(), do_krb_login();
 int    princ_maps_to_lname(), default_realm();
 
@@ -447,7 +456,7 @@ void doit(f, fromp)
      int f;
      struct sockaddr_in *fromp;
 {
-    int i, p, t, on = 1;
+    int i, p, t, vfd, on = 1;
     register struct hostent *hp;
     char c;
     char buferror[255];
@@ -512,6 +521,7 @@ void doit(f, fromp)
     write(f, "", 1);
     if (getpty(&p,line))
       fatal(f, "Out of ptys");
+    Pfd = p;
 #ifdef TIOCSWINSZ
     (void) ioctl(p, TIOCSWINSZ, &win);
 #endif
@@ -521,13 +531,14 @@ void doit(f, fromp)
     
     /* Make sure we can open slave pty, then close it for system 5 so that 
        the process group is set correctly..... */
-    t = open(line, O_RDWR);
-    if (t < 0)
+#ifdef VHANG_FIRST
+    vfd = open(line, O_RDWR);
+    if (vfd < 0)
       fatalperror(f, line);
 #ifdef NOFCHMOD
-    if (chmod(t,0))
+    if (chmod(vfd,0))
 #else
-    if (fchmod(t, 0))
+    if (fchmod(vfd, 0))
 #endif
       fatalperror(f, line);
 #ifndef SYSV
@@ -536,18 +547,20 @@ void doit(f, fromp)
        vhangup();
        signal(SIGHUP, SIG_DFL);
     }
-#ifdef ultrix   /* Someone needs to cleanup all this and have a consistant
-                  way of associating controlling tty to a process. */
-    setpgrp();
-#endif
+#endif 
+#endif /* VHANG_FIRST */
 #if defined (sun) || defined (POSIX)
     setsid();
 #endif
 
     t = open(line, O_RDWR);
+#ifdef VHANG_FIRST
+#ifndef VHANG_NO_CLOSE
+       (void) close(vfd);
+#endif
+#endif /* VHANG_FIRST */
     if (t < 0)
       fatalperror(f, line);
-#endif
 #ifdef SYSV
     close(t);
 #endif
@@ -600,7 +613,17 @@ void doit(f, fromp)
            pid = getpgrp(getpid());
 #endif
 #endif
-           ioctl(t, TIOCSPGRP, &pid);
+#ifdef POSIX /* solaris */
+           /* we've already done setsid above. Just do tcsetpgrp here. */
+           tcsetpgrp(0, pid);
+#else
+#ifndef hpux
+           ioctl(0, TIOCSPGRP, &pid);
+#else
+           /* we've already done setsid above. Just do tcsetpgrp here. */
+           tcsetpgrp(0, pid);
+#endif
+#endif /* posix */
            pid = 0;                    /*reset pid incase exec fails*/
 #endif
 #ifdef STREAMS
@@ -684,9 +707,9 @@ void doit(f, fromp)
        execl(LOGIN_PROGRAM, "login", "-r", rhost_name, 0);
 #else
        if (passwd_req)
-         execl(LOGIN_PROGRAM, "login","-r", rhost_name, 0);
+         execl(LOGIN_PROGRAM, "login","-h", rhost_name, lusername, 0);
        else
-         execl(LOGIN_PROGRAM, "login", "-fr", rhost_name, 0);
+         execl(LOGIN_PROGRAM, "login", "-h", rhost_name, "-e", lusername, 0);
 #endif
        
        fatalperror(2, LOGIN_PROGRAM, errno);
@@ -735,9 +758,11 @@ void doit(f, fromp)
     setpgrp(0, 0);
 #endif
     
+#ifdef DO_NOT_USE_K_LOGIN
     /* Pass down rusername and lusername to login. */
     (void) write(p, rusername, strlen(rusername) +1);
     (void) write(p, lusername, strlen(lusername) +1);
+#endif
     /* stuff term info down to login */
     if( write(p, term, strlen(term)+1) <= 0 ){
        /*
@@ -950,6 +975,10 @@ int cleanup()
     *p = 'p';
     (void)chmod(line, 0666);
     (void)chown(line, 0, 0);
+#endif
+#ifdef VHANG_LAST
+    close(Pfd);
+    vhangup();
 #endif
     shutdown(netf, 2);
     exit(1);
@@ -1038,7 +1067,7 @@ do_krb_login(host)
        if (client && krb5_kuserok(client, lusername))
            passed_krb++;
 #else
-       if (V4) {
+       if (auth_sys == KRB5_RECVAUTH_V4) {
            /* kuserok returns 0 if OK */
            if (!kuserok(v4_kdata, lusername))
                passed_krb++;
@@ -1348,60 +1377,92 @@ krb5_error_code
 recvauth()
 {
     krb5_error_code status;
-    struct sockaddr_in peersin;
+    struct sockaddr_in peersin, laddr;
     char krb_vers[KRB_SENDAUTH_VLEN + 1];
     int len;
-
+    krb5_principal server;
+    krb5_address peeraddr;
+    krb5_data inbuf;
+    char v4_instance[INST_SZ]; /* V4 Instance */
+    char v4_version[9];
+
+    len = sizeof(laddr);
+    if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
+           exit(1);
+    }
+       
     len = sizeof(peersin);
     if (getpeername(netf, (struct sockaddr *)&peersin, &len)) {
        syslog(LOG_ERR, "get peer name failed %d", netf);
        exit(1);
     }
 
-    len = sizeof(int);
-    if ((status = krb5_net_read(netf, krb_vers, len)) != len)
-      return((status < 0) ? errno : ECONNABORTED);
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
 
-    krb_vers[len] = '\0';
+    peeraddr.addrtype = peersin.sin_family;
+    peeraddr.length = SIZEOF_INADDR;
+    peeraddr.contents = (krb5_octet *)&peersin.sin_addr;
+       
+    if (status = krb5_sname_to_principal(NULL, "host", KRB5_NT_SRV_HST,
+                                        &server)) {
+           syslog(LOG_ERR, "parse server name %s: %s", "host",
+                  error_message(status));
+           exit(1);
+    }
 
-    if (!strncmp(krb_vers, KRB_SENDAUTH_VERS, len)) {
-       /* Must be V4 rlogin client */
-#ifdef SERVE_V4
-       char version[9];
-       struct sockaddr_in faddr;
-       char instance[INST_SZ];
-       long authoptions;
+    strcpy(v4_instance, "*");
+
+    status = krb5_compat_recvauth(&netf,
+                                 "KCMDV0.1",
+                                 server, /* Specify daemon principal */
+                                 &peeraddr, /* We do want to match */
+                                            /* this against caddrs in */
+                                            /* the ticket */
+                                 0, /* use v5srvtab */
+                                 0, /* no keyproc */
+                                 0, /* no keyprocarg */
+                                 0, /* default rc_type */
+                                 0, /* no flags */
+
+                                 do_encrypt ? KOPT_DO_MUTUAL : 0, /*v4_opts*/
+                                 "rcmd", /* v4_service */
+                                 v4_instance, /* v4_instance */
+                                 &peersin, /* foriegn address */
+                                 &laddr, /* our local address */
+                                 "", /* use default srvtab */
+
+                                 &auth_sys, /* which authentication system */
+                                 0, /* no seq number */
+                                 &client, /* return client */
+                                 &ticket, /* return ticket */
+                                 &kdata, /* return authenticator */
+                                 
+                                 &v4_kdata, v4_schedule, v4_version);
+
+    if (status) {
+       if (auth_sys == KRB5_RECVAUTH_V5) {
+           /*
+            * clean up before exiting
+            */
+           getstr(netf, lusername, sizeof (lusername), "locuser");
+           getstr(netf, term, sizeof(term), "Terminal type");
+           getstr(netf, rusername, sizeof(rusername), "remuser");
+       }
+       return status;
+    }
 
-       V4 = 1;        /* Set flag for rest of code */
+    getstr(netf, lusername, sizeof (lusername), "locuser");
+    getstr(netf, term, sizeof(term), "Terminal type");
+
+    if (auth_sys == KRB5_RECVAUTH_V4) {
 
        des_read  = v4_des_read;
        des_write = v4_des_write;
 
-       if (do_encrypt)
-         authoptions = KOPT_DO_MUTUAL;
-       else
-         authoptions = 0L;
-
-       len = sizeof(faddr);
-       if (getsockname(netf, (struct sockaddr *)&faddr, &len)) {
-           exit(1);
-       }
-       
-       v4_kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
-       v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
-
-       strcpy(instance, "*");
-
-       if (status = v4_recvauth(krb_vers, authoptions, netf, v4_ticket, 
-                                "rcmd", instance, 
-                                &peersin, &faddr,
-                                v4_kdata, "", 
-                                schedule, version)) {
-           return(status);
-       }
-
-       getstr(netf, lusername, sizeof (lusername), "locuser");
-       getstr(netf, term, sizeof(term), "Terminal type");
        /* We do not really know the remote user's login name.
          * Assume it to be the same as the first component of the
         * principal's name. 
@@ -1415,523 +1476,40 @@ recvauth()
        
        if (status = krb5_parse_name(krusername, &client))
          return(status);
-#else
-       syslog(LOG_ERR, "Kerberos V4 authentication: rejected!");
-       fatal(netf, "Permission denied");
-#endif
-    }
-    else if (isprint(krb_vers[0])) { 
-       /* Un-kerberized rlogin client */
-#ifdef SERVE_NON_KRB
-       des_read  = read;
-       des_write = write;
-
-       strncpy(rusername, krb_vers, sizeof(int));
-       getstr(netf, rusername+4, sizeof(rusername)-sizeof(int), "remuser");
-       getstr(netf, lusername, sizeof(lusername), "locuser");
-       getstr(netf, term, sizeof(term), "Terminal type");      
-#else
-       syslog(LOG_ERR, "Un-kerberized client: authentication rejected!");
-       fatal(netf, "Permission denied");
-#endif
+       return 0;
     }
-    else {
-       /* Must be V5 rlogin client */
-       krb5_principal server;
-       krb5_address peeraddr;
-       krb5_data inbuf;
-
-       des_read  = v5_des_read;
-       des_write = v5_des_write;
-
-       /*
-        * First read the sendauth version string and check it.
-        */
-       inbuf.length = ntohl(*((int *) krb_vers));
 
-       if (inbuf.length < 0 || inbuf.length > 25)
-         return 255;
+    /* Must be V5  */
        
-       if (!(inbuf.data = malloc(inbuf.length))) {
-           return(ENOMEM);
-       }
-       
-       if ((len = krb5_net_read(netf, inbuf.data, inbuf.length)) !=
-           inbuf.length) {
-           krb5_xfree(inbuf.data);
-           return((len < 0) ? errno : ECONNABORTED);
-       }
+    des_read  = v5_des_read;
+    des_write = v5_des_write;
 
-       if (strcmp(inbuf.data, "KRB5_SENDAUTH_V1.0")) {
-           krb5_xfree(inbuf.data);
-           status = KRB5_SENDAUTH_BADAUTHVERS;
-           return status;
-       }
-       krb5_xfree(inbuf.data);
+    getstr(netf, rusername, sizeof(rusername), "remuser");
 
-#ifdef unicos61
-#define SIZEOF_INADDR  SIZEOF_in_addr
-#else
-#define SIZEOF_INADDR sizeof(struct in_addr)
-#endif
-
-       peeraddr.addrtype = peersin.sin_family;
-       peeraddr.length = SIZEOF_INADDR;
-       peeraddr.contents = (krb5_octet *)&peersin.sin_addr;
-       
-       if (status = krb5_sname_to_principal(NULL, "host", KRB5_NT_SRV_HST,
-                                            &server)) {
-           syslog(LOG_ERR, "parse server name %s: %s", "host",
-                  error_message(status));
-           exit(1);
-       }
-
-       if (status = v5_recvauth(&netf, 
-                                "KCMDV0.1",
-                                server,     /* Specify daemon principal */
-                                &peeraddr,  /* We do want to match this
-                                               against caddrs in the
-                                               ticket. */
-                                0,             /* use v5srvtab */
-                                0,             /* no keyproc */
-                                0,             /* no keyproc arg */
-                                0,             /* no rc_type */
-                                0,             /* no seq number */
-                                &client,       /* return client */
-                                &ticket,       /* return ticket */
-                                &kdata      /* return authenticator */
-                                )) {
-           /* Dummy forwarding reads */
-           if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
-             fatal(netf, "Error reading message");
-           if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
-             fatal(netf, "Error reading message");
-           
-           /* Dont exit out for klogin, but
-              grab locuser, terminal, and remuser.
-              */
-           getstr(netf, lusername, sizeof(lusername), "locuser");
-           getstr(netf, term, sizeof(term), "Terminal type");
-           getstr(netf, rusername, sizeof(rusername), "remuser");
-           return status;
-       }
-       
-       if (status = krb5_unparse_name(client, &krusername))
-         return status;
+    if (status = krb5_unparse_name(client, &krusername))
+       return status;
     
-       /* Setup up eblock if encrypted login session */
-       /* otherwise zero out session key */
-       if (do_encrypt) {
-           krb5_use_keytype(&eblock,
-                            ticket->enc_part2->session->keytype);
-           if (status = krb5_process_key(&eblock,
-                                         ticket->enc_part2->session))
-             fatal(netf, "Permission denied");
-       }      
-
-       getstr(netf, lusername, sizeof(lusername), "locuser");
-       getstr(netf, term, sizeof(term), "Terminal type");
-       getstr(netf, rusername, sizeof(rusername), "remuser");
-
-       if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
-         fatal(netf, "Error reading message");
-
-       if (inbuf.length) { /* Forwarding being done, read creds */
-           if (status = rd_and_store_for_creds(&inbuf, ticket, lusername))
-             fatal(netf, "Can't get forwarded credentials");
-       }
+    /* Setup up eblock if encrypted login session */
+    /* otherwise zero out session key */
+    if (do_encrypt) {
+       krb5_use_keytype(&eblock,
+                        ticket->enc_part2->session->keytype);
+       if (status = krb5_process_key(&eblock,
+                                     ticket->enc_part2->session))
+           fatal(netf, "Permission denied");
+    }      
+
+    if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
+       fatal(netf, "Error reading message");
+
+    if (inbuf.length) { /* Forwarding being done, read creds */
+       if (status = rd_and_store_for_creds(&inbuf, ticket, lusername))
+           fatal(netf, "Can't get forwarded credentials");
     }
     return 0;
 }
 
 
-#ifdef SERVE_V4
-
-#ifndef max
-#define        max(a,b) (((a) > (b)) ? (a) : (b))
-#endif /* max */
-
-krb5_error_code
-v4_recvauth(krb_vers, options, fd, ticket, service, instance, faddr,
-           laddr, kdata, filename, schedule, version)
-     char *krb_vers;
-     long options;                      /* bit-pattern of options */
-     int fd;                            /* file descr. to read from */
-     KTEXT ticket;                      /* storage for client's ticket */
-     char *service;                     /* service expected */
-     char *instance;                    /* inst expected (may be filled in) */
-     struct sockaddr_in *faddr;         /* address of foreign host on fd */
-     struct sockaddr_in *laddr;         /* local address */
-     AUTH_DAT *kdata;           /* kerberos data (returned) */
-     char *filename;                    /* name of file with service keys */
-     Key_schedule schedule;             /* key schedule (return) */
-     char *version;                     /* version string (filled in) */
-{
-    
-    int i, cc;
-    char *cp;
-    int rem;
-    long tkt_len, priv_len;
-    u_long cksum;
-    u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)];
-    
-    /* read the protocol version number */
-    if (krb_net_read(fd, krb_vers+sizeof(int), 
-                    KRB_SENDAUTH_VLEN-sizeof(int)) !=
-       KRB_SENDAUTH_VLEN-sizeof(int))
-      return(errno);
-    krb_vers[KRB_SENDAUTH_VLEN] = '\0';
-    
-    /* check version string */
-    if (strcmp(krb_vers,KRB_SENDAUTH_VERS)) {
-       return(KFAILURE);
-    } else {
-       /* read the application version string */
-       if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) !=
-           KRB_SENDAUTH_VLEN)
-         return(errno);
-       version[KRB_SENDAUTH_VLEN] = '\0';
-       
-       /* get the length of the ticket */
-       if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) !=
-           sizeof(tkt_len))
-         return(errno);
-       
-       /* sanity check */
-       ticket->length = ntohl((unsigned long)tkt_len);
-       if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) {
-           if (options & KOPT_DO_MUTUAL) {
-               rem = KFAILURE;
-               goto mutual_fail;
-           } else
-             return(KFAILURE); /* XXX there may still be junk on the fd? */
-       }
-       
-       /* read the ticket */
-       if (krb_net_read(fd, (char *) ticket->dat, ticket->length)
-           != ticket->length)
-         return(errno);
-    }
-    /*
-     * now have the ticket.  decrypt it to get the authenticated
-     * data.
-     */
-    if (rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr,
-                    kdata,filename))
-      return(KFAILURE);
-    
-    /* if we are doing mutual auth (used by erlogin), compose a response */
-    if (options & KOPT_DO_MUTUAL) {
-       if (rem != KSUCCESS)
-         /* the krb_rd_req failed */
-         goto mutual_fail;
-       
-       /* add one to the (formerly) sealed checksum, and re-seal it
-          for return to the client */
-       cksum = kdata->checksum + 1;
-       cksum = htonl(cksum);
-#ifdef CRYPT
-       key_sched(kdata->session,schedule);
-#endif
-       priv_len = krb_mk_priv((unsigned char *)&cksum,
-                              tmp_buf,
-                              (unsigned long) sizeof(cksum),
-                              schedule,
-                              kdata->session,
-                              laddr,
-                              faddr);
-       if (priv_len < 0) {
-           /* re-sealing failed; notify the client */
-           rem = KFAILURE;      /* XXX */
-         mutual_fail:
-           priv_len = -1;
-           tkt_len = htonl((unsigned long) priv_len);
-           /* a length of -1 is interpreted as an authentication
-              failure by the client */
-           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
-               != sizeof(tkt_len))
-             return(cc);
-           return(rem);
-       } else {
-           /* re-sealing succeeded, send the private message */
-           tkt_len = htonl((unsigned long)priv_len);
-           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
-               != sizeof(tkt_len))
-             return(cc);
-           if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len))
-               != (int) priv_len)
-             return(cc);
-       }
-    }
-    return(0);
-}
-
-#endif /* SERVE_V4 */
-
-extern krb5_flags      krb5_kdc_default_options;
-
-krb5_error_code
-v5_recvauth(/* IN */
-           fd, appl_version, server, sender_addr, fetch_from,
-           keyproc, keyprocarg, rc_type, 
-           /* OUT */
-           seq_number, client, ticket, authent)
-     krb5_pointer      fd;
-     char      *appl_version;
-     krb5_principal    server;
-     krb5_address      *sender_addr;
-     krb5_pointer      fetch_from;
-     krb5_int32        *seq_number;
-     char              *rc_type;
-     krb5_rdreq_key_proc keyproc;
-     krb5_pointer keyprocarg;
-     krb5_principal    *client;
-     krb5_ticket       **ticket;
-     krb5_authenticator        **authent;
-{
-    krb5_error_code    retval, problem;
-    krb5_data  inbuf;
-    krb5_tkt_authent   *authdat;
-    krb5_data          outbuf;
-    krb5_rcache rcache;
-    krb5_octet         response;
-    krb5_data  *server_name;
-    char *cachename;
-    extern krb5_deltat krb5_clockskew;
-    static char                *rc_base = "rc_";
-    
-    /*
-     * Zero out problem variable.  If problem is set at the end of
-     * the intial version negotiation section, it means that we
-     * need to send an error code back to the client application
-     * and exit.
-     */
-    problem = 0;
-    
-    /*
-     * Read and check the application version string.
-     */
-    if (retval = krb5_read_message(fd, &inbuf))
-      return(retval);
-    if (strcmp(inbuf.data, appl_version)) {
-       krb5_xfree(inbuf.data);
-       if (!problem)
-         problem = KRB5_SENDAUTH_BADAPPLVERS;
-    }
-    krb5_xfree(inbuf.data);
-    /*
-     * OK, now check the problem variable.  If it's zero, we're
-     * fine and we can continue.  Otherwise, we have to signal an
-     * error to the client side and bail out.
-     */
-    switch (problem) {
-      case 0:
-       response = 0;
-       break;
-      case KRB5_SENDAUTH_BADAUTHVERS:
-       response = 1;
-       break;
-      case KRB5_SENDAUTH_BADAPPLVERS:
-       response = 2;
-       break;
-      default:
-       /*
-        * Should never happen!
-        */
-       response = 255;
-#ifdef SENDAUTH_DEBUG
-       fprintf(stderr, "Programming botch in recvauth!  problem = %d",
-               problem);
-       abort();
-#endif
-       break;
-    }
-
-    /*
-     * Now we actually write the response.  If the response is non-zero,
-     * exit with a return value of problem
-     */
-    if ((krb5_net_write(*((int *) fd), (char *)&response, 1)) < 0) {
-       return(problem); /* We'll return the top-level problem */
-    }
-    if (problem)
-      return(problem);
-    rcache = NULL;
-#ifdef WORKING_RCACHE
-    /*
-     * Setup the replay cache.
-     */
-    if (!(rcache = (krb5_rcache) malloc(sizeof(*rcache)))) 
-      problem = ENOMEM;
-    if (!problem) 
-      problem = krb5_rc_resolve_type(&rcache,
-                                    rc_type ? rc_type : "dfl");
-    cachename = NULL;
-    server_name = krb5_princ_component(server, 0);
-    if (!problem && !(cachename = malloc(server_name->length+1+strlen(rc_base))))
-      problem = ENOMEM;
-    if (!problem) {
-       strcpy(cachename, rc_base ? rc_base : "rc_");
-       strncat(cachename, server_name->data, server_name->length);
-       cachename[server_name->length+strlen(rc_base)] = '\0';
-       problem = krb5_rc_resolve(rcache, cachename);
-    }
-    if (!problem) {
-       if (krb5_rc_recover(rcache))
-         /*
-          * If the rc_recover didn't work, then try
-          * initializing the replay cache.
-          */
-         problem = krb5_rc_initialize(rcache, krb5_clockskew);
-       if (problem) {
-           krb5_rc_close(rcache);
-           rcache = NULL;
-       }
-    }
-#endif
-
-    /*
-     * Now, let's read the AP_REQ message and decode it
-     */
-    if (retval = krb5_read_message(fd, &inbuf)) {
-#ifdef WORKING_RCACHE          
-       (void) krb5_rc_close(rcache);
-       if (cachename)
-         free(cachename);
-#endif
-       return(retval);
-    }
-    authdat = 0;                       /* so we can tell if we need to
-                                          free it later... */
-    if (!problem)
-      problem = krb5_rd_req(&inbuf, server, sender_addr, fetch_from,
-                           keyproc, keyprocarg, rcache, &authdat);
-    krb5_xfree(inbuf.data);
-#ifdef WORKING_RCACHE
-    if (rcache)
-      retval = krb5_rc_close(rcache);
-#endif
-    if (!problem && retval)
-      problem = retval;
-#ifdef WORKING_RCACHE
-    if (cachename)
-      free(cachename);
-#endif
-    
-    /*
-     * If there was a problem, send back a krb5_error message,
-     * preceeded by the length of the krb5_error message.  If
-     * everything's ok, send back 0 for the length.
-     */
-    if (problem) {
-       krb5_error      error;
-       const   char *message;
-       
-       memset((char *)&error, 0, sizeof(error));
-       krb5_us_timeofday(&error.stime, &error.susec);
-       error.server = server;
-       error.error = problem - ERROR_TABLE_BASE_krb5;
-       if (error.error > 127)
-         error.error = KRB_ERR_GENERIC;
-       message = error_message(problem);
-       error.text.length  = strlen(message) + 1;
-       if (!(error.text.data = malloc(error.text.length)))
-         return(ENOMEM);
-       strcpy(error.text.data, message);
-       if (retval = krb5_mk_error(&error, &outbuf)) {
-           free(error.text.data);
-           return(retval);
-       }
-       free(error.text.data);
-    } else {
-       outbuf.length = 0;
-       outbuf.data = 0;
-    }
-    if (retval = krb5_write_message(fd, &outbuf)) {
-       if (outbuf.data)
-         krb5_xfree(outbuf.data);
-       if (!problem)
-         krb5_free_tkt_authent(authdat);
-       return(retval);
-    }
-    if (problem) {
-       /*
-        * We sent back an error, we need to return
-        */
-       if (authdat) krb5_free_tkt_authent(authdat);
-       return(problem);
-    }
-    /*
-     * Here lies the mutual authentication stuff...
-     *
-     * We're going to compose and send a AP_REP message.
-     */
-    if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) {
-       krb5_ap_rep_enc_part    repl;
-       
-       /*
-        * Generate a random sequence number
-        */
-       if (seq_number &&
-           (retval = krb5_generate_seq_number(authdat->ticket->enc_part2->session,
-                                              seq_number))) {
-           krb5_free_tkt_authent(authdat);
-           return(retval);
-       }
-       
-       repl.ctime = authdat->authenticator->ctime;
-       repl.cusec = authdat->authenticator->cusec;
-       repl.subkey = authdat->authenticator->subkey;
-       if (seq_number)
-         repl.seq_number = *seq_number;
-       else
-         repl.seq_number = 0;
-       
-       if (retval = krb5_mk_rep(&repl,
-                                authdat->ticket->enc_part2->session,
-                                &outbuf)) {
-           krb5_free_tkt_authent(authdat);
-           return(retval);
-       }
-       if (retval = krb5_write_message(fd, &outbuf)) {
-           krb5_xfree(outbuf.data);
-           krb5_free_tkt_authent(authdat);
-           return(retval);
-       }
-       krb5_xfree(outbuf.data);
-    }
-    /*
-     * At this point, we've won.  We just need to copy whatever
-     * parts of the authdat structure which the user wants, clean
-     * up, and exit.
-     */
-    if (client)
-      if (retval =
-         krb5_copy_principal(authdat->ticket->enc_part2->client,
-                             client))
-       return(retval);
-    /*
-     * The following efficiency hack assumes knowledge about the
-     * structure of krb5_tkt_authent.  If we later add additional
-     * allocated substructures to krb5_tkt_authent, they will have
-     * to be reflected here; otherwise, we will probably have a
-     * memory leak.
-     *
-     * If the user wants that part of the authdat structure,
-     * return it; otherwise free it.
-     */
-    if (ticket)
-      *ticket = authdat->ticket;
-    else
-      krb5_free_ticket(authdat->ticket);
-    if (authent)
-      *authent = authdat->authenticator;
-    else
-      krb5_free_authenticator(authdat->authenticator);
-    krb5_xfree(authdat);
-    return 0;
-}
-
 #ifdef SERVE_V4
 
 int
@@ -1982,7 +1560,7 @@ int len;
        (void) pcbc_encrypt(des_inbuf,
                            storage,
                            (net_len < 8) ? 8 : net_len,
-                           schedule,
+                           v4_schedule,
                            v4_kdata->session,
                            DECRYPT);
        /* 
@@ -2054,7 +1632,7 @@ int len;
        (void) pcbc_encrypt((len < 8) ? garbage_buf : buf,
                            des_outbuf,
                            (len < 8) ? 8 : len,
-                           schedule,
+                           v4_schedule,
                            v4_kdata->session,
                            ENCRYPT);
 
index 194ef97008aae018f6fb3b22cb3b37c1aba91ae6..8e878b3080b1ef9afc8f828df9b1c2ca9ad1658a 100644 (file)
@@ -77,10 +77,15 @@ krb5_sigtype  sendsig();
 char   *krb_realm = (char *)0;
 void   try_normal();
 #define UCB_RSH "/usr/ucb/rsh"
+#endif
+
+#ifndef RLOGIN_PROGRAM
+#ifdef KERBEROS
 #define RLOGIN_PROGRAM KRB5_PATH_RLOGIN
 #else /* KERBEROS */
 #define RLOGIN_PROGRAM "/usr/ucb/rlogin"
 #endif  /* KERBEROS */
+#endif /* !RLOGIN_PROGRAM */
      
 #define        mask(s) (1 << ((s) - 1))
      
index 8ea3840199592d6791a374a8e78e4258fc915380..6e4cf677c5af0694c7b4bc3bf4cb7514cf49b6fd 100644 (file)
@@ -75,9 +75,6 @@ static char sccsid[] = "@(#)rshd.c    5.12 (Berkeley) 9/12/88";
  *   SERVE_V4 - Define this if v4 rlogin clients are also to be served.
  *   ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
  *              checked even for v4 clients (instead of .klogin).
- *   SERVE_NON_KRB - Define this is non-kerberized rlogin clients are 
- *              to be served. NOTE HOWEVER THAT THIS IS A SERIOUS
- *              SECURITY FLAW!
  *   LOG_ALL_LOGINS - Define this if you want to log all logins.
  *   LOG_OTHER_USERS - Define this if you want to log all principals that do
  *              not map onto the local user.
@@ -123,6 +120,7 @@ static char sccsid[] = "@(#)rshd.c  5.12 (Berkeley) 9/12/88";
 #include <errno.h>
 #include <pwd.h>
 #include <ctype.h>
+#include <string.h>
      
 #ifdef sun
 #include <sys/label.h>
@@ -179,7 +177,6 @@ extern
 #endif /* CRAY */
 int     errno;
 
-char   *index(), *rindex(), *strncat();
 /*VARARGS1*/
 int    error();
 
@@ -199,7 +196,7 @@ main(argc, argv)
     char *options, ch;
     int i;
     int fd;
-    int debug_port;
+    int debug_port = 0;
 
 #ifdef CRAY
     secflag = sysconf(_SC_CRAY_SECURE_SYS);
@@ -385,7 +382,6 @@ char cmdbuf[NCARGS+1];
 char *kremuser;
 krb5_principal client;
 krb5_authenticator *kdata;
-krb5_ticket        *ticket = 0;
 
 #ifdef SERVE_V4
 #include <kerberosIV/krb.h>
@@ -393,7 +389,10 @@ AUTH_DAT   *v4_kdata;
 KTEXT          v4_ticket;
 #endif
 
-int V4 = 0;    /* Set when connection is seen to be from a V4 client */
+int auth_sys = 0;      /* Which version of Kerberos used to authenticate */
+
+#define KRB5_RECVAUTH_V4       4
+#define KRB5_RECVAUTH_V5       5
 
 doit(f, fromp)
      int f;
@@ -479,6 +478,7 @@ doit(f, fromp)
        exit(1);
     }
 #ifdef KERBEROS
+    krb5_init_ets();
     if ((must_pass_rhosts || must_pass_one)
        && (fromp->sin_port >= IPPORT_RESERVED ||
            fromp->sin_port < IPPORT_RESERVED/2))
@@ -882,7 +882,7 @@ doit(f, fromp)
            failed_k5 = 1;
        }
 #else
-       if (V4) {
+       if (auth_sys == KRB5_RECVAUTH_V4) {
            /* kuserok returns 0 if OK */
            if (kuserok(v4_kdata, locuser)){
                syslog(LOG_ERR ,
@@ -1066,7 +1066,7 @@ doit(f, fromp)
     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
     strncat(username, pwd->pw_name, sizeof(username)-6);
-    cp = rindex(pwd->pw_shell, '/');
+    cp = strrchr(pwd->pw_shell, '/');
     if (cp)
       cp++;
     else
@@ -1374,557 +1374,116 @@ recvauth(netf, peersin, peeraddr)
      struct sockaddr_in peersin;
      krb5_address peeraddr;
 {
-    char hostname[100];
-    krb5_principal server;
     krb5_error_code status;
+    struct sockaddr_in laddr;
     char krb_vers[KRB_SENDAUTH_VLEN + 1];
     int len;
+    krb5_principal server;
+    krb5_data inbuf;
+    char v4_instance[INST_SZ]; /* V4 Instance */
+    char v4_version[9];
+    krb5_ticket        *ticket;
 
-    len = sizeof(int);
-    if ((status = krb5_net_read(netf, krb_vers, len)) != len)
-      return((status < 0) ? errno : ECONNABORTED);
-
-    krb_vers[len] = '\0';
-
-    if (!strncmp(krb_vers, KRB_SENDAUTH_VERS, len)) {
-       /* Must be V4 rlogin client */
-#ifdef SERVE_V4
-       char version[9];
-       struct sockaddr_in faddr;
-       char instance[INST_SZ];
-       long authoptions;
-       int len;
-       
-       V4 = 1;
-
-       authoptions = 0L;
-       
-       len = sizeof(faddr);
-       if (getsockname(0, (struct sockaddr *)&faddr, &len)) {
+    len = sizeof(laddr);
+    if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
            exit(1);
-       }
-
-       v4_kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
-       v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
-
-       strcpy(instance, "*");
-
-       if (status = v4_recvauth(krb_vers, authoptions, netf,
-                                v4_ticket, "rcmd",
-                                instance, &peersin, &faddr,
-                                v4_kdata, "", (bit_64 *)0, version)) {
-           return(status);
-       }
-
-       getstr(netf, locuser, sizeof (locuser), "locuser");
-       getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
-       /* We do not really know the remote user's login name.
-         * Assume it to be the same as the first component of the
-        * principal's name. 
-         */
-       strcpy(remuser, v4_kdata->pname);
-       kremuser = (char *) malloc(strlen(v4_kdata->pname) + 1 +
-                                    strlen(v4_kdata->pinst) + 1 +
-                                    strlen(v4_kdata->prealm) + 1);
-       sprintf(kremuser, "%s/%s@%s", v4_kdata->pname,
-               v4_kdata->pinst, v4_kdata->prealm);
-
-       if (status = krb5_parse_name(kremuser, &client))
-         return(status);
-#else
-       syslog(LOG_ERR, "Kerberos V4 authentication: rejected!");
-       error("Permission denied");
-#endif
-    }
-    else if (isprint(krb_vers[0])) { 
-       /* Un-kerberized rlogin client */
-#ifdef SERVE_NON_KRB
-       strncpy(remuser, krb_vers, sizeof(int));
-       getstr(netf, remuser+4, sizeof(remuser)-sizeof(int), "remuser");
-       getstr(netf, locuser, sizeof(locuser), "locuser");
-       getstr(netf, cmdbuf, sizeof(cmdbuf), "command");        
-#else
-       syslog(LOG_ERR, "Un-kerberized client: authentication rejected!");
-       error( "Permission denied");
-#endif
     }
-    else {
-       /* Must be V5 rlogin client */
-       krb5_principal server;
-       krb5_data inbuf;
-       int len;
-
-       /*
-        * First read the sendauth version string and check it.
-        */
-       inbuf.length = ntohl(*((int *) krb_vers));
-
-       if (inbuf.length < 0 || inbuf.length > 25)
-         return 255;
-       
-       if (!(inbuf.data = malloc(inbuf.length))) {
-           return(ENOMEM);
-       }
        
-       if ((len = krb5_net_read(netf, inbuf.data, inbuf.length)) !=
-           inbuf.length) {
-           krb5_xfree(inbuf.data);
-           return((len < 0) ? errno : ECONNABORTED);
-       }
-
-       if (strcmp(inbuf.data, "KRB5_SENDAUTH_V1.0")) {
-           krb5_xfree(inbuf.data);
-           status = KRB5_SENDAUTH_BADAUTHVERS;
-           return status;
-       }
-       krb5_xfree(inbuf.data);
-
 #ifdef unicos61
 #define SIZEOF_INADDR  SIZEOF_in_addr
 #else
 #define SIZEOF_INADDR sizeof(struct in_addr)
 #endif
 
-       gethostname(hostname, 100);
-       if (status = krb5_sname_to_principal(hostname,"host", KRB5_NT_SRV_HST,
-                                            &server)) {
+    if (status = krb5_sname_to_principal(NULL, "host", KRB5_NT_SRV_HST,
+                                        &server)) {
            syslog(LOG_ERR, "parse server name %s: %s", "host",
                   error_message(status));
            exit(1);
-       }
-       krb5_princ_type(server) = KRB5_NT_SRV_HST;
-
-       krb5_init_ets();
-       
-       if (status = v5_recvauth(&netf,
-                                "KCMDV0.1",
-                                server,    /* Specify daemon principal */
-                                &peeraddr, /* We do want to match this
-                                              against caddrs in the
-                                              ticket. */
-                                0,         /* use srv5tab */
-                                0,         /* no keyproc */
-                                0,         /* no keyproc arg */
-                                0,         /* no rc_type */
-                                0,         /* no seq number */
-                                &client,   /* return client */
-                                &ticket,   /* return ticket */
-                                &kdata     /* return authenticator */
-                                )) {
-           error("Kerberos rsh or rcp failed: %s\n",
-                 error_message(status));
-           exit(1);
-       }
-       krb5_unparse_name(kdata->client,&kremuser);
-           
-       getstr(netf, locuser, sizeof(locuser), "locuser");
-       getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
-       getstr(netf, remuser, sizeof(locuser), "remuser");
-
-       if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) {
-           error("Error reading message: %s\n",
-                 error_message(status));
-           exit(1);
-       }
-
-       if (inbuf.length) {
-           if (status = rd_and_store_for_creds(&inbuf, ticket, locuser)) {
-               error("Can't get forwarded credentials: %s\n",
-                     error_message(status));
-               exit(1);
-           }
-       }
     }
-    return 0;
-}
-
-#ifdef SERVE_V4
-
-#ifndef max
-#define        max(a,b) (((a) > (b)) ? (a) : (b))
-#endif /* max */
 
-krb5_error_code
-v4_recvauth(krb_vers, options, fd, ticket, service, instance, faddr,
-           laddr, kdata, filename, schedule, version)
-     char *krb_vers;
-     long options;                      /* bit-pattern of options */
-     int fd;                            /* file descr. to read from */
-     KTEXT ticket;                      /* storage for client's ticket */
-     char *service;                     /* service expected */
-     char *instance;                    /* inst expected (may be filled in) */
-     struct sockaddr_in *faddr;         /* address of foreign host on fd */
-     struct sockaddr_in *laddr;         /* local address */
-     AUTH_DAT *kdata;           /* kerberos data (returned) */
-     char *filename;                    /* name of file with service keys */
-     Key_schedule schedule;             /* key schedule (return) */
-     char *version;                     /* version string (filled in) */
-{
-    
-    int i, cc, old_vers = 0;
-    char *cp;
-    int rem;
-    long tkt_len, priv_len;
-    u_long cksum;
-    u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)];
-    
-    /* read the protocol version number */
-    if (krb_net_read(fd, krb_vers+sizeof(int), 
-                    KRB_SENDAUTH_VLEN-sizeof(int)) !=
-       KRB_SENDAUTH_VLEN-sizeof(int))
-      return(errno);
-    krb_vers[KRB_SENDAUTH_VLEN] = '\0';
-    
-    /* check version string */
-    if (strcmp(krb_vers,KRB_SENDAUTH_VERS)) {
-       return(KFAILURE);
-    } else {
-       /* read the application version string */
-       if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) !=
-           KRB_SENDAUTH_VLEN)
-         return(errno);
-       version[KRB_SENDAUTH_VLEN] = '\0';
-       
-       /* get the length of the ticket */
-       if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) !=
-           sizeof(tkt_len))
-         return(errno);
-       
-       /* sanity check */
-       ticket->length = ntohl((unsigned long)tkt_len);
-       if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) {
-           if (options & KOPT_DO_MUTUAL) {
-               rem = KFAILURE;
-               goto mutual_fail;
-           } else
-             return(KFAILURE); /* XXX there may still be junk on the fd? */
-       }
-       
-       /* read the ticket */
-       if (krb_net_read(fd, (char *) ticket->dat, ticket->length)
-           != ticket->length)
-         return(errno);
-    }
-    /*
-     * now have the ticket.  decrypt it to get the authenticated
-     * data.
-     */
-    rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr,
-                    kdata,filename);
-    
-    if (old_vers) return(rem);  /* XXX can't do mutual with old client */
-    
-    /* if we are doing mutual auth (used by erlogin), compose a response */
-    if (options & KOPT_DO_MUTUAL) {
-       if (rem != KSUCCESS)
-         /* the krb_rd_req failed */
-         goto mutual_fail;
-       
-       /* add one to the (formerly) sealed checksum, and re-seal it
-          for return to the client */
-       cksum = kdata->checksum + 1;
-       cksum = htonl(cksum);
-#ifdef CRYPT
-       key_sched(kdata->session,schedule);
-#endif
-       priv_len = krb_mk_priv((unsigned char *)&cksum,
-                              tmp_buf,
-                              (unsigned long) sizeof(cksum),
-                              schedule,
-                              kdata->session,
-                              laddr,
-                              faddr);
-       if (priv_len < 0) {
-           /* re-sealing failed; notify the client */
-           rem = KFAILURE;      /* XXX */
-         mutual_fail:
-           priv_len = -1;
-           tkt_len = htonl((unsigned long) priv_len);
-           /* a length of -1 is interpreted as an authentication
-              failure by the client */
-           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
-               != sizeof(tkt_len))
-             return(cc);
-           return(rem);
-       } else {
-           /* re-sealing succeeded, send the private message */
-           tkt_len = htonl((unsigned long)priv_len);
-           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
-               != sizeof(tkt_len))
-             return(cc);
-           if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len))
-               != (int) priv_len)
-             return(cc);
+    strcpy(v4_instance, "*");
+
+    status = krb5_compat_recvauth(&netf,
+                                 "KCMDV0.1",
+                                 server, /* Specify daemon principal */
+                                 &peeraddr, /* We do want to match */
+                                            /* this against caddrs in */
+                                            /* the ticket */
+                                 0, /* use v5srvtab */
+                                 0, /* no keyproc */
+                                 0, /* no keyprocarg */
+                                 0, /* default rc_type */
+                                 0, /* no flags */
+
+                                 0, /*v4_opts*/
+                                 "rcmd", /* v4_service */
+                                 v4_instance, /* v4_instance */
+                                 &peersin, /* foriegn address */
+                                 &laddr, /* our local address */
+                                 "", /* use default srvtab */
+
+                                 &auth_sys, /* which authentication system */
+                                 0, /* no seq number */
+                                 &client, /* return client */
+                                 &ticket, /* return ticket */
+                                 &kdata, /* return authenticator */
+                                 
+                                 &v4_kdata, 0, v4_version);
+
+    if (status) {
+       if (auth_sys == KRB5_RECVAUTH_V5) {
+           /*
+            * clean up before exiting
+            */
+           getstr(netf, locuser, sizeof(locuser), "locuser");
+           getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
+           getstr(netf, remuser, sizeof(locuser), "remuser");
        }
+       return status;
     }
-    return(0);
-}
-
-#endif /* SERVE_V4 */
 
-extern krb5_flags      krb5_kdc_default_options;
+    getstr(netf, locuser, sizeof(locuser), "locuser");
+    getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
 
-krb5_error_code
-v5_recvauth(/* IN */
-           fd, appl_version, server, sender_addr, fetch_from,
-           keyproc, keyprocarg, rc_type, 
-           /* OUT */
-           seq_number, client, ticket, authent)
-     krb5_pointer      fd;
-     char      *appl_version;
-     krb5_principal    server;
-     krb5_address      *sender_addr;
-     krb5_pointer      fetch_from;
-     krb5_int32        *seq_number;
-     char              *rc_type;
-     krb5_rdreq_key_proc keyproc;
-     krb5_pointer keyprocarg;
-     krb5_principal    *client;
-     krb5_ticket       **ticket;
-     krb5_authenticator        **authent;
-{
-    krb5_error_code    retval, problem;
-    krb5_data  inbuf;
-    krb5_tkt_authent   *authdat;
-    krb5_data          outbuf;
-    krb5_rcache rcache;
-    krb5_octet         response;
-    krb5_data  *server_name;
-    char *cachename;
-    extern krb5_deltat krb5_clockskew;
-    static char                *rc_base = "rc_";
-    
-    /*
-     * Zero out problem variable.  If problem is set at the end of
-     * the intial version negotiation section, it means that we
-     * need to send an error code back to the client application
-     * and exit.
-     */
-    problem = 0;
-  
-    /*
-     * Read and check the application version string.
-     */
-    if (retval = krb5_read_message(fd, &inbuf))
-      return(retval);
-    if (strcmp(inbuf.data, appl_version)) {
-       krb5_xfree(inbuf.data);
-       if (!problem)
-         problem = KRB5_SENDAUTH_BADAPPLVERS;
-    }
-    krb5_xfree(inbuf.data);
-    /*
-     * OK, now check the problem variable.  If it's zero, we're
-     * fine and we can continue.  Otherwise, we have to signal an
-     * error to the client side and bail out.
-     */
-    switch (problem) {
-      case 0:
-       response = 0;
-       break;
-      case KRB5_SENDAUTH_BADAUTHVERS:
-       response = 1;
-       break;
-      case KRB5_SENDAUTH_BADAPPLVERS:
-       response = 2;
-       break;
-      default:
-       /*
-        * Should never happen!
-        */
-       response = 255;
-#ifdef SENDAUTH_DEBUG
-       fprintf(stderr, "Programming botch in recvauth!  problem = %d",
-               problem);
-       abort();
-#endif
-       break;
+    if (auth_sys == KRB5_RECVAUTH_V4) {
+       /* We do not really know the remote user's login name.
+         * Assume it to be the same as the first component of the
+        * principal's name. 
+         */
+       strcpy(remuser, v4_kdata->pname);
+       kremuser = (char *) malloc(strlen(v4_kdata->pname) + 1 +
+                                  strlen(v4_kdata->pinst) + 1 +
+                                  strlen(v4_kdata->prealm) + 1);
+       sprintf(kremuser, "%s/%s@%s", v4_kdata->pname,
+               v4_kdata->pinst, v4_kdata->prealm);
+       
+       if (status = krb5_parse_name(kremuser, &client))
+         return(status);
+       return 0;
     }
 
-    /*
-     * Now we actually write the response.  If the response is non-zero,
-     * exit with a return value of problem
-     */
-    if ((krb5_net_write(*((int *) fd), (char *)&response, 1)) < 0) {
-       return(problem); /* We'll return the top-level problem */
-    }
-    if (problem)
-      return(problem);
-    rcache = NULL;
-#ifdef WORKING_RCACHE
-    /*
-     * Setup the replay cache.
-     */
-    if (!(rcache = (krb5_rcache) malloc(sizeof(*rcache)))) 
-      problem = ENOMEM;
-    if (!problem) 
-      problem = krb5_rc_resolve_type(&rcache,
-                                    rc_type ? rc_type : "dfl");
-    cachename = NULL;
-    server_name = krb5_princ_component(server, 0);
-    if (!problem && !(cachename = malloc(server_name->length+1+strlen(rc_base))))
-      problem = ENOMEM;
-    if (!problem) {
-       strcpy(cachename, rc_base ? rc_base : "rc_");
-       strncat(cachename, server_name->data, server_name->length);
-       cachename[server_name->length+strlen(rc_base)] = '\0';
-       problem = krb5_rc_resolve(rcache, cachename);
-    }
-    if (!problem) {
-       if (krb5_rc_recover(rcache))
-         /*
-          * If the rc_recover didn't work, then try
-          * initializing the replay cache.
-          */
-         problem = krb5_rc_initialize(rcache, krb5_clockskew);
-       if (problem) {
-           krb5_rc_close(rcache);
-           rcache = NULL;
-       }
-    }
-#endif
+    /* Must be V5  */
+       
+    getstr(netf, remuser, sizeof(locuser), "remuser");
 
-    /*
-     * Now, let's read the AP_REQ message and decode it
-     */
-    if (retval = krb5_read_message(fd, &inbuf)) {
-#ifdef WORKING_RCACHE          
-       (void) krb5_rc_close(rcache);
-       if (cachename)
-         free(cachename);
-#endif
-       return(retval);
-    }
-    authdat = 0;                       /* so we can tell if we need to
-                                          free it later... */
-    if (!problem)
-      problem = krb5_rd_req(&inbuf, server, sender_addr, fetch_from,
-                           keyproc, keyprocarg, rcache, &authdat);
-    krb5_xfree(inbuf.data);
-#ifdef WORKING_RCACHE
-    if (rcache)
-      retval = krb5_rc_close(rcache);
-#endif
-    if (!problem && retval)
-      problem = retval;
-#ifdef WORKING_RCACHE
-    if (cachename)
-      free(cachename);
-#endif
+    if (status = krb5_unparse_name(client, &kremuser))
+       return status;
     
-    /*
-     * If there was a problem, send back a krb5_error message,
-     * preceeded by the length of the krb5_error message.  If
-     * everything's ok, send back 0 for the length.
-     */
-    if (problem) {
-       krb5_error      error;
-       const   char *message;
-       
-       memset((char *)&error, 0, sizeof(error));
-       krb5_us_timeofday(&error.stime, &error.susec);
-       error.server = server;
-       error.error = problem - ERROR_TABLE_BASE_krb5;
-       if (error.error > 127)
-         error.error = KRB_ERR_GENERIC;
-       message = error_message(problem);
-       error.text.length  = strlen(message) + 1;
-       if (!(error.text.data = malloc(error.text.length)))
-         return(ENOMEM);
-       strcpy(error.text.data, message);
-       if (retval = krb5_mk_error(&error, &outbuf)) {
-           free(error.text.data);
-           return(retval);
-       }
-       free(error.text.data);
-    } else {
-       outbuf.length = 0;
-       outbuf.data = 0;
-    }
-    if (retval = krb5_write_message(fd, &outbuf)) {
-       if (outbuf.data)
-         krb5_xfree(outbuf.data);
-       if (!problem)
-         krb5_free_tkt_authent(authdat);
-       return(retval);
-    }
-    if (problem) {
-       /*
-        * We sent back an error, we need to return
-        */
-       if (authdat) krb5_free_tkt_authent(authdat);
-       return(problem);
+    if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) {
+       error("Error reading message: %s\n",
+             error_message(status));
+       exit(1);
     }
 
-    /*
-     * Here lies the mutual authentication stuff...
-     *
-     * We're going to compose and send a AP_REP message.
-     */
-    if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) {
-       krb5_ap_rep_enc_part    repl;
-       
-       /*
-        * Generate a random sequence number
-        */
-       if (seq_number &&
-           (retval = krb5_generate_seq_number(authdat->ticket->enc_part2->session,
-                                              seq_number))) {
-           krb5_free_tkt_authent(authdat);
-           return(retval);
-       }
-       
-       repl.ctime = authdat->authenticator->ctime;
-       repl.cusec = authdat->authenticator->cusec;
-       repl.subkey = authdat->authenticator->subkey;
-       if (seq_number)
-         repl.seq_number = *seq_number;
-       else
-         repl.seq_number = 0;
-       
-       if (retval = krb5_mk_rep(&repl,
-                                authdat->ticket->enc_part2->session,
-                                &outbuf)) {
-           krb5_free_tkt_authent(authdat);
-           return(retval);
-       }
-       if (retval = krb5_write_message(fd, &outbuf)) {
-           krb5_xfree(outbuf.data);
-           krb5_free_tkt_authent(authdat);
-           return(retval);
+    if (inbuf.length) { /* Forwarding being done, read creds */
+       if (status = rd_and_store_for_creds(&inbuf, ticket, locuser)) {
+           error("Can't get forwarded credentials: %s\n",
+                 error_message(status));
+           exit(1);
        }
-       krb5_xfree(outbuf.data);
     }
-    
-    /*
-     * At this point, we've won.  We just need to copy whatever
-     * parts of the authdat structure which the user wants, clean
-     * up, and exit.
-     */
-    if (client)
-      if (retval =
-         krb5_copy_principal(authdat->ticket->enc_part2->client,
-                             client))
-       return(retval);
-    /*
-     * The following efficiency hack assumes knowledge about the
-     * structure of krb5_tkt_authent.  If we later add additional
-     * allocated substructures to krb5_tkt_authent, they will have
-     * to be reflected here; otherwise, we will probably have a
-     * memory leak.
-     *
-     * If the user wants that part of the authdat structure,
-     * return it; otherwise free it.
-     */
-    if (ticket)
-      *ticket = authdat->ticket;
-    else
-      krb5_free_ticket(authdat->ticket);
-    if (authent)
-      *authent = authdat->authenticator;
-    else
-      krb5_free_authenticator(authdat->authenticator);
-    krb5_xfree(authdat);
+    krb5_free_ticket(ticket);
     return 0;
 }
 
index 55118414a3e1b9c3af4c5a88b8ece840f3b450ea..e09a80f33a1991ff0d89975ff58857cd08bd83a3 100644 (file)
@@ -40,15 +40,22 @@ static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89";
  * login -r hostname   (for rlogind)
  * login -h hostname   (for telnetd, etc.)
  * login -f name       (for pre-authenticated login: datakit, xterm, etc.)
+ * login -e name       (for pre-authenticated encrypted, must do term
+ *                      negotiation)
+ * ifdef KRB4
+ * login -k hostname (for Kerberos V4 rlogind with password access)
+ * login -K hostname (for Kerberos V4 rlogind with restricted access)
+ * endif KRB4 
+ *
+ * only one of: -r -f -e -k -K
+ * only one of: -r -h -k -K
  */
 
-#define VFS
-#define BYPASS_ROOT_CHK
-
+#include <sys/types.h>
 #include <sys/param.h>
-#ifndef VFS
+#ifdef OQUOTA
 #include <sys/quota.h>
-#endif VFS
+#endif
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -57,7 +64,11 @@ static char sccsid[] = "@(#)login.c  5.25 (Berkeley) 1/6/89";
 
 #include <utmp.h>
 #include <signal.h>
+
+#if !defined(_AIX)
 #include <lastlog.h>
+#endif
+
 #include <errno.h>
 #ifndef NOTTYENT
 #include <ttyent.h>
@@ -68,9 +79,34 @@ static char sccsid[] = "@(#)login.c  5.25 (Berkeley) 1/6/89";
 #include <setjmp.h>
 #include <stdio.h>
 #include <strings.h>
-
+#ifdef KRB4
+#include <krb.h>
 #include <netdb.h>
-#include <string.h>
+#include <netinet/in.h>
+#ifdef BIND_HACK
+#include <arpa/nameser.h>
+#include <arpa/resolv.h>
+#endif /* BIND_HACK */
+#endif /* KRB4 */
+
+#ifdef POSIX
+#include <stdlib.h>
+#include <termios.h>
+#ifdef _AIX
+#include <termio.h>
+#endif
+#endif
+
+#ifdef _IBMR2
+#include <usersec.h>
+#include <sys/id.h>
+#endif
+
+#if defined(_AIX)
+#define PRIO_OFFSET 20
+#else
+#define PRIO_OFFSET 0
+#endif
 
 #ifdef UIDGID_T
 uid_t getuid();
@@ -91,13 +127,24 @@ int getuid();
 #define        LASTLOG         "/usr/adm/lastlog"
 #define        BSHELL          "/bin/sh"
 
-#ifdef VFS
+#if !defined(OQUOTA) && !defined(QUOTAWARN)
 #define QUOTAWARN      "/usr/ucb/quota" /* warn user about quotas */
-#endif VFS
+#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"
 
 #define        UT_HOSTSIZE     sizeof(((struct utmp *)0)->ut_host)
 #define        UT_NAMESIZE     sizeof(((struct utmp *)0)->ut_name)
 
+#define MAXENVIRON     32
+
 /*
  * This bounds the time given to login.  Not a define so it can
  * be patched on machines where it's too small.
@@ -107,6 +154,7 @@ int timeout = 300;
 struct passwd *pwd;
 char term[64], *hostname, *username;
 
+#ifndef POSIX
 struct sgttyb sgttyb;
 struct tchars tc = {
        CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
@@ -114,20 +162,49 @@ struct tchars tc = {
 struct ltchars ltc = {
        CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
 };
+#endif
 
 extern int errno;
 
+#ifdef KRB4
+#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 */
+
+extern char *krb_err_txt[];            /* From libkrb */
+
+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 */
+
+char *getenv();
+char *strsave();
+void dofork();
+
 #ifdef POSIX
 typedef void sigtype;
 #else
 typedef int sigtype;
 #endif /* POSIX */
 
-#define EXCL_TEST if (rflag || hflag) { \
-                      fprintf(stderr, \
-                              "login: only one of -r and -h allowed.\n"); \
-                      exit(1);\
-                    }
+#define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag) { \
+                               fprintf(stderr, \
+                                   "login: only one of -r, -k, -K, -e, and -f allowed.\n"); \
+                               exit(1);\
+                       }
+
+#define EXCL_HOST_TEST if (rflag || kflag || Kflag || hflag) { \
+                               fprintf(stderr, \
+                                   "login: only one of -r, -k, -K, and -h allowed.\n"); \
+                               exit(1);\
+                       }
+
 main(argc, argv)
        int argc;
        char **argv;
@@ -135,53 +212,62 @@ main(argc, argv)
        extern int optind;
        extern char *optarg, **environ;
        struct group *gr;
-       register int ch;
+       register int ch, i;
        register char *p;
        int fflag, hflag, pflag, rflag, cnt;
+       int kflag, Kflag, eflag;
        int quietlog, passwd_req, ioctlval;
        sigtype timedout();
-       char *domain, *salt, *envinit[1], *ttyn, *tty;
+       char *domain, *salt, **envinit, *ttyn, *tty, *ktty;
        char tbuf[MAXPATHLEN + 2];
        char *ttyname(), *stypeof(), *crypt(), *getpass();
-       time_t time();
+       time_t time(), login_time;
        off_t lseek();
-       struct hostent *hp;
+#ifdef POSIX
+       struct termios tc;
+#endif
 
        (void)signal(SIGALRM, timedout);
        (void)alarm((u_int)timeout);
        (void)signal(SIGQUIT, SIG_IGN);
        (void)signal(SIGINT, SIG_IGN);
-       (void)setpriority(PRIO_PROCESS, 0, 0);
-#ifndef VFS
+       (void)setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+#ifdef OQUOTA
        (void)quota(Q_SETUID, 0, 0, 0);
-#endif VFS
+#endif
 
        /*
         * -p is used by getty to tell login not to destroy the environment
         * -r is used by rlogind to cause the autologin protocol;
         * -f is used to skip a second login authentication 
+        * -e is used to skip a second login authentication, but allows
+        *      login as root.
         * -h is used by other servers to pass the name of the
         * remote host to login so that it may be placed in utmp and wtmp
+        * -k is used by klogind to cause the Kerberos V4 autologin protocol;
+        * -K is used by klogind to cause the Kerberos V4 autologin
+        *    protocol with restricted access.
         */
        (void)gethostname(tbuf, sizeof(tbuf));
-       domain = index(tbuf, '.');
+       domain = strchr(tbuf, '.');
 
-       fflag = hflag = pflag = rflag = 0;
+       fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
        passwd_req = 1;
-       while ((ch = getopt(argc, argv, "fh:pr:")) != EOF)
+       while ((ch = getopt(argc, argv, "feh:pr:k:K:")) != EOF)
                switch (ch) {
                case 'f':
+                       EXCL_AUTH_TEST;
                        fflag = 1;
                        break;
                case 'h':
-                       EXCL_TEST;
+                       EXCL_HOST_TEST;
                        if (getuid()) {
                                fprintf(stderr,
                                    "login: -h for super-user only.\n");
                                exit(1);
                        }
                        hflag = 1;
-                       if (domain && (p = index(optarg, '.')) &&
+                       if (domain && (p = strchr(optarg, '.')) &&
                            strcmp(p, domain) == 0)
                                *p = 0;
                        hostname = optarg;
@@ -190,7 +276,8 @@ main(argc, argv)
                        pflag = 1;
                        break;
                case 'r':
-                       EXCL_TEST;
+                       EXCL_AUTH_TEST;
+                       EXCL_HOST_TEST;
                        if (getuid()) {
                                fprintf(stderr,
                                    "login: -r for super-user only.\n");
@@ -203,14 +290,51 @@ main(argc, argv)
                        }
                        rflag = 1;
                        passwd_req = (doremotelogin(optarg) == -1);
-                       if (domain && (p = index(optarg, '.')) &&
+                       if (domain && (p = strchr(optarg, '.')) &&
                            !strcmp(p, domain))
                                *p = '\0';
                        hostname = optarg;
                        break;
+#ifdef KRB4
+               case 'k':
+               case 'K':
+                       EXCL_AUTH_TEST;
+                       EXCL_HOST_TEST;
+                       if (getuid()) {
+                               fprintf(stderr,
+                                   "login: -%c for super-user only.\n", ch);
+                               exit(1);
+                       }
+                       /* "-k hostname" must be last args */
+                       if (optind != argc) {
+                               fprintf(stderr, "Syntax error.\n");
+                               exit(1);
+                       }
+                       if (ch == 'K')
+                           Kflag = 1;
+                       else
+                           kflag = 1;
+                       passwd_req = (do_krb_login(optarg,
+                                                  Kflag ? 1 : 0) == -1);
+                       if (domain && (p = strchr(optarg, '.')) &&
+                           !strcmp(p, domain))
+                               *p = '\0';
+                       hostname = optarg;
+                       break;
+#endif /* KRB4 */
+               case 'e':
+                       EXCL_AUTH_TEST;
+                       if (getuid()) {
+                           fprintf(stderr,
+                                   "login: -e for super-user only.\n");
+                           exit(1);
+                       }
+                       eflag = 1;
+                       passwd_req = 0;
+                       break;
                case '?':
                default:
-                       fprintf(stderr, "usage: login [-fp] [-h hostname] [-r hostname] [username] \n");
+                       fprintf(stderr, "usage: login [-fp] [username]\n");
                        exit(1);
                }
        argc -= optind;
@@ -218,34 +342,69 @@ main(argc, argv)
        if (*argv)
                username = *argv;
 
-       if (!(hp = gethostbyname(hostname))) {
-           fprintf(stderr, "Unknown host: %s\n", hostname);
-           exit(1);
-       }
-       hostname = malloc(strlen(hp->h_name)+1);
-       if (!hostname) {
-               fprintf(stderr, "Couldn't malloc space for hostname.\n");
-               exit(1);
-       }
-       strcpy(hostname, hp->h_name);
-
+#if !defined(_AIX)
        ioctlval = 0;
        (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
        (void)ioctl(0, TIOCNXCL, (char *)0);
        (void)fcntl(0, F_SETFL, ioctlval);
+#endif
+#ifdef POSIX
+       (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 (rflag)
+       if (eflag)
+               lgetstr(term, sizeof(term), "Terminal type");
+#ifdef POSIX
+       if (rflag || kflag || Kflag || eflag)
+               doremoteterm(&tc);
+       tc.c_cc[VMIN] = 1;
+       tc.c_cc[VTIME] = 0;
+       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;
+       tc.c_cc[VEOL] = CNUL;
+       /* The following are common extensions to POSIX */
+#ifdef VEOL2
+       tc.c_cc[VEOL2] = CNUL;
+#endif
+#ifdef VSUSP
+       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 VWERSE
+       tc.c_cc[VWERSE] = CWERASE;
+#endif
+       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 *)&ltc);
        (void)ioctl(0, TIOCSETC, (char *)&tc);
        (void)ioctl(0, TIOCSETP, (char *)&sgttyb);
+#endif
 
        for (cnt = getdtablesize(); cnt > 2; cnt--)
                (void) close(cnt);
@@ -253,11 +412,19 @@ main(argc, argv)
        ttyn = ttyname(0);
        if (ttyn == NULL || *ttyn == '\0')
                ttyn = "/dev/tty??";
-       if (tty = rindex(ttyn, '/'))
+
+       /* This allows for tty names of the form /dev/pts/4 as well */
+       if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/')))
                ++tty;
        else
                tty = ttyn;
 
+       /* For kerberos tickets, extract only the last part of the ttyname */
+       if (ktty = strrchr(tty, '/'))
+               ++ktty;
+       else
+               ktty = tty;
+
 #ifndef LOG_ODELAY /* 4.2 syslog ... */                      
        openlog("login", 0);
 #else
@@ -265,13 +432,28 @@ main(argc, argv)
 #endif /* 4.2 syslog */
 
        for (cnt = 0;; username = NULL) {
+#ifdef KRB4
+               char pp[9], pp2[MAXPWSIZE], *namep;
+               int krbval;
+               char realm[REALM_SZ];
+               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(_IBMR2)
                ioctlval = 0;
                (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+#endif
 
                if (username == NULL) {
                        fflag = 0;
                        getloginname();
                }
+
                if (pwd = getpwnam(username))
                        salt = pwd->pw_passwd;
                else
@@ -288,12 +470,8 @@ main(argc, argv)
                if (fflag && pwd) {
                        int uid = (int) getuid();
 
-                       passwd_req = (uid && uid != pwd->pw_uid)
-#ifndef BYPASS_ROOT_CHK
-                         || (pwd->pw_uid == 0);
-#else
-                       ;
-#endif
+                       passwd_req = pwd->pw_uid == 0 ||
+                           (uid && uid != pwd->pw_uid);
                }
 
                /*
@@ -303,11 +481,115 @@ main(argc, argv)
                if (!passwd_req || pwd && !*pwd->pw_passwd)
                        break;
 
-               (void) setpriority(PRIO_PROCESS, 0, -4);
-               p = crypt(getpass("Password:"), salt);
-               (void) setpriority(PRIO_PROCESS, 0, 0);
+#ifdef KRB4
+               kpass_ok = 0;
+               lpass_ok = 0;
+
+               (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
+               if (read_long_pw_string(pp2, sizeof(pp2)-1, "Password: ", 0)) {
+                   /* reading password failed... */
+                   (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+                   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, pwd->pw_passwd);
+               bzero (pp, sizeof(pp)); /* To the best of my recollection, Senator... */
+               lpass_ok = !strcmp (namep, pwd->pw_passwd);
+               
+               if (pwd->pw_uid != 0) { /* Don't get tickets for root */
+
+                   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 */
+#if 0  /* XXX krb5 has defaults; don't do this. */
+                   /* Set up the ticket file environment variable */
+                   strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile));
+                   strncat(tkfile, ktty,
+                           sizeof(tkfile) - strlen(tkfile) - 1);
+                   (void) setenv(KRB_ENVIRON, tkfile, 1);
+                   krb_set_tkt_string(tkfile);
+#endif
+
+#ifdef _IBMR2
+                   krbval = setuidx(ID_REAL|ID_EFFECTIVE, pwd->pw_uid);
+#else
+                   krbval = setreuid(pwd->pw_uid, -1);
+#endif
+                   if (krbval) {
+                       /* can't set ruid to user! */
+                       krbval = -1;
+                       fprintf(stderr,
+                               "login: Can't set ruid for ticket file.\n");
+                   } else
+                       krbval = krb_get_pw_in_tkt(username, "",
+                                                  realm, "krbtgt",
+                                                  realm,
+                                                  DEFAULT_TKT_LIFE, pp2);
+                   bzero (pp2, sizeof(pp2));
+                   (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+                   switch (krbval) {
+                   case INTK_OK:
+                       kpass_ok = 1;
+                       krbflag = 1;
+                       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) bzero (pp2, sizeof(pp2));
+                   (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+               }
+
+               /* Policy: If local password is good, user is good.
+                  We really can't trust the Kerberos password,
+                  because somebody on the net could spoof the
+                  Kerberos server (not easy, but possible).
+                  Some sites might want to use it anyways, in
+                  which case they should change this line
+                  to:
+                  if (kpass_ok)
+                  */
+               if (lpass_ok)
+                   break;
+bad_login:
+               if (krbflag)
+                   dest_tkt();         /* clean up tickets if login fails */
+#else /* !KRB4 */
+               (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
+               p = crypt(getpass("password:"), salt);
+               (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
                if (pwd && !strcmp(p, pwd->pw_passwd))
                        break;
+#endif /* KRB4 */
 
                printf("Login incorrect\n");
                if (++cnt >= 5) {
@@ -331,9 +613,10 @@ main(argc, argv)
        /*
         * If valid so far and root is logging in, see if root logins on
         * this terminal are permitted.
+        *
+        * We allow authenticated remote root logins (except -r style)
         */
-#ifndef BYPASS_ROOT_CHK
-       if (pwd->pw_uid == 0 && !rootterm(tty)) {
+       if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) {
                if (hostname)
                        syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
                            tty, UT_HOSTSIZE, hostname);
@@ -342,9 +625,8 @@ main(argc, argv)
                printf("Login incorrect\n");
                sleepexit(1);
        }
-#endif
 
-#ifndef VFS
+#ifdef OQUOTA
        if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
                switch(errno) {
                case EUSERS:
@@ -360,7 +642,7 @@ main(argc, argv)
                }
                sleepexit(0);
        }
-#endif /* !VFS */
+#endif
 
        if (chdir(pwd->pw_dir) < 0) {
                printf("No directory %s!\n", pwd->pw_dir);
@@ -374,7 +656,8 @@ main(argc, argv)
        {
                struct utmp utmp;
 
-               (void)time(&utmp.ut_time);
+               bzero((char *)&utmp, sizeof(utmp));
+               login_time = time(&utmp.ut_time);
                (void) strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
                if (hostname)
                    (void) strncpy(utmp.ut_host, hostname,
@@ -388,7 +671,7 @@ main(argc, argv)
        quietlog = access(HUSHLOGIN, F_OK) == 0;
        dolastlog(quietlog, tty);
 
-       if (!hflag && !rflag) { /* XXX */
+       if (!hflag && !rflag && !kflag && !Kflag && !eflag) {   /* XXX */
                static struct winsize win = { 0, 0, 0, 0 };
 
                (void)ioctl(0, TIOCSWINSZ, (char *)&win);
@@ -396,48 +679,144 @@ main(argc, argv)
 
        (void)chown(ttyn, pwd->pw_uid,
            (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+#ifdef KRB4
+       if(krbflag)
+           (void) chown(getenv(KRB_ENVIRON), pwd->pw_uid, pwd->pw_gid);
+#endif
        (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();
+       }
+#endif
+       /* Fork so that we can call kdestroy */
+       dofork();
+#endif /* KRB4 */
        (void)setgid((gid_type) pwd->pw_gid);
-
        (void) initgroups(username, pwd->pw_gid);
 
-#ifndef VFS
+#ifdef OQUOTA
        quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
 #endif
-       (void)setuid((uid_type) pwd->pw_uid);
+       /* This call MUST succeed */
+#ifdef _IBMR2
+       setuidx(ID_LOGIN, pwd->pw_uid);
+#endif
+       if(setuid((uid_type) pwd->pw_uid) < 0) {
+            perror("setuid");
+            sleepexit(1);
+       }
 
        if (*pwd->pw_shell == '\0')
                pwd->pw_shell = BSHELL;
        /* turn on new line discipline for the csh */
        else if (!strcmp(pwd->pw_shell, "/bin/csh")) {
+#if !defined(_IBMR2)
                ioctlval = NTTYDISC;
                (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+#endif
        }
 
        /* destroy environment unless user has requested preservation */
+       envinit = (char **)malloc(MAXENVIRON * sizeof(char *));
+       if (envinit == 0) {
+               fprintf(stderr, "Can't malloc empty environment.\n");
+               sleepexit(1);
+       }
        if (!pflag)
                environ = envinit;
-       (void)setenv("HOME", pwd->pw_dir, 1);
-       (void)setenv("SHELL", pwd->pw_shell, 1);
+
+       i = 0;
+
+#if defined(_AIX) && defined(_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
+       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;
+
+       setenv("HOME", pwd->pw_dir, 0);
+       setenv("PATH", "/usr/local/krb5/bin:/usr/local/bin:/usr/bin/X11:/usr/ucb:/bin:/usr/bin:.", 0);
+       setenv("USER", pwd->pw_name, 0);
+       setenv("SHELL", pwd->pw_shell, 0);
+
        if (term[0] == '\0')
                (void) strncpy(term, stypeof(tty), sizeof(term));
        (void)setenv("TERM", term, 0);
-       (void)setenv("USER", pwd->pw_name, 1);
-       (void)setenv("PATH", ":/usr/ucb:/bin:/usr/bin", 0);
+#ifdef KRB4
+       /* tkfile[0] is only set if we got tickets above */
+       if (tkfile[0])
+           (void) setenv(KRB_ENVIRON, tkfile, 1);
+#endif /* KRB4 */
+
+#if 0
+       strcpy(wgfile, "/tmp/wg.XXXXXX");
+       mktemp(wgfile);
+       setenv("WGFILE", wgfile, 0);
+#endif
 
        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
+                       if (kdata) {
+                           /* @*$&@#*($)#@$ syslog doesn't handle very
+                              many arguments */
+                           char buf[BUFSIZ];
+                           (void) sprintf(buf,
+                                  "ROOT LOGIN (krb) %s from %.*s, %s.%s@%s",
+                                  tty, UT_HOSTSIZE, hostname,
+                                  kdata->pname, kdata->pinst,
+                                  kdata->prealm);
+                           syslog(LOG_NOTICE, buf);
+                       } else {
+#endif /* KRB4 */
                        syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
                            tty, UT_HOSTSIZE, hostname);
+#ifdef KRB4
+                       }
+               else 
+                       if (kdata) {
+                           syslog(LOG_NOTICE,
+                                  "ROOT LOGIN (krb) %s, %s.%s@%s",
+                                  tty,
+                                  kdata->pname, kdata->pinst,
+                                  kdata->prealm);
+                       } 
+#endif /* KRB4 */
                else
                        syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
 
        if (!quietlog) {
                struct stat st;
 
+#ifdef KRB4
+               if (!krbflag)
+                   printf("\nWarning: No Kerberos tickets obtained.\n\n");
+#endif /* KRB4 */
                motd();
                (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
                if (stat(tbuf, &st) == 0 && st.st_size != 0)
@@ -445,16 +824,16 @@ main(argc, argv)
                            (st.st_mtime > st.st_atime) ? "new " : "");
        }
 
-#ifdef VFS
+#ifndef OQUOTA
        if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN);
-#endif VFS
+#endif
        (void)signal(SIGALRM, SIG_DFL);
        (void)signal(SIGQUIT, SIG_DFL);
        (void)signal(SIGINT, SIG_DFL);
        (void)signal(SIGTSTP, SIG_IGN);
 
        tbuf[0] = '-';
-       (void) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
+       (void) strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
            p + 1 : pwd->pw_shell);
        execlp(pwd->pw_shell, tbuf, 0);
        fprintf(stderr, "login: no shell: ");
@@ -496,7 +875,7 @@ timedout()
 }
 
 #ifdef NOTTYENT
-int root_tty_security = 0;
+int root_tty_security = 1;
 #endif
 rootterm(tty)
        char *tty;
@@ -507,7 +886,7 @@ rootterm(tty)
        struct ttyent *t;
 
        return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
-#endif NOTTYENT
+#endif /* NOTTYENT */
 }
 
 jmp_buf motdinterrupt;
@@ -520,7 +899,7 @@ motd()
 
        if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
                return;
-       oldint = (sigtype (*)())signal(SIGINT, sigint);
+       oldint = signal(SIGINT, sigint);
        if (setjmp(motdinterrupt) == 0)
                while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
                        (void)write(fileno(stdout), tbuf, nchars);
@@ -550,6 +929,7 @@ dolastlog(quiet, tty)
        int quiet;
        char *tty;
 {
+#if !defined(_AIX)
        struct lastlog ll;
        int fd;
 
@@ -578,6 +958,7 @@ dolastlog(quiet, tty)
                (void)write(fd, (char *)&ll, sizeof(ll));
                (void)close(fd);
        }
+#endif
 }
 
 #undef UNKNOWN
@@ -602,9 +983,9 @@ doremotelogin(host)
        static char lusername[UT_NAMESIZE+1];
        char rusername[UT_NAMESIZE+1];
 
-       getstr(rusername, sizeof(rusername), "remuser");
-       getstr(lusername, sizeof(lusername), "locuser");
-       getstr(term, sizeof(term), "Terminal type");
+       lgetstr(rusername, sizeof(rusername), "Remote user");
+       lgetstr(lusername, sizeof(lusername), "Local user");
+       lgetstr(term, sizeof(term), "Terminal type");
        username = lusername;
        pwd = getpwnam(username);
        if (pwd == NULL)
@@ -612,17 +993,114 @@ doremotelogin(host)
        return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
 }
 
-getstr(buf, cnt, err)
+#ifdef KRB4
+do_krb_login(host, strict)
+       char *host;
+       int strict;
+{
+       int rc;
+       struct sockaddr_in sin;
+       char instance[INST_SZ], version[9];
+       long authoptions = 0L;
+        struct hostent *hp = gethostbyname(host);
+       static char lusername[UT_NAMESIZE+1];
+
+       /*
+        * Kerberos autologin protocol.
+        */
+
+       (void) bzero((char *) &sin, (int) sizeof(sin));
+
+        if (hp)
+                (void) bcopy (hp->h_addr, (char *)&sin.sin_addr,
+                             sizeof(sin.sin_addr));
+       else
+               sin.sin_addr.s_addr = inet_addr(host);
+
+       if ((hp == NULL) && (sin.sin_addr.s_addr == -1)) {
+           printf("Hostname did not resolve to an address, so Kerberos authentication failed\r\n");
+                /*
+                * No host addr prevents auth, so
+                 * punt krb and require password
+                */
+                if (strict) {
+                        goto paranoid;
+                } else {
+                       pwd = NULL;
+                        return(-1);
+               }
+       }
+
+       kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
+       ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+
+       (void) strcpy(instance, "*");
+       if (rc=krb_recvauth(authoptions, 0, ticket, "rcmd",
+                           instance, &sin,
+                           (struct sockaddr_in *)0,
+                           kdata, "", (bit_64 *) 0, version)) {
+               printf("Kerberos rlogin failed: %s\r\n",krb_err_txt[rc]);
+               if (strict) {
+paranoid:
+                       /*
+                        * Paranoid hosts, such as a Kerberos server,
+                        * specify the Klogind daemon to disallow
+                        * even password access here.
+                        */
+                       printf("Sorry, you must have Kerberos authentication to access this host.\r\n");
+                       exit(1);
+               }
+       }
+       (void) lgetstr(lusername, sizeof (lusername), "Local user");
+       (void) lgetstr(term, sizeof(term), "Terminal type");
+       username = lusername;
+       if (getuid()) {
+               pwd = NULL;
+               return(-1);
+       }
+       pwd = getpwnam(lusername);
+       if (pwd == NULL) {
+               pwd = NULL;
+               return(-1);
+       }
+
+       /*
+        * if Kerberos login failed because of an error in krb_recvauth,
+        * return the indication of a bad attempt.  User will be prompted
+        * for a password.  We CAN'T check the .rhost file, because we need 
+        * the remote username to do that, and the remote username is in the 
+        * Kerberos ticket.  This affects ONLY the case where there is
+        * Kerberos on both ends, but Kerberos fails on the server end. 
+        */
+       if (rc) {
+               return(-1);
+       }
+
+       if (rc=kuserok(kdata,lusername)) {
+               printf("login: %s has not given you permission to login without a password.\r\n",lusername);
+               if (strict) {
+                 exit(1);
+               }
+               return(-1);
+       }
+       return(0);
+}
+#endif /* KRB4 */
+
+lgetstr(buf, cnt, err)
        char *buf, *err;
        int cnt;
 {
+       int ocnt = cnt;
+       char *obuf = buf;
        char ch;
 
        do {
                if (read(0, &ch, sizeof(ch)) != sizeof(ch))
                        exit(1);
                if (--cnt < 0) {
-                       fprintf(stderr, "%s too long\r\n", err);
+                       fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n",
+                              err, ocnt, obuf, ocnt-1);
                        sleepexit(1);
                }
                *buf++ = ch;
@@ -636,29 +1114,128 @@ char *speeds[] = {
 #define        NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
 
 doremoteterm(tp)
+#ifdef POSIX
+       struct termios *tp;
+#else
        struct sgttyb *tp;
+#endif
 {
-       register char *cp = index(term, '/'), **cpp;
+       register char *cp = strchr(term, '/'), **cpp;
        char *speed;
 
        if (cp) {
                *cp++ = '\0';
                speed = cp;
-               cp = index(speed, '/');
+               cp = strchr(speed, '/');
                if (cp)
                        *cp++ = '\0';
                for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
                        if (strcmp(*cpp, speed) == 0) {
+#ifdef POSIX
+                               tp->c_cflag =
+                                       (tp->c_cflag & ~CBAUD) | (cpp-speeds);
+#else
                                tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
+#endif
                                break;
                        }
        }
+#ifdef POSIX
+       /* set all standard echo, edit, and job control options */
+       tp->c_lflag = ECHO|ECHOE|ECHOK|ICANON|ISIG;
+       tp->c_iflag |= ICRNL|BRKINT;
+       tp->c_oflag |= ONLCR|OPOST|TAB3;
+#else /* !POSIX */
        tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
+#endif
 }
 
 sleepexit(eval)
        int eval;
 {
+#ifdef KRB4
+       if (krbflag)
+           (void) dest_tkt();
+#endif /* KRB4 */
        sleep((u_int)5);
        exit(eval);
 }
+
+#ifdef KRB4
+/*
+ * This routine handles cleanup stuff, and the like.
+ * It exits only in the child process.
+ */
+#include <sys/wait.h>
+void
+dofork()
+{
+    int child;
+
+#ifdef _IBMR2
+    update_ref_count(1);
+#endif
+    if(!(child=fork()))
+           return; /* Child process */
+
+    /* Setup stuff?  This would be things we could do in parallel with login */
+    (void) chdir("/"); /* Let's not keep the fs busy... */
+    
+    /* If we're the parent, watch the child until it dies */
+    while(wait((union wait *)0) != child)
+           ;
+
+    /* Cleanup stuff */
+    /* Run dest_tkt to destroy tickets */
+    (void) dest_tkt();         /* If this fails, we lose quietly */
+#ifdef SETPAG
+    if (pagflag)
+       ktc_ForgetAllTokens();
+#endif
+#ifdef _IBMR2
+    update_ref_count(-1);
+#endif
+
+    /* Leave */
+    exit(0);
+}
+#endif /* KRB4 */
+
+
+char *strsave(s)
+char *s;
+{
+    char *ret = (char *)malloc(strlen(s) + 1);
+    strcpy(ret, s);
+    return(ret);
+}
+
+#ifdef _IBMR2
+update_ref_count(int adj)
+{
+    static char *empty = "\0";
+    char *grp;
+    int i;
+
+    /* Update reference count on all user's temporary groups */
+    setuserdb(S_READ|S_WRITE);
+    if (getuserattr(username, S_GROUPS, (void *)&grp, SEC_LIST) == 0) {
+       while (*grp) {
+           if (getgroupattr(grp, "athena_temp", (void *)&i, SEC_INT) == 0) {
+               i += adj;
+               if (i > 0) {
+                   putgroupattr(grp, "athena_temp", (void *)i, SEC_INT);
+                   putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT);
+               } else {
+                   putgroupattr(grp, S_USERS, (void *)empty, SEC_LIST);
+                   putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT);
+                   rmufile(grp, 0, GROUP_TABLE);
+               }
+           }
+           while (*grp) grp++;
+           grp++;
+       }
+    }
+    enduserdb();
+}
+#endif
index 645df54592392f5fc6786505250b29806aa815fc..861fa89d85ac95a0c37245b9ccd566e3a3d8f019 100644 (file)
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)login.c    5.1 (Berkeley) 9/27/88";
-#endif /* LIBC_SCCS and not lint */
-     
 #include <sys/types.h>
 #include <sys/file.h>
 #if defined (CRAY) || defined (sgi)
@@ -28,6 +24,7 @@ static char sccsid[] = "@(#)login.c   5.1 (Berkeley) 9/27/88";
 #endif
 #include <utmp.h>
 #include <stdio.h>
+#include <strings.h>
 #include <sys/time.h>
 #include <sys/stat.h>
      
@@ -46,64 +43,61 @@ void login(ut)
      struct utmp *ut;
 {
     register int fd;
+    struct utmp utmp;
     int tty;
-    off_t lseek();
     
+#if defined(_AIX)
+    if (!ut->ut_pid)
+       ut->ut_pid = getppid();
+    ut->ut_type = USER_PROCESS;
+    (void) strncpy(ut->ut_id, ut->ut_line, sizeof(ut->ut_id));
+
+    (void) setutent();
+    (void) bzero((char *)&utmp, sizeof(utmp));
+    (void) strncpy(utmp.ut_id, ut->ut_id, sizeof(utmp.ut_id));
+    utmp.ut_type = DEAD_PROCESS;
+    (void) getutid(&utmp);
+
+    (void) pututline(ut);
+    (void) endutent();
+#else
     tty = ttyslot();
     if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
        (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET);
        (void)write(fd, (char *)ut, sizeof(struct utmp));
        (void)close(fd);
     }
+#endif
     if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
        (void)write(fd, (char *)ut, sizeof(struct utmp));
        (void)close(fd);
     }
 }
 
-
-
-/*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)logout.c   5.1 (Berkeley) 8/31/88";
-#endif /* LIBC_SCCS and not lint */
-     
 logout(line)
-     register char *line;
+    register char *line;
 {
     register FILE *fp;
     struct utmp ut;
     int rval;
-    time_t time();
     
     if (!(fp = fopen(UTMP_FILE, "r+")))
-      return(0);
+       return(0);
     rval = 1;
     while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) {
        if (!ut.ut_name[0] ||
            strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
-         continue;
+           continue;
        memset(ut.ut_name,0, sizeof(ut.ut_name));
 #ifndef  NO_UT_HOST
        memset(ut.ut_host,0, sizeof(ut.ut_host));
 #endif
        (void)time(&ut.ut_time);
+#if defined(_AIX)
+       memset(ut.ut_id, 0, sizeof(ut.ut_id));
+       ut.ut_pid = ut.ut_exit.e_exit = 0;
+       ut.ut_type = EMPTY;
+#endif
        (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR);
        (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp);
        (void)fseek(fp, (long)0, L_INCR);
@@ -113,29 +107,6 @@ logout(line)
     return(rval);
 }
 
-
-
-/*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)logwtmp.c  5.2 (Berkeley) 9/20/88";
-#endif /* LIBC_SCCS and not lint */
-     
 static int fd = -1;
 
 #ifndef SYSV
@@ -169,6 +140,15 @@ logwtmp(line, name, host, keep_open, logingin)
        ut.ut_pid = getpid();
 #endif
        (void)time(&ut.ut_time);
+#if defined(_AIX)
+       if (*name) {
+           if (!ut.ut_pid)
+               ut.ut_pid = getpid();
+           ut.ut_type = USER_PROCESS;
+       } else {
+           ut.ut_type = EMPTY;
+       }
+#endif
        if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
            sizeof(struct utmp))
          (void)ftruncate(fd, buf.st_size);