Hans Leidekker : msv1_0: Implement SpAcceptLsaModeContext.

Alexandre Julliard julliard at winehq.org
Fri Apr 30 16:03:27 CDT 2021


Module: wine
Branch: master
Commit: 57ae625141ba4d90aa75f08787fa57e04a03eef6
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=57ae625141ba4d90aa75f08787fa57e04a03eef6

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Fri Apr 30 11:59:35 2021 +0200

msv1_0: Implement SpAcceptLsaModeContext.

Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msv1_0/main.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 208 insertions(+), 1 deletion(-)

diff --git a/dlls/msv1_0/main.c b/dlls/msv1_0/main.c
index 4b0a636bd77..28cad0cb14c 100644
--- a/dlls/msv1_0/main.c
+++ b/dlls/msv1_0/main.c
@@ -829,6 +829,213 @@ done:
     return status;
 }
 
+static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
+                                                   SecBufferDesc *input, ULONG ctx_req, ULONG data_rep,
+                                                   LSA_SEC_HANDLE *new_ctx_handle, SecBufferDesc *output,
+                                                   ULONG *ctx_attr, TimeStamp *expiry, BOOLEAN *mapped_ctx,
+                                                   SecBuffer *ctx_data )
+{
+    NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
+    struct ntlm_ctx *ctx = NULL;
+    char *buf, *bin, *want_flags = NULL;
+    unsigned int len, bin_len;
+
+    TRACE( "%lx, %lx, %08x, %u, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, ctx_req, data_rep, input,
+           new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
+    if (ctx_req) FIXME( "ignoring flags %08x\n", ctx_req );
+
+    if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
+    if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
+
+    if (!ctx_handle)
+    {
+        struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
+        char *argv[3];
+
+        if (!cred || cred->mode != MODE_SERVER)
+        {
+            status = SEC_E_INVALID_HANDLE;
+            goto done;
+        }
+
+        if (!input || input->cBuffers < 1)
+        {
+            status = SEC_E_INCOMPLETE_MESSAGE;
+            goto done;
+        }
+
+        if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
+        {
+            status = SEC_E_INVALID_TOKEN;
+            goto done;
+        }
+        else bin_len = input->pBuffers[0].cbBuffer;
+
+        argv[0] = (char *)"ntlm_auth";
+        argv[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
+        argv[2] = NULL;
+        if ((status = ntlm_funcs->fork( argv, &ctx )) != SEC_E_OK) goto done;
+        ctx->mode = MODE_SERVER;
+
+        if (!(want_flags = malloc( 73 )))
+        {
+            status = SEC_E_INSUFFICIENT_MEMORY;
+            goto done;
+        }
+        strcpy( want_flags, "SF" );
+        if (ctx_req & ASC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
+        if (ctx_req & ASC_REQ_CONNECTION)
+        {
+            strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
+            ctx->attrs |= ASC_RET_CONNECTION;
+        }
+        if (ctx_req & ASC_REQ_INTEGRITY) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
+        if (ctx_req & ASC_REQ_ALLOCATE_MEMORY) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
+        if (ctx_req & ASC_REQ_EXTENDED_ERROR) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
+        if (ctx_req & ASC_REQ_MUTUAL_AUTH) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
+        if (ctx_req & ASC_REQ_REPLAY_DETECT) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
+        if (ctx_req & ASC_REQ_SEQUENCE_DETECT) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
+        if (ctx_req & ASC_REQ_STREAM) FIXME( "ASC_REQ_STREAM\n" );
+
+        if (strlen( want_flags ) > 3)
+        {
+            TRACE( "want flags are %s\n", debugstr_a(want_flags) );
+            strcpy( buf, want_flags );
+            if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
+            if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
+        }
+
+        memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
+        strcpy( buf, "YR " );
+        encode_base64( bin, bin_len, buf + 3 );
+
+        if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
+        TRACE( "ntlm_auth returned %s\n", buf );
+        if (strncmp( buf, "TT ", 3))
+        {
+            status = SEC_E_INTERNAL_ERROR;
+            goto done;
+        }
+        bin_len = decode_base64( buf + 3, len - 3, bin );
+
+        if (!output || output->cBuffers < 1)
+        {
+            status = SEC_E_INSUFFICIENT_MEMORY;
+            goto done;
+        }
+        output->pBuffers[0].cbBuffer = bin_len;
+        output->pBuffers[0].BufferType = SECBUFFER_DATA;
+        memcpy( output->pBuffers[0].pvBuffer, bin, bin_len );
+
+        *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
+        status = SEC_I_CONTINUE_NEEDED;
+    }
+    else
+    {
+        if (!input || input->cBuffers < 1)
+        {
+            status = SEC_E_INCOMPLETE_MESSAGE;
+            goto done;
+        }
+
+        ctx = (struct ntlm_ctx *)ctx_handle;
+        if (!ctx || ctx->mode != MODE_SERVER)
+        {
+            status = SEC_E_INVALID_HANDLE;
+            goto done;
+        }
+
+        if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
+        {
+            status = SEC_E_INVALID_TOKEN;
+            goto done;
+        }
+        else bin_len = input->pBuffers[0].cbBuffer;
+        memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
+
+        strcpy( buf, "KK " );
+        encode_base64( bin, bin_len, buf + 3 );
+
+        TRACE( "client sent %s\n", debugstr_a(buf) );
+        if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
+        TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
+
+        /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
+         * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
+         * so just handle this as a failed login. */
+        if (strncmp( buf, "AF ", 3 ))
+        {
+            if (!strncmp( buf, "NA ", 3 ))
+            {
+                status = SEC_E_LOGON_DENIED;
+                goto done;
+            }
+            else
+            {
+                const char err_v3[] = "BH NT_STATUS_ACCESS_DENIED";
+                const char err_v4[] = "BH NT_STATUS_UNSUCCESSFUL";
+
+                if ((len >= strlen(err_v3) && !strncmp( buf, err_v3, strlen(err_v3) )) ||
+                    (len >= strlen(err_v4) && !strncmp( buf, err_v4, strlen(err_v4) )))
+                {
+                    TRACE( "connection to winbindd failed\n" );
+                    status = SEC_E_LOGON_DENIED;
+                }
+                else status = SEC_E_INTERNAL_ERROR;
+                goto done;
+            }
+        }
+        output->pBuffers[0].cbBuffer = 0;
+
+        strcpy( buf, "GF" );
+        if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
+        if (len < 3) ctx->flags = 0;
+        else sscanf( buf + 3, "%x", &ctx->flags );
+
+        strcpy( buf, "GK" );
+        if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
+
+        if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
+        else if (!strncmp( buf, "GK ", 3 ))
+        {
+            bin_len = decode_base64( buf + 3, len - 3, bin );
+            TRACE( "session key is %s\n", debugstr_a(buf + 3) );
+            memcpy( ctx->session_key, bin, bin_len );
+        }
+
+        if (len < 3) memset( ctx->session_key, 0 , 16 );
+        else
+        {
+            if (!strncmp( buf, "BH ", 3 ))
+            {
+                TRACE( "helper sent %s\n", debugstr_a(buf + 3) );
+                /*FIXME: generate dummy session key = MD4(MD4(password))*/
+                memset( ctx->session_key, 0 , 16 );
+            }
+            else if (!strncmp( buf, "GK ", 3 ))
+            {
+                bin_len = decode_base64( buf + 3, len - 3, bin );
+                TRACE( "session key is %s\n", debugstr_a(buf + 3) );
+                memcpy( ctx->session_key, bin, 16 );
+            }
+        }
+        arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
+        ctx->crypt.ntlm.seq_no = 0;
+
+        *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
+        status = SEC_E_OK;
+    }
+
+done:
+    if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) ntlm_funcs->cleanup( ctx );
+    free( buf );
+    free( bin );
+    free( want_flags );
+
+    TRACE( "returning %08x\n", status );
+    return status;
+}
+
 static NTSTATUS NTAPI ntlm_SpDeleteContext( LSA_SEC_HANDLE handle )
 {
     struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
@@ -861,7 +1068,7 @@ static SECPKG_FUNCTION_TABLE ntlm_table =
     NULL, /* GetCredentials */
     NULL, /* DeleteCredentials */
     ntlm_SpInitLsaModeContext,
-    NULL, /* SpAcceptLsaModeContext */
+    ntlm_SpAcceptLsaModeContext,
     ntlm_SpDeleteContext,
     NULL, /* ApplyControlToken */
     NULL, /* GetUserInfo */




More information about the wine-cvs mailing list