[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