CreateFileW для READ_CONTROL завершается с ошибкой «Доступ запрещен», несмотря на то, что он является владельцем файла - PullRequest
1 голос
/ 15 октября 2019

В Windows, даже если дискреционный ACL (DACL) пуст, т.е. никто не имеет разрешения на файл, владелец файла может читать и записывать DACL (READ_CONTROL и WRITE_DAC доступ).

ИтакЯ попытался сделать следующее:

  1. Установить пустой DACL для файла
  2. Получить дескриптор файла для READ_CONTROL
  3. Получить дескриптор безопасности с помощью GetSecurityInfo и дескриптор
  4. Проверьте, что DACL фактически пуст

Однако получение дескриптора с использованием CreateFileW не удалось с ошибкой Access is denied. Удивительно, но GetFileSecurity, что эквивалентно GetSecurityInfo для файлов, работало нормально. Согласно документации , GetFileSecurity требуется READ_CONTROL доступ.

Почему CreateFileW не работает в следующем примере?

import sys
import win32security
import win32con
import win32file
import ntsecuritycon
import os

path = sys.argv[1]

with open(path, "w"):
    pass  # I am the owner of the file

print("Set empty ACL")
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = win32security.ACL()
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)

try:
    print("Ensure that ACL is empty with GetFileSecurity")
    sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
    dacl = sd.GetSecurityDescriptorDacl()
    assert 0 == dacl.GetAceCount()

    print("Try to ensure that ACL is empty using handle")
    handle = win32file.CreateFileW(
        path,
        ntsecuritycon.READ_CONTROL,
        0,
        None,  # security attributes
        win32con.OPEN_EXISTING,
        0,
        None,
    )
    sd = win32security.GetSecurityInfo(handle, win32security.SE_FILE_OBJECT, win32security.DACL_SECURITY_INFORMATION)
    dacl = sd.GetSecurityDescriptorDacl()
    assert 0 == dacl.GetAceCount()
except Exception as e:
    print("FAILURE:", e)
finally:
    print("Restore inherited ACEs before removing file")
    dacl = win32security.ACL()
    win32security.SetNamedSecurityInfo(
        path, 
        win32security.SE_FILE_OBJECT, 
        win32security.DACL_SECURITY_INFORMATION,
        None,
        None,
        dacl,
        None
    )
    os.unlink(path)

Вывод:

> python acl-test.py file
Set empty ACL
Ensure that ACL is empty with GetFileSecurity
Try to ensure that ACL is empty using handle
FAILURE: (5, 'CreateFileW', 'Access is denied.')
Restore inherited ACEs before removing file

1 Ответ

2 голосов
/ 15 октября 2019

CreateFileW внутренне вызывает NtCreateFile с параметром DesiredAccess, переданным как dwDesiredAccess | FILE_READ_ATTRIBUTES | SYNCHRONIZE. Таким образом, если вы передаете dwDesiredAccess как READ_CONTROL, то он на самом деле пытается открыть файл с доступом READ_CONTROL | FILE_READ_ATTRIBUTES | SYNCHRONIZE. FILE_READ_ATTRIBUTES доступ предоставляется неявно файловой системой, если у вызывающей стороны есть FILE_LIST_DIRECTORY доступ к родительской папке. Однако, SYNCHRONIZE доступ не будет предоставлен, если файл имеет пустой DACL.

Одним из решений здесь было бы использование NtOpenFile или NtCreateFile для точного контроля запрошенного доступа.

...