svn commit: samba r23474 - in branches: SAMBA_3_0/source/libads SAMBA_3_0/source/nsswitch SAMBA_3_0/source/smbd SAMBA_3_0/source/utils SAMBA_3_0_26/source/libads SAMBA_3_0_26/source/nsswitch SAMBA_3_0_26/source/smbd SAMBA_3_0_26/source/utils

jerry at samba.org jerry at samba.org
Wed Jun 13 20:49:21 GMT 2007


Author: jerry
Date: 2007-06-13 20:49:20 +0000 (Wed, 13 Jun 2007)
New Revision: 23474

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=23474

Log:
Here's a small patch that disables the libkrb5.so replay cache 
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.


Modified:
   branches/SAMBA_3_0/source/libads/kerberos_verify.c
   branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c
   branches/SAMBA_3_0/source/smbd/sesssetup.c
   branches/SAMBA_3_0/source/utils/ntlm_auth.c
   branches/SAMBA_3_0_26/source/libads/kerberos_verify.c
   branches/SAMBA_3_0_26/source/nsswitch/winbindd_pam.c
   branches/SAMBA_3_0_26/source/smbd/sesssetup.c
   branches/SAMBA_3_0_26/source/utils/ntlm_auth.c


Changeset:
Modified: branches/SAMBA_3_0/source/libads/kerberos_verify.c
===================================================================
--- branches/SAMBA_3_0/source/libads/kerberos_verify.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0/source/libads/kerberos_verify.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -214,7 +214,14 @@
 	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 @@
 	*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 @@
 			   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 @@
 	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 @@
 		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 @@
 	}
 
 
-	/* 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);
+        auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+					    ticket, &tkt, &keyblock, &ret);
+
+	if (!auth_ok && 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);
-	}
 
-	release_server_mutex();
-	got_replay_mutex = False;
-
+	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", 

Modified: branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c
===================================================================
--- branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -615,7 +615,7 @@
 				   &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)));

Modified: branches/SAMBA_3_0/source/smbd/sesssetup.c
===================================================================
--- branches/SAMBA_3_0/source/smbd/sesssetup.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0/source/smbd/sesssetup.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -270,7 +270,9 @@
 		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);
 

Modified: branches/SAMBA_3_0/source/utils/ntlm_auth.c
===================================================================
--- branches/SAMBA_3_0/source/utils/ntlm_auth.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0/source/utils/ntlm_auth.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -1169,7 +1169,7 @@
 			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);
 

Modified: branches/SAMBA_3_0_26/source/libads/kerberos_verify.c
===================================================================
--- branches/SAMBA_3_0_26/source/libads/kerberos_verify.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0_26/source/libads/kerberos_verify.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -214,7 +214,14 @@
 	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 @@
 	*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 @@
 			   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 @@
 	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 @@
 		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 @@
 	}
 
 
-	/* 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);
+        auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+					    ticket, &tkt, &keyblock, &ret);
+
+	if (!auth_ok && 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);
-	}
 
-	release_server_mutex();
-	got_replay_mutex = False;
-
+	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", 

Modified: branches/SAMBA_3_0_26/source/nsswitch/winbindd_pam.c
===================================================================
--- branches/SAMBA_3_0_26/source/nsswitch/winbindd_pam.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0_26/source/nsswitch/winbindd_pam.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -615,7 +615,7 @@
 				   &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)));

Modified: branches/SAMBA_3_0_26/source/smbd/sesssetup.c
===================================================================
--- branches/SAMBA_3_0_26/source/smbd/sesssetup.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0_26/source/smbd/sesssetup.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -267,7 +267,9 @@
 		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);
 

Modified: branches/SAMBA_3_0_26/source/utils/ntlm_auth.c
===================================================================
--- branches/SAMBA_3_0_26/source/utils/ntlm_auth.c	2007-06-13 20:45:55 UTC (rev 23473)
+++ branches/SAMBA_3_0_26/source/utils/ntlm_auth.c	2007-06-13 20:49:20 UTC (rev 23474)
@@ -1169,7 +1169,7 @@
 			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);
 



More information about the samba-cvs mailing list