📄 msvsam.c
字号:
//
// Open the user account.
//
Status = I_SamIGetUserLogonInformation(
DomainHandle,
SamFlags,
&LocalUserName,
&UserAllInfo,
&GroupMembership,
&UserHandle
);
if ( !NT_SUCCESS(Status) ) {
UserHandle = NULL;
*Authoritative = FALSE;
Status = STATUS_NO_SUCH_USER;
goto Cleanup;
}
UserAll = &UserAllInfo->All;
//
// pickup RelativeId from looked up information.
//
RelativeId = UserAll->UserId;
//
// If the account type isn't allowed,
// Treat this as though the User Account doesn't exist.
//
// SubAuthentication packages can be more specific than this test but
// they can't become less restrictive.
//
if ( (UserAccountControl & UserAll->UserAccountControl) == 0 ) {
*Authoritative = FALSE;
Status = STATUS_NO_SUCH_USER;
goto Cleanup;
}
//
// determine if machine account, if so, certain failures are treated
// as Authoritative, to prevent fallback to guest and returning incorrect
// error codes.
//
if ( (UserAll->UserAccountControl & USER_MACHINE_ACCOUNT_MASK) != 0 ) {
fMachineAccount = TRUE;
} else {
fMachineAccount = FALSE;
}
//
// If there is a SubAuthentication DLL,
// call it to do all the authentication work.
//
if ( (LogonInfo->ParameterControl & MSV1_0_SUBAUTHENTICATION_DLL) &&
(!(LogonInfo->ParameterControl & MSV1_0_SUBAUTHENTICATION_DLL_EX))) {
ULONG LocalUserFlags = 0;
ULONG Flags = 0;
//
// Ensure the account isn't locked out.
// We did this regardless before NT 5.0. Now, we do it when either
// No SubAuth package is specified or
// New SubAuth package asks us to do account lockout test
// But, for those who call with old SubAuth packages, they will expect
// us to do the dirty work.
//
if (RelativeId != DOMAIN_USER_RID_ADMIN) {
if ( UserAll->UserAccountControl & USER_ACCOUNT_AUTO_LOCKED ) {
//
// Since the UI strongly encourages admins to disable user
// accounts rather than delete them. Treat disabled acccount as
// non-authoritative allowing the search to continue for other
// accounts by the same name.
//
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED ) {
*Authoritative = fMachineAccount;
} else {
*Authoritative = TRUE;
}
Status = STATUS_ACCOUNT_LOCKED_OUT;
goto Cleanup;
}
}
if ( SecureChannelType != MsvApSecureChannel ) {
Flags |= MSV1_0_PASSTHRU;
}
if ( GuestRelativeId != 0 ) {
Flags |= MSV1_0_GUEST_LOGON;
}
Status = Msv1_0SubAuthenticationRoutine(
LogonLevel,
LogonInformation,
Flags,
(PUSER_ALL_INFORMATION) UserAll,
&WhichFields,
&LocalUserFlags,
Authoritative,
&LogoffTime,
&KickoffTime );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// Sanity check what the SubAuthentication package returned
//
if ( (WhichFields & ~USER_ALL_PARAMETERS) != 0 ) {
Status = STATUS_INTERNAL_ERROR;
*Authoritative = TRUE;
goto Cleanup;
}
UserFlags |= LocalUserFlags;
} else { // we may still have an NT 5.0 SubAuth dll
//
// If there is an NT 5.0 SubAuthentication DLL,
// call it to do all the authentication work.
//
if ( (LogonInfo->ParameterControl & MSV1_0_SUBAUTHENTICATION_DLL_EX))
{
ULONG LocalUserFlags = 0;
ULONG Flags = 0;
if ( SecureChannelType != MsvApSecureChannel ) {
Flags |= MSV1_0_PASSTHRU;
}
if ( GuestRelativeId != 0 ) {
Flags |= MSV1_0_GUEST_LOGON;
}
Status = Msv1_0SubAuthenticationRoutineEx(
LogonLevel,
LogonInformation,
Flags,
(PUSER_ALL_INFORMATION) UserAll,
(SAM_HANDLE)UserHandle,
&SubAuthValidationInformation,
&ActionsPerformed );
*Authoritative = SubAuthValidationInformation.Authoritative;
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
// We need to do this because even if any of the following checks
// fail, ARAP stills wants the returned blobs from teh subauth
// package to be returned to the caller.
fSubAuthEx = TRUE;
}
//
// Ensure the account isn't locked out.
//
if ((ActionsPerformed & MSV1_0_SUBAUTH_LOCKOUT) == 0)
{
if (RelativeId != DOMAIN_USER_RID_ADMIN) {
if ( UserAll->UserAccountControl & USER_ACCOUNT_AUTO_LOCKED ) {
//
// Since the UI strongly encourages admins to disable user
// accounts rather than delete them. Treat disabled acccount as
// non-authoritative allowing the search to continue for other
// accounts by the same name.
//
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED ) {
*Authoritative = fMachineAccount;
} else {
*Authoritative = TRUE;
}
Status = STATUS_ACCOUNT_LOCKED_OUT;
goto Cleanup;
}
}
}
//
// Check the password if there's no subauth or if subauth did
// not already check password.
//
if ((ActionsPerformed & MSV1_0_SUBAUTH_PASSWORD) == 0)
{
if ( SecureChannelType != NullSecureChannel ) {
USER_INTERNAL1_INFORMATION Passwords;
//
// Copy the password info to the right structure.
//
Passwords.NtPasswordPresent = UserAll->NtPasswordPresent;
if ( UserAll->NtPasswordPresent ) {
Passwords.NtOwfPassword =
*((PNT_OWF_PASSWORD)(UserAll->NtOwfPassword.Buffer));
}
Passwords.LmPasswordPresent = UserAll->LmPasswordPresent;
if ( UserAll->LmPasswordPresent ) {
Passwords.LmOwfPassword =
*((PLM_OWF_PASSWORD)(UserAll->LmOwfPassword.Buffer));
}
//
// If the password specified doesn't match the SAM password,
// then we've got a password mismatch.
//
if ( ! MsvpPasswordValidate (
UasCompatibilityRequired,
LogonLevel,
LogonInformation,
&Passwords,
&UserFlags,
&UserSessionKey,
&LmSessionKey ) ) {
//
// If this is a guest logon and the guest account has no password,
// let the user log on.
//
// This special case check is after the MsvpPasswordValidate to
// give MsvpPasswordValidate every opportunity to compute the
// correct values for UserSessionKey and LmSessionKey.
//
if ( GuestRelativeId != 0 &&
!UserAll->NtPasswordPresent &&
!UserAll->LmPasswordPresent ) {
RtlZeroMemory( &UserSessionKey, sizeof(UserSessionKey) );
RtlZeroMemory( &LmSessionKey, sizeof(LmSessionKey) );
//
// The password mismatched. We treat STATUS_WRONG_PASSWORD as
// an authoritative response. Our caller may choose to do otherwise.
//
} else {
Status = STATUS_WRONG_PASSWORD;
//
// Since the UI strongly encourages admins to disable user
// accounts rather than delete them. Treat disabled acccount as
// non-authoritative allowing the search to continue for other
// accounts by the same name.
//
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED ) {
*Authoritative = fMachineAccount;
} else {
*Authoritative = TRUE;
}
goto Cleanup;
}
}
}
}
//
// Prevent some things from effecting the Administrator user
//
if (RelativeId != DOMAIN_USER_RID_ADMIN) {
//
// Check if the account is disabled if there's no subauth or if
// subauth has not already checked.
//
if ((ActionsPerformed & MSV1_0_SUBAUTH_ACCOUNT_DISABLED) == 0)
{
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED ) {
//
// Since the UI strongly encourages admins to disable user
// accounts rather than delete them. Treat disabled acccount as
// non-authoritative allowing the search to continue for other
// accounts by the same name.
//
*Authoritative = fMachineAccount;
Status = STATUS_ACCOUNT_DISABLED;
goto Cleanup;
}
}
//
// Check if the account has expired if there's no subauth or if
// subauth has not already checked.
//
if ((ActionsPerformed & MSV1_0_SUBAUTH_ACCOUNT_EXPIRY) == 0)
{
OLD_TO_NEW_LARGE_INTEGER( UserAll->AccountExpires, AccountExpires );
if ( AccountExpires.QuadPart != 0 &&
LogonTime.QuadPart >= AccountExpires.QuadPart ) {
*Authoritative = TRUE;
Status = STATUS_ACCOUNT_EXPIRED;
goto Cleanup;
}
}
//
// The password is valid, check to see if the password is expired.
// (SAM will have appropriately set PasswordMustChange to reflect
// USER_DONT_EXPIRE_PASSWORD)
//
// Don't check if the password is expired if we didn't check the password.
// BUGBUG What happens when a Subauth does the password checking
// but requests us to do password expiry ??
//
if ((ActionsPerformed & MSV1_0_SUBAUTH_PASSWORD_EXPIRY) == 0)
{
OLD_TO_NEW_LARGE_INTEGER( UserAll->PasswordMustChange, PasswordMustChange );
OLD_TO_NEW_LARGE_INTEGER( UserAll->PasswordLastSet, PasswordLastSet );
if ( SecureChannelType != NullSecureChannel ) {
if ( LogonTime.QuadPart >= PasswordMustChange.QuadPart ) {
if ( PasswordLastSet.QuadPart == 0 ) {
Status = STATUS_PASSWORD_MUST_CHANGE;
} else {
Status = STATUS_PASSWORD_EXPIRED;
}
*Authoritative = TRUE;
goto Cleanup;
}
}
}
}
//
// Validate the workstation the user logged on from.
//
// Ditch leading \\ on workstation name before passing it to SAM.
//
LocalWorkstation = LogonInfo->Workstation;
if ( LocalWorkstation.Length > 0 &&
LocalWorkstation.Buffer[0] == L'\\' &&
LocalWorkstation.Buffer[1] == L'\\' ) {
LocalWorkstation.Buffer += 2;
LocalWorkstation.Length -= 2*sizeof(WCHAR);
LocalWorkstation.MaximumLength -= 2*sizeof(WCHAR);
}
//
// Check if SAM found some more specific reason to not allow logon.
//
Status = I_SamIAccountRestrictions(
UserHandle,
&LocalWorkstation,
(PUNICODE_STRING) &UserAll->WorkStations,
(PLOGON_HOURS) &UserAll->LogonHours,
&LogoffTime,
&KickoffTime );
if ( !NT_SUCCESS(Status) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -