secur32: Get rid of builtin NTLM support.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
8a9c3b1e54
commit
1565a12a55
|
@ -1,21 +1,16 @@
|
|||
MODULE = secur32.dll
|
||||
IMPORTLIB = secur32
|
||||
IMPORTS = netapi32 advapi32
|
||||
IMPORTS = advapi32
|
||||
DELAYIMPORTS = crypt32
|
||||
EXTRAINCL = $(GNUTLS_CFLAGS)
|
||||
EXTRALIBS = $(SECURITY_LIBS)
|
||||
|
||||
C_SRCS = \
|
||||
base64_codec.c \
|
||||
dispatcher.c \
|
||||
hmac_md5.c \
|
||||
lsa.c \
|
||||
negotiate.c \
|
||||
ntlm.c \
|
||||
schannel.c \
|
||||
schannel_gnutls.c \
|
||||
schannel_macosx.c \
|
||||
secur32.c \
|
||||
thunks.c \
|
||||
util.c \
|
||||
wrapper.c
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* base64 encoder/decoder
|
||||
*
|
||||
* Copyright 2005 by Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "windef.h"
|
||||
#include "winerror.h"
|
||||
#include "sspi.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
||||
|
||||
static const char b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf,
|
||||
int max_len, int *out_len)
|
||||
{
|
||||
int div, i;
|
||||
PBYTE d = in_buf;
|
||||
int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
|
||||
|
||||
TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
|
||||
*out_len = bytes + pad_bytes;
|
||||
|
||||
if(bytes + pad_bytes + 1 > max_len)
|
||||
return SEC_E_BUFFER_TOO_SMALL;
|
||||
|
||||
/* Three bytes of input give 4 chars of output */
|
||||
div = in_len / 3;
|
||||
|
||||
i = 0;
|
||||
while(div > 0)
|
||||
{
|
||||
/* first char is the first 6 bits of the first byte*/
|
||||
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
|
||||
/* second char is the last 2 bits of the first byte and the first 4
|
||||
* bits of the second byte */
|
||||
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
|
||||
/* third char is the last 4 bits of the second byte and the first 2
|
||||
* bits of the third byte */
|
||||
out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
|
||||
/* fourth char is the remaining 6 bits of the third byte */
|
||||
out_buf[i + 3] = b64[ d[2] & 0x3f];
|
||||
i += 4;
|
||||
d += 3;
|
||||
div--;
|
||||
}
|
||||
|
||||
switch(pad_bytes)
|
||||
{
|
||||
case 1:
|
||||
/* first char is the first 6 bits of the first byte*/
|
||||
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
|
||||
/* second char is the last 2 bits of the first byte and the first 4
|
||||
* bits of the second byte */
|
||||
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
|
||||
/* third char is the last 4 bits of the second byte padded with
|
||||
* two zeroes */
|
||||
out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) ];
|
||||
/* fourth char is a = to indicate one byte of padding */
|
||||
out_buf[i + 3] = '=';
|
||||
out_buf[i + 4] = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* first char is the first 6 bits of the first byte*/
|
||||
out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ];
|
||||
/* second char is the last 2 bits of the first byte padded with
|
||||
* four zeroes*/
|
||||
out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30)];
|
||||
/* third char is = to indicate padding */
|
||||
out_buf[i + 2] = '=';
|
||||
/* fourth char is = to indicate padding */
|
||||
out_buf[i + 3] = '=';
|
||||
out_buf[i + 4] = 0;
|
||||
break;
|
||||
default:
|
||||
out_buf[i] = 0;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static inline BYTE decode(char c)
|
||||
{
|
||||
if( c >= 'A' && c <= 'Z')
|
||||
return c - 'A';
|
||||
if( c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 26;
|
||||
if( c >= '0' && c <= '9')
|
||||
return c - '0' + 52;
|
||||
if( c == '+')
|
||||
return 62;
|
||||
if( c == '/')
|
||||
return 63;
|
||||
else
|
||||
return 64;
|
||||
}
|
||||
|
||||
SECURITY_STATUS decodeBase64(char *in_buf, int in_len, PBYTE out_buf,
|
||||
int max_len, int *out_len)
|
||||
{
|
||||
int len = in_len, i;
|
||||
char *d = in_buf;
|
||||
int ip0, ip1, ip2, ip3;
|
||||
|
||||
TRACE("in_len: %d\n", in_len);
|
||||
|
||||
if((in_len % 4) != 0)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if(in_len > max_len)
|
||||
return SEC_E_BUFFER_TOO_SMALL;
|
||||
|
||||
i = 0;
|
||||
while(len > 4)
|
||||
{
|
||||
if((ip0 = decode(d[0])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip1 = decode(d[1])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip2 = decode(d[2])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip3 = decode(d[3])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
|
||||
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
|
||||
out_buf[i + 2] = (ip2 << 6) | ip3;
|
||||
len -= 4;
|
||||
i += 3;
|
||||
d += 4;
|
||||
}
|
||||
|
||||
if(d[2] == '=')
|
||||
{
|
||||
if((ip0 = decode(d[0])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip1 = decode(d[1])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
out_buf[i] = (ip0 << 2) | (ip1 >> 4);
|
||||
i++;
|
||||
}
|
||||
else if(d[3] == '=')
|
||||
{
|
||||
if((ip0 = decode(d[0])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip1 = decode(d[1])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip2 = decode(d[2])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
|
||||
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((ip0 = decode(d[0])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip1 = decode(d[1])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip2 = decode(d[2])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
if((ip3 = decode(d[3])) > 63)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
|
||||
out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
|
||||
out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
|
||||
out_buf[i + 2] = (ip2 << 6) | ip3;
|
||||
i += 3;
|
||||
}
|
||||
*out_len = i;
|
||||
return SEC_E_OK;
|
||||
}
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* Copyright 2005, 2006 Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* A dispatcher to run ntlm_auth for wine's sspi module.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "sspi.h"
|
||||
#include "secur32_priv.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#define INITIAL_BUFFER_SIZE 200
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
||||
|
||||
SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
|
||||
char* const argv[])
|
||||
{
|
||||
#ifdef HAVE_FORK
|
||||
int pipe_in[2];
|
||||
int pipe_out[2];
|
||||
int i;
|
||||
PNegoHelper helper;
|
||||
|
||||
TRACE("%s ", debugstr_a(prog));
|
||||
for(i = 0; argv[i] != NULL; ++i)
|
||||
{
|
||||
TRACE("%s ", debugstr_a(argv[i]));
|
||||
}
|
||||
TRACE("\n");
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
if (pipe2( pipe_in, O_CLOEXEC ) < 0 )
|
||||
#endif
|
||||
{
|
||||
if( pipe(pipe_in) < 0 ) return SEC_E_INTERNAL_ERROR;
|
||||
fcntl( pipe_in[0], F_SETFD, FD_CLOEXEC );
|
||||
fcntl( pipe_in[1], F_SETFD, FD_CLOEXEC );
|
||||
}
|
||||
#ifdef HAVE_PIPE2
|
||||
if (pipe2( pipe_out, O_CLOEXEC ) < 0 )
|
||||
#endif
|
||||
{
|
||||
if( pipe(pipe_out) < 0 )
|
||||
{
|
||||
close(pipe_in[0]);
|
||||
close(pipe_in[1]);
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
fcntl( pipe_out[0], F_SETFD, FD_CLOEXEC );
|
||||
fcntl( pipe_out[1], F_SETFD, FD_CLOEXEC );
|
||||
}
|
||||
|
||||
if (!(helper = heap_alloc( sizeof(NegoHelper) )))
|
||||
{
|
||||
close(pipe_in[0]);
|
||||
close(pipe_in[1]);
|
||||
close(pipe_out[0]);
|
||||
close(pipe_out[1]);
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
helper->helper_pid = fork();
|
||||
|
||||
if(helper->helper_pid == -1)
|
||||
{
|
||||
close(pipe_in[0]);
|
||||
close(pipe_in[1]);
|
||||
close(pipe_out[0]);
|
||||
close(pipe_out[1]);
|
||||
heap_free( helper );
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if(helper->helper_pid == 0)
|
||||
{
|
||||
/* We're in the child now */
|
||||
dup2(pipe_out[0], 0);
|
||||
close(pipe_out[0]);
|
||||
close(pipe_out[1]);
|
||||
|
||||
dup2(pipe_in[1], 1);
|
||||
close(pipe_in[0]);
|
||||
close(pipe_in[1]);
|
||||
|
||||
execvp(prog, argv);
|
||||
|
||||
/* Whoops, we shouldn't get here. Big badaboom.*/
|
||||
write(STDOUT_FILENO, "BH\n", 3);
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*new_helper = helper;
|
||||
helper->major = helper->minor = helper->micro = -1;
|
||||
helper->com_buf = NULL;
|
||||
helper->com_buf_size = 0;
|
||||
helper->com_buf_offset = 0;
|
||||
helper->session_key = NULL;
|
||||
helper->neg_flags = 0;
|
||||
helper->crypt.ntlm.a4i = NULL;
|
||||
helper->crypt.ntlm2.send_a4i = NULL;
|
||||
helper->crypt.ntlm2.recv_a4i = NULL;
|
||||
helper->crypt.ntlm2.send_sign_key = NULL;
|
||||
helper->crypt.ntlm2.send_seal_key = NULL;
|
||||
helper->crypt.ntlm2.recv_sign_key = NULL;
|
||||
helper->crypt.ntlm2.recv_seal_key = NULL;
|
||||
helper->pipe_in = pipe_in[0];
|
||||
close(pipe_in[1]);
|
||||
helper->pipe_out = pipe_out[1];
|
||||
close(pipe_out[0]);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
#else
|
||||
ERR( "no fork support on this platform\n" );
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
static SECURITY_STATUS read_line(PNegoHelper helper, int *offset_len)
|
||||
{
|
||||
char *newline;
|
||||
int read_size;
|
||||
|
||||
if(helper->com_buf == NULL)
|
||||
{
|
||||
TRACE("Creating a new buffer for the helper\n");
|
||||
if (!(helper->com_buf = heap_alloc(INITIAL_BUFFER_SIZE)))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
/* Created a new buffer, size is INITIAL_BUFFER_SIZE, offset is 0 */
|
||||
helper->com_buf_size = INITIAL_BUFFER_SIZE;
|
||||
helper->com_buf_offset = 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
TRACE("offset = %d, size = %d\n", helper->com_buf_offset, helper->com_buf_size);
|
||||
if(helper->com_buf_offset + INITIAL_BUFFER_SIZE > helper->com_buf_size)
|
||||
{
|
||||
/* increment buffer size in INITIAL_BUFFER_SIZE steps */
|
||||
char *buf = heap_realloc(helper->com_buf, helper->com_buf_size + INITIAL_BUFFER_SIZE);
|
||||
TRACE("Resizing buffer!\n");
|
||||
if (!buf) return SEC_E_INSUFFICIENT_MEMORY;
|
||||
helper->com_buf_size += INITIAL_BUFFER_SIZE;
|
||||
helper->com_buf = buf;
|
||||
}
|
||||
if((read_size = read(helper->pipe_in, helper->com_buf + helper->com_buf_offset,
|
||||
helper->com_buf_size - helper->com_buf_offset)) <= 0)
|
||||
{
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
TRACE("read_size = %d, read: %s\n", read_size,
|
||||
debugstr_a(helper->com_buf + helper->com_buf_offset));
|
||||
helper->com_buf_offset += read_size;
|
||||
newline = memchr(helper->com_buf, '\n', helper->com_buf_offset);
|
||||
}while(newline == NULL);
|
||||
|
||||
/* Now, if there's a newline character, and we read more than that newline,
|
||||
* we have to store the offset so we can preserve the additional data.*/
|
||||
if( newline != helper->com_buf + helper->com_buf_offset)
|
||||
{
|
||||
TRACE("offset_len is calculated from %p - %p\n",
|
||||
(helper->com_buf + helper->com_buf_offset), newline+1);
|
||||
/* the length of the offset is the number of chars after the newline */
|
||||
*offset_len = (helper->com_buf + helper->com_buf_offset) - (newline + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*offset_len = 0;
|
||||
}
|
||||
|
||||
*newline = '\0';
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS preserve_unused(PNegoHelper helper, int offset_len)
|
||||
{
|
||||
TRACE("offset_len = %d\n", offset_len);
|
||||
|
||||
if(offset_len > 0)
|
||||
{
|
||||
memmove(helper->com_buf, helper->com_buf + helper->com_buf_offset,
|
||||
offset_len);
|
||||
helper->com_buf_offset = offset_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
helper->com_buf_offset = 0;
|
||||
}
|
||||
|
||||
TRACE("helper->com_buf_offset was set to: %d\n", helper->com_buf_offset);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS run_helper(PNegoHelper helper, char *buffer,
|
||||
unsigned int max_buflen, int *buflen)
|
||||
{
|
||||
int offset_len;
|
||||
SECURITY_STATUS sec_status = SEC_E_OK;
|
||||
|
||||
TRACE("In helper: sending %s\n", debugstr_a(buffer));
|
||||
|
||||
/* buffer + '\n' */
|
||||
write(helper->pipe_out, buffer, lstrlenA(buffer));
|
||||
write(helper->pipe_out, "\n", 1);
|
||||
|
||||
if((sec_status = read_line(helper, &offset_len)) != SEC_E_OK)
|
||||
{
|
||||
return sec_status;
|
||||
}
|
||||
|
||||
TRACE("In helper: received %s\n", debugstr_a(helper->com_buf));
|
||||
*buflen = lstrlenA(helper->com_buf);
|
||||
|
||||
if( *buflen > max_buflen)
|
||||
{
|
||||
ERR("Buffer size too small(%d given, %d required) dropping data!\n",
|
||||
max_buflen, *buflen);
|
||||
return SEC_E_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if( *buflen < 2 )
|
||||
{
|
||||
return SEC_E_ILLEGAL_MESSAGE;
|
||||
}
|
||||
|
||||
/* We only get ERR if the input size is too big. On a GENSEC error,
|
||||
* ntlm_auth will return BH */
|
||||
if(strncmp(helper->com_buf, "ERR", 3) == 0)
|
||||
{
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
memcpy(buffer, helper->com_buf, *buflen+1);
|
||||
|
||||
sec_status = preserve_unused(helper, offset_len);
|
||||
|
||||
return sec_status;
|
||||
}
|
||||
|
||||
void cleanup_helper(PNegoHelper helper)
|
||||
{
|
||||
|
||||
TRACE("Killing helper %p\n", helper);
|
||||
if(helper == NULL)
|
||||
return;
|
||||
|
||||
heap_free(helper->com_buf);
|
||||
heap_free(helper->session_key);
|
||||
|
||||
/* closing stdin will terminate ntlm_auth */
|
||||
close(helper->pipe_out);
|
||||
close(helper->pipe_in);
|
||||
|
||||
#ifdef HAVE_FORK
|
||||
if (helper->helper_pid > 0) /* reap child */
|
||||
{
|
||||
pid_t wret;
|
||||
do {
|
||||
wret = waitpid(helper->helper_pid, NULL, 0);
|
||||
} while (wret < 0 && errno == EINTR);
|
||||
}
|
||||
#endif
|
||||
|
||||
heap_free(helper);
|
||||
}
|
||||
|
||||
void check_version(PNegoHelper helper)
|
||||
{
|
||||
char temp[80];
|
||||
char *newline;
|
||||
int major = 0, minor = 0, micro = 0, ret;
|
||||
|
||||
TRACE("Checking version of helper\n");
|
||||
if(helper != NULL)
|
||||
{
|
||||
int len = read(helper->pipe_in, temp, sizeof(temp)-1);
|
||||
if (len > 8)
|
||||
{
|
||||
if((newline = memchr(temp, '\n', len)) != NULL)
|
||||
*newline = '\0';
|
||||
else
|
||||
temp[len] = 0;
|
||||
|
||||
TRACE("Exact version is %s\n", debugstr_a(temp));
|
||||
ret = sscanf(temp, "Version %d.%d.%d", &major, &minor, µ);
|
||||
if(ret != 3)
|
||||
{
|
||||
ERR("Failed to get the helper version.\n");
|
||||
helper->major = helper->minor = helper->micro = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Version recognized: %d.%d.%d\n", major, minor, micro);
|
||||
helper->major = major;
|
||||
helper->minor = minor;
|
||||
helper->micro = micro;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* This file implements RFC 2104 (HMAC) for the MD5 provider.
|
||||
* It is needed for NTLM2 signing and sealing.
|
||||
*/
|
||||
|
||||
#include "hmac_md5.h"
|
||||
|
||||
void HMACMD5Init(HMAC_MD5_CTX *ctx, const unsigned char *key, unsigned int key_len)
|
||||
{
|
||||
int i;
|
||||
unsigned char inner_padding[64];
|
||||
unsigned char temp_key[16];
|
||||
|
||||
if(key_len > 64)
|
||||
{
|
||||
MD5_CTX temp_ctx;
|
||||
|
||||
MD5Init(&temp_ctx);
|
||||
MD5Update(&temp_ctx, key, key_len);
|
||||
MD5Final(&temp_ctx);
|
||||
memcpy(temp_key, temp_ctx.digest, 16);
|
||||
|
||||
key = temp_key;
|
||||
key_len = 16;
|
||||
}
|
||||
|
||||
memset(inner_padding, 0, 64);
|
||||
memset(ctx->outer_padding, 0, 64);
|
||||
memcpy(inner_padding, key, key_len);
|
||||
memcpy(ctx->outer_padding, key, key_len);
|
||||
|
||||
for(i = 0; i < 64; ++i)
|
||||
{
|
||||
inner_padding[i] ^= 0x36;
|
||||
ctx->outer_padding[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
MD5Init(&(ctx->ctx));
|
||||
MD5Update(&(ctx->ctx), inner_padding, 64);
|
||||
}
|
||||
|
||||
void HMACMD5Update(HMAC_MD5_CTX *ctx, const unsigned char *data, unsigned int data_len)
|
||||
{
|
||||
MD5Update(&(ctx->ctx), data, data_len);
|
||||
}
|
||||
|
||||
void HMACMD5Final(HMAC_MD5_CTX *ctx, unsigned char *digest)
|
||||
{
|
||||
MD5_CTX outer_ctx;
|
||||
unsigned char inner_digest[16];
|
||||
|
||||
MD5Final(&(ctx->ctx));
|
||||
memcpy(inner_digest, ctx->ctx.digest, 16);
|
||||
|
||||
MD5Init(&outer_ctx);
|
||||
MD5Update(&outer_ctx, ctx->outer_padding, 64);
|
||||
MD5Update(&outer_ctx, inner_digest, 16);
|
||||
MD5Final(&outer_ctx);
|
||||
|
||||
memcpy(digest, outer_ctx.digest, 16);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* This file holds the declarations needed for HMAC-MD5.
|
||||
*/
|
||||
|
||||
#ifndef _HMAC_MD5_H_
|
||||
#define _HMAC_MD5_H_
|
||||
|
||||
#include <string.h>
|
||||
#include "windef.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int i[2];
|
||||
unsigned int buf[4];
|
||||
unsigned char in[64];
|
||||
unsigned char digest[16];
|
||||
} MD5_CTX;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
unsigned char outer_padding[64];
|
||||
} HMAC_MD5_CTX;
|
||||
|
||||
void WINAPI MD5Init( MD5_CTX *ctx );
|
||||
void WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len );
|
||||
void WINAPI MD5Final( MD5_CTX *ctx );
|
||||
|
||||
void HMACMD5Init(HMAC_MD5_CTX *ctx, const unsigned char *key, unsigned int key_len) DECLSPEC_HIDDEN;
|
||||
void HMACMD5Update(HMAC_MD5_CTX *ctx, const unsigned char *data, unsigned int data_len) DECLSPEC_HIDDEN;
|
||||
void HMACMD5Final(HMAC_MD5_CTX *ctx, unsigned char *digest) DECLSPEC_HIDDEN;
|
||||
#endif /*_HMAC_MD5_H_*/
|
|
@ -58,6 +58,17 @@ struct sec_handle
|
|||
SecHandle handle_ntlm;
|
||||
};
|
||||
|
||||
/* matches layout from msv1_0 */
|
||||
struct ntlm_cred
|
||||
{
|
||||
int mode;
|
||||
char *username_arg;
|
||||
char *domain_arg;
|
||||
char *password;
|
||||
int password_len;
|
||||
int no_cached_credentials; /* don't try to use cached Samba credentials */
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* AcquireCredentialsHandleW
|
||||
*/
|
||||
|
@ -92,7 +103,7 @@ static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleW(
|
|||
fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, &cred->handle_ntlm, ptsExpiry );
|
||||
if (ret == SEC_E_OK)
|
||||
{
|
||||
NtlmCredentials *ntlm_cred = (NtlmCredentials *)cred->handle_ntlm.dwLower;
|
||||
struct ntlm_cred *ntlm_cred = (struct ntlm_cred *)cred->handle_ntlm.dwLower;
|
||||
ntlm_cred->no_cached_credentials = (pAuthData == NULL);
|
||||
cred->ntlm = package->provider;
|
||||
}
|
||||
|
|
2029
dlls/secur32/ntlm.c
2029
dlls/secur32/ntlm.c
File diff suppressed because it is too large
Load Diff
|
@ -44,65 +44,6 @@ typedef struct _SecurePackage
|
|||
SecureProvider *provider;
|
||||
} SecurePackage;
|
||||
|
||||
typedef enum _helper_mode {
|
||||
NTLM_SERVER,
|
||||
NTLM_CLIENT,
|
||||
NUM_HELPER_MODES
|
||||
} HelperMode;
|
||||
|
||||
typedef struct tag_arc4_info {
|
||||
unsigned char x, y;
|
||||
unsigned char state[256];
|
||||
} arc4_info;
|
||||
|
||||
typedef struct _NegoHelper {
|
||||
pid_t helper_pid;
|
||||
HelperMode mode;
|
||||
int pipe_in;
|
||||
int pipe_out;
|
||||
int major;
|
||||
int minor;
|
||||
int micro;
|
||||
char *com_buf;
|
||||
int com_buf_size;
|
||||
int com_buf_offset;
|
||||
BYTE *session_key;
|
||||
ULONG neg_flags;
|
||||
struct {
|
||||
struct {
|
||||
ULONG seq_num;
|
||||
arc4_info *a4i;
|
||||
} ntlm;
|
||||
struct {
|
||||
BYTE *send_sign_key;
|
||||
BYTE *send_seal_key;
|
||||
BYTE *recv_sign_key;
|
||||
BYTE *recv_seal_key;
|
||||
ULONG send_seq_no;
|
||||
ULONG recv_seq_no;
|
||||
arc4_info *send_a4i;
|
||||
arc4_info *recv_a4i;
|
||||
} ntlm2;
|
||||
} crypt;
|
||||
} NegoHelper, *PNegoHelper;
|
||||
|
||||
typedef struct _NtlmCredentials
|
||||
{
|
||||
HelperMode mode;
|
||||
|
||||
/* these are all in the Unix codepage */
|
||||
char *username_arg;
|
||||
char *domain_arg;
|
||||
char *password; /* not nul-terminated */
|
||||
int pwlen;
|
||||
int no_cached_credentials; /* don't try to use cached Samba credentials */
|
||||
} NtlmCredentials, *PNtlmCredentials;
|
||||
|
||||
typedef enum _sign_direction {
|
||||
NTLM_SEND,
|
||||
NTLM_RECV
|
||||
} SignDirection;
|
||||
|
||||
/* Allocates space for and initializes a new provider. If fnTableA or fnTableW
|
||||
* is non-NULL, assumes the provider is built-in, and if moduleName is non-NULL,
|
||||
* means must load the LSA/user mode functions tables from external SSP/AP module.
|
||||
|
@ -136,60 +77,11 @@ PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str) DECLSPEC_HIDDEN;
|
|||
/* Initialization functions for built-in providers */
|
||||
void SECUR32_initSchannelSP(void) DECLSPEC_HIDDEN;
|
||||
void SECUR32_initNegotiateSP(void) DECLSPEC_HIDDEN;
|
||||
void SECUR32_initNTLMSP(void) DECLSPEC_HIDDEN;
|
||||
void load_auth_packages(void) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Cleanup functions for built-in providers */
|
||||
void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Functions from dispatcher.c used elsewhere in the code */
|
||||
SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
|
||||
char * const argv[]) DECLSPEC_HIDDEN;
|
||||
|
||||
SECURITY_STATUS run_helper(PNegoHelper helper, char *buffer,
|
||||
unsigned int max_buflen, int *buflen) DECLSPEC_HIDDEN;
|
||||
|
||||
void cleanup_helper(PNegoHelper helper) DECLSPEC_HIDDEN;
|
||||
|
||||
void check_version(PNegoHelper helper) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Functions from base64_codec.c used elsewhere */
|
||||
SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf,
|
||||
int max_len, int *out_len) DECLSPEC_HIDDEN;
|
||||
|
||||
SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf,
|
||||
int max_len, int *out_len) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Functions from util.c */
|
||||
SECURITY_STATUS SECUR32_CreateNTLM1SessionKey(PBYTE password, int len, PBYTE session_key) DECLSPEC_HIDDEN;
|
||||
SECURITY_STATUS SECUR32_CreateNTLM2SubKeys(PNegoHelper helper) DECLSPEC_HIDDEN;
|
||||
arc4_info *SECUR32_arc4Alloc(void) DECLSPEC_HIDDEN;
|
||||
void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen) DECLSPEC_HIDDEN;
|
||||
void SECUR32_arc4Process(arc4_info *a4i, BYTE *inoutString, unsigned int length) DECLSPEC_HIDDEN;
|
||||
void SECUR32_arc4Cleanup(arc4_info *a4i) DECLSPEC_HIDDEN;
|
||||
|
||||
/* NTLMSSP flags indicating the negotiated features */
|
||||
#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
|
||||
#define NTLMSSP_NEGOTIATE_OEM 0x00000002
|
||||
#define NTLMSSP_REQUEST_TARGET 0x00000004
|
||||
#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
|
||||
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
|
||||
#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040
|
||||
#define NTLMSSP_NEGOTIATE_LM_SESSION_KEY 0x00000080
|
||||
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
|
||||
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
|
||||
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
|
||||
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000
|
||||
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
|
||||
#define NTLMSSP_NEGOTIATE_TARGET_TYPE_DOMAIN 0x00010000
|
||||
#define NTLMSSP_NEGOTIATE_TARGET_TYPE_SERVER 0x00020000
|
||||
#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
|
||||
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
|
||||
#define NTLMSSP_NEGOTIATE_128 0x20000000
|
||||
#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000
|
||||
#define NTLMSSP_NEGOTIATE_56 0x80000000
|
||||
|
||||
|
||||
/* schannel internal interface */
|
||||
typedef struct schan_imp_session_opaque *schan_imp_session;
|
||||
|
||||
|
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* This file contains various helper functions needed for NTLM and maybe others
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "rpc.h"
|
||||
#include "sspi.h"
|
||||
#include "secur32_priv.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
||||
|
||||
static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant";
|
||||
static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant";
|
||||
static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int buf[4];
|
||||
unsigned int i[2];
|
||||
unsigned char in[64];
|
||||
unsigned char digest[16];
|
||||
} MD4_CTX;
|
||||
|
||||
/* And now the same with a different memory layout. */
|
||||
typedef struct
|
||||
{
|
||||
unsigned int i[2];
|
||||
unsigned int buf[4];
|
||||
unsigned char in[64];
|
||||
unsigned char digest[16];
|
||||
} MD5_CTX;
|
||||
|
||||
VOID WINAPI MD4Init( MD4_CTX *ctx );
|
||||
VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len );
|
||||
VOID WINAPI MD4Final( MD4_CTX *ctx );
|
||||
VOID WINAPI MD5Init( MD5_CTX *ctx );
|
||||
VOID WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len );
|
||||
VOID WINAPI MD5Final( MD5_CTX *ctx );
|
||||
|
||||
SECURITY_STATUS SECUR32_CreateNTLM1SessionKey(PBYTE password, int len, PBYTE session_key)
|
||||
{
|
||||
MD4_CTX ctx;
|
||||
BYTE ntlm_hash[16];
|
||||
|
||||
TRACE("(%p, %p)\n", password, session_key);
|
||||
|
||||
MD4Init(&ctx);
|
||||
MD4Update(&ctx, password, len);
|
||||
MD4Final(&ctx);
|
||||
|
||||
memcpy(ntlm_hash, ctx.digest, 0x10);
|
||||
|
||||
MD4Init(&ctx);
|
||||
MD4Update(&ctx, ntlm_hash, 0x10u);
|
||||
MD4Final(&ctx);
|
||||
|
||||
memcpy(session_key, ctx.digest, 0x10);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static void SECUR32_CalcNTLM2Subkey(const BYTE *session_key, const char *magic, PBYTE subkey)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, session_key, 16);
|
||||
MD5Update(&ctx, (const unsigned char*)magic, lstrlenA(magic)+1);
|
||||
MD5Final(&ctx);
|
||||
memcpy(subkey, ctx.digest, 16);
|
||||
}
|
||||
|
||||
/* This assumes we do have a valid NTLM2 user session key */
|
||||
SECURITY_STATUS SECUR32_CreateNTLM2SubKeys(PNegoHelper helper)
|
||||
{
|
||||
helper->crypt.ntlm2.send_sign_key = heap_alloc(16);
|
||||
helper->crypt.ntlm2.send_seal_key = heap_alloc(16);
|
||||
helper->crypt.ntlm2.recv_sign_key = heap_alloc(16);
|
||||
helper->crypt.ntlm2.recv_seal_key = heap_alloc(16);
|
||||
|
||||
if(helper->mode == NTLM_CLIENT)
|
||||
{
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_sign_constant,
|
||||
helper->crypt.ntlm2.send_sign_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_seal_constant,
|
||||
helper->crypt.ntlm2.send_seal_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_sign_constant,
|
||||
helper->crypt.ntlm2.recv_sign_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_seal_constant,
|
||||
helper->crypt.ntlm2.recv_seal_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_sign_constant,
|
||||
helper->crypt.ntlm2.send_sign_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, server_to_client_seal_constant,
|
||||
helper->crypt.ntlm2.send_seal_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_sign_constant,
|
||||
helper->crypt.ntlm2.recv_sign_key);
|
||||
SECUR32_CalcNTLM2Subkey(helper->session_key, client_to_server_seal_constant,
|
||||
helper->crypt.ntlm2.recv_seal_key);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
arc4_info *SECUR32_arc4Alloc(void)
|
||||
{
|
||||
arc4_info *a4i = heap_alloc(sizeof(arc4_info));
|
||||
return a4i;
|
||||
}
|
||||
|
||||
/*
|
||||
* The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
|
||||
* which in turn is based on public domain code by Wei Dai
|
||||
*/
|
||||
void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen)
|
||||
{
|
||||
unsigned int keyIndex = 0, stateIndex = 0;
|
||||
unsigned int i, a;
|
||||
|
||||
TRACE("(%p, %p, %d)\n", a4i, key, keyLen);
|
||||
|
||||
a4i->x = a4i->y = 0;
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
a4i->state[i] = i;
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
{
|
||||
a = a4i->state[i];
|
||||
stateIndex += key[keyIndex] + a;
|
||||
stateIndex &= 0xff;
|
||||
a4i->state[i] = a4i->state[stateIndex];
|
||||
a4i->state[stateIndex] = a;
|
||||
if (++keyIndex >= keyLen)
|
||||
keyIndex = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SECUR32_arc4Process(arc4_info *a4i, BYTE *inoutString, unsigned int length)
|
||||
{
|
||||
BYTE *const s=a4i->state;
|
||||
unsigned int x = a4i->x;
|
||||
unsigned int y = a4i->y;
|
||||
unsigned int a, b;
|
||||
|
||||
while(length--)
|
||||
{
|
||||
x = (x+1) & 0xff;
|
||||
a = s[x];
|
||||
y = (y+a) & 0xff;
|
||||
b = s[y];
|
||||
s[x] = b;
|
||||
s[y] = a;
|
||||
*inoutString++ ^= s[(a+b) & 0xff];
|
||||
}
|
||||
|
||||
a4i->x = x;
|
||||
a4i->y = y;
|
||||
}
|
||||
|
||||
void SECUR32_arc4Cleanup(arc4_info *a4i)
|
||||
{
|
||||
heap_free(a4i);
|
||||
}
|
Loading…
Reference in New Issue