[PATCH] spnego_auth (attachment)
Anthony Liguori
aliguor at us.ibm.com
Fri Jul 25 19:16:39 GMT 2003
My trigger finger was a little too quick apparently...
diff -ruN samba-orig/source/include/includes.h
samba/source/include/includes.h
--- samba-orig/source/include/includes.h 2003-07-25
14:02:55.000000000 -0500
+++ samba/source/include/includes.h 2003-07-25 14:03:22.000000000
-0500
@@ -835,6 +835,8 @@
#include "nsswitch/winbind_client.h"
+#include "spnego.h"
+
/*
* Type for wide character dirent structure.
* Only d_name is defined by POSIX.
diff -ruN samba-orig/source/include/spnego.h samba/source/include/spnego.h
--- samba-orig/source/include/spnego.h 1969-12-31 18:00:00.000000000
-0600
+++ samba/source/include/spnego.h 2003-07-25 14:04:04.000000000
-0500
@@ -0,0 +1,65 @@
+/*
+ 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.
+*/
+
+#ifndef SAMBA_SPNEGO_H
+#define SAMBA_SPNEGO_H
+
+#define SPNEGO_DELEG_FLAG 0x01
+#define SPNEGO_MUTUAL_FLAG 0x02
+#define SPNEGO_REPLAY_FLAG 0x04
+#define SPNEGO_SEQUENCE_FLAG 0x08
+#define SPNEGO_ANON_FLAG 0x10
+#define SPNEGO_CONF_FLAG 0x20
+#define SPNEGO_INTEG_FLAG 0x40
+#define SPNEGO_REQ_FLAG 0x80
+
+#define SPNEGO_NEG_TOKEN_INIT 0
+#define SPNEGO_NEG_TOKEN_TARG 1
+
+typedef enum _spnego_negResult {
+ SPNEGO_ACCEPT_COMPLETED = 0,
+ SPNEGO_ACCEPT_INCOMPLETE = 1,
+ SPNEGO_REJECT = 2
+} negResult_t;
+
+typedef struct spnego_negTokenInit {
+ char **mechTypes;
+ int reqFlags;
+ DATA_BLOB mechToken;
+ DATA_BLOB mechListMIC;
+} negTokenInit_t;
+
+typedef struct spnego_negTokenTarg {
+ uint8 negResult;
+ char *supportedMech;
+ DATA_BLOB responseToken;
+ DATA_BLOB mechListMIC;
+} negTokenTarg_t;
+
+typedef struct spnego_spnego {
+ int type;
+ negTokenInit_t negTokenInit;
+ negTokenTarg_t negTokenTarg;
+} SPNEGO_DATA;
+
+#endif
diff -ruN samba-orig/source/libsmb/spnego.c samba/source/libsmb/spnego.c
--- samba-orig/source/libsmb/spnego.c 1969-12-31 18:00:00.000000000
-0600
+++ samba/source/libsmb/spnego.c 2003-07-25 14:03:45.000000000
-0500
@@ -0,0 +1,280 @@
+/*
+ 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
+
+static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
+{
+ ZERO_STRUCTP(token);
+
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ int i;
+
+ switch (asn1->data[asn1->ofs]) {
+ /* Read mechTypes */
+ case ASN1_CONTEXT(0):
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ token->mechTypes =
malloc(sizeof(*token->mechTypes));
+ for (i = 0; !asn1->has_error &&
+ 0 < asn1_tag_remaining(asn1); i++) {
+ token->mechTypes =
+ realloc(token->mechTypes, (i + 1)
*
+ sizeof(*token->mechTypes));
+ asn1_read_OID(asn1, token->mechTypes + i);
+ }
+ token->mechTypes[i] = NULL;
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ /* Read reqFlags */
+ case ASN1_CONTEXT(1):
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_read_Integer(asn1, &token->reqFlags);
+ token->reqFlags |= SPNEGO_REQ_FLAG;
+ asn1_end_tag(asn1);
+ break;
+ /* Read mechToken */
+ case ASN1_CONTEXT(2):
+ asn1_start_tag(asn1, ASN1_CONTEXT(2));
+ asn1_read_OctetString(asn1, &token->mechToken);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(3):
+ asn1_start_tag(asn1, ASN1_CONTEXT(3));
+ asn1_read_OctetString(asn1, &token->mechListMIC);
+ asn1_end_tag(asn1);
+ break;
+ default:
+ asn1->has_error = True;
+ break;
+ }
+ }
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
+{
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+
+ /* Write mechTypes */
+ if (token->mechTypes && *token->mechTypes) {
+ int i;
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+ for (i = 0; token->mechTypes[i]; i++) {
+ asn1_write_OID(asn1, token->mechTypes[i]);
+ }
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write reqFlags */
+ if (token->reqFlags & SPNEGO_REQ_FLAG) {
+ int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_write_Integer(asn1, flags);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write mechToken */
+ if (token->mechToken.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(2));
+ asn1_write_OctetString(asn1, token->mechToken.data,
+ token->mechToken.length);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write mechListMIC */
+ if (token->mechListMIC.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(2));
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+ asn1_pop_tag(asn1);
+ }
+
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
+{
+ ZERO_STRUCTP(token);
+
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ switch (asn1->data[asn1->ofs]) {
+ case ASN1_CONTEXT(0):
+ /* this is listed as being non-optional by RFC2478
but
+ Windows doesn't always send it... */
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_ENUMERATED);
+ asn1_read_uint8(asn1, &token->negResult);
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(1):
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_read_OID(asn1, &token->supportedMech);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(2):
+ asn1_start_tag(asn1, ASN1_CONTEXT(2));
+ asn1_read_OctetString(asn1,
&token->responseToken);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(3):
+ asn1_start_tag(asn1, ASN1_CONTEXT(3));
+ asn1_read_OctetString(asn1, &token->mechListMIC);
+ asn1_end_tag(asn1);
+ break;
+ default:
+ asn1->has_error = True;
+ break;
+ }
+ }
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
+{
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_write_enumerated(asn1, token->negResult);
+ asn1_pop_tag(asn1);
+
+ if (token->supportedMech) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_write_OID(asn1, token->supportedMech);
+ asn1_pop_tag(asn1);
+ }
+
+ if (token->responseToken.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(2));
+ asn1_write_OctetString(asn1, token->responseToken.data,
+ token->responseToken.length);
+ asn1_pop_tag(asn1);
+ }
+
+ if (token->mechListMIC.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(3));
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+ asn1_pop_tag(asn1);
+ }
+
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
+{
+ ASN1_DATA asn1;
+ ssize_t ret = -1;
+
+ ZERO_STRUCTP(token);
+ ZERO_STRUCT(asn1);
+ asn1_load(&asn1, data);
+
+ switch (asn1.data[asn1.ofs]) {
+ case ASN1_APPLICATION(0):
+ asn1_start_tag(&asn1, ASN1_APPLICATION(0));
+ asn1_check_OID(&asn1, OID_SPNEGO);
+ if (read_negTokenInit(&asn1, &token->negTokenInit)) {
+ token->type = SPNEGO_NEG_TOKEN_INIT;
+ }
+ asn1_end_tag(&asn1);
+ break;
+ case ASN1_CONTEXT(1):
+ if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
+ token->type = SPNEGO_NEG_TOKEN_TARG;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!asn1.has_error) ret = asn1.ofs;
+ asn1_free(&asn1);
+
+ return ret;
+}
+
+ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
+{
+ ASN1_DATA asn1;
+ ssize_t ret = -1;
+
+ ZERO_STRUCT(asn1);
+
+ switch (spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ asn1_push_tag(&asn1, ASN1_APPLICATION(0));
+ asn1_write_OID(&asn1, OID_SPNEGO);
+ write_negTokenInit(&asn1, &spnego->negTokenInit);
+ asn1_pop_tag(&asn1);
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ write_negTokenTarg(&asn1, &spnego->negTokenTarg);
+ break;
+ default:
+ asn1.has_error = True;
+ break;
+ }
+
+ if (!asn1.has_error) {
+ *blob = data_blob(asn1.data, asn1.length);
+ ret = asn1.ofs;
+ }
+ asn1_free(&asn1);
+
+ return ret;
+}
+
diff -ruN samba-orig/source/Makefile.in samba/source/Makefile.in
--- samba-orig/source/Makefile.in 2003-07-25 14:02:55.000000000
-0500
+++ samba/source/Makefile.in 2003-07-25 14:03:22.000000000 -0500
@@ -127,7 +127,7 @@
bin/nmblookup at EXEEXT@ bin/pdbedit at EXEEXT@
BIN_PROGS3 = bin/smbpasswd at EXEEXT@ bin/rpcclient at EXEEXT@
bin/smbcacls at EXEEXT@ \
bin/profiles at EXEEXT@ bin/ntlm_auth at EXEEXT@ \
- bin/smbcquotas at EXEEXT@
+ bin/smbcquotas at EXEEXT@ bin/spnego_auth at EXEEXT@
# editreg removed from standard build until it is portable. It needs a
major rewrite to
# achieve this (tridge)
@@ -208,10 +208,10 @@
LIBNMB_OBJ = libsmb/unexpected.o libsmb/namecache.o libsmb/nmblib.o \
libsmb/namequery.o libsmb/conncache.o
-LIBSAMBA_OBJ = libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o
libsmb/ntlmssp.o libsmb/ntlmssp_parse.o libsmb/ntlmssp_sign.o
+LIBSAMBA_OBJ = libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o
libsmb/ntlmssp.o libsmb/ntlmssp_parse.o libsmb/ntlmssp_sign.o
libsmb/asn1.o
LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
- libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
+ libsmb/clikrb5.o libsmb/clispnego.o \
libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \
libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \
libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \
@@ -559,7 +559,7 @@
$(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)
+ $(RPC_ECHO_OBJ) $(SMBLDAP_OBJ) $(IDMAP_OBJ) libsmb/spnego.o
WINBIND_WINS_NSS_OBJ = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) \
$(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
@@ -616,6 +616,8 @@
TDBBACKUP_OBJ = tdb/tdbbackup.o tdb/tdbback.o $(TDBBASE_OBJ)
NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ)
+SPNEGO_AUTH_OBJ = utils/spnego_auth.o libsmb/spnego.c $(LIBSAMBA_OBJ) \
+ $(POPT_LIB_OBJ)
######################################################################
# now the rules...
@@ -1067,6 +1069,12 @@
@$(LINK) -o $@ $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
$(UBIQX_OBJ) $(LIBS) @POPTLIBS@
+bin/spnego_auth at EXEEXT@: $(SPNEGO_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
+ $(UBIQX_OBJ) @BUILD_POPT@ bin/.dummy
+ @echo Linking $@
+ @$(LINK) -o $@ $(SPNEGO_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
+ $(UBIQX_OBJ) $(LIBS) @POPTLIBS@
+
bin/pam_smbpass. at SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ)
@echo "Linking shared library $@"
@$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_SMBPASS_PICOOBJ) -lpam $(DYNEXP)
$(LIBS) -lc
diff -ruN samba-orig/source/utils/spnego_auth.c
samba/source/utils/spnego_auth.c
--- samba-orig/source/utils/spnego_auth.c 1969-12-31
18:00:00.000000000 -0600
+++ samba/source/utils/spnego_auth.c 2003-07-25 14:03:52.000000000
-0500
@@ -0,0 +1,254 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SPNEGO Authentication Interface
+
+ 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
+
+struct spnego_auth_opts {
+ XFILE *out;
+ XFILE *in;
+ int use_krb5;
+ int use_ntlmssp;
+ int use_hex;
+};
+
+static void spnego_auth_write(struct spnego_auth_opts *opts,
+ const char *data, size_t len)
+{
+ if (opts->use_hex) {
+ char *data_hex = 0;
+
+ hex_encode(data, len, &data_hex);
+ x_fprintf(opts->out, "%s\n", data_hex);
+ SAFE_FREE(data_hex);
+ } else {
+ printf("writing %p of %d byte(s)\n", data, len);
+ x_fwrite(data, len, 1, opts->out);
+ }
+
+ x_fflush(opts->out);
+}
+
+static DATA_BLOB spnego_auth_read(struct spnego_auth_opts *opts)
+{
+ DATA_BLOB ret = data_blob(NULL, 4096);
+
+ if (NULL == x_fgets(ret.data, ret.length, opts->in)) {
+ data_blob_free(&ret);
+ ret = data_blob(NULL, 0);
+ } else {
+ DATA_BLOB data = data_blob(NULL, (strlen(ret.data) >> 1) +
1);
+
+ strhex_to_str(data.data, ret.length, ret.data);
+ data_blob_free(&ret);
+ ret = data;
+ }
+
+ return ret;
+}
+
+static NTSTATUS spnego_auth_check_password(NTLMSSP_STATE *ntlmssp_state)
+{
+ struct spnego_auth_opts opts = {
+ x_stdout,
+ x_stdin,
+ True, /* krb5 */
+ True, /* ntlmssp */
+ True /* hex */
+ };
+
+ printf("Password check for %s@%s.%s\n", ntlmssp_state->user,
+ ntlmssp_state->workstation, ntlmssp_state->domain);
+ if (ntlmssp_state->lm_resp.data) {
+ printf("LM Hash:\n");
+ spnego_auth_write(&opts, ntlmssp_state->lm_resp.data,
+ ntlmssp_state->lm_resp.length);
+ }
+ if (ntlmssp_state->nt_resp.data) {
+ printf("NT Hash:\n");
+ spnego_auth_write(&opts, ntlmssp_state->nt_resp.data,
+ ntlmssp_state->nt_resp.length);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static BOOL negotiate_ntlmssp(struct spnego_auth_opts *opts)
+{
+ DATA_BLOB token;
+ SPNEGO_DATA spnego;
+ ssize_t len;
+ char *OIDs[] = {OID_NTLMSSP, NULL};
+ ASN1_DATA asn1;
+ BOOL ret = False;
+ NTLMSSP_STATE *ntlmssp_state = 0;
+ NTSTATUS status;
+
+ ZERO_STRUCT(asn1);
+
+ /* Server negTokenInit (mech offerings) */
+ ZERO_STRUCT(spnego);
+ spnego.type = SPNEGO_NEG_TOKEN_INIT;
+ spnego.negTokenInit.mechTypes = OIDs;
+ 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);
+
+ if (-1 == (len = write_spnego_data(&token, &spnego))) goto out;
+ spnego_auth_write(opts, token.data, token.length);
+ data_blob_free(&token);
+
+ /* NTLMSSP_NEGOTIATE */
+ ZERO_STRUCT(spnego);
+ token = spnego_auth_read(opts);
+ len = read_spnego_data(token, &spnego);
+ if (-1 == len ||
+ SPNEGO_NEG_TOKEN_INIT != spnego.type ||
+ !spnego.negTokenInit.mechTypes ||
+ !spnego.negTokenInit.mechTypes[0] ||
+ strcmp(spnego.negTokenInit.mechTypes[0], OID_NTLMSSP) ||
+ !spnego.negTokenInit.mechToken.data) {
+ goto out;
+ }
+
+ status = ntlmssp_server_start(&ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s:%d:%s\n", __FILE__, __LINE__,
nt_errstr(status));
+ goto out;
+ }
+
+ ntlmssp_state->check_password = spnego_auth_check_password;
+
+ /* NTLMSSP_CHALLENGE */
+ spnego.type = SPNEGO_NEG_TOKEN_TARG;
+ spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ spnego.negTokenTarg.supportedMech = OID_NTLMSSP;
+ status = ntlmssp_server_update(ntlmssp_state,
+ spnego.negTokenInit.mechToken,
+ &spnego.negTokenTarg.responseToken);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
{
+ printf("%s:%d:%s\n", __FILE__, __LINE__,
nt_errstr(status));
+ goto out;
+ }
+
+ if (-1 == (len = write_spnego_data(&token, &spnego))) goto out;
+ spnego_auth_write(opts, token.data, token.length);
+ data_blob_free(&token);
+
+ /* NTLMSSP_AUTH */
+ ZERO_STRUCT(spnego);
+ token = spnego_auth_read(opts);
+ len = read_spnego_data(token, &spnego);
+ if (-1 == len ||
+ SPNEGO_NEG_TOKEN_TARG != spnego.type ||
+ !spnego.negTokenTarg.responseToken.data) {
+ goto out;
+ }
+
+ status = ntlmssp_server_update(ntlmssp_state,
+ spnego.negTokenTarg.responseToken,
+ &token);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s:%d:%s\n", __FILE__, __LINE__,
nt_errstr(status));
+ goto out;
+ }
+
+ ntlmssp_server_end(&ntlmssp_state);
+
+ ret = True;
+
+out:
+ /* Server Response */
+ ZERO_STRUCT(spnego);
+ spnego.type = SPNEGO_NEG_TOKEN_TARG;
+ spnego.negTokenTarg.negResult =
+ ret ? SPNEGO_ACCEPT_COMPLETED : SPNEGO_REJECT;
+
+ if (-1 != (len = write_spnego_data(&token, &spnego))) {
+ spnego_auth_write(opts, token.data, token.length);
+ data_blob_free(&token);
+ }
+
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ int ret = 0;
+ struct spnego_auth_opts opts = {
+ x_stdout,
+ x_stdin,
+ True, /* krb5 */
+ True, /* ntlmssp */
+ True /* hex */
+ };
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+#if 0
+ { "display-hex", 'x', POPT_ARG_NONE, &opts.use_hex, 'x',
+ "display output as hex"},
+#endif
+ { "no-krb5", 0, POPT_ARG_NONE, 0, 'n',
+ "disable kerberos negotiation"},
+ { "force-krb5", 'k', POPT_ARG_NONE, 0, 'k',
+ "force kerberos negotiation"},
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ int opt;
+
+ pc = poptGetContext("spnego_auth", argc, argv, long_options, 0);
+
+ while (-1 != (opt = poptGetNextOpt(pc))) {
+ switch(opt) {
+ case 'n':
+ opts.use_krb5 = 0;
+ opts.use_ntlmssp = 1;
+ break;
+ case 'k':
+ opts.use_krb5 = 1;
+ opts.use_ntlmssp = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
+ ret = 1;
+ goto out;
+ }
+
+ negotiate_ntlmssp(&opts);
+out:
+ poptFreeContext(pc);
+ return ret;
+}
+
Anthony Liguori
Linux/Active Directory Interoperability
Linux Technology Center (LTC) - IBM Austin
E-mail: aliguor at us.ibm.com
Phone: (512) 838-1208
Tie Line: 678-1208
----- Forwarded by Anthony Liguori/Austin/IBM on 25/07/2003 02:16 PM -----
Anthony Liguori
25/07/2003 02:15 PM
To: samba-technical at lists.samba.org
cc: Jim McDonough/Portland/IBM at IBMUS, Andrew Bartlett <abartlet at samba.org>,
Volker Lendecke <Volker.Lendecke at SerNet.DE>
From: Anthony Liguori/Austin/IBM at IBMUS
Subject: [PATCH] spnego_auth
All,
In our quest for the elusive AD domain controller, we came across the need
to implement a GSS-SPNEGO sasl plugin.
Here's a first attempt at a spnego_auth helper program that will allow
SPNEGO negotiations to occur over stdout/stdin. This probably isn't very
useful to anything else right now but it might make sense to perhaps add
spnego support to ntlm_auth or something to combine the two.
At any rate, you'll notice that I wrote a small SPNEGO lib. The
libsmb/clispnego.c isn't very useful outside of smbd and it doesn't have
full coverage of SPNEGO. If there's interested, perhaps when HEAD gets
into order I could begin porting smbd to use these SPNEGO routines...
Anthony Liguori
Linux/Active Directory Interoperability
Linux Technology Center (LTC) - IBM Austin
E-mail: aliguor at us.ibm.com
Phone: (512) 838-1208
Tie Line: 678-1208
More information about the samba-technical
mailing list