svn commit: samba r17171 - in branches/SAMBA_4_0/source/auth/gensec: .

abartlet at samba.org abartlet at samba.org
Fri Jul 21 01:44:24 GMT 2006


Author: abartlet
Date: 2006-07-21 01:44:24 +0000 (Fri, 21 Jul 2006)
New Revision: 17171

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

Log:
Add a gensec function to determine the maximum negotiated buffer size,
and the maximum amount of user data that may be fitted into that.

This is used in the new SASL code, to correctly honour SASL buffer sizes.

Andrew Bartlett

Modified:
   branches/SAMBA_4_0/source/auth/gensec/gensec.c
   branches/SAMBA_4_0/source/auth/gensec/gensec.h
   branches/SAMBA_4_0/source/auth/gensec/gensec_gssapi.c


Changeset:
Modified: branches/SAMBA_4_0/source/auth/gensec/gensec.c
===================================================================
--- branches/SAMBA_4_0/source/auth/gensec/gensec.c	2006-07-21 01:37:38 UTC (rev 17170)
+++ branches/SAMBA_4_0/source/auth/gensec/gensec.c	2006-07-21 01:44:24 UTC (rev 17171)
@@ -815,6 +815,24 @@
 	return gensec_security->ops->sig_size(gensec_security, data_size);
 }
 
+size_t gensec_max_input_size(struct gensec_security *gensec_security) 
+{
+	if (!gensec_security->ops->max_input_size) {
+		return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
+	}
+	
+	return gensec_security->ops->max_input_size(gensec_security);
+}
+
+size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
+{
+	if (!gensec_security->ops->max_wrapped_size) {
+		return (1 << 17);
+	}
+	
+	return gensec_security->ops->max_wrapped_size(gensec_security);
+}
+
 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
 		     TALLOC_CTX *mem_ctx, 
 		     const DATA_BLOB *in, 

Modified: branches/SAMBA_4_0/source/auth/gensec/gensec.h
===================================================================
--- branches/SAMBA_4_0/source/auth/gensec/gensec.h	2006-07-21 01:37:38 UTC (rev 17170)
+++ branches/SAMBA_4_0/source/auth/gensec/gensec.h	2006-07-21 01:44:24 UTC (rev 17171)
@@ -78,6 +78,8 @@
 				const uint8_t *whole_pdu, size_t pdu_length, 
 				DATA_BLOB *sig);
 	size_t   (*sig_size)(struct gensec_security *gensec_security, size_t data_size);
+	size_t   (*max_input_size)(struct gensec_security *gensec_security);
+	size_t   (*max_wrapped_size)(struct gensec_security *gensec_security);
 	NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, 
 				 const uint8_t *data, size_t length, 
 				 const uint8_t *whole_pdu, size_t pdu_length, 

Modified: branches/SAMBA_4_0/source/auth/gensec/gensec_gssapi.c
===================================================================
--- branches/SAMBA_4_0/source/auth/gensec/gensec_gssapi.c	2006-07-21 01:37:38 UTC (rev 17170)
+++ branches/SAMBA_4_0/source/auth/gensec/gensec_gssapi.c	2006-07-21 01:44:24 UTC (rev 17171)
@@ -67,8 +67,13 @@
 	uint8_t sasl_protection; /* What was negotiated at the SASL
 				  * layer, independent of the GSSAPI
 				  * layer... */
+
+	size_t max_wrap_buf_size;
 };
 
+static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
+static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
+
 static char *gssapi_error_string(TALLOC_CTX *mem_ctx, 
 				 OM_uint32 maj_stat, OM_uint32 min_stat)
 {
@@ -129,6 +134,9 @@
 		return NT_STATUS_NO_MEMORY;
 	}
 	
+	gensec_gssapi_state->max_wrap_buf_size
+		= lp_parm_int(-1, "gensec_gssapi", "max wrap buf size", 65535);
+		
 	gensec_gssapi_state->sasl = False;
 	gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
 
@@ -490,6 +498,7 @@
 		}
 		break;
 	}
