https://git.reactos.org/?p=reactos.git;a=commitdiff;h=99dcd6f71cb72a973e85888903b5ed31241ad5c3

commit 99dcd6f71cb72a973e85888903b5ed31241ad5c3
Author:     Andreas Maier <[email protected]>
AuthorDate: Thu Jul 16 20:44:01 2020 +0200
Commit:     Victor Perevertkin <[email protected]>
CommitDate: Sat Dec 25 15:55:43 2021 +0300

    [MSV1_0] Implement LsaApLogonUserEx2_Network (5/5)
    
    This is a part of the Partial Network Login Implementation PR.
---
 dll/win32/msv1_0/CMakeLists.txt  |   1 +
 dll/win32/msv1_0/lsa.c           |   1 -
 dll/win32/msv1_0/lsa.h           |   3 -
 dll/win32/msv1_0/msv1_0.c        | 209 +++++++++++++++++-----
 dll/win32/msv1_0/msv1_0.h        |  58 +++++++
 dll/win32/msv1_0/ntlm/global.c   |  41 +++++
 dll/win32/msv1_0/ntlm/global.h   |  22 ++-
 dll/win32/msv1_0/ntlm/protocol.h |  24 +++
 dll/win32/msv1_0/ntlm/util.c     | 367 +++++++++++++++++++++++++++++++++++++++
 dll/win32/msv1_0/ntlm/util.h     |  64 +++++++
 dll/win32/msv1_0/precomp.h       |   2 +
 dll/win32/msv1_0/sam.c           |   2 +
 dll/win32/msv1_0/sam.h           |  12 ++
 13 files changed, 758 insertions(+), 48 deletions(-)

