mit-spnego-kerb-ap-rep   [plain text]


Index: samba/source/libsmb/asn1.c
===================================================================
--- samba/source/libsmb/asn1.c.orig
+++ samba/source/libsmb/asn1.c
@@ -261,6 +261,19 @@ BOOL asn1_read_uint8(ASN1_DATA *data, ui
 	return asn1_read(data, v, 1);
 }
 
+/*
+ * Check thta the value of the ASN1 buffer at the current offset equals tag.
+ */
+BOOL asn1_check_tag(ASN1_DATA *data, uint8 tag)
+{
+	if (data->has_error || data->ofs >= data->length || data->ofs < 0) {
+		data->has_error = True;
+		return False;
+	}
+
+	return (tag == data->data[data->ofs]);
+}
+
 /* start reading a nested asn1 structure */
 BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
 {
Index: samba/source/libsmb/clispnego.c
===================================================================
--- samba/source/libsmb/clispnego.c.orig
+++ samba/source/libsmb/clispnego.c
@@ -247,6 +247,18 @@ BOOL parse_negTokenTarg(DATA_BLOB blob, 
 	asn1_end_tag(&data);
 	asn1_end_tag(&data);
 
+	/* Skip any optional req_flags that are sent per RFC 4178 */
+	if (asn1_check_tag(&data, ASN1_CONTEXT(1))) {
+		uint8 flags;
+
+		asn1_start_tag(&data, ASN1_CONTEXT(1));
+		asn1_start_tag(&data, ASN1_BITFIELD);
+		while (asn1_tag_remaining(&data) > 0)
+			asn1_read_uint8(&data, &flags);
+		asn1_end_tag(&data);
+		asn1_end_tag(&data);
+	}
+
 	asn1_start_tag(&data, ASN1_CONTEXT(2));
 	asn1_read_OctetString(&data,secblob);
 	asn1_end_tag(&data);
Index: samba/source/smbd/sesssetup.c
===================================================================
--- samba/source/smbd/sesssetup.c.orig
+++ samba/source/smbd/sesssetup.c
@@ -226,6 +226,7 @@ static BOOL make_krb5_skew_error(DATA_BL
 static int reply_spnego_kerberos(connection_struct *conn, 
 				 char *inbuf, char *outbuf,
 				 int length, int bufsize,
+				 char *mechOID,
 				 DATA_BLOB *secblob,
 				 BOOL *p_invalidate_vuid)
 {
@@ -562,7 +563,7 @@ static int reply_spnego_kerberos(connect
 	} else {
 		ap_rep_wrapped = data_blob(NULL, 0);
 	}
-	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
+	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, mechOID);
 	reply_sesssetup_blob(conn, outbuf, response, ret);
 
 	data_blob_free(&ap_rep);
@@ -658,12 +659,13 @@ static BOOL reply_spnego_ntlmssp(connect
  Is this a krb5 mechanism ?
 ****************************************************************************/
 
-static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
+static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, char **kerb_mechOID)
 {
 	char *OIDs[ASN1_MAX_OIDS];
 	int i;
+	NTSTATUS ret = NT_STATUS_OK;
 
-	*p_is_krb5 = False;
+	*kerb_mechOID = NULL;
 
 	/* parse out the OIDs and the first sec blob */
 	if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
@@ -683,7 +685,9 @@ static NTSTATUS parse_spnego_mechanisms(
 #ifdef HAVE_KRB5	
 	if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
 	    strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
-		*p_is_krb5 = True;
+		*kerb_mechOID = strdup(OIDs[0]);
+		if (*kerb_mechOID == NULL)
+			ret = NT_STATUS_NO_MEMORY;
 	}
 #endif
 		
@@ -691,7 +695,7 @@ static NTSTATUS parse_spnego_mechanisms(
 		DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
 		free(OIDs[i]);
 	}
-	return NT_STATUS_OK;
+	return ret;
 }
 
 /****************************************************************************
@@ -708,10 +712,10 @@ static int reply_spnego_negotiate(connec
 {
 	DATA_BLOB secblob;
 	DATA_BLOB chal;
-	BOOL got_kerberos_mechanism = False;
+	char *kerb_mech;
 	NTSTATUS status;
 
-	status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
+	status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
 	if (!NT_STATUS_IS_OK(status)) {
 		/* Kill the intermediate vuid */
 		invalidate_vuid(vuid);
@@ -721,17 +725,21 @@ static int reply_spnego_negotiate(connec
 	DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
 
 #ifdef HAVE_KRB5
-	if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+	if ( kerb_mech && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
 		BOOL destroy_vuid = True;
 		int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
-						length, bufsize, &secblob, &destroy_vuid);
+						length, bufsize, kerb_mech,
+						&secblob, &destroy_vuid);
 		data_blob_free(&secblob);
 		if (destroy_vuid) {
 			/* Kill the intermediate vuid */
 			invalidate_vuid(vuid);
 		}
+		free(kerb_mech);
 		return ret;
 	}
+	if (kerb_mech)
+		free(kerb_mech);
 #endif
 
 	if (*auth_ntlmssp_state) {
@@ -787,23 +795,27 @@ static int reply_spnego_auth(connection_
 	if (auth.data[0] == ASN1_APPLICATION(0)) {
 		/* Might be a second negTokenTarg packet */
 
-		BOOL got_krb5_mechanism = False;
-		status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
+		char *kerb_mech = NULL;
+		status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
 		if (NT_STATUS_IS_OK(status)) {
 			DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
 #ifdef HAVE_KRB5
-			if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+			if ( kerb_mech && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
 				BOOL destroy_vuid = True;
 				int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
-								length, bufsize, &secblob, &destroy_vuid);
+								length, bufsize, kerb_mech,
+								&secblob, &destroy_vuid);
 				data_blob_free(&secblob);
 				data_blob_free(&auth);
 				if (destroy_vuid) {
 					/* Kill the intermediate vuid */
 					invalidate_vuid(vuid);
 				}
+				free(kerb_mech);
 				return ret;
 			}
+			if (kerb_mech)
+				free(kerb_mech);
 #endif
 		}
 	}