* Add checksum support to klogind making sure encrypted authenticators
authorSam Hartman <hartmans@mit.edu>
Wed, 24 Jan 1996 08:56:24 +0000 (08:56 +0000)
committerSam Hartman <hartmans@mit.edu>
Wed, 24 Jan 1996 08:56:24 +0000 (08:56 +0000)
cannot be replayed against unencrypted connections.
* Updated checksumming in kshd to be compatible with klogind so they
use the same client code.  CVS:
* Fixed Makefile to install kshd and klogind not kr*d
* Updated option process in krlogind and kshd per messages to c.p.k.

----------------------------------------------------------------------
automatically CVS: CVS: Committing in .  CVS: CVS: Modified Files:
----------------------------------------------------------------------

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

src/appl/bsd/ChangeLog
src/appl/bsd/Makefile.in
src/appl/bsd/kcmd.c
src/appl/bsd/krlogind.c
src/appl/bsd/krshd.c

index 564e33de85924f14027343c873731cf4337b6ac8..2ed5556de4348721af62e012c78adebf7d0cd363 100644 (file)
@@ -1,9 +1,36 @@
+Wed Jan 24 00:34:42 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+       * Makefile.in (install): Install as kshd and klogind not krshd and
+       krlogind.
+
+       * krshd.c (main): Use krlogind-style options (-54kce)
+
+       * krlogind.c (main): Change option parsing  to support new format.
+       (do_krb_login): Use auth_ok and auth_sent masks instead of passed_*
+
+Tue Jan 23 18:10:55 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+       * krshd.c (recvauth): Use the correct username in strlen call for
+        allocating chksumbuf.
+
+       * krlogind.c (recvauth): Code to copy checksum verification code.
+
+
+Mon Jan 22 15:14:11 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+       * krshd.c (recvauth): Update to expect port in checksum.
+
+       * kcmd.c (kcmd): Include port in string of checksumed data to
+       distinguish between encrypted and unencrypted rlogin.
+
+
 Mon Jan 22 18:14:05 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
 
        * krcp.c: Use KRB5_STDARG_P.
 
        * configure.in: Add KRB5_CHECK_PROTOS for prototyps definitions.
 
+
 Fri Jan 19 10:45:29 1996  Sam Hartman  <hartmans@tertius.mit.edu>
 
        * krshd.c (recvauth): Verify checksum against command line and remote user.
index 9bbdd56d2f54c54505d90368de2f2b9759961720..7ae3e0b29f32ebf1634c95886fe8dec378555621 100644 (file)
@@ -25,10 +25,10 @@ BSD=        -DUCB_RLOGIN=\"$(UCB_RLOGIN)\" \
 DEFINES= $(RSH) $(BSD) $(RPROGS) \
        -DLOGIN_PROGRAM=\"$(SERVER_BINDIR)/login.krb5\" -DKPROGDIR=\"$(CLIENT_BINDIR)\"
 
-all:: rsh rcp rlogin krshd krlogind login.krb5
+all:: rsh rcp rlogin kshd klogind login.krb5
 
 clean:: 
-       $(RM) rsh rcp rlogin krshd krlogind login.krb5
+       $(RM) rsh rcp rlogin kshd klogind login.krb5
 
 rsh: krsh.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS)
        $(LD) $(LDFLAGS) $(LDARGS) -o rsh krsh.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(LIBS)
@@ -51,19 +51,19 @@ install::
        $(INSTALL_PROGRAM) rlogin $(DESTDIR)$(CLIENT_BINDIR)/rlogin
        $(INSTALL_DATA) $(srcdir)/rlogin.M ${DESTDIR}$(CLIENT_MANDIR)/rlogin.1
 
-krshd: krshd.o kcmd.o  forward.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS)
-       $(LD) $(LDFLAGS) $(LDARGS) -o krshd krshd.o kcmd.o  forward.o $(SETENVOBJ) $(LIBOBJS) $(LIBS)
+kshd: krshd.o kcmd.o  forward.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS)
+       $(LD) $(LDFLAGS) $(LDARGS) -o kshd krshd.o kcmd.o  forward.o $(SETENVOBJ) $(LIBOBJS) $(LIBS)
 
 install::
