/********************************************************************** * NAME EXPORTED * RtlDeleteRange * * DESCRIPTION * Deletes a given range. * * ARGUMENTS * RangeList Pointer to the range list. * Start Start of the range to be deleted. * End End of the range to be deleted. * Owner Owner of the ranges to be deleted. * * RETURN VALUE * Status * * @implemented */ NTSTATUS NTAPI RtlDeleteRange (IN OUT PRTL_RANGE_LIST RangeList, IN ULONGLONG Start, IN ULONGLONG End, IN PVOID Owner) { PRTL_RANGE_ENTRY Current; PLIST_ENTRY Entry; Entry = RangeList->ListHead.Flink; while (Entry != &RangeList->ListHead) { Current = CONTAINING_RECORD (Entry, RTL_RANGE_ENTRY, Entry); if (Current->Range.Start == Start && Current->Range.End == End && Current->Range.Owner == Owner) { RemoveEntryList (Entry); RtlpFreeMemory(Current, 0); RangeList->Count--; RangeList->Stamp++; return STATUS_SUCCESS; } Entry = Entry->Flink; } return STATUS_RANGE_NOT_FOUND; }
/* * @implemented * * RETURNS * Docs says FreeSid does NOT return a value * even thou it's defined to return a PVOID... */ PVOID NTAPI RtlFreeSid(IN PSID Sid) { PAGED_CODE_RTL(); RtlpFreeMemory(Sid, TAG_SID); return NULL; }
/********************************************************************** * NAME EXPORTED * RtlFreeRangeList * * DESCRIPTION * Deletes all ranges in a range list. * * ARGUMENTS * RangeList Pointer to the range list. * * RETURN VALUE * None * * @implemented */ VOID NTAPI RtlFreeRangeList (IN PRTL_RANGE_LIST RangeList) { PLIST_ENTRY Entry; PRTL_RANGE_ENTRY Current; while (!IsListEmpty(&RangeList->ListHead)) { Entry = RemoveHeadList (&RangeList->ListHead); Current = CONTAINING_RECORD (Entry, RTL_RANGE_ENTRY, Entry); DPRINT ("Range start: %I64u\n", Current->Range.Start); DPRINT ("Range end: %I64u\n", Current->Range.End); RtlpFreeMemory(Current, 0); } RangeList->Flags = 0; RangeList->Count = 0; }
/********************************************************************** * NAME EXPORTED * RtlAddRange * * DESCRIPTION * Adds a range to a range list. * * ARGUMENTS * RangeList Range list. * Start * End * Attributes * Flags * UserData * Owner * * RETURN VALUE * Status * * TODO: * - Support shared ranges. * * @implemented */ NTSTATUS NTAPI RtlAddRange (IN OUT PRTL_RANGE_LIST RangeList, IN ULONGLONG Start, IN ULONGLONG End, IN UCHAR Attributes, IN ULONG Flags, IN PVOID UserData OPTIONAL, IN PVOID Owner OPTIONAL) { PRTL_RANGE_ENTRY RangeEntry; PRTL_RANGE_ENTRY Previous; PRTL_RANGE_ENTRY Current; PLIST_ENTRY Entry; if (Start > End) return STATUS_INVALID_PARAMETER; /* Create new range entry */ RangeEntry = RtlpAllocateMemory(sizeof(RTL_RANGE_ENTRY), 'elRR'); if (RangeEntry == NULL) return STATUS_INSUFFICIENT_RESOURCES; /* Initialize range entry */ RangeEntry->Range.Start = Start; RangeEntry->Range.End = End; RangeEntry->Range.Attributes = Attributes; RangeEntry->Range.UserData = UserData; RangeEntry->Range.Owner = Owner; RangeEntry->Range.Flags = 0; if (Flags & RTL_RANGE_LIST_ADD_SHARED) RangeEntry->Range.Flags |= RTL_RANGE_SHARED; /* Insert range entry */ if (RangeList->Count == 0) { InsertTailList (&RangeList->ListHead, &RangeEntry->Entry); RangeList->Count++; RangeList->Stamp++; return STATUS_SUCCESS; } else { Previous = NULL; Entry = RangeList->ListHead.Flink; while (Entry != &RangeList->ListHead) { Current = CONTAINING_RECORD (Entry, RTL_RANGE_ENTRY, Entry); if (Current->Range.Start > RangeEntry->Range.End) { /* Insert before current */ DPRINT ("Insert before current\n"); InsertTailList (&Current->Entry, &RangeEntry->Entry); RangeList->Count++; RangeList->Stamp++; return STATUS_SUCCESS; } Previous = Current; Entry = Entry->Flink; } DPRINT ("Insert tail\n"); InsertTailList (&RangeList->ListHead, &RangeEntry->Entry); RangeList->Count++; RangeList->Stamp++; return STATUS_SUCCESS; } RtlpFreeMemory(RangeEntry, 0); return STATUS_UNSUCCESSFUL; }
/* * @implemented */ NTSTATUS NTAPI RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; HANDLE hDirectory; UNICODE_STRING DirectoryName, NewPath; ULONG PathLen; PISECURITY_DESCRIPTOR SecurityDescriptor = NULL; PSID SystemSid = NULL; BOOLEAN AddSep = FALSE; NTSTATUS Status; PAGED_CODE_RTL(); RtlInitUnicodeString(&DirectoryName, L"System Volume Information"); PathLen = VolumeRootPath->Length + DirectoryName.Length; /* make sure we don't overflow while appending the strings */ if (PathLen > 0xFFFC) { return STATUS_INVALID_PARAMETER; } if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\') { AddSep = TRUE; PathLen += sizeof(WCHAR); } /* allocate the new string */ NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR); NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength, TAG_USTR); if (NewPath.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } /* create the new path string */ NewPath.Length = VolumeRootPath->Length; RtlCopyMemory(NewPath.Buffer, VolumeRootPath->Buffer, NewPath.Length); if (AddSep) { NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\'; NewPath.Length += sizeof(WCHAR); } RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)), DirectoryName.Buffer, DirectoryName.Length); NewPath.Length += DirectoryName.Length; NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0'; ASSERT(NewPath.Length == PathLen); ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR)); /* create the security descriptor for the new directory */ Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor, &SystemSid); if (NT_SUCCESS(Status)) { /* create or open the directory */ InitializeObjectAttributes(&ObjectAttributes, &NewPath, 0, NULL, SecurityDescriptor); Status = ZwCreateFile(&hDirectory, SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { Status = RtlpSysVolTakeOwnership(&NewPath, SecurityDescriptor); if (NT_SUCCESS(Status)) { /* successfully took ownership, attempt to open it */ Status = ZwCreateFile(&hDirectory, SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); } } if (NT_SUCCESS(Status)) { /* check security now and adjust it if neccessary */ Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory, SecurityDescriptor); ZwClose(hDirectory); } /* free allocated memory */ ASSERT(SecurityDescriptor != NULL); ASSERT(SecurityDescriptor->Dacl != NULL); RtlpFreeMemory(SecurityDescriptor->Dacl, 'cAeS'); RtlpFreeMemory(SecurityDescriptor, 'dSeS'); RtlFreeSid(SystemSid); } RtlpFreeStringMemory(NewPath.Buffer, TAG_USTR); return Status; }
static NTSTATUS RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor, OUT PSID *SystemSid) { PSECURITY_DESCRIPTOR AbsSD = NULL; PSID LocalSystemSid = NULL; PACL Dacl = NULL; ULONG DaclSize; NTSTATUS Status; /* 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)) { return Status; } /* allocate and initialize the security descriptor */ AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR), 'dSeS'); if (AbsSD == NULL) { Status = STATUS_NO_MEMORY; goto Cleanup; } Status = RtlCreateSecurityDescriptor(AbsSD, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* allocate and create the DACL */ DaclSize = sizeof(ACL) + sizeof(ACE) + RtlLengthSid(LocalSystemSid); Dacl = RtlpAllocateMemory(DaclSize, 'cAeS'); if (Dacl == NULL) { Status = STATUS_NO_MEMORY; goto Cleanup; } Status = RtlCreateAcl(Dacl, DaclSize, ACL_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlAddAccessAllowedAceEx(Dacl, ACL_REVISION, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE, STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, LocalSystemSid); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* set the DACL in the security descriptor */ Status = RtlSetDaclSecurityDescriptor(AbsSD, TRUE, Dacl, FALSE); /* all done */ if (NT_SUCCESS(Status)) { *SecurityDescriptor = AbsSD; *SystemSid = LocalSystemSid; } else { Cleanup: if (LocalSystemSid != NULL) { RtlFreeSid(LocalSystemSid); } if (Dacl != NULL) { RtlpFreeMemory(Dacl, 'cAeS'); } if (AbsSD != NULL) { RtlpFreeMemory(AbsSD, 'dSeS'); } } 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; }