mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1936 lines
48 KiB
1936 lines
48 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
context.c
|
|
|
|
Abstract:
|
|
|
|
This file contains services for operating on internal context blocks.
|
|
|
|
|
|
Author:
|
|
|
|
Jim Kelly (JimK) 4-July-1991
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
31 - May 1996 Murlis
|
|
Ported to use the NT5 DS.
|
|
|
|
ChrisMay 10-Jun-96
|
|
Added initialization of Context->ObjectNameInDs and IsDsObject data
|
|
members. Note that this causes context objects to be created with a
|
|
default storage of type registry (instead of DS).
|
|
|
|
6-16-96
|
|
Moved DS object decision to SampCreateContext for account objects.
|
|
|
|
--*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Includes //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <samsrvp.h>
|
|
#include <dslayer.h>
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// private service prototypes //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Context validation services.
|
|
// The service to invalidate a context is visible outside this file and so
|
|
// its prototype is in samsrvp.h.
|
|
//
|
|
|
|
VOID
|
|
SampAddNewValidContextAddress(
|
|
IN PSAMP_OBJECT NewContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SampValidateContextAddress(
|
|
IN PSAMP_OBJECT Context
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
SampCheckIfObjectExists(
|
|
IN PSAMP_OBJECT Context
|
|
);
|
|
|
|
BOOLEAN
|
|
SampIsObjectLocated(
|
|
IN PSAMP_OBJECT Context
|
|
);
|
|
|
|
NTSTATUS
|
|
SampLocateObject(
|
|
IN PSAMP_OBJECT Context,
|
|
IN ULONG Rid
|
|
);
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PSAMP_OBJECT
|
|
SampCreateContext(
|
|
IN SAMP_OBJECT_TYPE Type,
|
|
IN BOOLEAN TrustedClient
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service creates a new object context block of the specified type.
|
|
|
|
If the context block is for either a user or group object type, then
|
|
it will be added to the list of contexts for the transaction domain.
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Upon return:
|
|
|
|
- The ObjectType field will be set to the passed value.
|
|
|
|
- The Reference count field will be set to 1,
|
|
|
|
- The GrantedAccess field will be zero.
|
|
|
|
- The TrustedClient field will be set according to the passed
|
|
value.
|
|
|
|
- The Valid flag will be TRUE.
|
|
|
|
All other fields must be filled in by the creator.
|
|
|
|
|
|
Arguments:
|
|
|
|
Type - Specifies the type of context block being created.
|
|
|
|
TrustedClient - Indicates whether the client is a trusted component
|
|
of the operating syste. If so, than all access checks are
|
|
circumvented.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Non-Null - Pointer to a context block.
|
|
|
|
NULL - Insufficient resources. No context block allocated.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PSAMP_OBJECT Context;
|
|
|
|
SAMTRACE("SampCreateContext");
|
|
|
|
if (!TrustedClient) {
|
|
if (SampActiveContextCount >= SAMP_MAXIMUM_ACTIVE_CONTEXTS) {
|
|
return(NULL);
|
|
}
|
|
|
|
SampActiveContextCount += 1;
|
|
}
|
|
|
|
|
|
Context = MIDL_user_allocate( sizeof(SAMP_OBJECT) );
|
|
if (Context != NULL) {
|
|
|
|
#if SAMP_DIAGNOSTICS
|
|
IF_SAMP_GLOBAL( CONTEXT_TRACKING ) {
|
|
SampDiagPrint( CONTEXT_TRACKING, ("Creating ") );
|
|
if (Type == SampServerObjectType) SampDiagPrint(CONTEXT_TRACKING, ("Server "));
|
|
if (Type == SampDomainObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Domain "));
|
|
if (Type == SampGroupObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Group "));
|
|
if (Type == SampAliasObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Alias "));
|
|
if (Type == SampUserObjectType) SampDiagPrint(CONTEXT_TRACKING, (" User "));
|
|
SampDiagPrint(CONTEXT_TRACKING, ("context : 0x%lx\n", Context ));
|
|
}
|
|
#endif //SAMP_DIAGNOSTICS
|
|
|
|
|
|
Context->ObjectType = Type;
|
|
Context->ReferenceCount = 1; // Represents RPCs held context handle value
|
|
Context->GrantedAccess = 0;
|
|
|
|
Context->RootKey = INVALID_HANDLE_VALUE;
|
|
RtlInitUnicodeString(&Context->RootName, NULL);
|
|
|
|
Context->TrustedClient = TrustedClient;
|
|
Context->MarkedForDelete = FALSE;
|
|
Context->AuditOnClose = FALSE;
|
|
|
|
Context->OnDisk = NULL;
|
|
Context->OnDiskAllocated = 0;
|
|
Context->FixedValid = FALSE;
|
|
Context->VariableValid = FALSE;
|
|
|
|
//
|
|
// The following are meaningless at this point because of the
|
|
// values of the variables above, but we'll set them just to be
|
|
// neat.
|
|
//
|
|
|
|
Context->FixedDirty = FALSE;
|
|
Context->VariableDirty = FALSE;
|
|
|
|
Context->OnDiskUsed = 0;
|
|
Context->OnDiskFree = 0;
|
|
|
|
//
|
|
// Inititialize the IsDSObject to Registry Object and
|
|
// Object Name in DS to NULL. Later we will find out where
|
|
// the Object should actually exist
|
|
//
|
|
|
|
SetRegistryObject(Context);
|
|
Context->ObjectNameInDs = NULL;
|
|
|
|
//
|
|
// Add this new context to the set of valid contexts ...
|
|
//
|
|
|
|
SampAddNewValidContextAddress( Context );
|
|
|
|
|
|
//
|
|
// User and group context blocks are kept on linked lists
|
|
// from the domain's in-memory structure. Insert in the
|
|
// Appropriate List and then additionally for Account Objects
|
|
// Make the DS/Registry decision by looking at the TransactionDomain
|
|
//
|
|
|
|
|
|
Context->DomainIndex = SampTransactionDomainIndex;
|
|
|
|
switch (Type) {
|
|
|
|
case SampDomainObjectType:
|
|
InitializeListHead(
|
|
&(Context->TypeBody.Domain.DsEnumerationContext));
|
|
//////////////////////////////////////////////////////
|
|
// //
|
|
// Warning This case falls into the next one //
|
|
// //
|
|
//////////////////////////////////////////////////////
|
|
case SampServerObjectType:
|
|
|
|
InsertTailList(
|
|
&SampContextListHead,
|
|
&Context->ContextListEntry
|
|
);
|
|
break;
|
|
|
|
case SampUserObjectType:
|
|
|
|
// We must have set the Transaction Domain
|
|
ASSERT(SampTransactionWithinDomain);
|
|
|
|
// Set the DS or Registry Object Part
|
|
if (IsDsObject(SampDefinedDomains[SampTransactionDomainIndex].Context))
|
|
SetDsObject(Context);
|
|
|
|
// Insert into List
|
|
InsertTailList(
|
|
&SampDefinedDomains[SampTransactionDomainIndex].UserContextHead,
|
|
&Context->ContextListEntry
|
|
);
|
|
break;
|
|
|
|
case SampGroupObjectType:
|
|
|
|
// We must have set the Transaction Domain
|
|
ASSERT(SampTransactionWithinDomain);
|
|
|
|
// Set the DS or Registry Object Part
|
|
if (IsDsObject(SampDefinedDomains[SampTransactionDomainIndex].Context))
|
|
SetDsObject(Context);
|
|
|
|
// Insert into List
|
|
InsertTailList(
|
|
&SampDefinedDomains[SampTransactionDomainIndex].GroupContextHead,
|
|
&Context->ContextListEntry
|
|
);
|
|
break;
|
|
|
|
case SampAliasObjectType:
|
|
|
|
// We must have set the Transaction Domain
|
|
ASSERT(SampTransactionWithinDomain);
|
|
|
|
// Set the DS or Registry Object Part
|
|
if (IsDsObject(SampDefinedDomains[SampTransactionDomainIndex].Context))
|
|
SetDsObject(Context);
|
|
|
|
// Insert into List
|
|
InsertTailList(
|
|
&SampDefinedDomains[SampTransactionDomainIndex].AliasContextHead,
|
|
&Context->ContextListEntry
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(Context);
|
|
}
|
|
|
|
|
|
VOID
|
|
SampDeleteContext(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service marks a context object for delete and dereferences it.
|
|
If this causes the reference count to go to zero, then the context
|
|
block will be immediately deleted (deallocated). Otherwise, the
|
|
context block will be deleted when the reference count finally does
|
|
go to zero.
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to delete.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS IgnoreStatus;
|
|
|
|
SAMTRACE("SampDeleteContext");
|
|
|
|
Context->MarkedForDelete = TRUE;
|
|
|
|
//
|
|
// Audit the close of this context.
|
|
//
|
|
|
|
(VOID) NtCloseObjectAuditAlarm (
|
|
&SampSamSubsystem,
|
|
(PVOID)Context,
|
|
Context->AuditOnClose
|
|
);
|
|
|
|
//
|
|
// Remove this context from the valid context set.
|
|
// Note that the context may have already been removed. This is
|
|
// not an error.
|
|
//
|
|
|
|
SampInvalidateContextAddress( Context );
|
|
|
|
|
|
//
|
|
// User and group context blocks are kept on linked lists
|
|
// from the domain's in-memory structure. Domain and
|
|
// server context blocks are kept on a global in-memory list.
|
|
// They are removed when they are marked for delete.
|
|
//
|
|
|
|
RemoveEntryList(&Context->ContextListEntry);
|
|
|
|
//
|
|
// We have to call dereference to counter the initial count of 1
|
|
// put on by create.
|
|
//
|
|
|
|
IgnoreStatus = SampDeReferenceContext( Context, FALSE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampLookupContext(
|
|
IN PSAMP_OBJECT Context,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN SAMP_OBJECT_TYPE ExpectedType,
|
|
OUT PSAMP_OBJECT_TYPE FoundType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service:
|
|
|
|
- Checks to make sure the Service state is one in which an
|
|
object can be looked up (i.e., not Initializing or Terminating).
|
|
|
|
- Makes sure the Service state is compatible with the lookup.
|
|
Non-trusted clients can only perform lookups when the Service
|
|
state is Enabled. If the client isn't trusted and the context
|
|
is for a group or user, then the state of that object's domain
|
|
must also be enabled
|
|
|
|
- Checks to make sure the context block represents the
|
|
type of object expected, and, if so:
|
|
|
|
- Checks to see that the caller has the requested (desired)
|
|
access, and, if so:
|
|
|
|
- Makes sure the object still exists, and opens it if it
|
|
does. Servers and domains can't be deleted, and so
|
|
their handle is left open.
|
|
|
|
- References the context block
|
|
|
|
|
|
Note that if the block is marked as TrustedClient, then access will
|
|
always be granted unless service state prevents it.
|
|
|
|
Also, if the ExpectedType is specified to be unknown, then any type
|
|
of context will be accepted.
|
|
|
|
|
|
|
|
If the type of object is found to be , Domain, Group or User, then the
|
|
this service will set the transaction domain.
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to look-up.
|
|
|
|
DesiredAccess - The type of access the client is requesting to this
|
|
object. A zero-valued access mask may be specified. In this case,
|
|
the calling routine must do access validation.
|
|
|
|
ExpectedType - The type of object expected. This may be unknown. In
|
|
this case, the DesiredAccess should only include access types that
|
|
apply to any type of object (e.g., Delete, WriteDacl, et cetera).
|
|
|
|
FoundType - Receives the type of context actually found.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The context was found to be the type expected (or any
|
|
type if ExpectedType was unknown) and the DesiredAccesses are all
|
|
granted.
|
|
|
|
STATUS_OBJECT_TYPE_MISMATCH - Indicates the context was not the expected
|
|
type.
|
|
|
|
STATUS_ACCESS_DENIED - The desired access is not granted by this context.
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
SAMTRACE("SampLookupContext");
|
|
|
|
|
|
//
|
|
// Make sure we are in a legitimate state to at least access
|
|
// a context block. If we are initializing we have somehow allowed
|
|
// a connect through. This should never happen.
|
|
// If we are terminating, clients may still have handles (since we
|
|
// have no way to tell RPC they are no longer valid without the client
|
|
// calling us, Argh!). However, since we are terminating, the blocks
|
|
// are being cleaned up and may no longer be allocated.
|
|
//
|
|
|
|
ASSERT( SampServiceState != SampServiceInitializing );
|
|
if ( SampServiceState == SampServiceTerminating ) {
|
|
return(STATUS_INVALID_SERVER_STATE);
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the passed context address is (still) valid.
|
|
//
|
|
|
|
NtStatus = SampValidateContextAddress( Context );
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Check type
|
|
//
|
|
|
|
(*FoundType) = Context->ObjectType;
|
|
if (ExpectedType != SampUnknownObjectType) {
|
|
if (ExpectedType != (*FoundType)) {
|
|
return(STATUS_OBJECT_TYPE_MISMATCH);
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the object is either user or group, then we need to set the
|
|
// transaction domain.
|
|
|
|
if ((Context->ObjectType == SampDomainObjectType) ||
|
|
(Context->ObjectType == SampGroupObjectType) ||
|
|
(Context->ObjectType == SampAliasObjectType) ||
|
|
(Context->ObjectType == SampUserObjectType) ) {
|
|
|
|
SampSetTransactionDomain( Context->DomainIndex );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// If the client isn't trusted, then there are a number of things
|
|
// that will prevent them from continuing...
|
|
//
|
|
|
|
// If the service isn't enabled, we allow trusted clients to continue,
|
|
// but reject non-trusted client lookups.
|
|
//
|
|
|
|
if ( !Context->TrustedClient ) {
|
|
|
|
//
|
|
// The SAM service must be enabled
|
|
//
|
|
|
|
if (SampServiceState != SampServiceEnabled) {
|
|
return(STATUS_INVALID_SERVER_STATE);
|
|
}
|
|
|
|
|
|
//
|
|
// If the access is to a USER or GROUP and the client isn't trusted
|
|
// then the domain must be enabled or the operation is rejected.
|
|
//
|
|
|
|
if ( (Context->ObjectType == SampUserObjectType) ||
|
|
(Context->ObjectType == SampAliasObjectType) ||
|
|
(Context->ObjectType == SampGroupObjectType) ) {
|
|
if (SampDefinedDomains[Context->DomainIndex].CurrentFixed.ServerState
|
|
!= DomainServerEnabled) {
|
|
return(STATUS_INVALID_DOMAIN_STATE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Check the desired access ...
|
|
//
|
|
// There are several special cases:
|
|
//
|
|
// 1) The client is trusted. This is granted with no access check
|
|
// or role consistency check.
|
|
//
|
|
// 2) The caller specified 0 for desired access. This is used
|
|
// to close handles and is granted with no access check.
|
|
//
|
|
// 3) The role of the domain (for domain object operations) is
|
|
// inconsistent with the desired access.
|
|
//
|
|
//
|
|
|
|
if ( (!Context->TrustedClient) ) {
|
|
|
|
if (DesiredAccess != 0) {
|
|
|
|
if (!RtlAreAllAccessesGranted( Context->GrantedAccess, DesiredAccess)) {
|
|
return(STATUS_ACCESS_DENIED);
|
|
}
|
|
}
|
|
|
|
if ( (Context->ObjectType == SampDomainObjectType) ||
|
|
(Context->ObjectType == SampGroupObjectType) ||
|
|
(Context->ObjectType == SampAliasObjectType) ||
|
|
(Context->ObjectType == SampUserObjectType)
|
|
) {
|
|
//
|
|
// The state of the domain may have changed while the caller had
|
|
// the object open. In this case, the granted access mask may
|
|
// provide a write operation, but the role of the domain no longer
|
|
// allows un-trusted clients to perform write operations.
|
|
//
|
|
// Yuch.
|
|
//
|
|
|
|
if (SampDefinedDomains[Context->DomainIndex].CurrentFixed.ServerRole
|
|
!= DomainServerRolePrimary) {
|
|
|
|
if (RtlAreAnyAccessesGranted(
|
|
SampObjectInformation[ Context->ObjectType ].WriteOperations,
|
|
DesiredAccess) ) {
|
|
return(STATUS_INVALID_DOMAIN_ROLE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Make sure the object is still around (that is, somebody didn't delete
|
|
// it right out from under us).
|
|
//
|
|
|
|
NtStatus = SampCheckIfObjectExists(Context);
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Reference the context
|
|
//
|
|
|
|
Context->ReferenceCount ++;
|
|
}
|
|
|
|
|
|
return(NtStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SampReferenceContext(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service increments a context block's reference count.
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to dreference.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
SAMTRACE("SampReferenceContext");
|
|
|
|
Context->ReferenceCount++;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDeReferenceContext(
|
|
IN PSAMP_OBJECT Context,
|
|
IN BOOLEAN Commit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service decrements a context block's reference count.
|
|
If the reference count drops to zero, then the MarkedForDelete
|
|
flag is checked. If it is true, then the context block is
|
|
deallocated.
|
|
|
|
The attribute buffers are always deleted.
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to de-reference.
|
|
|
|
Commit - if TRUE, the attribute buffers will be added to the RXACT.
|
|
Otherwise, they will just be ignored.
|
|
|
|
Return Value:
|
|
|
|
|
|
STATUS_SUCCESS - The service completed successfully.
|
|
|
|
Errors may be returned from SampStoreObjectAttributes().
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus, IgnoreStatus;
|
|
BOOLEAN TrustedClient;
|
|
|
|
SAMTRACE("SampDeReferenceContext");
|
|
|
|
ASSERT( Context->ReferenceCount != 0 );
|
|
Context->ReferenceCount --;
|
|
|
|
TrustedClient = Context->TrustedClient;
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
if ( Context->OnDisk != NULL ) {
|
|
|
|
//
|
|
// There are attribute buffers for this context. Flush them if
|
|
// asked to do so.
|
|
// Use existing open keys
|
|
//
|
|
|
|
if ( Commit ) {
|
|
|
|
NtStatus = SampStoreObjectAttributes(Context, TRUE);
|
|
|
|
#if DBG
|
|
//
|
|
// SampFreeAttributeBuffer will assert if we try to free dirty
|
|
// buffers. This is generally useful, but if we're aborting
|
|
// (which is this case, Commit = FALSE) we don't want the assert
|
|
// so avoid it by pretending the buffers aren't dirty.
|
|
//
|
|
|
|
} else {
|
|
|
|
Context->FixedDirty = FALSE;
|
|
Context->VariableDirty = FALSE;
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Free the buffer that was being used to hold attributes.
|
|
//
|
|
|
|
SampFreeAttributeBuffer( Context );
|
|
}
|
|
|
|
if (Context->ReferenceCount == 0) {
|
|
|
|
//
|
|
// ReferenceCount has dropped to 0, see if we should delete this
|
|
// context.
|
|
//
|
|
|
|
if (Context->MarkedForDelete == TRUE) {
|
|
|
|
//
|
|
// Close the context block's root key.
|
|
// Domain and server contexts contain root key
|
|
// handles that are shared - so don't clean-up these
|
|
// if they match the ones in memory.
|
|
//
|
|
|
|
switch (Context->ObjectType) {
|
|
|
|
case SampServerObjectType:
|
|
|
|
if ((Context->RootKey != SampKey) &&
|
|
(Context->RootKey != INVALID_HANDLE_VALUE)) {
|
|
|
|
IgnoreStatus = NtClose( Context->RootKey );
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
}
|
|
break;
|
|
|
|
case SampDomainObjectType:
|
|
if (IsDsObject(Context))
|
|
{
|
|
|
|
// Free Any enumeration Context's
|
|
|
|
LIST_ENTRY * EnumerationList= (LIST_ENTRY *)
|
|
&(Context->TypeBody.Domain.DsEnumerationContext);
|
|
LIST_ENTRY * CurrentItem = EnumerationList->Flink ;
|
|
|
|
|
|
while(!IsListEmpty(EnumerationList))
|
|
{
|
|
LIST_ENTRY * ListItem;
|
|
|
|
ListItem = RemoveTailList(EnumerationList);
|
|
SampFreeRestart(((PSAMP_DS_ENUMERATION_CONTEXT)
|
|
ListItem)->Restart);
|
|
MIDL_user_free(ListItem);
|
|
}
|
|
|
|
// Free the DsName
|
|
MIDL_user_free(Context->ObjectNameInDs);
|
|
Context->ObjectNameInDs = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// Free all the Key Stuff
|
|
if ((Context->RootKey != SampDefinedDomains[Context->DomainIndex].Context->RootKey) &&
|
|
(Context->RootKey != INVALID_HANDLE_VALUE))
|
|
{
|
|
|
|
IgnoreStatus = NtClose( Context->RootKey );
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (IsDsObject(Context))
|
|
{
|
|
// Free the DSName
|
|
MIDL_user_free(Context->ObjectNameInDs);
|
|
Context->ObjectNameInDs = NULL;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Close the root key handle
|
|
//
|
|
|
|
if (Context->RootKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
|
|
IgnoreStatus = NtClose( Context->RootKey );
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
}
|
|
|
|
//
|
|
// Free the root key name
|
|
//
|
|
|
|
SampFreeUnicodeString( &(Context->RootName) );
|
|
}
|
|
}
|
|
|
|
|
|
#if SAMP_DIAGNOSTICS
|
|
IF_SAMP_GLOBAL( CONTEXT_TRACKING ) {
|
|
SampDiagPrint( CONTEXT_TRACKING, ("Deallocating ") );
|
|
if (Context->ObjectType == SampServerObjectType) SampDiagPrint(CONTEXT_TRACKING, ("Server "));
|
|
if (Context->ObjectType == SampDomainObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Domain "));
|
|
if (Context->ObjectType == SampGroupObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Group "));
|
|
if (Context->ObjectType == SampAliasObjectType) SampDiagPrint(CONTEXT_TRACKING, (" Alias "));
|
|
if (Context->ObjectType == SampUserObjectType) SampDiagPrint(CONTEXT_TRACKING, (" User "));
|
|
SampDiagPrint(CONTEXT_TRACKING, ("context : 0x%lx\n", Context ));
|
|
}
|
|
#endif //SAMP_DIAGNOSTICS
|
|
|
|
MIDL_user_free( Context );
|
|
|
|
|
|
|
|
//
|
|
// Decrement the number of active opens
|
|
//
|
|
|
|
if (!TrustedClient) {
|
|
ASSERT( SampActiveContextCount >= 1 );
|
|
SampActiveContextCount -= 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Make sure a commit worked.
|
|
//
|
|
|
|
if (Commit) {
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
SampDiagPrint(DISPLAY_STORAGE_FAIL,
|
|
("SAM: Commit failure, status: 0x%lx\n",
|
|
NtStatus) );
|
|
IF_SAMP_GLOBAL( BREAK_ON_STORAGE_FAIL ) {
|
|
ASSERT(NT_SUCCESS(NtStatus));
|
|
}
|
|
}
|
|
}
|
|
#endif //DBG
|
|
|
|
|
|
return( NtStatus );
|
|
}
|
|
|
|
|
|
VOID
|
|
SampInvalidateContextAddress(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service removes a context from the set of valid contexts.
|
|
|
|
Note that we may have already removed the context. This is not an
|
|
error is expected to happen in the case where an object (like a user
|
|
or group) is deleted out from under an open handle.
|
|
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to be removed from the set
|
|
of valid contexts. The ObjectType field of this context must
|
|
be valid.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
SAMTRACE("SampInvalidateContextAddress");
|
|
|
|
|
|
ASSERT( (Context->ObjectType == SampUserObjectType) ||
|
|
(Context->ObjectType == SampGroupObjectType) ||
|
|
(Context->ObjectType == SampAliasObjectType) ||
|
|
(Context->ObjectType == SampDomainObjectType) ||
|
|
(Context->ObjectType == SampServerObjectType)
|
|
);
|
|
|
|
Context->Valid = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampInvalidateGroupContexts(
|
|
IN ULONG Rid
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service marks all group contexts open to the specified
|
|
group as being invalid. This is typically done because the
|
|
object has been deleted while there were open handles. All
|
|
registry keys related to this context are closed.
|
|
|
|
This is done by walking the list of group contexts hung off
|
|
the permanent in-memory domain structure.
|
|
|
|
THIS IS AN IRRIVERSIBLE OPERATION.
|
|
|
|
|
|
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Rid - The RID of the group being invalidated.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS IgnoreStatus;
|
|
PLIST_ENTRY Head, NextEntry;
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
|
|
SAMTRACE("SampInvalidateGroupContexts");
|
|
|
|
|
|
Head = &SampDefinedDomains[SampTransactionDomainIndex].GroupContextHead;
|
|
|
|
//
|
|
// Walk the list of active contexts checking for RID matches
|
|
//
|
|
|
|
NextEntry = Head->Flink;
|
|
|
|
while (NextEntry != Head) {
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
if ( (Rid == NextContext->TypeBody.Group.Rid) &&
|
|
(NextContext->Valid == TRUE)
|
|
) {
|
|
NextContext->Valid = FALSE;
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Invalidating group context 0x%lx : <%wZ>, handle = 0x%lx\n", NextContext, &NextContext->RootName, NextContext->RootKey));
|
|
|
|
if (NextContext->RootKey != INVALID_HANDLE_VALUE) {
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Closing handle 0x%lx\n", NextContext->RootKey));
|
|
|
|
IgnoreStatus = NtClose(NextContext->RootKey);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
NextContext->RootKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampInvalidateAliasContexts(
|
|
IN ULONG Rid
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service marks all alias contexts open to the specified
|
|
alias as being invalid. This is typically done because the
|
|
object has been deleted while there were open handles. All
|
|
registry keys related to this context are closed.
|
|
|
|
This is done by walking the list of alias contexts hung off
|
|
the permanent in-memory domain structure.
|
|
|
|
THIS IS AN IRRIVERSIBLE OPERATION.
|
|
|
|
|
|
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Rid - The RID of the alias being invalidated.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS IgnoreStatus;
|
|
PLIST_ENTRY Head, NextEntry;
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
|
|
SAMTRACE("SampInvalidateAliasContexts");
|
|
|
|
|
|
Head = &SampDefinedDomains[SampTransactionDomainIndex].AliasContextHead;
|
|
|
|
//
|
|
// Walk the list of active contexts checking for RID matches
|
|
//
|
|
|
|
NextEntry = Head->Flink;
|
|
|
|
while (NextEntry != Head) {
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
if ( (Rid == NextContext->TypeBody.Alias.Rid) &&
|
|
(NextContext->Valid == TRUE)
|
|
) {
|
|
NextContext->Valid = FALSE;
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Invalidating alias context 0x%lx : <%wZ>, handle = 0x%lx\n", NextContext, &NextContext->RootName, NextContext->RootKey));
|
|
|
|
if (NextContext->RootKey != INVALID_HANDLE_VALUE) {
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Closing handle 0x%lx\n", NextContext->RootKey));
|
|
|
|
IgnoreStatus = NtClose(NextContext->RootKey);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
NextContext->RootKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SampInvalidateUserContexts(
|
|
IN ULONG Rid
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service marks all group contexts open to the specified
|
|
group as being invalid. This is typically done because the
|
|
object has been deleted while there were open handles. All
|
|
registry keys related to this context are closed.
|
|
|
|
|
|
This is done by walking the list of group contexts hung off
|
|
the permanent in-memory domain structure.
|
|
|
|
|
|
THIS IS AN IRRIVERSIBLE OPERATION.
|
|
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Rid - The RID of the group being invalidated.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS IgnoreStatus;
|
|
PLIST_ENTRY Head, NextEntry;
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
|
|
SAMTRACE("SampInvalidateUserContexts");
|
|
|
|
|
|
Head = &SampDefinedDomains[SampTransactionDomainIndex].UserContextHead;
|
|
|
|
//
|
|
// Walk the list of active contexts checking for RID matches
|
|
//
|
|
|
|
NextEntry = Head->Flink;
|
|
|
|
while (NextEntry != Head) {
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
if ( (Rid == NextContext->TypeBody.User.Rid) &&
|
|
(NextContext->Valid == TRUE)
|
|
) {
|
|
NextContext->Valid = FALSE;
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Invalidating user context 0x%lx : <%wZ>, handle = 0x%lx\n", NextContext, &NextContext->RootName, NextContext->RootKey));
|
|
|
|
if (NextContext->RootKey != INVALID_HANDLE_VALUE) {
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Closing handle 0x%lx\n", NextContext->RootKey));
|
|
|
|
IgnoreStatus = NtClose(NextContext->RootKey);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
NextContext->RootKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SampInvalidateContextListKeys(
|
|
IN PLIST_ENTRY Head,
|
|
IN BOOLEAN Close
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Marks all registry handles invalid in the contexts in the passed list.
|
|
Used after a registry hive refresh.
|
|
|
|
Arguments:
|
|
|
|
Close : If TRUE the registry handles are closed before invalidation
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS IgnoreStatus;
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
SAMTRACE("SampInvalidateContextListKeys");
|
|
|
|
NextEntry = Head->Flink;
|
|
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Invalidating key for context 0x%lx : <%wZ>, handle = 0x%lx\n", NextContext, &NextContext->RootName, NextContext->RootKey));
|
|
|
|
if (Close && (NextContext->RootKey != INVALID_HANDLE_VALUE)) {
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Closing handle 0x%lx\n", NextContext->RootKey));
|
|
|
|
IgnoreStatus = NtClose( NextContext->RootKey );
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
}
|
|
|
|
NextContext->RootKey = INVALID_HANDLE_VALUE;
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef SAMP_DIAGNOSTICS
|
|
VOID
|
|
SampDumpContext(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service prints out info on a context to debugger
|
|
|
|
Arguments:
|
|
|
|
Context - a context
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
PSTR Type;
|
|
|
|
switch (Context->ObjectType) {
|
|
case SampServerObjectType:
|
|
Type = "S";
|
|
break;
|
|
case SampDomainObjectType:
|
|
if (Context == SampDefinedDomains[Context->DomainIndex].Context) {
|
|
Type = "d";
|
|
} else {
|
|
Type = "D";
|
|
}
|
|
break;
|
|
case SampUserObjectType:
|
|
Type = "U";
|
|
break;
|
|
case SampAliasObjectType:
|
|
Type = "A";
|
|
break;
|
|
case SampGroupObjectType:
|
|
Type = "G";
|
|
break;
|
|
}
|
|
|
|
KdPrint(("%s 0x%8x %2d 0x%8x %s %s %s %wZ\n",
|
|
Type,
|
|
Context,
|
|
Context->ReferenceCount,
|
|
Context->RootKey,
|
|
Context->MarkedForDelete ? "D": " ",
|
|
Context->Valid ? " ": "NV",
|
|
Context->TrustedClient ? "TC": " ",
|
|
&Context->RootName
|
|
));
|
|
}
|
|
|
|
|
|
VOID
|
|
SampDumpContexts(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints out info on all contexts
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PLIST_ENTRY Head;
|
|
ULONG Servers;
|
|
ULONG Domains;
|
|
ULONG Domain0Users;
|
|
ULONG Domain0Aliases;
|
|
ULONG Domain0Groups;
|
|
ULONG Domain1Users;
|
|
ULONG Domain1Aliases;
|
|
ULONG Domain1Groups;
|
|
|
|
Domains = 0;
|
|
Servers = 0;
|
|
|
|
Head = &SampContextListHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
switch (NextContext->ObjectType) {
|
|
case SampServerObjectType:
|
|
(Servers)++;
|
|
break;
|
|
case SampDomainObjectType:
|
|
(Domains)++;
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
|
|
|
|
Domain0Users = 0;
|
|
Head = &SampDefinedDomains[0].UserContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain0Users) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampUserObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
Domain1Users = 0;
|
|
Head = &SampDefinedDomains[1].UserContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain1Users) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampUserObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
Domain0Groups = 0;
|
|
Head = &SampDefinedDomains[0].GroupContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain0Groups) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampGroupObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
Domain1Groups = 0;
|
|
Head = &SampDefinedDomains[1].GroupContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain1Groups) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampGroupObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
Domain0Aliases = 0;
|
|
Head = &SampDefinedDomains[0].AliasContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain0Aliases) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampAliasObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
Domain1Aliases = 0;
|
|
Head = &SampDefinedDomains[1].AliasContextHead;
|
|
NextEntry = Head->Flink;
|
|
while (NextEntry != Head) {
|
|
|
|
PSAMP_OBJECT NextContext;
|
|
|
|
(Domain1Aliases) ++;
|
|
|
|
NextContext = CONTAINING_RECORD(
|
|
NextEntry,
|
|
SAMP_OBJECT,
|
|
ContextListEntry
|
|
);
|
|
|
|
ASSERT (NextContext->ObjectType == SampAliasObjectType);
|
|
|
|
SampDumpContext(NextContext);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
|
|
KdPrint(("SAM: Active untrusted contexts = %d\n", SampActiveContextCount));
|
|
KdPrint((" Server = %4d Domain = %4d\n", Servers, Domains));
|
|
KdPrint((" Users0 = %4d Groups0 = %4d Aliases0 = %4d\n", Domain0Users, Domain0Aliases, Domain0Groups));
|
|
KdPrint((" Users1 = %4d Groups1 = %4d Aliases1 = %4d\n", Domain1Users, Domain1Aliases, Domain1Groups));
|
|
|
|
|
|
|
|
}
|
|
#endif //SAMP_DIAGNOSTICS
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// private service Implementations //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
SampAddNewValidContextAddress(
|
|
IN PSAMP_OBJECT NewContext
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service adds the new context to the set of valid contexts.
|
|
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
NewContext - Pointer to the context block to be added to the set
|
|
of valid contexts. The ObjectType field of this context must
|
|
be set.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
SAMTRACE("SampAddNewValidContextAddress");
|
|
|
|
ASSERT( (NewContext->ObjectType == SampUserObjectType) ||
|
|
(NewContext->ObjectType == SampGroupObjectType) ||
|
|
(NewContext->ObjectType == SampAliasObjectType) ||
|
|
(NewContext->ObjectType == SampDomainObjectType) ||
|
|
(NewContext->ObjectType == SampServerObjectType)
|
|
);
|
|
|
|
|
|
NewContext->Valid = TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampValidateContextAddress(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This service checks to make sure a context is still valid.
|
|
|
|
Note that even though RPC still thinks we have a context related
|
|
to a SAM_HANDLE, we may, in fact, have deleted it out from under
|
|
the user. Since there is no way to inform RPC of this, we must
|
|
suffer, and wait until RPC calls us (either with a call by the client
|
|
or to rundown the context handle). This sucks, but there apparently
|
|
isn't any other way around it.
|
|
|
|
|
|
|
|
WARNING - IT IS ASSUMED THE CONTEXT WAS ONCE VALID. IT MAY HAVE
|
|
BEEN INVALIDATED, BUT IF YOU ARE CALLING THIS ROUTINE
|
|
IT BETTER STILL HAVE A NON-ZERO REFERENCE COUNT. THIS
|
|
COULD BE CHANGED IN THE FUTURE, BUT IT WOULD REQUIRE
|
|
KEEPING A LIST OF VALID DOMAINS AND PERFORMING THE BULK
|
|
OF THIS ROUTINE INSIDE A TRY-EXCEPT CLAUSE. YOU COULD
|
|
LOCATE THE CONTEXT'S DOMAIN (WHICH MIGHT ACCESS VIOLATE)
|
|
AND THEN MAKE SURE THAT DOMAIN IS VALID. THEN WALK THAT
|
|
DOMAIN'S LIST TO ENSURE THE USER OR GROUP IS VALID.
|
|
|
|
THIS SERVICE MUST BE CALLED WITH THE SampLock HELD FOR WRITE ACCESS.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context block to be validated as still being
|
|
a valid context. The ObjectType field of this context must
|
|
be valid.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The context is still valid.
|
|
|
|
STATUS_INVALID_HANDLE - The context is no longer valid and the handle
|
|
that caused the reference should be invalidated as well. When the
|
|
handle is invalidated, the context should be closed (deleted).
|
|
|
|
STATUS_NO_SUCH_CONTEXT - This value is not yet returned by this routine.
|
|
It may be added in the future to distinguish between an attempt to
|
|
use a context that has been invalidated and an attempt to use a
|
|
context that doesn't exist. The prior being a legitimate condition,
|
|
the later representing a bug-check condition.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
SAMTRACE("SampValidateContextAddress");
|
|
|
|
ASSERT( (Context->ObjectType == SampUserObjectType) ||
|
|
(Context->ObjectType == SampGroupObjectType) ||
|
|
(Context->ObjectType == SampAliasObjectType) ||
|
|
(Context->ObjectType == SampDomainObjectType) ||
|
|
(Context->ObjectType == SampServerObjectType)
|
|
);
|
|
|
|
|
|
if (Context->Valid != TRUE) {
|
|
return(STATUS_INVALID_HANDLE);
|
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
SampCheckIfObjectExists(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks to see if the object exists in the DS/ Registry.
|
|
Will fill out the following information
|
|
|
|
1. If DS object its DSNAME, which must exist
|
|
2. If Registry object, Open its Root Key and fill out
|
|
the handle of the Root Key in the registry.
|
|
|
|
IMPORTANT NOTE:
|
|
|
|
In the Registry Case of SAM once the key is open nobody can
|
|
delete the object. However in the DS case this is not so. Currently
|
|
we have only the DS Name of the Object in Hand, and we have no way
|
|
of Locking the Object, for access. Since this is the case
|
|
|
|
Arguments:
|
|
Context -- Pointer to a Context block desribing the Object
|
|
Rid -- Rid of the desired Object
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS if everything succeeds
|
|
Error codes from Registry Manipulation / DsLayer.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
ULONG Rid;
|
|
|
|
|
|
|
|
//
|
|
// Check wether the Object is located or not.
|
|
// Location is the process of finding out
|
|
// 1. DSNAME of the object if it is in the DS. An object with this
|
|
// DSNAME must exist.
|
|
//
|
|
// 2. The Root Key HANDLE of the Object if it is in the Registry
|
|
//
|
|
|
|
if (!SampIsObjectLocated(Context)) {
|
|
|
|
//
|
|
// No we first need to locate the Object.
|
|
// This is done by using the Rid for Account Objects
|
|
// For Domain Objects we already cache all the defined domains, so fill out
|
|
// From the Cache
|
|
// BUG: For Server Objects Don't know what to do.
|
|
//
|
|
|
|
switch (Context->ObjectType) {
|
|
|
|
case SampGroupObjectType:
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Reopened group handle <%wZ>,", &Context->RootName));
|
|
Rid = Context->TypeBody.Group.Rid;
|
|
break;
|
|
|
|
case SampAliasObjectType:
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Reopened alias handle <%wZ>,", &Context->RootName));
|
|
Rid = Context->TypeBody.Alias.Rid;
|
|
break;
|
|
|
|
case SampUserObjectType:
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Reopened user handle <%wZ>,", &Context->RootName));
|
|
Rid = Context->TypeBody.User.Rid;
|
|
break;
|
|
|
|
case SampDomainObjectType:
|
|
|
|
//
|
|
// Domain objects share the root key and the object name in the DS that
|
|
// we keep around in the in memory domain context for each domain
|
|
//
|
|
|
|
|
|
ASSERT(Context != SampDefinedDomains[Context->DomainIndex].Context);
|
|
|
|
Context->RootKey = SampDefinedDomains[Context->DomainIndex].Context->RootKey;
|
|
Context->ObjectNameInDs = SampDefinedDomains[Context->DomainIndex].Context->ObjectNameInDs;
|
|
Context->ObjectNameInDs = SampDefinedDomains[Context->DomainIndex].Context->ObjectNameInDs;
|
|
|
|
ASSERT(SampIsObjectLocated(Context));
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Recopied domain context handle <%wZ>, 0x%lx\n", &Context->RootName, Context->RootKey));
|
|
goto ObjectLocated;
|
|
|
|
case SampServerObjectType:
|
|
|
|
//
|
|
// Server objects share our global root key
|
|
//
|
|
|
|
|
|
Context->RootKey = SampKey;
|
|
ASSERT(SampIsObjectLocated(Context));
|
|
|
|
SampDiagPrint( CONTEXT_TRACKING, ("SAM: Recopied server context handle <%wZ>, 0x%lx\n", &Context->RootName, Context->RootKey));
|
|
goto ObjectLocated;
|
|
}
|
|
|
|
//
|
|
// Go open the appropriate account key/ or find object Name from RID
|
|
//
|
|
|
|
NtStatus = SampLocateObject(Context, Rid);
|
|
|
|
ObjectLocated:
|
|
;;
|
|
|
|
|
|
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SampIsObjectLocated(
|
|
IN PSAMP_OBJECT Context
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
Checks if an object has been located in the DS or in the registry
|
|
An Object being Located implies the Following
|
|
1. For a DS Object we have the DS Name
|
|
2. For a Registry Object we have a Valid Open Registry Key for
|
|
the Object.
|
|
|
|
Arguments:
|
|
Context -- Pointer to a Context block desribing the Object
|
|
|
|
Return Values:
|
|
TRUE -- If Conditions above are satisfied
|
|
FALSE -- If Conditions above are not satisfied
|
|
--*/
|
|
{
|
|
if (IsDsObject(Context))
|
|
return (Context->ObjectNameInDs != NULL);
|
|
else
|
|
return (Context->RootKey != INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampLocateObject(
|
|
IN PSAMP_OBJECT Context,
|
|
IN ULONG Rid
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
Uses the Rid to find the Object in either the DS or
|
|
the Registry.
|
|
|
|
|
|
NOTE:
|
|
This routine is meaningful for Context's that represent
|
|
Account Objects Only.
|
|
|
|
Arguments:
|
|
Context -- Pointer to a Context block desribing the Object
|
|
Rid -- Rid of the desired Object
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS if everything succeeds
|
|
Error codes from Registry Manipulation / DsLayer.
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSAMP_OBJECT DomainContext = NULL;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
|
|
|
|
//
|
|
// This routine can be called only for Account Objects
|
|
//
|
|
|
|
ASSERT((Context->ObjectType == SampGroupObjectType)
|
|
|| (Context->ObjectType == SampAliasObjectType)
|
|
|| (Context->ObjectType == SampUserObjectType)
|
|
);
|
|
|
|
//
|
|
// Get the Domain Object, as we will need this to find out
|
|
// to find out in which domain we look for the Rid.
|
|
//
|
|
DomainContext = SampDefinedDomains[Context->DomainIndex].Context;
|
|
|
|
// Now Make the Decision
|
|
if (IsDsObject(Context))
|
|
{
|
|
//
|
|
// Object is in the DS
|
|
//
|
|
|
|
// Look it up using the Rid
|
|
Status = SampDsLookupObjectByRid(DomainContext->ObjectNameInDs, Rid, &Context->ObjectNameInDs);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Context->ObjectNameInDs = NULL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Object Should be in Registry
|
|
SetRegistryObject(Context);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&Context->RootName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
SampKey,
|
|
NULL
|
|
);
|
|
|
|
SampDumpNtOpenKey((KEY_READ | KEY_WRITE), &ObjectAttributes, 0);
|
|
|
|
// Try opening the Key
|
|
Status = RtlpNtOpenKey(
|
|
&Context->RootKey,
|
|
(KEY_READ | KEY_WRITE),
|
|
&ObjectAttributes,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Context->RootKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|