📄 msvpaswd.c
字号:
if ( MsvPaswdLogFile != NULL ) {
CloseHandle( MsvPaswdLogFile );
MsvPaswdLogFile = NULL;
}
return( dwErr );
}
//
// Stolen and hacked up from netlogon code
//
VOID
MsvPaswdDebugDumpRoutine(
IN LPSTR Format,
va_list arglist
)
{
char OutputBuffer[2049];
ULONG length;
ULONG BytesWritten;
SYSTEMTIME SystemTime;
static BeginningOfLine = TRUE;
//
// If we don't have an open log file, just bail
//
if ( MsvPaswdLogFile == NULL ) {
return;
}
length = 0;
//
// Handle the beginning of a new line.
//
//
if ( BeginningOfLine ) {
//
// If we're writing to the debug terminal,
// indicate this is a Netlogon message.
//
//
// Put the timestamp at the begining of the line.
//
GetLocalTime( &SystemTime );
length += (ULONG) sprintf( &OutputBuffer[length],
"%02u/%02u %02u:%02u:%02u ",
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond );
}
//
// Put a the information requested by the caller onto the line
//
length += (ULONG) vsprintf(&OutputBuffer[length], Format, arglist);
BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
if ( BeginningOfLine ) {
OutputBuffer[length-1] = '\r';
OutputBuffer[length] = '\n';
OutputBuffer[length+1] = '\0';
length++;
}
ASSERT( length <= sizeof( OutputBuffer ) / sizeof( CHAR ) );
//
// Write the debug info to the log file.
//
if ( !WriteFile( MsvPaswdLogFile,
OutputBuffer,
length,
&BytesWritten,
NULL ) ) {
}
}
VOID
MsvPaswdLogPrintRoutine(
IN LPSTR Format,
...
)
{
va_list arglist;
va_start(arglist, Format);
MsvPaswdDebugDumpRoutine( Format, arglist );
va_end(arglist);
}
ULONG
MsvPaswdSetAndClearLog(
VOID
)
/*++
Routine Description:
Flushes the log and seeks to the end of the file
Arguments:
None
Returns:
ERROR_SUCCESS - Success
--*/
{
ULONG dwErr = ERROR_SUCCESS;
if ( MsvPaswdLogFile != NULL ) {
if( FlushFileBuffers( MsvPaswdLogFile ) == FALSE ) {
dwErr = GetLastError();
}
}
return( dwErr );
}
#endif // DONT_LOG_PASSWORD_CHANGES
NTSTATUS
MspChangePasswordSam(
IN PUNICODE_STRING UncComputerName,
IN PUNICODE_STRING UserName,
IN PUNICODE_STRING OldPassword,
IN PUNICODE_STRING NewPassword,
IN PLSA_CLIENT_REQUEST ClientRequest,
IN BOOLEAN Impersonating,
OUT PDOMAIN_PASSWORD_INFORMATION *DomainPasswordInfo,
OUT PPOLICY_PRIMARY_DOMAIN_INFO *PrimaryDomainInfo OPTIONAL,
OUT PBOOLEAN Authoritative
)
/*++
Routine Description:
This routine is called by MspChangePassword to change the password
on a Windows NT machine.
Arguments:
UncComputerName - Name of the target machine. This name must begin with
two backslashes.
UserName - Name of the user to change password for.
OldPassword - Plaintext current password.
NewPassword - Plaintext replacement password.
ClientRequest - Is a pointer to an opaque data structure
representing the client's request.
DomainPasswordInfo - Password restriction information (returned only if
status is STATUS_PASSWORD_RESTRICTION).
PrimaryDomainInfo - DomainNameInformation (returned only if status is
STATUS_BACKUP_CONTROLLER).
Authoritative - The failure was authoritative and no retries should be
made.
Return Value:
STATUS_SUCCESS - Indicates the service completed successfully.
...
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQos;
SAM_HANDLE SamHandle = NULL;
SAM_HANDLE DomainHandle = NULL;
LSA_HANDLE LSAPolicyHandle = NULL;
OBJECT_ATTRIBUTES LSAObjectAttributes;
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
//
// Assume all failures are authoritative
//
*Authoritative = TRUE;
//
// If we're impersonating (ie, winlogon impersonated its caller before calling us),
// impersonate again. This allows us to get the name of the caller for auditing.
//
if ( Impersonating ) {
Status = (*Lsap.ImpersonateClient)(ClientRequest);
} else {
//
// Since the System context is a member of the Administrators alias,
// when we connect with the local SAM we come in as an Administrator.
// (When it's remote, we go over the null session and so have very
// low access). We don't want to be an Administrator because that
// would allow the user to change the password on an account whose
// ACL prohibits the user from changing the password. So we'll
// temporarily impersonate ourself and disable the Administrators
// alias in the impersonation token.
//
Status = MspDisableAdminsAlias();
}
if (!NT_SUCCESS( Status )) {
goto Cleanup;
}
try
{
Status = SamChangePasswordUser2(
UncComputerName,
UserName,
OldPassword,
NewPassword
);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
MsvPaswdLogPrint(("SamChangePasswordUser2 on machine %wZ for user %wZ returned 0x%x\n",
UncComputerName,
UserName,
Status
));
if ( !NT_SUCCESS(Status) ) {
#ifdef COMPILED_BY_DEVELOPER
KdPrint(("MspChangePasswordSam: SamChangePasswordUser2(%wZ) failed, status %x\n",
UncComputerName, Status));
#endif // COMPILED_BY_DEVELOPER
//
// If we failed to connect and we were impersonating a client
// then we may want to try again using the NULL session.
// Only try this if we found a server last try. Otherwise,
// we'll subject our user to another long timeout.
//
if (( Impersonating ) &&
( Status != STATUS_WRONG_PASSWORD ) &&
( Status != STATUS_PASSWORD_RESTRICTION ) &&
( Status != STATUS_ACCOUNT_RESTRICTION ) &&
( Status != RPC_NT_SERVER_UNAVAILABLE) &&
( Status != STATUS_INVALID_DOMAIN_ROLE) ) {
Status = MspDisableAdminsAlias();
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = SamChangePasswordUser2(
UncComputerName,
UserName,
OldPassword,
NewPassword
);
MsvPaswdLogPrint(("SamChangePasswordUser2 retry on machine %wZ for user %wZ returned 0x%x\n",
UncComputerName,
UserName,
Status
));
#ifdef COMPILED_BY_DEVELOPER
if ( !NT_SUCCESS(Status) ) {
KdPrint(("MspChangePasswordSam: SamChangePasswordUser2(%wZ) (2nd attempt) failed, status %x\n",
UncComputerName, Status));
}
#endif // COMPILED_BY_DEVELOPER
}
}
if ( !NT_SUCCESS(Status) ) {
#ifdef COMPILED_BY_DEVELOPER
KdPrint(("MspChangePasswordSam: Cannot change password for %wZ, status %x\n",
UserName, Status));
#endif // COMPILED_BY_DEVELOPER
if (Status == RPC_NT_SERVER_UNAVAILABLE ||
Status == RPC_S_SERVER_UNAVAILABLE ) {
Status = STATUS_CANT_ACCESS_DOMAIN_INFO;
} else if (Status == STATUS_PASSWORD_RESTRICTION) {
//
// Get the password restrictions for this domain and return them
//
//
// Get the SID of the account domain from LSA
//
InitializeObjectAttributes( &LSAObjectAttributes,
NULL, // Name
0, // Attributes
NULL, // Root
NULL ); // Security Descriptor
Status = LsaOpenPolicy( UncComputerName,
&LSAObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&LSAPolicyHandle );
if( !NT_SUCCESS(Status) ) {
KdPrint(("MspChangePasswordSam: LsaOpenPolicy(%wZ) failed, status %x\n",
UncComputerName, Status));
LSAPolicyHandle = NULL;
goto Cleanup;
}
Status = LsaQueryInformationPolicy(
LSAPolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &AccountDomainInfo );
if( !NT_SUCCESS(Status) ) {
KdPrint(("MspChangePasswordSam: LsaQueryInformationPolicy(%wZ) failed, status %x\n",
UncComputerName, Status));
AccountDomainInfo = NULL;
goto Cleanup;
}
//
// Setup ObjectAttributes for SamConnect call.
//
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL);
ObjectAttributes.SecurityQualityOfService = &SecurityQos;
SecurityQos.Length = sizeof(SecurityQos);
SecurityQos.ImpersonationLevel = SecurityIdentification;
SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
SecurityQos.EffectiveOnly = FALSE;
Status = SamConnect(
UncComputerName,
&SamHandle,
SAM_SERVER_LOOKUP_DOMAIN,
&ObjectAttributes
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("MspChangePasswordSam: Cannot open sam on %wZ, status %x\n",
UncComputerName, Status));
DomainHandle = NULL;
goto Cleanup;
}
//
// Open the Account domain in SAM.
//
Status = SamOpenDomain(
SamHandle,
GENERIC_EXECUTE,
AccountDomainInfo->DomainSid,
&DomainHandle
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("MspChangePasswordSam: Cannot open domain on %wZ, status %x\n",
UncComputerName, Status));
DomainHandle = NULL;
goto Cleanup;
}
Status = SamQueryInformationDomain(
DomainHandle,
DomainPasswordInformation,
(PVOID *)DomainPasswordInfo );
if (!NT_SUCCESS(Status)) {
*DomainPasswordInfo = NULL;
} else {
Status = STATUS_PASSWORD_RESTRICTION;
}
}
goto Cleanup;
}
Cleanup:
//
// If the only problem is that this is a BDC,
// Return the domain name back to the caller.
//
if ( (Status == STATUS_BACKUP_CONTROLLER ||
Status == STATUS_INVALID_DOMAIN_ROLE) &&
PrimaryDomainInfo != NULL ) {
NTSTATUS TempStatus;
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -