[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
This commit is contained in:
Hermès Bélusca-Maïto 2017-02-20 22:28:07 +00:00
parent 08a509daee
commit 5ccb049790
19 changed files with 4184 additions and 4 deletions

View file

@ -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)

View file

@ -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))
{

View file

@ -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.
*/

View file

@ -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.@)
*

View file

@ -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/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
static const char b64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf,
int max_len, int *out_len)
{
int div, i;
PBYTE d = in_buf;
int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
*out_len = bytes + pad_bytes;
if(bytes + pad_bytes + 1 > max_len)
return SEC_E_BUFFER_TOO_SMALL;
/* Three bytes of input give 4 chars of output */
div = in_len / 3;
i = 0;
while(div > 0)
{
/* first char is the first 6 bits of the first byte*/
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
/* second char is the last 2 bits of the first byte and the first 4
* bits of the second byte */
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
/* third char is the last 4 bits of the second byte and the first 2
* bits of the third byte */
out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
/* fourth char is the remaining 6 bits of the third byte */
out_buf[i + 3] = b64[ d[2] & 0x3f];
i += 4;
d += 3;
div--;
}
switch(pad_bytes)
{
case 1:
/* first char is the first 6 bits of the first byte*/
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
/* second char is the last 2 bits of the first byte and the first 4
* bits of the second byte */
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
/* third char is the last 4 bits of the second byte padded with
* two zeroes */
out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) ];
/* fourth char is a = to indicate one byte of padding */
out_buf[i + 3] = '=';
out_buf[i + 4] = 0;
break;
case 2:
/* first char is the first 6 bits of the first byte*/
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
/* second char is the last 2 bits of the first byte padded with
* four zeroes*/
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30)];
/* third char is = to indicate padding */
out_buf[i + 2] = '=';
/* fourth char is = to indicate padding */
out_buf[i + 3] = '=';
out_buf[i + 4] = 0;
break;
default:
out_buf[i] = 0;
}
return SEC_E_OK;
}
static inline BYTE decode(char c)
{
if( c >= 'A' && c <= 'Z')
return c - 'A';
if( c >= 'a' && c <= 'z')
return c - 'a' + 26;
if( c >= '0' && c <= '9')
return c - '0' + 52;
if( c == '+')
return 62;
if( c == '/')
return 63;
else
return 64;
}
SECURITY_STATUS decodeBase64(char *in_buf, int in_len, PBYTE out_buf,
int max_len, int *out_len)
{
int len = in_len, i;
char *d = in_buf;
int ip0, ip1, ip2, ip3;
TRACE("in_len: %d\n", in_len);
if((in_len % 4) != 0)
return SEC_E_INVALID_TOKEN;
if(in_len > max_len)
return SEC_E_BUFFER_TOO_SMALL;
i = 0;
while(len > 4)
{
if((ip0 = decode(d[0])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip1 = decode(d[1])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip2 = decode(d[2])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip3 = decode(d[3])) > 63)
return SEC_E_INVALID_TOKEN;
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
out_buf[i + 2] = (ip2 << 6) | ip3;
len -= 4;
i += 3;
d += 4;
}
if(d[2] == '=')
{
if((ip0 = decode(d[0])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip1 = decode(d[1])) > 63)
return SEC_E_INVALID_TOKEN;
out_buf[i] = (ip0 << 2) | (ip1 >> 4);
i++;
}
else if(d[3] == '=')
{
if((ip0 = decode(d[0])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip1 = decode(d[1])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip2 = decode(d[2])) > 63)
return SEC_E_INVALID_TOKEN;
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
i += 2;
}
else
{
if((ip0 = decode(d[0])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip1 = decode(d[1])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip2 = decode(d[2])) > 63)
return SEC_E_INVALID_TOKEN;
if((ip3 = decode(d[3])) > 63)
return SEC_E_INVALID_TOKEN;
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
out_buf[i + 2] = (ip2 << 6) | ip3;
i += 3;
}
*out_len = i;
return SEC_E_OK;
}

View file

@ -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__ */

View file

@ -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 <stdio.h>
#include <process.h>
#include <io.h>
#include <errno.h>
#include <fcntl.h>
#ifdef __REACTOS__
#define close _close
#define read _read
#define write _write
#endif
#include <wine/debug.h>
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, &micro);
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;
}
}
}
}

View file

@ -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__ */

View file

@ -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);
}

View file

@ -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 <string.h>
#include <windef.h>
typedef struct
{
unsigned int i[2];
unsigned int buf[4];
unsigned char in[64];
unsigned char digest[16];
} MD5_CTX;
typedef struct
{
MD5_CTX ctx;
unsigned char outer_padding[64];
} HMAC_MD5_CTX;
void WINAPI MD5Init( MD5_CTX *ctx );
void WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len );
void WINAPI MD5Final( MD5_CTX *ctx );
void HMACMD5Init(HMAC_MD5_CTX *ctx, const unsigned char *key, unsigned int key_len) DECLSPEC_HIDDEN;
void HMACMD5Update(HMAC_MD5_CTX *ctx, const unsigned char *data, unsigned int data_len) DECLSPEC_HIDDEN;
void HMACMD5Final(HMAC_MD5_CTX *ctx, unsigned char *digest) DECLSPEC_HIDDEN;
#endif /*_HMAC_MD5_H_*/

View file

@ -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 <assert.h>
#include <wine/debug.h>
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);
}

View file

@ -0,0 +1,7 @@
#ifndef __WINE_KERBEROS_H__
#define __WINE_KERBEROS_H__
void SECUR32_initKerberosSP(void) DECLSPEC_HIDDEN;
#endif /* __WINE_KERBEROS_H__ */

View file

@ -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/debug.h>
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);
}

View file

@ -0,0 +1,7 @@
#ifndef __WINE_NEGOTIATE_H__
#define __WINE_NEGOTIATE_H__
void SECUR32_initNegotiateSP(void) DECLSPEC_HIDDEN;
#endif /* __WINE_NEGOTIATE_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
#ifndef __WINE_NTLM_H__
#define __WINE_NTLM_H__
#include <sys/types.h>
#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__ */

View file

@ -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/debug.h>
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);
}

View file

@ -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__ */

View file

@ -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"