secur32: Getting some real functionality into the NTLM provider, try 2
Kai Blin
blin at gmx.net
Wed Aug 24 18:26:14 CDT 2005
base64_codec.c converts to and from base64 encoding, which is used by
ntlm_auth.
dispatcher.c runs ntlm_auth to do authentication. This will also be
used by the Negotiate provider. Fixed to close all file descriptors.
Also won't use stdio anymore.
NTLM will authenticate clients against ntlm_auth. If it's a samba3
ntlm_auth, this requires access to the winbindd privileged pipe. Client
side authentication in samba3 will work, it's broken in samba4's
ntlm_auth, but will work there once ntlm_auth is fixed.
Also added some NTLM specific tests.
Changelog:
Kai Blin <blin at gmx.net>
Get functionality into the NTLM security provider. Added some tests.
--
Kai Blin, (blin at gmx dot net)
My Bonnie looked into a gas tank,
The height of its contents to see!
She lit a small match to assist her,
Oh, bring back my Bonnie to me.
-------------- next part --------------
Index: dlls/secur32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/secur32/Makefile.in,v
retrieving revision 1.6
diff -u -3 -r1.6 Makefile.in
--- dlls/secur32/Makefile.in 17 Aug 2005 09:52:30 -0000 1.6
+++ dlls/secur32/Makefile.in 24 Aug 2005 23:13:11 -0000
@@ -4,9 +4,11 @@
VPATH = @srcdir@
MODULE = secur32.dll
IMPORTLIB = libsecur32.$(IMPLIBEXT)
-IMPORTS = user32 advapi32 kernel32 ntdll
+IMPORTS = user32 advapi32 kernel32 netapi32 ntdll
C_SRCS = \
+ base64_codec.c \
+ dispatcher.c \
negotiate.c \
ntlm.c \
schannel.c \
Index: dlls/secur32/ntlm.c
===================================================================
RCS file: /home/wine/wine/dlls/secur32/ntlm.c,v
retrieving revision 1.1
diff -u -3 -r1.1 ntlm.c
--- dlls/secur32/ntlm.c 17 Aug 2005 09:52:30 -0000 1.1
+++ dlls/secur32/ntlm.c 24 Aug 2005 23:13:16 -0000
@@ -16,13 +16,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This file implements the NTLM security provider.
- * FIXME: So far, this beast doesn't do anything.
*/
#include <assert.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
+#include "winnls.h"
+#include "rpc.h"
#include "sspi.h"
+#include "lm.h"
#include "secur32_priv.h"
#include "wine/debug.h"
@@ -31,7 +33,6 @@
static char ntlm_name_A[] = "NTLM";
static WCHAR ntlm_name_W[] = {'N', 'T', 'L', 'M', 0};
-
/***********************************************************************
* QueryCredentialsAttributesA
*/
@@ -74,27 +75,269 @@
return ret;
}
-static SECURITY_STATUS ntlm_AcquireCredentialsHandle(ULONG fCredentialsUse,
- PCredHandle phCredential, PTimeStamp ptsExpiry)
+/***********************************************************************
+ * AcquireCredentialsHandleW
+ */
+static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
+ PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
SECURITY_STATUS ret;
+ TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
+ debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
+ pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
- if(fCredentialsUse == SECPKG_CRED_BOTH)
- {
- ret = SEC_E_NO_CREDENTIALS;
- }
- else
- {
- /* Ok, just store the direction like schannel does for now.
- * FIXME: This should probably do something useful later on
- */
- phCredential->dwUpper = fCredentialsUse;
- phCredential->dwLower = 0;
- /* Same here, shamelessly stolen from schannel.c */
- if (ptsExpiry)
- ptsExpiry->QuadPart = 0;
- ret = SEC_E_OK;
+ PNegoHelper helper = NULL;
+
+ SEC_CHAR *client_user_arg = NULL;
+ SEC_CHAR *client_domain_arg = NULL;
+ SEC_CHAR *program = NULL;
+ SEC_CHAR *client_protocol = NULL;
+ SEC_CHAR *server_protocol = NULL;
+
+ SEC_WCHAR *convert = NULL;
+
+ /* convert the program name to Unicode */
+ int convert_size = MultiByteToWideChar(CP_ACP, 0, "ntlm_auth", 10, NULL,0);
+ convert = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, convert_size
+ * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, "ntlm_auth", 10, convert, convert_size);
+
+ /* and back to the CP_UNIXCP */
+ int unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ convert, convert_size, NULL, 0, NULL, NULL);
+ program = (SEC_CHAR *)HeapAlloc(GetProcessHeap(), 0, unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, convert, convert_size,
+ program, unixcp_size, NULL, NULL);
+
+ /* now for the client's protocol helper argument, to unicode and back */
+ convert_size = MultiByteToWideChar(CP_ACP, 0,
+ "--helper-protocol=ntlmssp-client-1", -1, NULL, 0);
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0, convert,
+ convert_size * sizeof(SEC_WCHAR *));
+ MultiByteToWideChar(CP_ACP, 0, "--helper-protocol=ntlmssp-client-1", -1,
+ convert, convert_size);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ convert, convert_size, NULL, 0, NULL, NULL);
+ client_protocol = (SEC_CHAR *)HeapAlloc(GetProcessHeap(), 0, unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, convert, convert_size,
+ client_protocol, unixcp_size, NULL, NULL);
+
+ /* server's protocol helper, to Unicode and back */
+ convert_size = MultiByteToWideChar(CP_ACP, 0,
+ "--helper-protocol=squid-2.5-ntlmssp", -1, NULL, 0);
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0, convert,
+ convert_size * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, "--helper-protocol=squid-2.5-ntlmssp", -1,
+ convert, convert_size);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ convert, convert_size, NULL, 0, NULL, NULL);
+ server_protocol = (SEC_CHAR*)HeapAlloc(GetProcessHeap(), 0, unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, convert, convert_size,
+ server_protocol, unixcp_size, NULL, NULL);
+
+ SEC_CHAR *server_argv[] = { program,
+ server_protocol,
+ NULL };
+
+ switch(fCredentialUse)
+ {
+ case SECPKG_CRED_INBOUND:
+ if( (ret = fork_helper(&helper, program, server_argv)) !=
+ SEC_E_OK)
+ {
+ phCredential = NULL;
+ break;
+ }
+ else
+ {
+ helper->mode = NTLM_SERVER;
+ phCredential->dwUpper = fCredentialUse;
+ phCredential->dwLower = (DWORD)helper;
+ }
+ ret = SEC_E_OK;
+ break;
+ case SECPKG_CRED_OUTBOUND:
+ if(pAuthData == NULL)
+ {
+ LPWKSTA_USER_INFO_1 ui = NULL;
+ NET_API_STATUS status;
+
+ if((status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui)) !=
+ NERR_Success)
+ {
+ ret = SEC_E_NO_CREDENTIALS;
+ phCredential = NULL;
+ break;
+ }
+
+ if(ui != NULL)
+ {
+ /* size of the user name + size of the Unicode version of
+ * --username= + the null terminator. */
+ convert_size = MultiByteToWideChar(CP_ACP,0, "--username=",
+ -1, NULL, 0) + lstrlenW(ui->wkui1_username) + 1;
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0,
+ convert, convert_size * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, "--username=", -1, convert,
+ convert_size);
+ lstrcatW(convert, ui->wkui1_username);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP,
+ WC_NO_BEST_FIT_CHARS, convert, convert_size,
+ NULL, 0, NULL, NULL);
+ client_user_arg = (SEC_CHAR *)HeapAlloc(GetProcessHeap(),0,
+ unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ convert, convert_size, client_user_arg,
+ unixcp_size, NULL, NULL);
+
+ /* same for the domain */
+ convert_size = MultiByteToWideChar(CP_ACP, 0, "--domain=",
+ -1, NULL, 0) + lstrlenW(ui->wkui1_logon_domain)+ 1;
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0,
+ convert, convert_size * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, "--domain=", -1, convert,
+ convert_size);
+ lstrcatW(convert, ui->wkui1_logon_domain);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP,
+ WC_NO_BEST_FIT_CHARS, convert, convert_size,
+ NULL, 0, NULL, NULL);
+ client_domain_arg = (SEC_CHAR *)HeapAlloc(GetProcessHeap(),
+ 0, unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ convert, convert_size, client_domain_arg,
+ unixcp_size, NULL, NULL);
+ }
+ else
+ {
+ ret = SEC_E_NO_CREDENTIALS;
+ phCredential = NULL;
+ break;
+ }
+
+ }
+ else
+ {
+ PSEC_WINNT_AUTH_IDENTITY_W auth_data =
+ (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
+
+ if(auth_data->UserLength != 0)
+ {
+ /* Get username and domain from pAuthData */
+ TRACE("Username is %s\n", debugstr_w(auth_data->User));
+ convert_size = MultiByteToWideChar(CP_ACP,0, "--username=",
+ -1, NULL, 0) + auth_data->UserLength + 2;
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0,
+ convert, convert_size * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP,0, "--username=", -1, convert,
+ convert_size);
+ lstrcatW(convert, auth_data->User);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP,
+ WC_NO_BEST_FIT_CHARS, convert, convert_size, NULL, 0,
+ NULL, NULL);
+ client_user_arg = (SEC_CHAR *)HeapAlloc(GetProcessHeap(),0,
+ unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, convert,
+ convert_size, client_user_arg, unixcp_size, NULL,NULL);
+ }
+ else
+ {
+ ret = SEC_E_NO_CREDENTIALS;
+ phCredential = NULL;
+ break;
+ }
+ if(auth_data->DomainLength != 0)
+ {
+ convert_size = MultiByteToWideChar(CP_ACP,0, "--domain=",
+ -1, NULL, 0) + auth_data->DomainLength + 2;
+ convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0,
+ convert, convert_size * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP,0, "--domain=", -1, convert,
+ convert_size);
+ lstrcatW(convert, auth_data->Domain);
+ unixcp_size = WideCharToMultiByte(CP_UNIXCP,
+ WC_NO_BEST_FIT_CHARS, convert, convert_size+1, NULL, 0,
+ NULL, NULL);
+ client_domain_arg = (SEC_CHAR *)HeapAlloc(GetProcessHeap(),0,
+ unixcp_size);
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, convert,
+ convert_size, client_domain_arg, unixcp_size, NULL,
+ NULL);
+ }
+ else
+ {
+ ret = SEC_E_NO_CREDENTIALS;
+ phCredential = NULL;
+ break;
+ }
+
+ }
+
+ SEC_CHAR *client_argv[] =
+ {
+ program,
+ client_protocol,
+ client_user_arg,
+ client_domain_arg,
+ NULL
+ };
+
+ if( (ret = fork_helper(&helper, program, client_argv)) !=
+ SEC_E_OK)
+ {
+ phCredential = NULL;
+ break;
+ }
+ else
+ {
+ helper->mode = NTLM_CLIENT;
+
+ if(pAuthData != NULL)
+ {
+ PSEC_WINNT_AUTH_IDENTITY_W auth_data =
+ (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
+
+ if(auth_data->PasswordLength != 0)
+ {
+ helper->pwlen = WideCharToMultiByte(CP_UNIXCP,
+ WC_NO_BEST_FIT_CHARS, auth_data->Password,
+ auth_data->PasswordLength+1, NULL, 0, NULL, NULL);
+
+ helper->password = (SEC_CHAR *)HeapAlloc(GetProcessHeap(),
+ 0, helper->pwlen);
+
+ WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
+ auth_data->Password, auth_data->PasswordLength+1,
+ helper->password, helper->pwlen, NULL, NULL);
+ }
+ }
+
+ phCredential->dwUpper = fCredentialUse;
+ phCredential->dwLower = (DWORD)helper;
+ TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n",
+ phCredential->dwUpper, phCredential->dwLower);
+ }
+ ret = SEC_E_OK;
+ break;
+ case SECPKG_CRED_BOTH:
+ FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n");
+ ret = SEC_E_UNSUPPORTED_FUNCTION;
+ phCredential = NULL;
+ break;
+ default:
+ phCredential = NULL;
+ ret = SEC_E_UNKNOWN_CREDENTIALS;
}
+
+
+ HeapFree(GetProcessHeap(), 0, client_user_arg);
+ HeapFree(GetProcessHeap(), 0, client_domain_arg);
+ HeapFree(GetProcessHeap(), 0, program);
+ HeapFree(GetProcessHeap(), 0, client_protocol);
+ HeapFree(GetProcessHeap(), 0, server_protocol);
+ HeapFree(GetProcessHeap(), 0, convert);
+
return ret;
}
@@ -106,33 +349,126 @@
PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
+ SECURITY_STATUS ret;
TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
- return ntlm_AcquireCredentialsHandle(fCredentialUse, phCredential,
- ptsExpiry);
-}
-/***********************************************************************
- * AcquireCredentialsHandleW
- */
-static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
- SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
- PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
- PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
-{
- TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
- debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
- pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
- return ntlm_AcquireCredentialsHandle(fCredentialUse, phCredential,
+ int user_sizeW, domain_sizeW, passwd_sizeW;
+
+ SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL;
+ SEC_WCHAR *principal = NULL, *package = NULL;
+
+ PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
+
+ if(pszPrincipal != NULL)
+ {
+ int principal_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPrincipal, -1,
+ NULL, 0);
+ principal = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+ principal_sizeW * sizeof(SEC_WCHAR));
+
+ MultiByteToWideChar(CP_ACP, 0, pszPrincipal, -1, principal,
+ principal_sizeW * sizeof(SEC_WCHAR));
+ }
+
+ if(pszPackage != NULL)
+ {
+ int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
+ NULL, 0);
+
+ package = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+ package_sizeW * sizeof(SEC_WCHAR));
+
+ MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
+ }
+
+
+ if(pAuthData != NULL)
+ {
+ PSEC_WINNT_AUTH_IDENTITY_A identity =
+ (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
+
+ pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)HeapAlloc(GetProcessHeap(), 0,
+ sizeof(SEC_WINNT_AUTH_IDENTITY_W));
+
+ if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
+ {
+ if(identity->UserLength != 0)
+ {
+ user_sizeW = MultiByteToWideChar(CP_ACP, 0, identity->User,
+ identity->UserLength+1, NULL, 0);
+ user = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, user_sizeW *
+ sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, identity->User,
+ identity->UserLength+1, user, user_sizeW);
+ }
+ else
+ {
+ user_sizeW = 0;
+ }
+
+ if(identity->DomainLength != 0)
+ {
+ domain_sizeW = MultiByteToWideChar(CP_ACP, 0, identity->Domain,
+ identity->DomainLength+1, NULL, 0);
+ domain = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, domain_sizeW
+ * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, identity->Domain,
+ identity->DomainLength+1, domain, domain_sizeW);
+ }
+ else
+ {
+ domain_sizeW = 0;
+ }
+
+ if(identity->PasswordLength != 0)
+ {
+ passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, identity->Password,
+ identity->PasswordLength+1, NULL, 0);
+ passwd = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, passwd_sizeW
+ * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, identity->Password,
+ identity->PasswordLength, passwd, passwd_sizeW);
+ }
+ else
+ {
+ passwd_sizeW = 0;
+ }
+
+ pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+ pAuthDataW->User = (unsigned short *)user;
+ pAuthDataW->UserLength = (unsigned long)user_sizeW;
+ pAuthDataW->Domain = (unsigned short *)domain;
+ pAuthDataW->DomainLength = (unsigned long)domain_sizeW;
+ pAuthDataW->Password = (unsigned short *)passwd;
+ pAuthDataW->PasswordLength = (unsigned long)passwd_sizeW;
+ }
+ else
+ {
+ memcpy(pAuthDataW, identity, sizeof(SEC_WINNT_AUTH_IDENTITY_W));
+ }
+ }
+
+ ret = ntlm_AcquireCredentialsHandleW(principal, package, fCredentialUse,
+ pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
ptsExpiry);
+
+ HeapFree(GetProcessHeap(), 0, principal);
+ HeapFree(GetProcessHeap(), 0, package);
+ HeapFree(GetProcessHeap(), 0, user);
+ HeapFree(GetProcessHeap(), 0, domain);
+ HeapFree(GetProcessHeap(), 0, passwd);
+ HeapFree(GetProcessHeap(), 0, pAuthDataW);
+
+ return ret;
}
/***********************************************************************
- * InitializeSecurityContextA
+ * InitializeSecurityContextW
*/
-static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
- PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
+static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
+ PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
@@ -140,10 +476,314 @@
SECURITY_STATUS ret;
TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
- debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+ debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
if(phCredential){
- ret = SEC_E_UNSUPPORTED_FUNCTION;
+ /* As the server side of sspi never calls this, make sure that
+ * the handler is a client handler.
+ */
+ PNegoHelper helper = (PNegoHelper)phCredential->dwLower;
+ ULONG ctxt_attr = 0;
+ if(helper->mode == NTLM_CLIENT)
+ {
+ /****************************************
+ * When communicating with the client, there can be the
+ * following reply packets:
+ * YR <base64 blob> should be sent to the server
+ * PW should be sent back to helper with
+ * base64 encoded password
+ * AF <base64 blob> client is done, blob should be
+ * sent to server with KK prefixed
+ * BH <char reason> something broke
+ */
+ BOOL first = FALSE;
+ /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
+ unsigned char* buffer = (char*) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(char) * 2010);
+ PBYTE bin = (PBYTE) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(BYTE) * 2010);
+ int buffer_len, bin_len, max_len = 2010;
+
+ if((phContext == NULL) && (pInput == NULL))
+ first = TRUE;
+ if (pszTargetName)
+ {
+ TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
+ }
+ /* Handle all the flags */
+ if(fContextReq & ISC_REQ_ALLOCATE_MEMORY)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n");
+ }
+ if(fContextReq & ISC_REQ_CONFIDENTIALITY)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
+ }
+ if(fContextReq & ISC_REQ_CONNECTION)
+ {
+ /* This is default, so we'll enable it */
+ ctxt_attr |= ISC_RET_CONNECTION;
+ }
+ if(fContextReq & ISC_REQ_EXTENDED_ERROR)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n");
+ }
+ if(fContextReq & ISC_REQ_INTEGRITY)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_INTEGRITY stub\n");
+ }
+ if(fContextReq & ISC_REQ_MUTUAL_AUTH)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n");
+ }
+ if(fContextReq & ISC_REQ_REPLAY_DETECT)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n");
+ }
+ if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n");
+ }
+ if(fContextReq & ISC_REQ_STREAM)
+ {
+ FIXME("InitializeSecurityContext(): ISC_REQ_STREAM stub\n");
+ }
+ /* Done with the flags */
+ if(TargetDataRep == SECURITY_NETWORK_DREP){
+ FIXME("Don't know how to do SECURITY_NETWORK_DREP\n");
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_UNSUPPORTED_FUNCTION;
+ }
+
+ if(first)
+ {
+ TRACE("First time in ISC()\n");
+ /* Request a challenge request from ntlm_auth */
+ if(helper->password == NULL)
+ {
+ FIXME("Using empty password for now.\n");
+ lstrcpynA(buffer, "PW AA==", max_len-1);
+ }
+ else
+ {
+ lstrcpynA(buffer, "PW ", max_len-1);
+ if((ret = encodeBase64(helper->password,
+ helper->pwlen-2, buffer+3,
+ max_len-3, &buffer_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ }
+
+ TRACE("Sending to helper: %s\n", debugstr_a(buffer));
+ /* workaround for ntlm_auth v4 bug */
+ helper->first_time = 1;
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+ TRACE("Helper returned %s\n", debugstr_a(buffer));
+ helper->first_time = 0;
+ /* and restore to ntlm_auth v4 behaviour */
+
+ lstrcpynA(buffer, "YR", max_len-1);
+
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("%s\n", buffer);
+
+ if(strncmp(buffer, "YR", 2) != 0)
+ {
+
+ /* Something borked */
+ TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INTERNAL_ERROR;
+ }
+ if((ret = decodeBase64(buffer+3, buffer_len-3, bin,
+ max_len-1, &bin_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ /* put the decoded client blob into the out buffer */
+ if(pOutput == NULL){
+ TRACE("pOutput is NULL\n");
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ if(pOutput->cBuffers < 1)
+ {
+ TRACE("pOutput->cBuffers is %ld\n", pOutput->cBuffers);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+ pOutput->pBuffers[0].cbBuffer = bin_len;
+ pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
+ memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
+
+ ret = SEC_I_CONTINUE_NEEDED;
+ }
+ else
+ {
+ /* handle second call here */
+ /* encode server data to base64 */
+ if(pInput == NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->cBuffers < 1)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->pBuffers[0].cbBuffer > max_len)
+ {
+ TRACE("pInput->pBuffers[0].cbBuffer is: %ld\n",
+ pInput->pBuffers[0].cbBuffer);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+ else
+ bin_len = pInput->pBuffers[0].cbBuffer;
+
+ memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
+
+ lstrcpynA(buffer, "TT ", max_len-1);
+
+ if((ret = encodeBase64(bin, bin_len, buffer+3,
+ max_len-3, &buffer_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Server sent: %s\n", debugstr_a(buffer));
+
+ /* send TT base64 blob to ntlm_auth */
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Helper replied: %s\n", debugstr_a(buffer));
+
+ /* return should be AF base64 blob or KK base64 blob
+ * it could be PW, though, which needs to be handled first */
+ if(strncmp(buffer, "PW", 2) == 0)
+ {
+ if(helper->password == NULL)
+ {
+ FIXME("Using empty password for now.\n");
+ lstrcpynA(buffer, "PW AA==", max_len-1);
+ }
+ else
+ {
+ lstrcpynA(buffer, "PW ", max_len-1);
+ if((ret = encodeBase64(helper->password,
+ helper->pwlen-2, buffer+3,
+ max_len-3, &buffer_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ }
+
+ TRACE("Sending to helper: %s\n", debugstr_a(buffer));
+
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+ TRACE("Helper returned %s\n", debugstr_a(buffer));
+
+ }
+
+ if( (strncmp(buffer, "KK", 2) != 0) &&
+ (strncmp(buffer, "AF", 2) !=0))
+ {
+ TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+
+ /* decode the blob and send it to server */
+ if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
+ &bin_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ if(pOutput == NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ if(pOutput->cBuffers < 1)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ pOutput->pBuffers[0].cbBuffer = bin_len;
+ pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
+ memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
+
+ ret = SEC_E_OK;
+ phNewContext->dwUpper = ctxt_attr;
+ phNewContext->dwLower = ret;
+
+ }
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+
+ }
+ else
+ {
+ ret = SEC_E_INVALID_HANDLE;
+ TRACE("Helper mode = %d\n", helper->mode);
+ }
}
else
{
@@ -153,10 +793,10 @@
}
/***********************************************************************
- * InitializeSecurityContextW
+ * InitializeSecurityContextA
*/
-static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
- PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
+static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
+ PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext,
PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
@@ -164,11 +804,27 @@
SECURITY_STATUS ret;
TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
- debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+ debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
if (phCredential)
{
- ret = SEC_E_UNSUPPORTED_FUNCTION;
+ SEC_WCHAR *target = NULL;
+ if(pszTargetName != NULL)
+ {
+ int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName,
+ strlen(pszTargetName)+1, NULL, 0);
+ target = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, target_size
+ * sizeof(SEC_WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1,
+ target, target_size);
+ }
+
+ ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target,
+ fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
+ phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
+ HeapFree(GetProcessHeap(), 0, target);
}
else
{
@@ -192,7 +848,232 @@
ptsExpiry);
if (phCredential)
{
- ret = SEC_E_UNSUPPORTED_FUNCTION;
+ PNegoHelper helper = (PNegoHelper)phCredential->dwLower;
+ /* Max size of input data is 2010 byte, as that's the maximum size
+ * ntlm_auth will handle*/
+ unsigned char *buffer = (char *)HeapAlloc(GetProcessHeap(), 0,
+ sizeof(char) * 2010);
+ PBYTE bin = (PBYTE)HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * 2010);
+ int buffer_len, bin_len, max_len = 2010;
+ ULONG ctxt_attr = 0;
+
+ if(helper->mode != NTLM_SERVER)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_HANDLE;
+ }
+
+ /* Handle all the flags */
+ if(fContextReq & ISC_REQ_ALLOCATE_MEMORY)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n");
+ }
+ if(fContextReq & ISC_REQ_CONFIDENTIALITY)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
+ }
+ if(fContextReq & ISC_REQ_CONNECTION)
+ {
+ /* This is default, so we'll enable it */
+ ctxt_attr |= ISC_RET_CONNECTION;
+ }
+ if(fContextReq & ISC_REQ_EXTENDED_ERROR)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n");
+ }
+ if(fContextReq & ISC_REQ_INTEGRITY)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_INTEGRITY stub\n");
+ }
+ if(fContextReq & ISC_REQ_MUTUAL_AUTH)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n");
+ }
+ if(fContextReq & ISC_REQ_REPLAY_DETECT)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n");
+ }
+ if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n");
+ }
+ if(fContextReq & ISC_REQ_STREAM)
+ {
+ FIXME("AcceptSecurityContext(): ISC_REQ_STREAM stub\n");
+ }
+ /* Done with the flags */
+ if(TargetDataRep == SECURITY_NETWORK_DREP){
+ FIXME("Don't know how to do SECURITY_NETWORK_DREP\n");
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_UNSUPPORTED_FUNCTION;
+ }
+
+
+ if(phContext == NULL)
+ {
+ /* This is the first call to AcceptSecurityHandle */
+ if(pInput == NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->cBuffers < 1)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->pBuffers[0].cbBuffer > max_len)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+ else
+ bin_len = pInput->pBuffers[0].cbBuffer;
+
+ /* This is the YR request from the client, encode to base64 */
+
+ memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
+
+ lstrcpynA(buffer, "YR ", max_len-1);
+
+ if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
+ &buffer_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Client sent: %s\n", debugstr_a(buffer));
+
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
+ /* The expected answer is TT <base64 blob> */
+
+ if(strncmp(buffer, "TT", 2) != 0)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+
+ if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
+ &bin_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ /* send this to the client */
+ if(pOutput == NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ if(pOutput->cBuffers < 1)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ pOutput->pBuffers[0].cbBuffer = bin_len;
+ pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
+ memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
+ ret = SEC_I_CONTINUE_NEEDED;
+
+ }
+ else
+ {
+ /* we expect a KK request from client */
+ if(pInput == NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->cBuffers < 1)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INCOMPLETE_MESSAGE;
+ }
+
+ if(pInput->pBuffers[0].cbBuffer > max_len)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+ else
+ bin_len = pInput->pBuffers[0].cbBuffer;
+
+ memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
+
+ lstrcpynA(buffer, "KK ", max_len-1);
+
+ if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
+ &buffer_len)) != SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Client sent: %s\n", debugstr_a(buffer));
+
+ if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
+ SEC_E_OK)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return ret;
+ }
+
+ TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
+
+ if(strncmp(buffer, "AF", 2) != 0)
+ {
+ if(strncmp(buffer, "NA", 2) == 0)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_LOGON_DENIED;
+ }
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+ return SEC_E_INVALID_TOKEN;
+ }
+ }
+
+ ret = SEC_E_OK;
+ }
+
+ phNewContext->dwUpper = ctxt_attr;
+ phNewContext->dwLower = ret;
+ HeapFree(GetProcessHeap(), 0, buffer);
+ HeapFree(GetProcessHeap(), 0, bin);
+
}
else
{
@@ -231,27 +1112,9 @@
TRACE("%p\n", phContext);
if (phContext)
{
- ret = SEC_E_UNSUPPORTED_FUNCTION;
- }
- else
- {
- ret = SEC_E_INVALID_HANDLE;
- }
- return ret;
-}
-
-/***********************************************************************
- * ApplyControlToken
- */
-static SECURITY_STATUS SEC_ENTRY ntlm_ApplyControlToken(PCtxtHandle phContext,
- PSecBufferDesc pInput)
-{
- SECURITY_STATUS ret;
-
- TRACE("%p %p\n", phContext, pInput);
- if (phContext)
- {
- ret = SEC_E_UNSUPPORTED_FUNCTION;
+ phContext->dwUpper = 0;
+ phContext->dwLower = 0;
+ ret = SEC_E_OK;
}
else
{
@@ -268,10 +1131,6 @@
{
SECURITY_STATUS ret;
- /* FIXME: From reading wrapper.h, I think the dwUpper part of a context is
- * the SecurePackage part and the dwLower part is the actual context
- * handle. It should be easy to extract the context attributes from that.
- */
TRACE("%p %ld %p\n", phContext, ulAttribute, pBuffer);
if (phContext)
{
@@ -371,20 +1230,39 @@
return ret;
}
+/***********************************************************************
+ * FreeCredentialsHandle
+ */
+static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
+ PCredHandle phCredential)
+{
+ SECURITY_STATUS ret;
+ if(phCredential){
+ PNegoHelper helper = (PNegoHelper) phCredential->dwLower;
+ phCredential->dwUpper = 0;
+ phCredential->dwLower = 0;
+ cleanup_helper(helper);
+ ret = SEC_E_OK;
+ }
+ else
+ ret = SEC_E_OK;
+
+ return ret;
+}
static SecurityFunctionTableA negoTableA = {
1,
NULL, /* EnumerateSecurityPackagesA */
ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */
ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */
- FreeCredentialsHandle, /* FreeCredentialsHandle */
+ ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
NULL, /* Reserved2 */
ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
ntlm_CompleteAuthToken, /* CompleteAuthToken */
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
- ntlm_ApplyControlToken, /* ApplyControlToken */
+ NULL, /* ApplyControlToken */
ntlm_QueryContextAttributesA, /* QueryContextAttributesA */
ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
ntlm_RevertSecurityContext, /* RevertSecurityContext */
@@ -409,13 +1287,13 @@
NULL, /* EnumerateSecurityPackagesW */
ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */
ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */
- FreeCredentialsHandle, /* FreeCredentialsHandle */
+ ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
NULL, /* Reserved2 */
ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
ntlm_CompleteAuthToken, /* CompleteAuthToken */
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
- ntlm_ApplyControlToken, /* ApplyControlToken */
+ NULL, /* ApplyControlToken */
ntlm_QueryContextAttributesW, /* QueryContextAttributesW */
ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
ntlm_RevertSecurityContext, /* RevertSecurityContext */
@@ -459,7 +1337,9 @@
static const USHORT version = 1;
static const USHORT rpcid = 10;
- static const ULONG max_token = 12000;
+ /* In Windows, this is 12000, but ntlm_auth won't take more than 2010
+ * characters, so there is no use reporting a bigger size */
+ static const ULONG max_token = 2010;
const SecPkgInfoW infoW = { caps, version, rpcid, max_token, ntlm_name_W,
ntlm_comment_W};
const SecPkgInfoA infoA = { caps, version, rpcid, max_token, ntlm_name_A,
Index: dlls/secur32/secur32_priv.h
===================================================================
RCS file: /home/wine/wine/dlls/secur32/secur32_priv.h,v
retrieving revision 1.4
diff -u -3 -r1.4 secur32_priv.h
--- dlls/secur32/secur32_priv.h 17 Aug 2005 09:52:30 -0000 1.4
+++ dlls/secur32/secur32_priv.h 24 Aug 2005 23:13:16 -0000
@@ -21,6 +21,9 @@
#ifndef __SECUR32_PRIV_H__
#define __SECUR32_PRIV_H__
+#include <sys/types.h>
+#include <stdio.h>
+
/* Memory allocation functions for memory accessible by callers of secur32.
* There is no REALLOC, because LocalReAlloc can only work if used in
* conjunction with LMEM_MOVEABLE and LocalLock, but callers aren't using
@@ -47,6 +50,24 @@
SecureProvider *provider;
} SecurePackage;
+typedef enum _helper_mode {
+ NTLM_SERVER,
+ NTLM_CLIENT,
+ NEGO_SERVER,
+ NEGO_CLIENT,
+ NUM_HELPER_MODES
+} HelperMode;
+
+typedef struct _NegoHelper {
+ pid_t helper_pid;
+ HelperMode mode;
+ SEC_CHAR *password;
+ int pwlen;
+ int pipe_in;
+ int pipe_out;
+ int first_time;
+} NegoHelper, *PNegoHelper;
+
/* Allocates space for and initializes a new provider. If fnTableA or fnTableW
* is non-NULL, assumes the provider is built-in (and is thus already loaded.)
* Otherwise moduleName must not be NULL.
@@ -82,4 +103,21 @@
void SECUR32_initNegotiateSP(void);
void SECUR32_initNTLMSP(void);
+/* Functions from dispatcher.c used elsewhere in the code */
+SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
+ char * const argv[]);
+
+SECURITY_STATUS run_helper(PNegoHelper helper, unsigned char *buffer,
+ unsigned int max_buflen, int *buflen);
+
+void cleanup_helper(PNegoHelper helper);
+
+/* 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);
+
+SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf,
+ int max_len, int *out_len);
+
+
#endif /* ndef __SECUR32_PRIV_H__ */
Index: dlls/secur32/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/secur32/tests/Makefile.in,v
retrieving revision 1.1
diff -u -3 -r1.1 Makefile.in
--- dlls/secur32/tests/Makefile.in 3 Aug 2005 13:08:49 -0000 1.1
+++ dlls/secur32/tests/Makefile.in 24 Aug 2005 23:13:16 -0000
@@ -6,7 +6,8 @@
IMPORTS = secur32
CTESTS = \
- main.c
+ main.c \
+ ntlm.c
@MAKE_TEST_RULES@
--- /dev/null 2005-08-19 11:42:14.099901488 +0200
+++ dlls/secur32/base64_codec.c 2005-08-25 01:03:16.125351056 +0200
@@ -0,0 +1,199 @@
+/*
+ * base64 encode/decode functions
+ *
+ * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Based on code by Matthias Gaertner.
+ */
+
+#include <string.h>
+#include "windef.h"
+#include "winerror.h"
+#include "sspi.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+
+static const char* to_b64 =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf,
+ int max_len, int *out_len)
+{
+ unsigned int div;
+ unsigned int rem;
+ unsigned int num_out = 0;
+ char res[4 + (in_len * 4)/3];
+ BYTE *pIn = in_buf;
+
+ if(in_len == 0){
+ memset(out_buf, '\0', max_len);
+ *out_len = 0;
+ return SEC_E_OK;
+ }
+
+ div = in_len / 3;
+ rem = in_len % 3;
+
+ TRACE("in_len = %d, rem = %d, div = %d\n", in_len, rem, div);
+
+ while(div > 0)
+ {
+ res[num_out + 0] = to_b64[ (pIn[0] >> 2) & 0x3f];
+ res[num_out + 1] = to_b64[((pIn[0] << 4) & 0x30) + ((pIn[1] >> 4) & 0xf)];
+ res[num_out + 2] = to_b64[((pIn[1] << 2) & 0x3c) + ((pIn[2] >> 6) & 0x3)];
+ res[num_out + 3] = to_b64[ pIn[2] & 0x3f];
+
+ pIn += 3;
+ num_out += 4;
+ div--;
+ }
+
+ switch(rem)
+ {
+ case 2:
+ res[num_out + 0] = to_b64[ (pIn[0] >> 2) & 0x3f];
+ res[num_out + 1] = to_b64[((pIn[0] << 4) & 0x30) + ((pIn[1] >> 4) & 0xf)];
+ res[num_out + 2] = to_b64[((pIn[1] << 2) & 0x3c)];
+ res[num_out + 3] = '=';
+
+ num_out += 4;
+ break;
+
+ case 1:
+ res[num_out + 0] = to_b64[ (pIn[0] >> 2) & 0x3f];
+ res[num_out + 1] = to_b64[((pIn[0] << 4) & 0x30)];
+ res[num_out + 2] = '=';
+ res[num_out + 3] = '=';
+
+ num_out += 4;
+ break;
+ }
+
+ /* Input buffer was too long */
+ if(num_out + 1 > max_len){
+ memset(out_buf, '\0', max_len);
+ *out_len = 0;
+ TRACE("Buffer size is too small: num out is %d, max_len is %d\n",
+ num_out, max_len);
+ return SEC_E_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ res[num_out] = '\0';
+ num_out++;
+ strncpy(out_buf, res, num_out);
+ *out_len = num_out;
+ return SEC_E_OK;
+ }
+
+ /* We never get here, but some compilers whine about it */
+ return SEC_E_INTERNAL_ERROR;
+}
+
+BYTE decode(char c)
+{
+ if( (c >= 'A') && (c <= 'Z'))
+ return (unsigned char) (c - 'A');
+ if( (c >= 'a') && (c <= 'z'))
+ return (unsigned char) (c - 'a' + (char)26);
+ if( (c >= '0') && (c <= '9'))
+ return (unsigned char) (c - '0' + (char)52);
+ if( c == '+')
+ return (unsigned char)62;
+ if( c == '/')
+ return (unsigned char)63;
+ return -1;
+}
+
+
+SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf,
+ int max_len, int *out_len)
+{
+ BYTE data[in_len+1];
+ BYTE *pIn = (PBYTE) in_buf;
+ unsigned int num_data = 0;
+ unsigned int div;
+
+ if( (in_len % 4) != 0)
+ {
+ TRACE("in_len = %d\n", in_len);
+ TRACE("message is %s\n", debugstr_a(in_buf));
+ return SEC_E_ILLEGAL_MESSAGE;
+ }
+
+ if( (div = in_len/4) < 1)
+ {
+ TRACE("div = %d\n", div);
+ return SEC_E_ILLEGAL_MESSAGE;
+ }
+ TRACE("in_len = %d, div = %d\n", in_len, div);
+
+ while(div > 1)
+ {
+ data[num_data + 0] = ((decode(pIn[0])<<2) & 0xfc) | ((decode(pIn[1])>>4) & 0x03);
+ data[num_data + 1] = ((decode(pIn[1])<<4) & 0xf0) | ((decode(pIn[2])>>2) & 0x0f);
+ data[num_data + 2] = ((decode(pIn[2])<<6) & 0xc0) | ( decode(pIn[3]) & 0x3f);
+
+ num_data += 3;
+ pIn += 4;
+ div--;
+ }
+
+ if(pIn[2] == '=')
+ {
+ /* We have two bytes of padding */
+ data[num_data] = ((decode(pIn[0])<<2) & 0xfc) | ((decode(pIn[1])>>4) & 0x03);
+ num_data++;
+ }
+ else if(pIn[3] == '=')
+ {
+ /* One byte of padding */
+ data[num_data + 0] = ((decode(pIn[0])<<2) & 0xfc) | ((decode(pIn[1])>>4) & 0x03);
+ data[num_data + 1] = ((decode(pIn[1])<<4) & 0xf0) | ((decode(pIn[2])>>2) & 0x0f);
+ num_data += 2;
+ }
+ else
+ {
+ /* No padding */
+ data[num_data + 0] = ((decode(pIn[0])<<2) & 0xfc) | ((decode(pIn[1])>>4) & 0x03);
+ data[num_data + 1] = ((decode(pIn[1])<<4) & 0xf0) | ((decode(pIn[2])>>2) & 0x0f);
+ data[num_data + 2] = ((decode(pIn[2])<<6) & 0xc0) | ( decode(pIn[3]) & 0x3f);
+ num_data += 3;
+ }
+
+ TRACE("num_data = %d\n", num_data);
+
+ if(num_data > max_len)
+ {
+ /* Input data too big for output buffer */
+ memset(out_buf, 0, (size_t)max_len);
+ *out_len = 0;
+ return SEC_E_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ memcpy(out_buf, data, (size_t)num_data);
+ *out_len = num_data;
+ return SEC_E_OK;
+ }
+
+ /* This is never reached, but some compilers whine if they don't have it. */
+ return SEC_E_INTERNAL_ERROR;
+}
+
+
--- /dev/null 2005-08-19 11:42:14.099901488 +0200
+++ dlls/secur32/dispatcher.c 2005-08-25 01:09:01.591832168 +0200
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * A dispatcher to run ntlm_auth for wine's sspi module.
+ */
+
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.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"
+
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+
+SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
+ char* const argv[])
+{
+ int pipe_in[2];
+ int pipe_out[2];
+ int i;
+
+ TRACE("%s ", debugstr_a(prog));
+ for(i = 0; argv[i] != NULL; ++i)
+ {
+ TRACE("%s ", debugstr_a(argv[i]));
+ }
+ TRACE("\n");
+ PNegoHelper helper = (PNegoHelper) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(NegoHelper) );
+
+ if (helper == NULL)
+ {
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ *new_helper = helper;
+
+ if( ( pipe(pipe_in) < 0 ) || ( pipe(pipe_out) < 0 ) )
+ {
+ close(pipe_in[0]);
+ close(pipe_in[1]);
+ close(pipe_out[0]);
+ close(pipe_out[1]);
+ return SEC_E_INTERNAL_ERROR;
+ }
+
+ helper->first_time = 0;
+ 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]);
+ return SEC_E_INTERNAL_ERROR;
+ }
+
+ if(helper->helper_pid == 0)
+ {
+ /* We're in the child now */
+ close(0);
+ close(1);
+
+ 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.*/
+ exit(0x302);
+
+ }
+ else
+ {
+ helper->pipe_in = pipe_in[0];
+ close(pipe_in[1]);
+ helper->pipe_out = pipe_out[1];
+ close(pipe_out[0]);
+ }
+
+ return SEC_E_OK;
+}
+
+SECURITY_STATUS run_helper(PNegoHelper helper, unsigned char *buffer,
+ unsigned int max_buflen, int *buflen)
+{
+ /* ntlm_auth's buffer size is fixed at 2010 chars */
+ if(strlen(buffer) > 2010){
+ return SEC_E_BUFFER_TOO_SMALL;
+ }
+ TRACE("In helper: sending %s\n", debugstr_a(buffer));
+
+ /* buffer + '\n' */
+ int out_len = strlen(buffer) + 1;
+ char *out_buf = (char *)HeapAlloc(GetProcessHeap(), 0, out_len+1);
+ lstrcpyA(out_buf, buffer);
+ strcat(out_buf, "\n");
+
+ write(helper->pipe_out, out_buf, out_len);
+ HeapFree(GetProcessHeap(), 0, out_buf);
+
+ if(read(helper->pipe_in, buffer, 3) <= 2)
+ {
+ return SEC_E_INTERNAL_ERROR;
+ }
+
+ if(strncmp(buffer, "OK", 2) == 0)
+ {
+ /* if the first two chars are OK, kill OK\n */
+ /* workaround for ntlm_auth v4 bug */
+ if(helper->first_time == 0)
+ read(helper->pipe_in, buffer, max_buflen-1);
+ }
+ else
+ {
+ if(strncmp(buffer, "PW", 2) != 0)
+ read(helper->pipe_in, buffer+3, max_buflen-4);
+ }
+
+ TRACE("In helper: recieved %s\n", debugstr_a(buffer));
+
+ char *newline;
+
+ if((newline = strchr(buffer, '\n'))!= NULL)
+ {
+ *newline = '\0';
+ }
+ *buflen = strlen(buffer);
+
+ if( *buflen < 2 )
+ {
+ return SEC_E_ILLEGAL_MESSAGE;
+ }
+
+ if( (*buflen <= 3) && (strncmp(buffer, "BH", 2) == 0))
+ {
+ return SEC_E_INTERNAL_ERROR;
+ }
+
+ return SEC_E_OK;
+}
+
+void cleanup_helper(PNegoHelper helper){
+
+ TRACE("Killing helper %p\n", helper);
+ if( (helper == NULL) || (helper->helper_pid == 0))
+ return;
+
+ kill(helper->helper_pid, SIGTERM);
+ waitpid(helper->helper_pid, NULL, 0);
+
+ HeapFree(GetProcessHeap(), 0, helper->password);
+
+ close(helper->pipe_out);
+ close(helper->pipe_in);
+
+ helper->helper_pid = 0;
+ HeapFree(GetProcessHeap(), 0, helper);
+}
+
--- /dev/null 2005-08-19 11:42:14.099901488 +0200
+++ dlls/secur32/tests/ntlm.c 2005-08-25 01:04:34.080500072 +0200
@@ -0,0 +1,441 @@
+/*
+ * NTLM security provider tests
+ *
+ * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define SECURITY_WIN32
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <windows.h>
+#include "wine/test.h"
+#include <winbase.h>
+#include <sspi.h>
+#include <rpc.h>
+#include <string.h>
+
+#define MAX_MESSAGE 3000
+
+static const char* getSecError(SECURITY_STATUS status)
+{
+#define _SEC_ERR(x) case (x): return #x;
+ switch(status)
+ {
+ _SEC_ERR(SEC_E_OK);
+ _SEC_ERR(SEC_E_INSUFFICIENT_MEMORY);
+ _SEC_ERR(SEC_E_INVALID_HANDLE);
+ _SEC_ERR(SEC_E_UNSUPPORTED_FUNCTION);
+ _SEC_ERR(SEC_E_TARGET_UNKNOWN);
+ _SEC_ERR(SEC_E_INTERNAL_ERROR);
+ _SEC_ERR(SEC_E_SECPKG_NOT_FOUND);
+ _SEC_ERR(SEC_E_NOT_OWNER);
+ _SEC_ERR(SEC_E_CANNOT_INSTALL);
+ _SEC_ERR(SEC_E_INVALID_TOKEN);
+ _SEC_ERR(SEC_E_CANNOT_PACK);
+ _SEC_ERR(SEC_E_QOP_NOT_SUPPORTED);
+ _SEC_ERR(SEC_E_NO_IMPERSONATION);
+ _SEC_ERR(SEC_I_CONTINUE_NEEDED);
+ _SEC_ERR(SEC_E_BUFFER_TOO_SMALL);
+ _SEC_ERR(SEC_E_ILLEGAL_MESSAGE);
+ _SEC_ERR(SEC_E_LOGON_DENIED);
+ default:
+ trace("Error = 0x%08lx\n", status);
+ return "Unknown error";
+ }
+#undef _SEC_ERR
+}
+
+/**********************************************************************/
+
+SECURITY_STATUS setupClient(PCredHandle cred, const char *user,
+ const char *pass, const char *domain)
+{
+ SECURITY_STATUS ret;
+ PSEC_WINNT_AUTH_IDENTITY identity = NULL;
+ TimeStamp ttl;
+
+ trace("Running setupClient\n");
+
+ if(user != NULL)
+ {
+ identity = (PSEC_WINNT_AUTH_IDENTITY_A)HeapAlloc(GetProcessHeap(), 0,
+ sizeof(SEC_WINNT_AUTH_IDENTITY_A));
+
+#define _strdup(x) HeapAlloc(GetProcessHeap(), 0, lstrlenA(x))
+ memset( identity, 0, sizeof(identity));
+ identity->Domain = (char *) _strdup( domain ? domain :"");
+ lstrcpyA(identity->Domain, domain ? domain :"");
+ identity->DomainLength = domain ? strlen(domain): 0;
+ identity->User = (char *) _strdup( user ? user : "");
+ lstrcpyA(identity->User, user ? user :"");
+ identity->UserLength = user ? strlen(user) : 0;
+ identity->Password = "testpass";
+ //lstrcpyA(identity->Password, pass ? pass :"");
+ identity->PasswordLength = strlen("testpass");
+ identity->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+#undef _strdup
+ }
+
+ if((ret = AcquireCredentialsHandle(NULL, "NTLM", SECPKG_CRED_OUTBOUND,
+ NULL, identity, NULL, NULL, cred, &ttl)) != SEC_E_OK)
+ {
+ trace("AcquireCredentialsHandle() returned %s\n", getSecError(ret));
+ }
+
+ ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n",
+ getSecError(ret));
+
+ if( identity != NULL)
+ {
+ if(identity->Domain != 0)
+ HeapFree(GetProcessHeap(), 0, identity->Domain);
+ if(identity->User != 0)
+ HeapFree(GetProcessHeap(), 0, identity->User);
+ if(identity->Password != 0)
+ HeapFree(GetProcessHeap(), 0, identity->Password);
+ HeapFree(GetProcessHeap(), 0, identity);
+ }
+
+ return ret;
+}
+
+/**********************************************************************/
+
+SECURITY_STATUS setupServer(PCredHandle cred)
+{
+ SECURITY_STATUS ret;
+ TimeStamp ttl;
+
+ trace("Running setupServer\n");
+
+ if((ret = AcquireCredentialsHandle(NULL, "NTLM", SECPKG_CRED_INBOUND, NULL,
+ NULL, NULL, NULL, cred, &ttl)) != SEC_E_OK)
+ {
+ trace("AcquireCredentialsHandle() returned %s\n", getSecError(ret));
+ }
+
+ ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n",
+ getSecError(ret));
+
+ return ret;
+}
+
+/**********************************************************************/
+
+SECURITY_STATUS setupBuffers(PSecBufferDesc *new_in_buf,
+ PSecBufferDesc *new_out_buf)
+{
+ int size = MAX_MESSAGE;
+ PSecBufferDesc in_buf = (PSecBufferDesc) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(SecBufferDesc));
+
+ if(in_buf != NULL)
+ {
+ PSecBuffer sec_buffer = (PSecBuffer) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(SecBuffer));
+ if(sec_buffer == NULL){
+ trace("in_buf: sec_buffer == NULL");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ PBYTE buffer = (PBYTE) HeapAlloc(GetProcessHeap(), 0, size);
+
+ if(buffer == NULL){
+ trace("in_buf: buffer == NULL");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ in_buf->ulVersion = SECBUFFER_VERSION;
+ in_buf->cBuffers = 1;
+ in_buf->pBuffers = sec_buffer;
+
+ sec_buffer->cbBuffer = size;
+ sec_buffer->BufferType = SECBUFFER_TOKEN;
+ sec_buffer->pvBuffer = buffer;
+ *new_in_buf = in_buf;
+ }
+ else
+ {
+ trace("HeapAlloc in_buf returned NULL\n");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ PSecBufferDesc out_buf = (PSecBufferDesc) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(PSecBufferDesc));
+
+ if(out_buf != NULL)
+ {
+ PSecBuffer sec_buffer = (PSecBuffer) HeapAlloc(GetProcessHeap(), 0,
+ sizeof(SecBuffer));
+
+ if(sec_buffer == NULL){
+ trace("out_buf: sec_buffer == NULL");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ PBYTE buffer = (PBYTE) HeapAlloc(GetProcessHeap(), 0, size);
+
+ if(buffer == NULL){
+ trace("out_buf: buffer == NULL");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ out_buf->ulVersion = SECBUFFER_VERSION;
+ out_buf->cBuffers = 1;
+ out_buf->pBuffers = sec_buffer;
+
+ sec_buffer->cbBuffer = 0;
+ sec_buffer->BufferType = SECBUFFER_TOKEN;
+ sec_buffer->pvBuffer = buffer;
+ *new_out_buf = out_buf;
+ }
+ else
+ {
+ trace("HeapAlloc out_buf returned NULL\n");
+ return SEC_E_INSUFFICIENT_MEMORY;
+ }
+
+ return SEC_E_OK;
+}
+
+/**********************************************************************/
+
+void cleanupBuffers(PSecBufferDesc in_buf, PSecBufferDesc out_buf)
+{
+ int i;
+
+ if(in_buf != NULL)
+ {
+ for(i = 0; i < in_buf->cBuffers; ++i)
+ {
+ HeapFree(GetProcessHeap(), 0, in_buf->pBuffers[i].pvBuffer);
+ }
+ HeapFree(GetProcessHeap(), 0, in_buf->pBuffers);
+ HeapFree(GetProcessHeap(), 0, in_buf);
+ }
+
+ if(out_buf != NULL)
+ {
+ for(i = 0; i < out_buf->cBuffers; ++i)
+ {
+ HeapFree(GetProcessHeap(), 0, out_buf->pBuffers[i].pvBuffer);
+ }
+ HeapFree(GetProcessHeap(), 0, out_buf->pBuffers);
+ HeapFree(GetProcessHeap(), 0, out_buf);
+ }
+}
+
+/**********************************************************************/
+
+SECURITY_STATUS runClient(PCredHandle cred, PCtxtHandle ctxt,
+ PSecBufferDesc in_buf, PSecBufferDesc out_buf, BOOL first)
+{
+ SECURITY_STATUS ret;
+ ULONG req_attr = ISC_REQ_CONNECTION;
+ ULONG ctxt_attr;
+ TimeStamp ttl;
+
+ trace("Running the client the %s time.\n", first?"first":"second");
+
+ ret = InitializeSecurityContext(cred, first?NULL:ctxt, NULL, req_attr,
+ 0, SECURITY_NATIVE_DREP, first?NULL:in_buf, 0, ctxt, out_buf,
+ &ctxt_attr, &ttl);
+
+ if(ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
+ {
+ CompleteAuthToken(ctxt, out_buf);
+ if(ret == SEC_I_COMPLETE_AND_CONTINUE)
+ ret = SEC_I_CONTINUE_NEEDED;
+ else if(ret == SEC_I_COMPLETE_NEEDED)
+ ret = SEC_E_OK;
+ }
+
+ return ret;
+}
+
+/**********************************************************************/
+
+SECURITY_STATUS runServer(PCredHandle cred, PCtxtHandle ctxt,
+ PSecBufferDesc in_buf, PSecBufferDesc out_buf, BOOL first)
+{
+ SECURITY_STATUS ret;
+ ULONG ctxt_attr;
+ TimeStamp ttl;
+
+ trace("Running the server the %s time\n", first?"first":"second");
+
+ ret = AcceptSecurityContext(cred, first?NULL:ctxt, in_buf, 0,
+ SECURITY_NATIVE_DREP, ctxt, out_buf, &ctxt_attr, &ttl);
+
+ if(ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
+ {
+ CompleteAuthToken(ctxt, out_buf);
+ if(ret == SEC_I_COMPLETE_AND_CONTINUE)
+ ret = SEC_I_CONTINUE_NEEDED;
+ else if(ret == SEC_I_COMPLETE_NEEDED)
+ ret = SEC_E_OK;
+ }
+
+
+ return ret;
+}
+
+/**********************************************************************/
+
+void communicate(PSecBufferDesc in_buf, PSecBufferDesc out_buf)
+{
+ if(in_buf != NULL && out_buf != NULL)
+ {
+ trace("Running communicate.\n");
+ if((in_buf->cBuffers >= 1) && (out_buf->cBuffers >= 1))
+ {
+ if((in_buf->pBuffers[0].pvBuffer != NULL) &&
+ (out_buf->pBuffers[0].pvBuffer != NULL))
+ {
+ memset(out_buf->pBuffers[0].pvBuffer, 0, MAX_MESSAGE);
+
+ memcpy(out_buf->pBuffers[0].pvBuffer,
+ in_buf->pBuffers[0].pvBuffer,
+ in_buf->pBuffers[0].cbBuffer);
+
+ out_buf->pBuffers[0].cbBuffer = in_buf->pBuffers[0].cbBuffer;
+
+ memset(in_buf->pBuffers[0].pvBuffer, 0, MAX_MESSAGE);
+ }
+ }
+ }
+}
+
+/**********************************************************************/
+
+void testNTLMAuthWithUser(void)
+{
+ SECURITY_STATUS sec_status;
+ CredHandle server_cred;
+ CredHandle client_cred;
+ CtxtHandle server_ctxt;
+ CtxtHandle client_ctxt;
+
+ PSecBufferDesc client_in = NULL, client_out = NULL;
+ PSecBufferDesc server_in = NULL, server_out = NULL;
+
+ BOOL continue_client = FALSE, continue_server = FALSE;
+
+ sec_status = setupClient(&client_cred, "testuser", "testpass", NULL);
+
+ if(sec_status != SEC_E_OK)
+ {
+ trace("Error: Setting up the client returned %s, exiting test!\n",
+ getSecError(sec_status));
+ FreeCredentialsHandle(&server_cred);
+ FreeCredentialsHandle(&client_cred);
+ return;
+ }
+
+ sec_status = setupServer(&server_cred);
+
+ if(sec_status != SEC_E_OK)
+ {
+ trace("Error: Setting up the server returned %s, exiting test!\n",
+ getSecError(sec_status));
+ FreeCredentialsHandle(&server_cred);
+ FreeCredentialsHandle(&client_cred);
+ return;
+ }
+
+ setupBuffers(&client_in, &client_out);
+ setupBuffers(&server_in, &server_out);
+
+ sec_status = runClient(&client_cred, &client_ctxt, client_in, client_out,
+ TRUE);
+
+ ok(sec_status == SEC_E_OK || sec_status == SEC_I_CONTINUE_NEEDED,
+ "Running the client returned %s, more tests will fail from now.\n",
+ getSecError(sec_status));
+
+ if(sec_status == SEC_I_CONTINUE_NEEDED)
+ continue_client = TRUE;
+
+ communicate(client_out, server_in);
+
+ sec_status = runServer(&server_cred, &server_ctxt, server_in, server_out,
+ TRUE);
+
+ ok(sec_status == SEC_E_OK || sec_status == SEC_I_CONTINUE_NEEDED,
+ "Running the server returned %s, more tests will fail from now.\n",
+ getSecError(sec_status));
+
+ if(sec_status == SEC_I_CONTINUE_NEEDED)
+ {
+ continue_server = TRUE;
+ communicate(server_out, client_in);
+ }
+
+ if(continue_client)
+ {
+ sec_status = runClient(&client_cred, &client_ctxt, client_in, client_out,
+ FALSE);
+
+ ok(sec_status == SEC_E_OK,
+ "Running the client returned %s, more tests will fail from now.\n",
+ getSecError(sec_status));
+
+ communicate(client_out, server_in);
+ }
+
+ if(continue_server)
+ {
+ sec_status = runServer(&server_cred, &server_ctxt, server_in, server_out,
+ FALSE);
+ todo_wine
+ {
+ ok(sec_status == SEC_E_OK,
+ "Running the server returned %s.\n", getSecError(sec_status));
+ }
+ }
+
+ /* contine writing the test here */
+
+ trace("Before cleanupBuffers\n");
+ cleanupBuffers(client_in, client_out);
+ cleanupBuffers(server_in, server_out);
+
+ trace("After cleanupBuffers\n");
+
+ sec_status = DeleteSecurityContext(&server_ctxt);
+ ok(sec_status == SEC_E_OK, "DeleteSecurityContext(server) returned %s\n",
+ getSecError(sec_status));
+
+ sec_status = DeleteSecurityContext(&client_ctxt);
+ ok(sec_status == SEC_E_OK, "DeleteSecurityContext(client) returned %s\n",
+ getSecError(sec_status));
+
+ sec_status = FreeCredentialsHandle(&server_cred);
+ ok(sec_status == SEC_E_OK, "FreeCredentialsHandle(server) returned %s\n",
+ getSecError(sec_status));
+
+ sec_status = FreeCredentialsHandle(&client_cred);
+ ok(sec_status == SEC_E_OK, "FreeCredentialsHandle(client) returned %s\n",
+ getSecError(sec_status));
+
+}
+
+START_TEST(ntlm)
+{
+ testNTLMAuthWithUser();
+}
More information about the wine-patches
mailing list