怎样设置文件夹权限:如何在Windows中设置文件夹权限

我正在使用 Python 在创建用户 AD 帐户时创建新的个人文件夹。该文件夹正在创建但权限不正确。Python 可以将用户添加到新创建的文件夹并更改其权限吗?我不确定从哪里开始编码这个

39

您需要win32security模块,它是pywin32的一部分。

该示例为文件创建一个新的 DACL 并替换旧的 DACL,但是修改现有的 DACL 很容易;您需要做的就是从安全描述符中获取现有的 DACL,而不是创建一个空的 DACL,如下所示:

import win32security
import ntsecuritycon as con
FILENAME = "whatever"
userx, domain, type = win32security.LookupAccountName ("", "User X")
usery, domain, type = win32security.LookupAccountName ("", "User Y")
sd = win32security.GetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()   # instead of dacl = win32security.ACL()
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, con.FILE_GENERIC_READ | con.FILE_GENERIC_WRITE, userx)
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, con.FILE_ALL_ACCESS, usery)
sd.SetSecurityDescriptorDacl(1, dacl, 0)   # may not be necessary
win32security.SetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION, sd)
11

这里是使用EXPLICIT_ACCESS条目与SetEntriesInAclkindall's answer版本,创建与按规范顺序的 ACE 的适当 ACL (例如,访问被拒绝的 ACE 首先列出)。此外,此版本设置使用SetNamedSecurityInfo的 DACL,支持传播可继承的 ACE,不同于过时的功能SetFileSecurity

import ntsecuritycon
import win32security
FILENAME = "whatever"
USERX = "UserX"
USERY = "UserY"
entries = [{'AccessMode': win32security.GRANT_ACCESS,
            'AccessPermissions': 0,
            'Inheritance': win32security.CONTAINER_INHERIT_ACE |
                           win32security.OBJECT_INHERIT_ACE,
            'Trustee': {'TrusteeType': win32security.TRUSTEE_IS_USER,
                        'TrusteeForm': win32security.TRUSTEE_IS_NAME,
                        'Identifier': ''}}
            for i in range(2)]
entries[0]['AccessPermissions'] = (ntsecuritycon.GENERIC_READ |
                                   ntsecuritycon.GENERIC_WRITE)
