secur32: Implementing InitializeSecurityContext(A|W) for the NTLM security provider

Kai Blin blin at gmx.net
Wed Dec 7 03:00:39 CST 2005


* Kai Blin <blin at gmx.net> [07/12/05, 09:55:29]:
> Changelog
> Kai Blin  <blin at gmx.net>
> Implementing InitializeSecurityContext(A|W) for the NTLM security
> provider.
> 
>  dlls/secur32/ntlm.c |  309
>  +++++++++++++++++++++++++++++++++++++++++++++++++--
>   1 files changed, 299 insertions(+), 10 deletions(-)
> 
 
This time, including the attachment. Sorry about that.

-- 
Kai Blin, (blin at gmx dot net)
You know, Callahan's is a peaceable bar, but if you ask that dog what his
favorite formatter is, and he says "roff! roff!", well, I'll just have to...
-------------- next part --------------
2a67e40b6a6e104c4fc3351f36e2af0050700600
diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c
index c6bdcc7..94715b5 100644
--- a/dlls/secur32/ntlm.c
+++ b/dlls/secur32/ntlm.c
@@ -389,10 +389,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_Ac
 }
 
 /***********************************************************************
- *              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)
@@ -400,10 +400,283 @@ static SECURITY_STATUS SEC_ENTRY ntlm_In
     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 */
+            char* buffer = HeapAlloc(GetProcessHeap(), 0, 
+                    sizeof(char) * NTLM_MAX_BUF);
+            PBYTE bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * 
+                    NTLM_MAX_BUF);
+            int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
+            
+            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((unsigned char*)helper->password, 
+                                helper->pwlen-2, buffer+3,
+                                max_len-3, &buffer_len)) != SEC_E_OK)
+                    {
+                        TRACE("Deleting password!\n");
+                        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));
+                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 ", 3) != 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));
+                                
+                if( (strncmp(buffer, "KK ", 3) != 0) && 
+                        (strncmp(buffer, "AF ", 3) !=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);
+            if(ret != SEC_I_CONTINUE_NEEDED)
+            {
+                TRACE("Deleting password!\n");
+                if(helper->password)
+                    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
     {
@@ -413,10 +686,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_In
 }
 
 /***********************************************************************
- *              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)
@@ -424,11 +697,27 @@ static SECURITY_STATUS SEC_ENTRY ntlm_In
     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 = 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
     {
---
0.99.9i


More information about the wine-patches mailing list