int get_sid_id(struct _SID_AND_ATTRIBUTES *sid_a, ULONG sid_a_size) { // doing linear search (optimize?) KIRQL irql; int i, result = 0; KdPrint(("[tdi_fw] get_sid_id: (sid_size = %u/%u)\n", SeLengthSid(sid_a->Sid), sid_a_size)); KeAcquireSpinLock(&g_sids.guard, &irql); for (i = 1; i < g_sids.count; i++) { // comparing sids byte by byte (can't call RtlEqualSid() due to DISPATCH_LEVEL) KdPrint(("[tdi_fw] get_sid_id: sid #%d size %u\n", i, SeLengthSid((PSID)g_sids.list[i]->sid_data))); if (SeLengthSid(sid_a->Sid) == SeLengthSid((PSID)g_sids.list[i]->sid_data) && memcmp(sid_a->Sid, (PSID)g_sids.list[i]->sid_data, SeLengthSid(sid_a->Sid)) == 0) { result = i; break; } } KeReleaseSpinLock(&g_sids.guard, irql); KdPrint(("[tdi_fw] get_sid_id: %d\n", result)); return result; }
VOID SepFreePrimaryGroup( IN PTOKEN Token ) /*++ Routine Description: Free up the space in the dynamic part of the token take up by the primary group. The token is assumed to be locked for write access before calling this routine. Arguments: Token - Pointer to the token. Return Value: None. --*/ { PAGED_CODE(); // // Add the size of the primary group to the DynamicAvailable field. // Token->DynamicAvailable += SeLengthSid( Token->PrimaryGroup ); // // If there is a default discretionary ACL, and it is not already at the // beginning of the dynamic part, move it there (remember to update the // pointer to it). // if (ARGUMENT_PRESENT(Token->DefaultDacl)) { if (Token->DynamicPart != (PULONG)(Token->DefaultDacl)) { RtlMoveMemory( (PVOID)(Token->DynamicPart), (PVOID)(Token->DefaultDacl), Token->DefaultDacl->AclSize ); Token->DefaultDacl = (PACL)(Token->DynamicPart); } } return; }
VOID SepInitSystemDacls( VOID ) /*++ Routine Description: This function initializes the system's default dacls & security descriptors. Arguments: None. Return Value: None. --*/ { NTSTATUS Status; ULONG PublicLength, PublicUnrestrictedLength, SystemLength, PublicOpenLength, LocalServiceLength; PAGED_CODE(); // // Set up a default ACLs // // Public: WORLD:execute, SYSTEM:all, ADMINS:all // PublicUnrestricted: WORLD:execute, SYSTEM:all, ADMINS:all, Restricted:execute // Public Open: WORLD:(Read|Write|Execute), ADMINS:(all), SYSTEM:all // System: SYSTEM:all, ADMINS:(read|execute|read_control) // Unrestricted: WORLD:(all), Restricted:(all) SystemLength = (ULONG)sizeof(ACL) + (2*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) + SeLengthSid( SeLocalSystemSid ) + SeLengthSid( SeAliasAdminsSid ); PublicLength = SystemLength + ((ULONG)sizeof(ACCESS_ALLOWED_ACE)) + SeLengthSid( SeWorldSid ); PublicUnrestrictedLength = PublicLength + ((ULONG)sizeof(ACCESS_ALLOWED_ACE)) + SeLengthSid( SeRestrictedSid ); PublicOpenLength = PublicLength; LocalServiceLength = (ULONG)sizeof(ACL) + 4 * (ULONG)sizeof(ACCESS_ALLOWED_ACE) + SeLengthSid(SeWorldSid) + SeLengthSid(SeLocalSystemSid) + SeLengthSid(SeLocalServiceSid) + SeLengthSid(SeAliasAdminsSid); SePublicDefaultDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, PublicLength, 'cAeS'); SePublicDefaultUnrestrictedDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, PublicUnrestrictedLength, 'cAeS'); SePublicOpenDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, PublicOpenLength, 'cAeS'); SePublicOpenUnrestrictedDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, PublicUnrestrictedLength, 'cAeS'); SeSystemDefaultDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, SystemLength, 'cAeS'); SeLocalServicePublicDacl = (PACL)ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, LocalServiceLength, 'cAeS'); ASSERT(SePublicDefaultDacl != NULL); ASSERT(SePublicDefaultUnrestrictedDacl != NULL); ASSERT(SePublicOpenDacl != NULL); ASSERT(SePublicOpenUnrestrictedDacl != NULL); ASSERT(SeSystemDefaultDacl != NULL); ASSERT(SeLocalServicePublicDacl != NULL); Status = RtlCreateAcl( SePublicDefaultDacl, PublicLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlCreateAcl( SePublicDefaultUnrestrictedDacl, PublicUnrestrictedLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlCreateAcl( SePublicOpenDacl, PublicOpenLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlCreateAcl( SePublicOpenUnrestrictedDacl, PublicUnrestrictedLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlCreateAcl( SeSystemDefaultDacl, SystemLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlCreateAcl( SeLocalServicePublicDacl, LocalServiceLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); // // WORLD access (Public DACLs and OpenUnrestricted only) // Status = RtlAddAccessAllowedAce ( SePublicDefaultDacl, ACL_REVISION2, GENERIC_EXECUTE, SeWorldSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicDefaultUnrestrictedDacl, ACL_REVISION2, GENERIC_EXECUTE, SeWorldSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenDacl, ACL_REVISION2, (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE), SeWorldSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenUnrestrictedDacl, ACL_REVISION2, (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE), SeWorldSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SeLocalServicePublicDacl, ACL_REVISION2, GENERIC_EXECUTE, SeWorldSid ); ASSERT( NT_SUCCESS(Status) ); // // SYSTEM access (PublicDefault, PublicOpen, and SystemDefault) // Status = RtlAddAccessAllowedAce ( SePublicDefaultDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicDefaultUnrestrictedDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenUnrestrictedDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SeSystemDefaultDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SeLocalServicePublicDacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); ASSERT( NT_SUCCESS(Status) ); // // ADMINISTRATORS access (PublicDefault, PublicOpen, and SystemDefault) // Status = RtlAddAccessAllowedAce ( SePublicDefaultDacl, ACL_REVISION2, GENERIC_ALL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicDefaultUnrestrictedDacl, ACL_REVISION2, GENERIC_ALL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenDacl, ACL_REVISION2, GENERIC_ALL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenUnrestrictedDacl, ACL_REVISION2, GENERIC_ALL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SeSystemDefaultDacl, ACL_REVISION2, GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SeLocalServicePublicDacl, ACL_REVISION2, GENERIC_ALL, SeAliasAdminsSid ); ASSERT( NT_SUCCESS(Status) ); // // RESTRICTED access (PublicDefaultUnrestricted and OpenUnrestricted) // Status = RtlAddAccessAllowedAce ( SePublicDefaultUnrestrictedDacl, ACL_REVISION2, GENERIC_EXECUTE, SeRestrictedSid ); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAccessAllowedAce ( SePublicOpenUnrestrictedDacl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, SeRestrictedSid ); ASSERT( NT_SUCCESS(Status) ); // // Local Service // Status = RtlAddAccessAllowedAce ( SeLocalServicePublicDacl, ACL_REVISION2, GENERIC_ALL, SeLocalServiceSid ); ASSERT( NT_SUCCESS(Status) ); // // Now initialize security descriptors // that export this protection // SePublicDefaultSd = (PSECURITY_DESCRIPTOR)&SepPublicDefaultSd; Status = RtlCreateSecurityDescriptor( SePublicDefaultSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SePublicDefaultSd, TRUE, // DaclPresent SePublicDefaultDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); SePublicDefaultUnrestrictedSd = (PSECURITY_DESCRIPTOR)&SepPublicDefaultUnrestrictedSd; Status = RtlCreateSecurityDescriptor( SePublicDefaultUnrestrictedSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SePublicDefaultUnrestrictedSd, TRUE, // DaclPresent SePublicDefaultUnrestrictedDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); SePublicOpenSd = (PSECURITY_DESCRIPTOR)&SepPublicOpenSd; Status = RtlCreateSecurityDescriptor( SePublicOpenSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SePublicOpenSd, TRUE, // DaclPresent SePublicOpenDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); SePublicOpenUnrestrictedSd = (PSECURITY_DESCRIPTOR)&SepPublicOpenUnrestrictedSd; Status = RtlCreateSecurityDescriptor( SePublicOpenUnrestrictedSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SePublicOpenUnrestrictedSd, TRUE, // DaclPresent SePublicOpenUnrestrictedDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); SeSystemDefaultSd = (PSECURITY_DESCRIPTOR)&SepSystemDefaultSd; Status = RtlCreateSecurityDescriptor( SeSystemDefaultSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SeSystemDefaultSd, TRUE, // DaclPresent SeSystemDefaultDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); SeLocalServicePublicSd = (PSECURITY_DESCRIPTOR)&SepLocalServicePublicSd; Status = RtlCreateSecurityDescriptor( SeLocalServicePublicSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( SeLocalServicePublicSd, TRUE, // DaclPresent SeLocalServicePublicDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); return; }
VOID SepInitProcessAuditSd( VOID ) /*++ Routine Description: This function initializes SepProcessAuditSd -- a security descriptor that is used by SepAddSaclToProcess to add SACL to the existing security descriptor on a system process. A system process is defined as the one whose token has at least one of the following sids. -- SeLocalSystemSid -- SeLocalServiceSid -- SeNetworkServiceSid Arguments: None. Return Value: None. --*/ { #define PROCESS_ACCESSES_TO_AUDIT ( PROCESS_CREATE_THREAD |\ PROCESS_SET_INFORMATION |\ PROCESS_SET_PORT |\ PROCESS_SUSPEND_RESUME ) NTSTATUS Status = STATUS_SUCCESS; ULONG AclLength, TotalSdLength; PISECURITY_DESCRIPTOR Sd = NULL; PISECURITY_DESCRIPTOR Sd2 = NULL; PACL Acl = NULL; // // free earlier instance if present // if ( SepProcessAuditSd != NULL ) { ExFreePool( SepProcessAuditSd ); SepProcessAuditSd = NULL; } // // Don't initialize SeProcessAuditSd if SepProcessAccessesToAudit is 0 // This effectively disables process access auditing // if ( SepProcessAccessesToAudit == 0 ) { goto Cleanup; } AclLength = (ULONG)sizeof(ACL) + ((ULONG)sizeof(SYSTEM_AUDIT_ACE) - sizeof(ULONG)) + SeLengthSid( SeWorldSid ); TotalSdLength = sizeof(SECURITY_DESCRIPTOR) + AclLength; Sd = (PSECURITY_DESCRIPTOR) ExAllocatePoolWithTag( NonPagedPool, TotalSdLength, 'cAeS'); if ( Sd == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Acl = (PACL) (Sd + 1); Status = RtlCreateAcl( Acl, AclLength, ACL_REVISION2 ); if ( NT_SUCCESS( Status )) { Status = RtlAddAuditAccessAce( Acl, ACL_REVISION2, SepProcessAccessesToAudit, SeWorldSid, TRUE, TRUE ); if ( NT_SUCCESS( Status )) { Status = RtlCreateSecurityDescriptor( Sd, SECURITY_DESCRIPTOR_REVISION1 ); if ( NT_SUCCESS( Status )) { Status = RtlSetSaclSecurityDescriptor( Sd, TRUE, Acl, FALSE ); if ( NT_SUCCESS( Status )) { SepProcessAuditSd = Sd; } } } } ASSERT( NT_SUCCESS(Status) ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } // // create and initialize SepImportantProcessSd // AclLength = (ULONG)sizeof(ACL) + (3*((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + SeLengthSid( SeLocalSystemSid ) + SeLengthSid( SeLocalServiceSid ) + SeLengthSid( SeNetworkServiceSid ); TotalSdLength = sizeof(SECURITY_DESCRIPTOR) + AclLength; Sd2 = (PSECURITY_DESCRIPTOR) ExAllocatePoolWithTag( NonPagedPool, TotalSdLength, 'cAeS'); if ( Sd2 == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Acl = (PACL) (Sd2 + 1); Status = RtlCreateAcl( Acl, AclLength, ACL_REVISION2 ); if ( NT_SUCCESS( Status )) { Status = RtlAddAccessAllowedAce( Acl, ACL_REVISION2, SEP_QUERY_MEMBERSHIP, SeLocalSystemSid ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } Status = RtlAddAccessAllowedAce( Acl, ACL_REVISION2, SEP_QUERY_MEMBERSHIP, SeLocalServiceSid ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } Status = RtlAddAccessAllowedAce( Acl, ACL_REVISION2, SEP_QUERY_MEMBERSHIP, SeNetworkServiceSid ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } Status = RtlCreateSecurityDescriptor( Sd2, SECURITY_DESCRIPTOR_REVISION1 ); if ( NT_SUCCESS( Status )) { Status = RtlSetDaclSecurityDescriptor( Sd2, TRUE, Acl, FALSE ); if ( NT_SUCCESS( Status )) { SepImportantProcessSd = Sd2; } } } Cleanup: if ( !NT_SUCCESS( Status )) { ASSERT( FALSE && L"SepInitProcessAuditSd failed" ); // // this will bugcheck if SepCrashOnAuditFail is TRUE // SepAuditFailed( Status ); if ( Sd ) { ExFreePool( Sd ); Sd = NULL; SepProcessAuditSd = NULL; } if ( Sd2 ) { ExFreePool( Sd2 ); Sd2 = NULL; SepImportantProcessSd = NULL; } } }
BOOLEAN SeRmInitPhase1( ) /*++ Routine Description: This function is called by Phase 1 System Initialization to initialize the Security Reference Monitor. Note that initialization of the Reference Monitor Global State has already been performed in Phase 0 initialization to allow access validation routines to operate without having to check that Reference Monitor Initialization is complete. The steps listed below are performed in this routine. The remainder of Reference Monitor initialization requires the LSA subsystem to have run, so that initialization is performed in a separate thread (the RM Command Server Thread, see below), so that the present thread can create the Session Manager which execs the LSA. o Create the Reference Monitor Command LPC port. The LSA subsystem sends commands (e.g. turn on auditing) which change the Reference Monitor Global State. o Create an Event for use in synchronizing with the LSA subsystem. The LSA will signal the event when the portion of LSA initialization upon with the Reference Monitor depends is complete. The Reference Monitor uses another LPC port, called the LSA Command Port to send commands to the LSA, so the RM must know that this port has been created before trying to connect to it. o Create the Reference Monitor Command Server Thread. This thread is a permanent thread of the System Init process that fields the Reference Monitor State Change commands described above. Arguments: None. Return Value: BOOLEAN - TRUE if Rm Initialization (Phase 1) succeeded, else FALSE --*/ { NTSTATUS Status; STRING RmCommandPortName; UNICODE_STRING UnicodeRmCommandPortName; OBJECT_ATTRIBUTES ObjectAttributes; STRING LsaInitEventName; UNICODE_STRING UnicodeLsaInitEventName; OBJECT_ATTRIBUTES LsaInitEventObjectAttributes; SECURITY_DESCRIPTOR LsaInitEventSecurityDescriptor; ULONG AclSize; PAGED_CODE(); // // Create an LPC port called the Reference Monitor Command Port. // This will be used by the LSA to send commands to the Reference // Monitor to update its state data. // RtlInitString( &RmCommandPortName, "\\SeRmCommandPort" ); Status = RtlAnsiStringToUnicodeString( &UnicodeRmCommandPortName, &RmCommandPortName, TRUE ); ASSERT( NT_SUCCESS(Status) ); InitializeObjectAttributes( &ObjectAttributes, &UnicodeRmCommandPortName, 0, NULL, NULL ); Status = ZwCreatePort( &SepRmState.RmCommandPortHandle, &ObjectAttributes, sizeof(SEP_RM_CONNECT_INFO), sizeof(RM_COMMAND_MESSAGE), sizeof(RM_COMMAND_MESSAGE) * 32 ); RtlFreeUnicodeString( &UnicodeRmCommandPortName ); if( !NT_SUCCESS(Status) ) { KdPrint(("Security: Rm Create Command Port failed 0x%lx\n", Status)); return FALSE; } // // Prepare to create an event for synchronizing with the LSA. // First, build the Security Descriptor for the Init Event Object // Status = RtlCreateSecurityDescriptor( &LsaInitEventSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if (!NT_SUCCESS(Status)) { KdPrint(("Security: Creating Lsa Init Event Desc failed 0x%lx\n", Status)); return FALSE; } // // Allocate a temporary buffer from the paged pool. It is a fatal // system error if the allocation fails since security cannot be // enabled. // AclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + SeLengthSid(SeLocalSystemSid); LsaInitEventSecurityDescriptor.Dacl = ExAllocatePoolWithTag(PagedPool, AclSize, 'cAeS'); if (LsaInitEventSecurityDescriptor.Dacl == NULL) { KdPrint(("Security LSA: Insufficient resources to initialize\n")); return FALSE; } // // Now create the Discretionary ACL within the Security Descriptor // Status = RtlCreateAcl( LsaInitEventSecurityDescriptor.Dacl, AclSize, ACL_REVISION2 ); if (!NT_SUCCESS(Status)) { KdPrint(("Security: Creating Lsa Init Event Dacl failed 0x%lx\n", Status)); return FALSE; } // // Now add an ACE giving GENERIC_ALL access to the User ID // Status = RtlAddAccessAllowedAce( LsaInitEventSecurityDescriptor.Dacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); if (!NT_SUCCESS(Status)) { KdPrint(("Security: Adding Lsa Init Event ACE failed 0x%lx\n", Status)); return FALSE; } // // Set up the Object Attributes for the Lsa Initialization Event // RtlInitString( &LsaInitEventName, "\\SeLsaInitEvent" ); Status = RtlAnsiStringToUnicodeString( &UnicodeLsaInitEventName, &LsaInitEventName, TRUE ); ASSERT( NT_SUCCESS(Status) ); InitializeObjectAttributes( &LsaInitEventObjectAttributes, &UnicodeLsaInitEventName, 0, NULL, &LsaInitEventSecurityDescriptor ); // // Create an event for use in synchronizing with the LSA. The LSA will // signal this event when LSA initialization has reached the point // where the LSA's Reference Monitor Server Port has been created. // Status = ZwCreateEvent( &(SepRmState.LsaInitEventHandle), EVENT_MODIFY_STATE, &LsaInitEventObjectAttributes, NotificationEvent, FALSE); RtlFreeUnicodeString( &UnicodeLsaInitEventName ); if (!NT_SUCCESS(Status)) { KdPrint(("Security: LSA init event creation failed.0x%xl\n", Status)); return FALSE; } // // Deallocate the pool memory used for the Init Event DACL // ExFreePool( LsaInitEventSecurityDescriptor.Dacl ); // // Create a permanent thread of the Sysinit Process, called the // Reference Monitor Server Thread. This thread is dedicated to // receiving Reference Monitor commands and dispatching them. // Status = PsCreateSystemThread( &SepRmState.SepRmThreadHandle, THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SET_INFORMATION, NULL, NULL, NULL, SepRmCommandServerThread, NULL ); if (!NT_SUCCESS(Status)) { KdPrint(("Security: Rm Server Thread creation failed 0x%lx\n", Status)); return FALSE; } // // Initialize data from the registry. This must go here because all other // Se initialization takes place before the registry is initialized. // SepAdtInitializeCrashOnFail(); SepAdtInitializePrivilegeAuditing(); SepAdtInitializeAuditingOptions(); // // Reference Monitor initialization is successful if we get to here. // ZwClose( SepRmState.SepRmThreadHandle ); SepRmState.SepRmThreadHandle = NULL; return TRUE; }
PSECURITY_DESCRIPTOR NTAPI INIT_FUNCTION CmpHiveRootSecurityDescriptor(VOID) { NTSTATUS Status; PSECURITY_DESCRIPTOR SecurityDescriptor; PACL Acl, AclCopy; PSID Sid[4]; SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; ULONG AceLength, AclLength, SidLength; PACE_HEADER AceHeader; ULONG i; PAGED_CODE(); /* Phase 1: Allocate SIDs */ SidLength = RtlLengthRequiredSid(1); Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); SidLength = RtlLengthRequiredSid(2); Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); /* Make sure all SIDs were allocated */ if (!(Sid[0]) || !(Sid[1]) || !(Sid[2]) || !(Sid[3])) { /* Bugcheck */ KeBugCheckEx(REGISTRY_ERROR, 11, 1, 0, 0); } /* Phase 2: Initialize all SIDs */ Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1); Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1); Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1); Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 2, 0, 0); /* Phase 2: Setup SID Sub Authorities */ *RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID; *RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID; *RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID; *RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID; *RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS; /* Make sure all SIDs are valid */ ASSERT(RtlValidSid(Sid[0])); ASSERT(RtlValidSid(Sid[1])); ASSERT(RtlValidSid(Sid[2])); ASSERT(RtlValidSid(Sid[3])); /* Phase 3: Calculate ACL Length */ AclLength = sizeof(ACL); for (i = 0; i < 4; i++) { /* This is what MSDN says to do */ AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart); AceLength += SeLengthSid(Sid[i]); AclLength += AceLength; } /* Phase 3: Allocate the ACL */ Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CM); if (!Acl) KeBugCheckEx(REGISTRY_ERROR, 11, 3, 0, 0); /* Phase 4: Create the ACL */ Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 4, Status, 0); /* Phase 5: Build the ACL */ Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[0]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[1]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[2]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[3]); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 5, Status, 0); /* Phase 5: Make the ACEs inheritable */ Status = RtlGetAce(Acl, 0,( PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; /* Phase 6: Allocate the security descriptor and make space for the ACL */ SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_DESCRIPTOR) + AclLength, TAG_CM); if (!SecurityDescriptor) KeBugCheckEx(REGISTRY_ERROR, 11, 6, 0, 0); /* Phase 6: Make a copy of the ACL */ AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1); RtlCopyMemory(AclCopy, Acl, AclLength); /* Phase 7: Create the security descriptor */ Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 7, Status, 0); /* Phase 8: Set the ACL as a DACL */ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, AclCopy, FALSE); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 8, Status, 0); /* Free the SIDs and original ACL */ for (i = 0; i < 4; i++) ExFreePoolWithTag(Sid[i], TAG_CM); ExFreePoolWithTag(Acl, TAG_CM); /* Return the security descriptor */ return SecurityDescriptor; }
NTSTATUS RtlSelfRelativeToAbsoluteSD( IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, OUT PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, IN OUT PULONG AbsoluteSecurityDescriptorSize, IN OUT PACL Dacl, IN OUT PULONG DaclSize, IN OUT PACL Sacl, IN OUT PULONG SaclSize, IN OUT PSID Owner, IN OUT PULONG OwnerSize, IN OUT PSID PrimaryGroup, IN OUT PULONG PrimaryGroupSize ) /*++ Routine Description: Converts a security descriptor from self-relative format to absolute format Arguments: SecurityDescriptor - Supplies a pointer to a security descriptor in Self-Relative format AbsoluteSecurityDescriptor - A pointer to a buffer in which will be placed the main body of the Absolute format security descriptor. Dacl - Supplies a pointer to a buffer that will contain the Dacl of the output descriptor. This pointer will be referenced by, not copied into, the output descriptor. DaclSize - Supplies the size of the buffer pointed to by Dacl. In case of error, it will return the minimum size necessary to contain the Dacl. Sacl - Supplies a pointer to a buffer that will contain the Sacl of the output descriptor. This pointer will be referenced by, not copied into, the output descriptor. SaclSize - Supplies the size of the buffer pointed to by Sacl. In case of error, it will return the minimum size necessary to contain the Sacl. Owner - Supplies a pointer to a buffer that will contain the Owner of the output descriptor. This pointer will be referenced by, not copied into, the output descriptor. OwnerSize - Supplies the size of the buffer pointed to by Owner. In case of error, it will return the minimum size necessary to contain the Owner. PrimaryGroup - Supplies a pointer to a buffer that will contain the PrimaryGroup of the output descriptor. This pointer will be referenced by, not copied into, the output descriptor. PrimaryGroupSize - Supplies the size of the buffer pointed to by PrimaryGroup. In case of error, it will return the minimum size necessary to contain the PrimaryGroup. Return Value: STATUS_SUCCESS - Success STATUS_BUFFER_TOO_SMALL - One of the buffers passed was too small. STATUS_INVALID_OWNER - There was not a valid owner in the passed security descriptor. --*/ { ULONG NewDaclSize; ULONG NewSaclSize; ULONG NewBodySize; ULONG NewOwnerSize; ULONG NewGroupSize; PSID NewOwner; PSID NewGroup; PACL NewDacl; PACL NewSacl; // // typecast security descriptors so we don't have to cast all over the place. // PISECURITY_DESCRIPTOR OutSD = AbsoluteSecurityDescriptor; PISECURITY_DESCRIPTOR InSD = (PISECURITY_DESCRIPTOR)SelfRelativeSecurityDescriptor; RTL_PAGED_CODE(); if ( !RtlpAreControlBitsSet( InSD, SE_SELF_RELATIVE) ) { return( STATUS_BAD_DESCRIPTOR_FORMAT ); } NewBodySize = sizeof(SECURITY_DESCRIPTOR); RtlpQuerySecurityDescriptor( InSD, &NewOwner, &NewOwnerSize, &NewGroup, &NewGroupSize, &NewDacl, &NewDaclSize, &NewSacl, &NewSaclSize ); if ( (NewBodySize > *AbsoluteSecurityDescriptorSize) || (NewOwnerSize > *OwnerSize ) || (NewDaclSize > *DaclSize ) || (NewSaclSize > *SaclSize ) || (NewGroupSize > *PrimaryGroupSize ) ) { *AbsoluteSecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR); *PrimaryGroupSize = NewGroupSize; *OwnerSize = NewOwnerSize; *SaclSize = NewSaclSize; *DaclSize = NewDaclSize; return( STATUS_BUFFER_TOO_SMALL ); } RtlMoveMemory( OutSD, InSD, sizeof(SECURITY_DESCRIPTOR_RELATIVE) ); OutSD->Owner = NULL; OutSD->Group = NULL; OutSD->Sacl = NULL; OutSD->Dacl = NULL; RtlpClearControlBits( OutSD, SE_SELF_RELATIVE ); if (NewOwner != NULL) { RtlMoveMemory( Owner, NewOwner, SeLengthSid( NewOwner )); OutSD->Owner = Owner; } if (NewGroup != NULL) { RtlMoveMemory( PrimaryGroup, NewGroup, SeLengthSid( NewGroup )); OutSD->Group = PrimaryGroup; } if (NewSacl != NULL) { RtlMoveMemory( Sacl, NewSacl, NewSacl->AclSize ); OutSD->Sacl = Sacl; } if (NewDacl != NULL) { RtlMoveMemory( Dacl, NewDacl, NewDacl->AclSize ); OutSD->Dacl = Dacl; } return( STATUS_SUCCESS ); }
VOID RtlpQuerySecurityDescriptor( IN PISECURITY_DESCRIPTOR SecurityDescriptor, OUT PSID *Owner, OUT PULONG OwnerSize, OUT PSID *PrimaryGroup, OUT PULONG PrimaryGroupSize, OUT PACL *Dacl, OUT PULONG DaclSize, OUT PACL *Sacl, OUT PULONG SaclSize ) /*++ Routine Description: Returns the pieces of a security descriptor structure. Arguments: SecurityDescriptor - Provides the security descriptor of interest. Owner - Returns a pointer to the owner information contained in the security descriptor. OwnerSize - Returns the size of the owner information. PrimaryGroup - Returns a pointer to the primary group information. PrimaryGroupSize - Returns the size of the primary group information. Dacl - Returns a pointer to the Dacl. DaclSize - Returns the size of the Dacl. Sacl - Returns a pointer to the Sacl. SaclSize - Returns the size of the Sacl. Return Value: None. --*/ { RTL_PAGED_CODE(); *Owner = RtlpOwnerAddrSecurityDescriptor( SecurityDescriptor ); if (*Owner != NULL) { *OwnerSize = LongAlignSize(SeLengthSid(*Owner)); } else { *OwnerSize = 0; } *Dacl = RtlpDaclAddrSecurityDescriptor ( SecurityDescriptor ); if (*Dacl !=NULL) { *DaclSize = LongAlignSize((*Dacl)->AclSize); } else { *DaclSize = 0; } *PrimaryGroup = RtlpGroupAddrSecurityDescriptor( SecurityDescriptor ); if (*PrimaryGroup != NULL) { *PrimaryGroupSize = LongAlignSize(SeLengthSid(*PrimaryGroup)); } else { *PrimaryGroupSize = 0; } *Sacl = RtlpSaclAddrSecurityDescriptor( SecurityDescriptor ); if (*Sacl != NULL) { *SaclSize = LongAlignSize((*Sacl)->AclSize); } else { *SaclSize = 0; } }
NTSTATUS IopApplySystemPartitionProt( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This routine applies protection to the system partition that prevents all users except administrators from accessing the partition. This routine is only used during system initialization. As such, all memory allocations are expected to succeed. Success is tested only with assertions. Arguments: LoaderBlock - Supplies a pointer to the loader parameter block that was created by the OS Loader. Return Value: The function value is the final status from attempting to set the system partition protection. --*/ { NTSTATUS status; PACL dacl; SECURITY_DESCRIPTOR securityDescriptor; OBJECT_ATTRIBUTES objectAttributes; ULONG length; CHAR ArcNameFmt[12]; ArcNameFmt[0] = '\\'; ArcNameFmt[1] = 'A'; ArcNameFmt[2] = 'r'; ArcNameFmt[3] = 'c'; ArcNameFmt[4] = 'N'; ArcNameFmt[5] = 'a'; ArcNameFmt[6] = 'm'; ArcNameFmt[7] = 'e'; ArcNameFmt[8] = '\\'; ArcNameFmt[9] = '%'; ArcNameFmt[10] = 's'; ArcNameFmt[11] = '\0'; ASSERT( ARGUMENT_PRESENT( LoaderBlock ) ); ASSERT( ARGUMENT_PRESENT( LoaderBlock->ArcHalDeviceName ) ); // // Build an appropriate discretionary ACL. // length = (ULONG) sizeof( ACL ) + ( 2 * ((ULONG) sizeof( ACCESS_ALLOWED_ACE ))) + SeLengthSid( SeLocalSystemSid ) + SeLengthSid( SeAliasAdminsSid ) + 8; // The 8 is just for good measure dacl = (PACL) ExAllocatePool( PagedPool, length ); if (!dacl) { return STATUS_INSUFFICIENT_RESOURCES; } status = RtlCreateAcl( dacl, length, ACL_REVISION2 ); if (NT_SUCCESS( status )) { status = RtlAddAccessAllowedAce( dacl, ACL_REVISION2, GENERIC_ALL, SeLocalSystemSid ); if (NT_SUCCESS( status )) { status = RtlAddAccessAllowedAce( dacl, ACL_REVISION2, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | READ_CONTROL, SeAliasAdminsSid ); if (NT_SUCCESS( status )) { // // Put it in a security descriptor so that it may be applied to // the system partition device. // status = RtlCreateSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if (NT_SUCCESS( status )) { status = RtlSetDaclSecurityDescriptor( &securityDescriptor, TRUE, dacl, FALSE ); } } } } if (!NT_SUCCESS( status )) { ExFreePool( dacl ); return status; } // // Open the ARC boot device and apply the ACL. // { NTSTATUS tmpStatus; UCHAR deviceNameBuffer[256]; STRING deviceNameString; UNICODE_STRING deviceNameUnicodeString; HANDLE deviceHandle; IO_STATUS_BLOCK ioStatusBlock; // // Begin by formulating the ARC name of the boot device in the ARC // name space. // sprintf( deviceNameBuffer, ArcNameFmt, LoaderBlock->ArcHalDeviceName ); RtlInitAnsiString( &deviceNameString, deviceNameBuffer ); status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString, &deviceNameString, TRUE ); if (NT_SUCCESS( status )) { InitializeObjectAttributes( &objectAttributes, &deviceNameUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwOpenFile( &deviceHandle, WRITE_DAC, &objectAttributes, &ioStatusBlock, TRUE, 0 ); RtlFreeUnicodeString( &deviceNameUnicodeString ); if (NT_SUCCESS( status )) { // // Apply the ACL built above to the system partition device // object. // status = ZwSetSecurityObject( deviceHandle, DACL_SECURITY_INFORMATION, &securityDescriptor ); tmpStatus = NtClose( deviceHandle ); } } } // // Free the memory used to hold the ACL. // ExFreePool( dacl ); return status; }
NTSTATUS SepCreateImpersonationTokenDacl( IN PTOKEN Token, IN PACCESS_TOKEN PrimaryToken, OUT PACL *Acl ) /*++ Routine Description: This routine modifies the DACL protecting the passed token to allow the current user (described by the PrimaryToken parameter) full access. This permits callers of NtOpenThreadToken to call with OpenAsSelf==TRUE and succeed. The new DACL placed on the token is as follows: ACE 0 - Server gets TOKEN_ALL_ACCESS ACE 1 - Client gets TOKEN_ALL_ACCESS ACE 2 - Admins gets TOKEN_ALL_ACCESS ACE 3 - System gets TOKEN_ALL_ACCESS ACE 4 - Restricted gets TOKEN_ALL_ACCESS Arguments: Token - The token whose protection is to be modified. PrimaryToken - Token representing the subject to be granted access. Acl - Returns the modified ACL, allocated out of PagedPool. Return Value: --*/ { PSID ServerUserSid; PSID ClientUserSid; NTSTATUS Status = STATUS_SUCCESS; ULONG AclLength; PACL NewDacl; PSECURITY_DESCRIPTOR OldDescriptor; BOOLEAN MemoryAllocated; PACL OldDacl; BOOLEAN DaclPresent; BOOLEAN DaclDefaulted; PAGED_CODE(); ServerUserSid = ((PTOKEN)PrimaryToken)->UserAndGroups[0].Sid; ClientUserSid = Token->UserAndGroups[0].Sid; // // Compute how much space we'll need for the new DACL. // AclLength = 5 * sizeof( ACCESS_ALLOWED_ACE ) - 5 * sizeof( ULONG ) + SeLengthSid( ServerUserSid ) + SeLengthSid( SeLocalSystemSid ) + SeLengthSid( ClientUserSid ) + SeLengthSid( SeAliasAdminsSid ) + SeLengthSid( SeRestrictedSid ) + sizeof( ACL ); NewDacl = ExAllocatePool( PagedPool, AclLength ); if (NewDacl == NULL) { *Acl = NULL; return STATUS_INSUFFICIENT_RESOURCES; } Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 ); ASSERT(NT_SUCCESS( Status )); Status = RtlAddAccessAllowedAce ( NewDacl, ACL_REVISION2, TOKEN_ALL_ACCESS, ServerUserSid ); ASSERT( NT_SUCCESS( Status )); Status = RtlAddAccessAllowedAce ( NewDacl, ACL_REVISION2, TOKEN_ALL_ACCESS, ClientUserSid ); ASSERT( NT_SUCCESS( Status )); Status = RtlAddAccessAllowedAce ( NewDacl, ACL_REVISION2, TOKEN_ALL_ACCESS, SeAliasAdminsSid ); ASSERT( NT_SUCCESS( Status )); Status = RtlAddAccessAllowedAce ( NewDacl, ACL_REVISION2, TOKEN_ALL_ACCESS, SeLocalSystemSid ); ASSERT( NT_SUCCESS( Status )); if(ARGUMENT_PRESENT(((PTOKEN)PrimaryToken)->RestrictedSids) || ARGUMENT_PRESENT(Token->RestrictedSids)) { Status = RtlAddAccessAllowedAce ( NewDacl, ACL_REVISION2, TOKEN_ALL_ACCESS, SeRestrictedSid ); ASSERT( NT_SUCCESS( Status )); } *Acl = NewDacl; return STATUS_SUCCESS; }
VOID SepAppendDefaultDacl( IN PTOKEN Token, IN PACL PAcl ) /*++ Routine Description: Add a default discretionary ACL to the available space at the end of the dynamic part of the token. It is the caller's responsibility to ensure that the default Dacl fits within the available space of the dynamic part of the token. The token is assumed to be locked for write access before calling this routine. Arguments: Token - Pointer to the token. PAcl - Pointer to the ACL to add. Return Value: None. --*/ { ULONG NextFree; ULONG AclSize; PAGED_CODE(); // // Add the size of the primary group to the // address of the Dynamic Part of the token to establish // where the primary group should be placed. // ASSERT(ARGUMENT_PRESENT(Token->PrimaryGroup)); NextFree = (ULONG)(Token->DynamicPart) + SeLengthSid(Token->PrimaryGroup); // // Now copy the default Dacl // AclSize = (ULONG)(PAcl->AclSize); // ASSERT(AclSize == LongAlign(AclSize)); RtlMoveMemory( (PVOID)NextFree, (PVOID)PAcl, AclSize ); Token->DefaultDacl = (PACL)NextFree; // // And decrement the amount of the dynamic part that is available. // ASSERT( AclSize <= (Token->DynamicAvailable) ); Token->DynamicAvailable -= AclSize; return; }
VOID SepAppendPrimaryGroup( IN PTOKEN Token, IN PSID PSid ) /*++ Routine Description: Add a primary group SID to the available space at the end of the dynamic part of the token. It is the caller's responsibility to ensure that the primary group SID fits within the available space of the dynamic part of the token. The token is assumed to be locked for write access before calling this routine. Arguments: Token - Pointer to the token. PSid - Pointer to the SID to add. Return Value: None. --*/ { ULONG NextFree; ULONG SidSize; PAGED_CODE(); // // Add the size of the Default Dacl (if there is one) to the // address of the Dynamic Part of the token to establish // where the primary group should be placed. // if (ARGUMENT_PRESENT(Token->DefaultDacl)) { // ASSERT( (ULONG)(Token->DefaultDacl->AclSize) == // LongAlign(Token->DefaultDacl->AclSize) ); NextFree = (ULONG)(Token->DynamicPart) + Token->DefaultDacl->AclSize; } else { NextFree = (ULONG)(Token->DynamicPart); } // // Now copy the primary group SID. // SidSize = SeLengthSid( PSid ); RtlMoveMemory( (PVOID)NextFree, (PVOID)PSid, SidSize ); Token->PrimaryGroup = (PSID)NextFree; // // And decrement the amount of the dynamic part that is available. // ASSERT( SidSize <= (Token->DynamicAvailable) ); Token->DynamicAvailable -= SidSize; return; }
VOID SepFreeDefaultDacl( IN PTOKEN Token ) /*++ Routine Description: Free up the space in the dynamic part of the token take up by the default discretionary access control list. The token is assumed to be locked for write access before calling this routine. Arguments: Token - Pointer to the token. Return Value: None. --*/ { ULONG PrimaryGroupSize; PAGED_CODE(); // // Add the size of the Default Dacl (if there is one) to the // DynamicAvailable field. // if (ARGUMENT_PRESENT(Token->DefaultDacl)) { Token->DynamicAvailable += Token->DefaultDacl->AclSize; Token->DefaultDacl = NULL; } // // If it is not already at the beginning of the dynamic part, move // the primary group there (remember to update the pointer to it). // if (Token->DynamicPart != (PULONG)(Token->PrimaryGroup)) { PrimaryGroupSize = SeLengthSid( Token->PrimaryGroup ); RtlMoveMemory( (PVOID)(Token->DynamicPart), (PVOID)(Token->PrimaryGroup), PrimaryGroupSize ); Token->PrimaryGroup = (PSID)(Token->DynamicPart); } return; }
NTSTATUS NtSetInformationToken ( IN HANDLE TokenHandle, IN TOKEN_INFORMATION_CLASS TokenInformationClass, IN PVOID TokenInformation, IN ULONG TokenInformationLength ) /*++ Routine Description: Modify information in a specified token. Arguments: TokenHandle - Provides a handle to the token to operate on. TokenInformationClass - The token information class being set. TokenInformation - The buffer containing the new values for the specified class of information. The buffer must be aligned on at least a longword boundary. The actual structures provided are dependent upon the information class specified, as defined in the TokenInformationClass parameter description. TokenInformation Format By Information Class: TokenUser => This value is not a valid value for this API. The User ID may not be replaced. TokenGroups => This value is not a valid value for this API. The Group IDs may not be replaced. However, groups may be enabled and disabled using NtAdjustGroupsToken(). TokenPrivileges => This value is not a valid value for this API. Privilege information may not be replaced. However, privileges may be explicitly enabled and disabled using the NtAdjustPrivilegesToken API. TokenOwner => TOKEN_OWNER data structure. TOKEN_ADJUST_DEFAULT access is needed to replace this information in a token. The owner values that may be specified are restricted to the user and group IDs with an attribute indicating they may be assigned as the owner of objects. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure. TOKEN_ADJUST_DEFAULT access is needed to replace this information in a token. The primary group values that may be specified are restricted to be one of the group IDs already in the token. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure. TOKEN_ADJUST_DEFAULT access is needed to replace this information in a token. The ACL provided as a new default discretionary ACL is not validated for structural correctness or consistency. TokenSource => This value is not a valid value for this API. The source name and context handle may not be replaced. TokenStatistics => This value is not a valid value for this API. The statistics of a token are read-only. TokenInformationLength - Indicates the length, in bytes, of the TokenInformation buffer. This is only the length of the primary buffer. All extensions of the primary buffer are self describing. Return Value: STATUS_SUCCESS - The operation was successful. STATUS_INVALID_OWNER - The ID specified to be an owner (or default owner) is not one the caller may assign as the owner of an object. STATUS_INVALID_INFO_CLASS - The specified information class is not one that may be specified in this API. STATUS_ALLOTTED_SPACE_EXCEEDED - The space allotted for storage of the default discretionary access control and the primary group ID is not large enough to accept the new value of one of these fields. --*/ { KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PTOKEN Token; ULONG Index; BOOLEAN Found; BOOLEAN TokenModified = FALSE; ULONG NewLength; ULONG CurrentLength; PSID CapturedOwner; PSID CapturedPrimaryGroup; PACL CapturedDefaultDacl; PAGED_CODE(); // // Get previous processor mode and probe input buffer if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { // // This just probes the main part of the information buffer. // Any information class-specific data hung off the primary // buffer are self describing and must be probed separately // below. // ProbeForRead( TokenInformation, TokenInformationLength, sizeof(ULONG) ); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } // // Return error if not legal class // if ( (TokenInformationClass != TokenOwner) && (TokenInformationClass != TokenPrimaryGroup) && (TokenInformationClass != TokenDefaultDacl) ) { return STATUS_INVALID_INFO_CLASS; } // // Check access rights and reference token // Status = ObReferenceObjectByHandle( TokenHandle, // Handle TOKEN_ADJUST_DEFAULT, // DesiredAccess SepTokenObjectType, // ObjectType PreviousMode, // AccessMode (PVOID *)&Token, // Object NULL // GrantedAccess ); if ( !NT_SUCCESS(Status) ) { return Status; } // // Case on information class. // switch ( TokenInformationClass ) { case TokenOwner: // // Make sure the buffer is large enough to hold the // necessary information class data structure. // if (TokenInformationLength < (ULONG)sizeof(TOKEN_OWNER)) { ObDereferenceObject( Token ); return STATUS_INFO_LENGTH_MISMATCH; } // // Capture and copy try { // // Capture Owner SID // CapturedOwner = ((PTOKEN_OWNER)TokenInformation)->Owner; Status = SeCaptureSid( CapturedOwner, PreviousMode, NULL, 0, PagedPool, TRUE, &CapturedOwner ); } except(EXCEPTION_EXECUTE_HANDLER) { ObDereferenceObject( Token ); return GetExceptionCode(); } if (!NT_SUCCESS(Status)) { ObDereferenceObject( Token ); return Status; } // // Gain write access to the token. // SepAcquireTokenWriteLock( Token ); // // Walk through the list of user and group IDs looking // for a match to the specified SID. If one is found, // make sure it may be assigned as an owner. If it can, // then set the index in the token's OwnerIndex field. // Otherwise, return invalid owner error. // Index = 0; while (Index < Token->UserAndGroupCount) { try { Found = RtlEqualSid( CapturedOwner, Token->UserAndGroups[Index].Sid ); if ( Found ) { if ( SepIdAssignableAsOwner(Token,Index) ){ Token->DefaultOwnerIndex = Index; TokenModified = TRUE; Status = STATUS_SUCCESS; } else { Status = STATUS_INVALID_OWNER; } //endif assignable SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); SeReleaseSid( CapturedOwner, PreviousMode, TRUE); return Status; } //endif Found } except(EXCEPTION_EXECUTE_HANDLER) { SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); SeReleaseSid( CapturedOwner, PreviousMode, TRUE); return GetExceptionCode(); } //endtry Index += 1; } //endwhile SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); SeReleaseSid( CapturedOwner, PreviousMode, TRUE); return STATUS_INVALID_OWNER; case TokenPrimaryGroup: // // Assuming everything works out, the strategy is to move everything // in the Dynamic part of the token (exept the primary group) to // the beginning of the dynamic part, freeing up the entire end of // the dynamic part for the new primary group. // // // Make sure the buffer is large enough to hold the // necessary information class data structure. // if (TokenInformationLength < (ULONG)sizeof(TOKEN_PRIMARY_GROUP)) { ObDereferenceObject( Token ); return STATUS_INFO_LENGTH_MISMATCH; } // // Capture And Validate TOKEN_PRIMARY_GROUP and corresponding SID. // try { CapturedPrimaryGroup = ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup; Status = SeCaptureSid( CapturedPrimaryGroup, PreviousMode, NULL, 0, PagedPool, TRUE, &CapturedPrimaryGroup ); } except(EXCEPTION_EXECUTE_HANDLER) { ObDereferenceObject( Token ); return GetExceptionCode(); } if (!NT_SUCCESS(Status)) { ObDereferenceObject( Token ); return Status; } // // Gain write access to the token. // SepAcquireTokenWriteLock( Token ); // // See if there is enough room in the dynamic part of the token // to replace the current Primary Group with the one specified. // NewLength = SeLengthSid( CapturedPrimaryGroup ); CurrentLength = SeLengthSid( Token->PrimaryGroup ); if (NewLength > (CurrentLength + Token->DynamicAvailable) ) { SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE); return STATUS_ALLOTTED_SPACE_EXCEEDED; } // // Free up the existing primary group // SepFreePrimaryGroup( Token ); // // And put the new SID in its place // SepAppendPrimaryGroup( Token, CapturedPrimaryGroup ); TokenModified = TRUE; // // All done. // SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE); return STATUS_SUCCESS; case TokenDefaultDacl: // // Assuming everything works out, the strategy is to move everything // in the Dynamic part of the token (exept the default Dacl) to // the beginning of the dynamic part, freeing up the entire end of // the dynamic part for the new default Dacl. // // // Make sure the buffer is large enough to hold the // necessary information class data structure. // if (TokenInformationLength < (ULONG)sizeof(TOKEN_DEFAULT_DACL)) { ObDereferenceObject( Token ); return STATUS_INFO_LENGTH_MISMATCH; } // // Capture And Validate TOKEN_DEFAULT_DACL and corresponding ACL. // try { CapturedDefaultDacl = ((PTOKEN_DEFAULT_DACL)TokenInformation)->DefaultDacl; if (ARGUMENT_PRESENT(CapturedDefaultDacl)) { Status = SeCaptureAcl( CapturedDefaultDacl, PreviousMode, NULL, 0, PagedPool, TRUE, &CapturedDefaultDacl, &NewLength ); } else { NewLength = 0; Status = STATUS_SUCCESS; } } except(EXCEPTION_EXECUTE_HANDLER) { ObDereferenceObject( Token ); return GetExceptionCode(); } if (!NT_SUCCESS(Status)) { ObDereferenceObject( Token ); return Status; } // // Gain write access to the token. // SepAcquireTokenWriteLock( Token ); // // See if there is enough room in the dynamic part of the token // to replace the current Default Dacl with the one specified. // if (ARGUMENT_PRESENT(Token->DefaultDacl)) { CurrentLength = Token->DefaultDacl->AclSize; } else { CurrentLength = 0; } if (NewLength > (CurrentLength + Token->DynamicAvailable) ) { SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); if (ARGUMENT_PRESENT(CapturedDefaultDacl)) { SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE); } return STATUS_ALLOTTED_SPACE_EXCEEDED; } // // Free up the existing Default Dacl // SepFreeDefaultDacl( Token ); // // And put the new ACL in its place // if (ARGUMENT_PRESENT(CapturedDefaultDacl)) { SepAppendDefaultDacl( Token, CapturedDefaultDacl ); } TokenModified = TRUE; // // All done. // SepReleaseTokenWriteLock( Token, TokenModified ); ObDereferenceObject( Token ); if (ARGUMENT_PRESENT(CapturedDefaultDacl)) { SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE); } return STATUS_SUCCESS; } //endswitch ASSERT( TRUE == FALSE ); // Should never reach here. }
BOOLEAN ObInitSystem( VOID ) /*++ Routine Description: This function performs the system initialization for the object manager. The object manager data structures are self describing with the exception of the root directory, the type object type and the directory object type. The initialization code then constructs these objects by hand to get the ball rolling. Arguments: None. Return Value: TRUE if successful and FALSE if an error occurred. The following errors can occur: - insufficient memory --*/ { USHORT CreateInfoMaxDepth; USHORT NameBufferMaxDepth; ULONG RegionSegmentSize; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING TypeTypeName; UNICODE_STRING SymbolicLinkTypeName; UNICODE_STRING DosDevicesDirectoryName; UNICODE_STRING DirectoryTypeName; UNICODE_STRING RootDirectoryName; UNICODE_STRING TypeDirectoryName; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE RootDirectoryHandle; HANDLE TypeDirectoryHandle; PLIST_ENTRY Next, Head; POBJECT_HEADER ObjectTypeHeader; POBJECT_HEADER_CREATOR_INFO CreatorInfo; POBJECT_HEADER_NAME_INFO NameInfo; MM_SYSTEMSIZE SystemSize; SECURITY_DESCRIPTOR AuditSd; PSECURITY_DESCRIPTOR EffectiveSd; PACL AuditAllAcl; UCHAR AuditAllBuffer[250]; // Ample room for the ACL ULONG AuditAllLength; PACE_HEADER Ace; // // PHASE 0 Initialization // if (InitializationPhase == 0) { // // Determine the the size of the object creation and the name buffer // lookaside lists. // SystemSize = MmQuerySystemSize(); if (SystemSize == MmLargeSystem) { if (MmIsThisAnNtAsSystem()) { CreateInfoMaxDepth = 64; NameBufferMaxDepth = 32; } else { CreateInfoMaxDepth = 32; NameBufferMaxDepth = 16; } } else { CreateInfoMaxDepth = 3; NameBufferMaxDepth = 3; } // // Initialize the object creation lookaside list. // ExInitializeNPagedLookasideList(&ObpCreateInfoLookasideList, NULL, NULL, 0, sizeof(OBJECT_CREATE_INFORMATION), 'iCbO', CreateInfoMaxDepth); // // Initialize the name buffer lookaside list. // ExInitializeNPagedLookasideList(&ObpNameBufferLookasideList, NULL, NULL, 0, OBJECT_NAME_BUFFER_SIZE, 'mNbO', NameBufferMaxDepth); InitializeListHead( &ObpRemoveObjectQueue ); // // Initialize security descriptor cache // ObpInitSecurityDescriptorCache(); KeInitializeMutant( &ObpInitKillMutant, FALSE ); KeInitializeEvent( &ObpDefaultObject, NotificationEvent, TRUE ); KeInitializeSpinLock( &ObpLock ); PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS; PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS; // // Initialize the quota block // KeInitializeSpinLock(&PspDefaultQuotaBlock.QuotaLock); PspDefaultQuotaBlock.ReferenceCount = 1; PspDefaultQuotaBlock.QuotaPoolLimit[PagedPool] = (ULONG)-1; PspDefaultQuotaBlock.QuotaPoolLimit[NonPagedPool] = (ULONG)-1; PspDefaultQuotaBlock.PagefileLimit = (ULONG)-1; PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock; PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL, 0, 0 ); RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) ); ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer ); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.PoolType = NonPagedPool; RtlInitUnicodeString( &TypeTypeName, L"Type" ); ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpTypeMapping; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_TYPE ); ObjectTypeInitializer.MaintainTypeList = TRUE; ObjectTypeInitializer.UseDefaultObject = TRUE; ObCreateObjectType( &TypeTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpTypeObjectType ); RtlInitUnicodeString( &DirectoryTypeName, L"Directory" ); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_DIRECTORY ); ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping; ObjectTypeInitializer.MaintainTypeList = FALSE; ObCreateObjectType( &DirectoryTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpDirectoryObjectType ); RtlInitUnicodeString( &SymbolicLinkTypeName, L"SymbolicLink" ); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_SYMBOLIC_LINK ); ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping; ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink; ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink; ObCreateObjectType( &SymbolicLinkTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpSymbolicLinkObjectType ); ExInitializeResourceLite( &ObpRootDirectoryMutex ); #if i386 && !FPO ObpCurCachedGrantedAccessIndex = 0; ObpMaxCachedGrantedAccessIndex = PAGE_SIZE / sizeof( ACCESS_MASK ); ObpCachedGrantedAccesses = ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE, 'gAbO' ); #endif // i386 && !FPO #if DBG ObpCreateObjectEventId = RtlCreateEventId( NULL, 0, "CreateObject", 6, RTL_EVENT_ULONG_PARAM, "Object", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Type", 0, RTL_EVENT_ULONG_PARAM, "PagedPool", 0, RTL_EVENT_ULONG_PARAM, "NonPagedPool", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Name", 0, RTL_EVENT_FLAGS_PARAM, "", 5, OBJ_INHERIT, "Inherit", OBJ_PERMANENT, "Permanent", OBJ_OPENIF, "OpenIf", OBJ_CASE_INSENSITIVE, "CaseInsenitive", OBJ_EXCLUSIVE, "Exclusive" ); ObpFreeObjectEventId = RtlCreateEventId( NULL, 0, "FreeObject", 3, RTL_EVENT_ULONG_PARAM, "Object", 0, RTL_EVENT_ULONG_PARAM, "Type", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Name", 0 ); #endif // DBG } // End of Phase 0 Initializtion // // PHASE 1 Initialization // if (InitializationPhase == 1) { EffectiveSd = SePublicDefaultSd; // // This code is only executed if base auditing is turned on. // if ((ObpAuditBaseDirectories != 0) || (ObpAuditBaseObjects != 0)) { // // build an SACL to audit // AuditAllAcl = (PACL)AuditAllBuffer; AuditAllLength = (ULONG)sizeof(ACL) + ((ULONG)sizeof(SYSTEM_AUDIT_ACE)) + SeLengthSid(SeWorldSid); ASSERT( sizeof(AuditAllBuffer) > AuditAllLength ); Status = RtlCreateAcl( AuditAllAcl, AuditAllLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAuditAccessAce ( AuditAllAcl, ACL_REVISION2, GENERIC_ALL, SeWorldSid, TRUE, TRUE //Audit success and failure ); ASSERT( NT_SUCCESS(Status) ); Status = RtlGetAce( AuditAllAcl, 0, (PVOID)&Ace ); ASSERT( NT_SUCCESS(Status) ); if (ObpAuditBaseDirectories != 0) { Ace->AceFlags |= (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); } if (ObpAuditBaseObjects != 0) { Ace->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); } // // Now create a security descriptor that looks just like // the public default, but has auditing in it as well. EffectiveSd = (PSECURITY_DESCRIPTOR)&AuditSd; Status = RtlCreateSecurityDescriptor( EffectiveSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( EffectiveSd, TRUE, // DaclPresent SePublicDefaultDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetSaclSecurityDescriptor( EffectiveSd, TRUE, // DaclPresent AuditAllAcl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); } // // We only need to use the EffectiveSd on the root. The SACL // will be inherited by all other objects. // RtlInitUnicodeString( &RootDirectoryName, L"\\" ); InitializeObjectAttributes( &ObjectAttributes, &RootDirectoryName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, EffectiveSd ); Status = NtCreateDirectoryObject( &RootDirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = ObReferenceObjectByHandle( RootDirectoryHandle, 0, ObpDirectoryObjectType, KernelMode, (PVOID *)&ObpRootDirectoryObject, NULL ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = NtClose( RootDirectoryHandle ); if (!NT_SUCCESS( Status )) { return( FALSE ); } RtlInitUnicodeString( &TypeDirectoryName, L"\\ObjectTypes" ); InitializeObjectAttributes( &ObjectAttributes, &TypeDirectoryName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL ); Status = NtCreateDirectoryObject( &TypeDirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = ObReferenceObjectByHandle( TypeDirectoryHandle, 0, ObpDirectoryObjectType, KernelMode, (PVOID *)&ObpTypeDirectoryObject, NULL ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = NtClose( TypeDirectoryHandle ); if (!NT_SUCCESS( Status )) { return( FALSE ); } ObpEnterRootDirectoryMutex(); Head = &ObpTypeObjectType->TypeList; Next = Head->Flink; while (Next != Head) { CreatorInfo = CONTAINING_RECORD( Next, OBJECT_HEADER_CREATOR_INFO, TypeList ); ObjectTypeHeader = (POBJECT_HEADER)(CreatorInfo+1); NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectTypeHeader ); if (NameInfo != NULL && NameInfo->Directory == NULL) { if (!ObpLookupDirectoryEntry( ObpTypeDirectoryObject, &NameInfo->Name, OBJ_CASE_INSENSITIVE ) ) { ObpInsertDirectoryEntry( ObpTypeDirectoryObject, &ObjectTypeHeader->Body ); } } Next = Next->Flink; } ObpLeaveRootDirectoryMutex(); // // Create \DosDevices object directory for drive letters and Win32 device names // Status = ObpCreateDosDevicesDirectory(); if (!NT_SUCCESS( Status )) { return FALSE; } } return TRUE; }
VOID NtfsInitializeNtfsData ( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine initializes the global ntfs data record Arguments: DriverObject - Supplies the driver object for NTFS Return Value: None. --*/ { USHORT FileLockMaxDepth; USHORT IoContextMaxDepth; USHORT IrpContextMaxDepth; USHORT KeventMaxDepth; USHORT ScbNonpagedMaxDepth; USHORT ScbSnapshotMaxDepth; USHORT CcbDataMaxDepth; USHORT CcbMaxDepth; USHORT DeallocatedRecordsMaxDepth; USHORT FcbDataMaxDepth; USHORT FcbIndexMaxDepth; USHORT IndexContextMaxDepth; USHORT LcbMaxDepth; USHORT NukemMaxDepth; USHORT ScbDataMaxDepth; PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; BOOLEAN CapturedSubjectContext = FALSE; PACL SystemDacl = NULL; ULONG SystemDaclLength; PSID AdminSid = NULL; PSID SystemSid = NULL; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsInitializeNtfsData\n") ); // // Zero the record and set its node type code and size // RtlZeroMemory( &NtfsData, sizeof(NTFS_DATA)); NtfsData.NodeTypeCode = NTFS_NTC_DATA_HEADER; NtfsData.NodeByteSize = sizeof(NTFS_DATA); // // Initialize the queue of mounted Vcbs // InitializeListHead(&NtfsData.VcbQueue); // // This list head keeps track of closes yet to be done. // InitializeListHead( &NtfsData.AsyncCloseList ); InitializeListHead( &NtfsData.DelayedCloseList ); ExInitializeWorkItem( &NtfsData.NtfsCloseItem, (PWORKER_THREAD_ROUTINE)NtfsFspClose, NULL ); // // Set the driver object, device object, and initialize the global // resource protecting the file system // NtfsData.DriverObject = DriverObject; ExInitializeResource( &NtfsData.Resource ); // // Now allocate and initialize the s-list structures used as our pool // of IRP context records. The size of the zone is based on the // system memory size. We also initialize the spin lock used to protect // the zone. // KeInitializeSpinLock( &NtfsData.StrucSupSpinLock ); { switch ( MmQuerySystemSize() ) { case MmSmallSystem: NtfsData.FreeEresourceTotal = 14; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 4; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 8; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 4; CcbMaxDepth = 4; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 8; FcbIndexMaxDepth = 4; IndexContextMaxDepth = 8; LcbMaxDepth = 4; NukemMaxDepth = 8; ScbDataMaxDepth = 4; SetFlag( NtfsData.Flags, NTFS_FLAGS_SMALL_SYSTEM ); NtfsMaxDelayedCloseCount = MAX_DELAYED_CLOSE_COUNT; break; case MmMediumSystem: NtfsData.FreeEresourceTotal = 30; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 8; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 30; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 12; CcbMaxDepth = 6; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 30; FcbIndexMaxDepth = 12; IndexContextMaxDepth = 8; LcbMaxDepth = 12; NukemMaxDepth = 8; ScbDataMaxDepth = 12; SetFlag( NtfsData.Flags, NTFS_FLAGS_MEDIUM_SYSTEM ); NtfsMaxDelayedCloseCount = 4 * MAX_DELAYED_CLOSE_COUNT; break; case MmLargeSystem: SetFlag( NtfsData.Flags, NTFS_FLAGS_LARGE_SYSTEM ); NtfsMaxDelayedCloseCount = 16 * MAX_DELAYED_CLOSE_COUNT; if (MmIsThisAnNtAsSystem()) { NtfsData.FreeEresourceTotal = 256; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 256; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 128; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 40; CcbMaxDepth = 20; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 128; FcbIndexMaxDepth = 40; IndexContextMaxDepth = 8; LcbMaxDepth = 40; NukemMaxDepth = 8; ScbDataMaxDepth = 40; } else { NtfsData.FreeEresourceTotal = 128; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 64; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 64; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 20; CcbMaxDepth = 10; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 64; FcbIndexMaxDepth = 20; IndexContextMaxDepth = 8; LcbMaxDepth = 20; NukemMaxDepth = 8; ScbDataMaxDepth = 20; } break; } NtfsMinDelayedCloseCount = NtfsMaxDelayedCloseCount * 4 / 5; } // // Initialize our various lookaside lists. To make it a bit more readable we'll // define two quick macros to do the initialization // #if DBG && i386 && defined (NTFSPOOLCHECK) #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #else // DBG && i386 #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #endif // DBG && i386 NPagedInit( &NtfsFileLockLookasideList, sizeof(FILE_LOCK), 'kftN', FileLockMaxDepth ); NPagedInit( &NtfsIoContextLookasideList, sizeof(NTFS_IO_CONTEXT), 'IftN', IoContextMaxDepth ); NPagedInit( &NtfsIrpContextLookasideList, sizeof(IRP_CONTEXT), 'iftN', IrpContextMaxDepth ); NPagedInit( &NtfsKeventLookasideList, sizeof(KEVENT), 'KftN', KeventMaxDepth ); NPagedInit( &NtfsScbNonpagedLookasideList, sizeof(SCB_NONPAGED), 'nftN', ScbNonpagedMaxDepth ); NPagedInit( &NtfsScbSnapshotLookasideList, sizeof(SCB_SNAPSHOT), 'TftN', ScbSnapshotMaxDepth ); PagedInit( &NtfsCcbLookasideList, sizeof(CCB), 'CftN', CcbMaxDepth ); PagedInit( &NtfsCcbDataLookasideList, sizeof(CCB_DATA), 'cftN', CcbDataMaxDepth ); PagedInit( &NtfsDeallocatedRecordsLookasideList, sizeof(DEALLOCATED_RECORDS), 'DftN', DeallocatedRecordsMaxDepth ); PagedInit( &NtfsFcbDataLookasideList, sizeof(FCB_DATA), 'fftN', FcbDataMaxDepth ); PagedInit( &NtfsFcbIndexLookasideList, sizeof(FCB_INDEX), 'FftN', FcbIndexMaxDepth ); PagedInit( &NtfsIndexContextLookasideList, sizeof(INDEX_CONTEXT), 'EftN', IndexContextMaxDepth ); PagedInit( &NtfsLcbLookasideList, sizeof(LCB), 'lftN', LcbMaxDepth ); PagedInit( &NtfsNukemLookasideList, sizeof(NUKEM), 'NftN', NukemMaxDepth ); PagedInit( &NtfsScbDataLookasideList, SIZEOF_SCB_DATA, 'sftN', ScbDataMaxDepth ); // // Initialize the cache manager callback routines, First are the routines // for normal file manipulations, followed by the routines for // volume manipulations. // { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireScbForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseScbFromLazyWrite; Callbacks->AcquireForReadAhead = &NtfsAcquireScbForReadAhead; Callbacks->ReleaseFromReadAhead = &NtfsReleaseScbFromReadAhead; } { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerVolumeCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireVolumeFileForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseVolumeFileFromLazyWrite; Callbacks->AcquireForReadAhead = NULL; Callbacks->ReleaseFromReadAhead = NULL; } // // Initialize the queue of read ahead threads // InitializeListHead(&NtfsData.ReadAheadThreads); // // Set up global pointer to our process. // NtfsData.OurProcess = PsGetCurrentProcess(); // // Use a try-finally to cleanup on errors. // try { SECURITY_DESCRIPTOR NewDescriptor; SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY; SubjectContext = NtfsAllocatePool( PagedPool, sizeof( SECURITY_SUBJECT_CONTEXT )); SeCaptureSubjectContext( SubjectContext ); CapturedSubjectContext = TRUE; // // Build the default security descriptor which gives full access to // system and administrator. // AdminSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 2 )); RtlInitializeSid( AdminSid, &Authority, 2 ); *(RtlSubAuthoritySid( AdminSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID; *(RtlSubAuthoritySid( AdminSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS; SystemSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 1 )); RtlInitializeSid( SystemSid, &Authority, 1 ); *(RtlSubAuthoritySid( SystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; SystemDaclLength = sizeof( ACL ) + (2 * sizeof( ACCESS_ALLOWED_ACE )) + SeLengthSid( AdminSid ) + SeLengthSid( SystemSid ) + 8; // The 8 is just for good measure SystemDacl = NtfsAllocatePool( PagedPool, SystemDaclLength ); Status = RtlCreateAcl( SystemDacl, SystemDaclLength, ACL_REVISION2 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, SystemSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, AdminSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlCreateSecurityDescriptor( &NewDescriptor, SECURITY_DESCRIPTOR_REVISION1 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlSetDaclSecurityDescriptor( &NewDescriptor, TRUE, SystemDacl, FALSE ); if (!NT_SUCCESS( Status )) { leave; } Status = SeAssignSecurity( NULL, &NewDescriptor, &NtfsData.DefaultDescriptor, FALSE, SubjectContext, IoGetFileObjectGenericMapping(), PagedPool ); if (!NT_SUCCESS( Status )) { leave; } NtfsData.DefaultDescriptorLength = RtlLengthSecurityDescriptor( NtfsData.DefaultDescriptor ); ASSERT( SeValidSecurityDescriptor( NtfsData.DefaultDescriptorLength, NtfsData.DefaultDescriptor )); } finally { if (CapturedSubjectContext) { SeReleaseSubjectContext( SubjectContext ); } if (SubjectContext != NULL) { NtfsFreePool( SubjectContext ); } if (SystemDacl != NULL) { NtfsFreePool( SystemDacl ); } if (AdminSid != NULL) { NtfsFreePool( AdminSid ); } if (SystemSid != NULL) { NtfsFreePool( SystemSid ); } } // // Raise if we hit an error building the security descriptor. // if (!NT_SUCCESS( Status )) { ExRaiseStatus( Status ); } // // And return to our caller // DebugTrace( -1, Dbg, ("NtfsInitializeNtfsData -> VOID\n") ); return; }
BOOLEAN SepValidateAce ( IN PVOID Ace, IN PACL Dacl ) /*++ Routine Description: Performs rudimentary validation on an Ace. Ace must be within the passed ACl, the SID must be within the Ace, and the Ace must be of at least a minimal size. Arguments: Ace - Pointer to Ace to be examined Dacl - Pointer to Acl in which Ace is supposed to exist Return Value: A value of TRUE indicates the Ace is well formed, FALSE otherwise. --*/ { USHORT AceSize; USHORT AclSize; PAGED_CODE(); // // make sure ACE is within ACL // AceSize = ((PACE_HEADER)Ace)->AceSize; AclSize = Dacl->AclSize; if ( (PVOID)((PUCHAR)Ace + AceSize) > (PVOID)((PUSHORT)Dacl + AclSize)) { return(FALSE); } // // make sure SID is within ACE // if (IsKnownAceType( Ace )) { if ( (PVOID) ( (ULONG)Ace + SeLengthSid(&(((PKNOWN_ACE)Ace)->SidStart)) ) > (PVOID) ( (PUCHAR)Ace + AceSize ) ) { return(FALSE); } } // // Make sure ACE is big enough for minimum grant ACE // if (AceSize < sizeof(KNOWN_ACE)) { return(FALSE); } return(TRUE); }