mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
0934fc14ef
Fixes. 1) sorting of xml.etree.ElementTree.Element, in PY2 sort seems to sort lists of these. In PY3 this no longer works. Choosing tag as the sort key for py3 so at least in python3 there is a consistent sort (probably won't match how it is sorted in PY2 but nothing seems to depend on that) 2) md5 requires bytes 3) tostring returns bytes in PY3, adjust code for that Signed-off-by: Noel Power <noel.power@suse.com> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
186 lines
6.0 KiB
Python
186 lines
6.0 KiB
Python
# GPO Parser for generic extensions
|
|
#
|
|
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
|
|
# Written by Garming Sam <garming@catalyst.net.nz>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
from xml.dom import minidom
|
|
from io import BytesIO
|
|
from xml.etree.ElementTree import ElementTree, fromstring, tostring
|
|
from hashlib import md5
|
|
from samba.compat import get_bytes
|
|
|
|
|
|
ENTITY_USER_ID = 0
|
|
ENTITY_SDDL_ACL = 1
|
|
ENTITY_NETWORK_PATH = 2
|
|
|
|
|
|
class GPNoParserException(Exception):
|
|
pass
|
|
|
|
class GPGeneralizeException(Exception):
|
|
pass
|
|
|
|
|
|
def entity_type_to_string(ent_type):
|
|
type_str = None
|
|
|
|
if ent_type == ENTITY_USER_ID:
|
|
type_str = "USER_ID"
|
|
elif ent_type == ENTITY_SDDL_ACL:
|
|
type_str = "SDDL_ACL"
|
|
elif ent_type == ENTITY_NETWORK_PATH:
|
|
type_str = "NETWORK_PATH"
|
|
|
|
return type_str
|
|
|
|
|
|
# [MS-GPIPSEC] (LDAP)
|
|
# [MS-GPDPC] Deployed Printer Connections (LDAP)
|
|
# [MS-GPPREF] Preferences Extension (XML)
|
|
# [MS-GPWL] Wireless/Wired Protocol Extension (LDAP)
|
|
class GPParser(object):
|
|
encoding = 'utf-16'
|
|
output_encoding = 'utf-8'
|
|
|
|
def parse(self, contents):
|
|
pass
|
|
|
|
def write_xml(self, filename):
|
|
with file(filename, 'w') as f:
|
|
f.write('<?xml version="1.0" encoding="utf-8"?><UnknownFile/>')
|
|
|
|
def load_xml(self, filename):
|
|
pass
|
|
|
|
def write_binary(self, filename):
|
|
raise GPNoParserException("This file has no parser available.")
|
|
|
|
def write_pretty_xml(self, xml_element, handle):
|
|
# Add the xml header as well as format it nicely.
|
|
# ElementTree doesn't have a pretty-print, so use minidom.
|
|
|
|
et = ElementTree(xml_element)
|
|
temporary_bytes = BytesIO()
|
|
et.write(temporary_bytes, encoding=self.output_encoding,
|
|
xml_declaration=True)
|
|
minidom_parsed = minidom.parseString(temporary_bytes.getvalue())
|
|
handle.write(minidom_parsed.toprettyxml(encoding=self.output_encoding))
|
|
|
|
def new_xml_entity(self, name, ent_type):
|
|
identifier = md5(get_bytes(name)).hexdigest()
|
|
|
|
type_str = entity_type_to_string(ent_type)
|
|
|
|
if type_str is None:
|
|
raise GPGeneralizeException("No such entity type")
|
|
|
|
# For formattting reasons, align the length of the entities
|
|
longest = entity_type_to_string(ENTITY_NETWORK_PATH)
|
|
type_str = type_str.center(len(longest), '_')
|
|
|
|
return "&SAMBA__{}__{}__;".format(type_str, identifier)
|
|
|
|
def generalize_xml(self, root, out_file, global_entities):
|
|
entities = []
|
|
|
|
# Locate all user_id and all ACLs
|
|
user_ids = root.findall('.//*[@user_id="TRUE"]')
|
|
user_ids.sort(key = lambda x: x.tag)
|
|
|
|
for elem in user_ids:
|
|
old_text = elem.text
|
|
if old_text is None or old_text == '':
|
|
continue
|
|
|
|
if old_text in global_entities:
|
|
elem.text = global_entities[old_text]
|
|
entities.append((elem.text, old_text))
|
|
else:
|
|
elem.text = self.new_xml_entity(old_text,
|
|
ENTITY_USER_ID)
|
|
|
|
entities.append((elem.text, old_text))
|
|
global_entities.update([(old_text, elem.text)])
|
|
|
|
acls = root.findall('.//*[@acl="TRUE"]')
|
|
acls.sort(key = lambda x: x.tag)
|
|
|
|
for elem in acls:
|
|
old_text = elem.text
|
|
|
|
if old_text is None or old_text == '':
|
|
continue
|
|
|
|
if old_text in global_entities:
|
|
elem.text = global_entities[old_text]
|
|
entities.append((elem.text, old_text))
|
|
else:
|
|
elem.text = self.new_xml_entity(old_text,
|
|
ENTITY_SDDL_ACL)
|
|
|
|
entities.append((elem.text, old_text))
|
|
global_entities.update([(old_text, elem.text)])
|
|
|
|
share_paths = root.findall('.//*[@network_path="TRUE"]')
|
|
share_paths.sort(key = lambda x: x.tag)
|
|
|
|
for elem in share_paths:
|
|
old_text = elem.text
|
|
|
|
if old_text is None or old_text == '':
|
|
continue
|
|
|
|
stripped = old_text.lstrip('\\')
|
|
file_server = stripped.split('\\')[0]
|
|
|
|
server_index = old_text.find(file_server)
|
|
|
|
remaining = old_text[server_index + len(file_server):]
|
|
old_text = old_text[:server_index] + file_server
|
|
|
|
if old_text in global_entities:
|
|
elem.text = global_entities[old_text] + remaining
|
|
to_put = global_entities[old_text]
|
|
entities.append((to_put, old_text))
|
|
else:
|
|
to_put = self.new_xml_entity(old_text,
|
|
ENTITY_NETWORK_PATH)
|
|
elem.text = to_put + remaining
|
|
|
|
entities.append((to_put, old_text))
|
|
global_entities.update([(old_text, to_put)])
|
|
|
|
# Call any file specific customization of entities
|
|
# (which appear in any subclasses).
|
|
entities.extend(self.custom_entities(root, global_entities))
|
|
|
|
output_xml = tostring(root)
|
|
|
|
for ent in entities:
|
|
entb = get_bytes(ent[0])
|
|
output_xml = output_xml.replace(entb.replace(b'&', b'&'), entb)
|
|
|
|
with open(out_file, 'wb') as f:
|
|
f.write(output_xml)
|
|
|
|
return entities
|
|
|
|
def custom_entities(self, root, global_entities):
|
|
# Override this method to do special entity handling
|
|
return []
|