r23474: Here's a small patch that disables the libkrb5.so replay cache
authorGerald Carter <jerry@samba.org>
Wed, 13 Jun 2007 20:49:20 +0000 (20:49 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:23:19 +0000 (12:23 -0500)
when verifying a ticket from winbindd_pam.c.

I've found during multiple, fast, automated SSH logins (such
as from a cron script) that the replay cache in MIT's krb5
lib will occasionally fail the krb5_rd_req() as a replay attack.

There seems to be a small window during which the MIT krb5
libs could reproduce identical time stamps for ctime and cusec
in the authenticator since Unix systems only give back
milli-seconds rather than the micro-seconds needed by the
authenticator.  Checked against MIT 1.5.1.  Have not
researched how Heimdal does it.

My thinking is that if someone can spoof the KDC and TDS
services we are pretty hopeless anyways.
(This used to be commit cbd33da9f78373e29729325bbab1ae9040712b11)

source3/libads/kerberos_verify.c
source3/nsswitch/winbindd_pam.c
source3/smbd/sesssetup.c
source3/utils/ntlm_auth.c

index ca36e6e4254b1f7f5d83502321f470f83874178b..ecd0f0869c8ac0d2689b487881661ed3233c08b9 100644 (file)
@@ -214,7 +214,14 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
        BOOL auth_ok = False;
        char *password_s = NULL;
        krb5_data password;
-       krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 };
+       krb5_enctype enctypes[] = { 
+#if defined(ENCTYPE_ARCFOUR_HMAC)
+               ENCTYPE_ARCFOUR_HMAC,
+#endif
+               ENCTYPE_DES_CBC_CRC, 
+               ENCTYPE_DES_CBC_MD5, 
+               ENCTYPE_NULL
+       };
        krb5_data packet;
        int i;
 
@@ -222,9 +229,6 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
        *keyblock = NULL;
        *perr = 0;
 
-#if defined(ENCTYPE_ARCFOUR_HMAC)
-       enctypes[2] = ENCTYPE_ARCFOUR_HMAC;
-#endif
 
        if (!secrets_init()) {
                DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
@@ -307,7 +311,8 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                           char **principal,
                           PAC_DATA **pac_data,
                           DATA_BLOB *ap_rep,
-                          DATA_BLOB *session_key)
+                          DATA_BLOB *session_key,
+                          BOOL use_replay_cache)
 {
        NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
        NTSTATUS pac_ret;
@@ -320,7 +325,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
        krb5_keyblock *keyblock = NULL;
        time_t authtime;
        krb5_error_code ret = 0;
-       
+       krb5_int32 flags = 0;   
        krb5_principal host_princ = NULL;
        krb5_const_principal client_principal = NULL;
        char *host_princ_s = NULL;
@@ -363,6 +368,13 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                goto out;
        }
 
+       krb5_auth_con_getflags( context, auth_context, &flags );
+       if ( !use_replay_cache ) {
+               /* Disable default use of a replay cache */
+               flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
+               krb5_auth_con_setflags( context, auth_context, flags );
+       }
+
        asprintf(&host_princ_s, "%s$", global_myname());
        if (!host_princ_s) {
                goto out;
@@ -377,50 +389,62 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
        }
 
 
-       /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
-        * code surrounding the replay cache... */
+       if ( use_replay_cache ) {
+               
+               /* Lock a mutex surrounding the replay as there is no 
+                  locking in the MIT krb5 code surrounding the replay 
+                  cache... */
 
-       if (!grab_server_mutex("replay cache mutex")) {
-               DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n"));
-               ret = KRB5_CC_IO;
-               goto out;
-       }
+               if (!grab_server_mutex("replay cache mutex")) {
+                       DEBUG(1,("ads_verify_ticket: unable to protect "
+                                "replay cache with mutex.\n"));
+                       ret = KRB5_CC_IO;
+                       goto out;
+               }
 
-       got_replay_mutex = True;
+               got_replay_mutex = True;
 
-       /*
-        * JRA. We must set the rcache here. This will prevent replay attacks.
-        */
+               /* JRA. We must set the rcache here. This will prevent 
+                  replay attacks. */
+               
+               ret = krb5_get_server_rcache(context, 
+                                            krb5_princ_component(context, host_princ, 0), 
+                                            &rcache);
+               if (ret) {
+                       DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
+                                "failed (%s)\n", error_message(ret)));
+                       goto out;
+               }
 
-       ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache);
-       if (ret) {
-               DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret)));
-               goto out;
+               ret = krb5_auth_con_setrcache(context, auth_context, rcache);
+               if (ret) {
+                       DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
+                                "failed (%s)\n", error_message(ret)));
+                       goto out;
+               }
        }
 
-       ret = krb5_auth_con_setrcache(context, auth_context, rcache);
-       if (ret) {
-               DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret)));
-               goto out;
-       }
+       /* Try secrets.tdb first and fallback to the krb5.keytab if
+          necessary */
 
-       if (lp_use_kerberos_keytab()) {
-               auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret);
-       }
-       if (!auth_ok) {
-               auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
-                                                   ticket, &tkt, &keyblock, &ret);
-       }
+        auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+                                           ticket, &tkt, &keyblock, &ret);
 
-       release_server_mutex();
-       got_replay_mutex = False;
+       if (!auth_ok && lp_use_kerberos_keytab()) {
+               auth_ok = ads_keytab_verify_ticket(context, auth_context, 
+                                                  ticket, &tkt, &keyblock, &ret);
+       }
 
+       if ( use_replay_cache ) {               
+               release_server_mutex();
+               got_replay_mutex = False;
 #if 0
-       /* Heimdal leaks here, if we fix the leak, MIT crashes */
-       if (rcache) {
-               krb5_rc_close(context, rcache);
-       }
+               /* Heimdal leaks here, if we fix the leak, MIT crashes */
+               if (rcache) {
+                       krb5_rc_close(context, rcache);
+               }
 #endif
+       }       
 
        if (!auth_ok) {
                DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
index 9653e6c87678a9cc50abca1b01149828703a766d..9c0b642b94130a38b5460469ad20993cafa22129 100644 (file)
@@ -615,7 +615,7 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
                                   &client_princ_out, 
                                   &pac_data, 
                                   &ap_rep, 
-                                  &session_key);       
+                                  &session_key, False);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(0,("winbindd_raw_kerberos_login: ads_verify_ticket failed: %s\n", 
                        nt_errstr(result)));
index 42a71f8ad7627e57e03727d9854c9f5e34cb7b21..22c598a6547db45ee0cd2338afd5d53deedd83cc 100644 (file)
@@ -270,7 +270,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
        }
 
-       ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
+       ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, 
+                               &client, &pac_data, &ap_rep, 
+                               &session_key, True);
 
        data_blob_free(&ticket);
 
index 4a74db6b4ab81b28088d1656b152f945510b153d..a2b41660b58937abe8c536300aa6327cfe3e413e 100644 (file)
@@ -1169,7 +1169,7 @@ static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
                        status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
                                                   &request.negTokenInit.mechToken,
                                                   &principal, NULL, &ap_rep,
-                                                  &session_key);
+                                                  &session_key, True);
 
                        talloc_destroy(mem_ctx);