📄 credapi.cxx
字号:
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1996
//
// File: credapi.cxx
//
// Contents: Code for credentials APIs for the NtLm package
// Main entry points into this dll:
// SpAcceptCredentials
// SpAcquireCredentialsHandle
// SpFreeCredentialsHandle
// SpQueryCredentialsAttributes
// SpSaveCredentials
// SpGetCredentials
// SpDeleteCredentials
//
// Helper functions:
// CopyClientString
//
// History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\credapi.cxx
//
//------------------------------------------------------------------------
#define NTLM_CREDAPI
#include <global.h>
extern "C"
{
// BUGBUG Move to a header
NTSTATUS
SspAcceptCredentials(
IN SECURITY_LOGON_TYPE LogonType,
IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
);
#include <nlp.h>
}
//+-------------------------------------------------------------------------
//
// Function: CopyClientString
//
// Synopsis: copies a client string to local memory, including
// allocating space for it locally.
//
// Arguments:
// SourceString - Could be Oem or Wchar in client process
// SourceLength - bytes
// DoUnicode - whether the string is Wchar
//
// Returns:
// DestinationString - Unicode String in Lsa Process
//
// Notes:
//
//--------------------------------------------------------------------------
HRESULT
CopyClientString(
IN PWSTR SourceString,
IN ULONG SourceLength,
IN BOOLEAN DoUnicode,
OUT PUNICODE_STRING DestinationString
)
{
SspPrint((SSP_API_MORE,"Entering CopyClientString\n"));
NTSTATUS Status = STATUS_SUCCESS;
STRING TemporaryString;
ULONG SourceSize = 0;
ULONG CharacterSize = sizeof(CHAR);
//
// First initialize the string to zero, in case the source is a null
// string
//
DestinationString->Length = DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
TemporaryString.Buffer = NULL;
if (SourceString != NULL)
{
//
// If the length is zero, allocate one byte for a "\0" terminator
//
if (SourceLength == 0)
{
DestinationString->Buffer = (LPWSTR) NtLmAllocate(sizeof(WCHAR));
if (DestinationString->Buffer == NULL)
{
SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status));
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
DestinationString->MaximumLength = sizeof(WCHAR);
*DestinationString->Buffer = L'\0';
}
else
{
//
// Allocate a temporary buffer to hold the client string. We may
// then create a buffer for the unicode version. The length
// is the length in characters, so possible expand to hold unicode
// characters and a null terminator.
//
if (DoUnicode)
{
CharacterSize = sizeof(WCHAR);
}
SourceSize = (SourceLength + 1) * CharacterSize;
//
// insure no overflow aggainst UNICODE_STRING
//
if ( (SourceSize > 0xFFFF) ||
((SourceSize - CharacterSize) > 0xFFFF)
)
{
Status = STATUS_INVALID_PARAMETER;
SspPrint((SSP_CRITICAL,"CopyClientString, SourceSize is too large\n"));
goto Cleanup;
}
TemporaryString.Buffer = (LPSTR) NtLmAllocate(SourceSize);
if (TemporaryString.Buffer == NULL)
{
Status = STATUS_NO_MEMORY;
SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status));
goto Cleanup;
}
TemporaryString.Length = (USHORT) (SourceSize - CharacterSize);
TemporaryString.MaximumLength = (USHORT) SourceSize;
//
// Finally copy the string from the client
//
Status = LsaFunctions->CopyFromClientBuffer(
NULL,
SourceSize - CharacterSize,
TemporaryString.Buffer,
SourceString
);
if (!NT_SUCCESS(Status))
{
SspPrint((SSP_CRITICAL,"CopyClientString, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
goto Cleanup;
}
//
// If we are doing unicode, finish up now
//
if (DoUnicode)
{
DestinationString->Buffer = (LPWSTR) TemporaryString.Buffer;
DestinationString->Length = (USHORT) (SourceSize - CharacterSize);
DestinationString->MaximumLength = (USHORT) SourceSize;
}
else
{
NTSTATUS Status1;
Status1 = RtlOemStringToUnicodeString(
DestinationString,
&TemporaryString,
TRUE
); // allocate destination
if (!NT_SUCCESS(Status1))
{
Status = STATUS_NO_MEMORY;
SspPrint((SSP_CRITICAL,"CopyClientString, Error from RtlOemStringToUnicodeString is 0x%lx\n", Status));
goto Cleanup;
}
}
}
}
Cleanup:
if (TemporaryString.Buffer != NULL)
{
//
// Free this if we failed and were doing unicode or if we weren't
// doing unicode
//
if ((DoUnicode && !NT_SUCCESS(Status)) || !DoUnicode)
{
NtLmFree(TemporaryString.Buffer);
}
}
SspPrint((SSP_API_MORE,"Leaving CopyClientString\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: SpAcceptCredentials
//
// Synopsis: This routine is called after another package has logged
// a user on. The other package provides a user name and
// password and the NtLm package will create a logon
// session for this user.
//
// Effects: Creates a logon session
//
// Arguments: LogonType - Type of logon, such as network or interactive
// Accountname - Name of the account that logged on
// PrimaryCredentials - Primary credentials for the account,
// containing a domain name, password, SID, etc.
// SupplementalCredentials - NtLm -Specific blob of
// supplemental credentials.
//
// Returns: None
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpAcceptCredentials(
IN SECURITY_LOGON_TYPE LogonType,
IN PUNICODE_STRING AccountName,
IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
)
{
NTSTATUS Status = S_OK;
SspPrint((SSP_API,"Entering SpAcceptCredentials\n"));
Status = SspAcceptCredentials(
LogonType,
PrimaryCredentials,
SupplementalCredentials
);
SspPrint((SSP_API,"Leaving SpAcceptCredentials\n"));
return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
UNREFERENCED_PARAMETER( AccountName );
}
//+-------------------------------------------------------------------------
//
// Function: SpAcquireCredentialsHandle
//
// Synopsis: Contains NtLm Code for AcquireCredentialsHandle which
// creates a Credential associated with a logon session.
//
// Effects: Creates a SSP_CREDENTIAL
//
// Arguments: PrincipalName - Name of logon session for which to create credential
// CredentialUseFlags - Flags indicating whether the credentials
// is for inbound or outbound use.
// LogonId - The logon ID of logon session for which to create
// a credential.
// AuthorizationData - Unused blob of NtLm-specific data
// GetKeyFunction - Unused function to retrieve a session key
// GetKeyArgument - Argument for GetKeyFunction
// CredentialHandle - Receives handle to new credential
// ExpirationTime - Receives expiration time for credential
//
// Returns:
// STATUS_SUCCESS -- Call completed successfully
// SEC_E_NO_SPM -- Security Support Provider is not running
// SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
// SEC_E_PRINCIPAL_UNKNOWN -- No such principal
// SEC_E_NOT_OWNER -- caller does not own the specified credentials
// SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpAcquireCredentialsHandle(
IN OPTIONAL PUNICODE_STRING PrincipalName,
IN ULONG CredentialUseFlags,
IN OPTIONAL PLUID LogonId,
IN PVOID AuthorizationData,
IN PVOID GetKeyFunction,
IN PVOID GetKeyArgument,
OUT PULONG_PTR CredentialHandle,
OUT PTimeStamp ExpirationTime
)
{
SspPrint((SSP_API,"Entering SpAcquireCredentialsHandle\n"));
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING UserName;
UNICODE_STRING DomainName;
UNICODE_STRING Password;
HANDLE TokenHandle = NULL;
ULONG NewCredentialUseFlags = CredentialUseFlags;
PSEC_WINNT_AUTH_IDENTITY pAuthIdentity = NULL;
BOOLEAN DoUnicode = TRUE;
PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL;
PSEC_WINNT_AUTH_IDENTITY_W TmpCredentials = NULL;
ULONG CredSize = 0;
ULONG Offset = 0;
//
// Initialization
//
RtlInitUnicodeString(
&UserName,
NULL);
RtlInitUnicodeString(
&DomainName,
NULL);
RtlInitUnicodeString(
&Password,
NULL);
//
// BUGBUG Check args specific to NTLM
// Validate the arguments
//
if ( (CredentialUseFlags & (SECPKG_CRED_OUTBOUND |SECPKG_CRED_INBOUND)) == 0)
{
Status = SEC_E_INVALID_CREDENTIAL_USE;
goto Cleanup;
}
if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
Status = SEC_E_UNSUPPORTED_FUNCTION;
SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status));
goto Cleanup;
}
// RDR2 passes in a 1 while talking to down level clients
if ( ARGUMENT_PRESENT(GetKeyArgument) && (GetKeyArgument != (PVOID) 1)) {
Status = SEC_E_UNSUPPORTED_FUNCTION;
SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status));
goto Cleanup;
}
//
// First get information about the caller.
//
SECPKG_CLIENT_INFO ClientInfo;
PLUID LogonIdToUse;
Status = LsaFunctions->GetClientInfo(&ClientInfo);
if (!NT_SUCCESS(Status))
{
SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetClientInfo is 0x%lx\n", Status));
goto Cleanup;
}
//
// If the caller supplied a logon ID, and it doesn't match the caller,
// they must have the TCB privilege
//
if (ARGUMENT_PRESENT(LogonId) &&
((LogonId->LowPart != 0) || (LogonId->HighPart != 0)) &&
!RtlEqualLuid( LogonId, &ClientInfo.LogonId)
)
{
if (!ClientInfo.HasTcbPrivilege)
{
Status = STATUS_PRIVILEGE_NOT_HELD;
SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from ClientInfo.HasTcbPrivilege is 0x%lx\n", Status));
goto Cleanup;
}
LogonIdToUse = LogonId;
// note: there is a special case where the LogonIdToUse specifies
// the SYSTEM token, and there may not be a credential (and access token)
// for that Luid yet. This special case is handled in SsprAcquireCredentialsHandle()
}
else
{
//
// Use the callers logon id.
//
LogonIdToUse = &ClientInfo.LogonId;
// extract the token
Status = SspGetToken (&TokenHandle);
if (!NT_SUCCESS(Status))
{
SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from SspGetToken is 0x%lx\n", Status));
goto Cleanup;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -