rdiff-backup-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[rdiff-backup-users] [PATCH] Backing up Windows ACLs


From: Josh Nisly
Subject: [rdiff-backup-users] [PATCH] Backing up Windows ACLs
Date: Thu, 26 Jun 2008 17:01:41 +0600
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

Attached is a patch that fixes any problems I know about with the previous one, and includes several fixes by Fred Gansevles. It serializes the ACL record to string in the RPath member, which allows new versions to work with existing servers. I've also implemented the correct checks for whether the remote connection supports ACLs, so backing up a Windows client to a linux server should work fine.

Comments are welcome.

Thanks,
JoshN
Index: dist/makedist
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/dist/makedist,v
retrieving revision 1.29
diff -u -r1.29 makedist
--- dist/makedist       23 Jun 2008 02:30:21 -0000      1.29
+++ dist/makedist       23 Jun 2008 06:35:53 -0000
@@ -118,7 +118,7 @@
                                         "Security.py", "selection.py",
                                         "SetConnections.py", "static.py",
                                         "statistics.py", "TempFile.py", 
"Time.py",
-                                        "user_group.py"]:
+                                        "user_group.py", "win_acls.py"]:
                shutil.copyfile(os.path.join(SourceDir, filename),
                                                os.path.join(tardir, 
"rdiff_backup", filename))
 
Index: rdiff_backup/Globals.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/Globals.py,v
retrieving revision 1.45
diff -u -r1.45 Globals.py
--- rdiff_backup/Globals.py     13 Apr 2008 11:25:21 -0000      1.45
+++ rdiff_backup/Globals.py     26 Jun 2008 06:44:09 -0000
@@ -85,6 +85,12 @@
 acls_write = None
 acls_conn = None
 
+# Like the above, but applies to support of Windows
+# access control lists.
+win_acls_active = None
+win_acls_write = None
+win_acls_conn = None
+
 # Like above two setting groups, but applies to support of Mac OS X
 # style resource forks.
 resource_forks_active = None
Index: rdiff_backup/connection.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/connection.py,v
retrieving revision 1.29
diff -u -r1.29 connection.py
--- rdiff_backup/connection.py  9 Jul 2007 03:53:40 -0000       1.29
+++ rdiff_backup/connection.py  23 Jun 2008 06:35:52 -0000
@@ -27,7 +27,8 @@
 except ImportError: pass
 try: import posix1e
 except ImportError: pass
-
+try: import win32security
+except ImportError: pass
 
 class ConnectionError(Exception): pass
 class ConnectionReadError(ConnectionError): pass
@@ -539,6 +540,9 @@
           TempFile, SetConnections, librsync, log, regress, fs_abilities, \
           eas_acls, user_group, compare
 
+try: import win_acls
+except: pass
+
 Globals.local_connection = LocalConnection()
 Globals.connections.append(Globals.local_connection)
 # Following changed by server in SetConnections
Index: rdiff_backup/fs_abilities.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/fs_abilities.py,v
retrieving revision 1.46
diff -u -r1.46 fs_abilities.py
--- rdiff_backup/fs_abilities.py        14 Jun 2008 18:17:57 -0000      1.46
+++ rdiff_backup/fs_abilities.py        25 Jun 2008 05:59:05 -0000
@@ -29,7 +29,7 @@
 
 import errno, os
 import Globals, log, TempFile, selection, robust, SetConnections, \
-          static, FilenameMapping
+          static, FilenameMapping, win_acls
 
 class FSAbilities:
        """Store capabilities of given file system"""
@@ -39,6 +39,7 @@
        ownership = None # True if chown works on this filesystem
        acls = None # True if access control lists supported
        eas = None # True if extended attributes supported
+       win_acls = None # True if windows access control lists supported
        hardlinks = None # True if hard linking supported
        fsync_dirs = None # True if directories can be fsync'd
        dir_inc_perms = None # True if regular files can have full permissions
@@ -97,6 +98,7 @@
                                                           
