ctdb-scripts: Improve update and listing code
[samba4-gss.git] / python / samba / gp_parse / gp_inf.py
blob51035e6ec9fcfdb9499fa109fde0b5689cdf5b5e
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/>.
20 import codecs
21 import collections
22 import re
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):
31 sections = None
32 encoding = 'utf-16'
33 output_encoding = 'utf-16le'
35 class AbstractParam:
36 __metaclass__ = ABCMeta
38 def __init__(self):
39 self.param_list = []
41 @abstractmethod
42 def parse(self, line):
43 pass
45 @abstractmethod
46 def write_section(self, header, fp):
47 pass
49 @abstractmethod
50 def build_xml(self, xml_parent):
51 pass
53 @abstractmethod
54 def from_xml(self, section):
55 pass
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(),
64 val.strip()))
66 # print key.strip(), val.strip()
68 def write_section(self, header, fp):
69 if len(self.param_list) == 0:
70 return
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,
74 val_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')
81 key.text = key_ini
82 value.text = val_ini
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
88 if value is None:
89 value = ''
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)
98 # print line
100 def write_section(self, header, fp):
101 if len(self.param_list) == 0:
102 return
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')
111 value.text = val_ini
113 def from_xml(self, section):
114 for param in section.findall('Parameter'):
115 value = param.find('Value').text
116 if value is None:
117 value = ''
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(',')]))
128 # print line
130 def write_section(self, header, fp):
131 if len(self.param_list) == 0:
132 return
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')
142 key.text = key_ini
143 for val_ini in sid_list:
144 value = SubElement(child, 'Value')
145 value.attrib['user_id'] = 'TRUE'
146 value.text = val_ini
148 def from_xml(self, section):
149 for param in section.findall('Parameter'):
150 key = param.find('Key').text
152 sid_list = []
153 for val in param.findall('Value'):
154 value = val.text
155 if value is None:
156 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]
166 current_arg = 0
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 delimiter
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:]
185 # print parameters
186 # print line
187 self.param_list.append(parameters)
189 def write_section(self, header, fp):
190 if len(self.param_list) == 0:
191 return
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('=')
220 key = key.strip()
222 self.param_list.append((key.split('__'),
223 [x.strip() for x in val.split(',')]))
224 # print line
226 def write_section(self, header, fp):
227 if len(self.param_list) == 0:
228 return
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'
247 value.text = val_ini
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']
254 sid_list = []
255 for val in param.findall('Value'):
256 value = val.text
257 if value is None:
258 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):
266 # print line
267 pass
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
274 pass
276 def from_xml(self, section):
277 # We do not bother storing this field
278 pass
280 class VersionParam(AbstractParam):
281 def parse(self, line):
282 # print line
283 pass
285 def write_section(self, header, fp):
286 out = u'[Version]\r\nsignature="$CHICAGO$"\r\nRevision=1\r\n'
287 fp.write(out)
289 def build_xml(self, xml_parent):
290 # We do not bother storing this field
291 pass
293 def from_xml(self, section):
294 # We do not bother storing this field
295 pass
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)
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 # print current_param_parser
328 continue
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
338 f.write(u'\ufeff')
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)