[SCM] Samba Shared Repository - branch v4-0-test updated - release-4-0-0alpha5-251-g9246924

Stefan Metzmacher metze at samba.org
Tue Aug 12 16:33:21 GMT 2008


The branch, v4-0-test has been updated
       via  9246924effd4d0b08ca1ef87e45ad510020df93e (commit)
       via  f4f4bb7fe977301e468ab164ba750b69d9a92306 (commit)
       via  daa986d1d04e59550bb5d33b5075daa414d087ba (commit)
       via  05a3403967d3cf64bca8b06536dc1b20cf835396 (commit)
      from  54b873e49ff363609632fa2862208bf6b4c1b6ed (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test


- Log -----------------------------------------------------------------
commit 9246924effd4d0b08ca1ef87e45ad510020df93e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Aug 12 15:02:02 2008 +0200

    gensec_gssapi: add support for GENSEC_FEATURE_NEW_SPNEGO
    
    metze

commit f4f4bb7fe977301e468ab164ba750b69d9a92306
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Aug 12 14:57:14 2008 +0200

    gensec_gssapi: fix compiler warnings
    
    metze

commit daa986d1d04e59550bb5d33b5075daa414d087ba
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Aug 12 14:56:36 2008 +0200

    gensec_gssapi: add a function to load the lucid structure once
    
    metze

commit 05a3403967d3cf64bca8b06536dc1b20cf835396
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Aug 12 14:26:21 2008 +0200

    gensec: add support for new style spnego and correctly handle mechListMIC
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 source/auth/gensec/gensec.h        |    1 +
 source/auth/gensec/gensec_gssapi.c |   88 +++++++++++++++++++++++------
 source/auth/gensec/spnego.c        |  109 +++++++++++++++++++++++++++++++++--
 source/auth/gensec/spnego_parse.c  |   32 +++++++++++
 4 files changed, 206 insertions(+), 24 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/auth/gensec/gensec.h b/source/auth/gensec/gensec.h
index 2a89e67..2830297 100644
--- a/source/auth/gensec/gensec.h
+++ b/source/auth/gensec/gensec.h
@@ -53,6 +53,7 @@ struct gensec_target {
 #define GENSEC_FEATURE_ASYNC_REPLIES	0x00000010
 #define GENSEC_FEATURE_DATAGRAM_MODE	0x00000020
 #define GENSEC_FEATURE_SIGN_PKT_HEADER	0x00000040
+#define GENSEC_FEATURE_NEW_SPNEGO	0x00000080
 
 /* GENSEC mode */
 enum gensec_role
diff --git a/source/auth/gensec/gensec_gssapi.c b/source/auth/gensec/gensec_gssapi.c
index ff4a23e..0df40dc 100644
--- a/source/auth/gensec/gensec_gssapi.c
+++ b/source/auth/gensec/gensec_gssapi.c
@@ -65,6 +65,7 @@ struct gensec_gssapi_state {
 	struct smb_krb5_context *smb_krb5_context;
 	struct gssapi_creds_container *client_cred;
 	struct gssapi_creds_container *server_cred;
+	gss_krb5_lucid_context_v1_t *lucid;
 
 	gss_cred_id_t delegated_cred_handle;
 
@@ -143,9 +144,45 @@ static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_st
 	if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
 		maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
 	}
+
+	if (gensec_gssapi_state->lucid) {
+		gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+	}
+
 	return 0;
 }
 
+static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
+{
+	OM_uint32 maj_stat, min_stat;
+
+	if (gensec_gssapi_state->lucid) {
+		return NT_STATUS_OK;
+	}
+
+	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
+						     &gensec_gssapi_state->gssapi_context,
+						     1,
+						     (void **)&gensec_gssapi_state->lucid);
+	if (maj_stat != GSS_S_COMPLETE) {
+		DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
+			gssapi_error_string(gensec_gssapi_state,
+					    maj_stat, min_stat,
+					    gensec_gssapi_state->gss_oid)));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (gensec_gssapi_state->lucid->version != 1) {
+		DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
+			gensec_gssapi_state->lucid->version));
+		gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+		gensec_gssapi_state->lucid = NULL;
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
 	struct gensec_gssapi_state *gensec_gssapi_state;
