[MSV1_0] Extend parameter validation in LsaApLogonUserEx2() and MsvpChangePassword(); fix crash in LsaApLogonUserEx2() when LogonDomainName points to a NULL string.

This commit is contained in:
Hermès Bélusca-Maïto 2019-06-18 02:27:08 +02:00
parent 127fa1afc6
commit 8210396cb4
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0

View file

@ -496,6 +496,7 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
OUT PULONG ReturnBufferLength,
OUT PNTSTATUS ProtocolStatus)
{
NTSTATUS Status;
PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
ULONG_PTR PtrOffset;
@ -506,7 +507,6 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
RPC_UNICODE_STRING Names[1];
SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
SAMPR_ULONG_ARRAY Use = {0, NULL};
NTSTATUS Status;
ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
@ -524,17 +524,48 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL;
PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL;
TRACE("()\n");
TRACE("MsvpChangePassword()\n");
/* Parameters validation */
if (SubmitBufferLength < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST))
{
ERR("Invalid SubmitBufferLength %lu\n", SubmitBufferLength);
return STATUS_INVALID_PARAMETER;
}
RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
/* Fix-up pointers in the request buffer info */
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
Status = RtlValidateUnicodeString(0, &RequestBuffer->DomainName);
if (!NT_SUCCESS(Status))
return STATUS_INVALID_PARAMETER;
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
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.
RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
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.
RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
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.
RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length;
TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
@ -942,15 +973,15 @@ LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest,
OUT PULONG ReturnBufferLength,
OUT PNTSTATUS ProtocolStatus)
{
ULONG MessageType;
NTSTATUS Status;
MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
TRACE("LsaApCallPackage()\n");
if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
return STATUS_INVALID_PARAMETER;
MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
MessageType = *((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
*ProtocolReturnBuffer = NULL;
*ReturnBufferLength = 0;
@ -1140,6 +1171,11 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */
{
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;
PMSV1_0_INTERACTIVE_LOGON LogonInfo;
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
SAMPR_HANDLE ServerHandle = NULL;
@ -1157,9 +1193,8 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
LARGE_INTEGER PasswordLastSet;
DWORD ComputerNameSize;
BOOL SpecialAccount = FALSE;
NTSTATUS Status;
TRACE("LsaApLogonUser()\n");
TRACE("LsaApLogonUserEx2()\n");
TRACE("LogonType: %lu\n", LogonType);
TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
@ -1171,40 +1206,107 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
*AccountName = NULL;
*AuthenticatingAuthority = NULL;
/* Parameters validation */
if (LogonType == Interactive ||
LogonType == Batch ||
LogonType == Service)
{
ULONG_PTR PtrOffset;
if (SubmitBufferSize < sizeof(MSV1_0_INTERACTIVE_LOGON))
{
ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize);
return STATUS_INVALID_PARAMETER;
}
LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)ProtocolSubmitBuffer;
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
/* Fix-up pointers in the authentication info */
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
Status = RtlValidateUnicodeString(0, &LogonInfo->LogonDomainName);
if (!NT_SUCCESS(Status))
return STATUS_INVALID_PARAMETER;
/* 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;
}
Status = RtlValidateUnicodeString(0, &LogonInfo->UserName);
if (!NT_SUCCESS(Status))
return STATUS_INVALID_PARAMETER;
/* UserName is mandatory and cannot be an empty string */
// TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);
LogonInfo->UserName.MaximumLength = LogonInfo->UserName.Length;
Status = RtlValidateUnicodeString(0, &LogonInfo->Password);
if (!NT_SUCCESS(Status))
return STATUS_INVALID_PARAMETER;
/* 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;
}
TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
TRACE("User: %S\n", LogonInfo->UserName.Buffer);
TRACE("Password: %S\n", LogonInfo->Password.Buffer);
// TODO: If LogonType == Service, do some extra work using LogonInfo->Password.
}
else
{
FIXME("LogonType %lu is not supported yet!\n", LogonType);
return STATUS_NOT_IMPLEMENTED;
}
// TODO: Add other LogonType validity checks.
/* Get the logon time */
NtQuerySystemTime(&LogonTime);
/* Get the computer name */
ComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
ComputerNameSize = ARRAYSIZE(ComputerName);
GetComputerNameW(ComputerName, &ComputerNameSize);
/* Check for special accounts */
if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0)
// FIXME: Windows does not do this that way!! (msv1_0 does not contain these hardcoded values)
if (RtlEqualUnicodeString(&LogonInfo->LogonDomainName, &NtAuthorityU, TRUE))
{
SpecialAccount = TRUE;
@ -1216,7 +1318,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
return Status;
}
if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0)
if (RtlEqualUnicodeString(&LogonInfo->UserName, &LocalServiceU, TRUE))
{
TRACE("SpecialAccount: LocalService\n");
@ -1235,7 +1337,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
}
else if (_wcsicmp(LogonInfo->UserName.Buffer, L"NetworkService") == 0)
else if (RtlEqualUnicodeString(&LogonInfo->UserName, &NetworkServiceU, TRUE))
{
TRACE("SpecialAccount: NetworkService\n");
@ -1345,7 +1447,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
/* Check the password */
if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
{
Status = MsvpCheckPassword(&(LogonInfo->Password),
Status = MsvpCheckPassword(&LogonInfo->Password,
UserInfo);
if (!NT_SUCCESS(Status))
{
@ -1567,7 +1669,7 @@ done:
Status = STATUS_LOGON_FAILURE;
}
TRACE("LsaApLogonUser done (Status 0x%08lx SubStatus 0x%08lx)\n", Status, *SubStatus);
TRACE("LsaApLogonUserEx2 done (Status 0x%08lx, SubStatus 0x%08lx)\n", Status, *SubStatus);
return Status;
}