|
|
//+---------------------------------------------------------------------------
//
// 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 ;
}
|