@@ -169,6 +206,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 	gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
 	gensec_gssapi_state->server_name = GSS_C_NO_NAME;
 	gensec_gssapi_state->client_name = GSS_C_NO_NAME;
+	gensec_gssapi_state->lucid = NULL;
 
 	/* TODO: Fill in channel bindings */
 	gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
@@ -1083,10 +1121,10 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
 
 	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
 		input_message.length = pdu_length;
-		input_message.value = whole_pdu;
+		input_message.value = discard_const(whole_pdu);
 	} else {
 		input_message.length = length;
-		input_message.value = data;
+		input_message.value = discard_const(data);
 	}
 
 	input_token.length = sig->length;
@@ -1139,6 +1177,31 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
 	if (feature & GENSEC_FEATURE_DCE_STYLE) {
 		return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
 	}
+	if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
+		NTSTATUS status;
+
+		if (!(gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG)) {
+			return false;
+		}
+
+		if (lp_parm_bool(gensec_security->lp_ctx, NULL, "gensec_gssapi", "force_new_spnego", false)) {
+			return true;
+		}
+		if (lp_parm_bool(gensec_security->lp_ctx, NULL, "gensec_gssapi", "disable_new_spnego", false)) {
+			return false;
+		}
+
+		status = gensec_gssapi_init_lucid(gensec_gssapi_state);
+		if (!NT_STATUS_IS_OK(status)) {
+			return false;
+		}
+
+		if (gensec_gssapi_state->lucid->protocol == 1) {
+			return true;
+		}
+
+		return false;
+	}
 	/* We can always do async (rather than strict request/reply) packets.  */
 	if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
 		return true;
@@ -1386,8 +1449,7 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	OM_uint32 maj_stat, min_stat;
-	gss_krb5_lucid_context_v1_t *lucid = NULL;
+	NTSTATUS status;
 
 	if (gensec_gssapi_state->sig_size) {
 		return gensec_gssapi_state->sig_size;
@@ -1399,18 +1461,12 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
 		gensec_gssapi_state->sig_size = 37;
 	}
 
