windows-nt/Source/XPSP1/NT/ds/security/protocols/xtcb/creds.c
2020-09-26 16:20:57 +08:00

748 lines
16 KiB
C

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997.
//
// File: creds.c
//
// Contents: Cred Management for Xtcb Package
//
// Classes:
//
// Functions:
//
// History: 2-19-97 RichardW Created
//
//----------------------------------------------------------------------------
#include "xtcbpkg.h"
LIST_ENTRY XtcbCredList ;
CRITICAL_SECTION XtcbCredListLock ;
#define ReadLockCredList() EnterCriticalSection( &XtcbCredListLock )
#define WriteLockCredList() EnterCriticalSection( &XtcbCredListLock )
#define WriteFromReadLockCredList()
#define UnlockCredList() LeaveCriticalSection( &XtcbCredListLock )
//+---------------------------------------------------------------------------
//
// Function: XtcbInitCreds
//
// Synopsis: Initialize the credential management
//
// Arguments: (none)
//
// History: 2-19-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
XtcbInitCreds(
VOID
)
{
InitializeCriticalSection( &XtcbCredListLock );
InitializeListHead( &XtcbCredList );
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: XtcbFindCreds
//
// Synopsis: Look for credentials of a particular logon id, optionally
// referencing them
//
// Arguments: [LogonId] --
// [Ref] --
//
// History: 2-19-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PXTCB_CREDS
XtcbFindCreds(
PLUID LogonId,
BOOL Ref
)
{
PLIST_ENTRY Scan ;
PXTCB_CREDS Cred ;
Cred = NULL ;
ReadLockCredList();
Scan = XtcbCredList.Flink ;
while ( Scan != &XtcbCredList )
{
Cred = CONTAINING_RECORD( Scan, XTCB_CREDS, List );
DsysAssert( Cred->Check == XTCB_CRED_CHECK );
if ( RtlEqualLuid( &Cred->LogonId, LogonId ) )
{
break;
}
Scan = Cred->List.Flink ;
Cred = NULL ;
}
if ( Cred )
{
if ( Ref )
{
WriteFromReadLockCredList();
Cred->RefCount++;
}
}
UnlockCredList();
return Cred ;
}
//+---------------------------------------------------------------------------
//
// Function: XtcbCreateCreds
//
// Synopsis: Create and initialize a credential structure. The reference
// count is set to 1, so the pointer will remain valid.
//
// Arguments: [LogonId] --
//
// History: 2-19-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PXTCB_CREDS
XtcbCreateCreds(
PLUID LogonId
)
{
PXTCB_CREDS Creds ;
Creds = (PXTCB_CREDS) LocalAlloc( LMEM_FIXED, sizeof( XTCB_CREDS ) );
if ( Creds )
{
DebugLog(( DEB_TRACE_CREDS, "Creating new credential for (%x:%x)\n",
LogonId->HighPart, LogonId->LowPart ));
ZeroMemory( Creds, sizeof( XTCB_CREDS ) );
Creds->LogonId = *LogonId ;
Creds->RefCount = 1 ;
Creds->Check = XTCB_CRED_CHECK ;
Creds->Pac = XtcbCreatePacForCaller();
WriteLockCredList();
InsertTailList( &XtcbCredList, &Creds->List );
UnlockCredList();
}
return Creds ;
}
//+---------------------------------------------------------------------------
//
// Function: XtcbRefCreds
//
// Synopsis: Reference the credentials
//
// Arguments: [Creds] --
//
// History: 2-19-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
XtcbRefCreds(
PXTCB_CREDS Creds
)
{
WriteLockCredList();
Creds->RefCount++ ;
UnlockCredList();
}
//+---------------------------------------------------------------------------
//
// Function: XtcbDerefCreds
//
// Synopsis: Deref Credentials, freeing if the refcount goes to zero
//
// Arguments: [Creds] --
//
// History: 2-19-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
XtcbDerefCreds(
PXTCB_CREDS Creds
)
{
WriteLockCredList();
Creds->RefCount--;
if ( Creds->RefCount )
{
UnlockCredList();
return;
}
RemoveEntryList( &Creds->List );
UnlockCredList();
Creds->Check = 0 ;
LocalFree( Creds );
}
//+---------------------------------------------------------------------------
//
// Function: XtcbAllocateCredHandle
//
// Synopsis: Allocates and returns a cred handle (reference to a credential)
//
// Arguments: [Creds] -- Creds this handle is for
//
// History: 2-21-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PXTCB_CRED_HANDLE
XtcbAllocateCredHandle(
PXTCB_CREDS Creds
)
{
PXTCB_CRED_HANDLE Handle ;
Handle = (PXTCB_CRED_HANDLE) LocalAlloc( LMEM_FIXED,
sizeof( XTCB_CRED_HANDLE ) );
if ( Handle )
{
ZeroMemory( Handle, sizeof( XTCB_CRED_HANDLE ) );
Handle->Check = XTCB_CRED_HANDLE_CHECK ;
XtcbRefCreds( Creds );
Handle->Creds = Creds ;
Handle->RefCount = 1 ;
}
return Handle ;
}
//+---------------------------------------------------------------------------
//
// Function: XtcbRefCredHandle
//
// Synopsis: Reference a credential handle
//
// Arguments: [Handle] -- Handle to ref
//
// History: 2-24-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
XtcbRefCredHandle(
PXTCB_CRED_HANDLE Handle
)
{
WriteLockCredList();
Handle->RefCount ++ ;
UnlockCredList();
}
//+---------------------------------------------------------------------------
//
// Function: XtcbDerefCredHandle
//
// Synopsis: Dereference a cred handle
//
// Arguments: [Handle] --
//
// History: 2-24-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
XtcbDerefCredHandle(
PXTCB_CRED_HANDLE Handle
)
{
WriteLockCredList();
Handle->RefCount -- ;
if ( Handle->RefCount == 0 )
{
XtcbDerefCreds( Handle->Creds );
LocalFree( Handle );
}
UnlockCredList();
}
//+---------------------------------------------------------------------------
//
// Function: XtcbCreatePacForCaller
//
// Synopsis: Creates an XTCB_PAC for the caller
//
// Arguments: none
//
// History: 3-14-00 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PXTCB_PAC
XtcbCreatePacForCaller(
VOID
)
{
HANDLE Token ;
NTSTATUS Status ;
PXTCB_PAC Pac = NULL ;
PTOKEN_USER User = NULL ;
PTOKEN_GROUPS Groups = NULL ;
PTOKEN_GROUPS Restrictions = NULL ;
TOKEN_STATISTICS Stats ;
ULONG UserSize ;
ULONG GroupSize ;
ULONG RestrictionSize ;
ULONG PacGroupSize = 0 ;
ULONG PacRestrictionSize = 0 ;
ULONG PacUserName = 0 ;
ULONG PacDomainName = 0 ;
ULONG PacSize ;
ULONG i ;
PUCHAR CopyTo ;
PUCHAR Base ;
BOOL SpecialAccount = FALSE ;
PSECURITY_LOGON_SESSION_DATA LogonSessionData = NULL ;
Status = LsaTable->ImpersonateClient();
if ( !NT_SUCCESS( Status ) )
{
return NULL ;
}
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_READ,
TRUE,
&Token );
RevertToSelf();
if ( !NT_SUCCESS( Status ) )
{
return NULL ;
}
//
// Now that we have the token, capture all the information about this user,
// and compute our own "PAC" structure.
//
Status = NtQueryInformationToken(
Token,
TokenStatistics,
&Stats,
sizeof( Stats ),
&UserSize );
if ( !NT_SUCCESS( Status ) )
{
goto CreatePac_Exit ;
}
//
// If this is a special logon session (e.g. LocalSystem, LocalService, etc.),
// then the LUID will be less than 1000. Set the flag to copy all SIDs in the token.
//
if ( (Stats.AuthenticationId.HighPart == 0) &&
(Stats.AuthenticationId.LowPart < 1000 ) )
{
SpecialAccount = TRUE ;
}
UserSize = 0 ;
(void) NtQueryInformationToken(
Token,
TokenUser,
NULL,
0,
&UserSize );
if ( UserSize == 0 )
{
goto CreatePac_Exit ;
}
User = LocalAlloc( LMEM_FIXED, UserSize );
if ( !User )
{
goto CreatePac_Exit ;
}
Status = NtQueryInformationToken(
Token,
TokenUser,
User,
UserSize,
&UserSize );
if ( !NT_SUCCESS( Status ) )
{
goto CreatePac_Exit ;
}
GroupSize = 0 ;
(void) NtQueryInformationToken(
Token,
TokenGroups,
NULL,
0,
&GroupSize );
if ( GroupSize == 0 )
{
goto CreatePac_Exit ;
}
Groups = LocalAlloc( LMEM_FIXED, GroupSize );
if ( !Groups )
{
goto CreatePac_Exit ;
}
Status = NtQueryInformationToken(
Token,
TokenGroups,
Groups,
GroupSize,
&GroupSize );
if ( !NT_SUCCESS( Status ) )
{
goto CreatePac_Exit;
}
RestrictionSize = 0 ;
(void) NtQueryInformationToken(
Token,
TokenRestrictedSids,
NULL,
0,
&RestrictionSize );
if ( RestrictionSize != 0 )
{
Restrictions = LocalAlloc( LMEM_FIXED, RestrictionSize );
if ( Restrictions )
{
Status = NtQueryInformationToken(
Token,
TokenRestrictedSids,
Restrictions,
RestrictionSize,
&RestrictionSize );
if ( !NT_SUCCESS( Status ) )
{
goto CreatePac_Exit ;
}
}
else
{
goto CreatePac_Exit ;
}
}
//
// We now have all the users SIDs in the two (or three) pointers. First, grovel the Groups
// for non-local SIDs, and set all the rest to 0. This will let us compute how much space
// we need.
//
for ( i = 0 ; i < Groups->GroupCount ; i++ )
{
if ( (*RtlSubAuthorityCountSid( Groups->Groups[ i ].Sid ) > 2) ||
(SpecialAccount) )
{
//
// A "real" SID. Check to make sure it is not from this machine
//
if ( ( XtcbMachineSid != NULL ) &&
RtlEqualPrefixSid( XtcbMachineSid, Groups->Groups[ i ].Sid ) )
{
//
// Don't use this group
//
Groups->Groups[ i ].Attributes = 0 ;
}
else
{
//
// We like this SID (it is not from the local machine)
//
Groups->Groups[ i ].Attributes = SE_GROUP_MANDATORY ;
PacGroupSize += RtlLengthSid( Groups->Groups[ i ].Sid );
}
}
else
{
Groups->Groups[ i ].Attributes = 0 ;
}
}
//
// Do the same for the restrictions, if any
//
if ( Restrictions )
{
for ( i = 0 ; i < Restrictions->GroupCount ; i++ )
{
PacRestrictionSize += RtlLengthSid( Restrictions->Groups[ i ].Sid );
}
}
//
// Get the user's name and domain:
//
Status = LsaGetLogonSessionData(
&Stats.AuthenticationId,
&LogonSessionData );
if ( !NT_SUCCESS( Status ) )
{
goto CreatePac_Exit ;
}
PacUserName = LogonSessionData->UserName.Length ;
PacDomainName = LogonSessionData->LogonDomain.Length ;
//
// In an advanced world, we'd query the other packages for
// delegatable credentials, bundle them up and ship them
// over.
//
//
// Ok, we've got all the information we need
//
PacSize = sizeof( XTCB_PAC ) +
RtlLengthSid( User->User.Sid ) +
PacGroupSize +
PacRestrictionSize +
PacUserName +
PacDomainName ;
Pac = LocalAlloc( LMEM_FIXED, PacSize );
if ( !Pac )
{
goto CreatePac_Exit ;
}
//
// Create the PAC structure:
//
Pac->Tag = XTCB_PAC_TAG ;
Pac->Length = PacSize ;
CopyTo = (PUCHAR) (Pac + 1);
Base = (PUCHAR) Pac ;
//
// Assemble the PAC:
//
// first, the user
//
Pac->UserOffset = (ULONG) (CopyTo - Base);
Pac->UserLength = RtlLengthSid( User->User.Sid );
RtlCopyMemory(
CopyTo,
User->User.Sid,
Pac->UserLength );
CopyTo += RtlLengthSid( User->User.Sid );
//
// Now the normal groups:
//
Pac->GroupCount = 0 ;
Pac->GroupOffset = (ULONG) (CopyTo - Base);
for ( i = 0 ; i < Groups->GroupCount ; i++ )
{
if ( Groups->Groups[ i ].Attributes & SE_GROUP_MANDATORY )
{
RtlCopyMemory(
CopyTo,
Groups->Groups[ i ].Sid,
RtlLengthSid( Groups->Groups[ i ].Sid ) );
CopyTo += RtlLengthSid( Groups->Groups[ i ].Sid );
Pac->GroupCount++ ;
}
}
Pac->GroupLength = (ULONG) (CopyTo - Base) - Pac->GroupOffset;
//
// If there are restrictions, copy them in as well
//
if ( (Restrictions == NULL) ||
(Restrictions->GroupCount == 0 ) )
{
Pac->RestrictionCount = 0 ;
Pac->RestrictionOffset = 0 ;
Pac->RestrictionLength = 0 ;
}
else
{
Pac->RestrictionCount = Restrictions->GroupCount ;
Pac->RestrictionOffset = (ULONG) ( CopyTo - Base );
for ( i = 0 ; i < Restrictions->GroupCount ; i++ )
{
RtlCopyMemory(
CopyTo,
Restrictions->Groups[ i ].Sid,
RtlLengthSid( Restrictions->Groups[ i ].Sid ) );
CopyTo += RtlLengthSid( Restrictions->Groups[ i ].Sid );
Pac->RestrictionCount++ ;
}
Pac->RestrictionLength = (ULONG) (CopyTo - Base) - Pac->RestrictionOffset ;
}
Pac->NameOffset = (ULONG) ( CopyTo - Base );
Pac->NameLength = LogonSessionData->UserName.Length ;
RtlCopyMemory(
CopyTo,
LogonSessionData->UserName.Buffer,
LogonSessionData->UserName.Length );
CopyTo += LogonSessionData->UserName.Length ;
Pac->DomainLength = LogonSessionData->LogonDomain.Length ;
Pac->DomainOffset = (ULONG) ( CopyTo - Base );
RtlCopyMemory(
CopyTo,
LogonSessionData->LogonDomain.Buffer,
LogonSessionData->LogonDomain.Length );
//
// Someday, maybe, copy credential data here
//
Pac->CredentialLength = 0 ;
Pac->CredentialOffset = 0 ;
CreatePac_Exit:
if ( LogonSessionData )
{
LsaFreeReturnBuffer( LogonSessionData );
}
if ( User )
{
LocalFree( User );
}
if ( Groups )
{
LocalFree( Groups );
}
if ( Restrictions )
{
LocalFree( Restrictions );
}
NtClose( Token );
return Pac ;
}