mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
This adds gss-spnego to ntlm_auth. It contains some new spnego support
from Jim McDonough. It is to enable cyrus sasl to provide the gss-spnego support. For a preliminary patch to cyrus sasl see http://samba.sernet.de/cyrus-gss-spnego.diff Volker
This commit is contained in:
parent
a4e342c20c
commit
45cef8f66e
@ -615,7 +615,8 @@ POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
|
||||
TDBBACKUP_OBJ = tdb/tdbbackup.o tdb/tdbback.o $(TDBBASE_OBJ)
|
||||
|
||||
NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ)
|
||||
NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
|
||||
libsmb/asn1.o libsmb/spnego.o
|
||||
|
||||
######################################################################
|
||||
# now the rules...
|
||||
|
@ -835,6 +835,8 @@ extern int errno;
|
||||
|
||||
#include "nsswitch/winbind_client.h"
|
||||
|
||||
#include "spnego.h"
|
||||
|
||||
/*
|
||||
* Type for wide character dirent structure.
|
||||
* Only d_name is defined by POSIX.
|
||||
|
65
source/include/spnego.h
Normal file
65
source/include/spnego.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
RFC2478 Compliant SPNEGO implementation
|
||||
|
||||
Copyright (C) Jim McDonough <jmcd@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
|
292
source/libsmb/spnego.c
Normal file
292
source/libsmb/spnego.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
RFC2478 Compliant SPNEGO implementation
|
||||
|
||||
Copyright (C) Jim McDonough <jmcd@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;
|
||||
/* Read mecListMIC */
|
||||
case ASN1_CONTEXT(3):
|
||||
asn1_start_tag(asn1, ASN1_CONTEXT(3));
|
||||
if (!asn1_read_OctetString(asn1, &token->mechListMIC)) {
|
||||
char *mechListMIC;
|
||||
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
|
||||
asn1_push_tag(asn1, ASN1_CONTEXT(0));
|
||||
asn1_read_GeneralString(asn1, &mechListMIC);
|
||||
asn1_pop_tag(asn1);
|
||||
asn1_pop_tag(asn1);
|
||||
|
||||
token->mechListMIC =
|
||||
data_blob(mechListMIC, strlen(mechListMIC));
|
||||
SAFE_FREE(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(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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
enum squid_mode {
|
||||
SQUID_2_4_BASIC,
|
||||
SQUID_2_5_BASIC,
|
||||
SQUID_2_5_NTLMSSP
|
||||
SQUID_2_5_NTLMSSP,
|
||||
GSS_SPNEGO
|
||||
};
|
||||
|
||||
|
||||
@ -342,6 +343,225 @@ static void manage_squid_basic_request(enum squid_mode squid_mode,
|
||||
}
|
||||
}
|
||||
|
||||
static void offer_gss_spnego_mechs(void) {
|
||||
|
||||
DATA_BLOB token;
|
||||
ASN1_DATA asn1;
|
||||
SPNEGO_DATA spnego;
|
||||
const char *OIDs[] = {OID_NTLMSSP, NULL};
|
||||
ssize_t len;
|
||||
char *reply_base64;
|
||||
|
||||
/* Server negTokenInit (mech offerings) */
|
||||
ZERO_STRUCT(spnego);
|
||||
spnego.type = SPNEGO_NEG_TOKEN_INIT;
|
||||
spnego.negTokenInit.mechTypes = OIDs;
|
||||
|
||||
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);
|
||||
data_blob_free(&spnego.negTokenInit.mechListMIC);
|
||||
|
||||
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;
|
||||
NTSTATUS status;
|
||||
char *reply_base64;
|
||||
pstring reply;
|
||||
ssize_t len;
|
||||
|
||||
if (strlen(buf) < 2) {
|
||||
|
||||
if (ntlmssp_state != NULL) {
|
||||
DEBUG(1, ("Request for initial SPNEGO request where "
|
||||
"we already have a state\n"));
|
||||
x_fprintf(x_stdout, "BH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
|
||||
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) ) {
|
||||
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);
|
||||
|
||||
if (len == -1) {
|
||||
DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
|
||||
x_fprintf(x_stdout, "BH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (spnego.type != SPNEGO_NEG_TOKEN_INIT) &&
|
||||
(spnego.type != SPNEGO_NEG_TOKEN_TARG) ) {
|
||||
|
||||
DEBUG(1, ("Got an invalid SPNEGO token!\n"));
|
||||
x_fprintf(x_stdout, "BH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ntlmssp_server_start(&ntlmssp_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);
|
||||
|
||||
ZERO_STRUCT(spnego);
|
||||
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);
|
||||
|
||||
} 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) &&
|
||||
!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ) {
|
||||
|
||||
/* Neither ok nor more work to do, so reject */
|
||||
|
||||
x_fprintf(x_stdout, "NA %s\n", nt_errstr(status));
|
||||
DEBUG(10, ("NTLMSSP %s\n", nt_errstr(status)));
|
||||
return;
|
||||
}
|
||||
|
||||
pstr_sprintf(reply, "TT");
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
pstr_sprintf(reply, "AF %s\\%s",
|
||||
ntlmssp_state->domain, ntlmssp_state->user);
|
||||
|
||||
spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
|
||||
|
||||
DEBUG(10, ("NTLMSSP OK!\n"));
|
||||
}
|
||||
|
||||
len = write_spnego_data(&token, &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, "%s %s\n", reply, reply_base64);
|
||||
SAFE_FREE(reply_base64);
|
||||
data_blob_free(&token);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
ntlmssp_server_end(&ntlmssp_state);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void manage_squid_request(enum squid_mode squid_mode)
|
||||
{
|
||||
char buf[SQUID_BUFFER_SIZE+1];
|
||||
@ -383,6 +603,8 @@ static void manage_squid_request(enum squid_mode squid_mode)
|
||||
manage_squid_basic_request(squid_mode, buf, length);
|
||||
} else if (squid_mode == SQUID_2_5_NTLMSSP) {
|
||||
manage_squid_ntlmssp_request(squid_mode, buf, length);
|
||||
} else if (squid_mode == GSS_SPNEGO) {
|
||||
manage_gss_spnego_request(squid_mode, buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1334,6 +1556,8 @@ enum {
|
||||
squid_stream(SQUID_2_5_BASIC);
|
||||
} else if (strcmp(helper_protocol, "squid-2.4-basic")== 0) {
|
||||
squid_stream(SQUID_2_4_BASIC);
|
||||
} else if (strcmp(helper_protocol, "gss-spnego")== 0) {
|
||||
squid_stream(GSS_SPNEGO);
|
||||
} else {
|
||||
x_fprintf(x_stderr, "unknown helper protocol [%s]\n", helper_protocol);
|
||||
exit(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user