diff options
-rw-r--r-- | config.hw.in | 2 | ||||
-rw-r--r-- | neon.mak | 3 | ||||
-rw-r--r-- | src/ne_auth.c | 114 | ||||
-rw-r--r-- | src/ne_socket.c | 15 | ||||
-rw-r--r-- | src/ne_sspi.c | 546 | ||||
-rw-r--r-- | src/ne_sspi.h | 48 |
6 files changed, 723 insertions, 5 deletions
diff --git a/config.hw.in b/config.hw.in index 5a5fe1b..7813889 100644 --- a/config.hw.in +++ b/config.hw.in @@ -37,6 +37,8 @@ #define HAVE_MEMCPY #define HAVE_SETSOCKOPT +#define HAVE_SSPI + #define NE_FMT_SIZE_T "u" #define NE_FMT_SSIZE_T "d" #define NE_FMT_OFF_T "ld" @@ -115,6 +115,7 @@ LIB32_OBJS= \ "$(INTDIR)\ne_request.obj" \ "$(INTDIR)\ne_session.obj" \ "$(INTDIR)\ne_socket.obj" \ + "$(INTDIR)\ne_sspi.obj" \ "$(INTDIR)\ne_string.obj" \ "$(INTDIR)\ne_uri.obj" \ "$(INTDIR)\ne_utils.obj" @@ -169,6 +170,7 @@ CLEAN: $(ZLIB_CLEAN) -@erase "$(INTDIR)\ne_openssl.obj" -@erase "$(INTDIR)\ne_stubssl.obj" -@erase "$(INTDIR)\ne_socket.obj" + -@erase "$(INTDIR)\ne_sspi.obj" -@erase "$(INTDIR)\ne_string.obj" -@erase "$(INTDIR)\ne_uri.obj" -@erase "$(INTDIR)\ne_utils.obj" @@ -214,6 +216,7 @@ CLEAN: $(ZLIB_CLEAN) "$(INTDIR)\ne_openssl.obj": .\src\ne_openssl.c "$(INTDIR)\ne_stubssl.obj": .\src\ne_stubssl.c "$(INTDIR)\ne_socket.obj": .\src\ne_socket.c +"$(INTDIR)\ne_sspi.obj": .\src\ne_sspi.c "$(INTDIR)\ne_string.obj": .\src\ne_string.c "$(INTDIR)\ne_uri.obj": .\src\ne_uri.c "$(INTDIR)\ne_utils.obj": .\src\ne_utils.c diff --git a/src/ne_auth.c b/src/ne_auth.c index 8cf7ea9..659ab5f 100644 --- a/src/ne_auth.c +++ b/src/ne_auth.c @@ -1,6 +1,6 @@ /* HTTP Authentication routines - Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk> + Copyright (C) 1999-2005, Joe Orton <joe@manyfish.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -77,6 +77,10 @@ #endif #endif +#ifdef HAVE_SSPI +#include "ne_sspi.h" +#endif + /* TODO: should remove this eventually. Need it for * ne_pull_request_body. */ #include "ne_private.h" @@ -88,7 +92,9 @@ typedef enum { auth_scheme_basic, auth_scheme_digest, - auth_scheme_gssapi + auth_scheme_gssapi, + auth_scheme_sspi_negotiate, + auth_scheme_sspi_ntlm } auth_scheme; typedef enum { @@ -167,6 +173,11 @@ typedef struct { gss_name_t gssname; gss_OID gssmech; #endif +#ifdef HAVE_SSPI + /* This is used for SSPI (Negotiate/NTLM) auth */ + char *sspi_token; + void *sspi_context; +#endif /* These all used for Digest auth */ char *realm; char *nonce; @@ -227,6 +238,11 @@ static void clean_session(auth_session *sess) } NE_FREE(sess->gssapi_token); #endif +#ifdef HAVE_SSPI + NE_FREE(sess->sspi_token); + ne_sspi_destroy_context(sess->sspi_context); + sess->sspi_context = NULL; +#endif } /* Returns client nonce string. */ @@ -491,6 +507,53 @@ static int verify_negotiate_response(auth_session *sess, char *hdr) } #endif +#ifdef HAVE_SSPI +static char *request_sspi(auth_session *sess) +{ + const char *mechanism; + + if (ne_sspi_get_mechanism(sess->sspi_context, &mechanism)) { + return NULL; + } + + return ne_concat(mechanism, " ", sess->sspi_token, "\r\n", NULL); +} + +static int sspi_challenge(auth_session *sess, struct auth_challenge *parms, + int ntlm) +{ + int status; + char *response = NULL; + + NE_DEBUG(NE_DBG_HTTPAUTH, "auth: SSPI challenge.\n"); + + if (!sess->sspi_context) { + status = ne_sspi_create_context(&sess->sspi_context, + sess->sess->server.hostname, ntlm); + if (status) { + return status; + } + } + + status = ne_sspi_authenticate(sess->sspi_context, parms->opaque, &response); + if (status) { + return status; + } + + sess->sspi_token = response; + + NE_DEBUG(NE_DBG_HTTPAUTH, "auth: SSPI challenge [%s]\n", sess->sspi_token); + + if (ntlm) { + sess->scheme = auth_scheme_sspi_ntlm; + } else { + sess->scheme = auth_scheme_sspi_negotiate; + } + + return 0; +} +#endif + /* Examine a digest challenge: return 0 if it is a valid Digest challenge, * else non-zero. */ static int digest_challenge(auth_session *sess, struct auth_challenge *parms) @@ -963,6 +1026,14 @@ static int auth_challenge(auth_session *sess, const char *value) else if (strcasecmp(key, "negotiate") == 0) { scheme = auth_scheme_gssapi; } +#else +#ifdef HAVE_SSPI + else if (strcasecmp(key, "negotiate") == 0) { + scheme = auth_scheme_sspi_negotiate; + } else if (strcasecmp(key, "ntlm") == 0) { + scheme = auth_scheme_sspi_ntlm; + } +#endif #endif else { NE_DEBUG(NE_DBG_HTTPAUTH, "Ignoring challenge '%s'.\n", key); @@ -976,7 +1047,10 @@ static int auth_challenge(auth_session *sess, const char *value) chall->next = challenges; challenges = chall; - if (scheme == auth_scheme_gssapi && sep == ' ') { + if (sep == ' ' && + (scheme == auth_scheme_gssapi + || scheme == auth_scheme_sspi_negotiate + || scheme == auth_scheme_sspi_ntlm) ) { /* Cope with the fact that the unquoted base64 * paramater token doesn't match the 2617 auth-param * grammar: */ @@ -1057,6 +1131,32 @@ static int auth_challenge(auth_session *sess, const char *value) } #endif +#ifdef HAVE_SSPI + if (!success) { + NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/Negotiate.\n"); + for (chall = challenges; chall != NULL; chall = chall->next) { + if (chall->scheme == auth_scheme_sspi_negotiate) { + if (!sspi_challenge(sess, chall, 0)) { + success = 1; + break; + } + } + } + } + + if (!success) { + NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/NTLM.\n"); + for (chall = challenges; chall != NULL; chall = chall->next) { + if (chall->scheme == auth_scheme_sspi_ntlm) { + if (!sspi_challenge(sess, chall, 1)) { + success = 1; + break; + } + } + } + } +#endif + /* Try a digest challenge */ if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n"); @@ -1170,7 +1270,13 @@ static void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request) value = request_gssapi(sess); break; #endif - default: +#ifdef HAVE_SSPI + case auth_scheme_sspi_negotiate: + case auth_scheme_sspi_ntlm: + value = request_sspi(sess); + break; +#endif + default: value = NULL; break; } diff --git a/src/ne_socket.c b/src/ne_socket.c index 2ab3b61..2a0b865 100644 --- a/src/ne_socket.c +++ b/src/ne_socket.c @@ -1,6 +1,6 @@ /* Socket handling routines - Copyright (C) 1998-2004, Joe Orton <joe@manyfish.co.uk>, + Copyright (C) 1998-2005, Joe Orton <joe@manyfish.co.uk>, Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi> Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org> @@ -134,6 +134,7 @@ typedef struct in_addr ne_inet_addr; #include "ne_string.h" #include "ne_socket.h" #include "ne_alloc.h" +#include "ne_sspi.h" #if defined(__BEOS__) && !defined(BONE_VERSION) /* pre-BONE */ @@ -320,6 +321,13 @@ int ne_sock_init(void) #endif +#ifdef HAVE_SSPI + if (ne_sspi_init() < 0) { + init_result = -1; + return init_result; + } +#endif + #ifdef NE_HAVE_SOCKS SOCKSinit("neon"); #endif @@ -348,6 +356,11 @@ void ne_sock_exit(void) #ifdef HAVE_GNUTLS gnutls_global_deinit(); #endif + +#ifdef HAVE_SSPI + ne_sspi_deinit(); +#endif + init_result = 0; } diff --git a/src/ne_sspi.c b/src/ne_sspi.c new file mode 100644 index 0000000..4fc4e90 --- /dev/null +++ b/src/ne_sspi.c @@ -0,0 +1,546 @@ +/* + Microsoft SSPI based authentication routines + Copyright (C) 2004-2005, Vladimir Berezniker @ http://public.xdi.org/=vmpn + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +*/ + +#include "config.h" + +#include "ne_utils.h" +#include "ne_string.h" +#include "ne_sspi.h" + +#define SEC_SUCCESS(Status) ((Status) >= 0) + +struct SSPIContextStruct { + CtxtHandle context; + char *serverName; + CredHandle credentials; + int continueNeeded; + char *mechanism; + int ntlm; + ULONG maxTokenSize; +}; + +typedef struct SSPIContextStruct SSPIContext; + +static ULONG negotiateMaxTokenSize = 0; +static ULONG ntlmMaxTokenSize = 0; +static HINSTANCE hSecDll = NULL; +static PSecurityFunctionTable pSFT = NULL; +static int initialized = 0; + +/* + * Query specified package for it's maximum token size. + */ +static int getMaxTokenSize(const char *package, ULONG * maxTokenSize) +{ + SECURITY_STATUS status; + SecPkgInfo *packageSecurityInfo = NULL; + + status = pSFT->QuerySecurityPackageInfo(package, &packageSecurityInfo); + if (status == SEC_E_OK) { + *maxTokenSize = packageSecurityInfo->cbMaxToken; + if (pSFT->FreeContextBuffer(packageSecurityInfo) != SEC_E_OK) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unable to free security package info."); + } + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: QuerySecurityPackageInfo [failed] [%x].", status); + return -1; + } + + return 0; +} + +/* + * Initialize all the SSPI data + */ +static void initDll(HINSTANCE hSecDll) +{ + INIT_SECURITY_INTERFACE initSecurityInterface = NULL; + + initSecurityInterface = + (INIT_SECURITY_INTERFACE) GetProcAddress(hSecDll, + SECURITY_ENTRYPOINT); + + if (initSecurityInterface == NULL) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Obtaining security interface [fail].\n"); + initialized = -1; + return; + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Obtaining security interface [ok].\n"); + } + + pSFT = (initSecurityInterface) (); + + if (pSFT == NULL) { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Security Function Table [fail].\n"); + initialized = -2; + return; + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Security Function Table [ok].\n"); + } + + if (getMaxTokenSize("Negotiate", &negotiateMaxTokenSize)) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unable to get negotiate maximum packet size"); + initialized = -3; + } + + if (getMaxTokenSize("NTLM", &ntlmMaxTokenSize)) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unable to get negotiate maximum packet size"); + initialized = -3; + } +} + +/* + * This function needs to be called at least once before using any other. + */ +int sspiInit() +{ + + if (initialized) { + return 0; + } + + NE_DEBUG(NE_DBG_SOCKET, "sspiInit\n"); + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Loading security dll.\n"); + hSecDll = LoadLibrary("security.dll"); + + if (hSecDll == NULL) { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Loading of security dll [fail].\n"); + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Loading of security dll [ok].\n"); + initDll(hSecDll); + if (initialized == 0) { + initialized = 1; + } + } + + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: sspiInit [%d].\n", initialized); + if (initialized < 0) { + return initialized; + } else { + return 0; + } +} + +/* + * This function can be called to free resources used by SSPI. + */ +int ne_sspi_init(void) +{ + NE_DEBUG(NE_DBG_SOCKET, "sspi: DeInit\n"); + if (initialized <= 0) { + return initialized; + } + + pSFT = NULL; + + if (hSecDll != NULL) { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Unloading security dll.\n"); + if (FreeLibrary(hSecDll)) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unloading of security dll [ok].\n"); + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unloading of security dll [fail].\n"); + return -1; + } + hSecDll = NULL; + } + + initialized = 0; + return 0; +} + +/* + * Simplification wrapper arround AcquireCredentialsHandle as most of + * the parameters do not change. + */ +static int acquireCredentialsHandle(CredHandle * credentials, char *package) +{ + SECURITY_STATUS status; + TimeStamp timestamp; + + status = + pSFT->AcquireCredentialsHandle(NULL, package, SECPKG_CRED_OUTBOUND, + NULL, NULL, NULL, NULL, credentials, + ×tamp); + + if (status != SEC_E_OK) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: AcquireCredentialsHandle [fail] [%x].\n", status); + return -1; + } + + return 0; +} + +/* + * Wrapper arround initializeSecurityContext. Supplies several + * default parameters as well as logging in case of errors. + */ +static SECURITY_STATUS +initializeSecurityContext(CredHandle * credentials, CtxtHandle * context, + char *spn, ULONG contextReq, + SecBufferDesc * inBuffer, CtxtHandle * newContext, + SecBufferDesc * outBuffer) +{ + ULONG contextAttributes; + SECURITY_STATUS status; + + status = + pSFT->InitializeSecurityContext(credentials, context, spn, contextReq, + 0, SECURITY_NETWORK_DREP, inBuffer, 0, + newContext, outBuffer, + &contextAttributes, NULL); + + if (!SEC_SUCCESS(status)) { + if (status == SEC_E_INVALID_TOKEN) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "InitializeSecurityContext [fail] SEC_E_INVALID_TOKEN.\n"); + } else if (status == SEC_E_UNSUPPORTED_FUNCTION) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "InitializeSecurityContext [fail] SEC_E_UNSUPPORTED_FUNCTION.\n"); + } else { + NE_DEBUG(NE_DBG_HTTPAUTH, + "InitializeSecurityContext [fail] [%x].\n", status); + } + } + + return status; +} + +/* + * Validates that the pointer is not NULL and converts it to its real type. + */ +static int getContext(void *context, SSPIContext **sspiContext) +{ + if (!context) { + return -1; + } + + *sspiContext = context; + return 0; +} + +/* + * Verifies that the buffer descriptor point only to one buffer and + * returns the pointer to it. + */ +static int getSingleBufferDescriptor(SecBufferDesc *secBufferDesc, + SecBuffer **secBuffer) +{ + if (secBufferDesc->cBuffers != 1) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: fillBufferDescriptor " + "[fail] numbers of descriptor buffers. 1 != [%d].\n", + secBufferDesc->cBuffers); + return -1; + } + + *secBuffer = secBufferDesc->pBuffers; + return 0; +} + +/* + * Decodes BASE64 string into SSPI SecBuffer + */ +static int base64ToBuffer(const char *token, SecBufferDesc * secBufferDesc) +{ + SecBuffer *buffer; + if (getSingleBufferDescriptor(secBufferDesc, &buffer)) { + return -1; + } + + buffer->BufferType = SECBUFFER_TOKEN; + buffer->cbBuffer = + ne_unbase64(token, &((unsigned char *) buffer->pvBuffer)); + + if (buffer->cbBuffer == 0) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: Unable to decode BASE64 SSPI token.\n"); + return -1; + } + + return 0; +} + +/* + * Creates a SecBuffer of a specified size. + */ +static int makeBuffer(SecBufferDesc * secBufferDesc, ULONG size) +{ + SecBuffer *buffer; + if (getSingleBufferDescriptor(secBufferDesc, &buffer)) { + return -1; + } + + buffer->BufferType = SECBUFFER_TOKEN; + buffer->cbBuffer = size; + buffer->pvBuffer = ne_calloc(size); + + return 0; +} + +/* + * Frees data allocated in the buffer. + */ +static int freeBuffer(SecBufferDesc * secBufferDesc) +{ + SecBuffer *buffer; + if (getSingleBufferDescriptor(secBufferDesc, &buffer)) { + return -1; + } + + if (buffer->cbBuffer > 0 && buffer->pvBuffer) { + ne_free(buffer->pvBuffer); + buffer->cbBuffer = 0; + buffer->pvBuffer = NULL; + } + + return 0; +} + +/* + * Returns mechanism string for the specified context. + */ +int ne_sspi_get_mechanism(void *context, char const **mechanism) +{ + int status; + SSPIContext *sspiContext; + + if (initialized <= 0) { + return -1; + } + + status = getContext(context, &sspiContext); + if (status) { + return status; + } + + *mechanism = sspiContext->mechanism; + return 0; +} + +/* + * Create a context to authenticate to specified server, using either + * ntlm or negotiate. + */ +int ne_sspi_create_context(void **context, char *serverName, int ntlm) +{ + SSPIContext *sspiContext; + + if (initialized <= 0) { + return -1; + } + + sspiContext = ne_calloc(sizeof(SSPIContext)); + sspiContext->continueNeeded = 0; + + if (ntlm) { + sspiContext->mechanism = "NTLM"; + sspiContext->serverName = ne_strdup(serverName); + sspiContext->maxTokenSize = ntlmMaxTokenSize; + } else { + sspiContext->mechanism = "Negotiate"; + sspiContext->serverName = ne_concat("HTTP/", serverName, NULL); + sspiContext->maxTokenSize = negotiateMaxTokenSize; + } + + sspiContext->ntlm = ntlm; + *context = sspiContext; + return 0; +} + +/* + * Resets the context + */ +static void resetContext(SSPIContext * sspiContext) +{ + pSFT->DeleteSecurityContext(&(sspiContext->context)); + pSFT->FreeCredentialsHandle(&(sspiContext->credentials)); + sspiContext->continueNeeded = 0; +} + +/* + * Initializes supplied SecBufferDesc to point to supplied SecBuffer + * that is also initialized; + */ +static void +initSingleEmptyBuffer(SecBufferDesc * bufferDesc, SecBuffer * buffer) +{ + buffer->BufferType = SECBUFFER_EMPTY; + buffer->cbBuffer = 0; + buffer->pvBuffer = NULL; + + bufferDesc->cBuffers = 1; + bufferDesc->ulVersion = SECBUFFER_VERSION; + bufferDesc->pBuffers = buffer; + +} + +/* + * Destroyes the supplied context. + */ +int ne_sspi_destroy_context(void *context) +{ + + int status; + SSPIContext *sspiContext; + + if (initialized <= 0) { + return -1; + } + + status = getContext(context, &sspiContext); + if (status) { + return status; + } + + resetContext(sspiContext); + if (sspiContext->serverName) { + ne_free(sspiContext->serverName); + sspiContext->serverName = NULL; + } + + ne_free(sspiContext); + return 0; +} + +/* + * Processes received authentication tokens as well as supplies the + * response token. + */ +int ne_sspi_authenticate(void *context, const char *base64Token, char **responseToken) +{ + SecBufferDesc outBufferDesc; + SecBuffer outBuffer; + int status; + SECURITY_STATUS securityStatus; + ULONG contextFlags; + + SSPIContext *sspiContext; + if (initialized <= 0) { + return -1; + } + + status = getContext(context, &sspiContext); + if (status) { + return status; + } + + /* TODO: Not sure what flags should be set. joe: this needs to be + * driven by the ne_auth interface; the GSSAPI code needs similar + * flags. */ + contextFlags = ISC_REQ_CONFIDENTIALITY | ISC_REQ_MUTUAL_AUTH; + + initSingleEmptyBuffer(&outBufferDesc, &outBuffer); + status = makeBuffer(&outBufferDesc, sspiContext->maxTokenSize); + if (status) { + return status; + } + + if (base64Token) { + SecBufferDesc inBufferDesc; + SecBuffer inBuffer; + + if (!sspiContext->continueNeeded) { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Got an unexpected token.\n"); + return -1; + } + + initSingleEmptyBuffer(&inBufferDesc, &inBuffer); + + status = base64ToBuffer(base64Token, &inBufferDesc); + if (status) { + return status; + } + + securityStatus = + initializeSecurityContext(&sspiContext->credentials, + &(sspiContext->context), + sspiContext->serverName, contextFlags, + &inBufferDesc, &(sspiContext->context), + &outBufferDesc); + freeBuffer(&inBufferDesc); + } else { + if (sspiContext->continueNeeded) { + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Expected a token from server.\n"); + return -1; + } + + /* Reset any existing context since we are starting over */ + resetContext(sspiContext); + + if (acquireCredentialsHandle + (&sspiContext->credentials, sspiContext->mechanism) != SEC_E_OK) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: acquireCredentialsHandle failed.\n"); + return -1; + } + + securityStatus = + initializeSecurityContext(&sspiContext->credentials, NULL, + sspiContext->serverName, contextFlags, + NULL, &(sspiContext->context), + &outBufferDesc); + } + + if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE + || securityStatus == SEC_I_COMPLETE_NEEDED) { + SECURITY_STATUS compleStatus = + pSFT->CompleteAuthToken(&(sspiContext->context), &outBufferDesc); + + if (compleStatus != SEC_E_OK) { + freeBuffer(&outBufferDesc); + NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: CompleteAuthToken failed.\n"); + return -1; + } + } + + if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE + || securityStatus == SEC_I_CONTINUE_NEEDED) { + sspiContext->continueNeeded = 1; + } else { + sspiContext->continueNeeded = 0; + } + + if (!(securityStatus == SEC_I_COMPLETE_AND_CONTINUE + || securityStatus == SEC_I_COMPLETE_NEEDED + || securityStatus == SEC_I_CONTINUE_NEEDED + || securityStatus == SEC_E_OK)) { + NE_DEBUG(NE_DBG_HTTPAUTH, + "sspi: initializeSecurityContext [failed] [%x].\n", + securityStatus); + freeBuffer(&outBufferDesc); + return -1; + } + + *responseToken = ne_base64(outBufferDesc.pBuffers->pvBuffer, + outBufferDesc.pBuffers->cbBuffer); + freeBuffer(&outBufferDesc); + + return 0; +} diff --git a/src/ne_sspi.h b/src/ne_sspi.h new file mode 100644 index 0000000..4c707a9 --- /dev/null +++ b/src/ne_sspi.h @@ -0,0 +1,48 @@ +/* + Microsoft SSPI based authentication routines + Copyright (C) 2004-2005, Vladimir Berezniker @ http://public.xdi.org/=vmpn + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +*/ + +#ifndef NE_SSPI_H +#define NE_SSPI_H + +/* Win32 SSPI-based authentication interfaces. PRIVATE TO NEON -- NOT + * PART OF THE EXTERNAL API. */ + +#ifdef HAVE_SSPI + +#include <windows.h> +#define SECURITY_WIN32 +#include <security.h> + +int ne_sspi_init(void); +fint ne_sspi_deinit(void); + +int ne_sspi_create_context(void **context, char * serverName, int ntlm); + +int ne_sspi_destroy_context(void *context); + +int ne_sspi_get_mechanism(void *context, char const **mechanism); + +int ne_sspi_authenticate(void *context, const char *base64Token, + char **responseToken); + +#endif /* HAVE_SSPI */ + +#endif /* NE_SSPI_H */ |