-	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
-						     &gensec_gssapi_state->gssapi_context,
-						     1, (void **)&lucid);
-	if (maj_stat != GSS_S_COMPLETE) {
-		return gensec_gssapi_state->sig_size;
-	}
-
-	if (lucid->version != 1) {
+	status = gensec_gssapi_init_lucid(gensec_gssapi_state);
+	if (!NT_STATUS_IS_OK(status)) {
 		return gensec_gssapi_state->sig_size;
 	}
 
-	if (lucid->protocol == 1) {
+	if (gensec_gssapi_state->lucid->protocol == 1) {
 		if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
 			/*
 			 * TODO: windows uses 76 here, but we don't know
@@ -1420,8 +1476,8 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
 		} else {
 			gensec_gssapi_state->sig_size = 28;
 		}
-	} else if (lucid->protocol == 0) {
-		switch (lucid->rfc1964_kd.ctx_key.type) {
+	} else if (gensec_gssapi_state->lucid->protocol == 0) {
+		switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
 		case KEYTYPE_DES:
 		case KEYTYPE_ARCFOUR:
 		case KEYTYPE_ARCFOUR_56:
@@ -1441,8 +1497,6 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
 		}
 	}
 
-	gss_krb5_free_lucid_sec_context(&min_stat, lucid);
-
 	return gensec_gssapi_state->sig_size;
 }
 
diff --git a/source/auth/gensec/spnego.c b/source/auth/gensec/spnego.c
index 1544326..1855e05 100644
--- a/source/auth/gensec/spnego.c
+++ b/source/auth/gensec/spnego.c
@@ -5,6 +5,7 @@
    
    Copyright (C) Jim McDonough <jmcd at us.ibm.com>      2003
    Copyright (C) Andrew Bartlett <abartlet at samba.org> 2004-2005
+   Copyright (C) Stefan Metzmacher <metze at samba.org>  2004-2008
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -44,6 +45,8 @@ struct spnego_state {
 	bool no_response_expected;
 
 	const char *neg_oid;
+
+	DATA_BLOB mech_types;
 };
 
 
@@ -60,6 +63,7 @@ static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_securi
 	spnego_state->state_position = SPNEGO_CLIENT_START;
 	spnego_state->sub_sec_security = NULL;
 	spnego_state->no_response_expected = false;
+	spnego_state->mech_types = data_blob(NULL, 0);
 
 	gensec_security->private_data = spnego_state;
 	return NT_STATUS_OK;
@@ -78,6 +82,7 @@ static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_securi
 	spnego_state->state_position = SPNEGO_SERVER_START;
 	spnego_state->sub_sec_security = NULL;
 	spnego_state->no_response_expected = false;
+	spnego_state->mech_types = data_blob(NULL, 0);
 
 	gensec_security->private_data = spnego_state;
 	return NT_STATUS_OK;
@@ -392,12 +397,22 @@ static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_
 	int i;
 	NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
 	DATA_BLOB null_data_blob = data_blob(NULL,0);
+	bool ok;
 
 	const struct gensec_security_ops_wrapper *all_sec
 		= gensec_security_by_oid_list(gensec_security, 
 					      out_mem_ctx, 
 					      mechType,
 					      GENSEC_OID_SPNEGO);
+
+	ok = spnego_write_mech_types(spnego_state,
+				     mechType,
+				     &spnego_state->mech_types);
+	if (!ok) {
+		DEBUG(1, ("SPNEGO: Failed to write mechTypes\n"));
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	if (spnego_state->state_position == SPNEGO_SERVER_START) {
 		for (i=0; all_sec && all_sec[i].op; i++) {
 			/* optomisitic token */
@@ -556,6 +571,9 @@ static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec
 					      GENSEC_OID_SPNEGO);
 	for (i=0; all_sec && all_sec[i].op; i++) {
 		struct spnego_data spnego_out;
+		const char **send_mech_types;
+		bool ok;
+
 		nt_status = gensec_subcontext_start(spnego_state,
 						    gensec_security,
 						    &spnego_state->sub_sec_security);
@@ -591,10 +609,20 @@ static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec
 		}
 
 		spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
-		
+
+		send_mech_types = gensec_security_oids_from_ops_wrapped(out_mem_ctx,
+									&all_sec[i]);
+
+		ok = spnego_write_mech_types(spnego_state,
+					     send_mech_types,
+					     &spnego_state->mech_types);
+		if (!ok) {
+			DEBUG(1, ("SPNEGO: Failed to write mechTypes\n"));
+			return NT_STATUS_NO_MEMORY;
+		}
+
 		/* List the remaining mechs as options */
-		spnego_out.negTokenInit.mechTypes = gensec_security_oids_from_ops_wrapped(out_mem_ctx, 
-											  &all_sec[i]);
+		spnego_out.negTokenInit.mechTypes = send_mech_types;
 		spnego_out.negTokenInit.reqFlags = 0;
 		
 		if (spnego_state->state_position == SPNEGO_SERVER_START) {
@@ -644,7 +672,9 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec
 						  struct spnego_state *spnego_state,
 						  TALLOC_CTX *out_mem_ctx, 
 						  NTSTATUS nt_status,
-						  const DATA_BLOB unwrapped_out, DATA_BLOB *out) 
+						  const DATA_BLOB unwrapped_out,
+						  DATA_BLOB mech_list_mic,
+						  DATA_BLOB *out)
 {
 	struct spnego_data spnego_out;
 	DATA_BLOB null_data_blob = data_blob(NULL, 0);
@@ -664,6 +694,7 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec
 			spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
 		}
 		spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
+		spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
 		spnego_state->state_position = SPNEGO_DONE;
 	} else {
 		spnego_out.negTokenTarg.negResult = SPNEGO_REJECT;
@@ -687,6 +718,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 {
 	struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
 	DATA_BLOB null_data_blob = data_blob(NULL, 0);
+	DATA_BLOB mech_list_mic = data_blob(NULL, 0);
 	DATA_BLOB unwrapped_out = data_blob(NULL, 0);
 	struct spnego_data spnego_out;
 	struct spnego_data spnego;
@@ -737,7 +769,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 								      spnego_state,
 								      out_mem_ctx,
 								      nt_status,
-								      unwrapped_out, 
+								      unwrapped_out,
+								      null_data_blob,
 								      out);
 			
 			spnego_free_data(&spnego);
@@ -829,6 +862,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 	case SPNEGO_SERVER_TARG:
 	{
 		NTSTATUS nt_status;
+		bool new_spnego = false;
+
 		if (!in.length) {
 			return NT_STATUS_INVALID_PARAMETER;
 		}
@@ -860,12 +895,40 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 					  out_mem_ctx, 
 					  spnego.negTokenTarg.responseToken,
 					  &unwrapped_out);
+		if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
+			new_spnego = true;
+			nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+							out_mem_ctx,
+							spnego_state->mech_types.data,
+							spnego_state->mech_types.length,
+							spnego_state->mech_types.data,
+							spnego_state->mech_types.length,
+							&spnego.negTokenTarg.mechListMIC);
+			if (!NT_STATUS_IS_OK(nt_status)) {
+				DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+					nt_errstr(nt_status)));
+			}
+		}
+		if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
+			nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
+						       out_mem_ctx,
+						       spnego_state->mech_types.data,
+						       spnego_state->mech_types.length,
+						       spnego_state->mech_types.data,
+						       spnego_state->mech_types.length,
+						       &mech_list_mic);
+			if (!NT_STATUS_IS_OK(nt_status)) {
+				DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
+					nt_errstr(nt_status)));
+			}
+		}
 
 		nt_status = gensec_spnego_server_negTokenTarg(gensec_security,
 							      spnego_state,
 							      out_mem_ctx, 
 							      nt_status,
-							      unwrapped_out, 
+							      unwrapped_out,
+							      mech_list_mic,
 							      out);
 		
 		spnego_free_data(&spnego);
