623 lines
18 KiB
C++
623 lines
18 KiB
C++
|
||
//+--------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
//
|
||
// Copyright (c) Microsoft Corporation 2000
|
||
//
|
||
// File: lsaap.cxx
|
||
//
|
||
// Contents: Authentication package dispatch routines
|
||
// LsaApInitializePackage (Not needed done in SpInitialize)
|
||
// LsaApLogonUser2
|
||
// LsaApCallPackage
|
||
// LsaApCallPackagePassthrough
|
||
// LsaApLogonTerminated
|
||
//
|
||
// Helper functions:
|
||
//
|
||
// History: KDamour 10Mar00 Stolen from msv_sspi\msv1_0.c
|
||
//
|
||
//---------------------------------------------------------------------
|
||
|
||
|
||
#include "global.h"
|
||
|
||
#include <samisrv.h>
|
||
|
||
#define SAM_CLEARTEXT_CREDENTIAL_NAME L"CLEARTEXT"
|
||
#define SAM_WDIGEST_CREDENTIAL_NAME WDIGEST_SP_NAME // Name of the Supplemental (primary) cred blob for MD5 hashes
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch routine for
|
||
LsaCallAuthenticationPackage().
|
||
|
||
--*/
|
||
NTSTATUS
|
||
LsaApCallPackage (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
IN PVOID ProtocolSubmitBuffer,
|
||
IN PVOID ClientBufferBase,
|
||
IN ULONG SubmitBufferLength,
|
||
OUT PVOID *ProtocolReturnBuffer,
|
||
OUT PULONG ReturnBufferLength,
|
||
OUT PNTSTATUS ProtocolStatus
|
||
)
|
||
|
||
{
|
||
ULONG MessageType;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApCallPackage: Entering/Leaving \n"));
|
||
return(SEC_E_UNSUPPORTED_FUNCTION);
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch routine for
|
||
LsaCallAuthenticationPackage() for untrusted clients.
|
||
|
||
|
||
--*/
|
||
NTSTATUS
|
||
LsaApCallPackageUntrusted (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
IN PVOID ProtocolSubmitBuffer,
|
||
IN PVOID ClientBufferBase,
|
||
IN ULONG SubmitBufferLength,
|
||
OUT PVOID *ProtocolReturnBuffer,
|
||
OUT PULONG ReturnBufferLength,
|
||
OUT PNTSTATUS ProtocolStatus
|
||
)
|
||
|
||
{
|
||
ULONG MessageType;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApCallPackageUntrusted: Entering/Leaving \n"));
|
||
return(SEC_E_UNSUPPORTED_FUNCTION);
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch routine for
|
||
LsaCallAuthenticationPackage() for passthrough logon requests.
|
||
When the passthrough is called (from AcceptSecurityCOntext)
|
||
a databuffer is sent to the DC and this function is called.
|
||
|
||
Arguments:
|
||
|
||
ClientRequest - Is a pointer to an opaque data structure
|
||
representing the client's request.
|
||
|
||
ProtocolSubmitBuffer - Supplies a protocol message specific to
|
||
the authentication package.
|
||
|
||
ClientBufferBase - Provides the address within the client
|
||
process at which the protocol message was resident.
|
||
This may be necessary to fix-up any pointers within the
|
||
protocol message buffer.
|
||
|
||
SubmitBufferLength - Indicates the length of the submitted
|
||
protocol message buffer.
|
||
|
||
ProtocolReturnBuffer - Is used to return the address of the
|
||
protocol buffer in the client process. The authentication
|
||
package is responsible for allocating and returning the
|
||
protocol buffer within the client process. This buffer is
|
||
expected to have been allocated with the
|
||
AllocateClientBuffer() service.
|
||
|
||
The format and semantics of this buffer are specific to the
|
||
authentication package.
|
||
|
||
ReturnBufferLength - Receives the length (in bytes) of the
|
||
returned protocol buffer.
|
||
|
||
ProtocolStatus - Assuming the services completion is
|
||
STATUS_SUCCESS, this parameter will receive completion status
|
||
returned by the specified authentication package. The list
|
||
of status values that may be returned are authentication
|
||
package specific.
|
||
|
||
Return Status:
|
||
|
||
STATUS_SUCCESS - The call was made to the authentication package.
|
||
The ProtocolStatus parameter must be checked to see what the
|
||
completion status from the authentication package is.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the return
|
||
buffer could not could not be allocated because the client
|
||
does not have sufficient quota.
|
||
|
||
|
||
|
||
|
||
--*/
|
||
NTSTATUS
|
||
LsaApCallPackagePassthrough (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
IN PVOID ProtocolSubmitBuffer,
|
||
IN PVOID ClientBufferBase,
|
||
IN ULONG SubmitBufferLength,
|
||
OUT PVOID *ProtocolReturnBuffer,
|
||
OUT PULONG ReturnBufferLength,
|
||
OUT PNTSTATUS ProtocolStatus
|
||
)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
NTSTATUS StatusProtocol = STATUS_SUCCESS;
|
||
PDIGEST_BLOB_REQUEST pDigestBlob = NULL;
|
||
ULONG MessageType = 0;
|
||
USHORT i = 0;
|
||
ULONG ulReturnBuffer = 0;
|
||
BYTE *pReturnBuffer = NULL;
|
||
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApCallPackagePassthrough: Entering \n"));
|
||
|
||
|
||
//
|
||
// Get the messsage type from the protocol submit buffer.
|
||
//
|
||
|
||
if ( SubmitBufferLength < sizeof(ULONG) ) {
|
||
DebugLog((DEB_ERROR, "FAILED message size to contain MessageType\n"));
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
memcpy((char *)&MessageType, (char *)ProtocolSubmitBuffer, sizeof(MessageType));
|
||
|
||
if ( MessageType != VERIFY_DIGEST_MESSAGE)
|
||
{
|
||
DebugLog((DEB_ERROR, "FAILED to have correct message type\n"));
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Allow the DigestCalc routine to only set the return buffer information
|
||
// on success conditions.
|
||
//
|
||
|
||
DebugLog((DEB_TRACE, "LsaApCallPackagePassthrough: setting return buffers to NULL\n"));
|
||
*ProtocolReturnBuffer = NULL;
|
||
*ReturnBufferLength = 0;
|
||
|
||
// We will need to free any memory allocated in the Returnbuffer
|
||
StatusProtocol = DigestPackagePassthrough((USHORT)SubmitBufferLength, (BYTE *)ProtocolSubmitBuffer,
|
||
&ulReturnBuffer, &pReturnBuffer);
|
||
if (!NT_SUCCESS(StatusProtocol))
|
||
{
|
||
DebugLog((DEB_ERROR,"LsaApCallPackagePassthrough: DigestPackagePassthrough failed 0x%x\n",Status));
|
||
ulReturnBuffer = 0;
|
||
goto CleanUp;
|
||
}
|
||
|
||
// DebugLog((DEB_TRACE, "LsaApCallPackagePassthrough: setting return auth status to STATUS_SUCCEED\n"));
|
||
// DebugLog((DEB_TRACE, "LsaApCallPackagePassthrough: Total Return Buffer size %ld bytes\n", ulReturnBuffer));
|
||
|
||
// Now place the data back to the client (the server calling this)
|
||
Status = g_LsaFunctions->AllocateClientBuffer(
|
||
NULL,
|
||
ulReturnBuffer,
|
||
ProtocolReturnBuffer
|
||
);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
goto CleanUp;
|
||
}
|
||
Status = g_LsaFunctions->CopyToClientBuffer(
|
||
NULL,
|
||
ulReturnBuffer,
|
||
*ProtocolReturnBuffer,
|
||
pReturnBuffer
|
||
);
|
||
if (!NT_SUCCESS(Status))
|
||
{ // Failed to copy over the data to the client
|
||
g_LsaFunctions->FreeClientBuffer(
|
||
NULL,
|
||
*ProtocolReturnBuffer
|
||
);
|
||
*ProtocolReturnBuffer = NULL;
|
||
}
|
||
else
|
||
{
|
||
*ReturnBufferLength = ulReturnBuffer;
|
||
}
|
||
|
||
CleanUp:
|
||
|
||
*ProtocolStatus = StatusProtocol;
|
||
|
||
if (pReturnBuffer)
|
||
{
|
||
DigestFreeMemory(pReturnBuffer);
|
||
pReturnBuffer = NULL;
|
||
ulReturnBuffer = 0;
|
||
}
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApCallPackagePassthrough: Leaving Status 0x%x\n", Status));
|
||
return(Status);
|
||
}
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to authenticate a user logon attempt. This is
|
||
the user's initial logon. A new LSA logon session will be established
|
||
for the user and validation information for the user will be returned.
|
||
|
||
|
||
--*/
|
||
NTSTATUS
|
||
LsaApLogonUserEx2 (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
IN SECURITY_LOGON_TYPE LogonType,
|
||
IN PVOID ProtocolSubmitBuffer,
|
||
IN PVOID ClientBufferBase,
|
||
IN ULONG SubmitBufferSize,
|
||
OUT PVOID *ProfileBuffer,
|
||
OUT PULONG ProfileBufferSize,
|
||
OUT PLUID LogonId,
|
||
OUT PNTSTATUS SubStatus,
|
||
OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
||
OUT PVOID *TokenInformation,
|
||
OUT PUNICODE_STRING *AccountName,
|
||
OUT PUNICODE_STRING *AuthenticatingAuthority,
|
||
OUT PUNICODE_STRING *MachineName,
|
||
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
|
||
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * SupplementalCredentials
|
||
)
|
||
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApLogonUserEx2: Entering/Leaving \n"));
|
||
|
||
//
|
||
// Return status to the caller
|
||
//
|
||
|
||
return (SEC_E_UNSUPPORTED_FUNCTION);
|
||
|
||
}
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to notify each authentication package when a logon
|
||
session terminates. A logon session terminates when the last token
|
||
referencing the logon session is deleted.
|
||
|
||
Arguments:
|
||
|
||
LogonId - Is the logon ID that just logged off.
|
||
|
||
Return Status:
|
||
|
||
None.
|
||
--*/
|
||
VOID
|
||
LsaApLogonTerminated (
|
||
IN PLUID pLogonId
|
||
)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PDIGEST_LOGONSESSION pLogonSession = NULL;
|
||
LONG lReferences = 0;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApLogonTerminated: Entering LogonID (%x:%lx) \n",
|
||
pLogonId->HighPart, pLogonId->LowPart));
|
||
|
||
//
|
||
// Find the entry, dereference, and de-link it from the active logon table.
|
||
//
|
||
|
||
Status = LogSessHandlerLogonIdToPtr(pLogonId, TRUE, &pLogonSession);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
goto CleanUp; // No LongonID found in Active list - simply exit quietly
|
||
}
|
||
|
||
DebugLog((DEB_TRACE, "LsaApLogonTerminated: Found LogonID (%x:%lx) \n",
|
||
pLogonId->HighPart, pLogonId->LowPart));
|
||
|
||
|
||
// This relies on the LSA terminating all of the credentials before killing off
|
||
// the LogonSession.
|
||
|
||
lReferences = InterlockedDecrement(&pLogonSession->lReferences);
|
||
|
||
DebugLog((DEB_TRACE, "LsaApLogonTerminated: Refcount %ld \n", lReferences));
|
||
|
||
ASSERT( lReferences >= 0 );
|
||
|
||
if (lReferences)
|
||
{
|
||
DebugLog((DEB_WARN, "LsaApLogonTerminated: WARNING Terminate LogonID (%x:%lx) non-zero RefCount!\n",
|
||
pLogonId->HighPart, pLogonId->LowPart));
|
||
}
|
||
else
|
||
{
|
||
DebugLog((DEB_TRACE, "LsaApLogonTerminated: Removed LogonID (%x:%lx) from Active List! \n",
|
||
pLogonId->HighPart, pLogonId->LowPart));
|
||
|
||
LogonSessionFree(pLogonSession);
|
||
}
|
||
|
||
CleanUp:
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "LsaApLogonTerminated: Exiting LogonID (%x:%lx) \n",
|
||
pLogonId->HighPart, pLogonId->LowPart));
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
// Routine to acquire the plaintext password for a given user
|
||
// If supplemental credentials exist that contain the Digest Hash values
|
||
// then return them also.
|
||
// This routine runs on the domain controller
|
||
// Must provide STRING strPasswd
|
||
// If ppucUserAuthData pointer is NULL - do not retrieve UserAuthData
|
||
|
||
NTSTATUS
|
||
DigestGetPasswd(
|
||
IN PUSER_CREDENTIALS pUserCreds,
|
||
OUT PUCHAR * ppucUserAuthData,
|
||
OUT PULONG pulAuthDataSize
|
||
)
|
||
{
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
SAMPR_HANDLE UserHandle = NULL;
|
||
UNICODE_STRING ustrcPackageName;
|
||
|
||
UNICODE_STRING ustrcTemp;
|
||
STRING strcTemp;
|
||
PVOID pvPlainPwd = NULL;
|
||
PVOID pvHashCred = NULL;
|
||
ULONG ulLenPassword = 0;
|
||
ULONG ulLenHash = 0;
|
||
ULONG ulVersion = 0;
|
||
BOOL bOpenedSAM = FALSE;
|
||
|
||
DebugLog((DEB_TRACE_FUNC,"DigestGetPasswd: Entering\n"));
|
||
|
||
RtlZeroMemory(&ustrcTemp, sizeof(ustrcTemp));
|
||
RtlZeroMemory(&strcTemp, sizeof(strcTemp));
|
||
RtlZeroMemory(&ustrcPackageName, sizeof(ustrcPackageName));
|
||
pUserCreds->fIsValidDigestHash = FALSE;
|
||
pUserCreds->fIsValidPasswd = FALSE;
|
||
|
||
*pulAuthDataSize = 0L;
|
||
*ppucUserAuthData = NULL;
|
||
|
||
DebugLog((DEB_TRACE,"DigestGetPasswd: looking for username (unicode) %wZ\n", &(pUserCreds->ustrUsername)));
|
||
|
||
if (!g_fDomainController)
|
||
{
|
||
DebugLog((DEB_ERROR,"DigestGetPasswd: Not on a domaincontroller - can not get credentials\n"));
|
||
Status = STATUS_INVALID_SERVER_STATE;
|
||
goto CleanUp;
|
||
}
|
||
|
||
// Call LsaOpenSamUser()
|
||
Status = g_LsaFunctions->OpenSamUser(&(pUserCreds->ustrUsername), SecNameSamCompatible,
|
||
NULL, FALSE, 0, &UserHandle);
|
||
if ( !NT_SUCCESS( Status ) )
|
||
{
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Failed to open SAM for user %wZ, Status = 0x%x\n",
|
||
&(pUserCreds->ustrUsername), Status));
|
||
goto CleanUp;
|
||
}
|
||
bOpenedSAM = TRUE;
|
||
|
||
|
||
DebugLog((DEB_TRACE,"DigestGetPasswd: Have a valid UserHandle\n"));
|
||
|
||
//
|
||
// Retrieve the MD5 hashed pre-calculated values if they exist for this user
|
||
//
|
||
// NOTE : On NT 5, this API only works on Domain Controllers !!
|
||
//
|
||
RtlInitUnicodeString(&ustrcPackageName, SAM_WDIGEST_CREDENTIAL_NAME);
|
||
|
||
Status = SamIRetrievePrimaryCredentials( (SAMPR_HANDLE) UserHandle,
|
||
&ustrcPackageName,
|
||
&pvHashCred,
|
||
&ulLenHash);
|
||
|
||
if (!NT_SUCCESS( Status ))
|
||
{
|
||
pvHashCred = NULL;
|
||
DebugLog((DEB_TRACE,"DigestGetPasswd: NO Pre-calc Hashes were found for user\n"));
|
||
}
|
||
else
|
||
{
|
||
|
||
strcTemp.Buffer = (PCHAR) pvHashCred;
|
||
strcTemp.Length = strcTemp.MaximumLength = (USHORT) ulLenHash;
|
||
|
||
Status = StringDuplicate(&(pUserCreds->strDigestHash), &strcTemp);
|
||
if (!NT_SUCCESS( Status ))
|
||
{
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Failed to copy plaintext password, error 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
// DebugLog((DEB_TRACE,"DigestGetPasswd: Have the PASSWORD %wZ\n", &(pUserCreds->ustrPasswd)));
|
||
|
||
|
||
Status = RtlCharToInteger(pUserCreds->strDigestHash.Buffer, TENBASE, &ulVersion);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Badly formatted pre-calc version\n"));
|
||
goto CleanUp;
|
||
}
|
||
|
||
// Check version and size of credentials
|
||
if ((ulVersion != SUPPCREDS_VERSION) || (ulLenHash < (TOTALPRECALC_HEADERS * MD5_HASH_BYTESIZE)))
|
||
{
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Invalid precalc version or size\n"));
|
||
pUserCreds->fIsValidDigestHash = FALSE;
|
||
}
|
||
else
|
||
{
|
||
pUserCreds->fIsValidDigestHash = TRUE;
|
||
// setup the hashes to utilize - get format from the notify.cxx hash calcs
|
||
switch (pUserCreds->typeName)
|
||
{
|
||
case NAMEFORMAT_ACCOUNTNAME:
|
||
pUserCreds->sHashTags[NAME_ACCT] = 1;
|
||
pUserCreds->sHashTags[NAME_ACCT_DOWNCASE] = 1;
|
||
pUserCreds->sHashTags[NAME_ACCT_UPCASE] = 1;
|
||
break;
|
||
case NAMEFORMAT_UPN:
|
||
pUserCreds->sHashTags[NAME_UPN] = 1;
|
||
pUserCreds->sHashTags[NAME_UPN_DOWNCASE] = 1;
|
||
pUserCreds->sHashTags[NAME_UPN_UPCASE] = 1;
|
||
break;
|
||
case NAMEFORMAT_NETBIOS:
|
||
pUserCreds->sHashTags[NAME_NT4] = 1;
|
||
pUserCreds->sHashTags[NAME_NT4_DOWNCASE] = 1;
|
||
pUserCreds->sHashTags[NAME_NT4_UPCASE] = 1;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
DebugLog((DEB_TRACE,"DigestGetPasswd: Read in Pre-calc Hashes size = %lu\n", ulLenHash));
|
||
}
|
||
|
||
//
|
||
// Retrieve the plaintext password
|
||
//
|
||
// NOTE : On NT 5, this API only works on Domain Controllers !!
|
||
//
|
||
RtlInitUnicodeString(&ustrcPackageName, SAM_CLEARTEXT_CREDENTIAL_NAME);
|
||
|
||
// Note: Would be nice to have this as a LSAFunction
|
||
Status = SamIRetrievePrimaryCredentials( (SAMPR_HANDLE) UserHandle,
|
||
&ustrcPackageName,
|
||
&pvPlainPwd,
|
||
&ulLenPassword);
|
||
|
||
if (!NT_SUCCESS( Status ))
|
||
{
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Failed to retrieve plaintext password, error 0x%x\n", Status));
|
||
|
||
if (pUserCreds->fIsValidDigestHash == FALSE)
|
||
{
|
||
// We have no pre-computed MD5 hashes and also no cleartext password
|
||
// we can not perform any Digest Auth operations
|
||
//
|
||
// Explicitly set the status to be "wrong password" instead of whatever
|
||
// is returned by SamIRetrievePrimaryCredentials
|
||
//
|
||
Status = STATUS_WRONG_PASSWORD;
|
||
DebugLog((DEB_ERROR,"DigestGetPasswd: Can not obtain cleartext or Hashed Creds\n"));
|
||
goto CleanUp;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
ustrcTemp.Buffer = (PUSHORT) pvPlainPwd;
|
||
ustrcTemp.Length = ustrcTemp.MaximumLength = (USHORT) ulLenPassword;
|
||
|
||
Status = UnicodeStringDuplicate(&(pUserCreds->ustrPasswd), &ustrcTemp);
|
||
if (!NT_SUCCESS( Status ))
|
||
{
|
||
DebugLog((DEB_ERROR, "DigestGetPasswd: Failed to copy plaintext password, error 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
// DebugLog((DEB_TRACE,"DigestGetPasswd: Have the PASSWORD %wZ\n", &(pUserCreds->ustrPasswd)));
|
||
|
||
pUserCreds->fIsValidPasswd = TRUE;
|
||
|
||
DebugLog((DEB_TRACE,"DigestGetPasswd: Password retrieved\n"));
|
||
}
|
||
|
||
// We have some form of credentials based on password (either cleartext or pre-computed)
|
||
|
||
if (ppucUserAuthData)
|
||
{ // Go fetch the AuthData to marshall back to the server for Token creation
|
||
*ppucUserAuthData = NULL;
|
||
*pulAuthDataSize = 0;
|
||
// Calling LsaGetUserAuthData()
|
||
Status = g_LsaFunctions->GetUserAuthData(UserHandle, ppucUserAuthData, pulAuthDataSize);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
DebugLog((DEB_ERROR,"DigestGetPasswd: failed acquire UseAuthData 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
}
|
||
|
||
CleanUp:
|
||
|
||
// Release any memory from SamI* calls Would be nice to have this as a LSAFunction
|
||
|
||
if (pvPlainPwd)
|
||
{
|
||
if (ulLenPassword > 0)
|
||
{
|
||
ZeroMemory(pvPlainPwd, ulLenPassword);
|
||
}
|
||
LocalFree(pvPlainPwd);
|
||
pvPlainPwd = NULL;
|
||
}
|
||
|
||
if (pvHashCred)
|
||
{
|
||
LocalFree(pvHashCred);
|
||
pvHashCred = NULL;
|
||
}
|
||
|
||
|
||
if (bOpenedSAM == TRUE)
|
||
{
|
||
// LsaCloseSamUser()
|
||
Status = g_LsaFunctions->CloseSamUser(UserHandle);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
DebugLog((DEB_ERROR,"DigestGetPasswd: failed LsaCloseSamUser 0x%x\n", Status));
|
||
}
|
||
bOpenedSAM = FALSE;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{ // Cleanup functions since there was a failure
|
||
if (*ppucUserAuthData)
|
||
{
|
||
g_LsaFunctions->FreeLsaHeap(*ppucUserAuthData);
|
||
*ppucUserAuthData = NULL;
|
||
*pulAuthDataSize = 0L;
|
||
}
|
||
}
|
||
|
||
DebugLog((DEB_TRACE_FUNC,"DigestGetPasswd: Leaving\n"));
|
||
|
||
return(Status);
|
||
}
|
||
|