secur32: Add some real functionality to the NTLM provider, try 3

Kai Blin blin at gmx.net
Thu Aug 25 05:18:39 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. Will also zero
the password that is stored in the helper once it's not needed anymore.

I've decided not to include the tests this time until I've resolved the
issues Juan noted.

Changelog:
Kai Blin <blin at gmx.net>
Added functionality to the NTLM security provider.

-- 
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	25 Aug 2005 10:07:14 -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	25 Aug 2005 10:07:19 -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,205 @@
     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_WCHAR *convert = NULL;
+    SEC_WCHAR *username = NULL, *domain = NULL;
+    
+    SEC_CHAR *client_argv[5];
+    SEC_CHAR *server_argv[] = { "ntlm_auth",
+        "--helper-protocol=squid-2.5-ntlmssp",
+        NULL };
+
+    switch(fCredentialUse)
+    {
+        case SECPKG_CRED_INBOUND:
+            if( (ret = fork_helper(&helper, "ntlm_auth", 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)
+                {
+                    username = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+                            lstrlenW(ui->wkui1_username) * sizeof(SEC_WCHAR));
+                    lstrcpyW(username, ui->wkui1_username);
+                    
+                    /* same for the domain */
+                    domain = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+                            lstrlenW(ui->wkui1_logon_domain) *
+                            sizeof(SEC_WCHAR));
+                }
+                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 */
+                    username = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+                            (auth_data->UserLength + 1) * sizeof(SEC_WCHAR));
+                    lstrcpyW(username, auth_data->User);
+                }
+                else
+                {
+                    ret = SEC_E_NO_CREDENTIALS;
+                    phCredential = NULL;
+                    break;
+                }
+                if(auth_data->DomainLength != 0)
+                {
+                    domain = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0,
+                            (auth_data->DomainLength + 1) * sizeof(SEC_WCHAR));
+                    lstrcpyW(domain, auth_data->Domain);
+
+                }
+                else
+                {
+                    ret = SEC_E_NO_CREDENTIALS;
+                    phCredential = NULL;
+                    break;
+                }
+
+            }
+            TRACE("Username is %s\n", debugstr_w(username));
+            int convert_size = MultiByteToWideChar(CP_ACP,0, "--username=", -1,
+                    NULL, 0) + lstrlenW(username);
+            convert = (SEC_WCHAR *)HeapAlloc(GetProcessHeap(), 0, convert_size
+                    * sizeof(SEC_WCHAR));
+            MultiByteToWideChar(CP_ACP,0, "--username=", -1, convert, 
+                    convert_size);
+            lstrcatW(convert, username);
+            int 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);
+
+            TRACE("Domain name is %s\n", debugstr_w(domain));
+            convert_size = MultiByteToWideChar(CP_ACP,0, "--domain=", -1, NULL,
+                    0) + lstrlenW(domain);
+            convert = (SEC_WCHAR *)HeapReAlloc(GetProcessHeap(), 0, convert,
+                    convert_size * sizeof(SEC_WCHAR));
+            MultiByteToWideChar(CP_ACP,0, "--domain=", -1, convert, 
+                    convert_size);
+            lstrcatW(convert, 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);
+
+            client_argv[0] = "ntlm_auth";
+            client_argv[1] = "--helper-protocol=ntlmssp-client-1";
+            client_argv[2] = client_user_arg;
+            client_argv[3] = client_domain_arg;
+            client_argv[4] = NULL;
+
+            if((ret = fork_helper(&helper, "ntlm_auth", 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, username);
+    HeapFree(GetProcessHeap(), 0, domain);
+    HeapFree(GetProcessHeap(), 0, convert);
+
     return ret;
 }
 
@@ -106,33 +285,114 @@
  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, *package = NULL;
+    
+    PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
+    PSEC_WINNT_AUTH_IDENTITY_A identity  = NULL;
+    
+    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)
+    {
+        identity = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
+        
+        if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
+        {
+            pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)HeapAlloc(
+                    GetProcessHeap(), 0, sizeof(SEC_WINNT_AUTH_IDENTITY_W));
+
+            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
+        {
+            pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
+        }
+    }       
+    
+    ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse, 
+            pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
             ptsExpiry);
+    
+    HeapFree(GetProcessHeap(), 0, package);
+    HeapFree(GetProcessHeap(), 0, user);
+    HeapFree(GetProcessHeap(), 0, domain);
+    HeapFree(GetProcessHeap(), 0, passwd);
+    if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity)
+        HeapFree(GetProcessHeap(), 0, pAuthDataW);
+    
+    return ret;
 }
 
 /***********************************************************************
- *              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 +400,320 @@
     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)
+                    {
+                        memset(helper->password, 0, helper->pwlen-2);
+                        HeapFree(GetProcessHeap(), 0, helper->password);
+                        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)
+                        {
+                            memset(helper->password, 0, helper->pwlen-2);
+                            HeapFree(GetProcessHeap(), 0, helper->password);
+                            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);
+            memset(helper->password, 0, helper->pwlen-2);
+            HeapFree(GetProcessHeap(), 0, helper->password);
+
+        }
+        else
+        {
+            ret = SEC_E_INVALID_HANDLE;
+            TRACE("Helper mode = %d\n", helper->mode);
+        }
     }
     else
     {
@@ -153,10 +723,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 +734,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 +778,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 +1042,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 +1061,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 +1160,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 +1217,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 +1267,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	25 Aug 2005 10:07:19 -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__ */
--- /dev/null	2005-08-19 11:42:14.099901488 +0200
+++ dlls/secur32/base64_codec.c	2005-08-25 01:03:16.000000000 +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 12:03:59.911334384 +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);
+}
+


More information about the wine-patches mailing list