BOOLEAN TestGetAce() { UCHAR Buffer[512]; PACL Acl; STANDARD_ACE Ace; NTSTATUS Status; Acl = (PACL)Buffer; BuildAcl( Fred, Acl, 512 ); // // Get first ace // if (!NT_SUCCESS(Status = RtlGetAce(Acl, 0, (PVOID)&Ace))) { DbgPrint("RtlGetAce first ace error : %8lx\n", Status); return FALSE; } // RtlDumpAcl(Acl); // // Get middle ace // if (!NT_SUCCESS(Status = RtlGetAce(Acl, 3, (PVOID)&Ace))) { DbgPrint("RtlGetAce middle ace error : %8lx\n", Status); return FALSE; } // RtlDumpAcl(Acl); // // Get last ace // if (!NT_SUCCESS(Status = RtlGetAce(Acl, 5, (PVOID)&Ace))) { DbgPrint("RtlGetAce last ace error : %8lx\n", Status); return FALSE; } // RtlDumpAcl(Acl); return TRUE; }
static void print_dacl (PACL dacl) { DWORD i; cyglsa_printf ("DefaultDacl: (0x%08x) ", (INT_PTR) dacl); if (!dacl) cyglsa_printf ("NULL\n"); else if (IsBadReadPtr (dacl, sizeof (ACL))) cyglsa_printf ("INVALID POINTER\n"); else if (IsBadReadPtr (dacl, dacl->AclSize)) cyglsa_printf ("INVALID POINTER SPACE\n"); else { cyglsa_printf ("Rev: %d, Count: %d\n", dacl->AclRevision, dacl->AceCount); for (i = 0; i < dacl->AceCount; ++i) { PVOID vace; PACCESS_ALLOWED_ACE ace; NTSTATUS stat; stat = RtlGetAce (dacl, i, &vace); if (!NT_SUCCESS (stat)) cyglsa_printf ("[%lu] RtlGetAce status 0x%08lx\n", i, stat); else { ace = (PACCESS_ALLOWED_ACE) vace; cyglsa_printf ("Type: %x, Flags: %x, Access: %lx,", ace->Header.AceType, ace->Header.AceFlags, (DWORD) ace->Mask); print_sid (" ", i, (PISID) &ace->SidStart); } } } }
/*++ * @name GetDosDevicesProtection * * The GetDosDevicesProtection creates a security descriptor for the DOS Devices * Object Directory. * * @param DosDevicesSd * Pointer to the Security Descriptor to return. * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks Depending on the DOS Devices Protection Mode (set in the registry), * regular users may or may not have full access to the directory. * *--*/ NTSTATUS NTAPI GetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR DosDevicesSd) { SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY}; PSID WorldSid, CreatorSid, AdminSid, SystemSid; UCHAR KeyValueBuffer[0x40]; PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo; UNICODE_STRING KeyName; ULONG ProtectionMode = 0; OBJECT_ATTRIBUTES ObjectAttributes; PACL Dacl; PACCESS_ALLOWED_ACE Ace; HANDLE hKey; NTSTATUS Status; ULONG ResultLength, SidLength, AclLength; /* Create the SD */ Status = RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION); ASSERT(NT_SUCCESS(Status)); /* Initialize the System SID */ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &SystemSid); ASSERT(NT_SUCCESS(Status)); /* Initialize the World SID */ Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid); ASSERT(NT_SUCCESS(Status)); /* Initialize the Admin SID */ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminSid); ASSERT(NT_SUCCESS(Status)); /* Initialize the Creator SID */ Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1, SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0, &CreatorSid); ASSERT(NT_SUCCESS(Status)); /* Open the Session Manager Key */ RtlInitUnicodeString(&KeyName, SM_REG_KEY); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* Read the key value */ RtlInitUnicodeString(&KeyName, L"ProtectionMode"); Status = NtQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, KeyValueBuffer, sizeof(KeyValueBuffer), &ResultLength); /* Make sure it's what we expect it to be */ KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer; if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) && (*(PULONG)KeyValuePartialInfo->Data)) { /* Save the Protection Mode */ ProtectionMode = *(PULONG)KeyValuePartialInfo->Data; } /* Close the handle */ NtClose(hKey); } /* Check the Protection Mode */ if (ProtectionMode & 3) { /* Calculate SID Lengths */ SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid); AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; /* Allocate memory for the DACL */ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength); ASSERT(Dacl != NULL); /* Build the ACL and add 3 ACEs */ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, AdminSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, CreatorSid); ASSERT(NT_SUCCESS(Status)); /* Edit the ACEs to make them inheritable */ Status = RtlGetAce(Dacl, 0, (PVOID*)&Ace); ASSERT(NT_SUCCESS(Status)); Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; Status = RtlGetAce(Dacl, 1, (PVOID*)&Ace); ASSERT(NT_SUCCESS(Status)); Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace); ASSERT(NT_SUCCESS(Status)); Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; /* Set this DACL with the SD */ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE); ASSERT(NT_SUCCESS(Status)); goto Quickie; } else { /* Calculate SID Lengths */ SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid); AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; /* Allocate memory for the DACL */ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength); ASSERT(Dacl != NULL); /* Build the ACL and add 3 ACEs */ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, WorldSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, WorldSid); ASSERT(NT_SUCCESS(Status)); /* Edit the last ACE to make it inheritable */ Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace); ASSERT(NT_SUCCESS(Status)); Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; /* Set this DACL with the SD */ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE); ASSERT(NT_SUCCESS(Status)); goto Quickie; } /* FIXME: failure cases! Fail: */ /* Free the memory */ RtlFreeHeap(CsrHeap, 0, Dacl); /* FIXME: semi-failure cases! Quickie: */ Quickie: /* Free the SIDs */ RtlFreeSid(CreatorSid); RtlFreeSid(AdminSid); RtlFreeSid(WorldSid); RtlFreeSid(SystemSid); /* Return */ return Status; }
static NTSTATUS RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle, IN PISECURITY_DESCRIPTOR SecurityDescriptor) { PSECURITY_DESCRIPTOR RelSD = NULL; PSECURITY_DESCRIPTOR NewRelSD = NULL; PSECURITY_DESCRIPTOR AbsSD = NULL; #ifdef _WIN64 BOOLEAN AbsSDAllocated = FALSE; #endif PSID AdminSid = NULL; PSID LocalSystemSid = NULL; ULONG DescriptorSize; ULONG AbsSDSize, RelSDSize = 0; PACL Dacl; BOOLEAN DaclPresent, DaclDefaulted; PSID OwnerSid; BOOLEAN OwnerDefaulted; ULONG AceIndex; PACE Ace = NULL; NTSTATUS Status; /* find out how much memory we need to allocate for the self-relative descriptor we're querying */ Status = ZwQuerySecurityObject(DirectoryHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NULL, 0, &DescriptorSize); if (Status != STATUS_BUFFER_TOO_SMALL) { /* looks like the FS doesn't support security... return success */ Status = STATUS_SUCCESS; goto Cleanup; } /* allocate enough memory for the security descriptor */ RelSD = RtlpAllocateMemory(DescriptorSize, 'dSeS'); if (RelSD == NULL) { Status = STATUS_NO_MEMORY; goto Cleanup; } /* query the self-relative security descriptor */ Status = ZwQuerySecurityObject(DirectoryHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, RelSD, DescriptorSize, &DescriptorSize); if (!NT_SUCCESS(Status)) { /* FIXME - handle the case where someone else modified the owner and/or DACL while we allocated memory. But that should be *very* unlikely.... */ goto Cleanup; } /* query the owner and DACL from the descriptor */ Status = RtlGetOwnerSecurityDescriptor(RelSD, &OwnerSid, &OwnerDefaulted); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlGetDaclSecurityDescriptor(RelSD, &DaclPresent, &Dacl, &DaclDefaulted); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* create the Administrators SID */ Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminSid); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* create the local SYSTEM SID */ Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &LocalSystemSid); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* check if the Administrators are the owner and at least a not-NULL DACL is present */ if (OwnerSid != NULL && RtlEqualSid(OwnerSid, AdminSid) && DaclPresent && Dacl != NULL) { /* check the DACL for an Allowed ACE for the SYSTEM account */ AceIndex = 0; do { Status = RtlGetAce(Dacl, AceIndex++, (PVOID*)&Ace); if (!NT_SUCCESS(Status)) { Ace = NULL; } else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) { /* check if the the ACE is a set of allowed permissions for the local SYSTEM account */ if (RtlEqualSid((PSID)(Ace + 1), LocalSystemSid)) { /* check if the ACE is inherited by noncontainer and container objects, if not attempt to change that */ if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) || !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE)) { Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; Status = ZwSetSecurityObject(DirectoryHandle, DACL_SECURITY_INFORMATION, RelSD); } else { /* all done, we have access */ Status = STATUS_SUCCESS; } goto Cleanup; } } } while (Ace != NULL); } AbsSDSize = DescriptorSize; /* because we need to change any existing data we need to convert it to an absolute security descriptor first */ Status = RtlSelfRelativeToAbsoluteSD2(RelSD, &AbsSDSize); #ifdef _WIN64 if (Status == STATUS_BUFFER_TOO_SMALL) { /* this error code can only be returned on 64 bit builds because the size of an absolute security descriptor is greater than the size of a self-relative security descriptor */ ASSERT(AbsSDSize > DescriptorSize); AbsSD = RtlpAllocateMemory(DescriptorSize, 'dSeS'); if (AbsSD == NULL) { Status = STATUS_NO_MEMORY; goto Cleanup; } AbsSDAllocated = TRUE; /* make a raw copy of the self-relative descriptor */ RtlCopyMemory(AbsSD, RelSD, DescriptorSize); /* finally convert it */ Status = RtlSelfRelativeToAbsoluteSD2(AbsSD, &AbsSDSize); } else #endif { AbsSD = RelSD; } if (!NT_SUCCESS(Status)) { goto Cleanup; } /* set the owner SID */ Status = RtlSetOwnerSecurityDescriptor(AbsSD, AdminSid, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* set the DACL in the security descriptor */ Status = RtlSetDaclSecurityDescriptor(AbsSD, TRUE, SecurityDescriptor->Dacl, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* convert it back to a self-relative descriptor, find out how much memory we need */ Status = RtlAbsoluteToSelfRelativeSD(AbsSD, NULL, &RelSDSize); if (Status != STATUS_BUFFER_TOO_SMALL) { goto Cleanup; } /* allocate enough memory for the new self-relative descriptor */ NewRelSD = RtlpAllocateMemory(RelSDSize, 'dSeS'); if (NewRelSD == NULL) { Status = STATUS_NO_MEMORY; goto Cleanup; } /* convert the security descriptor to self-relative format */ Status = RtlAbsoluteToSelfRelativeSD(AbsSD, NewRelSD, &RelSDSize); if (Status == STATUS_BUFFER_TOO_SMALL) { goto Cleanup; } /* finally attempt to change the security information */ Status = ZwSetSecurityObject(DirectoryHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NewRelSD); Cleanup: if (AdminSid != NULL) { RtlFreeSid(AdminSid); } if (LocalSystemSid != NULL) { RtlFreeSid(LocalSystemSid); } if (RelSD != NULL) { RtlpFreeMemory(RelSD, 'dSeS'); } if (NewRelSD != NULL) { RtlpFreeMemory(NewRelSD, 'dSeS'); } #ifdef _WIN64 if (AbsSDAllocated) { RtlpFreeMemory(AbsSD, 'dSeS'); } #endif return Status; }
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; }
NTSTATUS ObpGetDosDevicesProtection( PSECURITY_DESCRIPTOR SecurityDescriptor ) /*++ Routine Description: This routine builds a security descriptor for use in creating the \DosDevices object directory. The protection of \DosDevices must establish inheritable protection which will dictate how dos devices created via the DefineDosDevice() and IoCreateUnprotectedSymbolicLink() apis can be managed. The protection assigned is dependent upon an administrable registry key: Key: \hkey_local_machine\System\CurrentControlSet\Control\Session Manager Value: [REG_DWORD] ProtectionMode If this value is 0x1, then Administrators may control all Dos devices, Anyone may create new Dos devices (such as net drives or additional printers), Anyone may use any Dos device, The creator of a Dos device may delete it. Note that this protects system-defined LPTs and COMs so that only administrators may redirect them. However, anyone may add additional printers and direct them to wherever they would like. This is achieved with the following protection for the DosDevices Directory object: Grant: World: Execute | Read | Write (No Inherit) Grant: System: All Access (No Inherit) Grant: World: Execute (Inherit Only) Grant: Admins: All Access (Inherit Only) Grant: System: All Access (Inherit Only) Grant: Owner: All Access (Inherit Only) If this value is 0x0, or not present, then Administrators may control all Dos devices, Anyone may create new Dos devices (such as net drives or additional printers), Anyone may use any Dos device, Anyone may delete Dos devices created with either DefineDosDevice() or IoCreateUnprotectedSymbolicLink(). This is how network drives and LPTs are created (but not COMs). This is achieved with the following protection for the DosDevices Directory object: Grant: World: Execute | Read | Write (No Inherit) Grant: System: All Access (No Inherit) Grant: World: All Access (Inherit Only) Arguments: SecurityDescriptor - The address of a security descriptor to be initialized and filled in. When this security descriptor is no longer needed, you should call ObpFreeDosDevicesProtection() to free the protection information. Return Value: Returns one of the following status codes: STATUS_SUCCESS - normal, successful completion. STATUS_NO_MEMORY - not enough memory --*/ { NTSTATUS Status; ULONG aceIndex, aclLength; PACL dacl; PACE_HEADER ace; ACCESS_MASK accessMask; UCHAR inheritOnlyFlags = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE ); // // NOTE: This routine expects the value of ObpProtectionMode to have been set // Status = RtlCreateSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); ASSERT( NT_SUCCESS( Status ) ); if (ObpProtectionMode & 0x00000001) { // // Dacl: // Grant: World: Execute | Read | Write (No Inherit) // Grant: System: All Access (No Inherit) // Grant: World: Execute (Inherit Only) // Grant: Admins: All Access (Inherit Only) // Grant: System: All Access (Inherit Only) // Grant: Owner: All Access (Inherit Only) // aclLength = sizeof( ACL ) + 6 * sizeof( ACCESS_ALLOWED_ACE ) + (2*RtlLengthSid( SeWorldSid )) + (2*RtlLengthSid( SeLocalSystemSid )) + RtlLengthSid( SeAliasAdminsSid ) + RtlLengthSid( SeCreatorOwnerSid ); dacl = (PACL)ExAllocatePool(PagedPool, aclLength ); if (dacl == NULL) { return STATUS_NO_MEMORY; } Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2); ASSERT( NT_SUCCESS( Status ) ); // // Non-inheritable ACEs first // World // System // aceIndex = 0; accessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid ); ASSERT( NT_SUCCESS( Status ) ); aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid ); ASSERT( NT_SUCCESS( Status ) ); // // Inheritable ACEs at the end of the ACL // World // Admins // System // Owner // aceIndex++; accessMask = (GENERIC_EXECUTE); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid ); ASSERT( NT_SUCCESS( Status ) ); Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); ASSERT( NT_SUCCESS( Status ) ); ace->AceFlags |= inheritOnlyFlags; aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeAliasAdminsSid ); ASSERT( NT_SUCCESS( Status ) ); Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); ASSERT( NT_SUCCESS( Status ) ); ace->AceFlags |= inheritOnlyFlags; aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid ); ASSERT( NT_SUCCESS( Status ) ); Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); ASSERT( NT_SUCCESS( Status ) ); ace->AceFlags |= inheritOnlyFlags; aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeCreatorOwnerSid ); ASSERT( NT_SUCCESS( Status ) ); Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); ASSERT( NT_SUCCESS( Status ) ); ace->AceFlags |= inheritOnlyFlags; Status = RtlSetDaclSecurityDescriptor ( SecurityDescriptor, TRUE, //DaclPresent, dacl, //Dacl FALSE //!DaclDefaulted ); ASSERT( NT_SUCCESS( Status ) ); } else { // // DACL: // Grant: World: Execute | Read | Write (No Inherit) // Grant: System: All Access (No Inherit) // Grant: World: All Access (Inherit Only) // aclLength = sizeof( ACL ) + 3 * sizeof( ACCESS_ALLOWED_ACE ) + (2*RtlLengthSid( SeWorldSid )) + RtlLengthSid( SeLocalSystemSid ); dacl = (PACL)ExAllocatePool(PagedPool, aclLength ); if (dacl == NULL) { return STATUS_NO_MEMORY; } Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2); ASSERT( NT_SUCCESS( Status ) ); // // Non-inheritable ACEs first // World // System // aceIndex = 0; accessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid ); ASSERT( NT_SUCCESS( Status ) ); aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid ); ASSERT( NT_SUCCESS( Status ) ); // // Inheritable ACEs at the end of the ACL // World // aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid ); ASSERT( NT_SUCCESS( Status ) ); Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); ASSERT( NT_SUCCESS( Status ) ); ace->AceFlags |= inheritOnlyFlags; Status = RtlSetDaclSecurityDescriptor ( SecurityDescriptor, TRUE, //DaclPresent, dacl, //Dacl FALSE //!DaclDefaulted ); ASSERT( NT_SUCCESS( Status ) ); } return STATUS_SUCCESS; }
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; }
static DWORD DeconstructSecurityDescriptor( DWORD dwLength, PSECURITY_DESCRIPTOR_RELATIVE pRelative, PDWORD pdwAllowUserCount, PWSTR** pppwszAllowUsers, PDWORD pdwDenyUserCount, PWSTR** pppwszDenyUsers, PBOOLEAN pbReadOnly ) { NTSTATUS status = STATUS_SUCCESS; DWORD dwError = 0; ULONG ulSize = 0; ULONG ulDaclSize = 0; ULONG ulSaclSize = 0; ULONG ulOwnerSize = 0; ULONG ulGroupSize = 0; PSID pOwner = NULL; PSID pGroup = NULL; PACL pSacl = NULL; PSECURITY_DESCRIPTOR_ABSOLUTE pAbsolute = NULL; PACL pDacl = NULL; ULONG ulIndex = 0; PVOID pAce = NULL; PACCESS_ALLOWED_ACE pAllow = NULL; PACCESS_DENIED_ACE pDeny = NULL; DWORD dwAllowUserCount = 0; PWSTR* ppwszAllowUsers = NULL; DWORD dwDenyUserCount = 0; PWSTR* ppwszDenyUsers = NULL; PSID pSid = NULL; PWSTR pwszUser = NULL; HANDLE hLsa = NULL; ACCESS_MASK leastMask = FILE_ALL_ACCESS; dwError = LsaOpenServer(&hLsa); BAIL_ON_LTNET_ERROR(dwError); status = RtlSelfRelativeToAbsoluteSD( pRelative, pAbsolute, &ulSize, pDacl, &ulDaclSize, pSacl, &ulSaclSize, pOwner, &ulOwnerSize, pGroup, &ulGroupSize); if (status != STATUS_BUFFER_TOO_SMALL) { dwError = LwNtStatusToWin32Error(status); BAIL_ON_LTNET_ERROR(dwError); } dwError = LwNetAllocateMemory(ulSize, OUT_PPVOID(&pAbsolute)); BAIL_ON_LTNET_ERROR(dwError); if (ulDaclSize) { dwError = LwNetAllocateMemory(ulDaclSize, OUT_PPVOID(&pDacl)); BAIL_ON_LTNET_ERROR(dwError); } if (ulSaclSize) { dwError = LwNetAllocateMemory(ulSaclSize, OUT_PPVOID(&pSacl)); BAIL_ON_LTNET_ERROR(dwError); } if (ulOwnerSize) { dwError = LwNetAllocateMemory(ulOwnerSize, OUT_PPVOID(&pOwner)); BAIL_ON_LTNET_ERROR(dwError); } if (ulGroupSize) { dwError = LwNetAllocateMemory(ulGroupSize, OUT_PPVOID(&pGroup)); BAIL_ON_LTNET_ERROR(dwError); } dwError = LwNtStatusToWin32Error( RtlSelfRelativeToAbsoluteSD( pRelative, pAbsolute, &ulSize, pDacl, &ulDaclSize, pSacl, &ulSaclSize, pOwner, &ulOwnerSize, pGroup, &ulGroupSize)); BAIL_ON_LTNET_ERROR(dwError); if (pDacl) { for (ulIndex = 0; ulIndex < RtlGetAclAceCount(pDacl); ulIndex++) { RtlGetAce(pDacl, ulIndex, &pAce); switch(((PACE_HEADER) pAce)->AceType) { case ACCESS_ALLOWED_ACE_TYPE: pAllow = pAce; pSid = (PSID) &pAllow->SidStart; if ((pAllow->Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ) { dwError = MapSidToName(hLsa, pSid, &pwszUser); if (dwError != LW_ERROR_SUCCESS) { dwError = MapBuiltinSidToName(&pwszUser, pSid); } BAIL_ON_LTNET_ERROR(dwError); dwError = LwNetAppendStringArray( &dwAllowUserCount, &ppwszAllowUsers, pwszUser); BAIL_ON_LTNET_ERROR(dwError); pwszUser = NULL; leastMask &= pAllow->Mask; } break; case ACCESS_DENIED_ACE_TYPE: pDeny = pAce; pSid = (PSID) &pDeny->SidStart; if ((pDeny->Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ) { dwError = MapSidToName(hLsa, pSid, &pwszUser); if (dwError != LW_ERROR_SUCCESS) { dwError = MapBuiltinSidToName(&pwszUser, pSid); } BAIL_ON_LTNET_ERROR(dwError); dwError = LwNetAppendStringArray( &dwDenyUserCount, &ppwszDenyUsers, pwszUser); BAIL_ON_LTNET_ERROR(dwError); pwszUser = NULL; } break; default: break; } } } *pppwszAllowUsers = ppwszAllowUsers; *pdwAllowUserCount = dwAllowUserCount; *pppwszDenyUsers = ppwszDenyUsers; *pdwDenyUserCount = dwDenyUserCount; *pbReadOnly = !((leastMask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE); cleanup: if (hLsa) { LsaCloseServer(hLsa); } LTNET_SAFE_FREE_MEMORY(pSacl); LTNET_SAFE_FREE_MEMORY(pOwner); LTNET_SAFE_FREE_MEMORY(pGroup); LTNET_SAFE_FREE_MEMORY(pwszUser); LTNET_SAFE_FREE_MEMORY(pDacl); LTNET_SAFE_FREE_MEMORY(pAbsolute); return dwError; error: *pppwszAllowUsers = NULL; *pdwAllowUserCount = 0; *pppwszDenyUsers = NULL; *pdwDenyUserCount = 0; goto cleanup; }
/****************************************************************************** * GetAce [ADVAPI32.@] */ BOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce ) { CallWin32ToNt(RtlGetAce(pAcl, dwAceIndex, pAce)); }