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]
172 findex = line.find('"')
173 parameters[current_arg] = line[:findex]
174 line = line[findex + 1:]
175 # Skip past delimeter
176 elif line[:1] == ',':
179 # Read unquoted string
181 findex = line.find(',')
182 parameters[current_arg] = line[:findex]
187 self.param_list.append(parameters)
189 def write_section(self, header, fp):
190 if len(self.param_list) == 0:
192 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
193 for param in self.param_list:
194 fp.write((u'"%s",%s,"%s"\r\n' % tuple(param)).encode(self.encoding))
196 def build_xml(self, xml_parent):
197 for name_mode_acl in self.param_list:
198 child = SubElement(xml_parent, 'Parameter')
200 value = SubElement(child, 'Value')
201 value.text = name_mode_acl[0]
203 value = SubElement(child, 'Value')
204 value.text = name_mode_acl[1]
206 value = SubElement(child, 'Value')
207 value.attrib['acl'] = 'TRUE'
208 value.text = name_mode_acl[2]
210 def from_xml(self, section):
211 for param in section.findall('Parameter'):
212 name_mode_acl = [x.text if x.text else '' for x in param.findall('Value')]
213 self.param_list.append(name_mode_acl)
215 class MemberSIDListParam(AbstractParam):
216 # param_list = [([XXXX, Memberof|Members], [SID, SID...]),...]
217 def parse(self, line):
218 key, val = line.split('=')
222 self.param_list.append((key.split('__'),
223 [x.strip() for x in val.split(',')]))
226 def write_section(self, header, fp):
227 if len(self.param_list) == 0:
229 fp.write((u'[%s]\r\n' % header).encode(self.encoding))
231 for key, val in self.param_list:
232 key_out = u'__'.join(key)
233 val_out = u','.join(val)
234 fp.write((u'%s = %s\r\n' % (key_out, val_out)).encode(self.encoding))
236 def build_xml(self, xml_parent):
237 for key_ini, sid_list in self.param_list:
238 child = SubElement(xml_parent, 'Parameter')
239 key = SubElement(child, 'Key')
240 key.text = key_ini[0]
241 key.attrib['member_type'] = key_ini[1]
242 key.attrib['user_id'] = 'TRUE'
244 for val_ini in sid_list:
245 value = SubElement(child, 'Value')
246 value.attrib['user_id'] = 'TRUE'
249 def from_xml(self, section):
250 for param in section.findall('Parameter'):
251 key = param.find('Key')
252 member_type = key.attrib['member_type']
255 for val in param.findall('Value'):
260 sid_list.append(value)
262 self.param_list.append(([key.text, member_type], sid_list))
264 class UnicodeParam(AbstractParam):
265 def parse(self, line):
269 def write_section(self, header, fp):
270 fp.write(u'[Unicode]\r\nUnicode=yes\r\n'.encode(self.encoding))
272 def build_xml(self, xml_parent):
273 # We do not bother storing this field
276 def from_xml(self, section):
277 # We do not bother storing this field
280 class VersionParam(AbstractParam):
281 def parse(self, line):
285 def write_section(self, header, fp):
286 out = u'[Version]\r\nsignature="$CHICAGO$"\r\nRevision=1\r\n'
287 fp.write(out.encode(self.encoding))
289 def build_xml(self, xml_parent):
290 # We do not bother storing this field
293 def from_xml(self, section):
294 # We do not bother storing this field
297 def parse(self, contents):
298 inf_file = contents.decode(self.encoding)
300 self.sections = collections.OrderedDict([
301 (u'Unicode', self.UnicodeParam()),
302 (u'Version', self.VersionParam()),
304 (u'System Access', self.IniParam()),
305 (u'Kerberos Policy', self.IniParam()),
306 (u'System Log', self.IniParam()),
307 (u'Security Log', self.IniParam()),
308 (u'Application Log', self.IniParam()),
309 (u'Event Audit', self.IniParam()),
310 (u'Registry Values', self.RegParam()),
311 (u'Privilege Rights', self.PrivSIDListParam()),
312 (u'Service General Setting', self.NameModeACLParam()),
313 (u'Registry Keys', self.NameModeACLParam()),
314 (u'File Security', self.NameModeACLParam()),
315 (u'Group Membership', self.MemberSIDListParam()),
318 current_param_parser = None
319 current_header_name = None
321 for line in inf_file.splitlines():
322 match = re.match('\[(.*)\]', line)
324 header_name = match.group(1)
325 if header_name in self.sections:
326 current_param_parser = self.sections[header_name]
327 current_header_name = header_name
328 # print current_param_parser
331 # print 'using', current_param_parser
332 current_param_parser.parse(line)
335 def write_binary(self, filename):
336 with codecs.open(filename, 'wb+',
337 self.output_encoding) as f:
338 for s in self.sections:
339 self.sections[s].write_section(s, f)
341 def write_xml(self, filename):
342 with file(filename, 'w') as f:
343 root = Element('GptTmplInfFile')
345 for sec_inf in self.sections:
346 section = SubElement(root, 'Section')
347 section.attrib['name'] = sec_inf
349 self.sections[sec_inf].build_xml(section)
351 self.write_pretty_xml(root, f)
353 # contents = codecs.open(filename, encoding='utf-8').read()
354 # self.load_xml(fromstring(contents))
356 def load_xml(self, root):
357 self.sections = collections.OrderedDict([
358 (u'Unicode', self.UnicodeParam()),
359 (u'Version', self.VersionParam()),
361 (u'System Access', self.IniParam()),
362 (u'Kerberos Policy', self.IniParam()),
363 (u'System Log', self.IniParam()),
364 (u'Security Log', self.IniParam()),
365 (u'Application Log', self.IniParam()),
366 (u'Event Audit', self.IniParam()),
367 (u'Registry Values', self.RegParam()),
368 (u'Privilege Rights', self.PrivSIDListParam()),
369 (u'Service General Setting', self.NameModeACLParam()),
370 (u'Registry Keys', self.NameModeACLParam()),
371 (u'File Security', self.NameModeACLParam()),
372 (u'Group Membership', self.MemberSIDListParam()),
375 for s in root.findall('Section'):
376 self.sections[s.attrib['name']].from_xml(s)