/*++ Copyright (c) 1996 Microsoft Corporation Module Name: clusnet.c Abstract: Intialization and dispatch routines for the Cluster Network Driver. Author: Mike Massa (mikemas) July 29, 1996 Revision History: Who When What -------- -------- ---------------------------------------------- mikemas 07-29-96 created Notes: --*/ #include "precomp.h" #pragma hdrstop #include "clusnet.tmh" #include // // Global Data // PDRIVER_OBJECT CnDriverObject = NULL; PDEVICE_OBJECT CnDeviceObject = NULL; KSPIN_LOCK CnDeviceObjectStackSizeLock = 0; PDEVICE_OBJECT CdpDeviceObject = NULL; PKPROCESS CnSystemProcess = NULL; CN_STATE CnState = CnStateShutdown; PERESOURCE CnResource = NULL; CL_NODE_ID CnMinValidNodeId = ClusterInvalidNodeId; CL_NODE_ID CnMaxValidNodeId = ClusterInvalidNodeId; CL_NODE_ID CnLocalNodeId = ClusterInvalidNodeId; KSPIN_LOCK CnShutdownLock = 0; BOOLEAN CnShutdownScheduled = FALSE; PKEVENT CnShutdownEvent = NULL; WORK_QUEUE_ITEM CnShutdownWorkItem = {{NULL, NULL}, NULL, NULL}; HANDLE ClussvcProcessHandle = NULL; PSECURITY_DESCRIPTOR CdpAdminSecurityDescriptor = NULL; // // vars for managing Events. The lookaside list generates Event data structs // that are used to carry the data back to user mode. EventLock is the only // lock and synchronizes all access to any event structure (both here and in // CN_FSCONTEXT). EventFileHandles is a list of CN_FSCONTEXT structs that // are interested in receiving event notifications. To avoid synchronization // problems between clusnet and mm in clussvc, events have an epoch associated // with them. MM increments the epoch at the beginning of regroup event and // updates clusnet at the end of regroup. Any events still pending in the // event queue with a stale epoch are ignored by MM. // // EventDeliveryInProgress is a count of threads that are currently // iterating through the EventFileHandles list and delivering events. // The EventFileHandles list cannot be modified while EventDeliveryInProgress // is greater than zero. EventDeliveryComplete is a notification event // that is signalled when the EventDeliveryInProgress count reaches zero. // EventRevisitRequired indicates whether a new event IRP arrived during // event delivery. To avoid delivering events out of order, the IRP cannot // be completed immediately. // PNPAGED_LOOKASIDE_LIST EventLookasideList = NULL; LIST_ENTRY EventFileHandles = {0,0}; #if DBG CN_LOCK EventLock = {0,0}; #else CN_LOCK EventLock = 0; #endif ULONG EventEpoch; LONG EventDeliveryInProgress = 0; KEVENT EventDeliveryComplete; BOOLEAN EventRevisitRequired = FALSE; #if DBG ULONG CnDebug = 0; #endif // DBG // // Private Types // // // Private Data // SECURITY_STATUS SEC_ENTRY SecSetPagingMode( BOOLEAN Pageable ); BOOLEAN SecurityPagingModeSet = FALSE; // // Local Prototypes // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); VOID DriverUnload( IN PDRIVER_OBJECT DriverObject ); NTSTATUS CnCreateDeviceObjects( IN PDRIVER_OBJECT DriverObject ); VOID CnDeleteDeviceObjects( VOID ); VOID CnAdjustDeviceObjectStackSize( PDEVICE_OBJECT ClusnetDeviceObject, PDEVICE_OBJECT TargetDeviceObject ); NTSTATUS CnBuildDeviceAcl( OUT PACL *DeviceAcl ); NTSTATUS CnCreateSecurityDescriptor( VOID ); // // Mark init code as discardable. // #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(INIT, CnCreateDeviceObjects) #pragma alloc_text(INIT, CnCreateSecurityDescriptor) #pragma alloc_text(INIT, CnBuildDeviceAcl) #pragma alloc_text(PAGE, DriverUnload) #pragma alloc_text(PAGE, CnDeleteDeviceObjects) #endif // ALLOC_PRAGMA // // Function definitions // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Initialization routine for the driver. Arguments: DriverObject - Pointer to the driver object created by the system. RegistryPath - The driver's registry key. Return Value: An NT status code. --*/ { NTSTATUS status; USHORT i; #if DBG volatile BOOLEAN DontLoad = FALSE; if ( DontLoad ) return STATUS_UNSUCCESSFUL; #endif IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[ClusNet] Loading...\n")); } WPP_INIT_TRACING(DriverObject, RegistryPath); // // Save a pointer to the system process so that we can open // handles in the context of this process later. // CnSystemProcess = (PKPROCESS) IoGetCurrentProcess(); // // Allocate a synchronization resource. // CnResource = CnAllocatePool(sizeof(ERESOURCE)); if (CnResource == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); } status = ExInitializeResourceLite(CnResource); if (!NT_SUCCESS(status)) { goto error_exit; } // // initialize the mechanisms used to deliver event callbacks // to user mode // EventLookasideList = CnAllocatePool(sizeof(NPAGED_LOOKASIDE_LIST)); if (EventLookasideList == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } ExInitializeNPagedLookasideList(EventLookasideList, NULL, NULL, 0, sizeof( CLUSNET_EVENT_ENTRY ), CN_EVENT_SIGNATURE, 0); CnInitializeLock( &EventLock, CNP_EVENT_LOCK ); InitializeListHead( &EventFileHandles ); KeInitializeEvent( &EventDeliveryComplete, NotificationEvent, TRUE ); // // Initialize miscellaneous other items. // KeInitializeSpinLock(&CnShutdownLock); KeInitializeSpinLock(&CnDeviceObjectStackSizeLock); // // Initialize the driver object // CnDriverObject = DriverObject; DriverObject->DriverUnload = DriverUnload; DriverObject->FastIoDispatch = NULL; for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = CnDispatch; } DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CnDispatchDeviceControl; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = CnDispatchInternalDeviceControl; // // Create all the devices exported by this driver. // status = CnCreateDeviceObjects(DriverObject); if (!NT_SUCCESS(status)) { goto error_exit; } // // Initialize the CDP security descriptor. // status = CnCreateSecurityDescriptor(); if (!NT_SUCCESS(status)) { goto error_exit; } #ifdef MEMLOGGING // // initialize the in-memory log // CnInitializeMemoryLog(); #endif // MEMLOGGING // // Load the IP Address and NetBT support. // This must be done before the transport registers for PnP events. // status = IpaLoad(); if (!NT_SUCCESS(status)) { goto error_exit; } status = NbtIfLoad(); if (!NT_SUCCESS(status)) { goto error_exit; } // // Load the transport component // status = CxLoad(RegistryPath); if (!NT_SUCCESS(status)) { goto error_exit; } #ifdef MM_IN_CLUSNET // // Load the membership component // status = CmmLoad(RegistryPath); if (!NT_SUCCESS(status)) { goto error_exit; } #endif // MM_IN_CLUSNET // // make ksecdd non-pagable so we can sign and verify // signatures at raised IRQL // status = SecSetPagingMode( FALSE ); if (!NT_SUCCESS(status)) { goto error_exit; } SecurityPagingModeSet = TRUE; IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[ClusNet] Loaded.\n")); } return(STATUS_SUCCESS); error_exit: DriverUnload(CnDriverObject); return(status); } VOID DriverUnload( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: Unloads the driver. Arguments: DriverObject - Pointer to the driver object created by the system. Return Value: None --*/ { PAGED_CODE(); IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[ClusNet] Unloading...\n")); } CnTrace(HBEAT_ERROR,0, "[ClusNet] Unloading...\n"); // // First, force a shutdown. // CnShutdown(); // // Now unload the components. // #ifdef MM_IN_CLUSNET CmmUnload(); #endif // MM_IN_CLUSNET CxUnload(); #ifdef MEMLOGGING // // initialize the in-memory log // CnFreeMemoryLog(); #endif // MEMLOGGING if (CdpAdminSecurityDescriptor != NULL) { ExFreePool(CdpAdminSecurityDescriptor); CdpAdminSecurityDescriptor = NULL; } CnDeleteDeviceObjects(); if (CnResource != NULL) { ExDeleteResourceLite(CnResource); CnFreePool(CnResource); CnResource = NULL; } CnDriverObject = NULL; IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[ClusNet] Unloaded.\n")); } if (EventLookasideList != NULL) { ExDeleteNPagedLookasideList( EventLookasideList ); CnFreePool( EventLookasideList ); EventLookasideList = NULL; } // // finally, allow the security driver to return to nonpaged mode // if ( SecurityPagingModeSet ) { SecSetPagingMode( TRUE ); } WPP_CLEANUP(DriverObject); return; } // DriverUnload NTSTATUS CnCreateDeviceObjects( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: Creates the device objects exported by the driver. Arguments: DriverObject - Pointer to the driver object created by the system. Return Value: An NT status code. --*/ { NTSTATUS status; UNICODE_STRING deviceName; // // Create the driver control device // RtlInitUnicodeString(&deviceName, DD_CLUSNET_DEVICE_NAME); status = IoCreateDevice( DriverObject, 0, &deviceName, FILE_DEVICE_NETWORK, 0, FALSE, &CnDeviceObject ); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to create %ws device object, status %lx\n", deviceName.Buffer, status )); return(status); } CnDeviceObject->Flags |= DO_DIRECT_IO; CnDeviceObject->StackSize = CN_DEFAULT_IRP_STACK_SIZE; status = IoRegisterShutdownNotification(CnDeviceObject); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to register for shutdown notification, status %lx\n", status )); } #if defined(WMI_TRACING) status = IoWMIRegistrationControl (CnDeviceObject, WMIREG_ACTION_REGISTER); if (!NT_SUCCESS(status)) { CNPRINT(("[ClusNet] Failed to register for WMI Support, %lx\n", status) ); } #endif // // Create the datagram transport device // RtlInitUnicodeString(&deviceName, DD_CDP_DEVICE_NAME); status = IoCreateDevice( DriverObject, 0, &deviceName, FILE_DEVICE_NETWORK, 0, FALSE, &CdpDeviceObject ); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to create %ws device object, status %lx\n", deviceName.Buffer, status )); return(status); } CdpDeviceObject->Flags |= DO_DIRECT_IO; CdpDeviceObject->StackSize = CDP_DEFAULT_IRP_STACK_SIZE; return(STATUS_SUCCESS); } VOID CnDeleteDeviceObjects( VOID ) /*++ Routine Description: Deletes the device objects exported by the driver. Arguments: None. Return Value: None. --*/ { PAGED_CODE(); if (CnDeviceObject != NULL) { #if defined(WMI_TRACING) IoWMIRegistrationControl(CnDeviceObject, WMIREG_ACTION_DEREGISTER); #endif IoDeleteDevice(CnDeviceObject); CnDeviceObject = NULL; } if (CdpDeviceObject != NULL) { IoDeleteDevice(CdpDeviceObject); CdpDeviceObject = NULL; } return; } NTSTATUS CnInitialize( IN CL_NODE_ID LocalNodeId, IN ULONG MaxNodes ) /*++ Routine Description: Initialization routine for the Cluster Network Driver. Called when an initialize request is received. Arguments: LocalNodeId - The ID of the local node. MaxNodes - The maximum number of valid cluster nodes. Return Value: An NT status code. --*/ { NTSTATUS status; if ( (MaxNodes == 0) || (LocalNodeId < ClusterMinNodeId) || (LocalNodeId > (ClusterMinNodeId + MaxNodes - 1)) ) { return(STATUS_INVALID_PARAMETER); } IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Initializing...\n")); } CnState = CnStateInitializePending; // // Reset global values // CnAssert(CnLocalNodeId == ClusterInvalidNodeId); CnAssert(CnMinValidNodeId == ClusterInvalidNodeId); CnAssert(CnMaxValidNodeId == ClusterInvalidNodeId); CnMinValidNodeId = ClusterMinNodeId; CnMaxValidNodeId = ClusterMinNodeId + MaxNodes - 1; CnLocalNodeId = LocalNodeId; // // Initialize the IP Address support // status = IpaInitialize(); if (status != STATUS_SUCCESS) { goto error_exit; } #ifdef MM_IN_CLUSNET // // Call the Membership Manager's init routine. This will in turn call // the Transport's init routine. // status = CmmInitialize(); #else // MM_IN_CLUSNET status = CxInitialize(); #endif // MM_IN_CLUSNET if (status == STATUS_SUCCESS) { IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Initialized.\n")); } CnState = CnStateInitialized; } else { goto error_exit; } return(STATUS_SUCCESS); error_exit: IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Initialization failed, Shutting down. Status = %08X\n", status)); } CnShutdown(); return(status); } // CnInitialize NTSTATUS CnShutdown( VOID ) /*++ Routine Description: Terminates operation of the Cluster Membership Manager. Called when the Cluster Service is shutting down. Arguments: None. Return Value: None. --*/ { NTSTATUS status; if ( (CnState == CnStateInitialized) || (CnState == CnStateInitializePending) ) { IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Shutting down...\n")); } CnState = CnStateShutdownPending; // // Shutdown the NetBT and IP Address support. // NbtIfShutdown(); IpaShutdown(); #ifdef MM_IN_CLUSNET // // Shutdown the Membership Manager. This will shutdown the // Transport as a side-effect. // CmmShutdown(); #else // MM_IN_CLUSNET CxShutdown(); #endif // MM_IN_CLUSNET IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Shutdown complete.\n")); } CnAssert(CnLocalNodeId != ClusterInvalidNodeId); CnMinValidNodeId = ClusterInvalidNodeId; CnMaxValidNodeId = ClusterInvalidNodeId; CnLocalNodeId = ClusterInvalidNodeId; CnState = CnStateShutdown; status = STATUS_SUCCESS; } else { status = STATUS_DEVICE_NOT_READY; } // // always test if we have a handle to this process // and remove it // if ( ClussvcProcessHandle ) { CnCloseProcessHandle( ClussvcProcessHandle ); ClussvcProcessHandle = NULL; } return(status); } // CnShutdown VOID CnShutdownWorkRoutine( IN PVOID WorkItem ) { BOOLEAN acquired; NTSTATUS Status; acquired = CnAcquireResourceExclusive(CnResource, TRUE); if (!acquired) { KIRQL irql; CNPRINT(("[Clusnet] Failed to acquire CnResource\n")); KeAcquireSpinLock(&CnShutdownLock, &irql); CnShutdownScheduled = FALSE; if (CnShutdownEvent != NULL) { KeSetEvent(CnShutdownEvent, IO_NO_INCREMENT, FALSE); } KeReleaseSpinLock(&CnShutdownLock, irql); return; } (VOID) CnShutdown(); if (CnShutdownEvent != NULL) { KeSetEvent(CnShutdownEvent, IO_NO_INCREMENT, FALSE); } if (acquired) { CnReleaseResourceForThread( CnResource, (ERESOURCE_THREAD) PsGetCurrentThread() ); } // // Leave CnShutdownScheduled = TRUE until we are reinitialized to // prevent scheduling unnecessary work items. // return; } // CnShutdownWorkRoutine BOOLEAN CnHaltOperation( IN PKEVENT ShutdownEvent OPTIONAL ) /*++ Routine Description: Schedules a critical worker thread to perform clusnet shutdown, if a thread is not already scheduled. Arguments: ShutdownEvent - if provided, event to be signalled after shutdown is complete Return value: TRUE if shutdown was scheduled. FALSE if shutdown was already scheduled (in which case ShutdownEvent will not be signalled). --*/ { KIRQL irql; // Disable further processing of Clussvc to Clusnet Hbs. ClussvcClusnetHbTimeoutAction = ClussvcHangActionDisable; InterlockedExchange(&ClussvcClusnetHbTickCount, 0); ClussvcClusnetHbTimeoutTicks = 0; KeAcquireSpinLock(&CnShutdownLock, &irql); if (CnShutdownScheduled) { KeReleaseSpinLock(&CnShutdownLock, irql); return(FALSE); } CnShutdownScheduled = TRUE; CnShutdownEvent = ShutdownEvent; KeReleaseSpinLock(&CnShutdownLock, irql); // // Schedule a critical worker thread to do the shutdown work. // ExInitializeWorkItem( &CnShutdownWorkItem, CnShutdownWorkRoutine, &CnShutdownWorkItem ); ExQueueWorkItem(&CnShutdownWorkItem, CriticalWorkQueue); return(TRUE); } // CnHaltOperation // // ExResource wrappers that disable APCs. // BOOLEAN CnAcquireResourceExclusive( IN PERESOURCE Resource, IN BOOLEAN Wait ) { BOOLEAN acquired; KeEnterCriticalRegion(); acquired = ExAcquireResourceExclusiveLite(Resource, Wait); if (!acquired) { KeLeaveCriticalRegion(); } return(acquired); } // CnAcquireResourceExclusive BOOLEAN CnAcquireResourceShared( IN PERESOURCE Resource, IN BOOLEAN Wait ) { BOOLEAN acquired; KeEnterCriticalRegion(); acquired = ExAcquireResourceSharedLite(Resource, Wait); if (!acquired) { KeLeaveCriticalRegion(); } return(acquired); } // CnAcquireResourceShared VOID CnReleaseResourceForThread( IN PERESOURCE Resource, IN ERESOURCE_THREAD ResourceThreadId ) { ExReleaseResourceForThreadLite(Resource, ResourceThreadId); KeLeaveCriticalRegion(); return; } // CnReleaseResourceForThread NTSTATUS CnCloseProcessHandle( HANDLE Handle ) /*++ Routine Description: Close the cluster service process handle Arguments: None Return Value: None --*/ { NTSTATUS Status = STATUS_SUCCESS; CnAssert( Handle != NULL ); KeAttachProcess( CnSystemProcess ); Status = ZwClose( Handle ); KeDetachProcess(); IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Process handle released. status = %08X\n", Status)); } return Status; } VOID CnEnableHaltProcessing( VOID ) /*++ Routine Description: Initializes global data for halt processing. Arguments: None Return Value: None --*/ { KIRQL irql; KeAcquireSpinLock(&CnShutdownLock, &irql); CnShutdownScheduled = FALSE; CnShutdownEvent = NULL; KeReleaseSpinLock(&CnShutdownLock, irql); return; } // CnEnableHaltProcessing VOID CnAdjustDeviceObjectStackSize( PDEVICE_OBJECT ClusnetDeviceObject, PDEVICE_OBJECT TargetDeviceObject ) /*++ Routine Description Adjust the StackSize of ClusnetDeviceObject so that we can pass client IRPs down to TargetDeviceObject. The StackSize of clusnet device objects is initialized to a default that allows for some leeway for attached drivers. Arguments ClusnetDeviceObject - clusnet device object whose StackSize should be adjusted TargetDeviceObject - device object clusnet IRPs, originally issued to clusnet, will be forwarded to Return value None --*/ { CCHAR defaultStackSize, newStackSize = 0; KIRQL irql; if (ClusnetDeviceObject == CnDeviceObject) { defaultStackSize = CN_DEFAULT_IRP_STACK_SIZE; } else if (ClusnetDeviceObject == CdpDeviceObject) { defaultStackSize = CDP_DEFAULT_IRP_STACK_SIZE; } else { IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] CnAdjustDeviceObjectStackSize: " "unknown clusnet device object %p.\n", ClusnetDeviceObject )); } return; } KeAcquireSpinLock(&CnDeviceObjectStackSizeLock, &irql); if (ClusnetDeviceObject->StackSize < TargetDeviceObject->StackSize + defaultStackSize) { ClusnetDeviceObject->StackSize = TargetDeviceObject->StackSize + defaultStackSize; IF_CNDBG(CN_DEBUG_INIT) { newStackSize = ClusnetDeviceObject->StackSize; } } KeReleaseSpinLock(&CnDeviceObjectStackSizeLock, irql); IF_CNDBG(CN_DEBUG_INIT) { if (newStackSize != 0) { CNPRINT(("[Clusnet] Set StackSize of clusnet device " "object %p to %d " "based on target device object %p.\n", ClusnetDeviceObject, newStackSize, TargetDeviceObject )); } } return; } // CnAdjustDeviceObjectStackSize NTSTATUS CnBuildDeviceAcl( OUT PACL *DeviceAcl ) /*++ Routine Description: This routine builds an ACL which gives Administrators, LocalSystem, and NetworkService principals full access. All other principals have no access. Arguments: DeviceAcl - Output pointer to the new ACL. Return Value: STATUS_SUCCESS or an appropriate error code. Notes: This code was lifted from AFD. --*/ { PGENERIC_MAPPING genericMapping; ULONG aclLength; NTSTATUS status; ACCESS_MASK accessMask = GENERIC_ALL; PACL newAcl; PAGED_CODE(); // // Enable access to all the globally defined SIDs // genericMapping = IoGetFileObjectGenericMapping(); RtlMapGenericMask( &accessMask, genericMapping ); aclLength = sizeof( ACL ) + 3 * FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid( SeExports->SeAliasAdminsSid ) + RtlLengthSid( SeExports->SeLocalSystemSid ) + RtlLengthSid( SeExports->SeNetworkServiceSid ); newAcl = ExAllocatePoolWithTag( PagedPool, aclLength, CN_POOL_TAG ); if (newAcl == NULL) { return (STATUS_INSUFFICIENT_RESOURCES); } status = RtlCreateAcl (newAcl, aclLength, ACL_REVISION ); if (!NT_SUCCESS(status)) { ExFreePoolWithTag( newAcl, CN_POOL_TAG ); return (status); } status = RtlAddAccessAllowedAce ( newAcl, ACL_REVISION2, accessMask, SeExports->SeAliasAdminsSid ); CnAssert(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to add Admin to ACL, error: %lx\n", status )); return(status); } status = RtlAddAccessAllowedAce ( newAcl, ACL_REVISION2, accessMask, SeExports->SeLocalSystemSid ); CnAssert(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to add LocalSystem to ACL, error: %lx\n", status )); return(status); } status = RtlAddAccessAllowedAce ( newAcl, ACL_REVISION2, accessMask, SeExports->SeNetworkServiceSid ); CnAssert(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to add NetworkService to ACL, error: %lx. " "(Non-fatal error)\n", status )); } *DeviceAcl = newAcl; return (STATUS_SUCCESS); } // CnBuildDeviceAcl NTSTATUS CnCreateSecurityDescriptor( VOID ) /*++ Routine Description: This routine creates a security descriptor which gives access only to certain priviliged accounts. This descriptor is used to access check CDP socket opens. Arguments: None. Return Value: STATUS_SUCCESS or an appropriate error code. Notes: This code was lifted from AFD. --*/ { PACL devAcl = NULL; NTSTATUS status; BOOLEAN memoryAllocated = FALSE; PSECURITY_DESCRIPTOR cdpSecurityDescriptor; ULONG cdpSecurityDescriptorLength; CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; PSECURITY_DESCRIPTOR localSecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer; PSECURITY_DESCRIPTOR localCdpAdminSecurityDescriptor; SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION; PAGED_CODE(); // // Get a pointer to the security descriptor from the CDP device object. // status = ObGetObjectSecurity( CdpDeviceObject, &cdpSecurityDescriptor, &memoryAllocated ); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to get CDP device object security descriptor, " "status %lx\n", status )); return(status); } // // Build a local security descriptor with an ACL giving only // certain priviliged accounts. // status = CnBuildDeviceAcl(&devAcl); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet] Failed to create Raw ACL, error: %lx\n", status )); goto error_exit; } (VOID) RtlCreateSecurityDescriptor( localSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); (VOID) RtlSetDaclSecurityDescriptor( localSecurityDescriptor, TRUE, devAcl, FALSE ); // // Make a copy of the CDP descriptor. This copy will be // the raw descriptor. // cdpSecurityDescriptorLength = RtlLengthSecurityDescriptor( cdpSecurityDescriptor ); localCdpAdminSecurityDescriptor = ExAllocatePoolWithTag ( PagedPool, cdpSecurityDescriptorLength, CN_POOL_TAG ); if (localCdpAdminSecurityDescriptor == NULL) { CNPRINT(( "[ClusNet]: failed to allocate security descriptor " "of size %d.\n", cdpSecurityDescriptorLength )); status = STATUS_INSUFFICIENT_RESOURCES; goto error_exit; } RtlMoveMemory( localCdpAdminSecurityDescriptor, cdpSecurityDescriptor, cdpSecurityDescriptorLength ); CdpAdminSecurityDescriptor = localCdpAdminSecurityDescriptor; // // Now apply the local descriptor to the raw descriptor. // status = SeSetSecurityDescriptorInfo( NULL, &securityInformation, localSecurityDescriptor, &CdpAdminSecurityDescriptor, PagedPool, IoGetFileObjectGenericMapping() ); if (!NT_SUCCESS(status)) { CNPRINT(( "[ClusNet]: SeSetSecurity failed for CDP admin " "security descriptor, %lx\n", status )); CnAssert(CdpAdminSecurityDescriptor == localCdpAdminSecurityDescriptor); ExFreePool(CdpAdminSecurityDescriptor); CdpAdminSecurityDescriptor = NULL; goto error_exit; } if (CdpAdminSecurityDescriptor != localCdpAdminSecurityDescriptor) { ExFreePool(localCdpAdminSecurityDescriptor); } status = STATUS_SUCCESS; error_exit: ObReleaseObjectSecurity( cdpSecurityDescriptor, memoryAllocated ); if (devAcl != NULL) { ExFreePoolWithTag( devAcl, CN_POOL_TAG ); } return(status); } // CnCreateSecurityDescriptor #if DBG // // Debug code. // ULONG CnCpuLockMask[MAXIMUM_PROCESSORS]; VOID CnAssertBreak( PCHAR FailedStatement, PCHAR FileName, ULONG LineNumber ) { DbgPrint( "[Clusnet] Assertion \"%s\" failed in %s line %u\n", FailedStatement, FileName, LineNumber ); DbgBreakPoint(); return; } // CnAssertBreak ULONG CnGetCpuLockMask( VOID ) { ULONG mask; if (KeGetCurrentIrql() != DISPATCH_LEVEL) { CnAssert(CnCpuLockMask[KeGetCurrentProcessorNumber()] == 0); mask = 0; } else { mask = CnCpuLockMask[KeGetCurrentProcessorNumber()]; } return(mask); } VOID CnVerifyCpuLockMask( IN ULONG RequiredLockMask, IN ULONG ForbiddenLockMask, IN ULONG MaximumLockMask ) { ULONG mask; if (KeGetCurrentIrql() < DISPATCH_LEVEL) { mask = 0; } else { mask = CnCpuLockMask[KeGetCurrentProcessorNumber()]; } if ((mask & RequiredLockMask) != RequiredLockMask) { CNPRINT(( "[Clusnet] Locking bug: Req'd lock mask %lx, actual mask %lx\n", RequiredLockMask, mask )); DbgBreakPoint(); } if (mask & ForbiddenLockMask) { CNPRINT(( "[Clusnet] Locking bug: Forbidden mask %lx, actual mask %lx\n", ForbiddenLockMask, mask )); DbgBreakPoint(); } if (mask > MaximumLockMask) { CNPRINT(( "[Clusnet] Locking bug: Max lock mask %lx, actual mask %lx\n", MaximumLockMask, mask )); DbgBreakPoint(); } return; } VOID CnInitializeLock( PCN_LOCK Lock, ULONG Rank ) { KeInitializeSpinLock(&(Lock->SpinLock)); Lock->Rank = Rank; return; } VOID CnAcquireLock( IN PCN_LOCK Lock, OUT PCN_IRQL Irql ) { KIRQL irql; ULONG currentCpu; if (KeGetCurrentIrql() != DISPATCH_LEVEL) { KeRaiseIrql(DISPATCH_LEVEL, &irql); } else { irql = DISPATCH_LEVEL; } currentCpu = KeGetCurrentProcessorNumber(); if (CnCpuLockMask[currentCpu] >= Lock->Rank) { CNPRINT(( "[Clusnet] CPU %u trying to acquire lock %lx out of order, mask %lx\n", currentCpu, Lock->Rank, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } KeAcquireSpinLockAtDpcLevel(&(Lock->SpinLock)); *Irql = irql; CnCpuLockMask[currentCpu] |= Lock->Rank; return; } VOID CnAcquireLockAtDpc( IN PCN_LOCK Lock ) { ULONG currentCpu = KeGetCurrentProcessorNumber(); if (KeGetCurrentIrql() != DISPATCH_LEVEL) { CNPRINT(( "[Clusnet] CPU %u trying to acquire DPC lock at passive level.\n", currentCpu )); DbgBreakPoint(); } if (CnCpuLockMask[currentCpu] >= Lock->Rank) { CNPRINT(( "[Clusnet] CPU %u trying to acquire lock %lx out of order, mask %lx\n", currentCpu, Lock->Rank, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } KeAcquireSpinLockAtDpcLevel(&(Lock->SpinLock)); CnCpuLockMask[currentCpu] |= Lock->Rank; return; } VOID CnReleaseLock( IN PCN_LOCK Lock, IN CN_IRQL Irql ) { ULONG currentCpu = KeGetCurrentProcessorNumber(); if (KeGetCurrentIrql() != DISPATCH_LEVEL) { CNPRINT(( "[Clusnet] CPU %u trying to release lock from passive level.\n", currentCpu )); DbgBreakPoint(); } if ( !(CnCpuLockMask[currentCpu] & Lock->Rank) ) { CNPRINT(( "[Clusnet] CPU %u trying to release lock %lx, which it doesn't hold, mask %lx\n", currentCpu, Lock->Rank, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } CnCpuLockMask[currentCpu] &= ~(Lock->Rank); KeReleaseSpinLock(&(Lock->SpinLock), Irql); return; } VOID CnReleaseLockFromDpc( IN PCN_LOCK Lock ) { ULONG currentCpu = KeGetCurrentProcessorNumber(); if (KeGetCurrentIrql() != DISPATCH_LEVEL) { CNPRINT(( "[Clusnet] CPU %u trying to release lock from passive level.\n", currentCpu )); DbgBreakPoint(); } if ( !(CnCpuLockMask[currentCpu] & Lock->Rank) ) { CNPRINT(( "[Clusnet] CPU %u trying to release lock %lx, which it doesn't hold, mask %lx\n", currentCpu, Lock->Rank, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } CnCpuLockMask[currentCpu] &= ~(Lock->Rank); KeReleaseSpinLockFromDpcLevel(&(Lock->SpinLock)); return; } VOID CnMarkIoCancelLockAcquired( VOID ) { ULONG currentCpu = KeGetCurrentProcessorNumber(); CnAssert(KeGetCurrentIrql() == DISPATCH_LEVEL); CnAssert(!(CnCpuLockMask[currentCpu] & CN_IOCANCEL_LOCK)); CnAssert(CnCpuLockMask[currentCpu] < CN_IOCANCEL_LOCK_MAX); CnCpuLockMask[currentCpu] |= CN_IOCANCEL_LOCK; return; } VOID CnAcquireCancelSpinLock( OUT PCN_IRQL Irql ) { KIRQL irql; KIRQL tempIrql; ULONG currentCpu; if (KeGetCurrentIrql() != DISPATCH_LEVEL) { KeRaiseIrql(DISPATCH_LEVEL, &irql); } else { irql = DISPATCH_LEVEL; } currentCpu = KeGetCurrentProcessorNumber(); if (CnCpuLockMask[currentCpu] >= CN_IOCANCEL_LOCK) { CNPRINT(( "[Clusnet] CPU %u trying to acquire IoCancel lock out of order, mask %lx\n", currentCpu, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } IoAcquireCancelSpinLock(&tempIrql); CnAssert(tempIrql == DISPATCH_LEVEL); *Irql = irql; CnCpuLockMask[currentCpu] |= CN_IOCANCEL_LOCK; return; } VOID CnReleaseCancelSpinLock( IN CN_IRQL Irql ) { ULONG currentCpu = KeGetCurrentProcessorNumber(); if (KeGetCurrentIrql() != DISPATCH_LEVEL) { CNPRINT(( "[Clusnet] CPU %u trying to release lock from passive level.\n", currentCpu )); DbgBreakPoint(); } if ( !(CnCpuLockMask[currentCpu] & CN_IOCANCEL_LOCK) ) { CNPRINT(( "[Clusnet] CPU %u trying to release IoCancel lock, which it doesn't hold, mask %lx\n", currentCpu, CnCpuLockMask[currentCpu] )); DbgBreakPoint(); } CnCpuLockMask[currentCpu] &= ~(CN_IOCANCEL_LOCK); IoReleaseCancelSpinLock(Irql); return; } #endif // DEBUG