self.win_reserved_filenames)])
                add_boolean_list([('Access control lists', self.acls),
                                                  ('Extended attributes', 
self.eas),
+                                                 ('Windows access control 
lists', self.win_acls),
                                                  ('Case sensitivity', 
self.case_sensitive),
                                                  ('Escape DOS devices', 
self.escape_dos_devices),
                                                  ('Mac OS X style resource 
forks',
@@ -120,6 +122,7 @@
                self.read_only = 1
                self.set_eas(rp, 0)
                self.set_acls(rp)
+               self.set_win_acls(rp)
                self.set_resource_fork_readonly(rp)
                self.set_carbonfile()
                self.set_case_sensitive_readonly(rp)
@@ -151,6 +154,7 @@
                self.set_fsync_dirs(subdir)
                self.set_eas(subdir, 1)
                self.set_acls(subdir)
+               self.set_win_acls(subdir)
                self.set_dir_inc_perms(subdir)
                self.set_resource_fork_readwrite(subdir)
                self.set_carbonfile()
@@ -364,6 +368,24 @@
                        self.eas = 0
                else: self.eas = 1
 
+       def set_win_acls(self, dir_rp):
+               """Test if windows access control lists are supported"""
+               try:
+                       import win32security
+               except ImportError:
+                       log.Log("Unable to import win32security module. Windows 
ACLs\n"
+                                       "not supported by filesystem at %s" % 
dir_rp.path, 4)
+                       self.win_acls = 0
+                       return
+               try:
+                       win_acls.init_acls()
+               except OSError:
+                       log.Log("Windows ACLs not supported by filesystem\n"
+                                       "at %s" % dir_rp.path, 4)
+                       self.win_acls = 0
+                       return
+               self.win_acls = 1
+
        def set_dir_inc_perms(self, rp):
                """See if increments can have full permissions like a 
directory"""
                test_rp = rp.append('dir_inc_check')
@@ -489,6 +511,7 @@
                                        % (subdir.path), 4)
                        self.escape_dos_devices = 1
 
+
 def get_readonly_fsa(desc_string, rp):
        """Return an fsa with given description_string
 
@@ -521,6 +544,10 @@
                        log.Log.FatalError("--never-drop-acls specified, but 
ACL support\n"
                                                           "missing from 
destination filesystem")
 
+       def set_win_acls(self):
+               self.update_triple(self.src_fsa.win_acls, 
self.dest_fsa.win_acls,
+                         ('win_acls_active', 'win_acls_write', 
'win_acls_conn'))
+
        def set_resource_forks(self):
                self.update_triple(self.src_fsa.resource_forks,
                                                   self.dest_fsa.resource_forks,
@@ -729,6 +756,10 @@
        def set_acls(self):
                self.update_triple(self.dest_fsa.acls,
                                                  ('acls_active', 'acls_write', 
'acls_conn'))
+       def set_win_acls(self):
+               self.update_triple(self.src_fsa.win_acls, 
self.dest_fsa.win_acls,
+                         ('win_acls_active', 'win_acls_write', 
'win_acls_conn'))
+
        def set_resource_forks(self):
                self.update_triple(self.dest_fsa.resource_forks,
                                                   ('resource_forks_active',
@@ -754,6 +785,7 @@
        bsg = BackupSetGlobals(rpin.conn, Globals.rbdir.conn, src_fsa, dest_fsa)
        bsg.set_eas()
        bsg.set_acls()
+       bsg.set_win_acls()
        bsg.set_resource_forks()
        bsg.set_carbonfile()
        bsg.set_hardlinks()
@@ -781,6 +813,7 @@
        rsg = RestoreSetGlobals(Globals.rbdir.conn, rpout.conn, src_fsa, 
dest_fsa)
        rsg.set_eas()
        rsg.set_acls()
+       rsg.set_win_acls()
        rsg.set_resource_forks()
        rsg.set_carbonfile()
        rsg.set_hardlinks()
Index: rdiff_backup/metadata.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/metadata.py,v
retrieving revision 1.29
diff -u -r1.29 metadata.py
--- rdiff_backup/metadata.py    14 Jun 2008 18:17:57 -0000      1.29
+++ rdiff_backup/metadata.py    23 Jun 2008 06:35:52 -0000
@@ -433,9 +433,10 @@
 
 class CombinedWriter:
        """Used for simultaneously writting metadata, eas, and acls"""
-       def __init__(self, metawriter, eawriter, aclwriter):
+       def __init__(self, metawriter, eawriter, aclwriter, winaclwriter):
                self.metawriter = metawriter
-               self.eawriter, self.aclwriter = eawriter, aclwriter # these can 
be None
+               self.eawriter, self.aclwriter, self.winaclwriter = \
+                               eawriter, aclwriter, winaclwriter # these can 
be None
 
        def write_object(self, rorp):
                """Write information in rorp to all the writers"""
@@ -444,11 +445,14 @@
                        self.eawriter.write_object(rorp.get_ea())
                if self.aclwriter and not rorp.get_acl().is_basic():
                        self.aclwriter.write_object(rorp.get_acl())
+               if self.winaclwriter:
+                       self.winaclwriter.write_object(rorp.get_win_acl())
 
        def close(self):
                self.metawriter.close()
                if self.eawriter: self.eawriter.close()
                if self.aclwriter: self.aclwriter.close()
+               if self.winaclwriter: self.winaclwriter.close()
 
 
 class Manager:
@@ -456,6 +460,7 @@
        meta_prefix = 'mirror_metadata'
        acl_prefix = 'access_control_lists'
        ea_prefix = 'extended_attributes'
+       wacl_prefix = 'win_access_control_lists'
 
        def __init__(self):
                """Set listing of rdiff-backup-data dir"""
@@ -501,6 +506,11 @@
                return self._iter_helper(self.acl_prefix,
                                          eas_acls.AccessControlListFile, time, 
restrict_index)
 
+       def get_win_acls_at_time(self, time, restrict_index):
+               """Return WACLs iter at given time from recordfile (or None)"""
+               return self._iter_helper(self.wacl_prefix,
+                                         win_acls.WinAccessControlListFile, 
time, restrict_index)
+
        def GetAtTime(self, time, restrict_index = None):
                """Return combined metadata iter with ea/acl info if 
necessary"""
                cur_iter = self.get_meta_at_time(time, restrict_index)
@@ -521,6 +531,14 @@
                                log.Log("Warning: Extended Attributes file not 
found", 2)
                                ea_iter = iter([])
                        cur_iter = eas_acls.join_ea_iter(cur_iter, ea_iter)
+               if Globals.win_acls_active:
+                       wacl_iter = self.get_win_acls_at_time(time, 
restrict_index)
+                       if not wacl_iter:
+                               log.Log("Warning: Windows Access Control List 
file not"
+                                               " found.", 2)
+                               wacl_iter = iter([])
+                       cur_iter = win_acls.join_wacl_iter(cur_iter, wacl_iter)
+
                return cur_iter
 
        def _writer_helper(self, prefix, flatfileclass, typestr, time):
@@ -548,17 +566,26 @@
                return self._writer_helper(self.acl_prefix,
                                                 
eas_acls.AccessControlListFile, typestr, time)
 
+       def get_win_acl_writer(self, typestr, time):
+               """Return WinAccessControlListFile opened for writing"""
+               return self._writer_helper(self.wacl_prefix,
+                                                
win_acls.WinAccessControlListFile, typestr, time)
+
        def GetWriter(self, typestr = 'snapshot', time = None):
                """Get a writer object that can write meta and possibly 
acls/eas"""
                metawriter = self.get_meta_writer(typestr, time)
-               if not Globals.eas_active and not Globals.acls_active:
+               if not Globals.eas_active and not Globals.acls_active and \
+                               not Globals.win_acls_active:
                        return metawriter # no need for a CombinedWriter
 
                if Globals.eas_active: ea_writer = self.get_ea_writer(typestr, 
time)
                else: ea_writer = None
                if Globals.acls_active: acl_writer = 
self.get_acl_writer(typestr, time)
                else: acl_writer = None
-               return CombinedWriter(metawriter, ea_writer, acl_writer)
+               if Globals.win_acls_active: win_acl_writer = \
+                               self.get_win_acl_writer(typestr, time)
+               else: win_acl_writer = None
+               return CombinedWriter(metawriter, ea_writer, acl_writer, 
win_acl_writer)
 
 class PatchDiffMan(Manager):
        """Contains functions for patching and diffing metadata
@@ -664,3 +691,4 @@
 
 
 import eas_acls # put at bottom to avoid python circularity bug
+import win_acls
Index: rdiff_backup/rpath.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/rpath.py,v
retrieving revision 1.120
diff -u -r1.120 rpath.py
--- rdiff_backup/rpath.py       10 Jun 2008 13:14:52 -0000      1.120
+++ rdiff_backup/rpath.py       26 Jun 2008 06:44:09 -0000
@@ -185,6 +185,7 @@
        rpout.chmod(rpin.getperms())
        if Globals.acls_write: rpout.write_acl(rpin.get_acl())
        if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
+       if Globals.win_acls_write: rpout.write_win_acl(rpin.get_win_acl())
 
 def copy_attribs_inc(rpin, rpout):
        """Change file attributes of rpout to match rpin
@@ -257,6 +258,8 @@
                                if error.errno != errno.EEXIST: raise
 
                                # On Windows, files can't be renamed on top of 
an existing file
+                               try: rp_source.conn.os.chmod(rp_dest.path, 
stat.S_IWRITE)
+                               except: pass
                                rp_source.conn.os.unlink(rp_dest.path)
                                rp_source.conn.os.rename(rp_source.path, 
rp_dest.path)
                            
@@ -338,6 +361,7 @@
                        elif key == 'size' and not self.isreg(): pass
                        elif key == 'ea' and not Globals.eas_active: pass
                        elif key == 'acl' and not Globals.acls_active: pass
+                       elif key == 'win_acl' and not Globals.win_acls_active: 
pass
                        elif key == 'carbonfile' and not 
Globals.carbonfile_active: pass
                        elif key == 'resourcefork' and not 
Globals.resource_forks_active:
                                pass
@@ -378,6 +402,7 @@
                        elif key == 'inode': pass
                        elif key == 'ea' and not Globals.eas_write: pass
                        elif key == 'acl' and not Globals.acls_write: pass
+                       elif key == 'win_acl' and not Globals.win_acls_write: 
pass
                        elif key == 'carbonfile' and not 
Globals.carbonfile_write: pass
                        elif key == 'resourcefork' and not 
Globals.resource_forks_write:
                                pass
@@ -395,8 +420,8 @@
 
        def equal_verbose(self, other, check_index = 1,
                                          compare_inodes = 0, compare_ownership 
= 0,
-                                         compare_acls = 0, compare_eas = 0, 
compare_size = 1,
-                                         compare_type = 1, verbosity = 2):
+                                         compare_acls = 0, compare_eas = 0, 
compare_win_acls = 0,
+                                         compare_size = 1, compare_type = 1, 
verbosity = 2):
                """Like __eq__, but log more information.  Useful when 
testing"""
                if check_index and self.index != other.index:
                        log.Log("Index %s != index %s" % (self.index, 
other.index),
@@ -417,6 +442,7 @@
                                pass
                        elif key == 'ea' and not compare_eas: pass
                        elif key == 'acl' and not compare_acls: pass
+                       elif key == 'win_acl' and not compare_win_acls: pass
                        elif (not other.data.has_key(key) or
                                  self.data[key] != other.data[key]):
                                if not other.data.has_key(key):
@@ -434,7 +460,8 @@
                return self.equal_verbose(other,
                                                                  
compare_inodes = compare_inodes,
                                                                  compare_eas = 
Globals.eas_active,
-                                                                 compare_acls 
= Globals.acls_active)
+                                                                 compare_acls 
= Globals.acls_active,
+                                                                 
compare_win_acls = Globals.win_acls_active)
                                                         
        def __ne__(self, other): return not self.__eq__(other)
 
@@ -682,6 +709,17 @@
                """Record resource fork in dictionary.  Does not write"""
                self.data['resourcefork'] = rfork
 
+       def set_win_acl(self, acl):
+               """Record Windows access control list in dictionary. Does not 
write"""
+               self.data['win_acl'] = acl
+
+       def get_win_acl(self):
+               """Return access control list object from dictionary"""
+               try: return self.data['win_acl']
+               except KeyError:
+                       acl = self.data['win_acl'] = 
get_blank_win_acl(self.index)
+                       return acl
+
        def has_alt_mirror_name(self):
                """True if rorp has an alternate mirror name specified"""
                return self.data.has_key('mirrorname')
@@ -1304,6 +1342,16 @@
                assert not fp.close()
                self.set_resource_fork(rfork_data)
 
+       def get_win_acl(self):
+               """Return Windows access control list, setting if necessary"""
+               try: acl = self.data['win_acl']
+               except KeyError: acl = self.data['win_acl'] = win_acl_get(self)
+               return acl
+
+       def write_win_acl(self, acl):
+               """Change access control list of rp"""
+               write_win_acl(self, acl)
+               self.data['win_acl'] = acl
 
 class RPathFileHook:
        """Look like a file, but add closing hook"""
@@ -1394,6 +1442,8 @@
        rpath.data['gname'] = user_group.gid2gname(rpath.data['gid'])
        if Globals.eas_conn: rpath.data['ea'] = ea_get(rpath)
        if Globals.acls_conn: rpath.data['acl'] = acl_get(rpath)
+       if Globals.win_acls_conn:
+               rpath.data['win_acl'] = win_acl_get(rpath)
        if Globals.resource_forks_conn and rpath.isreg():
                rpath.get_resource_fork()
        if Globals.carbonfile_conn and rpath.isreg():
@@ -1427,3 +1477,7 @@
 def get_blank_acl(index): assert 0
 def ea_get(rp): assert 0
 def get_blank_ea(index): assert 0
+
+def win_acl_get(rp): assert 0
+def write_win_acl(rp): assert 0
+def get_blank_win_acl(): assert 0
--- rdiff_backup/win_acls.py.orig       Thu Jun 26 01:48:09 2008
+++ rdiff_backup/win_acls.py    Thu Jun 26 01:44:09 2008
@@ -0,0 +1,196 @@
+# Copyright 2008 Fred Gansevles <address@hidden>
+#
+# This file is part of rdiff-backup.
+#
+# rdiff-backup is free software; you can redistribute it and/or modify
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# rdiff-backup is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rdiff-backup; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+__version__ = (0, 1, 0)
+
+import C, metadata, re, rorpiter, rpath
+
+from win32security import *
+
+class ACL:
+       flags = (GROUP_SECURITY_INFORMATION|
+                OWNER_SECURITY_INFORMATION|
+                DACL_SECURITY_INFORMATION)
+
+       def __init__(self, index=()):
+               self.__acl = ""
+               self.index = index
+
+       def get_indexpath(self): return self.index and '/'.join(self.index) or 
'.'
+
+       def load_from_rp(self, rp, skip_inherit_only = True):
+               self.index = rp.index
+               try:
+                       sd = rp.conn.win32security.GetFileSecurity(rp.path, 
ACL.flags)
+               except:
+                       return
+
+               if skip_inherit_only:
+                       # skip the inherit_only aces
+                       acl = sd.GetSecurityDescriptorDacl()
+                       if acl:
+                               n = acl.GetAceCount()
+                               # traverse the ACL in reverse, so the indices 
stay correct
+                               while n:
+                                       n -= 1
+                                       ace_flags = acl.GetAce(n)[0][1]
+                                       if ace_flags & INHERIT_ONLY_ACE:
+                                               acl.DeleteAce(n)
+                       sd.SetSecurityDescriptorDacl(1, acl, 0)
+
+                       if ACL.flags & SACL_SECURITY_INFORMATION:
+                               acl = sd.GetSecurityDescriptorSacl()
+                               if acl:
+                                       n = acl.GetAceCount()
+                                       # traverse the ACL in reverse, so the 
indices stay correct
+                                       while n:
+                                               n -= 1
+                                               ace_flags = acl.GetAce(n)[0][1]
+                                               if ace_flags & INHERIT_ONLY_ACE:
+                                                       acl.DeleteAce(n)
+                                       sd.SetSecurityDescriptorSacl(1, acl, 0)
+
+               self.__acl = \
+                       
rp.conn.win32security.ConvertSecurityDescriptorToStringSecurityDescriptor(sd,
+                                       SDDL_REVISION_1, ACL.flags)
+
+       def clear_rp(self, rp):
+               # not sure how to interpret this
+               # I'll jus clear all acl-s from rp.path
+               sd = rp.conn.win32security.GetFileSecurity(rp.path, ACL.flags)
+
+               acl = sd.GetSecurityDescriptorDacl()
+               if acl:
+                       n = acl.GetAceCount()
+                       # traverse the ACL in reverse, so the indices stay 
correct
+                       while n:
+                               n -= 1
+                               acl.DeleteAce(n)
+                       sd.SetSecurityDescriptorDacl(1, acl, 0)
+
+               if ACL.flags & SACL_SECURITY_INFORMATION:
+                       acl = sd.GetSecurityDescriptorSacl()
+                       if acl:
+                               n = acl.GetAceCount()
+                               # traverse the ACL in reverse, so the indices 
stay correct
+                               while n:
+                                       n -= 1
+                                       acl.DeleteAce(n)
+                               sd.SetSecurityDescriptorSacl(1, acl, 0)
+
+               SetFileSecurity(rp.path, ACL.flags, sd)
+
+       def write_to_rp(self, rp):
+               if self.__acl:
+                       sd = 
rp.conn.win32security.ConvertStringSecurityDescriptorToSecurityDescriptor(self.__acl,
+                                               SDDL_REVISION_1)
+                       rp.conn.win32security.SetFileSecurity(rp.path, 
ACL.flags, sd)
+
+       def __str__(self):
+               return '# file: %s\n%s\n' % \
+                               (C.acl_quote(self.get_indexpath()), 
unicode(self.__acl))
+
+       def from_string(self, acl_str):
+               lines = acl_str.splitlines()
+               if len(lines) != 2 or not lines[0][:8] == "# file: ":
+                       raise metadata.ParsingError("Bad record beginning: " + 
lines[0][:8])
+               filename = lines[0][8:]
+               if filename == '.': self.index = ()
+               else: self.index = tuple(C.acl_unquote(filename).split('/'))
+               self.__acl = lines[1]
+
+def Record2WACL(record):
+       acl = ACL()
+       acl.from_string(record)
+       return acl
+
+def WACL2Record(wacl):
+       return unicode(wacl)
+
+class WACLExtractor(metadata.FlatExtractor):
+       """Iterate ExtendedAttributes objects from the WACL information file"""
+       record_boundary_regexp = re.compile('(?:\\n|^)(# file: (.*?))\\n')
+       record_to_object = staticmethod(Record2WACL)
+       def filename_to_index(self, filename):
+               """Convert possibly quoted filename to index tuple"""
+               if filename == '.': return ()
+               else: return tuple(C.acl_unquote(filename).split('/'))
+
+class WinAccessControlListFile(metadata.FlatFile):
+       """Store/retrieve ACLs from extended_attributes file"""
+       _prefix = "win_access_control_lists"
+       _extractor = WACLExtractor
+       _object_to_record = staticmethod(WACL2Record)
+
+def join_wacl_iter(rorp_iter, wacl_iter):
+       """Update a rorp iter by adding the information from acl_iter"""
+       for rorp, wacl in rorpiter.CollateIterators(rorp_iter, wacl_iter):
+               assert rorp, "Missing rorp for index %s" % (wacl.index,)
+               if not wacl: wacl = ACL(rorp.index)
+               rorp.set_win_acl(wacl)
+               yield rorp
+       
+def rpath_acl_win_get(rpath):
+       acl = ACL()
+       acl.load_from_rp(rpath)
+       return unicode(acl)
+rpath.win_acl_get = rpath_acl_win_get
+
+def rpath_get_blank_win_acl(index):
+       acl = ACL(index)
+       return unicode(acl)
+rpath.get_blank_win_acl = rpath_get_blank_win_acl
+
+def rpath_set_win_acl(rp, acl_str):
+       acl = ACL()
+       acl.from_string(acl_str)
+       acl.write_to_rp(rp)
+rpath.write_win_acl = rpath_set_win_acl
+
+def init_acls():
+       # A process that tries to read or write a SACL needs
+       # to have and enable the SE_SECURITY_NAME privilege.
+       # And inorder to backup/restore, the SE_BACKUP_NAME and
+       # SE_RESTORE_NAME privileges are needed.
+       import win32api
+       try:
+               hnd = OpenProcessToken(win32api.GetCurrentProcess(),
+                       TOKEN_ADJUST_PRIVILEGES| TOKEN_QUERY)
+       except win32api.error:
+               return
+       try:
+               try:
+                       lpv = lambda priv: LookupPrivilegeValue(None, priv)
+                       # enable the SE_*_NAME priveleges
+                       SecurityName = lpv(SE_SECURITY_NAME)
+                       AdjustTokenPrivileges(hnd, False, [
+                               (SecurityName, SE_PRIVILEGE_ENABLED),
+                               (lpv(SE_BACKUP_NAME), SE_PRIVILEGE_ENABLED),
+                               (lpv(SE_RESTORE_NAME), SE_PRIVILEGE_ENABLED)
+                               ])
+               except win32api.error:
+                       return
+               for name, enabled in GetTokenInformation(hnd, TokenPrivileges):
+                       if name == SecurityName and enabled:
+                               # now we *may* access the SACL (sigh)
+                               ACL.flags |= SACL_SECURITY_INFORMATION
+                               break
+       finally:
+               win32api.CloseHandle(hnd)
+

reply via email to

[Prev in Thread] Current Thread [Next in Thread]