From 5ccb04979079188bbc7429b8893bb2ee000ee82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 20 Feb 2017 22:28:07 +0000 Subject: [PATCH] [SECUR32]: As an interim step towards a proper NTLM implementation that is done by Samuel Serapion, I temporarily commit Wine's NTLM code layer around Samba's "ntlm_auth" utility. In addition I add the kerberos & negotiate stubs too. This is not a problem on Wine, because they run on Linux distributions, most of which have Samba available. But this is not the case on Windows / ReactOS, so few adaptations were needed: in the dispatcher.c code, the fork_helper function was partially rewritten around CreateProcess to start the ntlm_auth utility (I try to use maximally the CRT to not have to rewrite other functions). This works great. But then, to make this NTLM layer working on ReactOS, one has to find a Windows build of Samba. Here is one: http://smithii.com/samba . This is a Samba 3.0.23c build. You need to follow *exactly* the manual installation steps to make it work (actually, everything up to "Step 6" included, i.e. running smbsetup.cmd). This means in particular to copy Samba into C:\Program Files\samba, as this path is also hardcoded into the executables. As the Wine's NTLM layer expects Samba 3.0.25+, I manually downgraded the expected version, which appears to still work nice for the needs of Office 2010 installation. You can now play with it and try to install Office 2010. CORE-12601 #comment Wine's NTLM layer committed in r73868 as an interim step towards a proper implementation. CORE-12279 svn path=/trunk/; revision=73868 --- reactos/dll/win32/secur32/CMakeLists.txt | 9 +- reactos/dll/win32/secur32/dllmain.c | 8 + reactos/dll/win32/secur32/secur32_priv.h | 18 + reactos/dll/win32/secur32/sspi.c | 63 +- reactos/dll/win32/secur32/wine/base64_codec.c | 190 ++ reactos/dll/win32/secur32/wine/base64_codec.h | 12 + reactos/dll/win32/secur32/wine/dispatcher.c | 441 ++++ reactos/dll/win32/secur32/wine/dispatcher.h | 16 + reactos/dll/win32/secur32/wine/hmac_md5.c | 77 + reactos/dll/win32/secur32/wine/hmac_md5.h | 48 + reactos/dll/win32/secur32/wine/kerberos.c | 315 +++ reactos/dll/win32/secur32/wine/kerberos.h | 7 + reactos/dll/win32/secur32/wine/negotiate.c | 525 +++++ reactos/dll/win32/secur32/wine/negotiate.h | 7 + reactos/dll/win32/secur32/wine/ntlm.c | 2064 +++++++++++++++++ reactos/dll/win32/secur32/wine/ntlm.h | 116 + reactos/dll/win32/secur32/wine/util.c | 249 ++ reactos/dll/win32/secur32/wine/util.h | 14 + reactos/dll/win32/secur32/wine/wine_supp.h | 9 + 19 files changed, 4184 insertions(+), 4 deletions(-) create mode 100644 reactos/dll/win32/secur32/wine/base64_codec.c create mode 100644 reactos/dll/win32/secur32/wine/base64_codec.h create mode 100644 reactos/dll/win32/secur32/wine/dispatcher.c create mode 100644 reactos/dll/win32/secur32/wine/dispatcher.h create mode 100644 reactos/dll/win32/secur32/wine/hmac_md5.c create mode 100644 reactos/dll/win32/secur32/wine/hmac_md5.h create mode 100644 reactos/dll/win32/secur32/wine/kerberos.c create mode 100644 reactos/dll/win32/secur32/wine/kerberos.h create mode 100644 reactos/dll/win32/secur32/wine/negotiate.c create mode 100644 reactos/dll/win32/secur32/wine/negotiate.h create mode 100644 reactos/dll/win32/secur32/wine/ntlm.c create mode 100644 reactos/dll/win32/secur32/wine/ntlm.h create mode 100644 reactos/dll/win32/secur32/wine/util.c create mode 100644 reactos/dll/win32/secur32/wine/util.h create mode 100644 reactos/dll/win32/secur32/wine/wine_supp.h diff --git a/reactos/dll/win32/secur32/CMakeLists.txt b/reactos/dll/win32/secur32/CMakeLists.txt index ec6cd661e49..f1b696d584d 100644 --- a/reactos/dll/win32/secur32/CMakeLists.txt +++ b/reactos/dll/win32/secur32/CMakeLists.txt @@ -10,6 +10,13 @@ list(APPEND SOURCE stubs.c thunks.c wrapper.c + wine/base64_codec.c + wine/dispatcher.c + wine/hmac_md5.c + wine/kerberos.c + wine/negotiate.c + wine/ntlm.c + wine/util.c precomp.h) add_library(secur32 SHARED @@ -20,6 +27,6 @@ add_library(secur32 SHARED set_module_type(secur32 win32dll UNICODE) target_link_libraries(secur32 lsalib wine) -add_importlibs(secur32 advapi32 msvcrt kernel32 ntdll) +add_importlibs(secur32 advapi32 netapi32 msvcrt kernel32 ntdll) add_pch(secur32 precomp.h SOURCE) add_cd_file(TARGET secur32 DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/secur32/dllmain.c b/reactos/dll/win32/secur32/dllmain.c index b1f71ecc441..cb0fcf2a29a 100644 --- a/reactos/dll/win32/secur32/dllmain.c +++ b/reactos/dll/win32/secur32/dllmain.c @@ -18,6 +18,11 @@ HANDLE Secur32Heap; /* FUNCTIONS *****************************************************************/ +#ifdef __REACTOS__ +// See sspi.c +extern void SECUR32_freeProviders(void); +#endif + BOOL WINAPI DllMain(HINSTANCE hInstance, @@ -36,6 +41,9 @@ DllMain(HINSTANCE hInstance, break; case DLL_PROCESS_DETACH: +#ifdef __REACTOS__ + SECUR32_freeProviders(); +#endif LsapCloseLsaPort(); if (!RtlDestroyHeap(Secur32Heap)) { diff --git a/reactos/dll/win32/secur32/secur32_priv.h b/reactos/dll/win32/secur32/secur32_priv.h index 6c675ae43c8..e7de636b1ea 100644 --- a/reactos/dll/win32/secur32/secur32_priv.h +++ b/reactos/dll/win32/secur32/secur32_priv.h @@ -40,6 +40,24 @@ typedef struct _SecurePackage SecureProvider *provider; } SecurePackage; +/* 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. + * Otherwise moduleName must not be NULL. + * Returns a pointer to the stored provider entry, for use adding packages. + */ +SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, + const SecurityFunctionTableW *fnTableW, PCWSTR moduleName) DECLSPEC_HIDDEN; + +/* Allocates space for and adds toAdd packages with the given provider. + * provider must not be NULL, and either infoA or infoW may be NULL, but not + * both. + */ +void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, + const SecPkgInfoA *infoA, const SecPkgInfoW *infoW) DECLSPEC_HIDDEN; + +#include "wine/wine_supp.h" + /* Tries to find the package named packageName. If it finds it, implicitly * loads the package if it isn't already loaded. */ diff --git a/reactos/dll/win32/secur32/sspi.c b/reactos/dll/win32/secur32/sspi.c index 6fe7806f01f..d97e91ba441 100644 --- a/reactos/dll/win32/secur32/sspi.c +++ b/reactos/dll/win32/secur32/sspi.c @@ -42,6 +42,7 @@ typedef struct _SecureProviderTable } SecureProviderTable; static void SECUR32_initializeProviders(void); +/* static */ void SECUR32_freeProviders(void); static CRITICAL_SECTION cs; static CRITICAL_SECTION_DEBUG cs_debug = @@ -359,7 +360,7 @@ static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA, } } -static +// static SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, const SecurityFunctionTableW *fnTableW, PCWSTR moduleName) { @@ -406,7 +407,7 @@ SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, return ret; } -static +// static void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, const SecPkgInfoA *infoA, const SecPkgInfoW *infoW) { @@ -519,7 +520,6 @@ static const WCHAR securityProvidersW[] = { 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0 }; - /* FIXME: we're missing SECUR32_freeProviders, so all of this gets leaked */ static void SECUR32_initializeProviders(void) { HKEY key; @@ -559,6 +559,19 @@ static void SECUR32_initializeProviders(void) } RegCloseKey(key); } + + /* Now load the built-in providers (in Wine, this is done before the registry loading) */ +#ifdef __REACTOS__ +/// FIXME: Interim Wine code until we get Samuel's rewrite! + /* First load built-in providers */ + SECUR32_initNTLMSP(); + SECUR32_initKerberosSP(); + /* Load the Negotiate provider last so apps stumble over the working NTLM + * provider first. Attempting to fix bug #16905 while keeping the + * application reported on wine-users on 2006-09-12 working. */ + SECUR32_initNegotiateSP(); +#endif + } SecurePackage *SECUR32_findPackageW(PCWSTR packageName) @@ -632,6 +645,50 @@ SecurePackage *SECUR32_findPackageA(PCSTR packageName) return ret; } +/* static */ void SECUR32_freeProviders(void) +{ + TRACE("\n"); + EnterCriticalSection(&cs); + +#ifndef __REACTOS__ + SECUR32_deinitSchannelSP(); +#endif + + if (packageTable) + { + SecurePackage *package, *package_next; + LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table, + SecurePackage, entry) + { + HeapFree(GetProcessHeap(), 0, package->infoW.Name); + HeapFree(GetProcessHeap(), 0, package->infoW.Comment); + HeapFree(GetProcessHeap(), 0, package); + } + + HeapFree(GetProcessHeap(), 0, packageTable); + packageTable = NULL; + } + + if (providerTable) + { + SecureProvider *provider, *provider_next; + LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table, + SecureProvider, entry) + { + HeapFree(GetProcessHeap(), 0, provider->moduleName); + if (provider->lib) + FreeLibrary(provider->lib); + HeapFree(GetProcessHeap(), 0, provider); + } + + HeapFree(GetProcessHeap(), 0, providerTable); + providerTable = NULL; + } + + LeaveCriticalSection(&cs); + DeleteCriticalSection(&cs); +} + /*********************************************************************** * FreeContextBuffer (SECUR32.@) * diff --git a/reactos/dll/win32/secur32/wine/base64_codec.c b/reactos/dll/win32/secur32/wine/base64_codec.c new file mode 100644 index 00000000000..cd97ea41389 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/base64_codec.c @@ -0,0 +1,190 @@ +/* + * 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 "precomp.h" + +#include +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/reactos/dll/win32/secur32/wine/base64_codec.h b/reactos/dll/win32/secur32/wine/base64_codec.h new file mode 100644 index 00000000000..df5c1ff8273 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/base64_codec.h @@ -0,0 +1,12 @@ + +#ifndef __WINE_BASE64_CODEC_H__ +#define __WINE_BASE64_CODEC_H__ + +/* 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; + +#endif /* __WINE_BASE64_CODEC_H__ */ diff --git a/reactos/dll/win32/secur32/wine/dispatcher.c b/reactos/dll/win32/secur32/wine/dispatcher.c new file mode 100644 index 00000000000..e0089a61b27 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/dispatcher.c @@ -0,0 +1,441 @@ +/* + * 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 "precomp.h" + +#include +#include +#include +#include +#include + +#ifdef __REACTOS__ +#define close _close +#define read _read +#define write _write +#endif + +#include +WINE_DEFAULT_DEBUG_CHANNEL(ntlm); + +#define INITIAL_BUFFER_SIZE 200 + +char* flatten_cmdline(const char *prog, char* const argv[]) +{ + int i; + SIZE_T argstr_size = 0; + char *argstr, *p; + + /* Compute space needed for the new string, and allocate it */ + argstr_size += strlen(prog) + 3; // 3 == 2 quotes between 'prog', and 1 space + for(i = 0; argv[i] != NULL; ++i) + { + argstr_size += strlen(argv[i]) + 1; // 1 for space + } + argstr = HeapAlloc(GetProcessHeap(), 0, (argstr_size + 1) * sizeof(CHAR)); + if (argstr == NULL) + { + ERR("ERROR: Not enough memory\n"); + return NULL; + } + + /* Copy the contents and NULL-terminate the string */ + p = argstr; + strcpy(p, "\""); // Open quote + strcat(p, prog); + strcat(p, "\" "); // Close quote + space + p += strlen(p); + for(i = 0; argv[i] != NULL; ++i) + { + strcpy(p, argv[i]); + p += strlen(argv[i]); + *p++ = ' '; + } + *p = '\0'; + + return argstr; +} + +SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog, + char* const argv[]) +{ + int pipe_in[2]; + int pipe_out[2]; +#ifdef __REACTOS__ + HANDLE hPipe; + PROCESS_INFORMATION pi; + STARTUPINFOA si; + char* cmdline; +#endif + int i; + PNegoHelper helper; + + TRACE("%s ", debugstr_a(prog)); + for(i = 0; argv[i] != NULL; ++i) + { + TRACE("%s ", debugstr_a(argv[i])); + } + TRACE("\n"); + +#ifndef __REACTOS__ + +#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 ); + } + +#else + + if (_pipe(pipe_in, 0, _O_BINARY /* _O_TEXT */ | _O_NOINHERIT) < 0) + { + return SEC_E_INTERNAL_ERROR; + } + + if (_pipe(pipe_out, 0, _O_BINARY /* _O_TEXT */ | _O_NOINHERIT) < 0) + { + close(pipe_in[0]); + close(pipe_in[1]); + return SEC_E_INTERNAL_ERROR; + } + +#endif + + if (!(helper = HeapAlloc(GetProcessHeap(),0, sizeof(NegoHelper)))) + { + close(pipe_in[0]); + close(pipe_in[1]); + close(pipe_out[0]); + close(pipe_out[1]); + return SEC_E_INSUFFICIENT_MEMORY; + } + +#ifndef __REACTOS__ + helper->helper_pid = fork(); +#else + + cmdline = flatten_cmdline(prog, argv); + if (!cmdline) + { + close(pipe_in[0]); + close(pipe_in[1]); + close(pipe_out[0]); + close(pipe_out[1]); + HeapFree( GetProcessHeap(), 0, helper ); + return SEC_E_INSUFFICIENT_MEMORY; + } + + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + si.dwFlags |= STARTF_USESTDHANDLES; + + /* The reading side of the pipe is STDIN for this process */ + hPipe = (HANDLE)_get_osfhandle(pipe_out[0]); + SetHandleInformation(hPipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + si.hStdInput = hPipe; + + /* The writing side of the pipe is STDOUT for this process */ + hPipe = (HANDLE)_get_osfhandle(pipe_in[1]); + SetHandleInformation(hPipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + si.hStdOutput = hPipe; + si.hStdError = hPipe; + + if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) + { + /* We fail just afterwards */ + helper->helper_pid = (HANDLE)-1; + } + else + { + helper->helper_pid = pi.hProcess; + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + + HeapFree( GetProcessHeap(), 0, cmdline ); + +#endif + +#ifndef __REACTOS__ + if(helper->helper_pid == -1) +#else + if(helper->helper_pid == (HANDLE)-1) +#endif + { + close(pipe_in[0]); + close(pipe_in[1]); + close(pipe_out[0]); + close(pipe_out[1]); + HeapFree( GetProcessHeap(), 0, helper ); + return SEC_E_INTERNAL_ERROR; + } + +#ifndef __REACTOS__ + 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 +#endif + { + *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]; // Keep in(read) + close(pipe_in[1]); // Close in(write) + helper->pipe_out = pipe_out[1]; // Keep out(write) + close(pipe_out[0]); // Close out(read) + } + + return SEC_E_OK; +} + +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 = HeapAlloc(GetProcessHeap(), 0, INITIAL_BUFFER_SIZE)) == NULL) + 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 = HeapReAlloc(GetProcessHeap(), 0, 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; + + HeapFree(GetProcessHeap(), 0, helper->com_buf); + HeapFree(GetProcessHeap(), 0, helper->session_key); + + /* closing stdin will terminate ntlm_auth */ + close(helper->pipe_out); + close(helper->pipe_in); + +#ifndef __REACTOS__ + +#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 + +#endif + + HeapFree(GetProcessHeap(), 0, 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/reactos/dll/win32/secur32/wine/dispatcher.h b/reactos/dll/win32/secur32/wine/dispatcher.h new file mode 100644 index 00000000000..42f59def532 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/dispatcher.h @@ -0,0 +1,16 @@ + +#ifndef __WINE_DISPATCHER_H__ +#define __WINE_DISPATCHER_H__ + +/* 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; + +#endif /* __WINE_DISPATCHER_H__ */ diff --git a/reactos/dll/win32/secur32/wine/hmac_md5.c b/reactos/dll/win32/secur32/wine/hmac_md5.c new file mode 100644 index 00000000000..3479178132d --- /dev/null +++ b/reactos/dll/win32/secur32/wine/hmac_md5.c @@ -0,0 +1,77 @@ +/* + * 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/reactos/dll/win32/secur32/wine/hmac_md5.h b/reactos/dll/win32/secur32/wine/hmac_md5.h new file mode 100644 index 00000000000..2d5f3bfa184 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/hmac_md5.h @@ -0,0 +1,48 @@ +/* + * 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 +#include + +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/reactos/dll/win32/secur32/wine/kerberos.c b/reactos/dll/win32/secur32/wine/kerberos.c new file mode 100644 index 00000000000..7d7d102f5a7 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/kerberos.c @@ -0,0 +1,315 @@ +/* + * Copyright 2005, 2006 Kai Blin + * Copyright 2016 Jacek Caban for CodeWeavers + * + * 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 + */ + +#include "precomp.h" + +#include + +#include +WINE_DEFAULT_DEBUG_CHANNEL(secur32); + +#define KERBEROS_MAX_BUF 12000 + +/*********************************************************************** + * QueryCredentialsAttributesA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer) +{ + FIXME("(%p %d %p)\n", phCredential, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * QueryCredentialsAttributesW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer) +{ + FIXME("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * AcquireCredentialsHandleW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW(SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, + LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry) +{ + FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); + return SEC_E_NO_CREDENTIALS; +} + +/*********************************************************************** + * AcquireCredentialsHandleA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, + LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry) +{ + FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * InitializeSecurityContextW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW(CredHandle *phCredential, CtxtHandle *phContext, SEC_WCHAR *pszTargetName, + ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext, + SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry) +{ + FIXME("(%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); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * InitializeSecurityContextA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(CredHandle *phCredential, CtxtHandle *phContext, SEC_CHAR *pszTargetName, + ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext, + SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry) +{ + FIXME("%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); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * AcceptSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext(CredHandle *phCredential, CtxtHandle *phContext, SecBufferDesc *pInput, + ULONG fContextReq, ULONG TargetDataRep, CtxtHandle *phNewContext, SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry) +{ + FIXME("(%p %p %p %d %d %p %p %p %p)\n", phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, + pfContextAttr, ptsExpiry); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * CompleteAuthToken + */ +static SECURITY_STATUS SEC_ENTRY kerberos_CompleteAuthToken(CtxtHandle *phContext, SecBufferDesc *pToken) +{ + FIXME("(%p %p)\n", phContext, pToken); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * DeleteSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(CtxtHandle *phContext) +{ + FIXME("(%p)\n", phContext); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * QueryContextAttributesW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer) +{ + FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * QueryContextAttributesA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer) +{ + FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * ImpersonateSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_ImpersonateSecurityContext(CtxtHandle *phContext) +{ + FIXME("(%p)\n", phContext); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * RevertSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_RevertSecurityContext(CtxtHandle *phContext) +{ + FIXME("(%p)\n", phContext); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * MakeSignature + */ +static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo) +{ + FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * VerifySignature + */ +static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * FreeCredentialsHandle + */ +static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCredential) +{ + FIXME("(%p)\n", phCredential); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * EncryptMessage + */ +static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo) +{ + FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * DecryptMessage + */ +static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +static const SecurityFunctionTableA kerberosTableA = { + 1, + NULL, /* EnumerateSecurityPackagesA */ + kerberos_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ + kerberos_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ + kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + kerberos_InitializeSecurityContextA, /* InitializeSecurityContextA */ + kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ + kerberos_CompleteAuthToken, /* CompleteAuthToken */ + kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ + NULL, /* ApplyControlToken */ + kerberos_QueryContextAttributesA, /* QueryContextAttributesA */ + kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + kerberos_RevertSecurityContext, /* RevertSecurityContext */ + kerberos_MakeSignature, /* MakeSignature */ + kerberos_VerifySignature, /* VerifySignature */ + FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoA */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextA */ + NULL, /* AddCredentialsA */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + kerberos_EncryptMessage, /* EncryptMessage */ + kerberos_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesA */ +}; + +static const SecurityFunctionTableW kerberosTableW = { + 1, + NULL, /* EnumerateSecurityPackagesW */ + kerberos_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ + kerberos_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ + kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + kerberos_InitializeSecurityContextW, /* InitializeSecurityContextW */ + kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ + kerberos_CompleteAuthToken, /* CompleteAuthToken */ + kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ + NULL, /* ApplyControlToken */ + kerberos_QueryContextAttributesW, /* QueryContextAttributesW */ + kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + kerberos_RevertSecurityContext, /* RevertSecurityContext */ + kerberos_MakeSignature, /* MakeSignature */ + kerberos_VerifySignature, /* VerifySignature */ + FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoW */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextW */ + NULL, /* AddCredentialsW */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + kerberos_EncryptMessage, /* EncryptMessage */ + kerberos_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesW */ +}; + +#define KERBEROS_COMMENT \ + {'M','i','c','r','o','s','o','f','t',' ','K','e','r','b','e','r','o','s',' ','V','1','.','0',0} +static CHAR kerberos_comment_A[] = KERBEROS_COMMENT; +static WCHAR kerberos_comment_W[] = KERBEROS_COMMENT; + +#define KERBEROS_NAME {'K','e','r','b','e','r','o','s',0} +static char kerberos_name_A[] = KERBEROS_NAME; +static WCHAR kerberos_name_W[] = KERBEROS_NAME; + +#define CAPS \ + ( SECPKG_FLAG_INTEGRITY \ + | SECPKG_FLAG_PRIVACY \ + | SECPKG_FLAG_TOKEN_ONLY \ + | SECPKG_FLAG_DATAGRAM \ + | SECPKG_FLAG_CONNECTION \ + | SECPKG_FLAG_MULTI_REQUIRED \ + | SECPKG_FLAG_EXTENDED_ERROR \ + | SECPKG_FLAG_IMPERSONATION \ + | SECPKG_FLAG_ACCEPT_WIN32_NAME \ + | SECPKG_FLAG_NEGOTIABLE \ + | SECPKG_FLAG_GSS_COMPATIBLE \ + | SECPKG_FLAG_LOGON \ + | SECPKG_FLAG_MUTUAL_AUTH \ + | SECPKG_FLAG_DELEGATION \ + | SECPKG_FLAG_READONLY_WITH_CHECKSUM \ + | SECPKG_FLAG_RESTRICTED_TOKENS \ + | SECPKG_FLAG_APPCONTAINER_CHECKS) + +static const SecPkgInfoW infoW = { + CAPS, + 1, + RPC_C_AUTHN_GSS_KERBEROS, + KERBEROS_MAX_BUF, + kerberos_name_W, + kerberos_comment_W +}; + +static const SecPkgInfoA infoA = { + CAPS, + 1, + RPC_C_AUTHN_GSS_KERBEROS, + KERBEROS_MAX_BUF, + kerberos_name_A, + kerberos_comment_A +}; + +void SECUR32_initKerberosSP(void) +{ + SecureProvider *provider = SECUR32_addProvider(&kerberosTableA, &kerberosTableW, NULL); + SECUR32_addPackages(provider, 1, &infoA, &infoW); +} diff --git a/reactos/dll/win32/secur32/wine/kerberos.h b/reactos/dll/win32/secur32/wine/kerberos.h new file mode 100644 index 00000000000..9c6a37ff61a --- /dev/null +++ b/reactos/dll/win32/secur32/wine/kerberos.h @@ -0,0 +1,7 @@ + +#ifndef __WINE_KERBEROS_H__ +#define __WINE_KERBEROS_H__ + +void SECUR32_initKerberosSP(void) DECLSPEC_HIDDEN; + +#endif /* __WINE_KERBEROS_H__ */ diff --git a/reactos/dll/win32/secur32/wine/negotiate.c b/reactos/dll/win32/secur32/wine/negotiate.c new file mode 100644 index 00000000000..a5c99955208 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/negotiate.c @@ -0,0 +1,525 @@ +/* + * Copyright 2005 Kai Blin + * Copyright 2012 Hans Leidekker for CodeWeavers + * + * 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 a Negotiate provider that simply forwards to + * the NTLM provider. + */ + +#include "precomp.h" + +#include +WINE_DEFAULT_DEBUG_CHANNEL(secur32); + +/*********************************************************************** + * QueryCredentialsAttributesA + */ +static SECURITY_STATUS SEC_ENTRY nego_QueryCredentialsAttributesA( + PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) +{ + FIXME("%p, %u, %p\n", phCredential, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * QueryCredentialsAttributesW + */ +static SECURITY_STATUS SEC_ENTRY nego_QueryCredentialsAttributesW( + PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) +{ + FIXME("%p, %u, %p\n", phCredential, ulAttribute, pBuffer); + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * AcquireCredentialsHandleW + */ +static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleW( + SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, + PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, + PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry ) +{ + static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}; + SECURITY_STATUS ret; + + 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); + + FIXME("forwarding to NTLM\n"); + ret = ntlm_AcquireCredentialsHandleW( pszPrincipal, ntlmW, fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, + phCredential, ptsExpiry ); + if (ret == SEC_E_OK) + { + NtlmCredentials *cred = (NtlmCredentials *)phCredential->dwLower; + cred->no_cached_credentials = (pAuthData == NULL); + } + return ret; +} + +/*********************************************************************** + * AcquireCredentialsHandleA + */ +static SECURITY_STATUS SEC_ENTRY nego_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; + SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL; + SEC_WINNT_AUTH_IDENTITY_W *identityW = 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_len = MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, NULL, 0 ); + package = HeapAlloc( GetProcessHeap(), 0, package_len * sizeof(SEC_WCHAR) ); + if (!package) return SEC_E_INSUFFICIENT_MEMORY; + MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, package, package_len ); + } + if (pAuthData) + { + SEC_WINNT_AUTH_IDENTITY_A *identity = pAuthData; + int user_len, domain_len, passwd_len; + + if (identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) + { + identityW = HeapAlloc( GetProcessHeap(), 0, sizeof(*identityW) ); + if (!identityW) goto done; + + if (!identity->UserLength) user_len = 0; + else + { + user_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->User, + identity->UserLength, NULL, 0 ); + user = HeapAlloc( GetProcessHeap(), 0, user_len * sizeof(SEC_WCHAR) ); + if (!user) goto done; + MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->User, identity->UserLength, + user, user_len ); + } + if (!identity->DomainLength) domain_len = 0; + else + { + domain_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Domain, + identity->DomainLength, NULL, 0 ); + domain = HeapAlloc( GetProcessHeap(), 0, domain_len * sizeof(SEC_WCHAR) ); + if (!domain) goto done; + MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Domain, identity->DomainLength, + domain, domain_len ); + } + if (!identity->PasswordLength) passwd_len = 0; + else + { + passwd_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Password, + identity->PasswordLength, NULL, 0 ); + passwd = HeapAlloc( GetProcessHeap(), 0, passwd_len * sizeof(SEC_WCHAR) ); + if (!passwd) goto done; + MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Password, identity->PasswordLength, + passwd, passwd_len ); + } + identityW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + identityW->User = user; + identityW->UserLength = user_len; + identityW->Domain = domain; + identityW->DomainLength = domain_len; + identityW->Password = passwd; + identityW->PasswordLength = passwd_len; + } + else identityW = (SEC_WINNT_AUTH_IDENTITY_W *)identity; + } + ret = nego_AcquireCredentialsHandleW( NULL, package, fCredentialUse, pLogonID, identityW, + pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry ); +done: + HeapFree( GetProcessHeap(), 0, package ); + HeapFree( GetProcessHeap(), 0, user ); + HeapFree( GetProcessHeap(), 0, domain ); + HeapFree( GetProcessHeap(), 0, passwd ); + HeapFree( GetProcessHeap(), 0, identityW ); + return ret; +} + +/*********************************************************************** + * InitializeSecurityContextW + */ +static SECURITY_STATUS SEC_ENTRY nego_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 ) +{ + TRACE("%p, %p, %s, 0x%08x, %u, %u, %p, %u, %p, %p, %p, %p\n", + phCredential, phContext, debugstr_w(pszTargetName), fContextReq, + Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, + pfContextAttr, ptsExpiry); + + return ntlm_InitializeSecurityContextW( phCredential, phContext, pszTargetName, + fContextReq, Reserved1, TargetDataRep, + pInput, Reserved2, phNewContext, + pOutput, pfContextAttr, ptsExpiry ); +} + +/*********************************************************************** + * InitializeSecurityContextA + */ +static SECURITY_STATUS SEC_ENTRY nego_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, 0x%08x, %u, %u, %p, %u, %p, %p, %p, %p\n", + phCredential, phContext, debugstr_a(pszTargetName), fContextReq, + Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, + pfContextAttr, ptsExpiry); + + if (pszTargetName) + { + int target_len = MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, NULL, 0 ); + target = HeapAlloc(GetProcessHeap(), 0, target_len * sizeof(SEC_WCHAR) ); + if (!target) return SEC_E_INSUFFICIENT_MEMORY; + MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, target, target_len ); + } + ret = nego_InitializeSecurityContextW( phCredential, phContext, target, fContextReq, + Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry ); + HeapFree( GetProcessHeap(), 0, target ); + return ret; +} + +/*********************************************************************** + * AcceptSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY nego_AcceptSecurityContext( + PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, + ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) +{ + TRACE("%p, %p, %p, 0x%08x, %u, %p, %p, %p, %p\n", phCredential, phContext, + pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, + ptsExpiry); + + return ntlm_AcceptSecurityContext( phCredential, phContext, pInput, + fContextReq, TargetDataRep, phNewContext, + pOutput, pfContextAttr, ptsExpiry ); +} + +/*********************************************************************** + * CompleteAuthToken + */ +static SECURITY_STATUS SEC_ENTRY nego_CompleteAuthToken(PCtxtHandle phContext, + PSecBufferDesc pToken) +{ + SECURITY_STATUS ret; + + TRACE("%p %p\n", phContext, pToken); + if (phContext) + { + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + { + ret = SEC_E_INVALID_HANDLE; + } + return ret; +} + +/*********************************************************************** + * DeleteSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY nego_DeleteSecurityContext(PCtxtHandle phContext) +{ + TRACE("%p\n", phContext); + + return ntlm_DeleteSecurityContext( phContext ); +} + +/*********************************************************************** + * ApplyControlToken + */ +static SECURITY_STATUS SEC_ENTRY nego_ApplyControlToken(PCtxtHandle phContext, + PSecBufferDesc pInput) +{ + SECURITY_STATUS ret; + + TRACE("%p %p\n", phContext, pInput); + if (phContext) + { + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + { + ret = SEC_E_INVALID_HANDLE; + } + return ret; +} + +/*********************************************************************** + * QueryContextAttributesW + */ +static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesW( + PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer) +{ + TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer); + + switch (ulAttribute) + { + case SECPKG_ATTR_SIZES: + { + SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer; + sizes->cbMaxToken = 2888; + sizes->cbMaxSignature = 16; + sizes->cbSecurityTrailer = 16; + sizes->cbBlockSize = 0; + return SEC_E_OK; + } + case SECPKG_ATTR_NEGOTIATION_INFO: + { + SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)pBuffer; + info->PackageInfo = ntlm_package_infoW; + info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; + return SEC_E_OK; + } + default: + return ntlm_QueryContextAttributesW( phContext, ulAttribute, pBuffer ); + } +} + +/*********************************************************************** + * QueryContextAttributesA + */ +static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesA(PCtxtHandle phContext, + ULONG ulAttribute, void *pBuffer) +{ + TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer); + + switch (ulAttribute) + { + case SECPKG_ATTR_SIZES: + { + SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer; + sizes->cbMaxToken = 2888; + sizes->cbMaxSignature = 16; + sizes->cbSecurityTrailer = 16; + sizes->cbBlockSize = 0; + return SEC_E_OK; + } + case SECPKG_ATTR_NEGOTIATION_INFO: + { + SecPkgContext_NegotiationInfoA *info = (SecPkgContext_NegotiationInfoA *)pBuffer; + info->PackageInfo = ntlm_package_infoA; + info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; + return SEC_E_OK; + } + default: + return ntlm_QueryContextAttributesA( phContext, ulAttribute, pBuffer ); + } +} + +/*********************************************************************** + * ImpersonateSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY nego_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 nego_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; +} + +/*********************************************************************** + * MakeSignature + */ +static SECURITY_STATUS SEC_ENTRY nego_MakeSignature(PCtxtHandle phContext, + ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo); + + return ntlm_MakeSignature( phContext, fQOP, pMessage, MessageSeqNo ); +} + +/*********************************************************************** + * VerifySignature + */ +static SECURITY_STATUS SEC_ENTRY nego_VerifySignature(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP); + + return ntlm_VerifySignature( phContext, pMessage, MessageSeqNo, pfQOP ); +} + +/*********************************************************************** + * FreeCredentialsHandle + */ +static SECURITY_STATUS SEC_ENTRY nego_FreeCredentialsHandle(PCredHandle phCredential) +{ + TRACE("%p\n", phCredential); + + return ntlm_FreeCredentialsHandle( phCredential ); +} + +/*********************************************************************** + * EncryptMessage + */ +static SECURITY_STATUS SEC_ENTRY nego_EncryptMessage(PCtxtHandle phContext, + ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo); + + return ntlm_EncryptMessage( phContext, fQOP, pMessage, MessageSeqNo ); +} + +/*********************************************************************** + * DecryptMessage + */ +static SECURITY_STATUS SEC_ENTRY nego_DecryptMessage(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP); + + return ntlm_DecryptMessage( phContext, pMessage, MessageSeqNo, pfQOP ); +} + +static const SecurityFunctionTableA negoTableA = { + 1, + NULL, /* EnumerateSecurityPackagesA */ + nego_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ + nego_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ + nego_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + nego_InitializeSecurityContextA, /* InitializeSecurityContextA */ + nego_AcceptSecurityContext, /* AcceptSecurityContext */ + nego_CompleteAuthToken, /* CompleteAuthToken */ + nego_DeleteSecurityContext, /* DeleteSecurityContext */ + nego_ApplyControlToken, /* ApplyControlToken */ + nego_QueryContextAttributesA, /* QueryContextAttributesA */ + nego_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + nego_RevertSecurityContext, /* RevertSecurityContext */ + nego_MakeSignature, /* MakeSignature */ + nego_VerifySignature, /* VerifySignature */ + FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoA */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextA */ + NULL, /* AddCredentialsA */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + nego_EncryptMessage, /* EncryptMessage */ + nego_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesA */ +}; + +static const SecurityFunctionTableW negoTableW = { + 1, + NULL, /* EnumerateSecurityPackagesW */ + nego_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ + nego_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ + nego_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + nego_InitializeSecurityContextW, /* InitializeSecurityContextW */ + nego_AcceptSecurityContext, /* AcceptSecurityContext */ + nego_CompleteAuthToken, /* CompleteAuthToken */ + nego_DeleteSecurityContext, /* DeleteSecurityContext */ + nego_ApplyControlToken, /* ApplyControlToken */ + nego_QueryContextAttributesW, /* QueryContextAttributesW */ + nego_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + nego_RevertSecurityContext, /* RevertSecurityContext */ + nego_MakeSignature, /* MakeSignature */ + nego_VerifySignature, /* VerifySignature */ + FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoW */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextW */ + NULL, /* AddCredentialsW */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + nego_EncryptMessage, /* EncryptMessage */ + nego_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesW */ +}; + +#define NEGO_MAX_TOKEN 12000 + +static WCHAR nego_name_W[] = {'N','e','g','o','t','i','a','t','e',0}; +static char nego_name_A[] = "Negotiate"; + +static WCHAR negotiate_comment_W[] = + {'M','i','c','r','o','s','o','f','t',' ','P','a','c','k','a','g','e',' ', + 'N','e','g','o','t','i','a','t','o','r',0}; +static CHAR negotiate_comment_A[] = "Microsoft Package Negotiator"; + +#define CAPS ( \ + SECPKG_FLAG_INTEGRITY | \ + SECPKG_FLAG_PRIVACY | \ + SECPKG_FLAG_CONNECTION | \ + SECPKG_FLAG_MULTI_REQUIRED | \ + SECPKG_FLAG_EXTENDED_ERROR | \ + SECPKG_FLAG_IMPERSONATION | \ + SECPKG_FLAG_ACCEPT_WIN32_NAME | \ + SECPKG_FLAG_NEGOTIABLE | \ + SECPKG_FLAG_GSS_COMPATIBLE | \ + SECPKG_FLAG_LOGON | \ + SECPKG_FLAG_RESTRICTED_TOKENS ) + +void SECUR32_initNegotiateSP(void) +{ + SecureProvider *provider = SECUR32_addProvider(&negoTableA, &negoTableW, NULL); + + const SecPkgInfoW infoW = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN, + nego_name_W, negotiate_comment_W}; + const SecPkgInfoA infoA = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN, + nego_name_A, negotiate_comment_A}; + SECUR32_addPackages(provider, 1L, &infoA, &infoW); +} diff --git a/reactos/dll/win32/secur32/wine/negotiate.h b/reactos/dll/win32/secur32/wine/negotiate.h new file mode 100644 index 00000000000..1cb4711051c --- /dev/null +++ b/reactos/dll/win32/secur32/wine/negotiate.h @@ -0,0 +1,7 @@ + +#ifndef __WINE_NEGOTIATE_H__ +#define __WINE_NEGOTIATE_H__ + +void SECUR32_initNegotiateSP(void) DECLSPEC_HIDDEN; + +#endif /* __WINE_NEGOTIATE_H__ */ diff --git a/reactos/dll/win32/secur32/wine/ntlm.c b/reactos/dll/win32/secur32/wine/ntlm.c new file mode 100644 index 00000000000..1d9cb44ab03 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/ntlm.c @@ -0,0 +1,2064 @@ +/* + * 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 "precomp.h" + +#include +#include +#include +#include + +#include "hmac_md5.h" + +#include +#include +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 +#ifndef __REACTOS__ +#define MIN_NTLM_AUTH_MICRO_VERSION 25 +#else +#define MIN_NTLM_AUTH_MICRO_VERSION 23 +#endif + +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); + user = HeapAlloc(GetProcessHeap(), 0, unixcp_size); + if (!user) 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); + domain = HeapAlloc(GetProcessHeap(), 0, unixcp_size); + if (!domain) 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 + */ +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; + PNtlmCredentials ntlm_cred; + 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: + ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred)); + if (!ntlm_cred) + ret = SEC_E_INSUFFICIENT_MEMORY; + else + { + 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; + ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred)); + if (!ntlm_cred) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + break; + } + 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 != NULL) + { + 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); + domain = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * domain_len); + if(!domain) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + break; + } + 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); + user = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * user_len); + if(!user) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + break; + } + 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); + password = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * password_len); + if(!password) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + break; + } + 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 != 0) + { + ntlm_cred->pwlen = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, + password_len, NULL, 0, NULL, NULL); + + ntlm_cred->password = HeapAlloc(GetProcessHeap(), 0, + ntlm_cred->pwlen); + if(!ntlm_cred->password) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + break; + } + + 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; + phCredential = NULL; + break; + default: + phCredential = NULL; + ret = SEC_E_UNKNOWN_CREDENTIALS; + } + + if (auth_data && auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + HeapFree(GetProcessHeap(), 0, domain); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, password); + } + 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; + 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 identity = 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 != NULL) + { + int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, + NULL, 0); + + package = HeapAlloc(GetProcessHeap(), 0, package_sizeW * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW); + } + + + if(pAuthData != NULL) + { + identity = pAuthData; + + if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) + { + pAuthDataW = HeapAlloc(GetProcessHeap(), 0, + sizeof(SEC_WINNT_AUTH_IDENTITY_W)); + + if(identity->UserLength != 0) + { + user_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->User, identity->UserLength, NULL, 0); + user = HeapAlloc(GetProcessHeap(), 0, user_sizeW * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User, + identity->UserLength, user, user_sizeW); + } + else + { + user_sizeW = 0; + } + + if(identity->DomainLength != 0) + { + domain_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->Domain, identity->DomainLength, NULL, 0); + domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW + * sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain, + identity->DomainLength, domain, domain_sizeW); + } + else + { + domain_sizeW = 0; + } + + if(identity->PasswordLength != 0) + { + passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->Password, identity->PasswordLength, + NULL, 0); + passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW + * sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password, + identity->PasswordLength, passwd, passwd_sizeW); + } + else + { + passwd_sizeW = 0; + } + + 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)identity; + } + } + + ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse, + pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential, + ptsExpiry); + + HeapFree(GetProcessHeap(), 0, package); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, domain); + HeapFree(GetProcessHeap(), 0, passwd); + if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity) + HeapFree(GetProcessHeap(), 0, 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); + } + + pszHostOnly = HeapAlloc(GetProcessHeap(), 0, (p - pszHost + 1) * sizeof(WCHAR)); + if (!pszHostOnly) + return FALSE; + + memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR)); + pszHostOnly[p - pszHost] = '\0'; + + ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred); + + HeapFree(GetProcessHeap(), 0, pszHostOnly); + return ret; +} + +/*********************************************************************** + * InitializeSecurityContextW + */ +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 should be sent to the server + * PW should be sent back to helper with + * base64 encoded password + * AF client is done, blob should be + * sent to server with KK prefixed + * GF A string list of negotiated flags + * GK base64 encoded session key + * BH 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 = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF); + bin = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, + 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); + + HeapFree(GetProcessHeap(), 0, 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" + */ + want_flags = HeapAlloc(GetProcessHeap(), 0, 73); + if(want_flags == NULL) + { + 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 = HeapAlloc(GetProcessHeap(), 0, 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, "%lx", &(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)); + HeapFree(GetProcessHeap(), 0, helper->session_key); + helper->session_key = HeapAlloc(GetProcessHeap(), 0, bin_len); + if(!helper->session_key) + { + 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: + HeapFree(GetProcessHeap(), 0, username); + HeapFree(GetProcessHeap(), 0, domain); + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, want_flags); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, 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 != NULL) + { + int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, + strlen(pszTargetName)+1, NULL, 0); + target = HeapAlloc(GetProcessHeap(), 0, target_size * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1, + target, target_size); + } + + ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target, + fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry); + + HeapFree(GetProcessHeap(), 0, target); + return ret; +} + +/*********************************************************************** + * AcceptSecurityContext + */ +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 = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF); + bin = HeapAlloc(GetProcessHeap(),0, 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 */ + want_flags = HeapAlloc(GetProcessHeap(), 0, 73); + if(want_flags == NULL) + { + 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 */ + + 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, "%lx", &(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)); + HeapFree(GetProcessHeap(), 0, helper->session_key); + helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16); + if (!helper->session_key) + { + 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)); + HeapFree(GetProcessHeap(), 0, helper->session_key); + helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16); + if(!helper->session_key) + { + 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: + HeapFree(GetProcessHeap(), 0, want_flags); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, 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 + */ +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); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_sign_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_seal_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_sign_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_seal_key); + + cleanup_helper(helper); + + return SEC_E_OK; +} + +/*********************************************************************** + * QueryContextAttributesW + */ +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); + _x(SECPKG_ATTR_NEGOTIATION_INFO); + _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 + */ +SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, + ULONG ulAttribute, void *pBuffer) +{ + 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 = ComputeCrc32(pMessage->pBuffers[i].pvBuffer, + pMessage->pBuffers[i].cbBuffer, crc); + } + } + + 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 + */ +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 + */ +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 = HeapAlloc(GetProcessHeap(), 0, 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; + + HeapFree(GetProcessHeap(), 0, local_buff); + + return ret; + +} + +/*********************************************************************** + * FreeCredentialsHandle + */ +SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential) +{ + SECURITY_STATUS ret; + + 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); + HeapFree(GetProcessHeap(), 0, ntlm_cred->password); + HeapFree(GetProcessHeap(), 0, ntlm_cred->username_arg); + HeapFree(GetProcessHeap(), 0, ntlm_cred->domain_arg); + HeapFree(GetProcessHeap(), 0, ntlm_cred); + ret = SEC_E_OK; + } + else + ret = SEC_E_OK; + + return ret; +} + +/*********************************************************************** + * EncryptMessage + */ +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 + */ +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 */ +}; + +#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; + +/* According to Windows, NTLM has the following capabilities. */ +#define 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 = { + CAPS, + 1, + RPC_C_AUTHN_WINNT, + NTLM_MAX_BUF, + ntlm_name_W, + ntlm_comment_W +}; + +static const SecPkgInfoA infoA = { + CAPS, + 1, + RPC_C_AUTHN_WINNT, + NTLM_MAX_BUF, + ntlm_name_A, + ntlm_comment_A +}; + +SecPkgInfoA *ntlm_package_infoA = (SecPkgInfoA *)&infoA; +SecPkgInfoW *ntlm_package_infoW = (SecPkgInfoW *)&infoW; + +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/reactos/dll/win32/secur32/wine/ntlm.h b/reactos/dll/win32/secur32/wine/ntlm.h new file mode 100644 index 00000000000..0006ad573aa --- /dev/null +++ b/reactos/dll/win32/secur32/wine/ntlm.h @@ -0,0 +1,116 @@ + +#ifndef __WINE_NTLM_H__ +#define __WINE_NTLM_H__ + +#include +#define CP_UNIXCP CP_ACP + +void SECUR32_initNTLMSP(void) DECLSPEC_HIDDEN; + +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 { +#ifndef __REACTOS__ + pid_t helper_pid; +#else + HANDLE helper_pid; +#endif + 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; + +SECURITY_STATUS SECUR32_CreateNTLM1SessionKey(PBYTE password, int len, PBYTE session_key) DECLSPEC_HIDDEN; +SECURITY_STATUS SECUR32_CreateNTLM2SubKeys(PNegoHelper helper) 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 + +SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR *, SEC_WCHAR *, + ULONG, PLUID, PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle, PCtxtHandle, + SEC_WCHAR *, ULONG fContextReq, ULONG, ULONG, PSecBufferDesc, ULONG, PCtxtHandle, + PSecBufferDesc, ULONG *, PTimeStamp) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle, PCtxtHandle, PSecBufferDesc, + ULONG, ULONG, PCtxtHandle, PSecBufferDesc, ULONG *, PTimeStamp) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle, ULONG, void *) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle, ULONG, void *) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle, ULONG, PSecBufferDesc, ULONG) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle, PSecBufferDesc, ULONG, PULONG) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle, ULONG, PSecBufferDesc, ULONG) DECLSPEC_HIDDEN; +SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle, PSecBufferDesc, ULONG, PULONG) DECLSPEC_HIDDEN; + +SecPkgInfoW *ntlm_package_infoW DECLSPEC_HIDDEN; +SecPkgInfoA *ntlm_package_infoA DECLSPEC_HIDDEN; + +#endif /* __WINE_NTLM_H__ */ diff --git a/reactos/dll/win32/secur32/wine/util.c b/reactos/dll/win32/secur32/wine/util.c new file mode 100644 index 00000000000..2f9fe015823 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/util.c @@ -0,0 +1,249 @@ +/* + * 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 "precomp.h" + +#include +WINE_DEFAULT_DEBUG_CHANNEL(ntlm); + +/* The CRC32 code is copyright (C) 1986 Gary S. Brown and was placed in the + * public domain. + * CRC polynomial 0xedb88320 + */ +static const ULONG CRC_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +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; + +#ifndef __REACTOS__ // See hmac_md5.h +/* 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; +#endif + +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 ); +#ifndef __REACTOS__ // See hmac_md5.h +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 ); +#endif + +ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc) +{ + ULONG crc = ~initial_crc; + + while (iLen > 0) + { + crc = CRC_table[(crc ^ *pData) & 0xff] ^ (crc >> 8); + pData++; + iLen--; + } + return ~crc; +} + +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 = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.send_seal_key = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.recv_sign_key = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.recv_seal_key = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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) +{ + HeapFree(GetProcessHeap(), 0, a4i); +} diff --git a/reactos/dll/win32/secur32/wine/util.h b/reactos/dll/win32/secur32/wine/util.h new file mode 100644 index 00000000000..f4b35f12580 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/util.h @@ -0,0 +1,14 @@ + +#ifndef __WINE_UTIL_H__ +#define __WINE_UTIL_H__ + +/* Functions from util.c */ +ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc) DECLSPEC_HIDDEN; +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; + +#endif /* __WINE_UTIL_H__ */ diff --git a/reactos/dll/win32/secur32/wine/wine_supp.h b/reactos/dll/win32/secur32/wine/wine_supp.h new file mode 100644 index 00000000000..5528290a028 --- /dev/null +++ b/reactos/dll/win32/secur32/wine/wine_supp.h @@ -0,0 +1,9 @@ + +#include "base64_codec.h" +#include "hmac_md5.h" +#include "kerberos.h" +#include "negotiate.h" +// WARN: The ordering of the following two headers must be kept! +#include "ntlm.h" +#include "dispatcher.h" +#include "util.h"