diff --git a/dll/win32/msv1_0/CMakeLists.txt b/dll/win32/msv1_0/CMakeLists.txt
index 50fa39aa44b..a336c7a6a4e 100644
--- a/dll/win32/msv1_0/CMakeLists.txt
+++ b/dll/win32/msv1_0/CMakeLists.txt
@@ -5,6 +5,7 @@ list(APPEND SOURCE
     lsa.c
     msv1_0.c
     ntlm/global.c
+    ntlm/util.c
     sam.c
     user.c
     usercontext.c
diff --git a/dll/win32/msv1_0/lsa.c b/dll/win32/msv1_0/lsa.c
index 0bbf4699c66..e8e4da8854e 100644
--- a/dll/win32/msv1_0/lsa.c
+++ b/dll/win32/msv1_0/lsa.c
@@ -10,7 +10,6 @@
 #include "wine/debug.h"
 WINE_DEFAULT_DEBUG_CHANNEL(msv1_0);
 
-SECPKG_FUNCTION_TABLE NtlmLsaFn[1];
 
 NTSTATUS
 NTAPI
diff --git a/dll/win32/msv1_0/lsa.h b/dll/win32/msv1_0/lsa.h
index 2df98a710c6..3577dbce361 100644
--- a/dll/win32/msv1_0/lsa.h
+++ b/dll/win32/msv1_0/lsa.h
@@ -7,9 +7,6 @@
 
 #pragma once
 
-// functions we provide to LSA in SpLsaModeInitialize
-extern SECPKG_FUNCTION_TABLE NtlmLsaFn[1];
-
 NTSTATUS
 NTAPI
 SpInitialize(
diff --git a/dll/win32/msv1_0/msv1_0.c b/dll/win32/msv1_0/msv1_0.c
index eefddf3d0e0..63aad086fd9 100644
--- a/dll/win32/msv1_0/msv1_0.c
+++ b/dll/win32/msv1_0/msv1_0.c
@@ -13,11 +13,6 @@
 WINE_DEFAULT_DEBUG_CHANNEL(msv1_0);
 
 
-/* GLOBALS *****************************************************************/
-
-LSA_DISPATCH_TABLE DispatchTable;
-
-
 /* FUNCTIONS ***************************************************************/
 
 static
@@ -176,6 +171,110 @@ done:
 }
 
 
+static
+NTSTATUS
+BuildLm20LogonProfileBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ PSAMPR_USER_INFO_BUFFER UserInfo,
+    _In_ PLSA_SAM_PWD_DATA LogonPwdData,
+    _Out_ PMSV1_0_LM20_LOGON_PROFILE *ProfileBuffer,
+    _Out_ PULONG ProfileBufferLength)
+{
+    PMSV1_0_LM20_LOGON_PROFILE LocalBuffer;
+    NTLM_CLIENT_BUFFER Buffer;
+    PBYTE PtrOffset;
+    ULONG BufferLength;
+    NTSTATUS Status = STATUS_SUCCESS;
+    UNICODE_STRING ComputerNameUCS;
+
+    *ProfileBuffer = NULL;
+    *ProfileBufferLength = 0;
+
+    if (!NtlmUStrAlloc(&ComputerNameUCS, LogonPwdData->ComputerName->Length + 
sizeof(WCHAR) * 3, 0))
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+    Status = RtlAppendUnicodeToString(&ComputerNameUCS, L"\\\\");
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("RtlAppendUnicodeToString failed 0x%lx\n", Status);
+        goto done;
+    }
+    Status = RtlAppendUnicodeStringToString(&ComputerNameUCS, 
LogonPwdData->ComputerName);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("RtlAppendUnicodeStringToString failed 0x%lx\n", Status);
+        goto done;
+    }
+
+    BufferLength = sizeof(MSV1_0_LM20_LOGON_PROFILE) + ComputerNameUCS.Length 
+ sizeof(WCHAR);
+
+    Status = NtlmAllocateClientBuffer(ClientRequest, BufferLength, &Buffer);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("DispatchTable.AllocateClientBuffer failed (Status 0x%08lx)\n", 
Status);
+        goto done;
+    }
+
+    TRACE("ClientBaseAddress: %p\n", Buffer.ClientBaseAddress);
+
+    LocalBuffer = (PMSV1_0_LM20_LOGON_PROFILE)Buffer.LocalBuffer;
+    PtrOffset = (PBYTE)(LocalBuffer + 1);
+
+    LocalBuffer->MessageType = MsV1_0Lm20LogonProfile;
+    LocalBuffer->KickOffTime.LowPart = UserInfo->All.AccountExpires.LowPart;
+    LocalBuffer->KickOffTime.HighPart = UserInfo->All.AccountExpires.HighPart;
+    LocalBuffer->LogoffTime.LowPart = UserInfo->All.AccountExpires.LowPart;
+    LocalBuffer->LogoffTime.HighPart = UserInfo->All.AccountExpires.HighPart;
+
+    memcpy(LocalBuffer->UserSessionKey,
+           &LogonPwdData->UserSessionKey,
+           MSV1_0_USER_SESSION_KEY_LENGTH);
+
+    //FIXME: Set Domainname if we domain joined
+    //       what to do if not? WORKGROUP
+    RtlInitUnicodeString(&LocalBuffer->LogonDomainName, NULL);
+
+    memcpy(LocalBuffer->LanmanSessionKey,
+           &LogonPwdData->LanmanSessionKey,
+           MSV1_0_LANMAN_SESSION_KEY_LENGTH);
+
+    if (!NtlmUStrWriteToStruct(LocalBuffer,
+                               BufferLength,
+                               &LocalBuffer->LogonServer,
+                               &ComputerNameUCS,
+                               &PtrOffset,
+                               TRUE))
+    {
+        ERR("NtlmStructWriteUCS failed.\n");
+        Status = ERROR_INTERNAL_ERROR;
+        goto done;
+    }
+    /* not supported */
+    RtlInitUnicodeString(&LocalBuffer->UserParameters, NULL);
+    /* Build user flags */
+    LocalBuffer->UserFlags = 0x0;
+    if (LogonPwdData->LogonType == NetLogonLmKey)
+        LocalBuffer->UserFlags |= LOGON_USED_LM_PASSWORD;
+
+    /* copy data to client buffer */
+    Status = NtlmCopyToClientBuffer(ClientRequest, BufferLength, &Buffer);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("DispatchTable.CopyToClientBuffer failed (Status 0x%08lx)\n", 
Status);
+        goto done;
+    }
+
+    *ProfileBuffer = (PMSV1_0_LM20_LOGON_PROFILE)Buffer.ClientBaseAddress;
+    *ProfileBufferLength = BufferLength;
+done:
+    /* On success Buffer.ClientBaseAddress will not be free */
+    NtlmFreeClientBuffer(ClientRequest, !NT_SUCCESS(Status), &Buffer);
+    NtlmUStrFree(&ComputerNameUCS);
+    return Status;
+}
+
 static
 PSID
 AppendRidToSid(PSID SrcSid,
@@ -931,7 +1030,72 @@ LsaApLogonUserEx2_Network(
     _Out_ PULONG LogonProfileSize,
     _Out_ PNTSTATUS SubStatus)
 {
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PMSV1_0_LM20_LOGON LogonInfo;
+    ULONG_PTR PtrOffset;
+
+    *LogonProfile = NULL;
+    *LogonProfileSize = 0;
+    *UserInfoPtr = NULL;
+    *AccountDomainSidPtr = NULL;
+    *SpecialAccount = FALSE;
+    LogonInfo = ProtocolSubmitBuffer;
+
+    if (SubmitBufferSize < sizeof(MSV1_0_LM20_LOGON))
+    {
+        ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Fix-up pointers in the authentication info */
+    PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
+
+    if ((!NtlmFixupAndValidateUStr(&LogonInfo->LogonDomainName, PtrOffset)) ||
+        (!NtlmFixupAndValidateUStr(&LogonInfo->UserName, PtrOffset)) ||
+        (!NtlmFixupAndValidateUStr(&LogonInfo->Workstation, PtrOffset)) ||
+        (!NtlmFixupAStr(&LogonInfo->CaseSensitiveChallengeResponse, 
PtrOffset)) ||
+        (!NtlmFixupAStr(&LogonInfo->CaseInsensitiveChallengeResponse, 
PtrOffset)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    LogonPwdData->IsNetwork = TRUE;
+    LogonPwdData->LogonInfo = LogonInfo;
+    LogonPwdData->ComputerName = ComputerName;
+    Status = SamValidateUser(Network,
+                             &LogonInfo->UserName,
+                             &LogonInfo->LogonDomainName,
+                             LogonPwdData,
+                             ComputerName,
+                             SpecialAccount,
+                             AccountDomainSidPtr,
+                             UserHandlePtr,
+                             UserInfoPtr,
+                             SubStatus);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("SamValidateUser failed with 0x%lx\n", Status);
+        return Status;
+    }
+
+    if (LogonInfo->ParameterControl & MSV1_0_RETURN_PROFILE_PATH)
+    {
+        Status = BuildLm20LogonProfileBuffer(ClientRequest,
+                                             *UserInfoPtr,
+                                             LogonPwdData,
+                                             LogonProfile,
+                                             LogonProfileSize);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("BuildLm20LogonProfileBuffer failed with 0x%lx\n", Status);
+            return Status;
+        }
+    }
+
+    *LogonUserRef = &LogonInfo->UserName;
+    *LogonDomainRef = &LogonInfo->LogonDomainName;
+
+    return Status;
 }
 
 /*
@@ -1325,39 +1489,6 @@ SpLsaModeInitialize(
 
     *PackageVersion = SECPKG_INTERFACE_VERSION;
 
-    RtlZeroMemory(NtlmLsaFn, sizeof(NtlmLsaFn));
-
-    /* msv1_0 (XP, win2k) returns NULL for
-     * InitializePackage, LsaLogonUser,LsaLogonUserEx,
-     * SpQueryContextAttributes and SpAddCredentials */
-    NtlmLsaFn[0].InitializePackage = NULL;
-    NtlmLsaFn[0].LsaLogonUser = NULL;
-    NtlmLsaFn[0].CallPackage = LsaApCallPackage;
-    NtlmLsaFn[0].LogonTerminated = LsaApLogonTerminated;
-    NtlmLsaFn[0].CallPackageUntrusted = LsaApCallPackageUntrusted;
-    NtlmLsaFn[0].CallPackagePassthrough = LsaApCallPackagePassthrough;
-    NtlmLsaFn[0].LogonUserEx = NULL;
-    NtlmLsaFn[0].LogonUserEx2 = LsaApLogonUserEx2;
-    NtlmLsaFn[0].Initialize = SpInitialize;
-    NtlmLsaFn[0].Shutdown = LsaSpShutDown;
-    NtlmLsaFn[0].GetInfo = LsaSpGetInfoW;
-    NtlmLsaFn[0].AcceptCredentials = SpAcceptCredentials;
-    NtlmLsaFn[0].SpAcquireCredentialsHandle = LsaSpAcquireCredentialsHandle;
-    NtlmLsaFn[0].SpQueryCredentialsAttributes = 
LsaSpQueryCredentialsAttributes;
-    NtlmLsaFn[0].FreeCredentialsHandle = LsaSpFreeCredentialsHandle;
-    NtlmLsaFn[0].SaveCredentials = LsaSpSaveCredentials;
-    NtlmLsaFn[0].GetCredentials = LsaSpGetCredentials;
-    NtlmLsaFn[0].DeleteCredentials = LsaSpDeleteCredentials;
-    NtlmLsaFn[0].InitLsaModeContext = LsaSpInitLsaModeContext;
-    NtlmLsaFn[0].AcceptLsaModeContext = LsaSpAcceptLsaModeContext;
-    NtlmLsaFn[0].DeleteContext = LsaSpDeleteContext;
-    NtlmLsaFn[0].ApplyControlToken = LsaSpApplyControlToken;
-    NtlmLsaFn[0].GetUserInfo = LsaSpGetUserInfo;
-    NtlmLsaFn[0].GetExtendedInformation = LsaSpGetExtendedInformation;
-    NtlmLsaFn[0].SpQueryContextAttributes = NULL;
-    NtlmLsaFn[0].SpAddCredentials = NULL;
-    NtlmLsaFn[0].SetExtendedInformation = LsaSpSetExtendedInformation;
-
     *ppTables = NtlmLsaFn;
     *pcTables = 1;
 
diff --git a/dll/win32/msv1_0/msv1_0.h b/dll/win32/msv1_0/msv1_0.h
index 1b656bca4f1..40b6c6bfc75 100644
--- a/dll/win32/msv1_0/msv1_0.h
+++ b/dll/win32/msv1_0/msv1_0.h
@@ -326,4 +326,62 @@ SystemFunction012(const BYTE *in,
                   const BYTE *key,
                   LPBYTE out);
 
+NTSTATUS
+NTAPI
+LsaApCallPackage(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ PVOID ProtocolSubmitBuffer,
+    _In_ PVOID ClientBufferBase,
+    _In_ ULONG SubmitBufferLength,
+    _Out_ PVOID *ProtocolReturnBuffer,
+    _Out_ PULONG ReturnBufferLength,
+    _Out_ PNTSTATUS ProtocolStatus);
+
+NTSTATUS
+NTAPI
+LsaApCallPackagePassthrough(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ PVOID ProtocolSubmitBuffer,
+    _In_ PVOID ClientBufferBase,
+    _In_ ULONG SubmitBufferLength,
+    _Out_ PVOID *ProtocolReturnBuffer,
+    _Out_ PULONG ReturnBufferLength,
+    _Out_ PNTSTATUS ProtocolStatus);
+
+NTSTATUS
+NTAPI
+LsaApCallPackageUntrusted(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ PVOID ProtocolSubmitBuffer,
+    _In_ PVOID ClientBufferBase,
+    _In_ ULONG SubmitBufferLength,
+    _Out_ PVOID *ProtocolReturnBuffer,
+    _Out_ PULONG ReturnBufferLength,
+    _Out_ PNTSTATUS ProtocolStatus);
+
+VOID
+NTAPI
+LsaApLogonTerminated(
+    _In_ PLUID LogonId);
+
+NTSTATUS
+NTAPI
+LsaApLogonUserEx2(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ SECURITY_LOGON_TYPE LogonType,
+    _In_ PVOID ProtocolSubmitBuffer,
+    _In_ PVOID ClientBufferBase,
+    _In_ ULONG SubmitBufferSize,
+    _Out_ PVOID *ProfileBuffer,
+    _Out_ PULONG ProfileBufferSize,
+    _Out_ PLUID LogonId,
+    _Out_ PNTSTATUS SubStatus,
+    _Out_ PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
+    _Out_ PVOID *TokenInformation,
+    _Out_ PUNICODE_STRING *AccountName,
+    _Out_ PUNICODE_STRING *AuthenticatingAuthority,
+    _Out_ PUNICODE_STRING *MachineName,
+    _Out_ PSECPKG_PRIMARY_CRED PrimaryCredentials,
+    _Out_ PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials);
+
 /* EOF */
diff --git a/dll/win32/msv1_0/ntlm/global.c b/dll/win32/msv1_0/ntlm/global.c
index ba1082f9ff9..12057fd2084 100644
--- a/dll/win32/msv1_0/ntlm/global.c
+++ b/dll/win32/msv1_0/ntlm/global.c
@@ -12,6 +12,47 @@
 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
 
 /* globals */
+NTLM_MODE NtlmMode = NtlmUnknownMode;
+
+LSA_DISPATCH_TABLE DispatchTable;
+
+PLSA_SECPKG_FUNCTION_TABLE LsaFunctions = NULL;
+/* msv1_0 (XP, win2k) returns NULL for
+ * InitializePackage, LsaLogonUser,LsaLogonUserEx,
+ * SpQueryContextAttributes and SpAddCredentials */
+SECPKG_FUNCTION_TABLE NtlmLsaFn[1] = 
+{
+    {
+        .InitializePackage = NULL,
+        .LsaLogonUser = NULL,
+        .CallPackage = LsaApCallPackage,
+        .LogonTerminated = LsaApLogonTerminated,
+        .CallPackageUntrusted = LsaApCallPackageUntrusted,
+        .CallPackagePassthrough = LsaApCallPackagePassthrough,
+        .LogonUserEx = NULL,
+        .LogonUserEx2 = LsaApLogonUserEx2,
+        .Initialize = SpInitialize,
+        .Shutdown = LsaSpShutDown,
+        .GetInfo = LsaSpGetInfoW,
+        .AcceptCredentials = SpAcceptCredentials,
+        .SpAcquireCredentialsHandle = LsaSpAcquireCredentialsHandle,
+        .SpQueryCredentialsAttributes = LsaSpQueryCredentialsAttributes,
+        .FreeCredentialsHandle = LsaSpFreeCredentialsHandle,
+        .SaveCredentials = LsaSpSaveCredentials,
+        .GetCredentials = LsaSpGetCredentials,
+        .DeleteCredentials = LsaSpDeleteCredentials,
+        .InitLsaModeContext = LsaSpInitLsaModeContext,
+        .AcceptLsaModeContext = LsaSpAcceptLsaModeContext,
+        .DeleteContext = LsaSpDeleteContext,
+        .ApplyControlToken = LsaSpApplyControlToken,
+        .GetUserInfo = LsaSpGetUserInfo,
+        .GetExtendedInformation = LsaSpGetExtendedInformation,
+        .SpQueryContextAttributes = NULL,
+        .SpAddCredentials = NULL,
+        .SetExtendedInformation = LsaSpSetExtendedInformation
+    }
+};
+
 PSECPKG_DLL_FUNCTIONS UsrFunctions = NULL;
 SECPKG_USER_FUNCTION_TABLE NtlmUsrFn[1] =
 {
diff --git a/dll/win32/msv1_0/ntlm/global.h b/dll/win32/msv1_0/ntlm/global.h
index 2ee2f1092dd..4b83d232bc4 100644
--- a/dll/win32/msv1_0/ntlm/global.h
+++ b/dll/win32/msv1_0/ntlm/global.h
@@ -1,17 +1,29 @@
 /*
  * PROJECT:     Authentication Package DLL
  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE:     ntlm globals definitions (header)
+ * PURPOSE:     NTLM globals definitions (header)
  * COPYRIGHT:   Copyright 2011 Samuel Serapión
- *              Copyright 2020 Andreas Maier ([email protected])
+ *              Copyright 2020 Andreas Maier <[email protected]>
  */
 
-#ifndef _MSV1_0_NTLM_GLOBALS_H_
-#define _MSV1_0_NTLM_GLOBALS_H_
+#pragma once
 
+/* functions provided by LSA in SpInitialize */
+extern PLSA_SECPKG_FUNCTION_TABLE LsaFunctions;
+/* functions we provide to LSA in SpLsaModeInitialize */
+extern SECPKG_FUNCTION_TABLE NtlmLsaFn[1];
 /* functions provided by LSA in SpInstanceInit */
 extern PSECPKG_DLL_FUNCTIONS UsrFunctions;
 /* functions we provide to LSA in SpUserModeInitialize */
 extern SECPKG_USER_FUNCTION_TABLE NtlmUsrFn[1];
 
-#endif
+extern LSA_DISPATCH_TABLE DispatchTable;
+
+typedef enum _NTLM_MODE
+{
+    NtlmUnknownMode = 0,
+    NtlmLsaMode = 1,
+    NtlmUserMode
+} NTLM_MODE, *PNTLM_MODE;
+
+extern NTLM_MODE NtlmMode;
diff --git a/dll/win32/msv1_0/ntlm/protocol.h b/dll/win32/msv1_0/ntlm/protocol.h
new file mode 100644
index 00000000000..e379845eb80
--- /dev/null
+++ b/dll/win32/msv1_0/ntlm/protocol.h
@@ -0,0 +1,24 @@
+/*
+ * PROJECT:     Authentication Package DLL
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     NTLM protocol definitions (header)
+ * COPYRIGHT:   Copyright 2011 Samuel Serapión
+ *              Copyright 2020 Andreas Maier <[email protected]>
+ */
+
+#pragma once
+
+typedef struct _CYPHER_BLOCK
+{
+    CHAR data[8];
+} CYPHER_BLOCK, *PCYPHER_BLOCK;
+
+typedef struct _USER_SESSION_KEY
+{
+    CYPHER_BLOCK data[2];
+} USER_SESSION_KEY, *PUSER_SESSION_KEY;
+
+typedef struct _LANMAN_SESSION_KEY
+{
+    UINT8 data[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
+} LANMAN_SESSION_KEY, *PLANMAN_SESSION_KEY;
diff --git a/dll/win32/msv1_0/ntlm/util.c b/dll/win32/msv1_0/ntlm/util.c
new file mode 100644
index 00000000000..948a0b72e09
--- /dev/null
+++ b/dll/win32/msv1_0/ntlm/util.c
@@ -0,0 +1,367 @@
+/*
+ * PROJECT:     Authentication Package DLL
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Utils for msv1_0
+ * COPYRIGHT:   Copyright 2011 Samuel Serapión
+ *              Copyright 2020 Andreas Maier <[email protected]>
+ */
+
+#include "../precomp.h"
+
+#include "wine/debug.h"
+WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
+
+#define NTLM_ALLOC_TAG "NTLM"
+#define NTLM_ALLOC_TAG_SIZE strlen(NTLM_ALLOC_TAG)
+
+PVOID
+NtlmAllocate(
+    _In_ size_t Size,
+    _In_ bool UsePrivateLsaHeap)
+{
+    PVOID buffer = NULL;
+
+    if (Size == 0)
+    {
+        ERR("Allocating 0 bytes!\n");
+        return NULL;
+    }
+
+    Size += NTLM_ALLOC_TAG_SIZE;
+
+    switch (NtlmMode)
+    {
+        case NtlmLsaMode:
+        {
+            if (UsePrivateLsaHeap)
+                buffer = LsaFunctions->AllocatePrivateHeap(Size);
+            else
+                buffer = LsaFunctions->AllocateLsaHeap(Size);
+
+            if (buffer != NULL)
+                RtlZeroMemory(buffer, Size);
+            break;
+        }
+        case NtlmUserMode:
+        {
+            buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
+            break;
+        }
+        default:
+        {
+            ERR("NtlmState unknown!\n");
+            break;
+        }
+    }
+
+    memcpy(buffer, NTLM_ALLOC_TAG, NTLM_ALLOC_TAG_SIZE);
+    buffer = (PBYTE)buffer + NTLM_ALLOC_TAG_SIZE;
+
+    return buffer;
+}
+
+VOID
+NtlmFree(
+    _In_ PVOID Buffer,
+    _In_ bool FromPrivateLsaHeap)
+{
+    if (Buffer)
+    {
+        Buffer = (PBYTE)Buffer - NTLM_ALLOC_TAG_SIZE;
+        ASSERT(memcmp(Buffer, NTLM_ALLOC_TAG, NTLM_ALLOC_TAG_SIZE) == 0);
+        *(char*)Buffer = 'D';
+
+        switch (NtlmMode)
+        {
+            case NtlmLsaMode:
+            {
+                if (FromPrivateLsaHeap)
+                    LsaFunctions->FreePrivateHeap(Buffer);
+                else
+                    LsaFunctions->FreeLsaHeap(Buffer);
+                break;
+            }
+            case NtlmUserMode:
+            {
+                HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, Buffer);
+                break;
+            }
+            default:
+            {
+                ERR("NtlmState unknown!\n");
+                break;
+            }
+        }
+    }
+    else
+    {
+        ERR("Trying to free NULL!\n");
+    }
+}
+
+bool
+NtlmUStrAlloc(
+    _Inout_ PUNICODE_STRING Dst,
+    _In_ UINT16 SizeInBytes,
+    _In_ UINT16 InitLength)
+{
+    Dst->Length = InitLength;
+    Dst->MaximumLength = SizeInBytes;
+    Dst->Buffer = NtlmAllocate(SizeInBytes, false);
+    return (Dst->Buffer != NULL);
+}
+
+VOID
+NtlmUStrFree(
+    _In_ PUNICODE_STRING String)
+{
+    if (String == NULL || String->Buffer == NULL || String->MaximumLength == 0)
+        return;
+
+    NtlmFree(String->Buffer, false);
+    String->Buffer = NULL;
+    String->MaximumLength = 0;
+}
+
+/**
+ * @brief Helper to fill a WCHAR-String in a struct.
+ *        The stringdata is appended to the struct.
+ *        The function does not allocate memory.
+ *
+ * @param[in] DataStart
+ * Start address of the struct
+ * 
+ * @param[in] DataSize
+ * Size of allocated memory (including payload)
+ * 
+ * @param[out] DstDataWPtr
+ * Pointer to the WCHAR* datafield. The address of the data will be written to 
it.
+ * 
+ * @param[in] SrcDataW
+ * Data to write/append at pOffset (payload). pOffset will be increased after 
writing data.
+ * 
+ * @param[in] SrcDataLen
+ * SrcDataLen is the length in bytes without terminator.
+ * if 0 it will be autodetected by assuming a 0-terminating string.
+ *            
+ * @param[in,out] AbsoluteOffsetPtr
+ * Current absolute offset. Will be increased by data length.
+ * 
+ * @param[in] TerminateWith0
+ * Whether to terminate the string with a NULL-char.
+ * 
+ * @return FALSE if something went wrong
+ */
+static
+bool
+NtlmStructWriteStrW(
+    _In_ PVOID DataStart,
+    _In_ ULONG DataSize,
+    _Out_ PWCHAR* DstDataWPtr,
+    _In_ const WCHAR* SrcDataW,
+    _In_ ULONG SrcDataLen,
+    _Inout_ PBYTE* AbsoluteOffsetPtr,
+    _In_ bool TerminateWith0)
+{
+    ULONG SrcDataMaxLen;
+
+    if (SrcDataLen == 0)
+        SrcDataLen = wcslen(SrcDataW) * sizeof(WCHAR);
+
+    SrcDataMaxLen = SrcDataLen;
+    if (TerminateWith0)
+        SrcDataMaxLen += sizeof(WCHAR);
+
+    if (*AbsoluteOffsetPtr < (PBYTE)DataStart)
+    {
+        ERR("Invalid offset\n");
+        return false;
+    }
+
+    if (*AbsoluteOffsetPtr + SrcDataMaxLen > (PBYTE)DataStart + DataSize)
+    {
+        ERR("Out of bounds!\n");
+        return false;
+    }
+
+    memcpy(*AbsoluteOffsetPtr, SrcDataW, SrcDataLen);
+    *DstDataWPtr = (WCHAR*)*AbsoluteOffsetPtr;
+    if (TerminateWith0)
+        (*DstDataWPtr)[SrcDataLen / sizeof(WCHAR)] = 0;
+    *AbsoluteOffsetPtr += SrcDataMaxLen;
+
+    return true;
+}
+
+bool
+NtlmUStrWriteToStruct(
+    _In_ PVOID DataStart,
+    _In_ ULONG DataSize,
+    _Out_ PUNICODE_STRING DstData,
+    _In_ const PUNICODE_STRING SrcData,
+    _Inout_ PBYTE* AbsoluteOffsetPtr,
+    _In_ bool TerminateWith0)
+{
+    if (!NtlmStructWriteStrW(DataStart,
+                             DataSize,
+                             &DstData->Buffer,
+                             SrcData->Buffer,
+                             SrcData->Length,
+                             AbsoluteOffsetPtr,
+                             TerminateWith0))
+        return false;
+
+    DstData->Length = SrcData->Length;
+    DstData->MaximumLength = SrcData->Length;
+    if (TerminateWith0)
+        SrcData->MaximumLength += sizeof(WCHAR);
+
+    return true;
+}
+
+bool
+NtlmFixupAndValidateUStr(
+    _Inout_ PUNICODE_STRING String,
+    _In_ ULONG_PTR FixupOffset)
+{
+    NTSTATUS Status;
+
+    if (String->Length)
+    {
+        String->Buffer = FIXUP_POINTER(String->Buffer, FixupOffset);
+        String->MaximumLength = String->Length;
+    }
+    else
+    {
+        String->Buffer = NULL;
+        String->MaximumLength = 0;
+    }
+
+    Status = RtlValidateUnicodeString(0, String);
+    return NT_SUCCESS(Status);
+}
+
+bool
+NtlmFixupAStr(
+    _Inout_ PSTRING String,
+    _In_ ULONG_PTR FixupOffset)
+{
+    if (String->Length)
+    {
+        String->Buffer = (PCHAR)FIXUP_POINTER(String->Buffer, FixupOffset);
+        String->MaximumLength = String->Length;
+    }
+    else
+    {
+        String->Buffer = NULL;
+        String->MaximumLength = 0;
+    }
+
+    return true;
+}
+
+NTSTATUS
+NtlmAllocateClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ ULONG BufferLength,
+    _Inout_ PNTLM_CLIENT_BUFFER Buffer)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (!Buffer)
+        return STATUS_NO_MEMORY;
+
+    Buffer->LocalBuffer = NtlmAllocate(BufferLength, false);
+    if (!Buffer->LocalBuffer)
+        return STATUS_NO_MEMORY;
+
+    if ((HANDLE)ClientRequest == INVALID_HANDLE_VALUE)
+    {
+        Buffer->ClientBaseAddress = Buffer->LocalBuffer;
+        //if (!ClientBaseAddress)
+        //    return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        Status = DispatchTable.AllocateClientBuffer(ClientRequest,
+                                                    BufferLength,
+                                                    
&Buffer->ClientBaseAddress);
+        if (!NT_SUCCESS(Status))
+        {
+            NtlmFree(Buffer->LocalBuffer, false);
+            Buffer->LocalBuffer = NULL;
+        }
+        //FIXME: Maybe we have to free ClientBaseAddress if something
+        //       goes wrong ...? I'm not sure about that ...
+    }
+    return Status;
+}
+
+NTSTATUS
+NtlmCopyToClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ ULONG BufferLength,
+    _Inout_ PNTLM_CLIENT_BUFFER Buffer)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if ((HANDLE)ClientRequest == INVALID_HANDLE_VALUE)
+    {
+        // If ClientRequest ist INVALID_HANDLE_VALUE
+        // Buffer->LocalBuffer == Buffer->ClientBaseAddress
+        if (Buffer->ClientBaseAddress != Buffer->LocalBuffer)
+        {
+            ERR("Buffer->ClientBaseAddress != Buffer->LocalBuffer (something 
must be wrong!)\n");
+            return STATUS_INTERNAL_ERROR;
+        }
+    }
+    else
+    {
+        if (!Buffer->ClientBaseAddress ||
+            !Buffer->LocalBuffer)
+        {
+            ERR("Invalid Buffer - not allocated!\n");
+            return STATUS_NO_MEMORY;
+        }
+        Status = DispatchTable.CopyToClientBuffer(ClientRequest,
+                                                  BufferLength,
+                                                  Buffer->ClientBaseAddress,
+                                                  Buffer->LocalBuffer);
+    }
+    return Status;
+}
+
+VOID
+NtlmFreeClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ bool FreeClientBuffer,
+    _Inout_ PNTLM_CLIENT_BUFFER Buffer)
+{
+    if (!Buffer->ClientBaseAddress)
+        return;
+
+    if ((HANDLE)ClientRequest == INVALID_HANDLE_VALUE)
+    {
+        if (Buffer->ClientBaseAddress != Buffer->LocalBuffer)
+        {
+            ERR("Buffer->ClientBaseAddress != Buffer->LocalBuffer (something 
must be wrong!)\n");
+            return;
+        }
+        // LocalBuffer and ClientBaseAddress is the same
+        // so we have only to free it if FreeClientBuffer is TRUE.
+        Buffer->LocalBuffer = NULL;
+        if (FreeClientBuffer)
+        {
+            NtlmFree(Buffer->ClientBaseAddress, false);
+            Buffer->ClientBaseAddress = NULL;
+        }
+    }
+    else
+    {
+        NtlmFree(Buffer->LocalBuffer, false);
+        Buffer->LocalBuffer = NULL;
+        if (FreeClientBuffer)
+            DispatchTable.FreeClientBuffer(ClientRequest, 
Buffer->ClientBaseAddress);
+        Buffer->ClientBaseAddress = NULL;
+    }
+}
diff --git a/dll/win32/msv1_0/ntlm/util.h b/dll/win32/msv1_0/ntlm/util.h
new file mode 100644
index 00000000000..69cfa5077ce
--- /dev/null
+++ b/dll/win32/msv1_0/ntlm/util.h
@@ -0,0 +1,64 @@
+/*
+ * PROJECT:     Authentication Package DLL
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Utils for msv1_0 (header)
+ * COPYRIGHT:   Copyright 2011 Samuel Serapión
+ *              Copyright 2020 Andreas Maier <[email protected]>
+ */
+
+#pragma once
+
+bool
+NtlmUStrAlloc(
+    _Out_ PUNICODE_STRING Dst,
+    _In_ UINT16 SizeInBytes,
+    _In_ UINT16 InitLength);
+
+VOID
+NtlmUStrFree(
+    _In_ PUNICODE_STRING String);
+
+bool
+NtlmUStrWriteToStruct(
+    _In_ PVOID DataStart,
+    _In_ ULONG DataSize,
+    _Out_ PUNICODE_STRING DstData,
+    _In_ const PUNICODE_STRING SrcData,
+    _In_ OUT PBYTE* AbsoluteOffsetPtr,
+    _In_ bool TerminateWith0);
+
+/* misc */
+bool
+NtlmFixupAndValidateUStr(
+    _Inout_ PUNICODE_STRING String,
+    _In_ ULONG_PTR FixupOffset);
+
+bool
+NtlmFixupAStr(
+    _Inout_ PSTRING String,
+    _In_ ULONG_PTR FixupOffset);
+
+/* ClientBuffer */
+typedef struct _NTLM_CLIENT_BUFFER
+{
+    PVOID ClientBaseAddress;
+    PVOID LocalBuffer;
+} NTLM_CLIENT_BUFFER, *PNTLM_CLIENT_BUFFER;
+
+NTSTATUS
+NtlmAllocateClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ ULONG BufferLength,
+    _Inout_ PNTLM_CLIENT_BUFFER Buffer);
+
+NTSTATUS
+NtlmCopyToClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ ULONG BufferLength,
+    _In_ OUT PNTLM_CLIENT_BUFFER Buffer);
+
+VOID
+NtlmFreeClientBuffer(
+    _In_ PLSA_CLIENT_REQUEST ClientRequest,
+    _In_ bool FreeClientBuffer,
+    _Inout_ PNTLM_CLIENT_BUFFER Buffer);
diff --git a/dll/win32/msv1_0/precomp.h b/dll/win32/msv1_0/precomp.h
index cf7b0842d50..71b2524844c 100644
--- a/dll/win32/msv1_0/precomp.h
+++ b/dll/win32/msv1_0/precomp.h
@@ -32,6 +32,8 @@
 //#include <lsass/lsasrv.h>
 
 #include "ntlm/global.h"
