python/gp_parse/gp_inf: remove shadowed method
[samba.git] / python / samba / gp_parse / gp_inf.py
1 # GPO Parser for security extensions
2 #
3 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
4 # Written by Garming Sam <garming@catalyst.net.nz>
5 #
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.
10 #
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.
15 #
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/>.
18 #
19
20 import codecs
21 import collections
22 import re
23
24 from abc import ABCMeta, abstractmethod
25 from xml.etree.ElementTree import Element, SubElement
26
27 from samba.gp_parse import GPParser
28
29 # [MS-GPSB] Security Protocol Extension
30 class GptTmplInfParser(GPParser):
31     sections = None
32
33     class AbstractParam:
34         __metaclass__ = ABCMeta
35         encoding = 'utf-16le'
36
37         def __init__(self):
38             self.param_list = []
39
40         @abstractmethod
41         def parse(self, line):
42             pass
43
44         @abstractmethod
45         def write_section(self, header, fp):
46             pass
47
48         @abstractmethod
49         def build_xml(self, xml_parent):
50             pass
51
52         @abstractmethod
53         def from_xml(self, section):
54             pass
55
56     class IniParam(AbstractParam):
57         # param_list = [(Key, Value),]
58
59         def parse(self, line):
60             key, val = line.split('=')
61
62             self.param_list.append((key.strip(),
63                                     val.strip()))
64
65             # print key.strip(), val.strip()
66
67         def write_section(self, header, fp):
68             if len(self.param_list) ==  0:
69                 return
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))
74
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')
80                 key.text = key_ini
81                 value.text = val_ini
82
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
87                 if value is None:
88                     value = ''
89
90                 self.param_list.append((key, value))
91
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)
97             # print line
98
99         def write_section(self, header, fp):
100             if len(self.param_list) ==  0:
101                 return
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))
105
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')
110                 value.text = val_ini
111
112         def from_xml(self, section):
113             for param in section.findall('Parameter'):
114                 value = param.find('Value').text
115                 if value is None:
116                     value = ''
117
118                 self.param_list.append(value)
119
120     class PrivSIDListParam(AbstractParam):
121         # param_list = [(Key, [SID, SID,..]),
122         def parse(self, line):
123             key, val = line.split('=')
124
125             self.param_list.append((key.strip(),
126                                     [x.strip() for x in val.split(',')]))
127             # print line
128
129         def write_section(self, header, fp):
130             if len(self.param_list) ==  0:
131                 return
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))
136
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')
141                 key.text = key_ini
142                 for val_ini in sid_list:
143                     value = SubElement(child, 'Value')
144                     value.attrib['user_id'] = 'TRUE'
145                     value.text = val_ini
146
147         def from_xml(self, section):
148             for param in section.findall('Parameter'):
149                 key = param.find('Key').text
150
151                 sid_list = []
152                 for val in param.findall('Value'):
153                     value = val.text
154                     if value is None:
155                         value = ''
156
157                     sid_list.append(value)
158
159                 self.param_list.append((key, sid_list))
160
161     class NameModeACLParam(AbstractParam):
162         # param_list = [[Name, Mode, ACL],]
163         def parse(self, line):
164             parameters = [None, None, None]
165             index = 0
166             current_arg = 0
167
168             while line != '':
169                 # Read quoted string
170                 if line[:1] == '"':
171                     line = line[1:]
172                     findex = line.find('"')
173                     parameters[current_arg] = line[:findex]
174                     line = line[findex + 1:]
175                 # Skip past delimeter
176                 elif line[:1] == ',':
177                     line = line[1:]
178                     current_arg += 1
179                 # Read unquoted string
180                 else:
181                     findex = line.find(',')
182                     parameters[current_arg] = line[:findex]
183                     line = line[findex:]
184
185             # print parameters
186             # print line
187             self.param_list.append(parameters)
188
189         def write_section(self, header, fp):
190             if len(self.param_list) ==  0:
191                 return
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))
195
196         def build_xml(self, xml_parent):
197             for name_mode_acl in self.param_list:
198                 child = SubElement(xml_parent, 'Parameter')
199
200                 value = SubElement(child, 'Value')
201                 value.text = name_mode_acl[0]
202
203                 value = SubElement(child, 'Value')
204                 value.text = name_mode_acl[1]
205
206                 value = SubElement(child, 'Value')
207                 value.attrib['acl'] = 'TRUE'
208                 value.text = name_mode_acl[2]
209
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)
214
215     class MemberSIDListParam(AbstractParam):
216         # param_list = [([XXXX, Memberof|Members], [SID, SID...]),...]
217         def parse(self, line):
218             key, val = line.split('=')
219
220             key = key.strip()
221
222             self.param_list.append((key.split('__'),
223                                     [x.strip() for x in val.split(',')]))
224             # print line
225
226         def write_section(self, header, fp):
227             if len(self.param_list) ==  0:
228                 return
229             fp.write((u'[%s]\r\n' % header).encode(self.encoding))
230
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))
235
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'
243
244                 for val_ini in sid_list:
245                     value = SubElement(child, 'Value')
246                     value.attrib['user_id'] = 'TRUE'
247                     value.text = val_ini
248
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']
253
254                 sid_list = []
255                 for val in param.findall('Value'):
256                     value = val.text
257                     if value is None:
258                         value = ''
259
260                     sid_list.append(value)
261
262                 self.param_list.append(([key.text, member_type], sid_list))
263
264     class UnicodeParam(AbstractParam):
265         def parse(self, line):
266             # print line
267             pass
268
269         def write_section(self, header, fp):
270             fp.write(u'[Unicode]\r\nUnicode=yes\r\n'.encode(self.encoding))
271
272         def build_xml(self, xml_parent):
273             # We do not bother storing this field
274             pass
275
276         def from_xml(self, section):
277             # We do not bother storing this field
278             pass
279
280     class VersionParam(AbstractParam):
281         def parse(self, line):
282             # print line
283             pass
284
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))
288
289         def build_xml(self, xml_parent):
290             # We do not bother storing this field
291             pass
292
293         def from_xml(self, section):
294             # We do not bother storing this field
295             pass
296
297     def parse(self, contents):
298         inf_file = contents.decode(self.encoding)
299
300         self.sections = collections.OrderedDict([
301             (u'Unicode', self.UnicodeParam()),
302             (u'Version', self.VersionParam()),
303
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()),
316         ])
317
318         current_param_parser = None
319         current_header_name = None
320
321         for line in inf_file.splitlines():
322             match = re.match('\[(.*)\]', line)
323             if match:
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
329                     continue
330
331             # print 'using', current_param_parser
332             current_param_parser.parse(line)
333
334
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)
340
341     def write_xml(self, filename):
342         with file(filename, 'w') as f:
343             root = Element('GptTmplInfFile')
344
345             for sec_inf in self.sections:
346                 section = SubElement(root, 'Section')
347                 section.attrib['name'] = sec_inf
348
349                 self.sections[sec_inf].build_xml(section)
350
351             self.write_pretty_xml(root, f)
352
353         # contents = codecs.open(filename, encoding='utf-8').read()
354         # self.load_xml(fromstring(contents))
355
356     def load_xml(self, root):
357         self.sections = collections.OrderedDict([
358             (u'Unicode', self.UnicodeParam()),
359             (u'Version', self.VersionParam()),
360
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()),
373         ])
374
375         for s in root.findall('Section'):
376             self.sections[s.attrib['name']].from_xml(s)