748 lines
16 KiB
C
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 ;
|
|
|
|
|
|
}
|