-       $(INSTALL_PROGRAM) krshd $(DESTDIR)$(SERVER_BINDIR)/krshd
-       $(INSTALL_DATA) $(srcdir)/krshd.M ${DESTDIR}$(SERVER_MANDIR)/krshd.8
+       $(INSTALL_PROGRAM) kshd $(DESTDIR)$(SERVER_BINDIR)/kshd
+       $(INSTALL_DATA) $(srcdir)/krshd.M ${DESTDIR}$(SERVER_MANDIR)/kshd.8
 
-krlogind: krlogind.o  kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS)
-       $(LD) $(LDFLAGS) $(LDARGS) -o krlogind krlogind.o  kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(LIBS)
+klogind: krlogind.o  kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(DEPLIBS)
+       $(LD) $(LDFLAGS) $(LDARGS) -o klogind krlogind.o  kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(LIBS)
 
 install::
-       $(INSTALL_PROGRAM) krlogind $(DESTDIR)$(SERVER_BINDIR)/krlogind
-       $(INSTALL_DATA) $(srcdir)/krlogind.M ${DESTDIR}$(SERVER_MANDIR)/krlogind.8
+       $(INSTALL_PROGRAM) klogind $(DESTDIR)$(SERVER_BINDIR)/klogind
+       $(INSTALL_DATA) $(srcdir)/krlogind.M ${DESTDIR}$(SERVER_MANDIR)/klogind.8
 
 #
 # We load the libraries twice here since des425 has a dependency on 
index 28944b6a1a6a030ca017c33a9191799148ce3aec..35ecde5347125b909273e1caf1b13725eafd0261 100644 (file)
@@ -109,11 +109,12 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
     krb5_auth_context auth_context = NULL;
     char *cksumbuf;
     krb5_data cksumdat;
