📄 credhand.cxx
字号:
SspPrint(( SSP_CRITICAL, "SspCredentialLookupSupplementalCredential: GetClientInfo returned 0x%lx\n", Status));
return(NULL);
}
if ( !LsaFunctions->GetCallInfo( &CallInfo ) )
{
SspPrint(( SSP_CRITICAL, "SspCredentialLookupSupplementalCredential: GetCallInfo returned FALSE\n" ));
return NULL ;
}
//
// Acquire exclusive access to the Credential list
//
EnterCriticalSection( &SspCredentialCritSect );
ListHead = &SspCredentialList;
//
// Now walk the list of Credentials looking for a match.
//
for ( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
Credential = CONTAINING_RECORD( ListEntry, SSP_CREDENTIAL, Next );
//
// We are only looking for outbound credentials.
//
if ((Credential->CredentialUseFlags & SECPKG_CRED_OUTBOUND) == 0) {
continue;
}
//
// We only want credentials from the same caller
//
if (Credential->ClientProcessID != ClientInfo.ProcessID) {
continue;
}
//
// if the caller is from kernel mode, only return creds
// granted to kernel mode
//
if ( ( CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE ) != 0 )
{
if ( !Credential->KernelClient )
{
continue;
}
}
//
// Check for a match
//
// The credential use check was added because null session
// credentials were being returned when default credentials
// were being asked. This happened becuase RtlEqualUnicodeString
// for NULL,0,0 and "",0,2 is TRUE
if ( (CredentialUseFlags == Credential->CredentialUseFlags) &&
AlterRtlEqualUnicodeString(
UserName,
&Credential->UserName,
FALSE
) &&
AlterRtlEqualUnicodeString(
DomainName,
&Credential->DomainName,
FALSE
) &&
RtlEqualLuid(
LogonId,
&Credential->LogonId
)) {
UNICODE_STRING RevealedPassword;
BOOLEAN fMatch;
Status = NtLmDuplicateUnicodeString( &RevealedPassword, &Credential->Password );
if(!NT_SUCCESS( Status ) ) {
SspPrint(( SSP_CRITICAL,
"SspCredentialLookupSupplementalCredential: NtLmDuplicateUnicodeString returned %d\n",Status));
// an allocation failure is catastrophic, bail out now.
break;
}
SspRevealPassword(&RevealedPassword);
fMatch = AlterRtlEqualUnicodeString(
Password,
&RevealedPassword,
FALSE
);
if( RevealedPassword.Buffer != NULL ) {
ZeroMemory( RevealedPassword.Buffer, RevealedPassword.Length );
NtLmFree( RevealedPassword.Buffer );
}
if( fMatch ) {
//
// Found a match - reference the credential
//
//
// Reference the credential and indicate that
// it is in use as two different handles to the caller
// (who may call FreeCredentialsHandle twice)
//
Credential->References++;
LeaveCriticalSection( &SspCredentialCritSect );
SspPrint((SSP_API_MORE, "Leaving SspCredentialLookupSupplementalCredential\n"));
return Credential;
}
}
}
//
// No match found
//
SspPrint(( SSP_API_MORE, "Tried to reference unknown Credential\n" ));
LeaveCriticalSection( &SspCredentialCritSect );
SspPrint((SSP_API_MORE, "Leaving SspCredentialLookupSupplementalCredential\n"));
return NULL;
}
VOID
SspCredentialDereferenceCredential(
IN PSSP_CREDENTIAL Credential
)
/*++
Routine Description:
This routine decrements the specified Credential's reference count.
If the reference count drops to zero, then the Credential is deleted
Arguments:
Credential - Points to the Credential to be dereferenced.
Return Value:
None.
--*/
{
ULONG References;
//
// Decrement the reference count
//
EnterCriticalSection( &SspCredentialCritSect );
ASSERT( Credential->References >= 1 );
References = -- Credential->References;
//
// If the count dropped to zero, then run-down the Credential
//
if ( References == 0 ) {
LPWSTR DomainName = Credential->DomainName.Buffer;
LPWSTR UserName = Credential->UserName.Buffer;
LPWSTR Password = Credential->Password.Buffer;
// note: Password.Length may contain run-encoding hint, so size may be illegal.
DWORD cbPassword = Credential->Password.MaximumLength;
HANDLE ClientTokenHandle = Credential->ClientTokenHandle;
SspPrint(( SSP_API_MORE, "Deleting Credential 0x%lx\n",
Credential ));
if (!Credential->Unlinked) {
RemoveEntryList( &Credential->Next );
}
ZeroMemory( Credential, sizeof(SSP_CREDENTIAL) );
LeaveCriticalSection( &SspCredentialCritSect );
if ( DomainName ) {
(VOID) NtLmFree( DomainName );
}
if ( UserName ) {
(VOID) NtLmFree( UserName );
}
if ( Password ) {
ZeroMemory( Password, cbPassword );
(VOID) NtLmFree( Password );
}
if ( ClientTokenHandle ) {
(VOID) NtClose( ClientTokenHandle );
}
(VOID) NtLmFree( Credential );
return;
}
LeaveCriticalSection( &SspCredentialCritSect );
return;
}
BOOLEAN
SsprCheckMachineLogon(
IN OUT PLUID pLogonId,
IN PUNICODE_STRING UserName,
IN PUNICODE_STRING DomainName,
IN PUNICODE_STRING Password
)
/*++
Routine Description:
This routine determines if the input credential matches a special
machine account logon over-ride.
Return Value:
TRUE - the intput credential was the special machine account logon over-ride.
the pLogonId is updated to utilize the machine credential.
--*/
{
UNICODE_STRING MachineAccountName;
static LUID LogonIdSystem = SYSTEM_LUID ;
BOOLEAN fMachineLogon = FALSE;
MachineAccountName.Buffer = NULL;
//
// check if caller was system, and requested machine credential
// eg: user=computername$, domain=NULL, password=NULL
//
if( !RtlEqualLuid( pLogonId, &LogonIdSystem ) )
{
return FALSE;
}
if( UserName->Buffer == NULL )
{
return FALSE;
}
if( DomainName->Buffer != NULL )
{
return FALSE;
}
if( Password->Buffer != NULL )
{
return FALSE;
}
EnterCriticalSection (&NtLmGlobalCritSect);
MachineAccountName.Length = NtLmGlobalUnicodeComputerNameString.Length + sizeof(WCHAR);
if( MachineAccountName.Length == UserName->Length )
{
MachineAccountName.MaximumLength = MachineAccountName.Length;
MachineAccountName.Buffer = (PWSTR)NtLmAllocate( MachineAccountName.Length );
if( MachineAccountName.Buffer != NULL )
{
RtlCopyMemory( MachineAccountName.Buffer,
NtLmGlobalUnicodeComputerNameString.Buffer,
NtLmGlobalUnicodeComputerNameString.Length
);
MachineAccountName.Buffer[ (MachineAccountName.Length / sizeof(WCHAR)) - 1 ] = L'$';
}
}
LeaveCriticalSection (&NtLmGlobalCritSect);
if( MachineAccountName.Buffer == NULL )
{
goto Cleanup;
}
if( RtlEqualUnicodeString( &MachineAccountName, UserName, TRUE ) )
{
//
// yes, it's a machine account logon request, update the
// requested LogonId to match our mapped logon session.
//
*pLogonId = NtLmGlobalLuidMachineLogon;
fMachineLogon = TRUE;
}
Cleanup:
if( MachineAccountName.Buffer )
{
NtLmFree( MachineAccountName.Buffer );
}
return fMachineLogon;
}
NTSTATUS
SsprAcquireCredentialHandle(
IN PHANDLE TokenHandle,
IN PLUID LogonId,
IN ULONG ClientProcessID,
IN ULONG CredentialUseFlags,
OUT PLSA_SEC_HANDLE CredentialHandle,
OUT PTimeStamp Lifetime,
IN OPTIONAL PUNICODE_STRING DomainName,
IN OPTIONAL PUNICODE_STRING UserName,
IN OPTIONAL PUNICODE_STRING Password
)
/*++
Routine Description:
This API allows applications to acquire a handle to pre-existing
credentials associated with the user on whose behalf the call is made
i.e. under the identity this application is running. These pre-existing
credentials have been established through a system logon not described
here. Note that this is different from "login to the network" and does
not imply gathering of credentials.
This API returns a handle to the credentials of a principal (user, client)
as used by a specific security package. This handle can then be used
in subsequent calls to the Context APIs. This API will not let a
process obtain a handle to credentials that are not related to the
process; i.e. we won't allow a process to grab the credentials of
another user logged into the same machine. There is no way for us
to determine if a process is a trojan horse or not, if it is executed
by the user.
Arguments:
CredentialUseFlags - Flags indicating the way with which these
credentials will be used.
#define CRED_INBOUND 0x00000001
#define CRED_OUTBOUND 0x00000002
#define CRED_BOTH 0x00000003
The credentials created with CRED_INBOUND option can only be used
for (validating incoming calls and can not be used for making accesses.
CredentialHandle - Returned credential handle.
Lifetime - Time that these credentials expire. The value returned in
this field depends on the security package.
DomainName, DomainNameSize, UserName, UserNameSize, Password, PasswordSize -
Optional credentials for this user.
Return Value:
STATUS_SUCCESS -- Call completed successfully
SEC_E_PRINCIPAL_UNKNOWN -- No such principal
SEC_E_NOT_OWNER -- caller does not own the specified credentials
STATUS_NO_MEMORY -- Not enough memory
--*/
{
SspPrint((SSP_API_MORE, "Entering SsprAcquireCredentialHandle\n"));
NTSTATUS Status = STATUS_SUCCESS;
PSSP_CREDENTIAL Credential = NULL;
SECPKG_CALL_INFO CallInfo ;
if ( !LsaFunctions->GetCallInfo( &CallInfo ) )
{
return STATUS_UNSUCCESSFUL ;
}
//
// If this is an outbound credential, and supplemental credentials
// were supplied, look to see if we have already
// created one with this set of credentials. Note - this leaves
// the credential referenced, so if we fail further down we need to
// dereference the credential.
//
if ((CredentialUseFlags & SECPKG_CRED_OUTBOUND) != 0) {
//
// check if machine account logon over-ride.
//
SsprCheckMachineLogon(
LogonId,
UserName,
DomainName,
Password
);
Credential = SspCredentialLookupSupplementalCredential(
LogonId,
CredentialUseFlags,
UserName,
DomainName,
Password
);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -