Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/secur32/Makefile.in | 7 +- dlls/secur32/base64_codec.c | 192 ---- dlls/secur32/dispatcher.c | 335 ------ dlls/secur32/hmac_md5.c | 77 -- dlls/secur32/hmac_md5.h | 48 - dlls/secur32/negotiate.c | 13 +- dlls/secur32/ntlm.c | 2029 ----------------------------------- dlls/secur32/secur32_priv.h | 108 -- dlls/secur32/util.c | 187 ---- 9 files changed, 13 insertions(+), 2983 deletions(-) delete mode 100644 dlls/secur32/base64_codec.c delete mode 100644 dlls/secur32/dispatcher.c delete mode 100644 dlls/secur32/hmac_md5.c delete mode 100644 dlls/secur32/hmac_md5.h delete mode 100644 dlls/secur32/ntlm.c delete mode 100644 dlls/secur32/util.c
diff --git a/dlls/secur32/Makefile.in b/dlls/secur32/Makefile.in index c9acdee4572..89a7c8bd078 100644 --- a/dlls/secur32/Makefile.in +++ b/dlls/secur32/Makefile.in @@ -1,21 +1,16 @@ MODULE = secur32.dll IMPORTLIB = secur32 -IMPORTS = netapi32 advapi32 +IMPORTS = advapi32 DELAYIMPORTS = crypt32 EXTRAINCL = $(GNUTLS_CFLAGS) EXTRALIBS = $(SECURITY_LIBS)
C_SRCS = \ - base64_codec.c \ - dispatcher.c \ - hmac_md5.c \ lsa.c \ negotiate.c \ - ntlm.c \ schannel.c \ schannel_gnutls.c \ schannel_macosx.c \ secur32.c \ thunks.c \ - util.c \ wrapper.c diff --git a/dlls/secur32/base64_codec.c b/dlls/secur32/base64_codec.c deleted file mode 100644 index 9f5eaecc3d4..00000000000 --- a/dlls/secur32/base64_codec.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * base64 encoder/decoder - * - * Copyright 2005 by Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "windef.h" -#include "winerror.h" -#include "sspi.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ntlm); - -static const char b64[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf, - int max_len, int *out_len) -{ - int div, i; - PBYTE d = in_buf; - int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; - - TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); - *out_len = bytes + pad_bytes; - - if(bytes + pad_bytes + 1 > max_len) - return SEC_E_BUFFER_TOO_SMALL; - - /* Three bytes of input give 4 chars of output */ - div = in_len / 3; - - i = 0; - while(div > 0) - { - /* first char is the first 6 bits of the first byte*/ - out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; - /* second char is the last 2 bits of the first byte and the first 4 - * bits of the second byte */ - out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; - /* third char is the last 4 bits of the second byte and the first 2 - * bits of the third byte */ - out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)]; - /* fourth char is the remaining 6 bits of the third byte */ - out_buf[i + 3] = b64[ d[2] & 0x3f]; - i += 4; - d += 3; - div--; - } - - switch(pad_bytes) - { - case 1: - /* first char is the first 6 bits of the first byte*/ - out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; - /* second char is the last 2 bits of the first byte and the first 4 - * bits of the second byte */ - out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; - /* third char is the last 4 bits of the second byte padded with - * two zeroes */ - out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) ]; - /* fourth char is a = to indicate one byte of padding */ - out_buf[i + 3] = '='; - out_buf[i + 4] = 0; - break; - case 2: - /* first char is the first 6 bits of the first byte*/ - out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; - /* second char is the last 2 bits of the first byte padded with - * four zeroes*/ - out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30)]; - /* third char is = to indicate padding */ - out_buf[i + 2] = '='; - /* fourth char is = to indicate padding */ - out_buf[i + 3] = '='; - out_buf[i + 4] = 0; - break; - default: - out_buf[i] = 0; - } - - return SEC_E_OK; -} - -static inline BYTE decode(char c) -{ - if( c >= 'A' && c <= 'Z') - return c - 'A'; - if( c >= 'a' && c <= 'z') - return c - 'a' + 26; - if( c >= '0' && c <= '9') - return c - '0' + 52; - if( c == '+') - return 62; - if( c == '/') - return 63; - else - return 64; -} - -SECURITY_STATUS decodeBase64(char *in_buf, int in_len, PBYTE out_buf, - int max_len, int *out_len) -{ - int len = in_len, i; - char *d = in_buf; - int ip0, ip1, ip2, ip3; - - TRACE("in_len: %d\n", in_len); - - if((in_len % 4) != 0) - return SEC_E_INVALID_TOKEN; - - if(in_len > max_len) - return SEC_E_BUFFER_TOO_SMALL; - - i = 0; - while(len > 4) - { - if((ip0 = decode(d[0])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip1 = decode(d[1])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip2 = decode(d[2])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip3 = decode(d[3])) > 63) - return SEC_E_INVALID_TOKEN; - - out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); - out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); - out_buf[i + 2] = (ip2 << 6) | ip3; - len -= 4; - i += 3; - d += 4; - } - - if(d[2] == '=') - { - if((ip0 = decode(d[0])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip1 = decode(d[1])) > 63) - return SEC_E_INVALID_TOKEN; - - out_buf[i] = (ip0 << 2) | (ip1 >> 4); - i++; - } - else if(d[3] == '=') - { - if((ip0 = decode(d[0])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip1 = decode(d[1])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip2 = decode(d[2])) > 63) - return SEC_E_INVALID_TOKEN; - - out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); - out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); - i += 2; - } - else - { - if((ip0 = decode(d[0])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip1 = decode(d[1])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip2 = decode(d[2])) > 63) - return SEC_E_INVALID_TOKEN; - if((ip3 = decode(d[3])) > 63) - return SEC_E_INVALID_TOKEN; - - - out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); - out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); - out_buf[i + 2] = (ip2 << 6) | ip3; - i += 3; - } - *out_len = i; - return SEC_E_OK; -} diff --git a/dlls/secur32/dispatcher.c b/dlls/secur32/dispatcher.c deleted file mode 100644 index 0871576848e..00000000000 --- a/dlls/secur32/dispatcher.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright 2005, 2006 Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * A dispatcher to run ntlm_auth for wine's sspi module. - */ - -#include "config.h" -#include "wine/port.h" -#include <stdarg.h> -#include <stdio.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <sys/types.h> -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#include <errno.h> -#include <stdlib.h> -#include <fcntl.h> -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "sspi.h" -#include "secur32_priv.h" -#include "wine/debug.h" - -#define INITIAL_BUFFER_SIZE 200 - -WINE_DEFAULT_DEBUG_CHANNEL(ntlm); - -SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog, - char* const argv[]) -{ -#ifdef HAVE_FORK - int pipe_in[2]; - int pipe_out[2]; - int i; - PNegoHelper helper; - - TRACE("%s ", debugstr_a(prog)); - for(i = 0; argv[i] != NULL; ++i) - { - TRACE("%s ", debugstr_a(argv[i])); - } - TRACE("\n"); - -#ifdef HAVE_PIPE2 - if (pipe2( pipe_in, O_CLOEXEC ) < 0 ) -#endif - { - if( pipe(pipe_in) < 0 ) return SEC_E_INTERNAL_ERROR; - fcntl( pipe_in[0], F_SETFD, FD_CLOEXEC ); - fcntl( pipe_in[1], F_SETFD, FD_CLOEXEC ); - } -#ifdef HAVE_PIPE2 - if (pipe2( pipe_out, O_CLOEXEC ) < 0 ) -#endif - { - if( pipe(pipe_out) < 0 ) - { - close(pipe_in[0]); - close(pipe_in[1]); - return SEC_E_INTERNAL_ERROR; - } - fcntl( pipe_out[0], F_SETFD, FD_CLOEXEC ); - fcntl( pipe_out[1], F_SETFD, FD_CLOEXEC ); - } - - if (!(helper = heap_alloc( sizeof(NegoHelper) ))) - { - close(pipe_in[0]); - close(pipe_in[1]); - close(pipe_out[0]); - close(pipe_out[1]); - return SEC_E_INSUFFICIENT_MEMORY; - } - - helper->helper_pid = fork(); - - if(helper->helper_pid == -1) - { - close(pipe_in[0]); - close(pipe_in[1]); - close(pipe_out[0]); - close(pipe_out[1]); - heap_free( helper ); - return SEC_E_INTERNAL_ERROR; - } - - if(helper->helper_pid == 0) - { - /* We're in the child now */ - dup2(pipe_out[0], 0); - close(pipe_out[0]); - close(pipe_out[1]); - - dup2(pipe_in[1], 1); - close(pipe_in[0]); - close(pipe_in[1]); - - execvp(prog, argv); - - /* Whoops, we shouldn't get here. Big badaboom.*/ - write(STDOUT_FILENO, "BH\n", 3); - _exit(1); - } - else - { - *new_helper = helper; - helper->major = helper->minor = helper->micro = -1; - helper->com_buf = NULL; - helper->com_buf_size = 0; - helper->com_buf_offset = 0; - helper->session_key = NULL; - helper->neg_flags = 0; - helper->crypt.ntlm.a4i = NULL; - helper->crypt.ntlm2.send_a4i = NULL; - helper->crypt.ntlm2.recv_a4i = NULL; - helper->crypt.ntlm2.send_sign_key = NULL; - helper->crypt.ntlm2.send_seal_key = NULL; - helper->crypt.ntlm2.recv_sign_key = NULL; - helper->crypt.ntlm2.recv_seal_key = NULL; - helper->pipe_in = pipe_in[0]; - close(pipe_in[1]); - helper->pipe_out = pipe_out[1]; - close(pipe_out[0]); - } - - return SEC_E_OK; -#else - ERR( "no fork support on this platform\n" ); - return SEC_E_INTERNAL_ERROR; -#endif -} - -static SECURITY_STATUS read_line(PNegoHelper helper, int *offset_len) -{ - char *newline; - int read_size; - - if(helper->com_buf == NULL) - { - TRACE("Creating a new buffer for the helper\n"); - if (!(helper->com_buf = heap_alloc(INITIAL_BUFFER_SIZE))) - return SEC_E_INSUFFICIENT_MEMORY; - - /* Created a new buffer, size is INITIAL_BUFFER_SIZE, offset is 0 */ - helper->com_buf_size = INITIAL_BUFFER_SIZE; - helper->com_buf_offset = 0; - } - - do - { - TRACE("offset = %d, size = %d\n", helper->com_buf_offset, helper->com_buf_size); - if(helper->com_buf_offset + INITIAL_BUFFER_SIZE > helper->com_buf_size) - { - /* increment buffer size in INITIAL_BUFFER_SIZE steps */ - char *buf = heap_realloc(helper->com_buf, helper->com_buf_size + INITIAL_BUFFER_SIZE); - TRACE("Resizing buffer!\n"); - if (!buf) return SEC_E_INSUFFICIENT_MEMORY; - helper->com_buf_size += INITIAL_BUFFER_SIZE; - helper->com_buf = buf; - } - if((read_size = read(helper->pipe_in, helper->com_buf + helper->com_buf_offset, - helper->com_buf_size - helper->com_buf_offset)) <= 0) - { - return SEC_E_INTERNAL_ERROR; - } - - TRACE("read_size = %d, read: %s\n", read_size, - debugstr_a(helper->com_buf + helper->com_buf_offset)); - helper->com_buf_offset += read_size; - newline = memchr(helper->com_buf, '\n', helper->com_buf_offset); - }while(newline == NULL); - - /* Now, if there's a newline character, and we read more than that newline, - * we have to store the offset so we can preserve the additional data.*/ - if( newline != helper->com_buf + helper->com_buf_offset) - { - TRACE("offset_len is calculated from %p - %p\n", - (helper->com_buf + helper->com_buf_offset), newline+1); - /* the length of the offset is the number of chars after the newline */ - *offset_len = (helper->com_buf + helper->com_buf_offset) - (newline + 1); - } - else - { - *offset_len = 0; - } - - *newline = '\0'; - - return SEC_E_OK; -} - -static SECURITY_STATUS preserve_unused(PNegoHelper helper, int offset_len) -{ - TRACE("offset_len = %d\n", offset_len); - - if(offset_len > 0) - { - memmove(helper->com_buf, helper->com_buf + helper->com_buf_offset, - offset_len); - helper->com_buf_offset = offset_len; - } - else - { - helper->com_buf_offset = 0; - } - - TRACE("helper->com_buf_offset was set to: %d\n", helper->com_buf_offset); - return SEC_E_OK; -} - -SECURITY_STATUS run_helper(PNegoHelper helper, char *buffer, - unsigned int max_buflen, int *buflen) -{ - int offset_len; - SECURITY_STATUS sec_status = SEC_E_OK; - - TRACE("In helper: sending %s\n", debugstr_a(buffer)); - - /* buffer + '\n' */ - write(helper->pipe_out, buffer, lstrlenA(buffer)); - write(helper->pipe_out, "\n", 1); - - if((sec_status = read_line(helper, &offset_len)) != SEC_E_OK) - { - return sec_status; - } - - TRACE("In helper: received %s\n", debugstr_a(helper->com_buf)); - *buflen = lstrlenA(helper->com_buf); - - if( *buflen > max_buflen) - { - ERR("Buffer size too small(%d given, %d required) dropping data!\n", - max_buflen, *buflen); - return SEC_E_BUFFER_TOO_SMALL; - } - - if( *buflen < 2 ) - { - return SEC_E_ILLEGAL_MESSAGE; - } - - /* We only get ERR if the input size is too big. On a GENSEC error, - * ntlm_auth will return BH */ - if(strncmp(helper->com_buf, "ERR", 3) == 0) - { - return SEC_E_INVALID_TOKEN; - } - - memcpy(buffer, helper->com_buf, *buflen+1); - - sec_status = preserve_unused(helper, offset_len); - - return sec_status; -} - -void cleanup_helper(PNegoHelper helper) -{ - - TRACE("Killing helper %p\n", helper); - if(helper == NULL) - return; - - heap_free(helper->com_buf); - heap_free(helper->session_key); - - /* closing stdin will terminate ntlm_auth */ - close(helper->pipe_out); - close(helper->pipe_in); - -#ifdef HAVE_FORK - if (helper->helper_pid > 0) /* reap child */ - { - pid_t wret; - do { - wret = waitpid(helper->helper_pid, NULL, 0); - } while (wret < 0 && errno == EINTR); - } -#endif - - heap_free(helper); -} - -void check_version(PNegoHelper helper) -{ - char temp[80]; - char *newline; - int major = 0, minor = 0, micro = 0, ret; - - TRACE("Checking version of helper\n"); - if(helper != NULL) - { - int len = read(helper->pipe_in, temp, sizeof(temp)-1); - if (len > 8) - { - if((newline = memchr(temp, '\n', len)) != NULL) - *newline = '\0'; - else - temp[len] = 0; - - TRACE("Exact version is %s\n", debugstr_a(temp)); - ret = sscanf(temp, "Version %d.%d.%d", &major, &minor, µ); - if(ret != 3) - { - ERR("Failed to get the helper version.\n"); - helper->major = helper->minor = helper->micro = -1; - } - else - { - TRACE("Version recognized: %d.%d.%d\n", major, minor, micro); - helper->major = major; - helper->minor = minor; - helper->micro = micro; - } - } - } -} diff --git a/dlls/secur32/hmac_md5.c b/dlls/secur32/hmac_md5.c deleted file mode 100644 index 3479178132d..00000000000 --- a/dlls/secur32/hmac_md5.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2006 Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * This file implements RFC 2104 (HMAC) for the MD5 provider. - * It is needed for NTLM2 signing and sealing. - */ - -#include "hmac_md5.h" - -void HMACMD5Init(HMAC_MD5_CTX *ctx, const unsigned char *key, unsigned int key_len) -{ - int i; - unsigned char inner_padding[64]; - unsigned char temp_key[16]; - - if(key_len > 64) - { - MD5_CTX temp_ctx; - - MD5Init(&temp_ctx); - MD5Update(&temp_ctx, key, key_len); - MD5Final(&temp_ctx); - memcpy(temp_key, temp_ctx.digest, 16); - - key = temp_key; - key_len = 16; - } - - memset(inner_padding, 0, 64); - memset(ctx->outer_padding, 0, 64); - memcpy(inner_padding, key, key_len); - memcpy(ctx->outer_padding, key, key_len); - - for(i = 0; i < 64; ++i) - { - inner_padding[i] ^= 0x36; - ctx->outer_padding[i] ^= 0x5c; - } - - MD5Init(&(ctx->ctx)); - MD5Update(&(ctx->ctx), inner_padding, 64); -} - -void HMACMD5Update(HMAC_MD5_CTX *ctx, const unsigned char *data, unsigned int data_len) -{ - MD5Update(&(ctx->ctx), data, data_len); -} - -void HMACMD5Final(HMAC_MD5_CTX *ctx, unsigned char *digest) -{ - MD5_CTX outer_ctx; - unsigned char inner_digest[16]; - - MD5Final(&(ctx->ctx)); - memcpy(inner_digest, ctx->ctx.digest, 16); - - MD5Init(&outer_ctx); - MD5Update(&outer_ctx, ctx->outer_padding, 64); - MD5Update(&outer_ctx, inner_digest, 16); - MD5Final(&outer_ctx); - - memcpy(digest, outer_ctx.digest, 16); -} diff --git a/dlls/secur32/hmac_md5.h b/dlls/secur32/hmac_md5.h deleted file mode 100644 index 2bb46dc55ad..00000000000 --- a/dlls/secur32/hmac_md5.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006 Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * This file holds the declarations needed for HMAC-MD5. - */ - -#ifndef _HMAC_MD5_H_ -#define _HMAC_MD5_H_ - -#include <string.h> -#include "windef.h" - -typedef struct -{ - unsigned int i[2]; - unsigned int buf[4]; - unsigned char in[64]; - unsigned char digest[16]; -} MD5_CTX; - -typedef struct -{ - MD5_CTX ctx; - unsigned char outer_padding[64]; -} HMAC_MD5_CTX; - -void WINAPI MD5Init( MD5_CTX *ctx ); -void WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len ); -void WINAPI MD5Final( MD5_CTX *ctx ); - -void HMACMD5Init(HMAC_MD5_CTX *ctx, const unsigned char *key, unsigned int key_len) DECLSPEC_HIDDEN; -void HMACMD5Update(HMAC_MD5_CTX *ctx, const unsigned char *data, unsigned int data_len) DECLSPEC_HIDDEN; -void HMACMD5Final(HMAC_MD5_CTX *ctx, unsigned char *digest) DECLSPEC_HIDDEN; -#endif /*_HMAC_MD5_H_*/ diff --git a/dlls/secur32/negotiate.c b/dlls/secur32/negotiate.c index 0df950093e4..6767790d09f 100644 --- a/dlls/secur32/negotiate.c +++ b/dlls/secur32/negotiate.c @@ -58,6 +58,17 @@ struct sec_handle SecHandle handle_ntlm; };
+/* matches layout from msv1_0 */ +struct ntlm_cred +{ + int mode; + char *username_arg; + char *domain_arg; + char *password; + int password_len; + int no_cached_credentials; /* don't try to use cached Samba credentials */ +}; + /*********************************************************************** * AcquireCredentialsHandleW */ @@ -92,7 +103,7 @@ static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleW( fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, &cred->handle_ntlm, ptsExpiry ); if (ret == SEC_E_OK) { - NtlmCredentials *ntlm_cred = (NtlmCredentials *)cred->handle_ntlm.dwLower; + struct ntlm_cred *ntlm_cred = (struct ntlm_cred *)cred->handle_ntlm.dwLower; ntlm_cred->no_cached_credentials = (pAuthData == NULL); cred->ntlm = package->provider; } diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c deleted file mode 100644 index 4e3fda3ea98..00000000000 --- a/dlls/secur32/ntlm.c +++ /dev/null @@ -1,2029 +0,0 @@ -/* - * Copyright 2005, 2006 Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * This file implements the NTLM security provider. - */ - -#include <assert.h> -#include <stdarg.h> -#include <stdio.h> -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wincred.h" -#include "winternl.h" -#include "rpc.h" -#include "sspi.h" -#include "lm.h" -#include "secur32_priv.h" -#include "hmac_md5.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ntlm); -WINE_DECLARE_DEBUG_CHANNEL(winediag); - -#define NTLM_MAX_BUF 1904 -#define MIN_NTLM_AUTH_MAJOR_VERSION 3 -#define MIN_NTLM_AUTH_MINOR_VERSION 0 -#define MIN_NTLM_AUTH_MICRO_VERSION 25 - -static CHAR ntlm_auth[] = "ntlm_auth"; - -/*********************************************************************** - * QueryCredentialsAttributesA - */ -static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA( - PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) -{ - SECURITY_STATUS ret; - - TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); - - if(ulAttribute == SECPKG_ATTR_NAMES) - { - FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); - ret = SEC_E_UNSUPPORTED_FUNCTION; - } - else - ret = SEC_E_UNSUPPORTED_FUNCTION; - - return ret; -} - -/*********************************************************************** - * QueryCredentialsAttributesW - */ -static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW( - PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) -{ - SECURITY_STATUS ret; - - TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); - - if(ulAttribute == SECPKG_ATTR_NAMES) - { - FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); - ret = SEC_E_UNSUPPORTED_FUNCTION; - } - else - ret = SEC_E_UNSUPPORTED_FUNCTION; - - return ret; -} - -static char *ntlm_GetUsernameArg(LPCWSTR userW, INT userW_length) -{ - static const char username_arg[] = "--username="; - char *user; - int unixcp_size; - - unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, - userW, userW_length, NULL, 0, NULL, NULL) + sizeof(username_arg); - if (!(user = heap_alloc(unixcp_size))) return NULL; - memcpy(user, username_arg, sizeof(username_arg) - 1); - WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, userW, userW_length, - user + sizeof(username_arg) - 1, - unixcp_size - sizeof(username_arg) + 1, NULL, NULL); - user[unixcp_size - 1] = '\0'; - return user; -} - -static char *ntlm_GetDomainArg(LPCWSTR domainW, INT domainW_length) -{ - static const char domain_arg[] = "--domain="; - char *domain; - int unixcp_size; - - unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, - domainW, domainW_length, NULL, 0, NULL, NULL) + sizeof(domain_arg); - if (!(domain = heap_alloc(unixcp_size))) return NULL; - memcpy(domain, domain_arg, sizeof(domain_arg) - 1); - WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domainW, - domainW_length, domain + sizeof(domain_arg) - 1, - unixcp_size - sizeof(domain) + 1, NULL, NULL); - domain[unixcp_size - 1] = '\0'; - return domain; -} - -/*********************************************************************** - * AcquireCredentialsHandleW - */ -static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW( - SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, - PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, - PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY; - PNtlmCredentials ntlm_cred = NULL; - LPWSTR domain = NULL, user = NULL, password = NULL; - PSEC_WINNT_AUTH_IDENTITY_W auth_data = NULL; - - TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", - debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, - pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - - switch (fCredentialUse) - { - case SECPKG_CRED_INBOUND: - if (!(ntlm_cred = heap_alloc(sizeof(*ntlm_cred)))) return SEC_E_INSUFFICIENT_MEMORY; - ntlm_cred->mode = NTLM_SERVER; - ntlm_cred->username_arg = NULL; - ntlm_cred->domain_arg = NULL; - ntlm_cred->password = NULL; - ntlm_cred->pwlen = 0; - ntlm_cred->no_cached_credentials = 0; - - phCredential->dwUpper = fCredentialUse; - phCredential->dwLower = (ULONG_PTR)ntlm_cred; - ret = SEC_E_OK; - break; - - case SECPKG_CRED_OUTBOUND: - auth_data = pAuthData; - if (!(ntlm_cred = heap_alloc(sizeof(*ntlm_cred)))) return SEC_E_INSUFFICIENT_MEMORY; - - ntlm_cred->mode = NTLM_CLIENT; - ntlm_cred->username_arg = NULL; - ntlm_cred->domain_arg = NULL; - ntlm_cred->password = NULL; - ntlm_cred->pwlen = 0; - ntlm_cred->no_cached_credentials = 0; - - if (pAuthData) - { - int domain_len = 0, user_len = 0, password_len = 0; - - if (auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) - { - if (auth_data->DomainLength) - { - domain_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, - auth_data->DomainLength, NULL, 0); - if (!(domain = heap_alloc(sizeof(WCHAR) * domain_len))) goto done; - MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, auth_data->DomainLength, - domain, domain_len); - } - if (auth_data->UserLength) - { - user_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, - auth_data->UserLength, NULL, 0); - if (!(user = heap_alloc(sizeof(WCHAR) * user_len))) goto done; - MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, auth_data->UserLength, - user, user_len); - } - if (auth_data->PasswordLength) - { - password_len = MultiByteToWideChar(CP_ACP, 0,(char *)auth_data->Password, - auth_data->PasswordLength, NULL, 0); - if (!(password = heap_alloc(sizeof(WCHAR) * password_len))) goto done; - MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Password, auth_data->PasswordLength, - password, password_len); - } - } - else - { - domain = auth_data->Domain; - domain_len = auth_data->DomainLength; - - user = auth_data->User; - user_len = auth_data->UserLength; - - password = auth_data->Password; - password_len = auth_data->PasswordLength; - } - - TRACE("Username is %s\n", debugstr_wn(user, user_len)); - TRACE("Domain name is %s\n", debugstr_wn(domain, domain_len)); - - ntlm_cred->username_arg = ntlm_GetUsernameArg(user, user_len); - ntlm_cred->domain_arg = ntlm_GetDomainArg(domain, domain_len); - - if (password_len) - { - ntlm_cred->pwlen = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, - password_len, NULL, 0, NULL, NULL); - if (!(ntlm_cred->password = heap_alloc(ntlm_cred->pwlen))) goto done; - WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len, - ntlm_cred->password, ntlm_cred->pwlen, NULL, NULL); - } - } - - phCredential->dwUpper = fCredentialUse; - phCredential->dwLower = (ULONG_PTR)ntlm_cred; - TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n", phCredential->dwUpper, - phCredential->dwLower); - ret = SEC_E_OK; - break; - - case SECPKG_CRED_BOTH: - FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n"); - ret = SEC_E_UNSUPPORTED_FUNCTION; - break; - - default: - ret = SEC_E_UNKNOWN_CREDENTIALS; - } - -done: - if (auth_data && (auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)) - { - heap_free(domain); - heap_free(user); - heap_free(password); - } - if (ret != SEC_E_OK) heap_free( ntlm_cred ); - - return ret; -} - -/*********************************************************************** - * AcquireCredentialsHandleA - */ -static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA( - SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, - PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, - PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY; - int user_sizeW, domain_sizeW, passwd_sizeW; - SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL; - PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL; - PSEC_WINNT_AUTH_IDENTITY_A id = NULL; - - TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", - debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, - pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - - if (pszPackage) - { - int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, NULL, 0); - if (!(package = heap_alloc(package_sizeW * sizeof(SEC_WCHAR)))) return SEC_E_INSUFFICIENT_MEMORY; - MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW); - } - - if (pAuthData) - { - id = pAuthData; - if (id->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) - { - if (!(pAuthDataW = heap_alloc(sizeof(SEC_WINNT_AUTH_IDENTITY_W)))) goto done; - - if (!id->UserLength) user_sizeW = 0; - else - { - user_sizeW = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->User, id->UserLength, NULL, 0); - if (!(user = heap_alloc(user_sizeW * sizeof(SEC_WCHAR)))) goto done; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->User, id->UserLength, user, user_sizeW); - } - - if (!id->DomainLength) domain_sizeW = 0; - else - { - domain_sizeW = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->Domain, id->DomainLength, NULL, 0); - if (!(domain = heap_alloc(domain_sizeW * sizeof(SEC_WCHAR)))) goto done; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->Domain, id->DomainLength, domain, domain_sizeW); - } - - if (!id->PasswordLength) passwd_sizeW = 0; - else - { - passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->Password, id->PasswordLength, NULL, 0); - if (!(passwd = heap_alloc(passwd_sizeW * sizeof(SEC_WCHAR)))) goto done; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)id->Password, id->PasswordLength, passwd, passwd_sizeW); - } - - pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; - pAuthDataW->User = user; - pAuthDataW->UserLength = user_sizeW; - pAuthDataW->Domain = domain; - pAuthDataW->DomainLength = domain_sizeW; - pAuthDataW->Password = passwd; - pAuthDataW->PasswordLength = passwd_sizeW; - } - else pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)id; - } - - ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse, - pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential, - ptsExpiry); - -done: - heap_free(package); - heap_free(user); - heap_free(domain); - heap_free(passwd); - if (pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)id) heap_free(pAuthDataW); - - return ret; -} - -/************************************************************************* - * ntlm_GetTokenBufferIndex - * Calculates the index of the secbuffer with BufferType == SECBUFFER_TOKEN - * Returns index if found or -1 if not found. - */ -static int ntlm_GetTokenBufferIndex(PSecBufferDesc pMessage) -{ - UINT i; - - TRACE("%p\n", pMessage); - - for( i = 0; i < pMessage->cBuffers; ++i ) - { - if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) - return i; - } - - return -1; -} - -/************************************************************************* - * ntlm_GetDataBufferIndex - * Calculates the index of the first secbuffer with BufferType == SECBUFFER_DATA - * Returns index if found or -1 if not found. - */ -static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage) -{ - UINT i; - - TRACE("%p\n", pMessage); - - for( i = 0; i < pMessage->cBuffers; ++i ) - { - if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA) - return i; - } - - return -1; -} - -static BOOL ntlm_GetCachedCredential(const SEC_WCHAR *pszTargetName, PCREDENTIALW *cred) -{ - LPCWSTR p; - LPCWSTR pszHost; - LPWSTR pszHostOnly; - BOOL ret; - - if (!pszTargetName) - return FALSE; - - /* try to get the start of the hostname from service principal name (SPN) */ - pszHost = strchrW(pszTargetName, '/'); - if (pszHost) - { - /* skip slash character */ - pszHost++; - - /* find end of host by detecting start of instance port or start of referrer */ - p = strchrW(pszHost, ':'); - if (!p) - p = strchrW(pszHost, '/'); - if (!p) - p = pszHost + strlenW(pszHost); - } - else /* otherwise not an SPN, just a host */ - { - pszHost = pszTargetName; - p = pszHost + strlenW(pszHost); - } - - if (!(pszHostOnly = heap_alloc((p - pszHost + 1) * sizeof(WCHAR)))) return FALSE; - memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR)); - pszHostOnly[p - pszHost] = '\0'; - - ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred); - - heap_free(pszHostOnly); - return ret; -} - -/*********************************************************************** - * InitializeSecurityContextW - */ -static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( - PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, - ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, - PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, - PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret; - PNtlmCredentials ntlm_cred; - PNegoHelper helper = NULL; - ULONG ctxt_attr = 0; - char* buffer, *want_flags = NULL; - PBYTE bin; - int buffer_len, bin_len, max_len = NTLM_MAX_BUF; - int token_idx; - SEC_CHAR *username = NULL; - SEC_CHAR *domain = NULL; - SEC_CHAR *password = NULL; - - TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext, - debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, - Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); - - /**************************************** - * When communicating with the client, there can be the - * following reply packets: - * YR <base64 blob> should be sent to the server - * PW should be sent back to helper with - * base64 encoded password - * AF <base64 blob> client is done, blob should be - * sent to server with KK prefixed - * GF <string list> A string list of negotiated flags - * GK <base64 blob> base64 encoded session key - * BH <char reason> something broke - */ - /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */ - - if(TargetDataRep == SECURITY_NETWORK_DREP){ - TRACE("Setting SECURITY_NETWORK_DREP\n"); - } - - buffer = heap_alloc(sizeof(char) * NTLM_MAX_BUF); - bin = heap_alloc(sizeof(BYTE) * NTLM_MAX_BUF); - - if((phContext == NULL) && (pInput == NULL)) - { - static char helper_protocol[] = "--helper-protocol=ntlmssp-client-1"; - static CHAR credentials_argv[] = "--use-cached-creds"; - SEC_CHAR *client_argv[5]; - int pwlen = 0; - - TRACE("First time in ISC()\n"); - - if(!phCredential) - { - ret = SEC_E_INVALID_HANDLE; - goto isc_end; - } - - /* As the server side of sspi never calls this, make sure that - * the handler is a client handler. - */ - ntlm_cred = (PNtlmCredentials)phCredential->dwLower; - if(ntlm_cred->mode != NTLM_CLIENT) - { - TRACE("Cred mode = %d\n", ntlm_cred->mode); - ret = SEC_E_INVALID_HANDLE; - goto isc_end; - } - - client_argv[0] = ntlm_auth; - client_argv[1] = helper_protocol; - if (!ntlm_cred->username_arg && !ntlm_cred->domain_arg) - { - LPWKSTA_USER_INFO_1 ui = NULL; - NET_API_STATUS status; - PCREDENTIALW cred; - - if (ntlm_GetCachedCredential(pszTargetName, &cred)) - { - LPWSTR p; - p = strchrW(cred->UserName, '\'); - if (p) - { - domain = ntlm_GetDomainArg(cred->UserName, p - cred->UserName); - p++; - } - else - { - domain = ntlm_GetDomainArg(NULL, 0); - p = cred->UserName; - } - - username = ntlm_GetUsernameArg(p, -1); - - if(cred->CredentialBlobSize != 0) - { - pwlen = WideCharToMultiByte(CP_UNIXCP, - WC_NO_BEST_FIT_CHARS, (LPWSTR)cred->CredentialBlob, - cred->CredentialBlobSize / sizeof(WCHAR), NULL, 0, - NULL, NULL); - - password = heap_alloc(pwlen); - WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, - (LPWSTR)cred->CredentialBlob, - cred->CredentialBlobSize / sizeof(WCHAR), - password, pwlen, NULL, NULL); - } - - CredFree(cred); - - client_argv[2] = username; - client_argv[3] = domain; - client_argv[4] = NULL; - } - else - { - status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui); - if (status != NERR_Success || ui == NULL || ntlm_cred->no_cached_credentials) - { - ret = SEC_E_NO_CREDENTIALS; - goto isc_end; - } - username = ntlm_GetUsernameArg(ui->wkui1_username, -1); - NetApiBufferFree(ui); - - TRACE("using cached credentials\n"); - - client_argv[2] = username; - client_argv[3] = credentials_argv; - client_argv[4] = NULL; - } - } - else - { - client_argv[2] = ntlm_cred->username_arg; - client_argv[3] = ntlm_cred->domain_arg; - client_argv[4] = NULL; - } - - if((ret = fork_helper(&helper, ntlm_auth, client_argv)) != SEC_E_OK) - goto isc_end; - - helper->mode = NTLM_CLIENT; - helper->session_key = heap_alloc(16); - if (!helper->session_key) - { - cleanup_helper(helper); - ret = SEC_E_INSUFFICIENT_MEMORY; - goto isc_end; - } - - /* Generate the dummy session key = MD4(MD4(password))*/ - if(password || ntlm_cred->password) - { - SEC_WCHAR *unicode_password; - int passwd_lenW; - - TRACE("Converting password to unicode.\n"); - passwd_lenW = MultiByteToWideChar(CP_ACP, 0, - password ? password : ntlm_cred->password, - password ? pwlen : ntlm_cred->pwlen, - NULL, 0); - unicode_password = heap_alloc(passwd_lenW * sizeof(SEC_WCHAR)); - MultiByteToWideChar(CP_ACP, 0, password ? password : ntlm_cred->password, - password ? pwlen : ntlm_cred->pwlen, unicode_password, passwd_lenW); - - SECUR32_CreateNTLM1SessionKey((PBYTE)unicode_password, - passwd_lenW * sizeof(SEC_WCHAR), helper->session_key); - heap_free(unicode_password); - } - else - memset(helper->session_key, 0, 16); - - /* Allocate space for a maximal string of - * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL - * NTLMSSP_FEATURE_SESSION_KEY" - */ - if (!(want_flags = heap_alloc(73))) - { - cleanup_helper(helper); - ret = SEC_E_INSUFFICIENT_MEMORY; - goto isc_end; - } - lstrcpyA(want_flags, "SF"); - if(fContextReq & ISC_REQ_CONFIDENTIALITY) - { - if(strstr(want_flags, "NTLMSSP_FEATURE_SEAL") == NULL) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); - } - if(fContextReq & ISC_REQ_CONNECTION) - ctxt_attr |= ISC_RET_CONNECTION; - if(fContextReq & ISC_REQ_EXTENDED_ERROR) - ctxt_attr |= ISC_RET_EXTENDED_ERROR; - if(fContextReq & ISC_REQ_INTEGRITY) - { - if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); - } - if(fContextReq & ISC_REQ_MUTUAL_AUTH) - ctxt_attr |= ISC_RET_MUTUAL_AUTH; - if(fContextReq & ISC_REQ_REPLAY_DETECT) - { - if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); - } - if(fContextReq & ISC_REQ_SEQUENCE_DETECT) - { - if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); - } - if(fContextReq & ISC_REQ_STREAM) - FIXME("ISC_REQ_STREAM\n"); - if(fContextReq & ISC_REQ_USE_DCE_STYLE) - ctxt_attr |= ISC_RET_USED_DCE_STYLE; - if(fContextReq & ISC_REQ_DELEGATE) - ctxt_attr |= ISC_RET_DELEGATE; - - /* If no password is given, try to use cached credentials. Fall back to an empty - * password if this failed. */ - if(!password && !ntlm_cred->password) - { - lstrcpynA(buffer, "OK", max_len-1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - /* If the helper replied with "PW", using cached credentials failed */ - if(!strncmp(buffer, "PW", 2)) - { - TRACE("Using cached credentials failed.\n"); - lstrcpynA(buffer, "PW AA==", max_len-1); - } - else /* Just do a noop on the next run */ - lstrcpynA(buffer, "OK", max_len-1); - } - else - { - lstrcpynA(buffer, "PW ", max_len-1); - if((ret = encodeBase64(password ? (unsigned char *)password : (unsigned char *)ntlm_cred->password, - password ? pwlen : ntlm_cred->pwlen, buffer+3, - max_len-3, &buffer_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - - } - - TRACE("Sending to helper: %s\n", debugstr_a(buffer)); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - - TRACE("Helper returned %s\n", debugstr_a(buffer)); - - if(lstrlenA(want_flags) > 2) - { - TRACE("Want flags are %s\n", debugstr_a(want_flags)); - lstrcpynA(buffer, want_flags, max_len-1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) - != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - if(!strncmp(buffer, "BH", 2)) - ERR("Helper doesn't understand new command set. Expect more things to fail.\n"); - } - - lstrcpynA(buffer, "YR", max_len-1); - - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - - TRACE("%s\n", buffer); - - if(strncmp(buffer, "YR ", 3) != 0) - { - /* Something borked */ - TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); - ret = SEC_E_INTERNAL_ERROR; - cleanup_helper(helper); - goto isc_end; - } - if((ret = decodeBase64(buffer+3, buffer_len-3, bin, - max_len-1, &bin_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto isc_end; - } - - /* put the decoded client blob into the out buffer */ - - phNewContext->dwUpper = ctxt_attr; - phNewContext->dwLower = (ULONG_PTR)helper; - - ret = SEC_I_CONTINUE_NEEDED; - } - else - { - int input_token_idx; - - /* handle second call here */ - /* encode server data to base64 */ - if (!pInput || ((input_token_idx = ntlm_GetTokenBufferIndex(pInput)) == -1)) - { - ret = SEC_E_INVALID_TOKEN; - goto isc_end; - } - - if(!phContext) - { - ret = SEC_E_INVALID_HANDLE; - goto isc_end; - } - - /* As the server side of sspi never calls this, make sure that - * the handler is a client handler. - */ - helper = (PNegoHelper)phContext->dwLower; - if(helper->mode != NTLM_CLIENT) - { - TRACE("Helper mode = %d\n", helper->mode); - ret = SEC_E_INVALID_HANDLE; - goto isc_end; - } - - if (!pInput->pBuffers[input_token_idx].pvBuffer) - { - ret = SEC_E_INTERNAL_ERROR; - goto isc_end; - } - - if(pInput->pBuffers[input_token_idx].cbBuffer > max_len) - { - TRACE("pInput->pBuffers[%d].cbBuffer is: %d\n", - input_token_idx, - pInput->pBuffers[input_token_idx].cbBuffer); - ret = SEC_E_INVALID_TOKEN; - goto isc_end; - } - else - bin_len = pInput->pBuffers[input_token_idx].cbBuffer; - - memcpy(bin, pInput->pBuffers[input_token_idx].pvBuffer, bin_len); - - lstrcpynA(buffer, "TT ", max_len-1); - - if((ret = encodeBase64(bin, bin_len, buffer+3, - max_len-3, &buffer_len)) != SEC_E_OK) - goto isc_end; - - TRACE("Server sent: %s\n", debugstr_a(buffer)); - - /* send TT base64 blob to ntlm_auth */ - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - goto isc_end; - - TRACE("Helper replied: %s\n", debugstr_a(buffer)); - - if( (strncmp(buffer, "KK ", 3) != 0) && - (strncmp(buffer, "AF ", 3) !=0)) - { - TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); - ret = SEC_E_INVALID_TOKEN; - goto isc_end; - } - - /* decode the blob and send it to server */ - if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, - &bin_len)) != SEC_E_OK) - { - goto isc_end; - } - - phNewContext->dwUpper = ctxt_attr; - phNewContext->dwLower = (ULONG_PTR)helper; - - ret = SEC_E_OK; - } - - /* put the decoded client blob into the out buffer */ - - if (!pOutput || ((token_idx = ntlm_GetTokenBufferIndex(pOutput)) == -1)) - { - TRACE("no SECBUFFER_TOKEN buffer could be found\n"); - ret = SEC_E_BUFFER_TOO_SMALL; - if ((phContext == NULL) && (pInput == NULL)) - { - cleanup_helper(helper); - phNewContext->dwUpper = 0; - phNewContext->dwLower = 0; - } - goto isc_end; - } - - if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) - { - pOutput->pBuffers[token_idx].pvBuffer = heap_alloc(bin_len); - pOutput->pBuffers[token_idx].cbBuffer = bin_len; - } - else if (pOutput->pBuffers[token_idx].cbBuffer < bin_len) - { - TRACE("out buffer is NULL or has not enough space\n"); - ret = SEC_E_BUFFER_TOO_SMALL; - if ((phContext == NULL) && (pInput == NULL)) - { - cleanup_helper(helper); - phNewContext->dwUpper = 0; - phNewContext->dwLower = 0; - } - goto isc_end; - } - - if (!pOutput->pBuffers[token_idx].pvBuffer) - { - TRACE("out buffer is NULL\n"); - ret = SEC_E_INTERNAL_ERROR; - if ((phContext == NULL) && (pInput == NULL)) - { - cleanup_helper(helper); - phNewContext->dwUpper = 0; - phNewContext->dwLower = 0; - } - goto isc_end; - } - - pOutput->pBuffers[token_idx].cbBuffer = bin_len; - memcpy(pOutput->pBuffers[token_idx].pvBuffer, bin, bin_len); - - if(ret == SEC_E_OK) - { - TRACE("Getting negotiated flags\n"); - lstrcpynA(buffer, "GF", max_len - 1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - goto isc_end; - - if(buffer_len < 3) - { - TRACE("No flags negotiated.\n"); - helper->neg_flags = 0l; - } - else - { - TRACE("Negotiated %s\n", debugstr_a(buffer)); - sscanf(buffer + 3, "%x", &(helper->neg_flags)); - TRACE("Stored 0x%08x as flags\n", helper->neg_flags); - } - - TRACE("Getting session key\n"); - lstrcpynA(buffer, "GK", max_len - 1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - goto isc_end; - - if(strncmp(buffer, "BH", 2) == 0) - TRACE("No key negotiated.\n"); - else if(strncmp(buffer, "GK ", 3) == 0) - { - if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, - &bin_len)) != SEC_E_OK) - { - TRACE("Failed to decode session key\n"); - } - TRACE("Session key is %s\n", debugstr_a(buffer+3)); - heap_free(helper->session_key); - if (!(helper->session_key = heap_alloc(bin_len))) - { - ret = SEC_E_INSUFFICIENT_MEMORY; - goto isc_end; - } - memcpy(helper->session_key, bin, bin_len); - } - - helper->crypt.ntlm.a4i = SECUR32_arc4Alloc(); - SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16); - helper->crypt.ntlm.seq_num = 0l; - SECUR32_CreateNTLM2SubKeys(helper); - helper->crypt.ntlm2.send_a4i = SECUR32_arc4Alloc(); - helper->crypt.ntlm2.recv_a4i = SECUR32_arc4Alloc(); - SECUR32_arc4Init(helper->crypt.ntlm2.send_a4i, - helper->crypt.ntlm2.send_seal_key, 16); - SECUR32_arc4Init(helper->crypt.ntlm2.recv_a4i, - helper->crypt.ntlm2.recv_seal_key, 16); - helper->crypt.ntlm2.send_seq_no = 0l; - helper->crypt.ntlm2.recv_seq_no = 0l; - } - -isc_end: - heap_free(username); - heap_free(domain); - heap_free(password); - heap_free(want_flags); - heap_free(buffer); - heap_free(bin); - return ret; -} - -/*********************************************************************** - * InitializeSecurityContextA - */ -static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( - PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, - ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, - PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, - PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret; - SEC_WCHAR *target = NULL; - - TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext, - debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, - Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); - - if (pszTargetName) - { - int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, NULL, 0); - if (!(target = heap_alloc(target_size * sizeof(SEC_WCHAR)))) return SEC_E_INSUFFICIENT_MEMORY; - MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, target, target_size); - } - - ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target, - fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, - phNewContext, pOutput, pfContextAttr, ptsExpiry); - - heap_free(target); - return ret; -} - -/*********************************************************************** - * AcceptSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext( - PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, - ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, - PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret; - char *buffer, *want_flags = NULL; - PBYTE bin; - int buffer_len, bin_len, max_len = NTLM_MAX_BUF; - ULONG ctxt_attr = 0; - PNegoHelper helper; - PNtlmCredentials ntlm_cred; - - TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput, - fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, - ptsExpiry); - - buffer = heap_alloc(sizeof(char) * NTLM_MAX_BUF); - bin = heap_alloc(sizeof(BYTE) * NTLM_MAX_BUF); - - if(TargetDataRep == SECURITY_NETWORK_DREP){ - TRACE("Using SECURITY_NETWORK_DREP\n"); - } - - if(phContext == NULL) - { - static CHAR server_helper_protocol[] = "--helper-protocol=squid-2.5-ntlmssp"; - SEC_CHAR *server_argv[] = { ntlm_auth, - server_helper_protocol, - NULL }; - - if (!phCredential) - { - ret = SEC_E_INVALID_HANDLE; - goto asc_end; - } - - ntlm_cred = (PNtlmCredentials)phCredential->dwLower; - - if(ntlm_cred->mode != NTLM_SERVER) - { - ret = SEC_E_INVALID_HANDLE; - goto asc_end; - } - - /* This is the first call to AcceptSecurityHandle */ - if(pInput == NULL) - { - ret = SEC_E_INCOMPLETE_MESSAGE; - goto asc_end; - } - - if(pInput->cBuffers < 1) - { - ret = SEC_E_INCOMPLETE_MESSAGE; - goto asc_end; - } - - if(pInput->pBuffers[0].cbBuffer > max_len) - { - ret = SEC_E_INVALID_TOKEN; - goto asc_end; - } - else - bin_len = pInput->pBuffers[0].cbBuffer; - - if( (ret = fork_helper(&helper, ntlm_auth, server_argv)) != - SEC_E_OK) - { - ret = SEC_E_INTERNAL_ERROR; - goto asc_end; - } - helper->mode = NTLM_SERVER; - - /* Handle all the flags */ - if (!(want_flags = heap_alloc(73))) - { - TRACE("Failed to allocate memory for the want_flags!\n"); - ret = SEC_E_INSUFFICIENT_MEMORY; - cleanup_helper(helper); - goto asc_end; - } - lstrcpyA(want_flags, "SF"); - if(fContextReq & ASC_REQ_ALLOCATE_MEMORY) - { - FIXME("ASC_REQ_ALLOCATE_MEMORY stub\n"); - } - if(fContextReq & ASC_REQ_CONFIDENTIALITY) - { - lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); - } - if(fContextReq & ASC_REQ_CONNECTION) - { - /* This is default, so we'll enable it */ - lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY"); - ctxt_attr |= ASC_RET_CONNECTION; - } - if(fContextReq & ASC_REQ_EXTENDED_ERROR) - { - FIXME("ASC_REQ_EXTENDED_ERROR stub\n"); - } - if(fContextReq & ASC_REQ_INTEGRITY) - { - lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); - } - if(fContextReq & ASC_REQ_MUTUAL_AUTH) - { - FIXME("ASC_REQ_MUTUAL_AUTH stub\n"); - } - if(fContextReq & ASC_REQ_REPLAY_DETECT) - { - FIXME("ASC_REQ_REPLAY_DETECT stub\n"); - } - if(fContextReq & ISC_REQ_SEQUENCE_DETECT) - { - FIXME("ASC_REQ_SEQUENCE_DETECT stub\n"); - } - if(fContextReq & ISC_REQ_STREAM) - { - FIXME("ASC_REQ_STREAM stub\n"); - } - /* Done with the flags */ - - if(lstrlenA(want_flags) > 3) - { - TRACE("Server set want_flags: %s\n", debugstr_a(want_flags)); - lstrcpynA(buffer, want_flags, max_len - 1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != - SEC_E_OK) - { - cleanup_helper(helper); - goto asc_end; - } - if(!strncmp(buffer, "BH", 2)) - TRACE("Helper doesn't understand new command set\n"); - } - - /* This is the YR request from the client, encode to base64 */ - - memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len); - - lstrcpynA(buffer, "YR ", max_len-1); - - if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3, - &buffer_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto asc_end; - } - - TRACE("Client sent: %s\n", debugstr_a(buffer)); - - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != - SEC_E_OK) - { - cleanup_helper(helper); - goto asc_end; - } - - TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer)); - /* The expected answer is TT <base64 blob> */ - - if(strncmp(buffer, "TT ", 3) != 0) - { - ret = SEC_E_INTERNAL_ERROR; - cleanup_helper(helper); - goto asc_end; - } - - if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, - &bin_len)) != SEC_E_OK) - { - cleanup_helper(helper); - goto asc_end; - } - - /* send this to the client */ - if(pOutput == NULL) - { - ret = SEC_E_INSUFFICIENT_MEMORY; - cleanup_helper(helper); - goto asc_end; - } - - if(pOutput->cBuffers < 1) - { - ret = SEC_E_INSUFFICIENT_MEMORY; - cleanup_helper(helper); - goto asc_end; - } - - pOutput->pBuffers[0].cbBuffer = bin_len; - pOutput->pBuffers[0].BufferType = SECBUFFER_DATA; - memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len); - ret = SEC_I_CONTINUE_NEEDED; - - } - else - { - /* we expect a KK request from client */ - if(pInput == NULL) - { - ret = SEC_E_INCOMPLETE_MESSAGE; - goto asc_end; - } - - if(pInput->cBuffers < 1) - { - ret = SEC_E_INCOMPLETE_MESSAGE; - goto asc_end; - } - - helper = (PNegoHelper)phContext->dwLower; - - if(helper->mode != NTLM_SERVER) - { - ret = SEC_E_INVALID_HANDLE; - goto asc_end; - } - - if(pInput->pBuffers[0].cbBuffer > max_len) - { - ret = SEC_E_INVALID_TOKEN; - goto asc_end; - } - else - bin_len = pInput->pBuffers[0].cbBuffer; - - memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len); - - lstrcpynA(buffer, "KK ", max_len-1); - - if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3, - &buffer_len)) != SEC_E_OK) - { - goto asc_end; - } - - TRACE("Client sent: %s\n", debugstr_a(buffer)); - - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != - SEC_E_OK) - { - goto asc_end; - } - - TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer)); - - /* At this point, we get a NA if the user didn't authenticate, but a BH - * if ntlm_auth could not connect to winbindd. Apart from running Wine - * as root, there is no way to fix this for now, so just handle this as - * a failed login. */ - if(strncmp(buffer, "AF ", 3) != 0) - { - if(strncmp(buffer, "NA ", 3) == 0) - { - ret = SEC_E_LOGON_DENIED; - goto asc_end; - } - else - { - size_t ntlm_pipe_err_v3_len = strlen("BH NT_STATUS_ACCESS_DENIED"); - size_t ntlm_pipe_err_v4_len = strlen("BH NT_STATUS_UNSUCCESSFUL"); - - if( (buffer_len >= ntlm_pipe_err_v3_len && - strncmp(buffer, "BH NT_STATUS_ACCESS_DENIED", ntlm_pipe_err_v3_len) == 0) || - (buffer_len >= ntlm_pipe_err_v4_len && - strncmp(buffer, "BH NT_STATUS_UNSUCCESSFUL", ntlm_pipe_err_v4_len) == 0) ) - { - TRACE("Connection to winbindd failed\n"); - ret = SEC_E_LOGON_DENIED; - } - else - ret = SEC_E_INTERNAL_ERROR; - - goto asc_end; - } - } - pOutput->pBuffers[0].cbBuffer = 0; - - TRACE("Getting negotiated flags\n"); - lstrcpynA(buffer, "GF", max_len - 1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - goto asc_end; - - if(buffer_len < 3) - { - TRACE("No flags negotiated, or helper does not support GF command\n"); - } - else - { - TRACE("Negotiated %s\n", debugstr_a(buffer)); - sscanf(buffer + 3, "%x", &(helper->neg_flags)); - TRACE("Stored 0x%08x as flags\n", helper->neg_flags); - } - - TRACE("Getting session key\n"); - lstrcpynA(buffer, "GK", max_len - 1); - if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) - goto asc_end; - - if(buffer_len < 3) - TRACE("Helper does not support GK command\n"); - else - { - if(strncmp(buffer, "BH ", 3) == 0) - { - TRACE("Helper sent %s\n", debugstr_a(buffer+3)); - heap_free(helper->session_key); - if (!(helper->session_key = heap_alloc(16))) - { - ret = SEC_E_INSUFFICIENT_MEMORY; - goto asc_end; - } - /*FIXME: Generate the dummy session key = MD4(MD4(password))*/ - memset(helper->session_key, 0 , 16); - } - else if(strncmp(buffer, "GK ", 3) == 0) - { - if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, - &bin_len)) != SEC_E_OK) - { - TRACE("Failed to decode session key\n"); - } - TRACE("Session key is %s\n", debugstr_a(buffer+3)); - heap_free(helper->session_key); - if (!(helper->session_key = heap_alloc(16))) - { - ret = SEC_E_INSUFFICIENT_MEMORY; - goto asc_end; - } - memcpy(helper->session_key, bin, 16); - } - } - helper->crypt.ntlm.a4i = SECUR32_arc4Alloc(); - SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16); - helper->crypt.ntlm.seq_num = 0l; - } - - phNewContext->dwUpper = ctxt_attr; - phNewContext->dwLower = (ULONG_PTR)helper; - -asc_end: - heap_free(want_flags); - heap_free(buffer); - heap_free(bin); - return ret; -} - -/*********************************************************************** - * CompleteAuthToken - */ -static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, - PSecBufferDesc pToken) -{ - /* We never need to call CompleteAuthToken anyway */ - TRACE("%p %p\n", phContext, pToken); - if (!phContext) - return SEC_E_INVALID_HANDLE; - - return SEC_E_OK; -} - -/*********************************************************************** - * DeleteSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) -{ - PNegoHelper helper; - - TRACE("%p\n", phContext); - if (!phContext) - return SEC_E_INVALID_HANDLE; - - helper = (PNegoHelper)phContext->dwLower; - - phContext->dwUpper = 0; - phContext->dwLower = 0; - - SECUR32_arc4Cleanup(helper->crypt.ntlm.a4i); - SECUR32_arc4Cleanup(helper->crypt.ntlm2.send_a4i); - SECUR32_arc4Cleanup(helper->crypt.ntlm2.recv_a4i); - heap_free(helper->crypt.ntlm2.send_sign_key); - heap_free(helper->crypt.ntlm2.send_seal_key); - heap_free(helper->crypt.ntlm2.recv_sign_key); - heap_free(helper->crypt.ntlm2.recv_seal_key); - - cleanup_helper(helper); - - return SEC_E_OK; -} - -#define NTLM_COMMENT \ - { 'N', 'T', 'L', 'M', ' ', \ - 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \ - 'P', 'a', 'c', 'k', 'a', 'g', 'e', 0} - -static CHAR ntlm_comment_A[] = NTLM_COMMENT; -static WCHAR ntlm_comment_W[] = NTLM_COMMENT; - -#define NTLM_NAME {'N', 'T', 'L', 'M', 0} - -static char ntlm_name_A[] = NTLM_NAME; -static WCHAR ntlm_name_W[] = NTLM_NAME; - -#define NTLM_CAPS ( \ - SECPKG_FLAG_INTEGRITY | \ - SECPKG_FLAG_PRIVACY | \ - SECPKG_FLAG_TOKEN_ONLY | \ - SECPKG_FLAG_CONNECTION | \ - SECPKG_FLAG_MULTI_REQUIRED | \ - SECPKG_FLAG_IMPERSONATION | \ - SECPKG_FLAG_ACCEPT_WIN32_NAME | \ - SECPKG_FLAG_NEGOTIABLE | \ - SECPKG_FLAG_LOGON | \ - SECPKG_FLAG_RESTRICTED_TOKENS ) - -static const SecPkgInfoW infoW = { - NTLM_CAPS, - 1, - RPC_C_AUTHN_WINNT, - NTLM_MAX_BUF, - ntlm_name_W, - ntlm_comment_W -}; - -static const SecPkgInfoA infoA = { - NTLM_CAPS, - 1, - RPC_C_AUTHN_WINNT, - NTLM_MAX_BUF, - ntlm_name_A, - ntlm_comment_A -}; - -static SecPkgInfoA *ntlm_package_infoA = (SecPkgInfoA *)&infoA; -static SecPkgInfoW *ntlm_package_infoW = (SecPkgInfoW *)&infoW; - -static SecPkgInfoW *build_package_infoW( const SecPkgInfoW *info ) -{ - SecPkgInfoW *ret; - DWORD size_name = (strlenW(info->Name) + 1) * sizeof(WCHAR); - DWORD size_comment = (strlenW(info->Comment) + 1) * sizeof(WCHAR); - - if (!(ret = heap_alloc( sizeof(*ret) + size_name + size_comment ))) return NULL; - ret->fCapabilities = info->fCapabilities; - ret->wVersion = info->wVersion; - ret->wRPCID = info->wRPCID; - ret->cbMaxToken = info->cbMaxToken; - ret->Name = (SEC_WCHAR *)(ret + 1); - memcpy( ret->Name, info->Name, size_name ); - ret->Comment = (SEC_WCHAR *)((char *)ret->Name + size_name); - memcpy( ret->Comment, info->Comment, size_comment ); - return ret; -} - -static SecPkgInfoA *build_package_infoA( const SecPkgInfoA *info ) -{ - SecPkgInfoA *ret; - DWORD size_name = strlen(info->Name) + 1, size_comment = strlen(info->Comment) + 1; - - if (!(ret = heap_alloc( sizeof(*ret) + size_name + size_comment ))) return NULL; - ret->fCapabilities = info->fCapabilities; - ret->wVersion = info->wVersion; - ret->wRPCID = info->wRPCID; - ret->cbMaxToken = info->cbMaxToken; - ret->Name = (SEC_CHAR *)(ret + 1); - memcpy( ret->Name, info->Name, size_name ); - ret->Comment = ret->Name + size_name; - memcpy( ret->Comment, info->Comment, size_comment ); - return ret; -} - -/*********************************************************************** - * QueryContextAttributesW - */ -static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, - ULONG ulAttribute, void *pBuffer) -{ - TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer); - if (!phContext) - return SEC_E_INVALID_HANDLE; - - switch(ulAttribute) - { -#define _x(x) case (x) : FIXME(#x" stub\n"); break - _x(SECPKG_ATTR_ACCESS_TOKEN); - _x(SECPKG_ATTR_AUTHORITY); - _x(SECPKG_ATTR_DCE_INFO); - case SECPKG_ATTR_FLAGS: - { - PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer; - PNegoHelper helper = (PNegoHelper)phContext->dwLower; - - spcf->Flags = 0; - if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - spcf->Flags |= ISC_RET_INTEGRITY; - if(helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) - spcf->Flags |= ISC_RET_CONFIDENTIALITY; - return SEC_E_OK; - } - _x(SECPKG_ATTR_KEY_INFO); - _x(SECPKG_ATTR_LIFESPAN); - _x(SECPKG_ATTR_NAMES); - _x(SECPKG_ATTR_NATIVE_NAMES); - case SECPKG_ATTR_NEGOTIATION_INFO: - { - SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)pBuffer; - if (!(info->PackageInfo = build_package_infoW( &infoW ))) return SEC_E_INSUFFICIENT_MEMORY; - info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; - return SEC_E_OK; - } - _x(SECPKG_ATTR_PACKAGE_INFO); - _x(SECPKG_ATTR_PASSWORD_EXPIRY); - _x(SECPKG_ATTR_SESSION_KEY); - case SECPKG_ATTR_SIZES: - { - PSecPkgContext_Sizes spcs = (PSecPkgContext_Sizes)pBuffer; - spcs->cbMaxToken = NTLM_MAX_BUF; - spcs->cbMaxSignature = 16; - spcs->cbBlockSize = 0; - spcs->cbSecurityTrailer = 16; - return SEC_E_OK; - } - _x(SECPKG_ATTR_STREAM_SIZES); - _x(SECPKG_ATTR_TARGET_INFORMATION); -#undef _x - default: - TRACE("Unknown value %d passed for ulAttribute\n", ulAttribute); - } - - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * QueryContextAttributesA - */ -static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, - ULONG ulAttribute, void *pBuffer) -{ - switch(ulAttribute) - { - case SECPKG_ATTR_NEGOTIATION_INFO: - { - SecPkgContext_NegotiationInfoA *info = (SecPkgContext_NegotiationInfoA *)pBuffer; - if (!(info->PackageInfo = build_package_infoA( &infoA ))) return SEC_E_INSUFFICIENT_MEMORY; - info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; - return SEC_E_OK; - } - default: - return ntlm_QueryContextAttributesW( phContext, ulAttribute, pBuffer ); - } -} - -/*********************************************************************** - * ImpersonateSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext) -{ - SECURITY_STATUS ret; - - TRACE("%p\n", phContext); - if (phContext) - { - ret = SEC_E_UNSUPPORTED_FUNCTION; - } - else - { - ret = SEC_E_INVALID_HANDLE; - } - return ret; -} - -/*********************************************************************** - * RevertSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext) -{ - SECURITY_STATUS ret; - - TRACE("%p\n", phContext); - if (phContext) - { - ret = SEC_E_UNSUPPORTED_FUNCTION; - } - else - { - ret = SEC_E_INVALID_HANDLE; - } - return ret; -} - -/*********************************************************************** - * ntlm_CreateSignature - * As both MakeSignature and VerifySignature need this, but different keys - * are needed for NTLM2, the logic goes into a helper function. - * To ensure maximal reusability, we can specify the direction as NTLM_SEND for - * signing/encrypting and NTLM_RECV for verifying/decrypting. When encrypting, - * the signature is encrypted after the message was encrypted, so - * CreateSignature shouldn't do it. In this case, encrypt_sig can be set to - * false. - */ -static SECURITY_STATUS ntlm_CreateSignature(PNegoHelper helper, PSecBufferDesc pMessage, - int token_idx, SignDirection direction, BOOL encrypt_sig) -{ - ULONG sign_version = 1; - UINT i; - PBYTE sig; - TRACE("%p, %p, %d, %d, %d\n", helper, pMessage, token_idx, direction, - encrypt_sig); - - sig = pMessage->pBuffers[token_idx].pvBuffer; - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && - helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - { - BYTE digest[16]; - BYTE seq_no[4]; - HMAC_MD5_CTX hmac_md5_ctx; - - TRACE("Signing NTLM2 style\n"); - - if(direction == NTLM_SEND) - { - seq_no[0] = (helper->crypt.ntlm2.send_seq_no >> 0) & 0xff; - seq_no[1] = (helper->crypt.ntlm2.send_seq_no >> 8) & 0xff; - seq_no[2] = (helper->crypt.ntlm2.send_seq_no >> 16) & 0xff; - seq_no[3] = (helper->crypt.ntlm2.send_seq_no >> 24) & 0xff; - - ++(helper->crypt.ntlm2.send_seq_no); - - HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.send_sign_key, 16); - } - else - { - seq_no[0] = (helper->crypt.ntlm2.recv_seq_no >> 0) & 0xff; - seq_no[1] = (helper->crypt.ntlm2.recv_seq_no >> 8) & 0xff; - seq_no[2] = (helper->crypt.ntlm2.recv_seq_no >> 16) & 0xff; - seq_no[3] = (helper->crypt.ntlm2.recv_seq_no >> 24) & 0xff; - - ++(helper->crypt.ntlm2.recv_seq_no); - - HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.recv_sign_key, 16); - } - - HMACMD5Update(&hmac_md5_ctx, seq_no, 4); - for( i = 0; i < pMessage->cBuffers; ++i ) - { - if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) - HMACMD5Update(&hmac_md5_ctx, pMessage->pBuffers[i].pvBuffer, - pMessage->pBuffers[i].cbBuffer); - } - - HMACMD5Final(&hmac_md5_ctx, digest); - - if(encrypt_sig && helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE) - { - if(direction == NTLM_SEND) - SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, digest, 8); - else - SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, digest, 8); - } - - /* The NTLM2 signature is the sign version */ - sig[ 0] = (sign_version >> 0) & 0xff; - sig[ 1] = (sign_version >> 8) & 0xff; - sig[ 2] = (sign_version >> 16) & 0xff; - sig[ 3] = (sign_version >> 24) & 0xff; - /* The first 8 bytes of the digest */ - memcpy(sig+4, digest, 8); - /* And the sequence number */ - memcpy(sig+12, seq_no, 4); - - pMessage->pBuffers[token_idx].cbBuffer = 16; - - return SEC_E_OK; - } - if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - { - ULONG crc = 0U; - TRACE("Signing NTLM1 style\n"); - - for(i=0; i < pMessage->cBuffers; ++i) - { - if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) - crc = RtlComputeCrc32(crc, pMessage->pBuffers[i].pvBuffer, pMessage->pBuffers[i].cbBuffer); - } - - sig[ 0] = (sign_version >> 0) & 0xff; - sig[ 1] = (sign_version >> 8) & 0xff; - sig[ 2] = (sign_version >> 16) & 0xff; - sig[ 3] = (sign_version >> 24) & 0xff; - memset(sig+4, 0, 4); - sig[ 8] = (crc >> 0) & 0xff; - sig[ 9] = (crc >> 8) & 0xff; - sig[10] = (crc >> 16) & 0xff; - sig[11] = (crc >> 24) & 0xff; - sig[12] = (helper->crypt.ntlm.seq_num >> 0) & 0xff; - sig[13] = (helper->crypt.ntlm.seq_num >> 8) & 0xff; - sig[14] = (helper->crypt.ntlm.seq_num >> 16) & 0xff; - sig[15] = (helper->crypt.ntlm.seq_num >> 24) & 0xff; - - ++(helper->crypt.ntlm.seq_num); - - if(encrypt_sig) - SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12); - return SEC_E_OK; - } - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0) - { - TRACE("Creating a dummy signature.\n"); - /* A dummy signature is 0x01 followed by 15 bytes of 0x00 */ - memset(pMessage->pBuffers[token_idx].pvBuffer, 0, 16); - memset(pMessage->pBuffers[token_idx].pvBuffer, 0x01, 1); - pMessage->pBuffers[token_idx].cbBuffer = 16; - return SEC_E_OK; - } - - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * MakeSignature - */ -static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, - ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) -{ - PNegoHelper helper; - int token_idx; - - TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo); - if (!phContext) - return SEC_E_INVALID_HANDLE; - - if(fQOP) - FIXME("Ignoring fQOP 0x%08x\n", fQOP); - - if(MessageSeqNo) - FIXME("Ignoring MessageSeqNo\n"); - - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) - return SEC_E_INVALID_TOKEN; - - /* If we didn't find a SECBUFFER_TOKEN type buffer */ - if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) - return SEC_E_INVALID_TOKEN; - - if(pMessage->pBuffers[token_idx].cbBuffer < 16) - return SEC_E_BUFFER_TOO_SMALL; - - helper = (PNegoHelper)phContext->dwLower; - TRACE("Negotiated flags are: 0x%08x\n", helper->neg_flags); - - return ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, TRUE); -} - -/*********************************************************************** - * VerifySignature - */ -static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, - PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) -{ - PNegoHelper helper; - UINT i; - int token_idx; - SECURITY_STATUS ret; - SecBufferDesc local_desc; - PSecBuffer local_buff; - BYTE local_sig[16]; - - TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP); - if(!phContext) - return SEC_E_INVALID_HANDLE; - - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) - return SEC_E_INVALID_TOKEN; - - if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) - return SEC_E_INVALID_TOKEN; - - if(pMessage->pBuffers[token_idx].cbBuffer < 16) - return SEC_E_BUFFER_TOO_SMALL; - - if(MessageSeqNo) - FIXME("Ignoring MessageSeqNo\n"); - - helper = (PNegoHelper)phContext->dwLower; - TRACE("Negotiated flags: 0x%08x\n", helper->neg_flags); - - local_buff = heap_alloc(pMessage->cBuffers * sizeof(SecBuffer)); - - local_desc.ulVersion = SECBUFFER_VERSION; - local_desc.cBuffers = pMessage->cBuffers; - local_desc.pBuffers = local_buff; - - for(i=0; i < pMessage->cBuffers; ++i) - { - if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) - { - local_buff[i].BufferType = SECBUFFER_TOKEN; - local_buff[i].cbBuffer = 16; - local_buff[i].pvBuffer = local_sig; - } - else - { - local_buff[i].BufferType = pMessage->pBuffers[i].BufferType; - local_buff[i].cbBuffer = pMessage->pBuffers[i].cbBuffer; - local_buff[i].pvBuffer = pMessage->pBuffers[i].pvBuffer; - } - } - - if((ret = ntlm_CreateSignature(helper, &local_desc, token_idx, NTLM_RECV, TRUE)) != SEC_E_OK) - return ret; - - if(memcmp(((PBYTE)local_buff[token_idx].pvBuffer) + 8, - ((PBYTE)pMessage->pBuffers[token_idx].pvBuffer) + 8, 8)) - ret = SEC_E_MESSAGE_ALTERED; - else - ret = SEC_E_OK; - - heap_free(local_buff); - return ret; - -} - -/*********************************************************************** - * FreeCredentialsHandle - */ -static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential) -{ - if (phCredential) - { - PNtlmCredentials ntlm_cred = (PNtlmCredentials) phCredential->dwLower; - phCredential->dwUpper = 0; - phCredential->dwLower = 0; - if (ntlm_cred->password) memset(ntlm_cred->password, 0, ntlm_cred->pwlen); - heap_free(ntlm_cred->password); - heap_free(ntlm_cred->username_arg); - heap_free(ntlm_cred->domain_arg); - heap_free(ntlm_cred); - } - - return SEC_E_OK; -} - -/*********************************************************************** - * EncryptMessage - */ -static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, - ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) -{ - PNegoHelper helper; - int token_idx, data_idx; - - TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); - - if(!phContext) - return SEC_E_INVALID_HANDLE; - - if(fQOP) - FIXME("Ignoring fQOP\n"); - - if(MessageSeqNo) - FIXME("Ignoring MessageSeqNo\n"); - - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) - return SEC_E_INVALID_TOKEN; - - if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) - return SEC_E_INVALID_TOKEN; - - if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1 ) - return SEC_E_INVALID_TOKEN; - - if(pMessage->pBuffers[token_idx].cbBuffer < 16) - return SEC_E_BUFFER_TOO_SMALL; - - helper = (PNegoHelper) phContext->dwLower; - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && - helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) - { - ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE); - SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, - pMessage->pBuffers[data_idx].pvBuffer, - pMessage->pBuffers[data_idx].cbBuffer); - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE) - SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, - ((BYTE *)pMessage->pBuffers[token_idx].pvBuffer)+4, 8); - } - else - { - PBYTE sig; - ULONG save_flags; - - /* EncryptMessage always produces real signatures, so make sure - * NTLMSSP_NEGOTIATE_SIGN is set*/ - save_flags = helper->neg_flags; - helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE); - helper->neg_flags = save_flags; - - sig = pMessage->pBuffers[token_idx].pvBuffer; - - SECUR32_arc4Process(helper->crypt.ntlm.a4i, - pMessage->pBuffers[data_idx].pvBuffer, - pMessage->pBuffers[data_idx].cbBuffer); - SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12); - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0) - memset(sig+4, 0, 4); - } - return SEC_E_OK; -} - -/*********************************************************************** - * DecryptMessage - */ -static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, - PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) -{ - SECURITY_STATUS ret; - ULONG ntlmssp_flags_save; - PNegoHelper helper; - int token_idx, data_idx; - TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); - - if(!phContext) - return SEC_E_INVALID_HANDLE; - - if(MessageSeqNo) - FIXME("Ignoring MessageSeqNo\n"); - - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) - return SEC_E_INVALID_TOKEN; - - if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) - return SEC_E_INVALID_TOKEN; - - if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1) - return SEC_E_INVALID_TOKEN; - - if(pMessage->pBuffers[token_idx].cbBuffer < 16) - return SEC_E_BUFFER_TOO_SMALL; - - helper = (PNegoHelper) phContext->dwLower; - - if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) - { - SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, - pMessage->pBuffers[data_idx].pvBuffer, - pMessage->pBuffers[data_idx].cbBuffer); - } - else - { - SECUR32_arc4Process(helper->crypt.ntlm.a4i, - pMessage->pBuffers[data_idx].pvBuffer, - pMessage->pBuffers[data_idx].cbBuffer); - } - - /* Make sure we use a session key for the signature check, EncryptMessage - * always does that, even in the dummy case */ - ntlmssp_flags_save = helper->neg_flags; - - helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - ret = ntlm_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP); - - helper->neg_flags = ntlmssp_flags_save; - - return ret; -} - -static const SecurityFunctionTableA ntlmTableA = { - 1, - NULL, /* EnumerateSecurityPackagesA */ - ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ - ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ - ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */ - NULL, /* Reserved2 */ - ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */ - ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ - ntlm_CompleteAuthToken, /* CompleteAuthToken */ - ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ - NULL, /* ApplyControlToken */ - ntlm_QueryContextAttributesA, /* QueryContextAttributesA */ - ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ - ntlm_RevertSecurityContext, /* RevertSecurityContext */ - ntlm_MakeSignature, /* MakeSignature */ - ntlm_VerifySignature, /* VerifySignature */ - FreeContextBuffer, /* FreeContextBuffer */ - NULL, /* QuerySecurityPackageInfoA */ - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ - NULL, /* ExportSecurityContext */ - NULL, /* ImportSecurityContextA */ - NULL, /* AddCredentialsA */ - NULL, /* Reserved8 */ - NULL, /* QuerySecurityContextToken */ - ntlm_EncryptMessage, /* EncryptMessage */ - ntlm_DecryptMessage, /* DecryptMessage */ - NULL, /* SetContextAttributesA */ -}; - -static const SecurityFunctionTableW ntlmTableW = { - 1, - NULL, /* EnumerateSecurityPackagesW */ - ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ - ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ - ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */ - NULL, /* Reserved2 */ - ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */ - ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ - ntlm_CompleteAuthToken, /* CompleteAuthToken */ - ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ - NULL, /* ApplyControlToken */ - ntlm_QueryContextAttributesW, /* QueryContextAttributesW */ - ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ - ntlm_RevertSecurityContext, /* RevertSecurityContext */ - ntlm_MakeSignature, /* MakeSignature */ - ntlm_VerifySignature, /* VerifySignature */ - FreeContextBuffer, /* FreeContextBuffer */ - NULL, /* QuerySecurityPackageInfoW */ - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ - NULL, /* ExportSecurityContext */ - NULL, /* ImportSecurityContextW */ - NULL, /* AddCredentialsW */ - NULL, /* Reserved8 */ - NULL, /* QuerySecurityContextToken */ - ntlm_EncryptMessage, /* EncryptMessage */ - ntlm_DecryptMessage, /* DecryptMessage */ - NULL, /* SetContextAttributesW */ -}; - -void SECUR32_initNTLMSP(void) -{ - PNegoHelper helper; - static CHAR version[] = "--version"; - - SEC_CHAR *args[] = { - ntlm_auth, - version, - NULL }; - - if(fork_helper(&helper, ntlm_auth, args) != SEC_E_OK) - helper = NULL; - else - check_version(helper); - - if( helper && - ((helper->major > MIN_NTLM_AUTH_MAJOR_VERSION) || - (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && - helper->minor > MIN_NTLM_AUTH_MINOR_VERSION) || - (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && - helper->minor == MIN_NTLM_AUTH_MINOR_VERSION && - helper->micro >= MIN_NTLM_AUTH_MICRO_VERSION)) ) - { - SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW, NULL); - SECUR32_addPackages(provider, 1L, ntlm_package_infoA, ntlm_package_infoW); - } - else - { - ERR_(winediag)("%s was not found or is outdated. " - "Make sure that ntlm_auth >= %d.%d.%d is in your path. " - "Usually, you can find it in the winbind package of your distribution.\n", - ntlm_auth, - MIN_NTLM_AUTH_MAJOR_VERSION, - MIN_NTLM_AUTH_MINOR_VERSION, - MIN_NTLM_AUTH_MICRO_VERSION); - - } - cleanup_helper(helper); -} diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index ca0062056d6..5571ac290e1 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -44,65 +44,6 @@ typedef struct _SecurePackage SecureProvider *provider; } SecurePackage;
-typedef enum _helper_mode { - NTLM_SERVER, - NTLM_CLIENT, - NUM_HELPER_MODES -} HelperMode; - -typedef struct tag_arc4_info { - unsigned char x, y; - unsigned char state[256]; -} arc4_info; - -typedef struct _NegoHelper { - pid_t helper_pid; - HelperMode mode; - int pipe_in; - int pipe_out; - int major; - int minor; - int micro; - char *com_buf; - int com_buf_size; - int com_buf_offset; - BYTE *session_key; - ULONG neg_flags; - struct { - struct { - ULONG seq_num; - arc4_info *a4i; - } ntlm; - struct { - BYTE *send_sign_key; - BYTE *send_seal_key; - BYTE *recv_sign_key; - BYTE *recv_seal_key; - ULONG send_seq_no; - ULONG recv_seq_no; - arc4_info *send_a4i; - arc4_info *recv_a4i; - } ntlm2; - } crypt; -} NegoHelper, *PNegoHelper; - -typedef struct _NtlmCredentials -{ - HelperMode mode; - - /* these are all in the Unix codepage */ - char *username_arg; - char *domain_arg; - char *password; /* not nul-terminated */ - int pwlen; - int no_cached_credentials; /* don't try to use cached Samba credentials */ -} NtlmCredentials, *PNtlmCredentials; - -typedef enum _sign_direction { - NTLM_SEND, - NTLM_RECV -} SignDirection; - /* Allocates space for and initializes a new provider. If fnTableA or fnTableW * is non-NULL, assumes the provider is built-in, and if moduleName is non-NULL, * means must load the LSA/user mode functions tables from external SSP/AP module. @@ -136,60 +77,11 @@ PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str) DECLSPEC_HIDDEN; /* Initialization functions for built-in providers */ void SECUR32_initSchannelSP(void) DECLSPEC_HIDDEN; void SECUR32_initNegotiateSP(void) DECLSPEC_HIDDEN; -void SECUR32_initNTLMSP(void) DECLSPEC_HIDDEN; void load_auth_packages(void) DECLSPEC_HIDDEN;
/* Cleanup functions for built-in providers */ void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN;
-/* Functions from dispatcher.c used elsewhere in the code */ -SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog, - char * const argv[]) DECLSPEC_HIDDEN; - -SECURITY_STATUS run_helper(PNegoHelper helper, char *buffer, - unsigned int max_buflen, int *buflen) DECLSPEC_HIDDEN; - -void cleanup_helper(PNegoHelper helper) DECLSPEC_HIDDEN; - -void check_version(PNegoHelper helper) DECLSPEC_HIDDEN; - -/* Functions from base64_codec.c used elsewhere */ -SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf, - int max_len, int *out_len) DECLSPEC_HIDDEN; - -SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf, - int max_len, int *out_len) DECLSPEC_HIDDEN; - -/* Functions from util.c */ -SECURITY_STATUS SECUR32_CreateNTLM1SessionKey(PBYTE password, int len, PBYTE session_key) DECLSPEC_HIDDEN; -SECURITY_STATUS SECUR32_CreateNTLM2SubKeys(PNegoHelper helper) DECLSPEC_HIDDEN; -arc4_info *SECUR32_arc4Alloc(void) DECLSPEC_HIDDEN; -void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen) DECLSPEC_HIDDEN; -void SECUR32_arc4Process(arc4_info *a4i, BYTE *inoutString, unsigned int length) DECLSPEC_HIDDEN; -void SECUR32_arc4Cleanup(arc4_info *a4i) DECLSPEC_HIDDEN; - -/* NTLMSSP flags indicating the negotiated features */ -#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 -#define NTLMSSP_NEGOTIATE_OEM 0x00000002 -#define NTLMSSP_REQUEST_TARGET 0x00000004 -#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 -#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 -#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040 -#define NTLMSSP_NEGOTIATE_LM_SESSION_KEY 0x00000080 -#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 -#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 -#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 -#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000 -#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 -#define NTLMSSP_NEGOTIATE_TARGET_TYPE_DOMAIN 0x00010000 -#define NTLMSSP_NEGOTIATE_TARGET_TYPE_SERVER 0x00020000 -#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 -#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 -#define NTLMSSP_NEGOTIATE_128 0x20000000 -#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000 -#define NTLMSSP_NEGOTIATE_56 0x80000000 - - /* schannel internal interface */ typedef struct schan_imp_session_opaque *schan_imp_session;
diff --git a/dlls/secur32/util.c b/dlls/secur32/util.c deleted file mode 100644 index b5cac5b6c06..00000000000 --- a/dlls/secur32/util.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2006 Kai Blin - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * This file contains various helper functions needed for NTLM and maybe others - */ -#include <stdarg.h> -#include <stdio.h> -#include "windef.h" -#include "winbase.h" -#include "rpc.h" -#include "sspi.h" -#include "secur32_priv.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ntlm); - -static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant"; -static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant"; -static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant"; -static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant"; - -typedef struct -{ - unsigned int buf[4]; - unsigned int i[2]; - unsigned char in[64]; - unsigned char digest[16]; -} MD4_CTX; - -/* And now the same with a different memory layout. */ -typedef struct -{ - unsigned int i[2]; - unsigned int buf[4]; - unsigned char in[64]; - unsigned char digest[16]; -} MD5_CTX; - -VOID WINAPI MD4Init( MD4_CTX *ctx ); -VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len ); -VOID WINAPI MD4Final( MD4_CTX *ctx ); -VOID WINAPI MD5Init( MD5_CTX *ctx ); -VOID WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len ); -VOID WINAPI MD5Final( MD5_CTX *ctx ); - -SECURITY_STATUS SECUR32_CreateNTLM1SessionKey(PBYTE password, int len, PBYTE session_key) -{ - MD4_CTX ctx; - BYTE ntlm_hash[16]; - - TRACE("(%p, %p)\n", password, session_key); - - MD4Init(&ctx); - MD4Update(&ctx, password, len); - MD4Final(&ctx); - - memcpy(ntlm_hash, ctx.digest, 0x10); - - MD4Init(&ctx); - MD4Update(&ctx, ntlm_hash, 0x10u); - MD4Final(&ctx); - - memcpy(session_key, ctx.digest, 0x10); - - return SEC_E_OK; -} - -static void SECUR32_CalcNTLM2Subkey(const BYTE *session_key, const char *magic, PBYTE subkey) -{ - MD5_CTX ctx; - - MD5Init(&ctx); - MD5Update(&ctx, session_key, 16); - MD5Update(&ctx, (const unsigned char*)magic, lstrlenA(magic)+1); - MD5Final(&ctx); - memcpy(subkey, ctx.digest, 16); -} - -/* This assumes we do have a valid NTLM2 user session key */ -SECURITY_STATUS SECUR32_CreateNTLM2SubKeys(PNegoHelper helper) -{ - helper->crypt.ntlm2.send_sign_key = heap_alloc(16); - helper->crypt.ntlm2.send_seal_key = heap_alloc(16); - helper->crypt.ntlm2.recv_sign_key = heap_alloc(16); - helper->crypt.ntlm2.recv_seal_key = heap_alloc(16); - - if(helper->mode == NTLM_CLIENT) - { - SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_sign_constant, - helper->crypt.ntlm2.send_sign_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_seal_constant, - helper->crypt.ntlm2.send_seal_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_sign_constant, - helper->crypt.ntlm2.recv_sign_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_seal_constant, - helper->crypt.ntlm2.recv_seal_key); - } - else - { - SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_sign_constant, - helper->crypt.ntlm2.send_sign_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_seal_constant, - helper->crypt.ntlm2.send_seal_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_sign_constant, - helper->crypt.ntlm2.recv_sign_key); - SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_seal_constant, - helper->crypt.ntlm2.recv_seal_key); - } - - return SEC_E_OK; -} - -arc4_info *SECUR32_arc4Alloc(void) -{ - arc4_info *a4i = heap_alloc(sizeof(arc4_info)); - return a4i; -} - -/* - * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack, - * which in turn is based on public domain code by Wei Dai - */ -void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen) -{ - unsigned int keyIndex = 0, stateIndex = 0; - unsigned int i, a; - - TRACE("(%p, %p, %d)\n", a4i, key, keyLen); - - a4i->x = a4i->y = 0; - - for (i=0; i<256; i++) - a4i->state[i] = i; - - for (i=0; i<256; i++) - { - a = a4i->state[i]; - stateIndex += key[keyIndex] + a; - stateIndex &= 0xff; - a4i->state[i] = a4i->state[stateIndex]; - a4i->state[stateIndex] = a; - if (++keyIndex >= keyLen) - keyIndex = 0; - } - -} - -void SECUR32_arc4Process(arc4_info *a4i, BYTE *inoutString, unsigned int length) -{ - BYTE *const s=a4i->state; - unsigned int x = a4i->x; - unsigned int y = a4i->y; - unsigned int a, b; - - while(length--) - { - x = (x+1) & 0xff; - a = s[x]; - y = (y+a) & 0xff; - b = s[y]; - s[x] = b; - s[y] = a; - *inoutString++ ^= s[(a+b) & 0xff]; - } - - a4i->x = x; - a4i->y = y; -} - -void SECUR32_arc4Cleanup(arc4_info *a4i) -{ - heap_free(a4i); -}
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=89651
Your paranoid android.
=== debiant2 (32 bit report) ===
secur32: negotiate.c:259: Test failed: server returned 80090302, more tests will fail ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE
=== debiant2 (32 bit Chinese:China report) ===
secur32: negotiate.c:259: Test failed: server returned 80090302, more tests will fail ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE
=== debiant2 (32 bit WoW report) ===
secur32: negotiate.c:259: Test failed: server returned 80090302, more tests will fail ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 0 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 3275880 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 4390912 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 2076349658 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE
=== debiant2 (64 bit WoW report) ===
secur32: negotiate.c:259: Test failed: server returned 80090302, more tests will fail ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 6487056 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 0 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 0 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 1779231552 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:901: Test failed: pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned SEC_E_UNSUPPORTED_FUNCTION ntlm.c:904: Test failed: cbMaxToken should be 1904 or 2888 but is 6487056 ntlm.c:907: Test failed: cbMaxSignature should be 16 but is 0 ntlm.c:910: Test failed: cbSecurityTrailer should be 16 but is 0 ntlm.c:913: Test failed: cbBlockSize should be 0 but is 1779231552 ntlm.c:919: Test failed: QueryContextAttributesA returned 80090302 ntlm.c:923: Test failed: expected non-NULL PackageInfo ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE ntlm.c:882: Test failed: Running the server returned SEC_E_UNSUPPORTED_FUNCTION, more tests will fail from now. ntlm.c:959: Test failed: DeleteSecurityContext(server) returned SEC_E_INVALID_HANDLE