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
):
33 output_encoding
= 'utf-16le'
36 __metaclass__
= ABCMeta
42 def parse(self
, line
):
46 def write_section(self
, header
, fp
):
50 def build_xml(self
, xml_parent
):
54 def from_xml(self
, section
):
57 class IniParam(AbstractParam
):
58 # param_list = [(Key, Value),]
60 def parse(self
, line
):
61 key
, val
= line
.split('=')
63 self
.param_list
.append((key
.strip(),
66 # print key.strip(), val.strip()
68 def write_section(self
, header
, fp
):
69 if len(self
.param_list
) == 0:
71 fp
.write(u
'[%s]\r\n' % header
)
72 for key_out
, val_out
in self
.param_list
:
73 fp
.write(u
'%s = %s\r\n' % (key_out
,
76 def build_xml(self
, xml_parent
):
77 for key_ini
, val_ini
in self
.param_list
:
78 child
= SubElement(xml_parent
, 'Parameter')
79 key
= SubElement(child
, 'Key')
80 value
= SubElement(child
, 'Value')
84 def from_xml(self
, section
):
85 for param
in section
.findall('Parameter'):
86 key
= param
.find('Key').text
87 value
= param
.find('Value').text
91 self
.param_list
.append((key
, value
))
93 class RegParam(AbstractParam
):
94 # param_list = [Value, Value, ...]
95 def parse(self
, line
):
96 # = can occur in a registry key, so don't parse these
97 self
.param_list
.append(line
)
100 def write_section(self
, header
, fp
):
101 if len(self
.param_list
) == 0:
103 fp
.write(u
'[%s]\r\n' % header
)
104 for param
in self
.param_list
:
105 fp
.write(u
'%s\r\n' % param
)
107 def build_xml(self
, xml_parent
):
108 for val_ini
in self
.param_list
:
109 child
= SubElement(xml_parent
, 'Parameter')
110 value
= SubElement(child
, 'Value')
113 def from_xml(self
, section
):
114 for param
in section
.findall('Parameter'):
115 value
= param
.find('Value').text
119 self
.param_list
.append(value
)
121 class PrivSIDListParam(AbstractParam
):
122 # param_list = [(Key, [SID, SID,..]),
123 def parse(self
, line
):
124 key
, val
= line
.split('=')
126 self
.param_list
.append((key
.strip(),
127 [x
.strip() for x
in val
.split(',')]))
130 def write_section(self
, header
, fp
):
131 if len(self
.param_list
) == 0:
133 fp
.write(u
'[%s]\r\n' % header
)
134 for key_out
, val
in self
.param_list
:
135 val_out
= u
','.join(val
)
136 fp
.write(u
'%s = %s\r\n' % (key_out
, val_out
))
138 def build_xml(self
, xml_parent
):
139 for key_ini
, sid_list
in self
.param_list
:
140 child
= SubElement(xml_parent
, 'Parameter')
141 key
= SubElement(child
, 'Key')
143 for val_ini
in sid_list
:
144 value
= SubElement(child
, 'Value')
145 value
.attrib
['user_id'] = 'TRUE'
148 def from_xml(self
, section
):
149 for param
in section
.findall('Parameter'):
150 key
= param
.find('Key').text
153 for val
in param
.findall('Value'):
158 sid_list
.append(value
)
160 self
.param_list
.append((key
, sid_list
))
162 class NameModeACLParam(AbstractParam
):
163 # param_list = [[Name, Mode, ACL],]
164 def parse(self
, line
):
165 parameters
= [None, None, None]
172 findex
= line
.find('"')
173 parameters
[current_arg
] = line
[:findex
]
174 line
= line
[findex
+ 1:]
175 # Skip past delimiter
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
)
193 for param
in self
.param_list
:
194 fp
.write(u
'"%s",%s,"%s"\r\n' % tuple(param
))
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
)
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
))
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')
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'
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(r
'\[(.*)\]', line
)
324 header_name
= match
.group(1)
325 if header_name
in self
.sections
:
326 current_param_parser
= self
.sections
[header_name
]
327 # print current_param_parser
330 # print 'using', current_param_parser
331 current_param_parser
.parse(line
)
334 def write_binary(self
, filename
):
335 with codecs
.open(filename
, 'wb+',
336 self
.output_encoding
) as f
:
337 # Write the byte-order mark
340 for s
in self
.sections
:
341 self
.sections
[s
].write_section(s
, f
)
343 def write_xml(self
, filename
):
344 with
open(filename
, 'wb') as f
:
345 root
= Element('GptTmplInfFile')
347 for sec_inf
in self
.sections
:
348 section
= SubElement(root
, 'Section')
349 section
.attrib
['name'] = sec_inf
351 self
.sections
[sec_inf
].build_xml(section
)
353 self
.write_pretty_xml(root
, f
)
355 # contents = codecs.open(filename, encoding='utf-8').read()
356 # self.load_xml(fromstring(contents))
358 def load_xml(self
, root
):
359 self
.sections
= collections
.OrderedDict([
360 (u
'Unicode', self
.UnicodeParam()),
361 (u
'Version', self
.VersionParam()),
363 (u
'System Access', self
.IniParam()),
364 (u
'Kerberos Policy', self
.IniParam()),
365 (u
'System Log', self
.IniParam()),
366 (u
'Security Log', self
.IniParam()),
367 (u
'Application Log', self
.IniParam()),
368 (u
'Event Audit', self
.IniParam()),
369 (u
'Registry Values', self
.RegParam()),
370 (u
'Privilege Rights', self
.PrivSIDListParam()),
371 (u
'Service General Setting', self
.NameModeACLParam()),
372 (u
'Registry Keys', self
.NameModeACLParam()),
373 (u
'File Security', self
.NameModeACLParam()),
374 (u
'Group Membership', self
.MemberSIDListParam()),
377 for s
in root
.findall('Section'):
378 self
.sections
[s
.attrib
['name']].from_xml(s
)