+
 	/* These last two stages are only done if we were invoked as SASL */
 	case STAGE_SASL_SSF_NEG:
 	{
@@ -497,11 +506,17 @@
 		case GENSEC_CLIENT:
 		{
 			uint8_t maxlength_proposed[4]; 
+			uint8_t maxlength_accepted[4]; 
 			uint8_t security_supported;
 			int conf_state;
 			gss_qop_t qop_state;
 			input_token.length = in.length;
 			input_token.value = in.data;
+
+			/* As a client, we have just send a
+			 * zero-length blob to the server (after the
+			 * normal GSSAPI exchange), and it has replied
+			 * with it's SASL negotiation */
 			
 			maj_stat = gss_unwrap(&min_stat, 
 					      gensec_gssapi_state->gssapi_context, 
@@ -521,10 +536,14 @@
 
 			memcpy(maxlength_proposed, output_token.value, 4);
 			gss_release_buffer(&min_stat, &output_token);
-		
+
 			/* first byte is the proposed security */
 			security_supported = maxlength_proposed[0];
 			maxlength_proposed[0] = '\0';
+			
+			/* Rest is the proposed max wrap length */
+			gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
+								     gensec_gssapi_state->max_wrap_buf_size);
 			gensec_gssapi_state->sasl_protection = 0;
 			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
 				if (security_supported & NEG_SEAL) {
@@ -540,13 +559,15 @@
 				DEBUG(1, ("Remote server does not support unprotected connections"));
 				return NT_STATUS_ACCESS_DENIED;
 			}
+
+			/* Send back the negotiated max length */
+
+			RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);
+
+			maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
 			
-			/* We just accept their max length, and send
-			 * it back with the SASL flags */
-			maxlength_proposed[0] = gensec_gssapi_state->sasl_protection;
-			
-			input_token.value = maxlength_proposed;
-			input_token.length = sizeof(maxlength_proposed);
+			input_token.value = maxlength_accepted;
+			input_token.length = sizeof(maxlength_accepted);
 
 			maj_stat = gss_wrap(&min_stat, 
 					    gensec_gssapi_state->gssapi_context, 
@@ -583,8 +604,14 @@
 			uint8_t security_supported = 0x0;
 			int conf_state;
 
-			/* TODO: Need some better ideas for this */
-			RSIVAL(maxlength_proposed, 0, 0xFFFFFF);
+			/* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
+			if (in.length != 0) {
+				DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
+			}
+			
+			/* Give the client some idea what we will support */
+			  
+			RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
 			/* first byte is the proposed security */
 			maxlength_proposed[0] = '\0';
 			
@@ -599,11 +626,9 @@
 				/* If we don't support anything, this must be 0 */
 				RSIVAL(maxlength_proposed, 0, 0x0);
 			}
-				
+
 			/* TODO:  We may not wish to support this */
 			security_supported |= NEG_NONE;
-			
-			/* Ignore 'in' */
 			maxlength_proposed[0] = security_supported;
 			
 			input_token.value = maxlength_proposed;
@@ -636,8 +661,8 @@
 	/* This is s server-only stage */
 	case STAGE_SASL_SSF_ACCEPT:
 	{
-		uint8_t maxlength_proposed[4]; 
-		uint8_t security_proposed;
+		uint8_t maxlength_accepted[4]; 
+		uint8_t security_accepted;
 		int conf_state;
 		gss_qop_t qop_state;
 		input_token.length = in.length;
@@ -659,24 +684,27 @@
 			return NT_STATUS_INVALID_PARAMETER;
 		}
 
-		memcpy(maxlength_proposed, output_token.value, 4);
+		memcpy(maxlength_accepted, output_token.value, 4);
 		gss_release_buffer(&min_stat, &output_token);
 		
 		/* first byte is the proposed security */
-		/* TODO: We should do something with the rest, but for now... */
-		security_proposed = maxlength_proposed[0];
+		security_accepted = maxlength_accepted[0];
+		maxlength_accepted[0] = '\0';
+		
+		/* Rest is the proposed max wrap length */
+		gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
+							     gensec_gssapi_state->max_wrap_buf_size);
 
-		maxlength_proposed[0] = 0x0;
 		gensec_gssapi_state->sasl_protection = 0;
 		if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
