1 # GPO Parser for security extensions
3 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
4 # Written by Garming Sam <garming@catalyst.net.nz>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 from abc import ABCMeta, abstractmethod
25 from xml.etree.ElementTree import Element, SubElement
27 from samba.gp_parse import GPParser
29 # [MS-GPSB] Security Protocol Extension
30 class GptTmplInfParser(GPParser):
34 __metaclass__ = ABCMeta
41 def parse(self, line):
45 def write_section(self, header, fp):
49 def build_xml(self, xml_parent):
53 def from_xml(self, section):
56 class IniParam(AbstractParam):
57 # param_list = [(Key, Value),]
59 def parse(self, line):
60 key, val = line.split('=')
62 self.param_list.append((key.strip(),
65 # print key.strip(), val.strip()
67 def write_section(self, header, fp):
68 if len(self.param_list) == 0:
70 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
71 for key_out, val_out in self.param_list:
72 fp.write((u'%s = %s\r\n' % (key_out,
73 val_out)).encode(self.encoding))
75 def build_xml(self, xml_parent):
76 for key_ini, val_ini in self.param_list:
77 child = SubElement(xml_parent, 'Parameter')
78 key = SubElement(child, 'Key')
79 value = SubElement(child, 'Value')
83 def from_xml(self, section):
84 for param in section.findall('Parameter'):
85 key = param.find('Key').text
86 value = param.find('Value').text
90 self.param_list.append((key, value))
92 class RegParam(AbstractParam):
93 # param_list = [Value, Value, ...]
94 def parse(self, line):
95 # = can occur in a registry key, so don't parse these
96 self.param_list.append(line)
99 def write_section(self, header, fp):
100 if len(self.param_list) == 0:
102 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
103 for param in self.param_list:
104 fp.write((u'%s\r\n' % param).encode(self.encoding))
106 def build_xml(self, xml_parent):
107 for val_ini in self.param_list:
108 child = SubElement(xml_parent, 'Parameter')
109 value = SubElement(child, 'Value')
112 def from_xml(self, section):
113 for param in section.findall('Parameter'):
114 value = param.find('Value').text
118 self.param_list.append(value)
120 class PrivSIDListParam(AbstractParam):
121 # param_list = [(Key, [SID, SID,..]),
122 def parse(self, line):
123 key, val = line.split('=')
125 self.param_list.append((key.strip(),
126 [x.strip() for x in val.split(',')]))
129 def write_section(self, header, fp):
130 if len(self.param_list) == 0:
132 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
133 for key_out, val in self.param_list:
134 val_out = u','.join(val)
135 fp.write((u'%s = %s\r\n' % (key_out, val_out)).encode(self.encoding))
137 def build_xml(self, xml_parent):
138 for key_ini, sid_list in self.param_list:
139 child = SubElement(xml_parent, 'Parameter')
140 key = SubElement(child, 'Key')
142 for val_ini in sid_list:
143 value = SubElement(child, 'Value')
144 value.attrib['user_id'] = 'TRUE'
147 def from_xml(self, section):
148 for param in section.findall('Parameter'):
149 key = param.find('Key').text
152 for val in param.findall('Value'):
157 sid_list.append(value)
159 self.param_list.append((key, sid_list))
161 class NameModeACLParam(AbstractParam):
162 # param_list = [[Name, Mode, ACL],]
163 def parse(self, line):
164 parameters = [None, None, None]
171 findex = line.find('"')
172 parameters[current_arg] = line[:findex]
173 line = line[findex + 1:]
174 # Skip past delimeter
175 elif line[:1] == ',':
178 # Read unquoted string
180 findex = line.find(',')
181 parameters[current_arg] = line[:findex]
186 self.param_list.append(parameters)
188 def write_section(self, header, fp):
189 if len(self.param_list) == 0:
191 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
192 for param in self.param_list:
193 fp.write((u'"%s",%s,"%s"\r\n' % tuple(param)).encode(self.encoding))
195 def build_xml(self, xml_parent):
196 for name_mode_acl in self.param_list:
197 child = SubElement(xml_parent, 'Parameter')
199 value = SubElement(child, 'Value')
200 value.text = name_mode_acl[0]
202 value = SubElement(child, 'Value')
203 value.text = name_mode_acl[1]
205 value = SubElement(child, 'Value')
206 value.attrib['acl'] = 'TRUE'
207 value.text = name_mode_acl[2]
209 def from_xml(self, section):
210 for param in section.findall('Parameter'):
211 name_mode_acl = [x.text if x.text else '' for x in param.findall('Value')]
212 self.param_list.append(name_mode_acl)
214 class MemberSIDListParam(AbstractParam):
215 # param_list = [([XXXX, Memberof|Members], [SID, SID...]),...]
216 def parse(self, line):
217 key, val = line.split('=')
221 self.param_list.append((key.split('__'),
222 [x.strip() for x in val.split(',')]))
225 def write_section(self, header, fp):
226 if len(self.param_list) == 0:
228 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
230 for key, val in self.param_list:
231 key_out = u'__'.join(key)
232 val_out = u','.join(val)
233 fp.write((u'%s = %s\r\n' % (key_out, val_out)).encode(self.encoding))
235 def build_xml(self, xml_parent):
236 for key_ini, sid_list in self.param_list:
237 child = SubElement(xml_parent, 'Parameter')
238 key = SubElement(child, 'Key')
239 key.text = key_ini[0]
240 key.attrib['member_type'] = key_ini[1]
241 key.attrib['user_id'] = 'TRUE'
243 for val_ini in sid_list:
244 value = SubElement(child, 'Value')
245 value.attrib['user_id'] = 'TRUE'
248 def from_xml(self, section):
249 for param in section.findall('Parameter'):
250 key = param.find('Key')
251 member_type = key.attrib['member_type']
254 for val in param.findall('Value'):
259 sid_list.append(value)
261 self.param_list.append(([key.text, member_type], sid_list))
263 class UnicodeParam(AbstractParam):
264 def parse(self, line):
268 def write_section(self, header, fp):
269 fp.write(u'[Unicode]\r\nUnicode=yes\r\n'.encode(self.encoding))
271 def build_xml(self, xml_parent):
272 # We do not bother storing this field
275 def from_xml(self, section):
276 # We do not bother storing this field
279 class VersionParam(AbstractParam):
280 def parse(self, line):
284 def write_section(self, header, fp):
285 out = u'[Version]\r\nsignature="$CHICAGO$"\r\nRevision=1\r\n'
286 fp.write(out.encode(self.encoding))
288 def build_xml(self, xml_parent):
289 # We do not bother storing this field
292 def from_xml(self, section):
293 # We do not bother storing this field
296 def parse(self, contents):
297 inf_file = contents.decode(self.encoding)
299 self.sections = collections.OrderedDict([
300 (u'Unicode', self.UnicodeParam()),
301 (u'Version', self.VersionParam()),
303 (u'System Access', self.IniParam()),
304 (u'Kerberos Policy', self.IniParam()),
305 (u'System Log', self.IniParam()),
306 (u'Security Log', self.IniParam()),
307 (u'Application Log', self.IniParam()),
308 (u'Event Audit', self.IniParam()),
309 (u'Registry Values', self.RegParam()),
310 (u'Privilege Rights', self.PrivSIDListParam()),
311 (u'Service General Setting', self.NameModeACLParam()),
312 (u'Registry Keys', self.NameModeACLParam()),
313 (u'File Security', self.NameModeACLParam()),
314 (u'Group Membership', self.MemberSIDListParam()),
317 current_param_parser = None
318 current_header_name = None
320 for line in inf_file.splitlines():
321 match = re.match('\[(.*)\]', line)
323 header_name = match.group(1)
324 if header_name in self.sections:
325 current_param_parser = self.sections[header_name]
326 # print current_param_parser
329 # print 'using', current_param_parser
330 current_param_parser.parse(line)
333 def write_binary(self, filename):
334 with codecs.open(filename, 'wb+',
335 self.output_encoding) as f:
336 for s in self.sections:
337 self.sections[s].write_section(s, f)
339 def write_xml(self, filename):
340 with open(filename, 'wb') as f:
341 root = Element('GptTmplInfFile')
343 for sec_inf in self.sections:
344 section = SubElement(root, 'Section')
345 section.attrib['name'] = sec_inf
347 self.sections[sec_inf].build_xml(section)
349 self.write_pretty_xml(root, f)
351 # contents = codecs.open(filename, encoding='utf-8').read()
352 # self.load_xml(fromstring(contents))
354 def load_xml(self, root):
355 self.sections = collections.OrderedDict([
356 (u'Unicode', self.UnicodeParam()),
357 (u'Version', self.VersionParam()),
359 (u'System Access', self.IniParam()),
360 (u'Kerberos Policy', self.IniParam()),
361 (u'System Log', self.IniParam()),
362 (u'Security Log', self.IniParam()),
363 (u'Application Log', self.IniParam()),
364 (u'Event Audit', self.IniParam()),
365 (u'Registry Values', self.RegParam()),
366 (u'Privilege Rights', self.PrivSIDListParam()),
367 (u'Service General Setting', self.NameModeACLParam()),
368 (u'Registry Keys', self.NameModeACLParam()),
369 (u'File Security', self.NameModeACLParam()),
370 (u'Group Membership', self.MemberSIDListParam()),
373 for s in root.findall('Section'):
374 self.sections[s.attrib['name']].from_xml(s)