+#include "ntlm/protocol.h"
+#include "ntlm/util.h"
 #include "lsa.h"
 #include "msv1_0.h"
 #include "sam.h"
diff --git a/dll/win32/msv1_0/sam.c b/dll/win32/msv1_0/sam.c
index 0ffcf20d4f7..684a9f89506 100644
--- a/dll/win32/msv1_0/sam.c
+++ b/dll/win32/msv1_0/sam.c
@@ -476,6 +476,8 @@ SamValidateUser(
     NTSTATUS Status = STATUS_SUCCESS;
 
     *SpecialAccount = FALSE;
+    *UserInfoPtr = NULL;
+    *SubStatus = STATUS_SUCCESS;
 
     /* Check for special accounts */
     // FIXME: Windows does not do this that way!! (msv1_0 does not contain 
these hardcoded values)
diff --git a/dll/win32/msv1_0/sam.h b/dll/win32/msv1_0/sam.h
index 2f82f0e1c6f..d02f2263751 100644
--- a/dll/win32/msv1_0/sam.h
+++ b/dll/win32/msv1_0/sam.h
@@ -7,6 +7,13 @@
 
 #pragma once
 
+typedef enum _LSA_SAM_NETLOGON_TYPE
+{
+    NetLogonAnonymous = 0,
+    NetLogonLmKey,
+    NetLogonNtKey
+} LSA_SAM_NETLOGON_TYPE;
+
 typedef struct _LSA_SAM_PWD_DATA
 {
     /* TRUE: PlainPwd is filled,
@@ -15,7 +22,12 @@ typedef struct _LSA_SAM_PWD_DATA
     PUNICODE_STRING PlainPwd;
 
     /* Input (IsNetwork = TRUE) */
+    PMSV1_0_LM20_LOGON LogonInfo;
     PUNICODE_STRING ComputerName;
+    /* Result (IsNetwork = TRUE) */
+    LSA_SAM_NETLOGON_TYPE LogonType;
+    LANMAN_SESSION_KEY LanmanSessionKey;
+    USER_SESSION_KEY UserSessionKey;
 } LSA_SAM_PWD_DATA, *PLSA_SAM_PWD_DATA;
 
 /**

Reply via email to