-    if ((cksumbuf = malloc(strlen(cmd)+strlen(remuser))) == 0 ) {
+    if ((cksumbuf = malloc(strlen(cmd)+strlen(remuser)+64)) == 0 ) {
       fprintf(stderr, "Unable to allocate memory for checksum buffer.\n");
       return(-1);
     }
-    strcpy(cksumbuf, cmd);
+sprintf(cksumbuf, "%u:", ntohs(rport));
+    strcat(cksumbuf, cmd);
     strcat(cksumbuf, remuser);
     cksumdat.data = cksumbuf;
        cksumdat.length = strlen(cksumbuf);
index 33867b1805e4ab1e9d0ef7941380188a310a877b..7b3848eade11edb4925e67a1182b3393d2680bc5 100644 (file)
@@ -50,20 +50,15 @@ char copyright[] =
  * The configuration is done either by command-line arguments passed by 
  * inetd, or by the name of the daemon. If command-line arguments are
  * present, they  take priority. The options are:
- * -k and -K means check .k5login (using krb5_kuserok).
- * -r and -R means check .rhosts  (using ruserok).
+ * -k means trust krb4 or krb5
+* -5 means trust krb5
+* -4 means trust krb4
+ * -r means trust .rhosts  (using ruserok).
  * -p and -P means prompt for password.
- * The difference between upper and lower case is as follows:
- *    If lower case -r or -k, then as long as one of krb5_kuserok or 
- * ruserok passes, allow login without password. If the -p option is
- * passed with -r or -k, then if both checks fail, allow login but
- * only after password verification. 
- *    If uppercase -R or -K, then those checks must be passed,
- * regardless of other checks, else no login with or without password.
  *    If the -P option is passed, then the password is verified in 
  * addition to all other checks. If -p is not passed with -k or -r,
  * and both checks fail, then login permission is denied.
- *    -x and -e means use encryption.
+ *    - -e means use encryption.
  *
  *    If no command-line arguments are present, then the presence of the 
  * letters kKrRexpP in the program-name before "logind" determine the 
@@ -246,9 +241,9 @@ krb5_context bsd_context;
 
 krb5_keytab keytab = NULL;
 
-#define ARGSTR "rRkKeExXpPD:S:M:L:?"
+#define ARGSTR "rk54cepPD:S:M:L:?"
 #else /* !KERBEROS */
-#define ARGSTR "rRpPD:?"
+#define ARGSTR "rpPD:?"
 #define (*des_read)  read
 #define (*des_write) write
 #endif /* KERBEROS */
@@ -298,8 +293,20 @@ void       fatal(), fatalperror(), doit(), usage(), do_krb_login();
 int    princ_maps_to_lname(), default_realm();
 krb5_sigtype   cleanup();
 
-int must_pass_rhosts = 0, must_pass_k5 = 0, must_pass_one = 0;
+/* There are two authentication related masks:
+   * auth_ok and auth_sent.
+* The auth_ok mask is the oring of authentication systems any one
+* of which can be used.  
+* The auth_sent mask is the oring of one or more authentication/authorization
+* systems that succeeded.  If the anding
+* of these two masks is true, then authorization is successful.
+*/
+#define AUTH_KRB4 (0x1)
+#define AUTH_KRB5 (0x2)
+#define AUTH_RHOSTS (0x4)
+int auth_ok = 0, auth_sent = 0;
 int do_encrypt = 0, passwd_if_fail = 0, passwd_req = 0;
+int checksum_required = 0;
 
 main(argc, argv)
      int argc;
@@ -313,6 +320,7 @@ main(argc, argv)
     int debug_port = 0;
     int fd;
 #ifdef KERBEROS
+int valid_checksum;
     krb5_error_code status;
 #endif
     
@@ -371,22 +379,28 @@ pty_init();
     while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
       switch (ch) {
        case 'r':         
-         must_pass_one = 1; /* If just 'r', any one check must succeed */
-         break;
-       case 'R':         /* If 'R', must pass .rhosts check*/
-         must_pass_rhosts = 1;
-         if (must_pass_one)
-           must_pass_one = 0;
+       auth_ok |= AUTH_RHOSTS;
          break;
 #ifdef KERBEROS
        case 'k':
-         must_pass_one = 1; /* If just 'k', any one check must succeed */
-         break;
-       case 'K':         /* If 'K', must pass .k5login check*/
-         must_pass_k5 = 1;
-         if (must_pass_one)
-           must_pass_one = 0;
-         break;
+#ifdef KRB5_KRB4_COMPAT
+       auth_ok |= (AUTH_KRB5|AUTH_KRB4);
+#else
+       auth_ok |= AUTH_KRB5;
+#endif /* KRB5_KRB4_COMPAT*/
+       break;
+       
+      case '5':
+         auth_ok |= AUTH_KRB5;
+       break;
+      case 'c':
+       checksum_required = 1;
+       break;
+#ifdef KRB5_KRB4_COMPAT
+      case '4':
+       auth_ok |= AUTH_KRB4;
+       break;
+#endif
 #ifdef CRYPT
        case 'x':         /* Use encryption. */
        case 'X':
@@ -471,7 +485,7 @@ pty_init();
 #ifdef STDERR_FILENO
             fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
 #else
-            fatal(3, "Can't get peer name of remote host", 1);
+            fatal(2, "Can't get peer name of remote host", 1);
 #endif
         }
         fd = 0;
@@ -480,6 +494,10 @@ pty_init();
     if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
                   (const char *) &on, sizeof (on)) < 0)
       syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+    if (auth_ok == 0) {
+      syslog(LOG_CRIT, "No authentication systems were enabled; all connections will be refused.");
+      fatal(fd, "All authentication systems disabled; connection refused.");
+    }
     
     doit(fd, &from);
 }
@@ -552,13 +570,13 @@ int syncpipe[2];
       fatal(f, "Permission denied - Malformed from address\n");
     
 #ifdef KERBEROS
-    if (must_pass_k5 || must_pass_one) {
+
        /* setup des buffers */
-       desinbuf.data = des_inbuf;
-       desoutbuf.data = des_outbuf;    /* Set up des buffers */
-    }
+    desinbuf.data = des_inbuf;
+    desoutbuf.data = des_outbuf;    /* Set up des buffers */
+
     /* Must come from privileged port when .rhosts is being looked into */
