1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00
samba-mirror/python/samba/gp_parse/gp_inf.py
Douglas Bagnall 07fa6678e4 python: use raw string for regex with escape
Python regards 'GPT\.INI$' as a string containing an invalid escape
sequence '\.', which is ignored (i.e. treated as the literal sequence
of those 2 characters), but only after Python has grumbled to itself,
and to you if you enabled DeprecationWarnings.

The proper thing to do here is use r-strings, like r'GPT\.INI$', which
tell Python that all backslashes are literal. Alternatively (as we do
once in this patch), the backslash can itself be escaped ('\\').

There are more problems of this nature in the build scripts.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Noel Power <npower@samba.org>
2020-02-07 10:37:37 +00:00

379 lines
13 KiB
Python

# GPO Parser for security 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/>.
#
import codecs
import collections
import re
from abc import ABCMeta, abstractmethod
from xml.etree.ElementTree import Element, SubElement
from samba.gp_parse import GPParser
# [MS-GPSB] Security Protocol Extension
class GptTmplInfParser(GPParser):
sections = None
encoding = 'utf-16'
output_encoding = 'utf-16le'
class AbstractParam:
__metaclass__ = ABCMeta
def __init__(self):
self.param_list = []
@abstractmethod
def parse(self, line):
pass
@abstractmethod
def write_section(self, header, fp):
pass
@abstractmethod
def build_xml(self, xml_parent):
pass
@abstractmethod
def from_xml(self, section):
pass
class IniParam(AbstractParam):
# param_list = [(Key, Value),]
def parse(self, line):
key, val = line.split('=')
self.param_list.append((key.strip(),
val.strip()))
# print key.strip(), val.strip()
def write_section(self, header, fp):
if len(self.param_list) == 0:
return
fp.write(u'[%s]\r\n' % header)
for key_out, val_out in self.param_list:
fp.write(u'%s = %s\r\n' % (key_out,
val_out))
def build_xml(self, xml_parent):
for key_ini, val_ini in self.param_list:
child = SubElement(xml_parent, 'Parameter')
key = SubElement(child, 'Key')
value = SubElement(child, 'Value')
key.text = key_ini
value.text = val_ini
def from_xml(self, section):
for param in section.findall('Parameter'):
key = param.find('Key').text
value = param.find('Value').text
if value is None:
value = ''
self.param_list.append((key, value))
class RegParam(AbstractParam):
# param_list = [Value, Value, ...]
def parse(self, line):
# = can occur in a registry key, so don't parse these
self.param_list.append(line)
# print line
def write_section(self, header, fp):
if len(self.param_list) == 0:
return
fp.write(u'[%s]\r\n' % header)
for param in self.param_list:
fp.write(u'%s\r\n' % param)
def build_xml(self, xml_parent):
for val_ini in self.param_list:
child = SubElement(xml_parent, 'Parameter')
value = SubElement(child, 'Value')
value.text = val_ini
def from_xml(self, section):
for param in section.findall('Parameter'):
value = param.find('Value').text
if value is None:
value = ''
self.param_list.append(value)
class PrivSIDListParam(AbstractParam):
# param_list = [(Key, [SID, SID,..]),
def parse(self, line):
key, val = line.split('=')
self.param_list.append((key.strip(),
[x.strip() for x in val.split(',')]))
# print line
def write_section(self, header, fp):
if len(self.param_list) == 0:
return
fp.write(u'[%s]\r\n' % header)
for key_out, val in self.param_list:
val_out = u','.join(val)
fp.write(u'%s = %s\r\n' % (key_out, val_out))
def build_xml(self, xml_parent):
for key_ini, sid_list in self.param_list:
child = SubElement(xml_parent, 'Parameter')
key = SubElement(child, 'Key')
key.text = key_ini
for val_ini in sid_list:
value = SubElement(child, 'Value')
value.attrib['user_id'] = 'TRUE'
value.text = val_ini
def from_xml(self, section):
for param in section.findall('Parameter'):
key = param.find('Key').text
sid_list = []
for val in param.findall('Value'):
value = val.text
if value is None:
value = ''
sid_list.append(value)
self.param_list.append((key, sid_list))
class NameModeACLParam(AbstractParam):
# param_list = [[Name, Mode, ACL],]
def parse(self, line):
parameters = [None, None, None]
current_arg = 0
while line != '':
# Read quoted string
if line[:1] == '"':
line = line[1:]
findex = line.find('"')
parameters[current_arg] = line[:findex]
line = line[findex + 1:]
# Skip past delimeter
elif line[:1] == ',':
line = line[1:]
current_arg += 1
# Read unquoted string
else:
findex = line.find(',')
parameters[current_arg] = line[:findex]
line = line[findex:]
# print parameters
# print line
self.param_list.append(parameters)
def write_section(self, header, fp):
if len(self.param_list) == 0:
return
fp.write(u'[%s]\r\n' % header)
for param in self.param_list:
fp.write(u'"%s",%s,"%s"\r\n' % tuple(param))
def build_xml(self, xml_parent):
for name_mode_acl in self.param_list:
child = SubElement(xml_parent, 'Parameter')
value = SubElement(child, 'Value')
value.text = name_mode_acl[0]
value = SubElement(child, 'Value')
value.text = name_mode_acl[1]
value = SubElement(child, 'Value')
value.attrib['acl'] = 'TRUE'
value.text = name_mode_acl[2]
def from_xml(self, section):
for param in section.findall('Parameter'):
name_mode_acl = [x.text if x.text else '' for x in param.findall('Value')]
self.param_list.append(name_mode_acl)
class MemberSIDListParam(AbstractParam):
# param_list = [([XXXX, Memberof|Members], [SID, SID...]),...]
def parse(self, line):
key, val = line.split('=')
key = key.strip()
self.param_list.append((key.split('__'),
[x.strip() for x in val.split(',')]))
# print line
def write_section(self, header, fp):
if len(self.param_list) == 0:
return
fp.write(u'[%s]\r\n' % header)
for key, val in self.param_list:
key_out = u'__'.join(key)
val_out = u','.join(val)
fp.write(u'%s = %s\r\n' % (key_out, val_out))
def build_xml(self, xml_parent):
for key_ini, sid_list in self.param_list:
child = SubElement(xml_parent, 'Parameter')
key = SubElement(child, 'Key')
key.text = key_ini[0]
key.attrib['member_type'] = key_ini[1]
key.attrib['user_id'] = 'TRUE'
for val_ini in sid_list:
value = SubElement(child, 'Value')
value.attrib['user_id'] = 'TRUE'
value.text = val_ini
def from_xml(self, section):
for param in section.findall('Parameter'):
key = param.find('Key')
member_type = key.attrib['member_type']
sid_list = []
for val in param.findall('Value'):
value = val.text
if value is None:
value = ''
sid_list.append(value)
self.param_list.append(([key.text, member_type], sid_list))
class UnicodeParam(AbstractParam):
def parse(self, line):
# print line
pass
def write_section(self, header, fp):
fp.write(u'[Unicode]\r\nUnicode=yes\r\n')
def build_xml(self, xml_parent):
# We do not bother storing this field
pass
def from_xml(self, section):
# We do not bother storing this field
pass
class VersionParam(AbstractParam):
def parse(self, line):
# print line
pass
def write_section(self, header, fp):
out = u'[Version]\r\nsignature="$CHICAGO$"\r\nRevision=1\r\n'
fp.write(out)
def build_xml(self, xml_parent):
# We do not bother storing this field
pass
def from_xml(self, section):
# We do not bother storing this field
pass
def parse(self, contents):
inf_file = contents.decode(self.encoding)
self.sections = collections.OrderedDict([
(u'Unicode', self.UnicodeParam()),
(u'Version', self.VersionParam()),
(u'System Access', self.IniParam()),
(u'Kerberos Policy', self.IniParam()),
(u'System Log', self.IniParam()),
(u'Security Log', self.IniParam()),
(u'Application Log', self.IniParam()),
(u'Event Audit', self.IniParam()),
(u'Registry Values', self.RegParam()),
(u'Privilege Rights', self.PrivSIDListParam()),
(u'Service General Setting', self.NameModeACLParam()),
(u'Registry Keys', self.NameModeACLParam()),
(u'File Security', self.NameModeACLParam()),
(u'Group Membership', self.MemberSIDListParam()),
])
current_param_parser = None
current_header_name = None
for line in inf_file.splitlines():
match = re.match(r'\[(.*)\]', line)
if match:
header_name = match.group(1)
if header_name in self.sections:
current_param_parser = self.sections[header_name]
# print current_param_parser
continue
# print 'using', current_param_parser
current_param_parser.parse(line)
def write_binary(self, filename):
with codecs.open(filename, 'wb+',
self.output_encoding) as f:
# Write the byte-order mark
f.write(u'\ufeff')
for s in self.sections:
self.sections[s].write_section(s, f)
def write_xml(self, filename):
with open(filename, 'wb') as f:
root = Element('GptTmplInfFile')
for sec_inf in self.sections:
section = SubElement(root, 'Section')
section.attrib['name'] = sec_inf
self.sections[sec_inf].build_xml(section)
self.write_pretty_xml(root, f)
# contents = codecs.open(filename, encoding='utf-8').read()
# self.load_xml(fromstring(contents))
def load_xml(self, root):
self.sections = collections.OrderedDict([
(u'Unicode', self.UnicodeParam()),
(u'Version', self.VersionParam()),
(u'System Access', self.IniParam()),
(u'Kerberos Policy', self.IniParam()),
(u'System Log', self.IniParam()),
(u'Security Log', self.IniParam()),
(u'Application Log', self.IniParam()),
(u'Event Audit', self.IniParam()),
(u'Registry Values', self.RegParam()),
(u'Privilege Rights', self.PrivSIDListParam()),
(u'Service General Setting', self.NameModeACLParam()),
(u'Registry Keys', self.NameModeACLParam()),
(u'File Security', self.NameModeACLParam()),
(u'Group Membership', self.MemberSIDListParam()),
])
for s in root.findall('Section'):
self.sections[s.attrib['name']].from_xml(s)