[PATCH] New spnego_auth{start|update|end} functions

Anthony Liguori aliguor at us.ibm.com
Fri Aug 1 20:02:40 GMT 2003


All,

This patch introduces a set of routines to access spnego authenticate 
similar to the ntlmssp_server_start, _update, _end functions.

A sample usage would be:

SPNEGO_STATE *spnego_state = 0;

spnego_auth_start(&spnego_state, True); /* true for server, false for 
client */
spnego_register_ntlmssp(spnego_state); /* add NTLMSSP a supported SPNEGO 
mechanism */

/* get packet in blob request */

while spnego_auth_update(spnego_state, request, &reply) == 
NT_STATUS_MORE_PROCESSING_REQUIRED
  send reply
  read request
end while

spnego_auth_end(&spnego_state);

Anthony Liguori
Linux/Active Directory Interoperability
Linux Technology Center (LTC) - IBM Austin
E-mail: aliguor at us.ibm.com
Phone: (512) 838-1208
-------------- next part --------------
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude='#*#' ../../samba-prestine/source/include/spnego.h ./include/spnego.h
--- ../../samba-prestine/source/include/spnego.h	2003-07-31 05:21:13.000000000 -0500
+++ ./include/spnego.h	2003-07-31 16:38:26.000000000 -0500
@@ -43,7 +43,7 @@ typedef enum _spnego_negResult {
 } negResult_t;
 
 typedef struct spnego_negTokenInit {
-	const char **mechTypes;
+	char **mechTypes;
 	int reqFlags;
 	DATA_BLOB mechToken;
 	DATA_BLOB mechListMIC;
@@ -51,15 +51,33 @@ typedef struct spnego_negTokenInit {
 
 typedef struct spnego_negTokenTarg {
 	uint8 negResult;
-	const char *supportedMech;
+	char *supportedMech;
 	DATA_BLOB responseToken;
 	DATA_BLOB mechListMIC;
 } negTokenTarg_t;
 
-typedef struct spnego_spnego {
+typedef struct spnego_data {
 	int type;
 	negTokenInit_t negTokenInit;
 	negTokenTarg_t negTokenTarg;
 } SPNEGO_DATA;
 
+struct spnego_state;
+typedef struct spnego_sec_mech {
+	const char *oid;
+	void *state;
+	NTSTATUS (*hint)(struct spnego_sec_mech *, DATA_BLOB *);
+	NTSTATUS (*step)(struct spnego_sec_mech *,
+			 const DATA_BLOB, DATA_BLOB *);
+	NTSTATUS (*end)(struct spnego_state *);
+	struct spnego_sec_mech *next;
+} SPNEGO_SEC_MECH;
+
+typedef struct spnego_state {
+	TALLOC_CTX *mem_ctx;
+	SPNEGO_SEC_MECH *mech_list;
+	SPNEGO_SEC_MECH *mech;
+	BOOL server;
+} SPNEGO_STATE;
+
 #endif
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude='#*#' ../../samba-prestine/source/libsmb/spnego.c ./libsmb/spnego.c
--- ../../samba-prestine/source/libsmb/spnego.c	2003-07-31 10:53:59.000000000 -0500
+++ ./libsmb/spnego.c	2003-08-01 09:47:04.000000000 -0500
@@ -26,6 +26,9 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
 
+/*****************************************************************************
+ *                  Private SPNEGO Parsing routines
+ ****************************************************************************/
 static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
 {
 	ZERO_STRUCTP(token);
@@ -213,6 +216,9 @@ static BOOL write_negTokenTarg(ASN1_DATA
 	return !asn1->has_error;
 }
 
+/*****************************************************************************
+ *                  Public SPNEGO Parsing routines
+ ****************************************************************************/
 ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
 {
 	ASN1_DATA asn1;
@@ -311,3 +317,226 @@ out:
 	return ret;
 }
 
+/*****************************************************************************
+ *                  Private SPNEGO negotiation routines
+ ****************************************************************************/
+static NTSTATUS spnego_negotiate(SPNEGO_STATE *spnego_state,
+				 const DATA_BLOB request, DATA_BLOB *reply)
+{
+	SPNEGO_DATA spnego;
+	NTSTATUS ret = NT_STATUS_INVALID_PARAMETER;
+	SPNEGO_SEC_MECH *mech;
+
+	if (-1 == read_spnego_data(request, &spnego)) {
+		return ret;
+	}
+
+	if (SPNEGO_NEG_TOKEN_INIT != spnego.type) {
+		DEBUG(1, ("spnego_negotiate: expected negTokenInit got"
+			  " negTokenTarg\n"));
+		goto out;
+	}
+	if (!spnego.negTokenInit.mechTypes ||
+	    !spnego.negTokenInit.mechTypes[0]) {
+		DEBUG(1, ("spnego_negotiate: no mechType specificed\n"));
+		goto out;
+	}
+
+	for (mech = spnego_state->mech_list;
+	     mech &&strcmp(spnego.negTokenInit.mechTypes[0], 
+			   mech->oid); mech = mech->next) { }
+
+	if (!mech) {
+		DEBUG(1, ("spnego_negotiate: unknown OID %s\n",
+			  spnego.negTokenInit.mechTypes[0]));
+		goto out;
+	}
+
+	spnego_state->mech = mech;
+
+	ret = spnego_state->mech->step(spnego_state->mech, 
+				       spnego.negTokenInit.mechToken,
+				       reply);
+out:
+	free_spnego_data(&spnego);
+	return ret;
+}
+
+static NTSTATUS spnego_choose_mech(SPNEGO_STATE *spnego_state,
+				   const DATA_BLOB request,
+				   DATA_BLOB *reply)
+{
+	SPNEGO_DATA spnego;
+	NTSTATUS ret = NT_STATUS_INVALID_PARAMETER;
+	int i;
+	SPNEGO_SEC_MECH *mech;
+
+	if (-1 == read_spnego_data(request, &spnego)) {
+		return ret;
+	}
+
+	if (SPNEGO_NEG_TOKEN_INIT != spnego.type) {
+		DEBUG(1, ("spnego_choose_mech: expected negTokenInit got"
+			  " negTokenTarg\n"));
+		goto out;
+	}
+	if (!spnego.negTokenInit.mechTypes) {
+		DEBUG(1, ("spnego_choose_mech: no mechType specificed\n"));
+		goto out;
+	}
+
+	for (i = 0; spnego.negTokenInit.mechTypes[i]; i++) {
+		for (mech = spnego_state->mech_list; mech; mech = mech->next) {
+			if (!strcmp(spnego.negTokenInit.mechTypes[i],
+				    mech->oid)) {
+				break;
+			}
+		}
+	}
+	
+	if (!mech) {
+		DEBUG(1, ("spnego_choose_mech: cannot negotiate an acceptable"
+			  " mechType\n"));
+		goto out;
+	}
+	free_spnego_data(&spnego);
+
+	spnego_state->mech = mech;
+
+	spnego.negTokenInit.mechTypes = smb_xmalloc(sizeof(char *) * 2);
+	spnego.negTokenInit.mechTypes[0] = 
+		smb_xstrdup(spnego_state->mech->oid);
+	spnego.negTokenInit.mechTypes[1] = NULL;
+	ret = spnego_state->mech->hint(spnego_state->mech,
+				       &spnego.negTokenInit.mechToken);
+
+	if (-1 == write_spnego_data(reply, &spnego)) {
+		ret = NT_STATUS_INVALID_PARAMETER;
+	}
+
+out:
+	free_spnego_data(&spnego);
+	return ret;
+}
+
+static NTSTATUS spnego_mech_offerings(SPNEGO_STATE *spnego_state,
+				      const DATA_BLOB unused,
+				      DATA_BLOB *reply)
+{
+	SPNEGO_DATA spnego;
+	NTSTATUS ret;
+	SPNEGO_SEC_MECH *mech;
+	int capacity = 0;
+	int i = 0;
+
+	ZERO_STRUCT(spnego);
+
+	/* Server negTokenInit (mech offerings) */
+	spnego.type = SPNEGO_NEG_TOKEN_INIT;
+
+	for (mech = spnego_state->mech_list; mech; mech = mech->next) {
+		if ((i + 1) >= capacity) {
+			capacity += 10;
+			spnego.negTokenInit.mechTypes = 
+				talloc_realloc(spnego_state->mem_ctx,
+					       spnego.negTokenInit.mechTypes,
+					       capacity * sizeof(char *));
+		}
+
+		spnego.negTokenInit.mechTypes[i] = 
+			talloc_strdup(spnego_state->mem_ctx,
+				      spnego_state->mech_list[i].oid);
+		i++;
+	}
+
+	spnego.negTokenInit.mechTypes[i] = NULL;
+
+	if (!spnego.negTokenInit.mechTypes[0]) {
+		DEBUG(0, ("spnego_mech_offerings: no mechTypes!\n"));
+		ret = NT_STATUS_INVALID_PARAMETER;
+		goto out;
+	}
+
+	ret = spnego_state->mech_list->hint(spnego_state->mech_list,
+					    &spnego.negTokenInit.mechListMIC);
+
+	if (-1 == write_spnego_data(reply, &spnego)) {
+		ret = NT_STATUS_INVALID_PARAMETER;
+	}
+out:
+	free_spnego_data(&spnego);
+	return ret;
+}
+
+/*****************************************************************************
+ *                  Public SPNEGO state machine functions
+ ****************************************************************************/
+/**
+ * Create an SPNEGO state machine
+ *
+ * @param spnego_state [out] the allocated SPNEGO state
+ */
+NTSTATUS spnego_auth_start(SPNEGO_STATE **spnego_state, BOOL server)
+{
+	TALLOC_CTX *ctx = talloc_init("SPNEGO context");
+	int i;
+
+	*spnego_state = talloc_zero(ctx, sizeof(**spnego_state));
+	if (!*spnego_state) {
+		DEBUG(0,("spnego_auth_start: talloc failed\n"));
+		talloc_destroy(ctx);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	(*spnego_state)->mem_ctx = ctx;
+	(*spnego_state)->server = server;
+
+	return NT_STATUS_OK;
+}
+
+/**
+ * Destroy an SPNEGO state machine
+ *
+ * @param spnego_state [in] the allocated SPNEGO state
+ */
+NTSTATUS spnego_auth_end(SPNEGO_STATE **spnego_state)
+{
+	NTSTATUS ret = NT_STATUS_OK;
+
+	if ((*spnego_state)->mech) {
+		ret = (*spnego_state)->mech->end(*spnego_state);
+	}
+
+	talloc_destroy((*spnego_state)->mem_ctx);
+	*spnego_state = NULL;
+
+	return ret;
+}
+
+/**
+ * Next state function for the SPNEGO state machine
+ *
+ * @param spnego_state SPNEGO state
+ * @param request The request as a DATA_BLOB--an empty request is valid on if
+ *                the server is initiating the exchange
+ * @param reply The reply as an allocated DATA_BLOB--caller must free
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK
+ */
+NTSTATUS spnego_auth_update(SPNEGO_STATE *spnego_state,
+			      const DATA_BLOB request, DATA_BLOB *reply)
+{
+	NTSTATUS ret;
+
+	if (spnego_state->mech) {
+		ret = spnego_state->mech->step(spnego_state->mech,
+					       request, reply);
+	} else if (!request.data) {
+		ret = spnego_mech_offerings(spnego_state, request, reply);
+	} else if (spnego_state->server) {
+		ret = spnego_negotiate(spnego_state, request, reply);
+	} else {
+		ret = spnego_choose_mech(spnego_state, request, reply);
+	}
+
+	return ret;
+}
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude='#*#' ../../samba-prestine/source/libsmb/spnego_ntlmssp.c ./libsmb/spnego_ntlmssp.c
--- ../../samba-prestine/source/libsmb/spnego_ntlmssp.c	1969-12-31 18:00:00.000000000 -0600
+++ ./libsmb/spnego_ntlmssp.c	2003-08-01 11:11:13.000000000 -0500
@@ -0,0 +1,262 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   RFC2478 Compliant SPNEGO implementation
+
+   Copyright (C) Jim McDonough <jmcd at us.ibm.com>   2003
+
+   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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/*****************************************************************************
+ *                  Private SPNEGO-NTLMSSP routines
+ ****************************************************************************/
+static NTSTATUS spnego_ntlmssp_end(SPNEGO_STATE *state)
+{
+	return state->server ? 
+		ntlmssp_server_end((NTLMSSP_STATE **)&state->mech->state) :
+		ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)
+				   &state->mech->state);
+}
+
+static NTSTATUS spnego_ntlmssp_results(SPNEGO_SEC_MECH *mech,
+				       const DATA_BLOB request,
+				       DATA_BLOB *reply)
+{
+	SPNEGO_DATA spnego;
+	NTSTATUS ret = NT_STATUS_INVALID_PARAMETER;		
+
+	mech->step = 0;
+
+	if (-1 == read_spnego_data(request, &spnego)) {
+		return ret;
+	}
+
+	if (SPNEGO_NEG_TOKEN_TARG != spnego.type) {
+		DEBUG(1, ("spnego_ntlmssp_results: expecting negTokenTarg got"
+			  " negTokenInit\n"));
+		goto out;
+	}
+
+	switch (spnego.negTokenTarg.negResult) {
+	case SPNEGO_ACCEPT_COMPLETED:
+		ret = NT_STATUS_OK;
+		break;
+	case SPNEGO_REJECT:
+		ret = NT_STATUS_ACCESS_DENIED;
+		break;
+	default:
+		break;
+	}
+
+out:
+	free_spnego_data(&spnego);
+	return ret;
+}
+
+static NTSTATUS spnego_ntlmssp_verify_auth(SPNEGO_SEC_MECH *mech,
+					   const DATA_BLOB request,
+					   DATA_BLOB *reply)
+{
+	SPNEGO_DATA spnego;
+	NTSTATUS ret = NT_STATUS_INVALID_PARAMETER;
+	NTLMSSP_STATE *ntlmssp_state = (NTLMSSP_STATE *)mech->state;
+	
+	mech->step = 0;
+
+	if (-1 == read_spnego_data(request, &spnego)) {
+		return ret;
+	}
+
+	if (SPNEGO_NEG_TOKEN_TARG != spnego.type) {
+		DEBUG(1, ("spnego_server_negotiate: expected negTokenTarg got"
+			  " negTokenInit\n"));
+		goto out;
+	}
+
+	if (!spnego.negTokenTarg.responseToken.data) {
+		DEBUG(1, ("spnego_server_negotiate: invalid responseToken\n"));
+		goto out;
+	}
+
+	ret = ntlmssp_server_update(ntlmssp_state,
+				    spnego.negTokenTarg.responseToken, reply);
+	data_blob_free(reply);
+
+	ZERO_STRUCT(spnego);
+	spnego.type = SPNEGO_NEG_TOKEN_TARG;
+	spnego.negTokenTarg.negResult = !NT_STATUS_IS_OK(ret) ?
+		SPNEGO_ACCEPT_COMPLETED : SPNEGO_REJECT;
+
+	if (-1 == write_spnego_data(reply, &spnego)) {
+		ret = NT_STATUS_INVALID_PARAMETER;
+	}
+
+out:
+	return ret;
+}
+
+static NTSTATUS spnego_ntlmssp_authenticate(SPNEGO_SEC_MECH *mech,
+					    const DATA_BLOB request,
+					    DATA_BLOB *reply)
+{
+	NTLMSSP_CLIENT_STATE *ntlmssp_state = 
+		(NTLMSSP_CLIENT_STATE *)mech->state;
+	SPNEGO_DATA spnego, spnego_out;
+	NTSTATUS ret = NT_STATUS_INVALID_PARAMETER;
+
+	mech->step = 0;
+	if (-1 == read_spnego_data(request, &spnego)) {
+		return ret;
+	}
+
+	ZERO_STRUCT(spnego_out);
+
+	if (SPNEGO_NEG_TOKEN_TARG != spnego.type) {
+		DEBUG(1, ("spnego_ntlmssp_gen_challenge: expected negTokenTarg"
+			  " got negTokenInit\n"));
+		goto out;
+	}
+
+	if (!spnego.negTokenTarg.responseToken.data) {
+		DEBUG(1, ("spnego_ntlmssp_gen_challenge: invalid "
+			  "responseToken\n"));
+		goto out;
+	}
+
+	spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
+	spnego_out.negTokenTarg.supportedMech = smb_xstrdup(OID_NTLMSSP);
+	ret = ntlmssp_client_update(ntlmssp_state,
+				    spnego.negTokenTarg.responseToken,
+				    &spnego_out.negTokenTarg.responseToken);
+
+	if (-1 == write_spnego_data(reply, &spnego_out)) {
+		ret = NT_STATUS_INVALID_PARAMETER;
+	} else {
+		ret = NT_STATUS_MORE_PROCESSING_REQUIRED;
+		mech->step = spnego_ntlmssp_results;
+	}
+
+out:
+	free_spnego_data(&spnego);
+	free_spnego_data(&spnego_out);
+	return ret;
+}
+
+static NTSTATUS spnego_ntlmssp_challenge(SPNEGO_SEC_MECH *mech,
+					 const DATA_BLOB request,
+					 DATA_BLOB *reply)
+{
+	NTLMSSP_STATE **ntlmssp_state;
+	SPNEGO_DATA spnego;
+	NTSTATUS ret;
+
+	mech->step = 0;
+
+	ntlmssp_state = (NTLMSSP_STATE **)&mech->state;
+	ret = ntlmssp_server_start(ntlmssp_state);
+
+	if (!NT_STATUS_IS_OK(ret)) {
+		goto out;
+	}
+
+	ret = NT_STATUS_MORE_PROCESSING_REQUIRED;
+
+	ZERO_STRUCT(spnego);
+	spnego.type = SPNEGO_NEG_TOKEN_TARG;
+	spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+	spnego.negTokenTarg.supportedMech = smb_xstrdup(OID_NTLMSSP);
+	ret = ntlmssp_server_update(*ntlmssp_state, request,
+				    &spnego.negTokenTarg.responseToken);
+
+	if (-1 == write_spnego_data(reply, &spnego)) {
+		ret = NT_STATUS_INVALID_PARAMETER;
+	} else {
+		mech->step = spnego_ntlmssp_verify_auth;
+	}
+
+	free_spnego_data(&spnego);
+out:
+	return ret;
+}
+
+static NTSTATUS spnego_ntlmssp_initial(SPNEGO_SEC_MECH *mech, DATA_BLOB *reply)
+{
+	NTLMSSP_CLIENT_STATE **ntlmssp_state = 
+		(NTLMSSP_CLIENT_STATE **)mech->state;
+
+	if (!NT_STATUS_IS_OK(ntlmssp_client_start(ntlmssp_state))) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	return ntlmssp_client_update(*ntlmssp_state, data_blob(0, 0),
+				     reply);
+}
+
+static NTSTATUS spnego_ntlmssp_hint(SPNEGO_SEC_MECH *unused, DATA_BLOB *reply)
+{
+	ASN1_DATA asn1;
+
+	ZERO_STRUCT(asn1);
+	asn1_push_tag(&asn1, ASN1_SEQUENCE(0));
+	asn1_push_tag(&asn1, ASN1_CONTEXT(0));
+	asn1_write_GeneralString(&asn1, "NONE");
+	asn1_pop_tag(&asn1);
+	asn1_pop_tag(&asn1);
+
+	*reply = data_blob(asn1.data, asn1.length);
+
+	asn1_free(&asn1);
+
+	return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static SPNEGO_SEC_MECH srv_builtin_mechs = {
+	OID_NTLMSSP,
+	NULL,
+	spnego_ntlmssp_hint,
+	spnego_ntlmssp_challenge,
+	spnego_ntlmssp_end,
+	NULL
+};
+
+static SPNEGO_SEC_MECH cli_builtin_mechs = {
+	OID_NTLMSSP,
+	NULL,
+	spnego_ntlmssp_initial,
+	spnego_ntlmssp_authenticate,
+	spnego_ntlmssp_end,
+	NULL
+};
+
+BOOL spnego_register_ntlmssp(SPNEGO_STATE *state)
+{
+	SPNEGO_SEC_MECH *mech = state->server ? 
+		talloc_memdup(state->mem_ctx, &srv_builtin_mechs, 
+			      sizeof(srv_builtin_mechs)):
+		talloc_memdup(state->mem_ctx, &cli_builtin_mechs, 
+			      sizeof(cli_builtin_mechs));
+
+	mech->next = state->mech_list;
+	state->mech_list = mech;
+
+	return True;
+}
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude='#*#' ../../samba-prestine/source/Makefile.in ./Makefile.in
--- ../../samba-prestine/source/Makefile.in	2003-08-01 09:47:37.000000000 -0500
+++ ./Makefile.in	2003-08-01 12:52:19.000000000 -0500
@@ -560,7 +560,8 @@ PROTO_OBJ = $(SMBD_OBJ_MAIN) \
 	    $(LIB_SMBD_OBJ) $(SAM_OBJ) $(REGISTRY_OBJ) $(POPT_LIB_OBJ) \
 	    $(RPC_LSA_OBJ) $(RPC_NETLOG_OBJ) $(RPC_SAMR_OBJ) $(RPC_REG_OBJ) \
 	    $(RPC_SVC_OBJ) $(RPC_WKS_OBJ) $(RPC_DFS_OBJ) $(RPC_SPOOLSS_OBJ) \
-	    $(RPC_ECHO_OBJ) $(SMBLDAP_OBJ) $(IDMAP_OBJ) libsmb/spnego.o
+	    $(RPC_ECHO_OBJ) $(SMBLDAP_OBJ) $(IDMAP_OBJ) libsmb/spnego.o \
+	    libsmb/spnego_ntlmssp.o
 
 WINBIND_WINS_NSS_OBJ = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) \
 	$(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
@@ -617,7 +618,7 @@ POPT_OBJS=popt/findme.o popt/popt.o popt
 TDBBACKUP_OBJ = tdb/tdbbackup.o tdb/tdbback.o $(TDBBASE_OBJ)
 
 NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
-		libsmb/asn1.o libsmb/spnego.o
+		libsmb/asn1.o libsmb/spnego.o libsmb/spnego_ntlmssp.o
 
 ######################################################################
 # now the rules...
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude='#*#' ../../samba-prestine/source/utils/ntlm_auth.c ./utils/ntlm_auth.c
--- ../../samba-prestine/source/utils/ntlm_auth.c	2003-08-01 02:59:23.000000000 -0500
+++ ./utils/ntlm_auth.c	2003-08-01 10:48:39.000000000 -0500
@@ -344,65 +344,20 @@ static void manage_squid_basic_request(e
 	}
 }
 
-static void offer_gss_spnego_mechs(void) {
-
-	DATA_BLOB token;
-	ASN1_DATA asn1;
-	SPNEGO_DATA spnego;
-	ssize_t len;
-	char *reply_base64;
-
-	ZERO_STRUCT(spnego);
-
-	/* Server negTokenInit (mech offerings) */
-	spnego.type = SPNEGO_NEG_TOKEN_INIT;
-	spnego.negTokenInit.mechTypes = smb_xmalloc(sizeof(char *) * 2);
-	spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
-	spnego.negTokenInit.mechTypes[1] = NULL;
-
-	ZERO_STRUCT(asn1);
-	asn1_push_tag(&asn1, ASN1_SEQUENCE(0));
-	asn1_push_tag(&asn1, ASN1_CONTEXT(0));
-	asn1_write_GeneralString(&asn1, "NONE");
-	asn1_pop_tag(&asn1);
-	asn1_pop_tag(&asn1);
-	spnego.negTokenInit.mechListMIC = data_blob(asn1.data, asn1.length);
-	asn1_free(&asn1);
-
-	len = write_spnego_data(&token, &spnego);
-	free_spnego_data(&spnego);
-
-	if (len == -1) {
-		DEBUG(1, ("Could not write SPNEGO data blob\n"));
-		x_fprintf(x_stdout, "BH\n");
-		return;
-	}
-
-	reply_base64 = base64_encode_data_blob(token);
-	x_fprintf(x_stdout, "TT %s *\n", reply_base64);
-
-	SAFE_FREE(reply_base64);
-	data_blob_free(&token);
-	DEBUG(10, ("sent SPNEGO negTokenInit\n"));
-	return;
-}
-
 static void manage_gss_spnego_request(enum squid_mode squid_mode,
 				      char *buf, int length) 
 {
-	static NTLMSSP_STATE *ntlmssp_state = NULL;
-	SPNEGO_DATA spnego;
-	DATA_BLOB request, token;
+	static SPNEGO_STATE *spnego_state = NULL;
+	DATA_BLOB request;
+	DATA_BLOB reply = data_blob(NULL, 0);
 	NTSTATUS status;
-	ssize_t len;
 
 	const char *reply_code;
 	char       *reply_base64;
 	pstring     reply_argument;
 
 	if (strlen(buf) < 2) {
-
-		if (ntlmssp_state != NULL) {
+		if (spnego_state != NULL) {
 			DEBUG(1, ("Request for initial SPNEGO request where "
 				  "we already have a state\n"));
 			x_fprintf(x_stdout, "BH\n");
@@ -413,147 +368,57 @@ static void manage_gss_spnego_request(en
 		x_fprintf(x_stdout, "BH\n");
 		return;
 	}
-
-	if ( (strlen(buf) == 2) && (strcmp(buf, "YR") == 0) ) {
-
-		/* Initial request, get the negTokenInit offering
-                   mechanisms */
-
-		offer_gss_spnego_mechs();
-		return;
-	}
-
-	/* All subsequent requests are "KK" (Knock, Knock ;)) and have
-	   a blob. This might be negTokenInit or negTokenTarg */
-
-	if ( (strlen(buf) <= 3) || (strncmp(buf, "KK", 2) != 0) ) {
+	if (!strncmp(buf, "YR", 2)) {
+		request = data_blob(NULL, 0);
+	} else if (strlen(buf) > 3 && !strncmp(buf, "KK", 2)) {
+		request = base64_decode_data_blob(buf + 3);
+	} else {
 		DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
 		x_fprintf(x_stdout, "BH\n");
 		return;
 	}
 
-	request = base64_decode_data_blob(buf + 3);
-	len = read_spnego_data(request, &spnego);
-	data_blob_free(&request);
-
-	if (len == -1) {
-		DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
-		x_fprintf(x_stdout, "BH\n");
-		return;
+	if (NULL == spnego_state) {
+		spnego_auth_start(&spnego_state, True);
+		spnego_register_ntlmssp(spnego_state);
 	}
 
-	if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
-
-		/* Second request from Client. This is where the
-		   client offers its mechanism to use. We currently
-		   only support NTLMSSP, the decision for Kerberos
-		   would be taken here. */
-
-		if ( (spnego.negTokenInit.mechTypes == NULL) ||
-		     (spnego.negTokenInit.mechTypes[0] == NULL) ) {
-			DEBUG(1, ("Client did not offer any mechanism"));
-			x_fprintf(x_stdout, "BH\n");
-			return;
-		}
-
-		if ( strcmp(spnego.negTokenInit.mechTypes[0], OID_NTLMSSP) != 0 ) {
-			DEBUG(1, ("Client did not choose NTLMSSP but %s\n",
-				  spnego.negTokenInit.mechTypes[0]));
-			x_fprintf(x_stdout, "BH\n");
-			return;
-		}
-
-		if ( spnego.negTokenInit.mechToken.data == NULL ) {
-			DEBUG(1, ("Client did not provide  NTLMSSP data\n"));
-			x_fprintf(x_stdout, "BH\n");
-			return;
-		}
-
-		if ( ntlmssp_state != NULL ) {
-			DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
-				  "already got one\n"));
-			x_fprintf(x_stdout, "BH\n");
-			ntlmssp_server_end(&ntlmssp_state);
-			return;
-		}
+	if (spnego_state->mech) {
+		NTLMSSP_STATE *ntlmssp_state;
 
-		ntlmssp_server_start(&ntlmssp_state);
+		ntlmssp_state = (NTLMSSP_STATE *)spnego_state->mech->state;
 		ntlmssp_state->check_password = winbind_pw_check;
 		ntlmssp_state->get_domain = get_winbind_domain;
 		ntlmssp_state->get_global_myname = get_winbind_netbios_name;
-
-		DEBUG(10, ("got NTLMSSP packet:\n"));
-		dump_data(10, spnego.negTokenInit.mechToken.data,
-			  spnego.negTokenInit.mechToken.length);
-
-		free_spnego_data(&spnego);
-
-		spnego.type = SPNEGO_NEG_TOKEN_TARG;
-		spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
-		spnego.negTokenTarg.supportedMech = strdup(OID_NTLMSSP);
-
-		status = ntlmssp_server_update(ntlmssp_state,
-					       spnego.negTokenInit.mechToken,
-					       &spnego.negTokenTarg.responseToken);
-
-	} else {
-
-		/* spnego.type == SPNEGO_NEG_TOKEN_TARG */
-
-		DATA_BLOB response;
-
-		if (spnego.negTokenTarg.responseToken.data == NULL) {
-			DEBUG(1, ("Got a negTokenArg without a responseToken!\n"));
-			x_fprintf(x_stdout, "BH\n");
-			return;
-		}
-
-		status = ntlmssp_server_update(ntlmssp_state,
-					       spnego.negTokenTarg.responseToken,
-					       &response);
-
-		data_blob_free(&spnego.negTokenTarg.responseToken);
-
-		spnego.negTokenTarg.responseToken = response;
-
 	}
 
-	if (NT_STATUS_IS_OK(status)) {
-		spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
+	status = spnego_auth_update(spnego_state, request, &reply);
+	data_blob_free(&request);
+
+       	if (NT_STATUS_IS_OK(status)) {
+		NTLMSSP_STATE *ntlmssp_state;
+		ntlmssp_state = (NTLMSSP_STATE *)spnego_state->mech->state;
 		reply_code = "AF";
 		pstr_sprintf(reply_argument, "%s\\%s",
 			     ntlmssp_state->domain, ntlmssp_state->user);
+		spnego_auth_end(&spnego_state);
 	} else if (NT_STATUS_EQUAL(status,
 				   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
 		reply_code = "TT";
 		pstr_sprintf(reply_argument, "*");
 	} else {
-		spnego.negTokenTarg.negResult = SPNEGO_REJECT;
 		reply_code = "NA";
 		pstrcpy(reply_argument, nt_errstr(status));
+		spnego_auth_end(&spnego_state);
 	}
 
-	len = write_spnego_data(&token, &spnego);
-	free_spnego_data(&spnego);
-
-	if (len == -1) {
-		DEBUG(1, ("Could not write SPNEGO data blob\n"));
-		x_fprintf(x_stdout, "BH\n");
-		return;
-	}
-
-	reply_base64 = base64_encode_data_blob(token);
+	reply_base64 = base64_encode_data_blob(reply);
+	data_blob_free(&reply);
 
 	x_fprintf(x_stdout, "%s %s %s\n",
 		  reply_code, reply_base64, reply_argument);
 
 	SAFE_FREE(reply_base64);
-	data_blob_free(&token);
-
-	if (NT_STATUS_IS_OK(status)) {
-		ntlmssp_server_end(&ntlmssp_state);
-	}
 
 	return;
 }


More information about the samba-technical mailing list