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