-			if (security_proposed & NEG_SEAL) {
+			if (security_accepted & NEG_SEAL) {
 				gensec_gssapi_state->sasl_protection |= NEG_SEAL;
 			}
 		} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-			if (security_proposed & NEG_SIGN) {
+			if (security_accepted & NEG_SIGN) {
 				gensec_gssapi_state->sasl_protection |= NEG_SIGN;
 			}
-		} else if (security_proposed & NEG_NONE) {
+		} else if (security_accepted & NEG_NONE) {
 			gensec_gssapi_state->sasl_protection |= NEG_NONE;
 		} else {
 			DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better"));
@@ -712,6 +740,16 @@
 	int conf_state;
 	input_token.length = in->length;
 	input_token.value = in->data;
+
+	if (gensec_gssapi_state->sasl) {
+		size_t max_input_size = gensec_gssapi_max_input_size(gensec_security);
+		if (max_input_size < in->length) {
+			DEBUG(1, ("gensec_gssapi_wrap: INPUT data (%u) is larger than SASL negotiated maximum size (%u)\n",
+				  in->length, 
+				  (unsigned int)max_input_size));
+		}
+		return NT_STATUS_INVALID_PARAMETER;
+	}
 	
 	maj_stat = gss_wrap(&min_stat, 
 			    gensec_gssapi_state->gssapi_context, 
@@ -749,6 +787,14 @@
 	input_token.length = in->length;
 	input_token.value = in->data;
 	
+	if (gensec_gssapi_state->sasl) {
+		size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
+		if (max_wrapped_size < in->length) {
+			DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+	}
+	
 	maj_stat = gss_unwrap(&min_stat, 
 			      gensec_gssapi_state->gssapi_context, 
 			      &input_token,
@@ -797,7 +843,7 @@
 				     &output_size);
 	if (GSS_ERROR(maj_stat)) {
 		TALLOC_CTX *mem_ctx = talloc_new(NULL); 
-		DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
+		DEBUG(1, ("gensec_gssapi_sig_size: determinaing signature size with gsskrb5_wrap_size failed: %s\n", 
 			  gssapi_error_string(mem_ctx, maj_stat, min_stat)));
 		talloc_free(mem_ctx);
 		return 0;
@@ -811,6 +857,38 @@
 	return output_size - data_size;
 }
 
+/* Find out the maximum input size negotiated on this connection */
+
+static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security) 
+{
+	struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
+	OM_uint32 maj_stat, min_stat;
+	OM_uint32 max_input_size;
+
+	maj_stat = gss_wrap_size_limit(&min_stat, 
+				       gensec_gssapi_state->gssapi_context,
+				       gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
+				       GSS_C_QOP_DEFAULT,
+				       gensec_gssapi_state->max_wrap_buf_size,
+				       &max_input_size);
+	if (GSS_ERROR(maj_stat)) {
+		TALLOC_CTX *mem_ctx = talloc_new(NULL); 
+		DEBUG(1, ("gensec_gssapi_max_input_size: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
+			  gssapi_error_string(mem_ctx, maj_stat, min_stat)));
+		talloc_free(mem_ctx);
+		return 0;
+	}
+
+	return max_input_size;
+}
+
+/* Find out the maximum output size negotiated on this connection */
+static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security) 
+{
+	struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
+	return gensec_gssapi_state->max_wrap_buf_size;
+}
+
 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
 					  TALLOC_CTX *mem_ctx, 
 					  uint8_t *data, size_t length, 
@@ -1287,18 +1365,20 @@
 
 /* As a server, this could in theory accept any GSSAPI mech */
 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
-	.name		= "gssapi_krb5_sasl",
-	.sasl_name      = "GSSAPI",
-	.client_start   = gensec_gssapi_sasl_client_start,
-	.server_start   = gensec_gssapi_sasl_server_start,
-	.update 	= gensec_gssapi_update,
-	.session_key	= gensec_gssapi_session_key,
-	.session_info	= gensec_gssapi_session_info,
-	.wrap           = gensec_gssapi_wrap,
-	.unwrap         = gensec_gssapi_unwrap,
-	.have_feature   = gensec_gssapi_have_feature,
-	.enabled        = True,
-	.kerberos       = True
+	.name		  = "gssapi_krb5_sasl",
+	.sasl_name        = "GSSAPI",
+	.client_start     = gensec_gssapi_sasl_client_start,
+	.server_start     = gensec_gssapi_sasl_server_start,
+	.update 	  = gensec_gssapi_update,
+	.session_key	  = gensec_gssapi_session_key,
+	.session_info	  = gensec_gssapi_session_info,
+	.max_input_size	  = gensec_gssapi_max_input_size,
+	.max_wrapped_size = gensec_gssapi_max_wrapped_size,
+	.wrap             = gensec_gssapi_wrap,
+	.unwrap           = gensec_gssapi_unwrap,
+	.have_feature     = gensec_gssapi_have_feature,
+	.enabled          = True,
+	.kerberos         = True
 };
 
 NTSTATUS gensec_gssapi_init(void)



More information about the samba-cvs mailing list