/*++ Copyright (c) 1991 Microsoft Corporation Module Name: fsctl.c Abstract: This module implements the NtDeviceIoControlFile API's for the NT datagram receiver (bowser). Author: Eyal Schwartz (EyalS) Dec-9-1998 Revision History: --*/ #include "precomp.h" #pragma hdrstop // // Extern defined from #include . // Couldn't include ob.h due to redefinition conflicts. We had attempted to change ntos\makefil0 // so as to include it in ntsrv.h, but decided we shouldn't expose it. This does the job. // NTSTATUS ObGetObjectSecurity( IN PVOID Object, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PBOOLEAN MemoryAllocated ); VOID ObReleaseObjectSecurity( IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN BOOLEAN MemoryAllocated ); // defines // // pool tag #define BOW_SECURITY_POOL_TAG ( (ULONG)'seLB' ) // local prototypes // NTSTATUS BowserBuildDeviceAcl( OUT PACL *DeviceAcl ); NTSTATUS BowserCreateAdminSecurityDescriptor( IN PDEVICE_OBJECT pDevice ); #ifdef ALLOC_PRAGMA #pragma alloc_text(SECUR, BowserBuildDeviceAcl) #pragma alloc_text(SECUR, BowserCreateAdminSecurityDescriptor) #pragma alloc_text(SECUR, BowserInitializeSecurity) #pragma alloc_text(SECUR, BowserSecurityCheck ) #endif SECURITY_DESCRIPTOR *g_pBowSecurityDescriptor = NULL; // function implementation // NTSTATUS BowserBuildDeviceAcl( OUT PACL *DeviceAcl ) /*++ Routine Description: This routine builds an ACL which gives Administrators and LocalSystem principals full access. All other principals have no access. Lifted form \nt\private\ntos\afd\init.c!AfdBuildDeviceAcl() Arguments: DeviceAcl - Output pointer to the new ACL. Return Value: STATUS_SUCCESS or an appropriate error code. --*/ { PGENERIC_MAPPING GenericMapping; PSID AdminsSid; PSID SystemSid; ULONG AclLength; NTSTATUS Status; ACCESS_MASK AccessMask = GENERIC_ALL; PACL NewAcl; // // Enable access to all the globally defined SIDs // GenericMapping = IoGetFileObjectGenericMapping(); RtlMapGenericMask( &AccessMask, GenericMapping ); // SeEnableAccessToExports(); AdminsSid = SeExports->SeAliasAdminsSid; SystemSid = SeExports->SeLocalSystemSid; AclLength = sizeof( ACL ) + 2 * sizeof( ACCESS_ALLOWED_ACE ) + RtlLengthSid( AdminsSid ) + RtlLengthSid( SystemSid ) - 2 * sizeof( ULONG ); NewAcl = ExAllocatePoolWithTag( PagedPool, AclLength, BOW_SECURITY_POOL_TAG ); if (NewAcl == NULL) { return( STATUS_INSUFFICIENT_RESOURCES ); } Status = RtlCreateAcl (NewAcl, AclLength, ACL_REVISION ); if (!NT_SUCCESS( Status )) { ExFreePool( NewAcl ); return( Status ); } Status = RtlAddAccessAllowedAce ( NewAcl, ACL_REVISION, AccessMask, AdminsSid ); ASSERT( NT_SUCCESS( Status )); Status = RtlAddAccessAllowedAce ( NewAcl, ACL_REVISION, AccessMask, SystemSid ); ASSERT( NT_SUCCESS( Status )); *DeviceAcl = NewAcl; return( STATUS_SUCCESS ); } // BowBuildDeviceAcl NTSTATUS BowserCreateAdminSecurityDescriptor( IN PDEVICE_OBJECT pDevice ) /*++ Routine Description: This routine creates a security descriptor which gives access only to Administrtors and LocalSystem. This descriptor is used to access check raw endpoint opens and exclisive access to transport addresses. LIfted form \nt\private\ntos\afd\init.c!AfdCreateAdminSecurityDescriptor() Arguments: None. Return Value: STATUS_SUCCESS or an appropriate error code. --*/ { PACL rawAcl = NULL; NTSTATUS status; BOOLEAN memoryAllocated = FALSE; PSECURITY_DESCRIPTOR BowSecurityDescriptor; ULONG BowSecurityDescriptorLength; CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; PSECURITY_DESCRIPTOR localSecurityDescriptor = (PSECURITY_DESCRIPTOR) &buffer; PSECURITY_DESCRIPTOR localBowAdminSecurityDescriptor; SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION; #if 1 // // this is the way AFD gets the object SD (the preferred way). // status = ObGetObjectSecurity( pDevice, &BowSecurityDescriptor, &memoryAllocated ); if (!NT_SUCCESS(status)) { KdPrint(( "Bowser: Unable to get security descriptor, error: %x\n", status )); ASSERT(memoryAllocated == FALSE); return(status); } #else // // Get a pointer to the security descriptor from the our device object. // If we can't access ob api's due to include dependencies, we'll use it directly. // ** Need to verify it is legal (I doubt it)** // Need to dump this as soon as we can fix ntos\makefil0 to include ob.h in // the generated ntsrv.h // BowSecurityDescriptor = pDevice->SecurityDescriptor; if ( !BowSecurityDescriptor ) { KdPrint(( "Bowser: Unable to get security descriptor, error: %x\n", status )); return STATUS_INVALID_SECURITY_DESCR; } #endif // // Build a local security descriptor with an ACL giving only // administrators and system access. // status = BowserBuildDeviceAcl(&rawAcl); if (!NT_SUCCESS(status)) { KdPrint(("Bowser: Unable to create Raw ACL, error: %x\n", status)); goto error_exit; } (VOID) RtlCreateSecurityDescriptor( localSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); (VOID) RtlSetDaclSecurityDescriptor( localSecurityDescriptor, TRUE, rawAcl, FALSE ); // // Make a copy of the Bow descriptor. This copy will be the raw descriptor. // BowSecurityDescriptorLength = RtlLengthSecurityDescriptor( BowSecurityDescriptor ); localBowAdminSecurityDescriptor = ExAllocatePoolWithTag ( PagedPool, BowSecurityDescriptorLength, BOW_SECURITY_POOL_TAG ); if (localBowAdminSecurityDescriptor == NULL) { KdPrint(("Bowser: couldn't allocate security descriptor\n")); goto error_exit; } RtlMoveMemory( localBowAdminSecurityDescriptor, BowSecurityDescriptor, BowSecurityDescriptorLength ); g_pBowSecurityDescriptor = localBowAdminSecurityDescriptor; // // Now apply the local descriptor to the raw descriptor. // status = SeSetSecurityDescriptorInfo( NULL, &securityInformation, localSecurityDescriptor, &g_pBowSecurityDescriptor, PagedPool, IoGetFileObjectGenericMapping() ); if (!NT_SUCCESS(status)) { KdPrint(("Bowser: SeSetSecurity failed, %lx\n", status)); ASSERT (g_pBowSecurityDescriptor==localBowAdminSecurityDescriptor); ExFreePool (g_pBowSecurityDescriptor); g_pBowSecurityDescriptor = NULL; goto error_exit; } if (g_pBowSecurityDescriptor!=localBowAdminSecurityDescriptor) { ExFreePool (localBowAdminSecurityDescriptor); } status = STATUS_SUCCESS; error_exit: #if 1 // // see remark above // ObReleaseObjectSecurity( BowSecurityDescriptor, memoryAllocated ); #endif if (rawAcl!=NULL) { ExFreePool( rawAcl ); } return(status); } NTSTATUS BowserInitializeSecurity( IN PDEVICE_OBJECT pDevice ) /*++ Routine Description (BowserInitializeSecurity): Initialize Bowser security. - Create default bowser security descriptor based on device sercurity Arguments: device: opened device Return Value: Remarks: None. --*/ { NTSTATUS Status; if ( g_pBowSecurityDescriptor ) { return STATUS_SUCCESS; } ASSERT(pDevice); Status = BowserCreateAdminSecurityDescriptor ( pDevice ); return Status; } BOOLEAN BowserSecurityCheck ( PIRP Irp, PIO_STACK_LOCATION IrpSp, PNTSTATUS Status ) /*++ Routine Description: Lifted as is from \\index1\src\nt\private\ntos\afd\create.c!AfdPerformSecurityCheck Compares security context of the endpoint creator to that of the administrator and local system. Note: This is currently called only on IOCTL Irps. IOCRTLs don't have a create security context (only creates...), thus we should always capture the security context rather then attempting to extract it from the IrpSp. Arguments: Irp - Pointer to I/O request packet. IrpSp - pointer to the IO stack location to use for this request. Status - returns status generated by access check on failure. Return Value: TRUE - the socket creator has admin or local system privilige FALSE - the socket creator is just a plain user --*/ { BOOLEAN accessGranted; PACCESS_STATE accessState; PIO_SECURITY_CONTEXT securityContext; SECURITY_SUBJECT_CONTEXT SubjectContext; PSECURITY_SUBJECT_CONTEXT pSubjectContext = &SubjectContext; ACCESS_MASK grantedAccess; PGENERIC_MAPPING GenericMapping; ACCESS_MASK AccessMask = GENERIC_ALL; PAGED_CODE(); ASSERT (g_pBowSecurityDescriptor); // // Get security context from process. // SeCaptureSubjectContext(&SubjectContext); SeLockSubjectContext(pSubjectContext); // // Build access evaluation: // Enable access to all the globally defined SIDs // GenericMapping = IoGetFileObjectGenericMapping(); RtlMapGenericMask( &AccessMask, GenericMapping ); // // AccessCheck test // accessGranted = SeAccessCheck( g_pBowSecurityDescriptor, pSubjectContext, TRUE, AccessMask, 0, NULL, IoGetFileObjectGenericMapping(), (KPROCESSOR_MODE)((IrpSp->Flags & SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode), &grantedAccess, Status ); // // Verify consistency. // #if DBG if (accessGranted) { ASSERT (NT_SUCCESS (*Status)); } else { ASSERT (!NT_SUCCESS (*Status)); } #endif // // Unlock & Release security subject context // SeUnlockSubjectContext(pSubjectContext); SeReleaseSubjectContext(pSubjectContext); return accessGranted; }