s4:kdc: adjust formatting of samba_kdc_update_pac() documentation
[Samba.git] / python / samba / gp_parse / gp_ini.py
blob1fac861b0a32f39646a9a52799f6f5cca7622336
1 # GPO Parser for extensions with ini files
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 xml.etree.ElementTree import Element, SubElement
25 from configparser import ConfigParser
26 from io import StringIO
28 from samba.gp_parse import GPParser, ENTITY_USER_ID
30 # [MS-GPFR] Group Policy Folder Redirection
31 # [MS-GPSCR] Scripts Extension
32 class GPIniParser(GPParser):
33 ini_conf = None
35 def parse(self, contents):
36 # Required dict_type in Python 2.7
37 self.ini_conf = ConfigParser(dict_type=collections.OrderedDict,
38 interpolation=None)
39 self.ini_conf.optionxform = str
41 self.ini_conf.readfp(StringIO(contents.decode(self.encoding)))
43 def build_xml_parameter(self, section_xml, section, key_ini, val_ini):
44 child = SubElement(section_xml, 'Parameter')
45 key = SubElement(child, 'Key')
46 value = SubElement(child, 'Value')
47 key.text = key_ini
48 value.text = val_ini
50 return child
52 def load_xml_parameter(self, param_xml, section):
53 key = param_xml.find('Key').text
54 value = param_xml.find('Value').text
55 if value is None:
56 value = ''
57 self.ini_conf.set(section, key, value)
59 return (key, value)
61 def build_xml_section(self, root_xml, sec_ini):
62 section = SubElement(root_xml, 'Section')
63 section.attrib['name'] = sec_ini
65 return section
67 def load_xml_section(self, section_xml):
68 section_name = section_xml.attrib['name']
69 self.ini_conf.add_section(section_name)
71 return section_name
73 def write_xml(self, filename):
74 with open(filename, 'wb') as f:
75 root = Element('IniFile')
77 for sec_ini in self.ini_conf.sections():
78 section = self.build_xml_section(root, sec_ini)
80 for key_ini, val_ini in self.ini_conf.items(sec_ini, raw=True):
81 self.build_xml_parameter(section, sec_ini, key_ini,
82 val_ini)
84 self.write_pretty_xml(root, f)
86 # from xml.etree.ElementTree import fromstring
87 # contents = codecs.open(filename, encoding='utf-8').read()
88 # self.load_xml(fromstring(contents))
90 def load_xml(self, root):
91 # Required dict_type in Python 2.7
92 self.ini_conf = ConfigParser(dict_type=collections.OrderedDict,
93 interpolation=None)
94 self.ini_conf.optionxform = str
96 for s in root.findall('Section'):
97 section_name = self.load_xml_section(s)
99 for param in s.findall('Parameter'):
100 self.load_xml_parameter(param, section_name)
102 def write_binary(self, filename):
103 with codecs.open(filename, 'wb+', self.encoding) as f:
104 self.ini_conf.write(f)
107 class GPTIniParser(GPIniParser):
108 encoding = 'utf-8'
110 def parse(self, contents):
111 try:
112 super(GPTIniParser, self).parse(contents)
113 except UnicodeDecodeError:
114 # Required dict_type in Python 2.7
115 self.ini_conf = ConfigParser(dict_type=collections.OrderedDict,
116 interpolation=None)
117 self.ini_conf.optionxform = str
119 # Fallback to Latin-1 which RSAT appears to use
120 self.ini_conf.readfp(StringIO(contents.decode('iso-8859-1')))
123 class GPScriptsIniParser(GPIniParser):
124 def build_xml_parameter(self, section_xml, section, key_ini, val_ini):
125 parent_return = super(GPScriptsIniParser,
126 self).build_xml_parameter(section_xml, section,
127 key_ini, val_ini)
129 cmdline = re.match('\\d+CmdLine$', key_ini)
130 if cmdline is not None:
131 value = parent_return.find('Value')
132 value.attrib['network_path'] = 'TRUE'
134 return parent_return
137 class GPFDeploy1IniParser(GPIniParser):
138 def build_xml_parameter(self, section_xml, section, key_ini, val_ini):
139 parent_return = super(GPFDeploy1IniParser,
140 self).build_xml_parameter(section_xml, section,
141 key_ini, val_ini)
142 # Add generalization metadata and parse out SID list
143 if section.lower() == 'folder_redirection':
144 # Process the header section
145 # {GUID} = S-1-1-0;S-1-1-0
147 # Remove the un-split SID values
148 key = parent_return.find('Value')
149 parent_return.remove(key)
151 sid_list = val_ini.strip().strip(';').split(';')
153 for sid in sid_list:
154 value = SubElement(parent_return, 'Value')
155 value.text = sid
156 value.attrib['user_id'] = 'TRUE'
158 else:
159 # Process redirection sections
160 # Only FullPath should be a network path
161 if key_ini == 'FullPath':
162 key = parent_return.find('Value')
163 key.attrib['network_path'] = 'TRUE'
165 return parent_return
167 def load_xml_parameter(self, param_xml, section):
168 # Re-join the SID list before entering ConfigParser
169 if section.lower() == 'folder_redirection':
170 key = param_xml.find('Key').text
171 values = param_xml.findall('Value')
173 if len(values) == 1:
174 # There appears to be a convention of a trailing semi-colon
175 # with only one value in the SID list.
176 value = values[0].text + ';'
177 else:
178 value = ';'.join([x.text for x in values])
180 self.ini_conf.set(section, key, value)
182 return (key, value)
184 # Do the normal ini code for other sections
185 return super(GPFDeploy1IniParser,
186 self).load_xml_parameter(param_xml, section)
188 def build_xml_section(self, root_xml, sec_ini):
189 section = SubElement(root_xml, 'Section')
191 if (sec_ini.lower() != 'folder_redirection' and
192 sec_ini.lower() != 'version'):
193 guid, sid = sec_ini.split('_')
194 section.attrib['fdeploy_GUID'] = guid
195 section.attrib['fdeploy_SID'] = sid
196 else:
197 section.attrib['name'] = sec_ini
199 return section
201 def load_xml_section(self, section_xml):
202 # Construct the name from GUID + SID if no name exists
203 if 'name' in section_xml.attrib:
204 section_name = section_xml.attrib['name']
205 else:
206 guid = section_xml.attrib['fdeploy_GUID']
207 sid = section_xml.attrib['fdeploy_SID']
208 section_name = guid + '_' + sid
210 self.ini_conf.add_section(section_name)
211 return section_name
213 def custom_entities(self, root, global_entities):
214 entities = []
215 fdeploy_sids = root.findall('.//Section[@fdeploy_SID]')
216 fdeploy_sids.sort(key = lambda x: x.tag)
218 for sid in fdeploy_sids:
219 old_attrib = sid.attrib['fdeploy_SID']
221 if old_attrib in global_entities:
222 new_attrib = global_entities[old_attrib]
223 else:
224 new_attrib = self.new_xml_entity(old_attrib, ENTITY_USER_ID)
225 entities.append((new_attrib, old_attrib))
227 global_entities.update([(old_attrib, new_attrib)])
229 sid.attrib['fdeploy_SID'] = new_attrib
231 return entities