Exemple #1
0
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;
}
Exemple #2
0
static
VOID
CheckDirectorySecurity__(
    _In_ PCWSTR DirectoryName,
    _In_ PSID ExpectedOwner,
    _In_ PSID ExpectedGroup,
    _In_ ULONG AceCount,
    _In_ PCSTR FileAndLine,
    ...)
{
    NTSTATUS Status;
    UNICODE_STRING DirectoryNameString;
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE DirectoryHandle;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    ULONG SecurityDescriptorSize;
    PSID Owner;
    PSID Group;
    PACL Dacl;
    PACL Sacl;
    BOOLEAN Present;
    BOOLEAN Defaulted;
    va_list Arguments;

    RtlInitUnicodeString(&DirectoryNameString, DirectoryName);
    InitializeObjectAttributes(&ObjectAttributes,
                               &DirectoryNameString,
                               OBJ_KERNEL_HANDLE,
                               NULL,
                               NULL);
    Status = ZwOpenDirectoryObject(&DirectoryHandle,
                                   READ_CONTROL | ACCESS_SYSTEM_SECURITY,
                                   &ObjectAttributes);
    ok_eq_hex(Status, STATUS_SUCCESS);
    if (skip(NT_SUCCESS(Status), "No directory (%ls)\n", DirectoryName))
    {
        return;
    }

    Status = ZwQuerySecurityObject(DirectoryHandle,
                                   OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
                                   NULL,
                                   0,
                                   &SecurityDescriptorSize);
    ok_eq_hex(Status, STATUS_BUFFER_TOO_SMALL);
    if (skip(Status == STATUS_BUFFER_TOO_SMALL, "No security size (%ls)\n", DirectoryName))
    {
        ObCloseHandle(DirectoryHandle, KernelMode);
        return;
    }

    SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
                                               SecurityDescriptorSize,
                                               'dSmK');
    ok(SecurityDescriptor != NULL, "Failed to allocate %lu bytes\n", SecurityDescriptorSize);
    if (skip(SecurityDescriptor != NULL, "No memory for descriptor (%ls)\n", DirectoryName))
    {
        ObCloseHandle(DirectoryHandle, KernelMode);
        return;
    }

    Status = ZwQuerySecurityObject(DirectoryHandle,
                                   OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
                                   SecurityDescriptor,
                                   SecurityDescriptorSize,
                                   &SecurityDescriptorSize);
    ok_eq_hex(Status, STATUS_SUCCESS);
    if (NT_SUCCESS(Status))
    {
        Owner = NULL;
        Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
                                               &Owner,
                                               &Defaulted);
        if (ExpectedOwner)
            CheckSid__(Owner, NO_SIZE, ExpectedOwner, FileAndLine);
        ok(Defaulted == FALSE, "Owner defaulted for %ls\n", DirectoryName);

        Group = NULL;
        Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
                                               &Group,
                                               &Defaulted);
        if (ExpectedGroup)
            CheckSid__(Group, NO_SIZE, ExpectedGroup, FileAndLine);
        ok(Defaulted == FALSE, "Group defaulted for %ls\n", DirectoryName);

        Dacl = NULL;
        Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
                                              &Present,
                                              &Dacl,
                                              &Defaulted);
        ok_eq_hex(Status, STATUS_SUCCESS);
        ok(Present == TRUE, "DACL not present for %ls\n", DirectoryName);
        ok(Defaulted == FALSE, "DACL defaulted for %ls\n", DirectoryName);
        va_start(Arguments, FileAndLine);
        VCheckAcl__(Dacl, AceCount, FileAndLine, Arguments);
        va_end(Arguments);

        Sacl = NULL;
        Status = RtlGetSaclSecurityDescriptor(SecurityDescriptor,
                                              &Present,
                                              &Sacl,
                                              &Defaulted);
        ok_eq_hex(Status, STATUS_SUCCESS);
        ok(Present == FALSE, "SACL present for %ls\n", DirectoryName);
        ok(Defaulted == FALSE, "SACL defaulted for %ls\n", DirectoryName);
        ok(Sacl == NULL, "Sacl is %p for %ls\n", Sacl, DirectoryName);
    }
    ExFreePoolWithTag(SecurityDescriptor, 'dSmK');
    ObCloseHandle(DirectoryHandle, KernelMode);
}