1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-03 01:18:10 +03:00

gpo: Add a --generalize to the backup command

This normally prints out the entities in DTD form to be given to the restore
command with --entities. Specifying --entities during the backup conveniently
writes these entities to a file. Generalizing occurs after the standard backup
on the XML files, which will then re-write the XML file.

There are a number of files which can be further handled, including many of the
preferences XML files. This will require more annotation and parsing.

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Garming Sam 2018-05-29 11:57:26 +12:00 committed by Andrew Bartlett
parent 3ff695fd36
commit 07de156598

View File

@ -48,7 +48,7 @@ import uuid
from samba.ntacls import dsacl2fsacl
from samba.dcerpc import nbt
from samba.net import Net
from samba.gp_parse import GPParser, GPNoParserException
from samba.gp_parse import GPParser, GPNoParserException, GPGeneralizeException
from samba.gp_parse.gp_pol import GPPolParser
from samba.gp_parse.gp_ini import (
GPIniParser,
@ -965,10 +965,15 @@ class cmd_backup(Command):
takes_options = [
Option("-H", help="LDB URL for database or target server", type=str),
Option("--tmpdir", help="Temporary directory for copying policy files", type=str)
Option("--tmpdir", help="Temporary directory for copying policy files", type=str),
Option("--generalize", help="Generalize XML entities to restore",
default=False, action='store_true'),
Option("--entities", help="File to export defining XML entities for the restore",
dest='ent_file', type=str)
]
def run(self, gpo, H=None, tmpdir=None, sambaopts=None, credopts=None, versionopts=None):
def run(self, gpo, H=None, tmpdir=None, generalize=False, sambaopts=None,
credopts=None, versionopts=None, ent_file=None):
self.lp = sambaopts.get_loadparm()
self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
@ -1020,8 +1025,79 @@ class cmd_backup(Command):
except Exception as e:
# FIXME: Catch more specific exception
raise CommandError("Error copying GPO from DC", e)
self.outf.write('GPO copied to %s\n' % gpodir)
if generalize:
self.outf.write('\nAttempting to generalize XML entities:\n')
entities = cmd_backup.generalize_xml_entities(self.outf, gpodir,
gpodir)
import operator
ents = ''
for ent in sorted(entities.items(), key=operator.itemgetter(1)):
ents += '<!ENTITY {} "{}">\n'.format(ent[1].strip('&;'), ent[0])
if ent_file:
with open(ent_file, 'w') as f:
f.write(ents)
self.outf.write('Entities successfully written to %s\n' %
ent_file)
else:
self.outf.write('\nEntities:\n')
self.outf.write(ents)
@staticmethod
def generalize_xml_entities(outf, sourcedir, targetdir):
entities = {}
if not os.path.exists(targetdir):
os.mkdir(targetdir)
l_dirs = [ sourcedir ]
r_dirs = [ targetdir ]
while l_dirs:
l_dir = l_dirs.pop()
r_dir = r_dirs.pop()
dirlist = os.listdir(l_dir)
dirlist.sort()
for e in dirlist:
l_name = os.path.join(l_dir, e)
r_name = os.path.join(r_dir, e)
if os.path.isdir(l_name):
l_dirs.append(l_name)
r_dirs.append(r_name)
if not os.path.exists(r_name):
os.mkdir(r_name)
else:
if l_name.endswith('.xml'):
# Restore the xml file if possible
# Get the filename to find the parser
to_parse = os.path.basename(l_name)[:-4]
parser = find_parser(to_parse)
try:
with open(l_name, 'r') as ltemp:
data = ltemp.read()
concrete_xml = ET.fromstring(data)
found_entities = parser.generalize_xml(concrete_xml, r_name, entities)
except GPGeneralizeException:
outf.write('SKIPPING: Generalizing failed for %s\n' % to_parse)
else:
# No need to generalize non-xml files.
#
# TODO This could be improved with xml files stored in
# the renamed backup file (with custom extension) by
# inlining them into the exported backups.
if not os.path.samefile(l_name, r_name):
shutil.copy2(l_name, r_name)
return entities
class cmd_create(Command):
"""Create an empty GPO."""
@ -1213,6 +1289,7 @@ class cmd_restore(cmd_create):
r_dir = r_dirs.pop()
dirlist = os.listdir(l_dir)
dirlist.sort()
for e in dirlist:
l_name = os.path.join(l_dir, e)
r_name = os.path.join(r_dir, e)