2013-03-03 19:11:22 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: Authentication Package DLL
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: dll/win32/msv1_0/msv1_0.c
|
|
|
|
* PURPOSE: Main file
|
|
|
|
* COPYRIGHT: Copyright 2013 Eric Kohl
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
|
2020-03-28 16:13:57 +00:00
|
|
|
#include "precomp.h"
|
2013-03-03 19:11:22 +00:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msv1_0);
|
|
|
|
|
|
|
|
|
2013-03-04 21:32:44 +00:00
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
|
|
|
|
LSA_DISPATCH_TABLE DispatchTable;
|
|
|
|
|
|
|
|
|
2013-03-03 19:11:22 +00:00
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
|
2013-03-17 13:55:51 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
2018-05-26 16:42:31 +00:00
|
|
|
GetAccountDomainSid(PRPC_SID *Sid)
|
2013-03-17 13:55:51 +00:00
|
|
|
{
|
|
|
|
LSAPR_HANDLE PolicyHandle = NULL;
|
|
|
|
PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
|
|
|
|
ULONG Length = 0;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = LsaIOpenPolicyTrusted(&PolicyHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("LsaIOpenPolicyTrusted() failed (Status 0x%08lx)\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = LsarQueryInformationPolicy(PolicyHandle,
|
|
|
|
PolicyAccountDomainInformation,
|
|
|
|
&PolicyInfo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("LsarQueryInformationPolicy() failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
Length = RtlLengthSid(PolicyInfo->PolicyAccountDomainInfo.Sid);
|
|
|
|
|
|
|
|
*Sid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
|
|
|
|
if (*Sid == NULL)
|
|
|
|
{
|
|
|
|
ERR("Failed to allocate SID\n");
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(*Sid, PolicyInfo->PolicyAccountDomainInfo.Sid, Length);
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (PolicyInfo != NULL)
|
|
|
|
LsaIFree_LSAPR_POLICY_INFORMATION(PolicyAccountDomainInformation,
|
|
|
|
PolicyInfo);
|
|
|
|
|
|
|
|
if (PolicyHandle != NULL)
|
|
|
|
LsarClose(&PolicyHandle);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
GetNtAuthorityDomainSid(PRPC_SID *Sid)
|
|
|
|
{
|
|
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
|
|
|
ULONG Length = 0;
|
|
|
|
|
|
|
|
Length = RtlLengthRequiredSid(0);
|
|
|
|
*Sid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
|
|
|
|
if (*Sid == NULL)
|
|
|
|
{
|
|
|
|
ERR("Failed to allocate SID\n");
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlInitializeSid(*Sid,&NtAuthority, 0);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-21 21:08:58 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest,
|
|
|
|
IN PSAMPR_USER_INFO_BUFFER UserInfo,
|
2019-03-04 16:25:11 +00:00
|
|
|
IN PWSTR ComputerName,
|
2013-04-21 21:08:58 +00:00
|
|
|
OUT PMSV1_0_INTERACTIVE_PROFILE *ProfileBuffer,
|
|
|
|
OUT PULONG ProfileBufferLength)
|
|
|
|
{
|
|
|
|
PMSV1_0_INTERACTIVE_PROFILE LocalBuffer = NULL;
|
|
|
|
PVOID ClientBaseAddress = NULL;
|
|
|
|
LPWSTR Ptr;
|
|
|
|
ULONG BufferLength;
|
2013-05-05 00:53:25 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2013-04-21 21:08:58 +00:00
|
|
|
|
|
|
|
*ProfileBuffer = NULL;
|
|
|
|
*ProfileBufferLength = 0;
|
|
|
|
|
|
|
|
BufferLength = sizeof(MSV1_0_INTERACTIVE_PROFILE) +
|
|
|
|
UserInfo->All.FullName.Length + sizeof(WCHAR) +
|
|
|
|
UserInfo->All.HomeDirectory.Length + sizeof(WCHAR) +
|
|
|
|
UserInfo->All.HomeDirectoryDrive.Length + sizeof(WCHAR) +
|
|
|
|
UserInfo->All.ScriptPath.Length + sizeof(WCHAR) +
|
|
|
|
UserInfo->All.ProfilePath.Length + sizeof(WCHAR) +
|
2019-03-04 16:25:11 +00:00
|
|
|
((wcslen(ComputerName) + 3) * sizeof(WCHAR));
|
2013-04-21 21:08:58 +00:00
|
|
|
|
|
|
|
LocalBuffer = DispatchTable.AllocateLsaHeap(BufferLength);
|
|
|
|
if (LocalBuffer == NULL)
|
|
|
|
{
|
|
|
|
TRACE("Failed to allocate the local buffer!\n");
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = DispatchTable.AllocateClientBuffer(ClientRequest,
|
|
|
|
BufferLength,
|
|
|
|
&ClientBaseAddress);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("DispatchTable.AllocateClientBuffer failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("ClientBaseAddress: %p\n", ClientBaseAddress);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)LocalBuffer + sizeof(MSV1_0_INTERACTIVE_PROFILE));
|
|
|
|
|
|
|
|
LocalBuffer->MessageType = MsV1_0InteractiveProfile;
|
|
|
|
LocalBuffer->LogonCount = UserInfo->All.LogonCount;
|
|
|
|
LocalBuffer->BadPasswordCount = UserInfo->All.BadPasswordCount;
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
LocalBuffer->LogonTime.LowPart = UserInfo->All.LastLogon.LowPart;
|
|
|
|
LocalBuffer->LogonTime.HighPart = UserInfo->All.LastLogon.HighPart;
|
|
|
|
|
2018-09-04 21:15:15 +00:00
|
|
|
LocalBuffer->LogoffTime.LowPart = UserInfo->All.AccountExpires.LowPart;
|
|
|
|
LocalBuffer->LogoffTime.HighPart = UserInfo->All.AccountExpires.HighPart;
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2018-09-04 21:15:15 +00:00
|
|
|
LocalBuffer->KickOffTime.LowPart = UserInfo->All.AccountExpires.LowPart;
|
|
|
|
LocalBuffer->KickOffTime.HighPart = UserInfo->All.AccountExpires.HighPart;
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
LocalBuffer->PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
|
|
|
|
LocalBuffer->PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;
|
|
|
|
|
|
|
|
LocalBuffer->PasswordCanChange.LowPart = UserInfo->All.PasswordCanChange.LowPart;
|
|
|
|
LocalBuffer->PasswordCanChange.HighPart = UserInfo->All.PasswordCanChange.HighPart;
|
|
|
|
|
|
|
|
LocalBuffer->PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
|
|
|
|
LocalBuffer->PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
|
2013-04-21 21:08:58 +00:00
|
|
|
|
|
|
|
LocalBuffer->LogonScript.Length = UserInfo->All.ScriptPath.Length;
|
|
|
|
LocalBuffer->LogonScript.MaximumLength = UserInfo->All.ScriptPath.Length + sizeof(WCHAR);
|
|
|
|
LocalBuffer->LogonScript.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
|
|
|
memcpy(Ptr,
|
|
|
|
UserInfo->All.ScriptPath.Buffer,
|
|
|
|
UserInfo->All.ScriptPath.Length);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->LogonScript.MaximumLength);
|
|
|
|
|
|
|
|
LocalBuffer->HomeDirectory.Length = UserInfo->All.HomeDirectory.Length;
|
|
|
|
LocalBuffer->HomeDirectory.MaximumLength = UserInfo->All.HomeDirectory.Length + sizeof(WCHAR);
|
|
|
|
LocalBuffer->HomeDirectory.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
|
|
|
memcpy(Ptr,
|
|
|
|
UserInfo->All.HomeDirectory.Buffer,
|
|
|
|
UserInfo->All.HomeDirectory.Length);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->HomeDirectory.MaximumLength);
|
|
|
|
|
|
|
|
LocalBuffer->FullName.Length = UserInfo->All.FullName.Length;
|
|
|
|
LocalBuffer->FullName.MaximumLength = UserInfo->All.FullName.Length + sizeof(WCHAR);
|
|
|
|
LocalBuffer->FullName.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
|
|
|
memcpy(Ptr,
|
|
|
|
UserInfo->All.FullName.Buffer,
|
|
|
|
UserInfo->All.FullName.Length);
|
|
|
|
TRACE("FullName.Buffer: %p\n", LocalBuffer->FullName.Buffer);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->FullName.MaximumLength);
|
|
|
|
|
|
|
|
LocalBuffer->ProfilePath.Length = UserInfo->All.ProfilePath.Length;
|
|
|
|
LocalBuffer->ProfilePath.MaximumLength = UserInfo->All.ProfilePath.Length + sizeof(WCHAR);
|
|
|
|
LocalBuffer->ProfilePath.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
|
|
|
memcpy(Ptr,
|
|
|
|
UserInfo->All.ProfilePath.Buffer,
|
|
|
|
UserInfo->All.ProfilePath.Length);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->ProfilePath.MaximumLength);
|
|
|
|
|
|
|
|
LocalBuffer->HomeDirectoryDrive.Length = UserInfo->All.HomeDirectoryDrive.Length;
|
|
|
|
LocalBuffer->HomeDirectoryDrive.MaximumLength = UserInfo->All.HomeDirectoryDrive.Length + sizeof(WCHAR);
|
|
|
|
LocalBuffer->HomeDirectoryDrive.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
|
|
|
memcpy(Ptr,
|
|
|
|
UserInfo->All.HomeDirectoryDrive.Buffer,
|
|
|
|
UserInfo->All.HomeDirectoryDrive.Length);
|
|
|
|
|
|
|
|
Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->HomeDirectoryDrive.MaximumLength);
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
LocalBuffer->LogonServer.Length = (wcslen(ComputerName) + 2) * sizeof(WCHAR);
|
|
|
|
LocalBuffer->LogonServer.MaximumLength = LocalBuffer->LogonServer.Length + sizeof(WCHAR);
|
2016-02-04 20:42:07 +00:00
|
|
|
LocalBuffer->LogonServer.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
|
2019-03-04 16:25:11 +00:00
|
|
|
wcscpy(Ptr, L"\\");
|
|
|
|
wcscat(Ptr, ComputerName);
|
2013-04-21 21:08:58 +00:00
|
|
|
|
|
|
|
LocalBuffer->UserFlags = 0;
|
|
|
|
|
|
|
|
Status = DispatchTable.CopyToClientBuffer(ClientRequest,
|
|
|
|
BufferLength,
|
|
|
|
ClientBaseAddress,
|
|
|
|
LocalBuffer);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("DispatchTable.CopyToClientBuffer failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ProfileBuffer = (PMSV1_0_INTERACTIVE_PROFILE)ClientBaseAddress;
|
|
|
|
*ProfileBufferLength = BufferLength;
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (LocalBuffer != NULL)
|
|
|
|
DispatchTable.FreeLsaHeap(LocalBuffer);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (ClientBaseAddress != NULL)
|
|
|
|
DispatchTable.FreeClientBuffer(ClientRequest,
|
|
|
|
ClientBaseAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
static
|
|
|
|
PSID
|
|
|
|
AppendRidToSid(PSID SrcSid,
|
|
|
|
ULONG Rid)
|
|
|
|
{
|
|
|
|
PSID DstSid = NULL;
|
|
|
|
UCHAR RidCount;
|
|
|
|
|
|
|
|
RidCount = *RtlSubAuthorityCountSid(SrcSid);
|
|
|
|
if (RidCount >= 8)
|
|
|
|
return NULL;
|
|
|
|
|
2013-05-13 13:47:33 +00:00
|
|
|
DstSid = DispatchTable.AllocateLsaHeap(RtlLengthRequiredSid(RidCount + 1));
|
2013-05-05 00:53:25 +00:00
|
|
|
if (DstSid == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2013-05-13 13:47:33 +00:00
|
|
|
RtlCopyMemory(DstSid,
|
|
|
|
SrcSid,
|
|
|
|
RtlLengthRequiredSid(RidCount));
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2013-05-13 13:47:33 +00:00
|
|
|
*RtlSubAuthorityCountSid(DstSid) = RidCount + 1;
|
2013-05-05 00:53:25 +00:00
|
|
|
*RtlSubAuthoritySid(DstSid, RidCount) = Rid;
|
|
|
|
|
|
|
|
return DstSid;
|
|
|
|
}
|
|
|
|
|
2018-09-04 21:15:15 +00:00
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
BuildTokenUser(OUT PTOKEN_USER User,
|
|
|
|
IN PSID AccountDomainSid,
|
|
|
|
IN ULONG RelativeId)
|
|
|
|
{
|
|
|
|
User->User.Sid = AppendRidToSid(AccountDomainSid,
|
|
|
|
RelativeId);
|
2013-05-13 13:47:33 +00:00
|
|
|
if (User->User.Sid == NULL)
|
|
|
|
{
|
|
|
|
ERR("Could not create the user SID\n");
|
2013-12-28 23:47:04 +00:00
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
2013-05-13 13:47:33 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
User->User.Attributes = 0;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
NTSTATUS
|
2013-12-28 23:47:04 +00:00
|
|
|
BuildTokenPrimaryGroup(OUT PTOKEN_PRIMARY_GROUP PrimaryGroup,
|
|
|
|
IN PSID AccountDomainSid,
|
|
|
|
IN ULONG RelativeId)
|
|
|
|
{
|
|
|
|
PrimaryGroup->PrimaryGroup = AppendRidToSid(AccountDomainSid,
|
|
|
|
RelativeId);
|
|
|
|
if (PrimaryGroup->PrimaryGroup == NULL)
|
|
|
|
{
|
|
|
|
ERR("Could not create the primary group SID\n");
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
BuildTokenGroups(OUT PTOKEN_GROUPS *Groups,
|
2018-05-26 16:42:31 +00:00
|
|
|
IN PSID AccountDomainSid,
|
|
|
|
IN ULONG RelativeId,
|
|
|
|
IN BOOL SpecialAccount)
|
2013-05-05 00:53:25 +00:00
|
|
|
{
|
|
|
|
SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
|
|
|
|
PTOKEN_GROUPS TokenGroups;
|
|
|
|
DWORD GroupCount = 0;
|
2018-05-26 16:42:31 +00:00
|
|
|
DWORD MaxGroups = 2;
|
2013-05-05 00:53:25 +00:00
|
|
|
PSID Sid;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
if (SpecialAccount)
|
|
|
|
MaxGroups++;
|
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
TokenGroups = DispatchTable.AllocateLsaHeap(sizeof(TOKEN_GROUPS) +
|
2018-05-26 16:42:31 +00:00
|
|
|
MaxGroups * sizeof(SID_AND_ATTRIBUTES));
|
2013-05-05 00:53:25 +00:00
|
|
|
if (TokenGroups == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
if (SpecialAccount)
|
2013-05-05 00:53:25 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Self */
|
|
|
|
Sid = AppendRidToSid(AccountDomainSid, RelativeId);
|
|
|
|
if (Sid == NULL)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
TokenGroups->Groups[GroupCount].Sid = Sid;
|
|
|
|
TokenGroups->Groups[GroupCount].Attributes =
|
|
|
|
SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
|
|
|
|
GroupCount++;
|
|
|
|
|
|
|
|
/* Member of 'Users' alias */
|
|
|
|
RtlAllocateAndInitializeSid(&SystemAuthority,
|
|
|
|
2,
|
|
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
|
|
DOMAIN_ALIAS_RID_USERS,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
&Sid);
|
|
|
|
TokenGroups->Groups[GroupCount].Sid = Sid;
|
|
|
|
TokenGroups->Groups[GroupCount].Attributes =
|
|
|
|
SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
|
|
|
|
GroupCount++;
|
2013-05-05 00:53:25 +00:00
|
|
|
}
|
2018-05-26 16:42:31 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Member of the domains users group */
|
|
|
|
Sid = AppendRidToSid(AccountDomainSid, DOMAIN_GROUP_RID_USERS);
|
|
|
|
if (Sid == NULL)
|
|
|
|
{
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
TokenGroups->Groups[GroupCount].Sid = Sid;
|
|
|
|
TokenGroups->Groups[GroupCount].Attributes =
|
|
|
|
SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
|
|
|
|
GroupCount++;
|
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
/* Member of 'Authenticated users' */
|
|
|
|
RtlAllocateAndInitializeSid(&SystemAuthority,
|
|
|
|
1,
|
|
|
|
SECURITY_AUTHENTICATED_USER_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
SECURITY_NULL_RID,
|
|
|
|
&Sid);
|
|
|
|
TokenGroups->Groups[GroupCount].Sid = Sid;
|
|
|
|
TokenGroups->Groups[GroupCount].Attributes =
|
|
|
|
SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
|
|
|
|
GroupCount++;
|
|
|
|
|
|
|
|
TokenGroups->GroupCount = GroupCount;
|
2018-05-26 16:42:31 +00:00
|
|
|
ASSERT(TokenGroups->GroupCount <= MaxGroups);
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
*Groups = TokenGroups;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
|
|
|
|
PRPC_SID AccountDomainSid,
|
2018-05-26 16:42:31 +00:00
|
|
|
PSAMPR_USER_INFO_BUFFER UserInfo,
|
|
|
|
BOOL SpecialAccount)
|
2013-05-05 00:53:25 +00:00
|
|
|
{
|
|
|
|
PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
|
|
|
|
ULONG i;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
Buffer = DispatchTable.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1));
|
|
|
|
if (Buffer == NULL)
|
|
|
|
{
|
2018-09-04 21:15:15 +00:00
|
|
|
WARN("Failed to allocate the local buffer!\n");
|
2013-05-05 00:53:25 +00:00
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-09-04 21:15:15 +00:00
|
|
|
Buffer->ExpirationTime.LowPart = UserInfo->All.AccountExpires.LowPart;
|
|
|
|
Buffer->ExpirationTime.HighPart = UserInfo->All.AccountExpires.HighPart;
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
Status = BuildTokenUser(&Buffer->User,
|
|
|
|
(PSID)AccountDomainSid,
|
2013-12-28 23:47:04 +00:00
|
|
|
UserInfo->All.UserId);
|
2013-05-05 00:53:25 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2018-09-04 21:15:15 +00:00
|
|
|
{
|
|
|
|
WARN("BuildTokenUser() failed (Status 0x%08lx)\n", Status);
|
2013-05-05 00:53:25 +00:00
|
|
|
goto done;
|
2018-09-04 21:15:15 +00:00
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2013-12-28 23:47:04 +00:00
|
|
|
Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup,
|
|
|
|
(PSID)AccountDomainSid,
|
|
|
|
UserInfo->All.PrimaryGroupId);
|
2013-05-05 00:53:25 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2018-09-04 21:15:15 +00:00
|
|
|
{
|
|
|
|
WARN("BuildTokenPrimaryGroup() failed (Status 0x%08lx)\n", Status);
|
2013-05-05 00:53:25 +00:00
|
|
|
goto done;
|
2018-09-04 21:15:15 +00:00
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
2013-12-28 23:47:04 +00:00
|
|
|
Status = BuildTokenGroups(&Buffer->Groups,
|
2018-05-26 16:42:31 +00:00
|
|
|
(PSID)AccountDomainSid,
|
|
|
|
UserInfo->All.UserId,
|
|
|
|
SpecialAccount);
|
2013-05-05 00:53:25 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2018-09-04 21:15:15 +00:00
|
|
|
{
|
|
|
|
WARN("BuildTokenGroups() failed (Status 0x%08lx)\n", Status);
|
2013-05-05 00:53:25 +00:00
|
|
|
goto done;
|
2018-09-04 21:15:15 +00:00
|
|
|
}
|
2013-05-05 00:53:25 +00:00
|
|
|
|
|
|
|
*TokenInformation = Buffer;
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (Buffer != NULL)
|
|
|
|
{
|
|
|
|
if (Buffer->User.User.Sid != NULL)
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer->User.User.Sid);
|
|
|
|
|
|
|
|
if (Buffer->Groups != NULL)
|
|
|
|
{
|
|
|
|
for (i = 0; i < Buffer->Groups->GroupCount; i++)
|
|
|
|
{
|
|
|
|
if (Buffer->Groups->Groups[i].Sid != NULL)
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer->Groups->Groups[i].Sid);
|
|
|
|
}
|
|
|
|
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer->Groups);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Buffer->PrimaryGroup.PrimaryGroup != NULL)
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup);
|
|
|
|
|
|
|
|
if (Buffer->DefaultDacl.DefaultDacl != NULL)
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl);
|
|
|
|
|
|
|
|
DispatchTable.FreeLsaHeap(Buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-01 18:43:36 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
2013-10-13 20:15:01 +00:00
|
|
|
MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
|
|
|
|
IN PVOID ProtocolSubmitBuffer,
|
|
|
|
IN PVOID ClientBufferBase,
|
|
|
|
IN ULONG SubmitBufferLength,
|
|
|
|
OUT PVOID *ProtocolReturnBuffer,
|
|
|
|
OUT PULONG ReturnBufferLength,
|
|
|
|
OUT PNTSTATUS ProtocolStatus)
|
2013-07-01 18:43:36 +00:00
|
|
|
{
|
2019-06-18 00:27:08 +00:00
|
|
|
NTSTATUS Status;
|
2013-07-01 18:43:36 +00:00
|
|
|
PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
|
|
|
|
ULONG_PTR PtrOffset;
|
|
|
|
|
2014-01-26 10:43:58 +00:00
|
|
|
SAMPR_HANDLE ServerHandle = NULL;
|
|
|
|
SAMPR_HANDLE DomainHandle = NULL;
|
|
|
|
SAMPR_HANDLE UserHandle = NULL;
|
|
|
|
PRPC_SID DomainSid = NULL;
|
|
|
|
RPC_UNICODE_STRING Names[1];
|
|
|
|
SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
|
|
|
|
SAMPR_ULONG_ARRAY Use = {0, NULL};
|
|
|
|
|
2014-02-10 20:08:29 +00:00
|
|
|
ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
|
|
|
|
ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
|
|
|
|
OEM_STRING LmPwdString;
|
|
|
|
CHAR LmPwdBuffer[15];
|
|
|
|
BOOLEAN OldLmPasswordPresent = FALSE;
|
|
|
|
BOOLEAN NewLmPasswordPresent = FALSE;
|
|
|
|
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt;
|
|
|
|
PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL;
|
|
|
|
PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL;
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
TRACE("MsvpChangePassword()\n");
|
|
|
|
|
|
|
|
/* Parameters validation */
|
|
|
|
|
|
|
|
if (SubmitBufferLength < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST))
|
|
|
|
{
|
|
|
|
ERR("Invalid SubmitBufferLength %lu\n", SubmitBufferLength);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2013-07-01 18:43:36 +00:00
|
|
|
|
|
|
|
RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
|
|
|
|
|
|
|
|
/* Fix-up pointers in the request buffer info */
|
|
|
|
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
Status = RtlValidateUnicodeString(0, &RequestBuffer->DomainName);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
2013-10-13 20:15:01 +00:00
|
|
|
RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
|
2019-06-18 00:27:08 +00:00
|
|
|
RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length;
|
|
|
|
|
|
|
|
Status = RtlValidateUnicodeString(0, &RequestBuffer->AccountName);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
2013-10-13 20:15:01 +00:00
|
|
|
RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
|
2019-06-18 00:27:08 +00:00
|
|
|
RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length;
|
|
|
|
|
|
|
|
Status = RtlValidateUnicodeString(0, &RequestBuffer->OldPassword);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
2013-10-13 20:15:01 +00:00
|
|
|
RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
|
2019-06-18 00:27:08 +00:00
|
|
|
RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length;
|
|
|
|
|
|
|
|
Status = RtlValidateUnicodeString(0, &RequestBuffer->NewPassword);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
2013-10-13 20:15:01 +00:00
|
|
|
RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
|
2019-06-18 00:27:08 +00:00
|
|
|
RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length;
|
2013-07-01 18:43:36 +00:00
|
|
|
|
|
|
|
TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
|
|
|
|
TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
|
|
|
|
TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
|
|
|
|
TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);
|
|
|
|
|
2014-01-26 10:43:58 +00:00
|
|
|
/* Connect to the SAM server */
|
|
|
|
Status = SamIConnect(NULL,
|
|
|
|
&ServerHandle,
|
|
|
|
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the domain SID */
|
|
|
|
Status = SamrLookupDomainInSamServer(ServerHandle,
|
|
|
|
(PRPC_UNICODE_STRING)&RequestBuffer->DomainName,
|
|
|
|
&DomainSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
2013-07-01 18:43:36 +00:00
|
|
|
|
2014-01-26 10:43:58 +00:00
|
|
|
/* Open the domain */
|
|
|
|
Status = SamrOpenDomain(ServerHandle,
|
|
|
|
DOMAIN_LOOKUP,
|
|
|
|
DomainSid,
|
|
|
|
&DomainHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
Names[0].Length = RequestBuffer->AccountName.Length;
|
|
|
|
Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
|
|
|
|
Names[0].Buffer = RequestBuffer->AccountName.Buffer;
|
|
|
|
|
|
|
|
/* Try to get the RID for the user name */
|
|
|
|
Status = SamrLookupNamesInDomain(DomainHandle,
|
|
|
|
1,
|
|
|
|
Names,
|
|
|
|
&RelativeIds,
|
|
|
|
&Use);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
|
|
|
|
Status = STATUS_NO_SUCH_USER;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fail, if it is not a user account */
|
|
|
|
if (Use.Element[0] != SidTypeUser)
|
|
|
|
{
|
|
|
|
TRACE("Account is not a user account!\n");
|
|
|
|
Status = STATUS_NO_SUCH_USER;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open the user object */
|
|
|
|
Status = SamrOpenUser(DomainHandle,
|
|
|
|
USER_CHANGE_PASSWORD,
|
|
|
|
RelativeIds.Element[0],
|
|
|
|
&UserHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-10 20:08:29 +00:00
|
|
|
/* Calculate the NT hash for the old password */
|
|
|
|
Status = SystemFunction007(&RequestBuffer->OldPassword,
|
|
|
|
(LPBYTE)&OldNtPassword);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the NT hash for the new password */
|
|
|
|
Status = SystemFunction007(&RequestBuffer->NewPassword,
|
|
|
|
(LPBYTE)&NewNtPassword);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the LM password and hash for the old password */
|
|
|
|
LmPwdString.Length = 15;
|
|
|
|
LmPwdString.MaximumLength = 15;
|
|
|
|
LmPwdString.Buffer = LmPwdBuffer;
|
|
|
|
ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
|
|
|
|
|
|
|
|
Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
|
|
|
|
&RequestBuffer->OldPassword,
|
|
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Calculate the LM hash value of the password */
|
|
|
|
Status = SystemFunction006(LmPwdString.Buffer,
|
|
|
|
(LPSTR)&OldLmPassword);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
OldLmPasswordPresent = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the LM password and hash for the new password */
|
|
|
|
LmPwdString.Length = 15;
|
|
|
|
LmPwdString.MaximumLength = 15;
|
|
|
|
LmPwdString.Buffer = LmPwdBuffer;
|
|
|
|
ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
|
|
|
|
|
|
|
|
Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
|
|
|
|
&RequestBuffer->NewPassword,
|
|
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Calculate the LM hash value of the password */
|
|
|
|
Status = SystemFunction006(LmPwdString.Buffer,
|
|
|
|
(LPSTR)&NewLmPassword);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
NewLmPasswordPresent = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Encrypt the old and new LM passwords, if they exist */
|
|
|
|
if (OldLmPasswordPresent && NewLmPasswordPresent)
|
|
|
|
{
|
|
|
|
/* Encrypt the old LM password */
|
|
|
|
Status = SystemFunction012((const BYTE *)&OldLmPassword,
|
|
|
|
(const BYTE *)&NewLmPassword,
|
|
|
|
(LPBYTE)&OldLmEncryptedWithNewLm);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Encrypt the new LM password */
|
|
|
|
Status = SystemFunction012((const BYTE *)&NewLmPassword,
|
|
|
|
(const BYTE *)&OldLmPassword,
|
|
|
|
(LPBYTE)&NewLmEncryptedWithOldLm);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm;
|
|
|
|
pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Encrypt the old NT password */
|
|
|
|
Status = SystemFunction012((const BYTE *)&OldNtPassword,
|
|
|
|
(const BYTE *)&NewNtPassword,
|
|
|
|
(LPBYTE)&OldNtEncryptedWithNewNt);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Encrypt the new NT password */
|
|
|
|
Status = SystemFunction012((const BYTE *)&NewNtPassword,
|
|
|
|
(const BYTE *)&OldNtPassword,
|
|
|
|
(LPBYTE)&NewNtEncryptedWithOldNt);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
2014-01-26 10:43:58 +00:00
|
|
|
|
|
|
|
/* Change the password */
|
|
|
|
Status = SamrChangePasswordUser(UserHandle,
|
2014-02-10 20:08:29 +00:00
|
|
|
OldLmPasswordPresent && NewLmPasswordPresent,
|
|
|
|
pOldLmEncryptedWithNewLm,
|
|
|
|
pNewLmEncryptedWithOldLm,
|
|
|
|
TRUE,
|
|
|
|
&OldNtEncryptedWithNewNt,
|
|
|
|
&NewNtEncryptedWithOldNt,
|
|
|
|
FALSE,
|
|
|
|
NULL,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
2014-01-26 10:43:58 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (UserHandle != NULL)
|
|
|
|
SamrCloseHandle(&UserHandle);
|
|
|
|
|
|
|
|
SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
|
|
|
|
SamIFree_SAMPR_ULONG_ARRAY(&Use);
|
|
|
|
|
|
|
|
if (DomainHandle != NULL)
|
|
|
|
SamrCloseHandle(&DomainHandle);
|
|
|
|
|
|
|
|
if (DomainSid != NULL)
|
|
|
|
SamIFreeVoid(DomainSid);
|
|
|
|
|
|
|
|
if (ServerHandle != NULL)
|
|
|
|
SamrCloseHandle(&ServerHandle);
|
|
|
|
|
|
|
|
return Status;
|
2013-07-01 18:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-05 15:27:26 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
MsvpCheckPassword(PUNICODE_STRING UserPassword,
|
|
|
|
PSAMPR_USER_INFO_BUFFER UserInfo)
|
|
|
|
{
|
|
|
|
ENCRYPTED_NT_OWF_PASSWORD UserNtPassword;
|
|
|
|
ENCRYPTED_LM_OWF_PASSWORD UserLmPassword;
|
|
|
|
BOOLEAN UserLmPasswordPresent = FALSE;
|
|
|
|
BOOLEAN UserNtPasswordPresent = FALSE;
|
|
|
|
OEM_STRING LmPwdString;
|
|
|
|
CHAR LmPwdBuffer[15];
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
TRACE("(%p %p)\n", UserPassword, UserInfo);
|
|
|
|
|
|
|
|
/* Calculate the LM password and hash for the users password */
|
|
|
|
LmPwdString.Length = 15;
|
|
|
|
LmPwdString.MaximumLength = 15;
|
|
|
|
LmPwdString.Buffer = LmPwdBuffer;
|
|
|
|
ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
|
|
|
|
|
|
|
|
Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
|
|
|
|
UserPassword,
|
|
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Calculate the LM hash value of the users password */
|
|
|
|
Status = SystemFunction006(LmPwdString.Buffer,
|
|
|
|
(LPSTR)&UserLmPassword);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
UserLmPasswordPresent = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the NT hash of the users password */
|
|
|
|
Status = SystemFunction007(UserPassword,
|
|
|
|
(LPBYTE)&UserNtPassword);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
UserNtPasswordPresent = TRUE;
|
|
|
|
}
|
|
|
|
|
2013-10-13 20:15:01 +00:00
|
|
|
Status = STATUS_WRONG_PASSWORD;
|
2013-10-05 15:27:26 +00:00
|
|
|
|
2013-10-13 20:15:01 +00:00
|
|
|
/* Succeed, if no password has been set */
|
|
|
|
if (UserInfo->All.NtPasswordPresent == FALSE &&
|
|
|
|
UserInfo->All.LmPasswordPresent == FALSE)
|
|
|
|
{
|
|
|
|
TRACE("No password check!\n");
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Succeed, if NT password matches */
|
2013-10-05 15:27:26 +00:00
|
|
|
if (UserNtPasswordPresent && UserInfo->All.NtPasswordPresent)
|
|
|
|
{
|
|
|
|
TRACE("Check NT password hashes:\n");
|
2013-10-13 20:15:01 +00:00
|
|
|
if (RtlEqualMemory(&UserNtPassword,
|
|
|
|
UserInfo->All.NtOwfPassword.Buffer,
|
|
|
|
sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
|
2013-10-05 15:27:26 +00:00
|
|
|
{
|
2013-10-13 20:15:01 +00:00
|
|
|
TRACE(" success!\n");
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto done;
|
2013-10-05 15:27:26 +00:00
|
|
|
}
|
2013-10-13 20:15:01 +00:00
|
|
|
|
|
|
|
TRACE(" failed!\n");
|
2013-10-05 15:27:26 +00:00
|
|
|
}
|
2013-10-13 20:15:01 +00:00
|
|
|
|
|
|
|
/* Succeed, if LM password matches */
|
|
|
|
if (UserLmPasswordPresent && UserInfo->All.LmPasswordPresent)
|
2013-10-05 15:27:26 +00:00
|
|
|
{
|
|
|
|
TRACE("Check LM password hashes:\n");
|
2013-10-13 20:15:01 +00:00
|
|
|
if (RtlEqualMemory(&UserLmPassword,
|
|
|
|
UserInfo->All.LmOwfPassword.Buffer,
|
|
|
|
sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
|
2013-10-05 15:27:26 +00:00
|
|
|
{
|
2013-10-13 20:15:01 +00:00
|
|
|
TRACE(" success!\n");
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto done;
|
2013-10-05 15:27:26 +00:00
|
|
|
}
|
2013-10-13 20:15:01 +00:00
|
|
|
TRACE(" failed!\n");
|
2013-10-05 15:27:26 +00:00
|
|
|
}
|
|
|
|
|
2013-10-13 20:15:01 +00:00
|
|
|
done:
|
2013-10-05 15:27:26 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
static
|
|
|
|
BOOL
|
|
|
|
MsvpCheckLogonHours(
|
|
|
|
_In_ PSAMPR_LOGON_HOURS LogonHours,
|
|
|
|
_In_ PLARGE_INTEGER LogonTime)
|
|
|
|
{
|
2019-07-28 22:10:26 +00:00
|
|
|
#if 0
|
2019-03-04 16:25:11 +00:00
|
|
|
LARGE_INTEGER LocalLogonTime;
|
|
|
|
TIME_FIELDS TimeFields;
|
|
|
|
USHORT MinutesPerUnit, Offset;
|
2019-07-28 22:10:26 +00:00
|
|
|
BOOL bFound;
|
2019-03-04 16:25:11 +00:00
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
FIXME("MsvpCheckLogonHours(%p %p)\n", LogonHours, LogonTime);
|
2019-03-04 16:25:11 +00:00
|
|
|
|
|
|
|
if (LogonHours->UnitsPerWeek == 0 || LogonHours->LogonHours == NULL)
|
2019-07-28 22:10:26 +00:00
|
|
|
{
|
|
|
|
FIXME("No logon hours!\n");
|
2019-03-04 16:25:11 +00:00
|
|
|
return TRUE;
|
2019-07-28 22:10:26 +00:00
|
|
|
}
|
2019-03-04 16:25:11 +00:00
|
|
|
|
|
|
|
RtlSystemTimeToLocalTime(LogonTime, &LocalLogonTime);
|
|
|
|
RtlTimeToTimeFields(&LocalLogonTime, &TimeFields);
|
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
FIXME("UnitsPerWeek: %u\n", LogonHours->UnitsPerWeek);
|
2019-03-04 16:25:11 +00:00
|
|
|
MinutesPerUnit = 10080 / LogonHours->UnitsPerWeek;
|
|
|
|
|
|
|
|
Offset = ((TimeFields.Weekday * 24 + TimeFields.Hour) * 60 + TimeFields.Minute) / MinutesPerUnit;
|
2019-07-28 22:10:26 +00:00
|
|
|
FIXME("Offset: %us\n", Offset);
|
2019-03-04 16:25:11 +00:00
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
bFound = (BOOL)(LogonHours->LogonHours[Offset / 8] & (1 << (Offset % 8)));
|
|
|
|
FIXME("Logon permitted: %s\n", bFound ? "Yes" : "No");
|
|
|
|
|
|
|
|
return bFound;
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
2019-03-04 16:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
BOOL
|
|
|
|
MsvpCheckWorkstations(
|
|
|
|
_In_ PRPC_UNICODE_STRING WorkStations,
|
|
|
|
_In_ PWSTR ComputerName)
|
|
|
|
{
|
|
|
|
PWSTR pStart, pEnd;
|
|
|
|
BOOL bFound = FALSE;
|
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
TRACE("MsvpCheckWorkstations(%p %S)\n", WorkStations, ComputerName);
|
2019-03-04 16:25:11 +00:00
|
|
|
|
|
|
|
if (WorkStations->Length == 0 || WorkStations->Buffer == NULL)
|
2019-07-28 22:10:26 +00:00
|
|
|
{
|
|
|
|
TRACE("No workstations!\n");
|
2019-03-04 16:25:11 +00:00
|
|
|
return TRUE;
|
2019-07-28 22:10:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Workstations: %wZ\n", WorkStations);
|
2019-03-04 16:25:11 +00:00
|
|
|
|
|
|
|
pStart = WorkStations->Buffer;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
pEnd = wcschr(pStart, L',');
|
|
|
|
if (pEnd != NULL)
|
|
|
|
*pEnd = UNICODE_NULL;
|
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
TRACE("Comparing '%S' and '%S'\n", ComputerName, pStart);
|
2019-03-04 16:25:11 +00:00
|
|
|
if (_wcsicmp(ComputerName, pStart) == 0)
|
|
|
|
{
|
|
|
|
bFound = TRUE;
|
|
|
|
if (pEnd != NULL)
|
|
|
|
*pEnd = L',';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pEnd == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
*pEnd = L',';
|
|
|
|
pStart = pEnd + 1;
|
|
|
|
}
|
|
|
|
|
2019-07-28 22:10:26 +00:00
|
|
|
TRACE("Found allowed workstation: %s\n", (bFound) ? "Yes" : "No");
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
return bFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-03 19:11:22 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
2013-07-01 18:43:36 +00:00
|
|
|
NTSTATUS Status;
|
2019-06-18 00:27:08 +00:00
|
|
|
MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
|
2013-07-01 18:43:36 +00:00
|
|
|
|
2019-03-04 00:31:20 +00:00
|
|
|
TRACE("LsaApCallPackage()\n");
|
2013-07-01 18:43:36 +00:00
|
|
|
|
|
|
|
if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
MessageType = *((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
|
2013-07-01 18:43:36 +00:00
|
|
|
|
|
|
|
*ProtocolReturnBuffer = NULL;
|
|
|
|
*ReturnBufferLength = 0;
|
|
|
|
|
|
|
|
switch (MessageType)
|
|
|
|
{
|
|
|
|
case MsV1_0Lm20ChallengeRequest:
|
|
|
|
case MsV1_0Lm20GetChallengeResponse:
|
2019-07-28 12:57:46 +00:00
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
|
2013-07-01 18:43:36 +00:00
|
|
|
case MsV1_0EnumerateUsers:
|
|
|
|
case MsV1_0GetUserInfo:
|
|
|
|
case MsV1_0ReLogonUsers:
|
2019-07-28 12:57:46 +00:00
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
2013-07-01 18:43:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MsV1_0ChangePassword:
|
2013-10-13 20:15:01 +00:00
|
|
|
Status = MsvpChangePassword(ClientRequest,
|
|
|
|
ProtocolSubmitBuffer,
|
|
|
|
ClientBufferBase,
|
|
|
|
SubmitBufferLength,
|
|
|
|
ProtocolReturnBuffer,
|
|
|
|
ReturnBufferLength,
|
|
|
|
ProtocolStatus);
|
2013-07-01 18:43:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MsV1_0ChangeCachedPassword:
|
|
|
|
case MsV1_0GenericPassthrough:
|
|
|
|
case MsV1_0CacheLogon:
|
|
|
|
case MsV1_0SubAuth:
|
|
|
|
case MsV1_0DeriveCredential:
|
|
|
|
case MsV1_0CacheLookup:
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
2013-03-03 19:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
2019-03-04 00:31:20 +00:00
|
|
|
TRACE("LsaApCallPackagePassthrough()\n");
|
2013-03-03 19:11:22 +00:00
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-09-17 10:46:49 +00:00
|
|
|
* @implemented
|
2013-03-03 19:11:22 +00:00
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
2019-09-17 10:46:49 +00:00
|
|
|
ULONG MessageType;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
2019-03-04 00:31:20 +00:00
|
|
|
TRACE("LsaApCallPackageUntrusted()\n");
|
2019-09-17 10:46:49 +00:00
|
|
|
|
|
|
|
if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
|
|
|
|
|
|
|
|
*ProtocolReturnBuffer = NULL;
|
|
|
|
*ReturnBufferLength = 0;
|
|
|
|
|
|
|
|
if (MessageType == MsV1_0ChangePassword)
|
|
|
|
Status = MsvpChangePassword(ClientRequest,
|
|
|
|
ProtocolSubmitBuffer,
|
|
|
|
ClientBufferBase,
|
|
|
|
SubmitBufferLength,
|
|
|
|
ProtocolReturnBuffer,
|
|
|
|
ReturnBufferLength,
|
|
|
|
ProtocolStatus);
|
|
|
|
else
|
|
|
|
Status = STATUS_ACCESS_DENIED;
|
|
|
|
|
|
|
|
return Status;
|
2013-03-03 19:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-03-04 16:25:11 +00:00
|
|
|
* @implemented
|
2013-03-03 19:11:22 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
LsaApInitializePackage(IN ULONG AuthenticationPackageId,
|
|
|
|
IN PLSA_DISPATCH_TABLE LsaDispatchTable,
|
|
|
|
IN PLSA_STRING Database OPTIONAL,
|
|
|
|
IN PLSA_STRING Confidentiality OPTIONAL,
|
|
|
|
OUT PLSA_STRING *AuthenticationPackageName)
|
|
|
|
{
|
2013-03-04 21:32:44 +00:00
|
|
|
PANSI_STRING NameString;
|
|
|
|
PCHAR NameBuffer;
|
|
|
|
|
2019-03-04 00:31:20 +00:00
|
|
|
TRACE("LsaApInitializePackage(%lu %p %p %p %p)\n",
|
2013-03-03 19:11:22 +00:00
|
|
|
AuthenticationPackageId, LsaDispatchTable, Database,
|
|
|
|
Confidentiality, AuthenticationPackageName);
|
|
|
|
|
2013-03-04 21:32:44 +00:00
|
|
|
/* Get the dispatch table entries */
|
2013-10-03 15:41:02 +00:00
|
|
|
DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession;
|
|
|
|
DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession;
|
|
|
|
DispatchTable.AddCredential = LsaDispatchTable->AddCredential;
|
|
|
|
DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials;
|
|
|
|
DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential;
|
2013-03-04 21:32:44 +00:00
|
|
|
DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap;
|
|
|
|
DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap;
|
2013-03-17 13:55:51 +00:00
|
|
|
DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer;
|
|
|
|
DispatchTable.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer;
|
|
|
|
DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer;
|
|
|
|
DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer;
|
2013-03-04 21:32:44 +00:00
|
|
|
|
|
|
|
/* Return the package name */
|
|
|
|
NameString = DispatchTable.AllocateLsaHeap(sizeof(LSA_STRING));
|
|
|
|
if (NameString == NULL)
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
|
|
NameBuffer = DispatchTable.AllocateLsaHeap(sizeof(MSV1_0_PACKAGE_NAME));
|
|
|
|
if (NameBuffer == NULL)
|
|
|
|
{
|
|
|
|
DispatchTable.FreeLsaHeap(NameString);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(NameBuffer, MSV1_0_PACKAGE_NAME);
|
|
|
|
|
|
|
|
RtlInitAnsiString(NameString, NameBuffer);
|
|
|
|
|
|
|
|
*AuthenticationPackageName = (PLSA_STRING)NameString;
|
2013-03-03 19:11:22 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
LsaApLogonTerminated(IN PLUID LogonId)
|
|
|
|
{
|
2019-03-04 00:31:20 +00:00
|
|
|
TRACE("LsaApLogonTerminated()\n");
|
2013-03-03 19:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-03-04 16:25:11 +00:00
|
|
|
* @implemented
|
2013-03-03 19:11:22 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2019-03-04 09:20:10 +00:00
|
|
|
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,
|
2019-03-04 16:25:11 +00:00
|
|
|
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
|
|
|
|
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */
|
2013-03-03 19:11:22 +00:00
|
|
|
{
|
2019-06-18 00:27:08 +00:00
|
|
|
static const UNICODE_STRING NtAuthorityU = RTL_CONSTANT_STRING(L"NT AUTHORITY");
|
|
|
|
static const UNICODE_STRING LocalServiceU = RTL_CONSTANT_STRING(L"LocalService");
|
|
|
|
static const UNICODE_STRING NetworkServiceU = RTL_CONSTANT_STRING(L"NetworkService");
|
|
|
|
|
|
|
|
NTSTATUS Status;
|
2013-03-17 13:55:51 +00:00
|
|
|
PMSV1_0_INTERACTIVE_LOGON LogonInfo;
|
2019-03-04 16:25:11 +00:00
|
|
|
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
2013-03-17 13:55:51 +00:00
|
|
|
SAMPR_HANDLE ServerHandle = NULL;
|
|
|
|
SAMPR_HANDLE DomainHandle = NULL;
|
2013-04-13 21:50:54 +00:00
|
|
|
SAMPR_HANDLE UserHandle = NULL;
|
2013-03-17 13:55:51 +00:00
|
|
|
PRPC_SID AccountDomainSid = NULL;
|
|
|
|
RPC_UNICODE_STRING Names[1];
|
|
|
|
SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
|
|
|
|
SAMPR_ULONG_ARRAY Use = {0, NULL};
|
2013-04-13 21:50:54 +00:00
|
|
|
PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
|
2013-10-03 15:41:02 +00:00
|
|
|
BOOLEAN SessionCreated = FALSE;
|
2014-03-16 19:54:33 +00:00
|
|
|
LARGE_INTEGER LogonTime;
|
2018-09-04 21:15:15 +00:00
|
|
|
LARGE_INTEGER AccountExpires;
|
2014-03-16 19:54:33 +00:00
|
|
|
LARGE_INTEGER PasswordMustChange;
|
|
|
|
LARGE_INTEGER PasswordLastSet;
|
2019-03-04 16:25:11 +00:00
|
|
|
DWORD ComputerNameSize;
|
2018-05-26 16:42:31 +00:00
|
|
|
BOOL SpecialAccount = FALSE;
|
2020-02-16 10:05:25 +00:00
|
|
|
UCHAR LogonPassHash;
|
|
|
|
PUNICODE_STRING ErasePassword = NULL;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
TRACE("LsaApLogonUserEx2()\n");
|
2013-03-17 13:55:51 +00:00
|
|
|
|
|
|
|
TRACE("LogonType: %lu\n", LogonType);
|
2019-03-04 09:20:10 +00:00
|
|
|
TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
|
|
|
|
TRACE("SubmitBufferSize: %lu\n", SubmitBufferSize);
|
2013-03-17 13:55:51 +00:00
|
|
|
|
|
|
|
*ProfileBuffer = NULL;
|
2019-03-04 09:20:10 +00:00
|
|
|
*ProfileBufferSize = 0;
|
2013-03-17 13:55:51 +00:00
|
|
|
*SubStatus = STATUS_SUCCESS;
|
2019-03-04 00:31:20 +00:00
|
|
|
*AccountName = NULL;
|
|
|
|
*AuthenticatingAuthority = NULL;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
/* Parameters validation */
|
2013-03-17 13:55:51 +00:00
|
|
|
if (LogonType == Interactive ||
|
|
|
|
LogonType == Batch ||
|
|
|
|
LogonType == Service)
|
|
|
|
{
|
|
|
|
ULONG_PTR PtrOffset;
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
if (SubmitBufferSize < sizeof(MSV1_0_INTERACTIVE_LOGON))
|
|
|
|
{
|
|
|
|
ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2019-03-04 09:20:10 +00:00
|
|
|
LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)ProtocolSubmitBuffer;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
if (LogonInfo->MessageType != MsV1_0InteractiveLogon &&
|
|
|
|
LogonInfo->MessageType != MsV1_0WorkstationUnlockLogon)
|
|
|
|
{
|
|
|
|
ERR("Invalid MessageType %lu\n", LogonInfo->MessageType);
|
|
|
|
return STATUS_BAD_VALIDATION_CLASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 // FIXME: These checks happen to be done on Windows. We however keep them general on ReactOS for now...
|
|
|
|
if (LogonInfo->UserName.Length > 512) // CRED_MAX_STRING_LENGTH * sizeof(WCHAR) or (CREDUI_MAX_USERNAME_LENGTH (== CRED_MAX_USERNAME_LENGTH) - 1) * sizeof(WCHAR)
|
|
|
|
{
|
|
|
|
ERR("UserName too long (%lu, maximum 512)\n", LogonInfo->UserName.Length);
|
|
|
|
return STATUS_NAME_TOO_LONG;
|
|
|
|
}
|
|
|
|
if (LogonInfo->Password.Length > 512) // CREDUI_MAX_PASSWORD_LENGTH * sizeof(WCHAR)
|
|
|
|
{
|
|
|
|
ERR("Password too long (%lu, maximum 512)\n", LogonInfo->Password.Length);
|
|
|
|
return STATUS_NAME_TOO_LONG;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-17 13:55:51 +00:00
|
|
|
/* Fix-up pointers in the authentication info */
|
2019-03-04 09:20:10 +00:00
|
|
|
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
/* LogonDomainName is optional and can be an empty string */
|
|
|
|
if (LogonInfo->LogonDomainName.Length)
|
|
|
|
{
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
|
|
|
LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
|
|
|
|
LogonInfo->LogonDomainName.MaximumLength = LogonInfo->LogonDomainName.Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogonInfo->LogonDomainName.Buffer = NULL;
|
|
|
|
LogonInfo->LogonDomainName.MaximumLength = 0;
|
|
|
|
}
|
2020-02-16 15:55:31 +00:00
|
|
|
Status = RtlValidateUnicodeString(0, &LogonInfo->LogonDomainName);
|
2019-06-18 00:27:08 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
2020-02-16 15:55:31 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
/* UserName is mandatory and cannot be an empty string */
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
2013-10-03 15:41:02 +00:00
|
|
|
LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
|
2019-06-18 00:27:08 +00:00
|
|
|
LogonInfo->UserName.MaximumLength = LogonInfo->UserName.Length;
|
|
|
|
|
2020-02-16 15:55:31 +00:00
|
|
|
Status = RtlValidateUnicodeString(0, &LogonInfo->UserName);
|
2019-06-18 00:27:08 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
2020-02-16 10:05:25 +00:00
|
|
|
|
|
|
|
/* MS docs says max length is 0xFF bytes. But thats not the full story:
|
|
|
|
*
|
|
|
|
* A Quote from https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.kernel/eFGcCo_ZObk:
|
|
|
|
* "... At least on my WinXP SP2. Domain and UserName are passed
|
|
|
|
* in clear text, but the Password is NOT. ..."
|
|
|
|
*
|
|
|
|
* If the higher byte of length != 0 we have to use RtlRunDecodeUnicodeString.
|
|
|
|
*/
|
|
|
|
LogonPassHash = (LogonInfo->Password.Length >> 8) & 0xFF;
|
|
|
|
LogonInfo->Password.Length = LogonInfo->Password.Length & 0xFF;
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
/* Password is optional and can be an empty string */
|
|
|
|
if (LogonInfo->Password.Length)
|
|
|
|
{
|
|
|
|
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
|
|
|
|
LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);
|
|
|
|
LogonInfo->Password.MaximumLength = LogonInfo->Password.Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogonInfo->Password.Buffer = NULL;
|
|
|
|
LogonInfo->Password.MaximumLength = 0;
|
|
|
|
}
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2020-02-16 10:05:25 +00:00
|
|
|
/* Decode password */
|
|
|
|
if (LogonPassHash > 0)
|
|
|
|
{
|
|
|
|
RtlRunDecodeUnicodeString(LogonPassHash, &LogonInfo->Password);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ErasePassword will be "erased" before we return */
|
|
|
|
ErasePassword = &LogonInfo->Password;
|
|
|
|
|
2020-02-16 15:55:31 +00:00
|
|
|
Status = RtlValidateUnicodeString(0, &LogonInfo->Password);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
TRACE("Domain: %wZ\n", &LogonInfo->LogonDomainName);
|
|
|
|
TRACE("User: %wZ\n", &LogonInfo->UserName);
|
|
|
|
TRACE("Password: %wZ\n", &LogonInfo->Password);
|
2019-06-18 00:27:08 +00:00
|
|
|
|
|
|
|
// TODO: If LogonType == Service, do some extra work using LogonInfo->Password.
|
2013-03-17 13:55:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("LogonType %lu is not supported yet!\n", LogonType);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
2019-06-18 00:27:08 +00:00
|
|
|
// TODO: Add other LogonType validity checks.
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2014-03-16 19:54:33 +00:00
|
|
|
/* Get the logon time */
|
|
|
|
NtQuerySystemTime(&LogonTime);
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
/* Get the computer name */
|
2019-06-18 00:27:08 +00:00
|
|
|
ComputerNameSize = ARRAYSIZE(ComputerName);
|
2019-03-04 16:25:11 +00:00
|
|
|
GetComputerNameW(ComputerName, &ComputerNameSize);
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Check for special accounts */
|
2019-06-18 00:27:08 +00:00
|
|
|
// FIXME: Windows does not do this that way!! (msv1_0 does not contain these hardcoded values)
|
|
|
|
if (RtlEqualUnicodeString(&LogonInfo->LogonDomainName, &NtAuthorityU, TRUE))
|
2013-03-17 13:55:51 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
SpecialAccount = TRUE;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Get the authority domain SID */
|
|
|
|
Status = GetNtAuthorityDomainSid(&AccountDomainSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
if (RtlEqualUnicodeString(&LogonInfo->UserName, &LocalServiceU, TRUE))
|
2018-05-26 16:42:31 +00:00
|
|
|
{
|
|
|
|
TRACE("SpecialAccount: LocalService\n");
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
if (LogonType != Service)
|
|
|
|
return STATUS_LOGON_FAILURE;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
HEAP_ZERO_MEMORY,
|
|
|
|
sizeof(SAMPR_USER_ALL_INFORMATION));
|
|
|
|
if (UserInfo == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
|
|
|
|
UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
|
|
|
|
}
|
2019-06-18 00:27:08 +00:00
|
|
|
else if (RtlEqualUnicodeString(&LogonInfo->UserName, &NetworkServiceU, TRUE))
|
2018-05-26 16:42:31 +00:00
|
|
|
{
|
|
|
|
TRACE("SpecialAccount: NetworkService\n");
|
2013-04-13 21:50:54 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
if (LogonType != Service)
|
|
|
|
return STATUS_LOGON_FAILURE;
|
2013-04-13 21:50:54 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
HEAP_ZERO_MEMORY,
|
|
|
|
sizeof(SAMPR_USER_ALL_INFORMATION));
|
|
|
|
if (UserInfo == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
2013-04-13 21:50:54 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID;
|
|
|
|
UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID;
|
|
|
|
}
|
|
|
|
else
|
2014-03-16 19:54:33 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
Status = STATUS_NO_SUCH_USER;
|
2014-03-16 19:54:33 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2018-05-26 16:42:31 +00:00
|
|
|
else
|
2014-03-01 17:12:21 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
TRACE("NormalAccount\n");
|
|
|
|
|
|
|
|
/* Get the account domain SID */
|
|
|
|
Status = GetAccountDomainSid(&AccountDomainSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2014-03-01 17:12:21 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Connect to the SAM server */
|
|
|
|
Status = SamIConnect(NULL,
|
|
|
|
&ServerHandle,
|
|
|
|
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
|
2014-03-01 17:12:21 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Open the account domain */
|
|
|
|
Status = SamrOpenDomain(ServerHandle,
|
|
|
|
DOMAIN_LOOKUP,
|
|
|
|
AccountDomainSid,
|
|
|
|
&DomainHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2014-03-01 17:12:21 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
ERR("SamrOpenDomain failed (Status %08lx)\n", Status);
|
2014-03-01 17:12:21 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
Names[0].Length = LogonInfo->UserName.Length;
|
|
|
|
Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
|
|
|
|
Names[0].Buffer = LogonInfo->UserName.Buffer;
|
2014-03-01 17:12:21 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Try to get the RID for the user name */
|
|
|
|
Status = SamrLookupNamesInDomain(DomainHandle,
|
|
|
|
1,
|
|
|
|
Names,
|
|
|
|
&RelativeIds,
|
|
|
|
&Use);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2014-03-16 19:54:33 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
|
|
|
|
Status = STATUS_NO_SUCH_USER;
|
2014-03-16 19:54:33 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2013-04-21 21:08:58 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Fail, if it is not a user account */
|
|
|
|
if (Use.Element[0] != SidTypeUser)
|
|
|
|
{
|
|
|
|
ERR("Account is not a user account!\n");
|
|
|
|
Status = STATUS_NO_SUCH_USER;
|
|
|
|
goto done;
|
|
|
|
}
|
2014-03-16 19:54:33 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
/* Open the user object */
|
|
|
|
Status = SamrOpenUser(DomainHandle,
|
|
|
|
USER_READ_GENERAL | USER_READ_LOGON |
|
|
|
|
USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
|
|
|
|
RelativeIds.Element[0],
|
|
|
|
&UserHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2013-10-05 15:27:26 +00:00
|
|
|
{
|
2018-05-26 16:42:31 +00:00
|
|
|
ERR("SamrOpenUser failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
2014-03-16 19:54:33 +00:00
|
|
|
|
2018-05-26 16:42:31 +00:00
|
|
|
Status = SamrQueryInformationUser(UserHandle,
|
|
|
|
UserAllInformation,
|
|
|
|
&UserInfo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status);
|
2013-10-05 15:27:26 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2014-03-16 19:54:33 +00:00
|
|
|
|
2020-02-16 15:55:31 +00:00
|
|
|
TRACE("UserName: %wZ\n", &UserInfo->All.UserName);
|
2018-05-26 16:42:31 +00:00
|
|
|
|
|
|
|
/* Check the password */
|
|
|
|
if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
|
|
|
|
{
|
2019-06-18 00:27:08 +00:00
|
|
|
Status = MsvpCheckPassword(&LogonInfo->Password,
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR("MsvpCheckPassword failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check account restrictions for non-administrator accounts */
|
|
|
|
if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
|
|
|
|
{
|
|
|
|
/* Check if the account has been disabled */
|
|
|
|
if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
|
|
|
|
{
|
|
|
|
ERR("Account disabled!\n");
|
|
|
|
*SubStatus = STATUS_ACCOUNT_DISABLED;
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the account has been locked */
|
|
|
|
if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
|
|
|
|
{
|
|
|
|
ERR("Account locked!\n");
|
|
|
|
*SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the account expired */
|
|
|
|
AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
|
|
|
|
AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;
|
2018-09-04 21:15:15 +00:00
|
|
|
if (LogonTime.QuadPart >= AccountExpires.QuadPart)
|
2018-05-26 16:42:31 +00:00
|
|
|
{
|
|
|
|
ERR("Account expired!\n");
|
|
|
|
*SubStatus = STATUS_ACCOUNT_EXPIRED;
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the password expired */
|
|
|
|
PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
|
|
|
|
PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
|
|
|
|
PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
|
|
|
|
PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;
|
|
|
|
|
|
|
|
if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
|
|
|
|
{
|
|
|
|
ERR("Password expired!\n");
|
|
|
|
if (PasswordLastSet.QuadPart == 0)
|
|
|
|
*SubStatus = STATUS_PASSWORD_MUST_CHANGE;
|
|
|
|
else
|
|
|
|
*SubStatus = STATUS_PASSWORD_EXPIRED;
|
|
|
|
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
/* Check logon hours */
|
|
|
|
if (!MsvpCheckLogonHours(&UserInfo->All.LogonHours, &LogonTime))
|
|
|
|
{
|
|
|
|
ERR("Invalid logon hours!\n");
|
|
|
|
*SubStatus = STATUS_INVALID_LOGON_HOURS;
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check workstations */
|
|
|
|
if (!MsvpCheckWorkstations(&UserInfo->All.WorkStations, ComputerName))
|
|
|
|
{
|
|
|
|
ERR("Invalid workstation!\n");
|
|
|
|
*SubStatus = STATUS_INVALID_WORKSTATION;
|
|
|
|
Status = STATUS_ACCOUNT_RESTRICTION;
|
|
|
|
goto done;
|
|
|
|
}
|
2018-05-26 16:42:31 +00:00
|
|
|
}
|
2013-04-21 21:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return logon information */
|
|
|
|
|
|
|
|
/* Create and return a new logon id */
|
|
|
|
Status = NtAllocateLocallyUniqueId(LogonId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2013-10-03 15:41:02 +00:00
|
|
|
/* Create the logon session */
|
|
|
|
Status = DispatchTable.CreateLogonSession(LogonId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("CreateLogonSession failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
SessionCreated = TRUE;
|
|
|
|
|
2016-11-12 21:53:33 +00:00
|
|
|
/* Build and fill the interactive profile buffer */
|
2013-04-21 21:08:58 +00:00
|
|
|
Status = BuildInteractiveProfileBuffer(ClientRequest,
|
|
|
|
UserInfo,
|
2019-03-04 16:25:11 +00:00
|
|
|
ComputerName,
|
2013-04-21 21:08:58 +00:00
|
|
|
(PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
|
2019-03-04 09:20:10 +00:00
|
|
|
ProfileBufferSize);
|
2013-04-21 21:08:58 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the token information type */
|
|
|
|
*TokenInformationType = LsaTokenInformationV1;
|
2013-03-17 13:55:51 +00:00
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
/* Build and fill the token information buffer */
|
|
|
|
Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
|
|
|
|
AccountDomainSid,
|
2018-05-26 16:42:31 +00:00
|
|
|
UserInfo,
|
|
|
|
SpecialAccount);
|
2013-05-05 00:53:25 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2013-03-17 13:55:51 +00:00
|
|
|
done:
|
2020-02-16 10:05:25 +00:00
|
|
|
/* Erase password */
|
|
|
|
if (ErasePassword)
|
|
|
|
{
|
|
|
|
RtlEraseUnicodeString(ErasePassword);
|
|
|
|
}
|
|
|
|
|
2018-09-04 22:10:54 +00:00
|
|
|
/* Update the logon time/count or the bad password time/count */
|
|
|
|
if ((UserHandle != NULL) &&
|
|
|
|
(Status == STATUS_SUCCESS || Status == STATUS_WRONG_PASSWORD))
|
|
|
|
{
|
|
|
|
SAMPR_USER_INFO_BUFFER InternalInfo;
|
|
|
|
|
|
|
|
RtlZeroMemory(&InternalInfo, sizeof(InternalInfo));
|
|
|
|
|
|
|
|
if (Status == STATUS_SUCCESS)
|
|
|
|
InternalInfo.Internal2.Flags = USER_LOGON_SUCCESS;
|
|
|
|
else
|
|
|
|
InternalInfo.Internal2.Flags = USER_LOGON_BAD_PASSWORD;
|
|
|
|
|
|
|
|
SamrSetInformationUser(UserHandle,
|
|
|
|
UserInternal2Information,
|
|
|
|
&InternalInfo);
|
|
|
|
}
|
|
|
|
|
2013-05-05 00:53:25 +00:00
|
|
|
/* Return the account name */
|
|
|
|
*AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
|
|
|
|
if (*AccountName != NULL)
|
|
|
|
{
|
|
|
|
(*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length +
|
|
|
|
sizeof(UNICODE_NULL));
|
|
|
|
if ((*AccountName)->Buffer != NULL)
|
|
|
|
{
|
|
|
|
(*AccountName)->MaximumLength = LogonInfo->UserName.Length +
|
|
|
|
sizeof(UNICODE_NULL);
|
|
|
|
RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 00:31:20 +00:00
|
|
|
/* Return the authenticating authority */
|
|
|
|
*AuthenticatingAuthority = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
|
|
|
|
if (*AuthenticatingAuthority != NULL)
|
|
|
|
{
|
|
|
|
(*AuthenticatingAuthority)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->LogonDomainName.Length +
|
|
|
|
sizeof(UNICODE_NULL));
|
|
|
|
if ((*AuthenticatingAuthority)->Buffer != NULL)
|
|
|
|
{
|
|
|
|
(*AuthenticatingAuthority)->MaximumLength = LogonInfo->LogonDomainName.Length +
|
|
|
|
sizeof(UNICODE_NULL);
|
|
|
|
RtlCopyUnicodeString(*AuthenticatingAuthority, &LogonInfo->LogonDomainName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 16:25:11 +00:00
|
|
|
/* Return the machine name */
|
|
|
|
*MachineName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
|
|
|
|
if (*MachineName != NULL)
|
|
|
|
{
|
|
|
|
(*MachineName)->Buffer = DispatchTable.AllocateLsaHeap((ComputerNameSize + 1) * sizeof(WCHAR));
|
|
|
|
if ((*MachineName)->Buffer != NULL)
|
|
|
|
{
|
|
|
|
(*MachineName)->MaximumLength = (ComputerNameSize + 1) * sizeof(WCHAR);
|
|
|
|
(*MachineName)->Length = ComputerNameSize * sizeof(WCHAR);
|
|
|
|
RtlCopyMemory((*MachineName)->Buffer, ComputerName, (*MachineName)->MaximumLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:08:58 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2017-10-01 14:42:04 +00:00
|
|
|
if (SessionCreated != FALSE)
|
2013-10-03 15:41:02 +00:00
|
|
|
DispatchTable.DeleteLogonSession(LogonId);
|
|
|
|
|
2013-04-21 21:08:58 +00:00
|
|
|
if (*ProfileBuffer != NULL)
|
|
|
|
{
|
|
|
|
DispatchTable.FreeClientBuffer(ClientRequest,
|
|
|
|
*ProfileBuffer);
|
|
|
|
*ProfileBuffer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-13 21:50:54 +00:00
|
|
|
if (UserHandle != NULL)
|
|
|
|
SamrCloseHandle(&UserHandle);
|
|
|
|
|
|
|
|
SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo,
|
|
|
|
UserAllInformation);
|
2013-03-17 13:55:51 +00:00
|
|
|
SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
|
|
|
|
SamIFree_SAMPR_ULONG_ARRAY(&Use);
|
|
|
|
|
|
|
|
if (DomainHandle != NULL)
|
|
|
|
SamrCloseHandle(&DomainHandle);
|
|
|
|
|
|
|
|
if (ServerHandle != NULL)
|
|
|
|
SamrCloseHandle(&ServerHandle);
|
|
|
|
|
|
|
|
if (AccountDomainSid != NULL)
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
|
|
|
|
|
2013-10-05 15:27:26 +00:00
|
|
|
if (Status == STATUS_NO_SUCH_USER ||
|
|
|
|
Status == STATUS_WRONG_PASSWORD)
|
|
|
|
{
|
|
|
|
*SubStatus = Status;
|
|
|
|
Status = STATUS_LOGON_FAILURE;
|
|
|
|
}
|
|
|
|
|
2019-06-18 00:27:08 +00:00
|
|
|
TRACE("LsaApLogonUserEx2 done (Status 0x%08lx, SubStatus 0x%08lx)\n", Status, *SubStatus);
|
2013-03-17 13:55:51 +00:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2019-08-18 12:54:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SpLsaModeInitialize(
|
|
|
|
_In_ ULONG LsaVersion,
|
|
|
|
_Out_ PULONG PackageVersion,
|
|
|
|
_Out_ PSECPKG_FUNCTION_TABLE *ppTables,
|
|
|
|
_Out_ PULONG pcTables)
|
|
|
|
{
|
|
|
|
TRACE("SpLsaModeInitialize(0x%lx %p %p %p)\n",
|
|
|
|
LsaVersion, PackageVersion, ppTables, pcTables);
|
|
|
|
|
|
|
|
if (LsaVersion != SECPKG_INTERFACE_VERSION)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
*PackageVersion = SECPKG_INTERFACE_VERSION;
|
|
|
|
|
2020-04-11 21:32:04 +00:00
|
|
|
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;
|
2019-08-18 12:54:12 +00:00
|
|
|
*pcTables = 1;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
WINAPI
|
|
|
|
SpUserModeInitialize(
|
|
|
|
_In_ ULONG LsaVersion,
|
|
|
|
_Out_ PULONG PackageVersion,
|
|
|
|
_Out_ PSECPKG_USER_FUNCTION_TABLE *ppTables,
|
|
|
|
_Out_ PULONG pcTables)
|
|
|
|
{
|
|
|
|
SECPKG_USER_FUNCTION_TABLE Tables[1];
|
|
|
|
|
|
|
|
TRACE("SpUserModeInitialize(0x%lx %p %p %p)\n",
|
|
|
|
LsaVersion, PackageVersion, ppTables, pcTables);
|
|
|
|
|
|
|
|
if (LsaVersion != SECPKG_INTERFACE_VERSION)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
*PackageVersion = SECPKG_INTERFACE_VERSION;
|
|
|
|
|
|
|
|
RtlZeroMemory(&Tables, sizeof(Tables));
|
|
|
|
|
|
|
|
// Tables[0].InstanceInit = SpInstanceInit;
|
|
|
|
// Tables[0].InitUserModeContext = NULL;
|
|
|
|
// Tables[0].MakeSignature = NULL;
|
|
|
|
// Tables[0].VerifySignature = NULL;
|
|
|
|
// Tables[0].SealMessage = NULL;
|
|
|
|
// Tables[0].UnsealMessage = NULL;
|
|
|
|
// Tables[0].GetContextToken = NULL;
|
|
|
|
// Tables[0].SpQueryContextAttributes = NULL;
|
|
|
|
// Tables[0].CompleteAuthToken = NULL;
|
|
|
|
// Tables[0].DeleteUserModeContext = NULL;
|
|
|
|
// Tables[0].FormatCredentials = NULL;
|
|
|
|
// Tables[0].MarshallSupplementalCreds = NULL;
|
|
|
|
// Tables[0].ExportContext = NULL;
|
|
|
|
// Tables[0].ImportContext = NULL;
|
|
|
|
|
|
|
|
*ppTables = Tables;
|
|
|
|
*pcTables = 1;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-03-03 19:11:22 +00:00
|
|
|
/* EOF */
|