-    if ((must_pass_rhosts || must_pass_one
+    if ((auth_ok&AUTH_RHOSTS
        && (fromp->sin_port >= IPPORT_RESERVED ||
            fromp->sin_port < IPPORT_RESERVED/2))
       non_privileged = 1;
@@ -1043,10 +1061,10 @@ do_krb_login(host)
 {
     krb5_error_code status;
     struct passwd *pwd;
-    int        passed_krb, passed_rhosts;
     char *msg_fail;
+int valid_checksum;
+
 
-    passed_krb = passed_rhosts = 0;
 
     if (getuid()) {
        exit(1);
@@ -1054,7 +1072,7 @@ do_krb_login(host)
 
     /* Check authentication. This can be either Kerberos V5, */
     /* Kerberos V4, or host-based. */
-    if (status = recvauth()) {
+    if (status = recvauth(&valid_checksum)) {
        if (ticket)
          krb5_free_ticket(bsd_context, ticket);
        if (status != 255)
@@ -1074,50 +1092,55 @@ do_krb_login(host)
   }
 #endif
     
-    if (must_pass_k5 || must_pass_one) {
+
 #if (defined(ALWAYS_V5_KUSEROK) || !defined(KRB5_KRB4_COMPAT))
        /* krb5_kuserok returns 1 if OK */
        if (client && krb5_kuserok(bsd_context, client, lusername))
-           passed_krb++;
+         auth_sent |= ((auth_sys == KRB5_RECVAUTH_V4)?AUTH_KRB4:AUTH_KRB5);
 #else
        if (auth_sys == KRB5_RECVAUTH_V4) {
            /* kuserok returns 0 if OK */
            if (!kuserok(v4_kdata, lusername))
-               passed_krb++;
+             auth_sent |= AUTH_KRB4;
        } else {
            /* krb5_kuserok returns 1 if OK */
            if (client && krb5_kuserok(bsd_context, client, lusername))
-               passed_krb++;
+             auth_sent |= AUTH_KRB5;
        }
 #endif
-    }
-    
-    /*  The kerberos authenticated request must pass ruserok also
-       if asked for. */
+
     
-    if (!must_pass_k5 &&
-       (must_pass_rhosts || (!passed_krb && must_pass_one))) {
+/* See if we pass .rhosts.*/
+    if (auth_ok&AUTH_RHOSTS) {
        /* Cannot check .rhosts unless connection from a privileged port. */
-       if (non_privileged) 
-         fatal(netf, "Permission denied - Connection from bad port");
-
-       pwd = (struct passwd *) getpwnam(lusername);
-       if (pwd &&
-           !ruserok(rhost_name, pwd->pw_uid == 0, rusername, lusername))
-           passed_rhosts++;
+       if (!non_privileged) {
+           pwd = (struct passwd *) getpwnam(lusername);
+           if (pwd &&
+               !ruserok(rhost_name, pwd->pw_uid == 0, rusername, lusername))
+               auth_sent |= AUTH_RHOSTS;
+       }
     }
 
-    if ((must_pass_k5 && passed_krb) ||
-       (must_pass_rhosts && passed_rhosts) ||
-       (must_pass_one && (passed_krb || passed_rhosts)))
-           return;
+    if (checksum_required) {
+       if ((auth_sent&AUTH_KRB5)&&(!valid_checksum)) {
+           syslog(LOG_WARNING, "Client did not supply required checksum.");
+       
+           fatal(netf, "You are using an old Kerberos5 without initial connection support; only newer clients are authorized.");
+    }
+    else {
+       syslog(LOG_WARNING, "Checksums are only required for v5 clients; other clients cannot produce initial authenticator checksums.");
+    }
+      }
+    if 
+(auth_ok&auth_sent) /* This should be bitwise.*/
+       return;
     
     if (ticket)
        krb5_free_ticket(bsd_context, ticket);
 
     msg_fail =  (char *) malloc( strlen(krusername) + strlen(lusername) + 80 );
     if (!msg_fail)
-       fatal(netf, "User is not authorized to login to specified account");
+    fatal(netf, "User is not authorized to login to specified account");
     sprintf(msg_fail, "User %s is not authorized to login to account %s",
            krusername, lusername);
     fatal(netf, msg_fail);
@@ -1386,10 +1409,10 @@ void usage()
 {
 #ifdef KERBEROS
     syslog(LOG_ERR, 
-          "usage: klogind [-rRkKxpP] [-D port] or [r/R][k/K][x/e][p/P]logind");
+          "usage: klogind [-rke45pP] [-D port] or [r/R][k/K][x/e][p/P]logind");
 #else
     syslog(LOG_ERR, 
-          "usage: rlogind [-rRpP] [-D port] or [r/R][p/P]logind");
+          "usage: rlogind [-rpP] [-D port] or [r/R][p/P]logind");
 #endif
 }
 
@@ -1440,7 +1463,8 @@ int default_realm(principal)
                                              chars */
 
 krb5_error_code
-recvauth()
+recvauth(valid_checksum)
+int *valid_checksum;
 {
     krb5_auth_context auth_context = NULL;
     krb5_error_code status;
@@ -1451,7 +1475,8 @@ recvauth()
     krb5_data inbuf;
     char v4_instance[INST_SZ]; /* V4 Instance */
     char v4_version[9];
-
+    krb5_authenticator *authenticator;
+*valid_checksum = 0;
     len = sizeof(laddr);
     if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
            exit(1);
@@ -1510,6 +1535,41 @@ recvauth()
 
     getstr(netf, lusername, sizeof (lusername), "locuser");
     getstr(netf, term, sizeof(term), "Terminal type");
+    if (status = krb5_auth_con_getauthenticator(bsd_context, auth_context, &authenticator))
+      return status;
+    
+    if (authenticator->checksum) {
+       struct sockaddr_in adr;
+       int adr_length = sizeof(adr);
+      char * chksumbuf = (char *) malloc(strlen(term)+strlen(lusername)+32);
+       if (getsockname(netf, (struct sockaddr *) &adr, &adr_length) != 0)
+    return errno;
+      if (chksumbuf == 0)
+    goto error_cleanup;
+
+      sprintf(chksumbuf,"%u:", ntohs(adr.sin_port));
+      strcat(chksumbuf,term);
+      strcat(chksumbuf,lusername);
+
+      if ( status = krb5_verify_checksum(bsd_context,
+                                        authenticator->checksum->checksum_type,
+                                        authenticator->checksum,
+                                        chksumbuf, strlen(chksumbuf),
+                                                                              ticket->enc_part2->session->contents, 
+                                      ticket->enc_part2->session->length))
+       goto error_cleanup;
+
+ error_cleanup:
+krb5_xfree(chksumbuf);
+      if (status) {
+       krb5_free_authenticator(bsd_context, authenticator);
+       return status;
+      }
+       *valid_checksum = 1;
+}
+    krb5_free_authenticator(bsd_context, authenticator);
+
+
 
 #ifdef KRB5_KRB4_COMPAT
     if (auth_sys == KRB5_RECVAUTH_V4) {
index 77d5fa45243c537b9e8737c05eaf0f2166bb2400..f5f324ee0676e3b63717f5edb2366a7a0a77ea69 100644 (file)
@@ -48,14 +48,10 @@ char copyright[] =
  * The configuration is done either by command-line arguments passed by inetd, 
  * or by the name of the daemon. If command-line arguments are present, they 
  * take priority. The options are:
- * -k and -K means check .k5login (using krb5_kuserok).
- * -r and -R means check .rhosts  (using ruserok).
- * The difference between upper and lower case is as follows:
- *    If lower case -r or -k, then as long as one of krb5_kuserok or ruserok 
- * passes, allow access. If both fail, no access. The program does not fall
- * back on password verification.
- *    If uppercase -R or -K, then those checks must be passed, regardless of 
- * other checks, else no access.
+ * -k means trust krb4 or krb5
+* -5 means trust krb5
+* -4 means trust krb4
+ * -r means trust .rhosts  (using ruserok).
  * 
  *     If no command-line arguments are present, then the presence of the 
  * letters kKrR in the program-name before "shd" determine the 
@@ -159,7 +155,7 @@ char copyright[] =
 #include "com_err.h"
 #include "loginpaths.h"
 
-#define ARGSTR "rRxXeEkKD:S:M:AP:?"
+#define ARGSTR "rek54cD:S:M:AP:?"
 
 #define SECURE_MESSAGE "This rsh session is using DES encryption for all data transmissions.\r\n"
 
@@ -181,7 +177,7 @@ int v5_des_write();
 
 int (*des_read)() = v5_des_read;
 int (*des_write)() = v5_des_write;
-
+int require_encrypt = 0;
 int do_encrypt = 0;
 int anyport = 0;
 char *kprogdir = KPROGDIR;
@@ -199,8 +195,19 @@ int netf;
 #define killpg(pid, sig) kill(-(pid), (sig))
 #endif
 
-int must_pass_rhosts = 0, must_pass_k5 = 0, must_pass_one = 0;
-int failed_k5 = 0;
+/* There are two authentication related masks:
+   * auth_ok and auth_sent.
+* The auth_ok mask is the oring of authentication systems any one
+* of which can be used.  
+* The auth_sent mask is the oring of one or more authentication/authorization
+* systems that succeeded.  If the anding
+* of these two masks is true, then authorization is successful.
+*/
+#define AUTH_KRB4 (0x1)
+#define AUTH_KRB5 (0x2)
+#define AUTH_RHOSTS (0x4)
+int auth_ok = 0, auth_sent = 0;
+int checksum_required = 0;
 char *progname;
 
 #define MAX_PROG_NAME 10
@@ -299,28 +306,31 @@ main(argc, argv)
     while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
       switch (ch) {
        case 'r':         
-         must_pass_one = 1; /* If just 'r', any one check must succeed */
-         break;
-       case 'R':         /* If 'R', must pass .rhosts check*/
-         must_pass_rhosts = 1;
-         if (must_pass_one)
-           must_pass_one = 0;
+       auth_ok |= AUTH_RHOSTS;
          break;
 #ifdef KERBEROS
        case 'k':
-         must_pass_one = 1; /* If just 'k', any one check must succeed */
-         break;
-       case 'K':         /* If 'K', must pass .k5login check*/
-         must_pass_k5 = 1;
-         if (must_pass_one)
-           must_pass_one = 0;
-         break;
+#ifdef KRB5_KRB4_COMPAT
+       auth_ok |= (AUTH_KRB5|AUTH_KRB4);
+#else
+       auth_ok |= AUTH_KRB5;
+#endif /* KRB5_KRB4_COMPAT*/
+       break;
+       
+      case '5':
+         auth_ok |= AUTH_KRB5;
+       break;
+      case 'c':
+       checksum_required = 1;
+       break;
+#ifdef KRB5_KRB4_COMPAT
+      case '4':
+       auth_ok |= AUTH_KRB4;
+       break;
+#endif
          
-        case 'x':
-        case 'X':
         case 'e':
-        case 'E':
-         do_encrypt = 1;
+       require_encrypt = 1;
          break;
 
        case 'S':
@@ -497,6 +507,7 @@ doit(f, fromp)
     krb5_error_code status;
 #endif
 
+int valid_checksum;
     int tmpint;
     
     int ioctlval, cnt;
@@ -587,8 +598,7 @@ doit(f, fromp)
     netf = f;
     desinbuf.data = des_inbuf;
     desoutbuf.data = des_outbuf;
-    if ((must_pass_rhosts || must_pass_one)
-       && (fromp->sin_port >= IPPORT_RESERVED ||
+    if ( (fromp->sin_port >= IPPORT_RESERVED ||
            fromp->sin_port < IPPORT_RESERVED/2))
       non_privileged = 1;
 #else
@@ -663,8 +673,7 @@ doit(f, fromp)
            exit(1);
        }
 #ifdef KERBEROS
-       if ((must_pass_rhosts || must_pass_one)
-           && port >= IPPORT_RESERVED)
+       if ( port >= IPPORT_RESERVED)
          non_privileged = 1;
 #else
        if (port >= IPPORT_RESERVED) {
@@ -694,7 +703,7 @@ doit(f, fromp)
     }
 
 #ifdef KERBEROS
-    if (status = recvauth(f, fromaddr)) {
+    if (status = recvauth(f, fromaddr,&valid_checksum)) {
        error("Authentication failed: %s\n", error_message(status));
        exit(1);
     }
@@ -726,7 +735,7 @@ doit(f, fromp)
     if (pwd == (struct passwd *) 0 ) {
        syslog(LOG_ERR ,
               "Principal %s (%s@%s) for local user %s has no account.\n",
-              kremuser, remuser, hostname, locuser);
+              kremuser, remuser, hostname, locuser); /* xxx sprintf buffer in syslog*/
        error("Login incorrect.\n");
        exit(1);
     }
@@ -972,7 +981,7 @@ doit(f, fromp)
     }
 
 #ifdef KERBEROS
-    if (must_pass_k5 || must_pass_one) {
+
 #if defined(KRB5_KRB4_COMPAT) && !defined(ALWAYS_V5_KUSEROK)
        if (auth_sys == KRB5_RECVAUTH_V4) {
            /* kuserok returns 0 if OK */
@@ -980,45 +989,35 @@ doit(f, fromp)
                syslog(LOG_ERR ,
                       "Principal %s (%s@%s) for local user %s failed kuserok.\n",
                       kremuser, remuser, hostname, locuser);
-               if (must_pass_k5) {
-                   error("Permission denied.\n");
-                   goto signout_please;
                }
-               failed_k5 = 1;
-           }
-       } else
+           else auth_sent |= AUTH_KRB4;
+       }else
 #endif
-       {
+           {
            /* krb5_kuserok returns 1 if OK */
            if (!krb5_kuserok(bsd_context, client, locuser)){
                syslog(LOG_ERR ,
                       "Principal %s (%s@%s) for local user %s failed krb5_kuserok.\n",
                       kremuser, remuser, hostname, locuser);
-               if (must_pass_k5) {
-                   error("Permission denied.\n");
-                   goto signout_please;
-               }
-               failed_k5 = 1;
            }
+else auth_sent |= AUTH_KRB5;
        }
-    }
+
        
-    if (must_pass_rhosts || (failed_k5 && must_pass_one)) {
+    if (auth_ok&AUTH_RHOSTS) {
        /* Cannot check .rhosts unless connection from privileged port */
-       if (non_privileged) {
-           syslog(LOG_ERR , "connection from bad port\n");
-           exit(1);
-       }
-
-       if (ruserok(hostname, pwd->pw_uid == 0,
+       if (!non_privileged) {
+               if (ruserok(hostname, pwd->pw_uid == 0,
                    remuser, locuser) < 0) {
            syslog(LOG_ERR ,
                   "Principal %s (%s@%s) for local user %s failed ruserok.\n",
                   kremuser, remuser, hostname, locuser);
-           error("Permission denied.\n");
-           goto signout_please;
+
+           
        }
-    }
+             else auth_sent |=AUTH_RHOSTS;
+             }
+}
 #else
     if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
        ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
@@ -1026,6 +1025,27 @@ doit(f, fromp)
        goto signout_please;
     }
 #endif /* KERBEROS */
+
+
+if (checksum_required) {
+                        if ((auth_sent&AUTH_KRB5)&&(!valid_checksum)) {
+                          syslog(LOG_WARNING, "Client did not supply required checksum.");
+       
+                        error( "You are using an old Kerberos5 without initial connection support; only newer clients are authorized.");
+goto signout_please;
+                      }
+else {
+       syslog(LOG_WARNING, "Checksums are only required for v5 clients; other clients cannot produce initial authenticator checksums.");
+     }
+                      }
+if (require_encrypt&&(!do_encrypt)) {
+  error("You must use encryption.");
+  goto signout_please;
+}
+    if (!(auth_ok&auth_sent)) {
+      error("Permission denied.");
+      goto signout_please;
+    }
     
     if (pwd->pw_uid && !access("/etc/nologin", F_OK)) {
        error("Logins currently disabled.\n");
@@ -1598,9 +1618,10 @@ int default_realm(principal)
                                              chars */
 
 krb5_error_code
-recvauth(netf, peersin)
+recvauth(netf, peersin, valid_checksum)
      int netf;
      struct sockaddr_in peersin;
+int *valid_checksum;
 {
     krb5_auth_context auth_context = NULL;
     krb5_error_code status;
@@ -1614,6 +1635,7 @@ recvauth(netf, peersin)
 krb5_authenticator *authenticator;
     krb5_ticket        *ticket;
 
+    *valid_checksum = 0;
     len = sizeof(laddr);
     if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
            exit(1);
@@ -1704,11 +1726,16 @@ krb5_authenticator *authenticator;
       return status;
     
     if (authenticator->checksum) {
-      char * chksumbuf = (char *) malloc(strlen(cmdbuf)+strlen(remuser)+1);
+       struct sockaddr_in adr;
+       int adr_length = sizeof(adr);
+      char * chksumbuf = (char *) malloc(strlen(cmdbuf)+strlen(locuser)+32);
+       if (getsockname(netf, (struct sockaddr *) &adr, &adr_length) != 0)
+    return errno;
       if (chksumbuf == 0)
     goto error_cleanup;
 
-      strcpy(chksumbuf,cmdbuf);
+      sprintf(chksumbuf,"%u:", ntohs(adr.sin_port));
+      strcat(chksumbuf,cmdbuf);
       strcat(chksumbuf,locuser);
 
       if ( status = krb5_verify_checksum(bsd_context,
@@ -1725,6 +1752,7 @@ krb5_xfree(chksumbuf);
        krb5_free_authenticator(bsd_context, authenticator);
        return status;
       }
+       *valid_checksum = 1;
 }
     krb5_free_authenticator(bsd_context, authenticator);