mirror of
https://github.com/reactos/reactos.git
synced 2025-03-27 15:40:45 +00:00
[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:
parent
127fa1afc6
commit
8210396cb4
1 changed files with 116 additions and 14 deletions
|
@ -496,6 +496,7 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
OUT PULONG ReturnBufferLength,
|
OUT PULONG ReturnBufferLength,
|
||||||
OUT PNTSTATUS ProtocolStatus)
|
OUT PNTSTATUS ProtocolStatus)
|
||||||
{
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
|
PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
|
||||||
ULONG_PTR PtrOffset;
|
ULONG_PTR PtrOffset;
|
||||||
|
|
||||||
|
@ -506,7 +507,6 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
RPC_UNICODE_STRING Names[1];
|
RPC_UNICODE_STRING Names[1];
|
||||||
SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
|
SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
|
||||||
SAMPR_ULONG_ARRAY Use = {0, NULL};
|
SAMPR_ULONG_ARRAY Use = {0, NULL};
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
|
ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
|
||||||
ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
|
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 pOldLmEncryptedWithNewLm = NULL;
|
||||||
PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = 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;
|
RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
|
||||||
|
|
||||||
/* Fix-up pointers in the request buffer info */
|
/* Fix-up pointers in the request buffer info */
|
||||||
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
|
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.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.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.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.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
|
||||||
|
RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length;
|
||||||
|
|
||||||
TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
|
TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
|
||||||
TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
|
TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
|
||||||
|
@ -942,15 +973,15 @@ LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
OUT PULONG ReturnBufferLength,
|
OUT PULONG ReturnBufferLength,
|
||||||
OUT PNTSTATUS ProtocolStatus)
|
OUT PNTSTATUS ProtocolStatus)
|
||||||
{
|
{
|
||||||
ULONG MessageType;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
|
||||||
|
|
||||||
TRACE("LsaApCallPackage()\n");
|
TRACE("LsaApCallPackage()\n");
|
||||||
|
|
||||||
if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
|
if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
|
MessageType = *((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
|
||||||
|
|
||||||
*ProtocolReturnBuffer = NULL;
|
*ProtocolReturnBuffer = NULL;
|
||||||
*ReturnBufferLength = 0;
|
*ReturnBufferLength = 0;
|
||||||
|
@ -1140,6 +1171,11 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
|
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
|
||||||
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* 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;
|
PMSV1_0_INTERACTIVE_LOGON LogonInfo;
|
||||||
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||||||
SAMPR_HANDLE ServerHandle = NULL;
|
SAMPR_HANDLE ServerHandle = NULL;
|
||||||
|
@ -1157,9 +1193,8 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
LARGE_INTEGER PasswordLastSet;
|
LARGE_INTEGER PasswordLastSet;
|
||||||
DWORD ComputerNameSize;
|
DWORD ComputerNameSize;
|
||||||
BOOL SpecialAccount = FALSE;
|
BOOL SpecialAccount = FALSE;
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
TRACE("LsaApLogonUser()\n");
|
TRACE("LsaApLogonUserEx2()\n");
|
||||||
|
|
||||||
TRACE("LogonType: %lu\n", LogonType);
|
TRACE("LogonType: %lu\n", LogonType);
|
||||||
TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
|
TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
|
||||||
|
@ -1171,40 +1206,107 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
*AccountName = NULL;
|
*AccountName = NULL;
|
||||||
*AuthenticatingAuthority = NULL;
|
*AuthenticatingAuthority = NULL;
|
||||||
|
|
||||||
|
/* Parameters validation */
|
||||||
if (LogonType == Interactive ||
|
if (LogonType == Interactive ||
|
||||||
LogonType == Batch ||
|
LogonType == Batch ||
|
||||||
LogonType == Service)
|
LogonType == Service)
|
||||||
{
|
{
|
||||||
ULONG_PTR PtrOffset;
|
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;
|
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 */
|
/* Fix-up pointers in the authentication info */
|
||||||
PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
|
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->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("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
|
||||||
TRACE("User: %S\n", LogonInfo->UserName.Buffer);
|
TRACE("User: %S\n", LogonInfo->UserName.Buffer);
|
||||||
TRACE("Password: %S\n", LogonInfo->Password.Buffer);
|
TRACE("Password: %S\n", LogonInfo->Password.Buffer);
|
||||||
|
|
||||||
|
// TODO: If LogonType == Service, do some extra work using LogonInfo->Password.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FIXME("LogonType %lu is not supported yet!\n", LogonType);
|
FIXME("LogonType %lu is not supported yet!\n", LogonType);
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
// TODO: Add other LogonType validity checks.
|
||||||
|
|
||||||
/* Get the logon time */
|
/* Get the logon time */
|
||||||
NtQuerySystemTime(&LogonTime);
|
NtQuerySystemTime(&LogonTime);
|
||||||
|
|
||||||
/* Get the computer name */
|
/* Get the computer name */
|
||||||
ComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
|
ComputerNameSize = ARRAYSIZE(ComputerName);
|
||||||
GetComputerNameW(ComputerName, &ComputerNameSize);
|
GetComputerNameW(ComputerName, &ComputerNameSize);
|
||||||
|
|
||||||
/* Check for special accounts */
|
/* 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;
|
SpecialAccount = TRUE;
|
||||||
|
|
||||||
|
@ -1216,7 +1318,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0)
|
if (RtlEqualUnicodeString(&LogonInfo->UserName, &LocalServiceU, TRUE))
|
||||||
{
|
{
|
||||||
TRACE("SpecialAccount: LocalService\n");
|
TRACE("SpecialAccount: LocalService\n");
|
||||||
|
|
||||||
|
@ -1235,7 +1337,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
|
UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
|
||||||
UserInfo->All.PrimaryGroupId = 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");
|
TRACE("SpecialAccount: NetworkService\n");
|
||||||
|
|
||||||
|
@ -1345,7 +1447,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
|
||||||
/* Check the password */
|
/* Check the password */
|
||||||
if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
|
if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
|
||||||
{
|
{
|
||||||
Status = MsvpCheckPassword(&(LogonInfo->Password),
|
Status = MsvpCheckPassword(&LogonInfo->Password,
|
||||||
UserInfo);
|
UserInfo);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
@ -1567,7 +1669,7 @@ done:
|
||||||
Status = STATUS_LOGON_FAILURE;
|
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;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue