📄 msvpaswd.c
字号:
NTSTATUS
MspLm20ChangePassword (
IN PLSA_CLIENT_REQUEST ClientRequest,
IN PVOID ProtocolSubmitBuffer,
IN PVOID ClientBufferBase,
IN ULONG SubmitBufferSize,
OUT PVOID *ProtocolReturnBuffer,
OUT PULONG ReturnBufferSize,
OUT PNTSTATUS ProtocolStatus
)
/*++
Routine Description:
This routine is the dispatch routine for LsaCallAuthenticationPackage()
with a message type of MsV1_0ChangePassword. This routine changes an
account's password by either calling SamXxxPassword (for NT domains) or
RxNetUserPasswordSet (for downlevel domains and standalone servers).
Arguments:
The arguments to this routine are identical to those of LsaApCallPackage.
Only the special attributes of these parameters as they apply to
this routine are mentioned here.
Return Value:
STATUS_SUCCESS - Indicates the service completed successfully.
STATUS_PASSWORD_RESTRICTION - The password change failed because the
- password doesn't meet one or more domain restrictions. The
- response buffer is allocated. If the PasswordInfoValid flag is
- set it contains valid information otherwise it contains no
- information because this was a down-level change.
STATUS_BACKUP_CONTROLLER - The named machine is a Backup Domain Controller.
Changing password is only allowed on the Primary Domain Controller.
--*/
{
PMSV1_0_CHANGEPASSWORD_REQUEST ChangePasswordRequest = NULL;
PMSV1_0_CHANGEPASSWORD_RESPONSE ChangePasswordResponse;
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS SavedStatus = STATUS_SUCCESS;
LPWSTR DomainName = NULL;
PDOMAIN_CONTROLLER_INFO DCInfo = NULL;
UNICODE_STRING DCNameString;
UNICODE_STRING ClientNetbiosDomain = {0};
PUNICODE_STRING ClientDsGetDcDomain;
UNICODE_STRING ClientDnsDomain = {0};
UNICODE_STRING ClientName = {0};
UNICODE_STRING ValidatedAccountName;
UNICODE_STRING ValidatedDomainName;
LPWSTR ValidatedOldPasswordBuffer;
LPWSTR ValidatedNewPasswordBuffer;
NET_API_STATUS NetStatus;
PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo = NULL;
PDOMAIN_PASSWORD_INFORMATION DomainPasswordInfo = NULL;
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
PWKSTA_INFO_100 WkstaInfo100 = NULL;
BOOLEAN PasswordBufferValidated = FALSE;
CLIENT_BUFFER_DESC ClientBufferDesc;
PSECURITY_SEED_AND_LENGTH SeedAndLength;
PDS_NAME_RESULTW NameResult = NULL;
HANDLE DsHandle = NULL;
UCHAR Seed;
BOOLEAN Authoritative = TRUE;
BOOLEAN AttemptRediscovery = FALSE;
RtlInitUnicodeString(
&DCNameString,
NULL
);
//
// Sanity checks.
//
NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
if ( SubmitBufferSize < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) ) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
ChangePasswordRequest = (PMSV1_0_CHANGEPASSWORD_REQUEST) ProtocolSubmitBuffer;
ASSERT( ChangePasswordRequest->MessageType == MsV1_0ChangePassword ||
ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword );
RELOCATE_ONE( &ChangePasswordRequest->DomainName );
RELOCATE_ONE( &ChangePasswordRequest->AccountName );
if ( ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword ) {
NULL_RELOCATE_ONE( &ChangePasswordRequest->OldPassword );
} else {
RELOCATE_ONE_ENCODED( &ChangePasswordRequest->OldPassword );
}
RELOCATE_ONE_ENCODED( &ChangePasswordRequest->NewPassword );
//
// save away copies of validated buffers to check later.
//
RtlCopyMemory( &ValidatedDomainName, &ChangePasswordRequest->DomainName, sizeof(ValidatedDomainName) );
RtlCopyMemory( &ValidatedAccountName, &ChangePasswordRequest->AccountName, sizeof(ValidatedAccountName) );
ValidatedOldPasswordBuffer = ChangePasswordRequest->OldPassword.Buffer;
ValidatedNewPasswordBuffer = ChangePasswordRequest->NewPassword.Buffer;
SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->OldPassword.Length;
Seed = SeedAndLength->Seed;
SeedAndLength->Seed = 0;
if (Seed != 0) {
try {
RtlRunDecodeUnicodeString(
Seed,
&ChangePasswordRequest->OldPassword
);
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_ILL_FORMED_PASSWORD;
goto Cleanup;
}
}
SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->NewPassword.Length;
Seed = SeedAndLength->Seed;
SeedAndLength->Seed = 0;
if (Seed != 0) {
if( ChangePasswordRequest->NewPassword.Buffer !=
ValidatedNewPasswordBuffer ) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
try {
RtlRunDecodeUnicodeString(
Seed,
&ChangePasswordRequest->NewPassword
);
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_ILL_FORMED_PASSWORD;
goto Cleanup;
}
}
//
// sanity check that we didn't whack over buffers.
//
if( !RtlCompareMemory(
&ValidatedDomainName,
&ChangePasswordRequest->DomainName,
sizeof(ValidatedDomainName)
)
||
!RtlCompareMemory(
&ValidatedAccountName,
&ChangePasswordRequest->AccountName,
sizeof(ValidatedAccountName)
)
||
(ValidatedOldPasswordBuffer != ChangePasswordRequest->OldPassword.Buffer)
||
(ValidatedNewPasswordBuffer != ChangePasswordRequest->NewPassword.Buffer)
) {
Status= STATUS_INVALID_PARAMETER;
goto Cleanup;
}
*ReturnBufferSize = 0;
*ProtocolReturnBuffer = NULL;
*ProtocolStatus = STATUS_PENDING;
PasswordBufferValidated = TRUE;
MsvPaswdLogPrint(("Attempting password change server/domain %wZ for user %wZ\n",
&ChangePasswordRequest->DomainName,
&ChangePasswordRequest->AccountName
));
#ifdef COMPILED_BY_DEVELOPER
KdPrint(("MSV1_0:\n"
"\tDomain:\t%wZ\n"
"\tAccount:\t%wZ\n"
"\tOldPassword(%d)\n"
"\tNewPassword(%d)\n",
&ChangePasswordRequest->DomainName,
&ChangePasswordRequest->AccountName,
(int) ChangePasswordRequest->OldPassword.Length,
(int) ChangePasswordRequest->NewPassword.Length
));
#endif // COMPILED_BY_DEVELOPER
//
// If we're just changing the cached password,
// skip changing the password on the domain.
//
if ( ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword ) {
ClientName = ChangePasswordRequest->AccountName;
ClientNetbiosDomain = ChangePasswordRequest->DomainName;
Status = STATUS_SUCCESS;
goto PasswordChangeSuccessfull;
}
//
// If the client supplied a non-nt4 name, go ahead and convert it here.
//
if (ChangePasswordRequest->DomainName.Length == 0) {
DWORD DsStatus;
WCHAR NameBuffer[UNLEN+1];
LPWSTR NameString = NameBuffer;
ULONG Index;
BOOLEAN fWorkstation = FALSE;
//
// BUGBUG: is this too limited?
//
if (ChangePasswordRequest->AccountName.Length / sizeof(WCHAR) > UNLEN) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
RtlCopyMemory(
NameBuffer,
ChangePasswordRequest->AccountName.Buffer,
ChangePasswordRequest->AccountName.Length
);
NameBuffer[ChangePasswordRequest->AccountName.Length/sizeof(WCHAR)] = L'\0';
DsStatus = DsBindW(
NULL,
NULL,
&DsHandle
);
//
// we allow the bind to fail on a member workstation, which allows
// us to attempt a 'manual' crack.
//
if (DsStatus != ERROR_SUCCESS) {
fWorkstation = NlpWorkstation;
if( !fWorkstation ) {
SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsBindW returned 0x%lx.\n",
DsStatus ));
Status = NetpApiStatusToNtStatus( DsStatus );
goto Cleanup;
}
}
if( !fWorkstation ) {
DsStatus = DsCrackNamesW(
DsHandle,
0, // no flags
DS_UNKNOWN_NAME,
DS_NT4_ACCOUNT_NAME,
1,
&NameString,
&NameResult
);
if (DsStatus != ERROR_SUCCESS) {
SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsCrackNamesW returned 0x%lx.\n",
DsStatus ));
Status = NetpApiStatusToNtStatus( DsStatus );
goto Cleanup;
}
//
// Look for the name in the result
//
if (NameResult->cItems < 1) {
SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsCrackNamesW returned zero items.\n"));
Status = STATUS_INTERNAL_ERROR;
goto Cleanup;
}
}
//
// Check if the crack succeeded
//
if ( (fWorkstation) ||
(NameResult->rItems[0].status != DS_NAME_NO_ERROR)
) {
//
// The name wasn't mapped. Try converting it manually by
// splitting it at the '@'
//
RtlInitUnicodeString(
&ClientName,
NameBuffer
);
// shortest possible is 3 Unicode chars (eg: a@a)
if (ClientName.Length < (sizeof(WCHAR) * 3)) {
Status = STATUS_NO_SUCH_USER;
goto Cleanup;
}
for (Index = (ClientName.Length / sizeof(WCHAR)) - 1; Index != 0 ; Index-- ) {
if (ClientName.Buffer[Index] == L'@') {
RtlInitUnicodeString(
&ClientDnsDomain,
&ClientName.Buffer[Index+1]
);
ClientName.Buffer[Index] = L'\0';
ClientName.Length = (USHORT) Index * sizeof(WCHAR);
break;
}
}
//
// If the name couldn't be parsed, give up and go home
//
if (ClientDnsDomain.Length == 0) {
Status = STATUS_NO_SUCH_USER;
goto Cleanup;
}
//
// This isn't really the Netbios Domain name, but it is the best we have.
//
ClientNetbiosDomain = ClientDnsDomain;
for (Index = 0; Index < (ClientNetbiosDomain.Length / sizeof(WCHAR)) ; Index++ ) {
//
// truncate the netbios domain to the first DOT
//
if( ClientNetbiosDomain.Buffer[Index] == L'.' ) {
ClientNetbiosDomain.Length = (USHORT)(Index * sizeof(WCHAR));
ClientNetbiosDomain.MaximumLength = ClientNetbiosDomain.Length;
break;
}
}
}
else
{
RtlInitUnicodeString(
&ClientDnsDomain,
NameResult->rItems[0].pDomain
);
RtlInitUnicodeString(
&ClientName,
NameResult->rItems[0].pName
);
RtlInitUnicodeString(
&ClientNetbiosDomain,
NameResult->rItems[0].pName
);
//
// Move the pointer for the name up to the first "\" in the name
//
for (Index = 0; Index < ClientName.Length / sizeof(WCHAR) ; Index++ ) {
if (ClientName.Buffer[Index] == L'\\') {
RtlInitUnicodeString(
&ClientName,
&ClientName.Buffer[Index+1]
);
// Set the Netbios Domain Name to the string to the left of the backslash
ClientNetbiosDomain.Length = (USHORT)(Index * sizeof(WCHAR));
break;
}
}
}
} else {
ClientName = ChangePasswordRequest->AccountName;
ClientNetbiosDomain = ChangePasswordRequest->DomainName;
}
// Make sure that NlpSamInitialized is TRUE. If we logon using
// Kerberos, this may not be true.
if ( !NlpSamInitialized)
{
Status = NlSamInitialize( SAM_STARTUP_TIME );
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
//
// Check to see if the name provided is a domain name. If it has no
// leading "\\" and does not match the name of the computer, it may be.
//
if ((( ClientNetbiosDomain.Length < 3 * sizeof(WCHAR)) ||
( ClientNetbiosDomain.Buffer[0] != L'\\' &&
ClientNetbiosDomain.Buffer[1] != L'\\' ) ) &&
!RtlEqualDomainName(
&NlpComputerName,
&ClientNetbiosDomain )) {
//
// Check if we are a DC in this domain.
// If so, use this DC.
// BUGBUG: should allow DnsDomain Name compare, too.
//
if ( !NlpWorkstation &&
RtlEqualDomainName(
&NlpSamDomainName,
&ClientNetbiosDomain )) {
DCNameString = NlpComputerName;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -