对windows 文件夹权限操作

关于源码解读,之前操作文件权限主要依赖salt 的win_dacl 模块的源码

下面的源码提供的功能:

  • _getUserSid(user) #根据用户名获取SID
  • _get_dacl(path, objectType) #根据文件路径和类型,获取dacl (权限类表)
  • get(path, objectType, user=None) # 根据文件路径和类型,获取ACLs
  • add_ace(path, objectType, user, permission, acetype, propagation)
  • 添加权限
from __future__ import absolute_import
import os
import re
import win32security
import ntsecuritycon
import win32api
class daclConstants(object):
    '''
    DACL constants used throughout the module
    '''
    def __init__(self):
        self.FILE_ALL_ACCESS = (ntsecuritycon.STANDARD_RIGHTS_REQUIRED | ntsecuritycon.SYNCHRONIZE | 0x1ff)

        self.hkeys_security = {
            'HKEY_LOCAL_MACHINE': 'MACHINE',
            'HKEY_USERS': 'USERS',
            'HKEY_CURRENT_USER': 'CURRENT_USER',
            'HKEY_CLASSES_ROOT': 'CLASSES_ROOT',
            'MACHINE': 'MACHINE',
            'USERS': 'USERS',
            'CURRENT_USER': 'CURRENT_USER',
            'CLASSES_ROOT': 'CLASSES_ROOT',
            'HKLM': 'MACHINE',
            'HKU': 'USERS',
            'HKCU': 'CURRENT_USER',
            'HKCR': 'CLASSES_ROOT',
            }
        self.rights = {
            win32security.SE_FILE_OBJECT: {
                'READ': {
                    'BITS': ntsecuritycon.FILE_GENERIC_READ,
                    'TEXT': 'read'},
                'WRITE': {
                    'BITS': ntsecuritycon.FILE_GENERIC_WRITE,
                    'TEXT': 'write'},
                'READ&EXECUTE': {
                    'BITS': ntsecuritycon.FILE_GENERIC_EXECUTE |
                    ntsecuritycon.FILE_GENERIC_READ,
                    'TEXT': 'read and execute'},#读取和执行
                'MODIFY': {
                    'BITS': ntsecuritycon.FILE_GENERIC_WRITE |
                    ntsecuritycon.FILE_GENERIC_READ |
                    ntsecuritycon.FILE_GENERIC_EXECUTE |
                    ntsecuritycon.DELETE,
                    'TEXT': 'modify'}, #修改
                'FULLCONTROL': {
                    'BITS': self.FILE_ALL_ACCESS,
                    'TEXT': 'full control'}#完全控制
            }
        }
        self.validAceTypes = {
            'ALLOW': {'TEXT': 'allowed', 'BITS': 0},
            'DENY': {'TEXT': 'denied', 'BITS': 1}}
        self.validPropagations = {
            win32security.SE_REGISTRY_KEY: {
                'KEY': {
                    'TEXT': 'this key only',
                    'BITS': win32security.NO_INHERITANCE},
                'KEY&SUBKEYS': {
                    'TEXT': 'this key and subkeys',
                    'BITS': win32security.CONTAINER_INHERIT_ACE},
                'SUBKEYS': {
                    'TEXT': 'subkeys only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE},
                'THIS KEY ONLY': {
                    'TEXT': 'this key only',
                    'BITS': win32security.NO_INHERITANCE},
                'THIS KEY AND SUBKEYS': {
                    'TEXT': 'this key and subkeys',
                    'BITS': win32security.CONTAINER_INHERIT_ACE},
                'SUBKEYS ONLY': {
                    'TEXT': 'subkeys only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE}
            },
            win32security.SE_FILE_OBJECT: {
                'FILE': {
                    'TEXT': 'this file/folder only',
                    'BITS': win32security.NO_INHERITANCE},
                'FOLDER': {
                    'TEXT': 'this file/folder only',
                    'BITS': win32security.NO_INHERITANCE},
                'FOLDER&SUBFOLDERS&FILES': {
                    'TEXT': 'this folder, subfolders, and files',
                    'BITS': win32security.CONTAINER_INHERIT_ACE |
                    win32security.OBJECT_INHERIT_ACE},
                'FOLDER&SUBFOLDERS': {
                    'TEXT': 'this folder and subfolders',
                    'BITS': win32security.CONTAINER_INHERIT_ACE},
                'FOLDER&FILES': {
                    'TEXT': 'this folder and files',
                    'BITS': win32security.OBJECT_INHERIT_ACE},
                'SUBFOLDERS&FILES': {
                    'TEXT': 'subfolders and files',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE |
                    win32security.OBJECT_INHERIT_ACE},
                'SUBFOLDERS': {
                    'TEXT': 'subfolders only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE},
                'FILES': {
                    'TEXT': 'files only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.OBJECT_INHERIT_ACE},
                'THIS FILE ONLY': {
                    'TEXT': 'this file/folder only',
                    'BITS': win32security.NO_INHERITANCE},
                'THIS FOLDER ONLY': {
                    'TEXT': 'this file/folder only',
                    'BITS': win32security.NO_INHERITANCE},
                'THIS FOLDER, SUBFOLDERS, AND FILES': {
                    'TEXT': 'this folder, subfolders, and files',
                    'BITS': win32security.CONTAINER_INHERIT_ACE |
                    win32security.OBJECT_INHERIT_ACE},
                'THIS FOLDER AND SUBFOLDERS': {
                    'TEXT': 'this folder and subfolders',
                    'BITS': win32security.CONTAINER_INHERIT_ACE},
                'THIS FOLDER AND FILES': {
                    'TEXT': 'this folder and files',
                    'BITS': win32security.OBJECT_INHERIT_ACE},
                'SUBFOLDERS AND FILES': {
                    'TEXT': 'subfolders and files',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE |
                    win32security.OBJECT_INHERIT_ACE},
                'SUBFOLDERS ONLY': {
                    'TEXT': 'subfolders only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.CONTAINER_INHERIT_ACE},
                'FILES ONLY': {
                    'TEXT': 'files only',
                    'BITS': win32security.INHERIT_ONLY_ACE |
                    win32security.OBJECT_INHERIT_ACE}
            }
        }

        self.objectType = {
            'FILE': win32security.SE_FILE_OBJECT,
            'DIRECTORY': win32security.SE_FILE_OBJECT,
            'REGISTRY': win32security.SE_REGISTRY_KEY}

    def getObjectTypeBit(self, t):
        '''
        returns the bit value of the string object type
        返回字符串对象类型的位值.
        '''
        if isinstance(t, str):
            t = t.upper()
            try:
                return self.objectType[t]
            except KeyError:
                print(123)
        else:
            return t

    def getSecurityHkey(self, s):
        '''
        returns the necessary string value for an HKEY for the win32security module
        返回的win32security模块HKEY必要的字符串值
        '''
        try:
            return self.hkeys_security[s]
        except KeyError:
            print(123)

    def getPermissionBit(self, t, m):
        '''
        returns a permission bit of the string permission value for the specified object type
        返回指定对象类型的字符串权限值的权限位.
        '''
        try:
            if isinstance(m, str):
                return self.rights[t][m]['BITS']
            else:
                return m
        except KeyError:
            print(123)

    def getPermissionText(self, t, m):
        '''
        returns the permission textual representation of a specified permission bit/object type
        '''
        try:
            return self.rights[t][m]['TEXT']
        except KeyError:
            print(123)

    def getAceTypeBit(self, t):
        '''
        returns the acetype bit of a text value
        '''
        try:
            return self.validAceTypes[t]['BITS']
        except KeyError:
            print(123)

    def getAceTypeText(self, t):
        '''
        returns the textual representation of a acetype bit
        '''
        try:
            return self.validAceTypes[t]['TEXT']
        except KeyError:
            print(123)

    def getPropagationBit(self, t, p):
        '''
        returns the propagation bit of a text value
        '''
        try:
            return self.validPropagations[t][p]['BITS']
        except KeyError:
            print(123)

    def getPropagationText(self, t, p):
        '''
        returns the textual representation of a propagation bit
        '''
        try:
            return self.validPropagations[t][p]['TEXT']
        except KeyError:
            print(123)

    def processPath(self, path, objectType):
        '''
        processes a path/object type combo and returns:
            registry types with the correct HKEY text representation
            files/directories with environment variables expanded
        '''
        if objectType == win32security.SE_REGISTRY_KEY:
            splt = path.split("\\")
            hive = self.getSecurityHkey(splt.pop(0).upper())
            splt.insert(0, hive)
            path = r'\\'.join(splt)
        else:
            path = os.path.expandvars(path)
        return path


def _getUserSid(user):
    '''
    return a state error dictionary, with 'sid' as a field if it could be returned
    if user is None, sid will also be None
    '''
    ret = {}

    sid_pattern = r'^S-1(-\d+){1,}$'

    if user and re.match(sid_pattern, user, re.I):
        try:
            sid = win32security.GetBinarySid(user)
        except Exception as e:
            ret['result'] = False
            ret['comment'] = 'Unable to obtain the binary security identifier for {0}.  The exception was {1}.'.format(
                user, e)
        else:
            try:
                win32security.LookupAccountSid('', sid)
                ret['result'] = True
                ret['sid'] = sid
            except Exception as e:
                ret['result'] = False
                ret['comment'] = 'Unable to lookup the account for the security identifier {0}.  The exception was {1}.'.format(
                    user, e)
    else:
        try:
            sid = win32security.LookupAccountName('', user)[0] if user else None
            ret['result'] = True
            ret['sid'] = sid
        except Exception as e:
            ret['result'] = False
            ret['comment'] = 'Unable to obtain the security identifier for {0}.  The exception was {1}.'.format(
                user, e)
    return ret


def _get_dacl(path, objectType):
    '''
    Gets the DACL of a path
    '''
    try:
        dacl = win32security.GetNamedSecurityInfo(
            path, objectType, win32security.DACL_SECURITY_INFORMATION
            ).GetSecurityDescriptorDacl()
    except Exception:
        dacl = None
    return dacl


def get(path, objectType, user=None):
    '''
    Get the ACL of an object. Will filter by user if one is provided.

    Args:
        path: The path to the object
        objectType: The type of object (FILE, DIRECTORY, REGISTRY)
        user: A user name to filter by

    Returns (dict): A dictionary containing the ACL

    CLI Example:

    .. code-block:: bash

        salt 'minion-id' win_dacl.get c:\temp directory
    '''
    ret = {'Path': path,
           'ACLs': []}

    sidRet = _getUserSid(user)

    if path and objectType:
        dc = daclConstants()
        objectTypeBit = dc.getObjectTypeBit(objectType)
        path = dc.processPath(path, objectTypeBit)
        tdacl = _get_dacl(path, objectTypeBit)
        if tdacl:
            for counter in range(0, tdacl.GetAceCount()):
                tAce = tdacl.GetAce(counter)
                if not sidRet['sid'] or (tAce[2] == sidRet['sid']):
                    ret['ACLs'].append(_ace_to_text(tAce, objectTypeBit))
    return ret

def add_ace(path, objectType, user, permission, acetype, propagation):
    r'''
    add an ace to an object

    path:  path to the object (i.e. c:\\temp\\file, HKEY_LOCAL_MACHINE\\SOFTWARE\\KEY, etc)
    user: user to add
    permission:  permissions for the user
    acetype:  either allow/deny for each user/permission (ALLOW, DENY)
    propagation: how the ACE applies to children for Registry Keys and Directories(KEY, KEY&SUBKEYS, SUBKEYS)

    CLI Example:

    .. code-block:: bash

        allow domain\fakeuser full control on HKLM\\SOFTWARE\\somekey, propagate to this key and subkeys
            salt 'myminion' win_dacl.add_ace 'HKEY_LOCAL_MACHINE\\SOFTWARE\\somekey' 'Registry' 'domain\fakeuser' 'FULLCONTROL' 'ALLOW' 'KEY&SUBKEYS'
    '''
    ret = {'result': None,
           'changes': {},
           'comment': ''}

    if (path and user and
            permission and acetype
            and propagation):
        if objectType.upper() == "FILE":
            propagation = "FILE"
        dc = daclConstants()
        objectTypeBit = dc.getObjectTypeBit(objectType)
        path = dc.processPath(path, objectTypeBit)
        user = user.strip()
        permission = permission.strip().upper()
        acetype = acetype.strip().upper()
        propagation = propagation.strip().upper()

        sidRet = _getUserSid(user)
        if not sidRet['result']:
            return sidRet
        permissionbit = dc.getPermissionBit(objectTypeBit, permission)
        acetypebit = dc.getAceTypeBit(acetype)
        propagationbit = dc.getPropagationBit(objectTypeBit, propagation)
        dacl = _get_dacl(path, objectTypeBit)

        if dacl:
            acesAdded = []
            try:
                if acetypebit == 0:
                    dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, sidRet['sid'])
                elif acetypebit == 1:
                    dacl.AddAccessDeniedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, sidRet['sid'])
                win32security.SetNamedSecurityInfo(
                    path, objectTypeBit, win32security.DACL_SECURITY_INFORMATION,
                    None, None, dacl, None)
                acesAdded.append((
                    '{0} {1} {2} on {3}'
                    ).format(
                    user, dc.getAceTypeText(acetype), dc.getPermissionText(objectTypeBit, permission),
                    dc.getPropagationText(objectTypeBit, propagation)))
                ret['result'] = True
            except Exception as e:
                ret['comment'] = 'An error occurred attempting to add the ace.  The error was {0}'.format(e)
                ret['result'] = False
                return ret
            if acesAdded:
                ret['changes']['Added ACEs'] = acesAdded
        else:
            ret['comment'] = 'Unable to obtain the DACL of {0}'.format(path)
    else:
        ret['comment'] = 'An empty value was specified for a required item.'
        ret['result'] = False
    return ret


def _ace_to_text(ace, objectType):
    '''
    helper function to convert an ace to a textual representation
    '''
    dc = daclConstants()
    objectType = dc.getObjectTypeBit(objectType)
    try:
        userSid = win32security.LookupAccountSid('', ace[2])
        if userSid[1]:
            userSid = '{1}\\{0}'.format(userSid[0], userSid[1])
        else:
            userSid = '{0}'.format(userSid[0])
    except Exception:
        userSid = win32security.ConvertSidToStringSid(ace[2])
    tPerm = ace[1]
    tAceType = ace[0][0]
    tProps = ace[0][1]
    tInherited = ''
    for x in dc.validAceTypes:
        if dc.validAceTypes[x]['BITS'] == tAceType:
            tAceType = dc.validAceTypes[x]['TEXT']
            break
    for x in dc.rights[objectType]:
        if dc.rights[objectType][x]['BITS'] == tPerm:
            tPerm = dc.rights[objectType][x]['TEXT']
            break
    if (tProps & win32security.INHERITED_ACE) == win32security.INHERITED_ACE:
        tInherited = '[Inherited]'
        tProps = (tProps ^ win32security.INHERITED_ACE)
    for x in dc.validPropagations[objectType]:
        if dc.validPropagations[objectType][x]['BITS'] == tProps:
            tProps = dc.validPropagations[objectType][x]['TEXT']
            break
    return ((
        '{0} {1} {2} on {3} {4}'
        ).format(userSid, tAceType, tPerm, tProps, tInherited))

当你需要的功能,在源码里面没有的时候

  • 例 (更改文件夹所有者 右键文件夹-属性-安全-高级-所有者)
  • 你就需要详细解读下这个源码,顺便看看其他文档
  • 我们可以看到核心模块
  • win32security 对权限的操作
  • win32api 获取一些权限
  • 抓住关键的核心代码

  • win32security.SetNamedSecurityInfo( path, objectTypeBit, win32security.DACL_SECURITY_INFORMATION, None, None, dacl, None)
  • win32security.DACL_SECURITY_INFORMATION #dacl 是权限类表 所有者是 OWNER
  • 官方相关网址:Python for Win32 Extensions Help
  • http://timgolden.me.uk/pywin32-docs/PyWin32.html
  • 对象安全描述符
  • https://blog.csdn.net/shineorrain/article/details/18141759

修改文件夹所有者

def set_file_owner(path, sid)
    try:
        sd = win32security.SECURITY_DESCRIPTOR()
        sd.SetSecurityDescriptorOwner(sid, False)
        win32security.SetFileSecurity(path,
            win32security.OWNER_SECURITY_INFORMATION, sd) #设置文件夹所有者
        return True
    except win32security.error as e:
        print(e)
        return False