@@ -940,13 +1003,45 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 			} else {
 				nt_status = NT_STATUS_OK;
 			}
+			if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
+				nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+								out_mem_ctx,
+								spnego_state->mech_types.data,
+								spnego_state->mech_types.length,
+								spnego_state->mech_types.data,
+								spnego_state->mech_types.length,
+								&spnego.negTokenTarg.mechListMIC);
+				if (!NT_STATUS_IS_OK(nt_status)) {
+					DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+						nt_errstr(nt_status)));
+				}
+			}
 		} else {
+			bool new_spnego = false;
+
 			nt_status = gensec_update(spnego_state->sub_sec_security,
 						  out_mem_ctx, 
 						  spnego.negTokenTarg.responseToken, 
 						  &unwrapped_out);
 
 			if (NT_STATUS_IS_OK(nt_status)) {
+				new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
+								 GENSEC_FEATURE_NEW_SPNEGO);
+			}
+			if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
+				nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
+							       out_mem_ctx,
+							       spnego_state->mech_types.data,
+							       spnego_state->mech_types.length,
+							       spnego_state->mech_types.data,
+							       spnego_state->mech_types.length,
+							       &mech_list_mic);
+				if (!NT_STATUS_IS_OK(nt_status)) {
+					DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
+						nt_errstr(nt_status)));
+				}
+			}
+			if (NT_STATUS_IS_OK(nt_status)) {
 				spnego_state->no_response_expected = true;
 			}
 		} 
@@ -967,7 +1062,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
 			spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
 			spnego_out.negTokenTarg.supportedMech = NULL;
 			spnego_out.negTokenTarg.responseToken = unwrapped_out;
-			spnego_out.negTokenTarg.mechListMIC = null_data_blob;
+			spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
 			
 			if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
 				DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
diff --git a/source/auth/gensec/spnego_parse.c b/source/auth/gensec/spnego_parse.c
index 8012a83..5ea8cf7 100644
--- a/source/auth/gensec/spnego_parse.c
+++ b/source/auth/gensec/spnego_parse.c
@@ -374,3 +374,35 @@ out:
 	return ret;
 }
 
+bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
+			     const char **mech_types,
+			     DATA_BLOB *blob)
+{
+	struct asn1_data *asn1 = asn1_init(mem_ctx);
+
+	/* Write mechTypes */
+	if (mech_types && *mech_types) {
+		int i;
+
+		asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+		for (i = 0; mech_types[i]; i++) {
+			asn1_write_OID(asn1, mech_types[i]);
+		}
+		asn1_pop_tag(asn1);
+	}
+
+	if (asn1->has_error) {
+		asn1_free(asn1);
+		return false;
+	}
+
+	*blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length);
+	if (blob->length != asn1->length) {
+		asn1_free(asn1);
+		return false;
+	}
+
+	asn1_free(asn1);
+
+	return true;
+}


-- 
Samba Shared Repository


More information about the samba-cvs mailing list