entries[0]['Trustee']['Identifier'] = USERX
entries[1]['AccessPermissions'] = ntsecuritycon.GENERIC_ALL
entries[1]['Trustee']['Identifier'] = USERY
sd = win32security.GetNamedSecurityInfo(FILENAME, win32security.SE_FILE_OBJECT,
        win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
dacl.SetEntriesInAcl(entries)
win32security.SetNamedSecurityInfo(FILENAME, win32security.SE_FILE_OBJECT,
    win32security.DACL_SECURITY_INFORMATION |
    win32security.UNPROTECTED_DACL_SECURITY_INFORMATION,
    None, None, dacl, None)
8

For those interested in the "list" of security descriptors for ACE,what-have-ya use the following data structures.I had some help awhile back with this and have used this ever since.

typical_aces={
    2032127L:"Full Control(All)",
    1179817L:"Read(RX)",
    1180086L:"Add",
    1180095L:"Add&Read",
    1245631L:"Change"
}
binary_aces={
    1:"ACCESS_READ",            #0x00000001
    2:"ACCESS_WRITE",           #0x00000002
    4:"ACCESS_CREATE",          #0x00000004
    8:"ACCESS_EXEC",            #0x00000008
    16:"ACCESS_DELETE",         #0x00000010
    32:"ACCESS_ATRIB",          #0x00000020
    64:"ACCESS_PERM",           #0x00000040
    32768:"ACCESS_GROUP",       #0x00008000
    65536:"DELETE",             #0x00010000
    131072:"READ_CONTROL",      #0x00020000
    262144:"WRITE_DAC",         #0x00040000
    524288:"WRITE_OWNER",       #0x00080000
    1048576:"SYNCHRONIZE",      #0x00100000
    16777216:"ACCESS_SYSTEM_SECURITY",#0x01000000
    33554432:"MAXIMUM_ALLOWED", #0x02000000
    268435456:"GENERIC_ALL",    #0x10000000
    536870912:"GENERIC_EXECUTE",#0x20000000
    1073741824:"GENERIC_WRITE", #0x40000000
    65535:"SPECIFIC_RIGHTS_ALL",#0x0000ffff
    983040:"STANDARD_RIGHTS_REQUIRED",#0x000f0000
    2031616:"STANDARD_RIGHTS_ALL",#0x001f0000
    }

将掩码从给定的 DACL / 路径传递到:

def calculate_plaintext_mask(mask):
    a=2147483648L
    if typical_aces.has_key(mask):
        return typical_aces[mask]
    else:
        result='NONE'
        while a>>1:
            a=a>>1
            masked=mask&a
            if masked:
                if binary_aces.has_key(masked):
                    result=binary_aces[masked]+':'+result
    return result
7

这是一个完整的 Python 方式设置文件所有权 / ACL 递归或不在 Windows 下的 NTFS 文件,有或没有 ACL 继承。

[编辑]

我现在已经发布了这个代码作为 Python 包windows_tools.file_utils,请参阅源代码here

[/ 编辑]

首先,我们需要一个可以获取文件所有权的函数(set_file_owner()),然后我们需要一个可以在 Windows 上处理 ACL 的函数(set_acls())。

为了使权限变得容易,我们将有一个函数(easy_permissions())将 R,RX,M,F 权限转换为权限位掩码。

一旦我们得到了,我们可能只是 os.listdir 递归到一个目录(使用 get_files_recursive()),并在 PermissionError 上执行一个函数来处理权限。

底层代码:

import os
from fnmatch import fnmatch
from itertools import chain
import win32api
import win32security
import ntsecuritycon
import pywintypes
def glob_path_match(path, pattern_list):
    """
    Checks if path is in a list of glob style wildcard paths
    :param path: path of file / directory
    :param pattern_list: list of wildcard patterns to check for
    :return: Boolean
    """
    return any(fnmatch(path, pattern) for pattern in pattern_list)
def get_files_recursive(root, d_exclude_list=None, f_exclude_list=None,
                    ext_exclude_list=None, ext_include_list=None,
                    depth=0, primary_root=None, fn_on_perm_error=None,
                    include_dirs=False):
"""
Walk a path to recursively find files
Modified version of https://stackoverflow.com/a/24771959/2635443 that includes exclusion lists
and accepts glob style wildcards on files and directories
:param root: (str) path to explore
:param include_dirs: (bool) should output list include directories
:param d_exclude_list: (list) list of root relative directories paths to exclude
:param f_exclude_list: (list) list of filenames without paths to exclude
:param ext_exclude_list: list() list of file extensions to exclude, ex: ['.log', '.bak'],
       takes precedence over ext_include_list
:param ext_include_lsit: (list) only include list of file extensions, ex: ['.py']
:param depth: (int) depth of recursion to acheieve, 0 means unlimited, 1 is just the current dir...
:param primary_root: (str) Only used for internal recursive exclusion lookup, don't p an argument here
:param fn_on_perm_error: (function) Optional function to p, which argument will be the file / directory that has permission errors
:return: list of files found in path
"""
# Make sure we don't get paths with antislashes on Windows
if os.path.isdir(root):
    root = os.path.normpath(root)
else:
    return root
# Check if we are allowed to read directory, if not, try to fix permissions if fn_on_perm_error is ped
try:
    os.listdir(root)
except PermissionError:
    if fn_on_perm_error is not None:
        fn_on_perm_error(root)
# Make sure we clean d_exclude_list only on first function call
if primary_root is None:
    if d_exclude_list is not None:
        # Make sure we use a valid os separator for exclusion lists
        d_exclude_list = [os.path.normpath(d) for d in d_exclude_list]
    else:
        d_exclude_list = []
if f_exclude_list is None:
    f_exclude_list = []
if ext_exclude_list is None:
    ext_exclude_list = []
def _find_files():
    try:
        if include_dirs:
            yield root
        for f in os.listdir(root):
            file_ext = os.path.splitext(f)[1]
            if os.path.isfile(os.path.join(root, f)) and not glob_path_match(f, f_exclude_list) \
                and file_ext not in ext_exclude_list \
                and (file_ext in ext_include_list if ext_include_list is not None else True):
                yield os.path.join(root, f)
    except PermissionError:
        p
def _find_files_in_dirs(depth):
    if depth == 0 or depth > 1:
        depth = depth - 1 if depth > 1 else 0
        try:
            for d in os.listdir(root):
                d_full_path = os.path.join(root, d)
                if os.path.isdir(d_full_path):
                    # p_root is the relative root the function has been called with recursively
                    # Let's check if p_root + d is in d_exclude_list
                    p_root = os.path.join(primary_root, d) if primary_root is not None else d
                    if not glob_path_match(p_root, d_exclude_list):
                        files_in_d = get_files_recursive(d_full_path,
                                                         d_exclude_list=d_exclude_list,
                                                         f_exclude_list=f_exclude_list,
                                                         ext_exclude_list=ext_exclude_list,
                                                         ext_include_list=ext_include_list,
                                                         depth=depth, primary_root=p_root,
                                                         fn_on_perm_error=fn_on_perm_error,
                                                         include_dirs=include_dirs)
                        if include_dirs:
                            yield d
                        if files_in_d:
                            for f in files_in_d:
                                yield f
        except PermissionError:
            p
# Chain both generators
return chain(_find_files(), _find_files_in_dirs(depth))
def get_binary_sid(string=None):
    """
    Wrapper function that returns PySID object from SID identifier or username
    If none given, we'll get current user
    :param string: (str) SID identifier or username
    :return: (PySID) object
    """
    if string is None:
        string = win32api.GetUserName()
    if string.startswith('S-1-'):
        # Consider we deal with a sid string
        return win32security.GetBinarySid(string)
    else:
        # Try to resolve username
        # LookupAccountName returns tuple (user, domain, type)
        try:
            user, _, _ = win32security.LookupAccountName('', string)
            print(user)
            return user
        except pywintypes.error as e:
            raise OSError('Cannot map security ID: {0} with name. {1}'.format(string, e))
def set_file_owner(path, owner=None, force=False):
    """
    Set owner on NTFS files / directories
    https://stackoverflow.com/a/61009508/2635443
    :param path: (str) path
    :param owner: (PySID) object that represents the security identifier. If not set, current security identifier will be used
    :param force: (bool) Shall we force take ownership
    :return:
    """
    try:
        hToken = win32security.OpenThreadToken(win32api.GetCurrentThread(),
                                               win32security.TOKEN_ALL_ACCESS, True)
    except win32security.error:
        hToken = win32security.OpenProcessToken(win32api.GetCurrentProcess(),
                                                win32security.TOKEN_ALL_ACCESS)
    if owner is None:
        owner = win32security.GetTokenInformation(hToken, win32security.TokenOwner)
    prev_state = ()
    if force:
        new_state = [(win32security.LookupPrivilegeValue(None, name),
                      win32security.SE_PRIVILEGE_ENABLED)
                     for name in (win32security.SE_TAKE_OWNERSHIP_NAME,
                                  win32security.SE_RESTORE_NAME)]
        prev_state = win32security.AdjustTokenPrivileges(hToken, False,
                                                         new_state)
    try:
        sd = win32security.SECURITY_DESCRIPTOR()
        sd.SetSecurityDescriptorOwner(owner, False)
        win32security.SetFileSecurity(path, win32security.OWNER_SECURITY_INFORMATION, sd)
    except pywintypes.error as e:
        # Let's raise OSError so we don't need to import pywintypes in parent module to catch the exception
        raise OSError('Cannot take ownership of file: {0}. {1}.'.format(path, e))
    finally:
        if prev_state:
            win32security.AdjustTokenPrivileges(hToken, False, prev_state)
def easy_permissions(permission):
    """
    Creates ntsecuritycon permission bitmask from simple rights
    :param permission: (str) Simple R, RX, RWX, F  rights
    :return: (int) ntsecuritycon permission bitmask
    """
    permission = permission.upper()
    if permission == 'R':
        return ntsecuritycon.GENERIC_READ
    if permission == 'RX':
        return ntsecuritycon.GENERIC_READ | ntsecuritycon.GENERIC_EXECUTE
    if permission in ['RWX', 'M']:
        return ntsecuritycon.GENERIC_READ | ntsecuritycon.GENERIC_WRITE | ntsecuritycon.GENERIC_EXECUTE
    if permission == 'F':
        return ntsecuritycon.GENERIC_ALL
    raise ValueError('Bogus easy permission')
def set_acls(path, user_list=None, group_list=None, owner=None, permission=None, inherit=False, inheritance=False):
    """
    Set Windows DACL list
    :param path: (str) path to directory/file
    :param user_sid_list: (list) str usernames or PySID objects
    :param group_sid_list: (list) str groupnames or PySID objects
    :param owner: (str) owner name or PySID obect
    :param permission: (int) permission bitmask
    :param inherit: (bool) inherit parent permissions
    :param inheritance: (bool) apply ACL to sub folders and files
    """
    if inheritance:
        inheritance_flags = win32security.CONTAINER_INHERIT_ACE | win32security.OBJECT_INHERIT_ACE
    else:
        inheritance_flags = win32security.NO_INHERITANCE
    security_descriptor = {'AccessMode': win32security.GRANT_ACCESS,
                           'AccessPermissions': 0,
                           'Inheritance': inheritance_flags,
                           'Trustee': {'TrusteeType': '',
                                       'TrusteeForm': win32security.TRUSTEE_IS_SID,
                                       'Identifier': ''}
                           }
    # Now create a security descriptor for each user in the ACL list
    security_descriptors = []
    # If no user / group is defined, let's take current user
    if user_list is None and group_list is None:
        user_list = [get_binary_sid()]
    if user_list is not None:
        for sid in user_list:
            sid = get_binary_sid(sid)
            s = security_descriptor
            s['AccessPermissions'] = permission
            s['Trustee']['TrusteeType'] = win32security.TRUSTEE_IS_USER
            s['Trustee']['Identifier'] = sid
            security_descriptors.append(s)
    if group_list is not None:
        for sid in group_list:
            sid = get_binary_sid(sid)
            s = security_descriptor
            s['AccessPermissions'] = permission
            s['Trustee']['TrusteeType'] = win32security.TRUSTEE_IS_GROUP
            s['Trustee']['Identifier'] = sid
            security_descriptors.append(s)
    try:
        sd = win32security.GetNamedSecurityInfo(path, win32security.SE_FILE_OBJECT,
                                                win32security.DACL_SECURITY_INFORMATION | win32security.UNPROTECTED_DACL_SECURITY_INFORMATION)
    except pywintypes.error as e:
        raise OSError('Failed to read security for file: {0}. {1}'.format(path, e))
    dacl = sd.GetSecurityDescriptorDacl()
    dacl.SetEntriesInAcl(security_descriptors)
    security_information_flags = win32security.DACL_SECURITY_INFORMATION
    if not inherit:
        # PROTECTED_DACL_SECURITY_INFORMATION disables inheritance from parent
        security_information_flags = security_information_flags | win32security.PROTECTED_DACL_SECURITY_INFORMATION
    else:
        security_information_flags = security_information_flags | win32security.UNPROTECTED_DACL_SECURITY_INFORMATION
    # If we want to change owner, SetNamedSecurityInfo will need win32security.OWNER_SECURITY_INFORMATION in SECURITY_INFORMATION
    if owner is not None:
        security_information_flags = security_information_flags | win32security.OWNER_SECURITY_INFORMATION
        if isinstance(owner, str):
            owner = get_binary_sid(owner)
    try:
        # SetNamedSecurityInfo(path, object_type, security_information, owner, group, dacl, sacl)
        win32security.SetNamedSecurityInfo(path, win32security.SE_FILE_OBJECT,
                                           security_information_flags,
                                           owner, None, dacl, None)
    except pywintypes.error as e:
        raise OSError
def take_ownership_recursive(path, owner=None):
    def take_own(path):
        nonlocal owner
        try:
            set_file_owner(path, owner=owner, force=True)
        except OSError:
            print('Permission error on: {0}.'.format(path))
    files = get_files_recursive(path, include_dirs=True, fn_on_perm_error=take_own)
    for file in files:
        set_file_owner(file, force=True)
def get_files_recursive_and_set_permissions(path, owner=None, permissions=None, user_list=None):
    def fix_perms(path):
        nonlocal permissions
        nonlocal owner
        nonlocal user_list
        if permissions == None:
            permissions = easy_permissions('F')
        print('Permission error on: {0}.'.format(path))
        try:
            set_acls(path, user_list=user_list, owner=owner, permission=permissions, inheritance=False)
        except OSError:
            # Lets force ownership change
            try:
                set_file_owner(path, force=True)
                # Now try again
                set_acls(path, user_list=user_list, owner=owner, permission=permissions, inheritance=False)
            except OSError as e:
                print('Cannot fix permission on {0}. {1}'.format(path, e))
    files = get_files_recursive(path, include_dirs=True, fn_on_perm_error=fix_perms)
    for file in files:
        set_acls(file, user_list=user_list, owner=owner, permission=easy_permissions('F'), inheritance=False)

以下是如何使用代码的一些示例:

# Recursively set owner
take_ownership_recursive(r'C:\MYPATH', owner=get_binary_sid('MyUser'))
# Recursively set permissions
get_files_recursive_and_set_permissions(r'C;\MYPATH', permissions=easy_permissions('F'), user_list=['MyUser', 'MyOtherUser'])
# Recursively set permissions with inheritance
get_files_recursive_and_set_permissions(r'C:\MYPATH', permissions=easy_permissions('RX'), user_list=['S-1-5-18'], inheritance=True)
# Set permissions
set_acls(r'C:\MYPATH', permissions=easy_permissions('F'), user_list['MyUser'])
# Take ownership
set_file_owner(r'C:\MYPATH', owner=get_binary_sid('MyUser'), Force=True)

非常感谢 Eryk Sun 关于 Python 中 win32security 文件处理的所有文章,这些文章使得编写正确的代码成为可能。请参阅https://stackoverflow.com/a/43244697/2635443https://stackoverflow.com/a/61009508/2635443

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(17)
布达拉宫小程序几点开始预约:从点开始的线段(what is line segment in geometry)
上一篇
应用心理专业代码:心理套餐:应用哪种探索性因素分析方法
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(85条)