OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 from xml.dom import minidom | |
7 from grit.format.policy_templates.writers import xml_formatted_writer | |
8 | |
9 | |
10 def GetWriter(config): | |
11 '''Factory method for instanciating the ADMXWriter. Every Writer needs a | |
12 GetWriter method because the TemplateFormatter uses this method to | |
13 instantiate a Writer. | |
14 ''' | |
15 return ADMXWriter(['win'], config) | |
16 | |
17 | |
18 class ADMXWriter(xml_formatted_writer.XMLFormattedWriter): | |
19 '''Class for generating an ADMX policy template. It is used by the | |
20 PolicyTemplateGenerator to write the admx file. | |
21 ''' | |
22 | |
23 # DOM root node of the generated ADMX document. | |
24 _doc = None | |
25 | |
26 # The ADMX "policies" element that contains the ADMX "policy" elements that | |
27 # are generated. | |
28 _active_policies_elem = None | |
29 | |
30 def _AdmlString(self, name): | |
31 '''Creates a reference to the named string in an ADML file. | |
32 Args: | |
33 name: Name of the referenced ADML string. | |
34 ''' | |
35 name = name.replace('.', '_') | |
36 return '$(string.' + name + ')' | |
37 | |
38 def _AdmlStringExplain(self, name): | |
39 '''Creates a reference to the named explanation string in an ADML file. | |
40 Args: | |
41 name: Name of the referenced ADML explanation. | |
42 ''' | |
43 name = name.replace('.', '_') | |
44 return '$(string.' + name + '_Explain)' | |
45 | |
46 def _AdmlPresentation(self, name): | |
47 '''Creates a reference to the named presentation element in an ADML file. | |
48 Args: | |
49 name: Name of the referenced ADML presentation element. | |
50 ''' | |
51 return '$(presentation.' + name + ')' | |
52 | |
53 def _AddPolicyNamespaces(self, parent, prefix, namespace): | |
54 '''Generates the ADMX "policyNamespace" element and adds the elements to the | |
55 passed parent element. The namespace of the generated ADMX document is | |
56 define via the ADMX "target" element. Used namespaces are declared with an | |
57 ADMX "using" element. ADMX "target" and "using" elements are children of the | |
58 ADMX "policyNamespace" element. | |
59 | |
60 Args: | |
61 parent: The parent node to which all generated elements are added. | |
62 prefix: A logical name that can be used in the generated ADMX document to | |
63 refere to this namespace. | |
64 namespace: Namespace of the generated ADMX document. | |
65 ''' | |
66 policy_namespaces_elem = self.AddElement(parent, 'policyNamespaces') | |
67 attributes = { | |
68 'prefix': prefix, | |
69 'namespace': namespace, | |
70 } | |
71 self.AddElement(policy_namespaces_elem, 'target', attributes) | |
72 attributes = { | |
73 'prefix': 'windows', | |
74 'namespace': 'Microsoft.Policies.Windows', | |
75 } | |
76 self.AddElement(policy_namespaces_elem, 'using', attributes) | |
77 | |
78 def _AddCategory(self, parent, name, display_name, | |
79 parent_category_name=None): | |
80 '''Adds an ADMX category element to the passed parent node. The following | |
81 snippet shows an example of a category element where "chromium" is the value | |
82 of the parameter name: | |
83 | |
84 <category displayName="$(string.chromium)" name="chromium"/> | |
85 | |
86 Each parent node can have only one category with a given name. Adding the | |
87 same category again with the same attributes is ignored, but adding it | |
88 again with different attributes is an error. | |
89 | |
90 Args: | |
91 parent: The parent node to which all generated elements are added. | |
92 name: Name of the category. | |
93 display_name: Display name of the category. | |
94 parent_category_name: Name of the parent category. Defaults to None. | |
95 ''' | |
96 existing = filter(lambda e: e.getAttribute('name') == name, | |
97 parent.getElementsByTagName('category')) | |
98 if existing: | |
99 assert len(existing) == 1 | |
100 assert existing[0].getAttribute('name') == name | |
101 assert existing[0].getAttribute('displayName') == display_name | |
102 return | |
103 attributes = { | |
104 'name': name, | |
105 'displayName': display_name, | |
106 } | |
107 category_elem = self.AddElement(parent, 'category', attributes) | |
108 if parent_category_name: | |
109 attributes = {'ref': parent_category_name} | |
110 self.AddElement(category_elem, 'parentCategory', attributes) | |
111 | |
112 def _AddCategories(self, categories): | |
113 '''Generates the ADMX "categories" element and adds it to the categories | |
114 main node. The "categories" element defines the category for the policies | |
115 defined in this ADMX document. Here is an example of an ADMX "categories" | |
116 element: | |
117 | |
118 <categories> | |
119 <category displayName="$(string.google)" name="google"/> | |
120 <category displayName="$(string.googlechrome)" name="googlechrome"> | |
121 <parentCategory ref="google"/> | |
122 </category> | |
123 </categories> | |
124 | |
125 Args: | |
126 categories_path: The categories path e.g. ['google', 'googlechrome']. For | |
127 each level in the path a "category" element will be generated. Except | |
128 for the root level, each level refers to its parent. Since the root | |
129 level category has no parent it does not require a parent reference. | |
130 ''' | |
131 category_name = None | |
132 for category in categories: | |
133 parent_category_name = category_name | |
134 category_name = category | |
135 self._AddCategory(self._categories_elem, category_name, | |
136 self._AdmlString(category_name), parent_category_name) | |
137 | |
138 def _AddSupportedOn(self, parent, supported_os): | |
139 '''Generates the "supportedOn" ADMX element and adds it to the passed | |
140 parent node. The "supportedOn" element contains information about supported | |
141 Windows OS versions. The following code snippet contains an example of a | |
142 "supportedOn" element: | |
143 | |
144 <supportedOn> | |
145 <definitions> | |
146 <definition name="SUPPORTED_WINXPSP2" | |
147 displayName="$(string.SUPPORTED_WINXPSP2)"/> | |
148 </definitions> | |
149 ... | |
150 </supportedOn> | |
151 | |
152 Args: | |
153 parent: The parent element to which all generated elements are added. | |
154 supported_os: List with all supported Win OSes. | |
155 ''' | |
156 supported_on_elem = self.AddElement(parent, 'supportedOn') | |
157 definitions_elem = self.AddElement(supported_on_elem, 'definitions') | |
158 attributes = { | |
159 'name': supported_os, | |
160 'displayName': self._AdmlString(supported_os) | |
161 } | |
162 self.AddElement(definitions_elem, 'definition', attributes) | |
163 | |
164 def _AddStringPolicy(self, parent, name): | |
165 '''Generates ADMX elements for a String-Policy and adds them to the | |
166 passed parent node. | |
167 ''' | |
168 attributes = { | |
169 'id': name, | |
170 'valueName': name, | |
171 'maxLength': '1000000', | |
172 } | |
173 self.AddElement(parent, 'text', attributes) | |
174 | |
175 def _AddIntPolicy(self, parent, name): | |
176 '''Generates ADMX elements for an Int-Policy and adds them to the passed | |
177 parent node. | |
178 ''' | |
179 attributes = { | |
180 'id': name, | |
181 'valueName': name, | |
182 'maxValue': '2000000000', | |
183 } | |
184 self.AddElement(parent, 'decimal', attributes) | |
185 | |
186 def _AddEnumPolicy(self, parent, policy): | |
187 '''Generates ADMX elements for an Enum-Policy and adds them to the | |
188 passed parent element. | |
189 ''' | |
190 name = policy['name'] | |
191 items = policy['items'] | |
192 attributes = { | |
193 'id': name, | |
194 'valueName': name, | |
195 } | |
196 enum_elem = self.AddElement(parent, 'enum', attributes) | |
197 for item in items: | |
198 attributes = {'displayName': self._AdmlString(item['name'])} | |
199 item_elem = self.AddElement(enum_elem, 'item', attributes) | |
200 value_elem = self.AddElement(item_elem, 'value') | |
201 value_string = str(item['value']) | |
202 if policy['type'] == 'int-enum': | |
203 self.AddElement(value_elem, 'decimal', {'value': value_string}) | |
204 else: | |
205 self.AddElement(value_elem, 'string', {}, value_string) | |
206 | |
207 def _AddListPolicy(self, parent, key, name): | |
208 '''Generates ADMX XML elements for a List-Policy and adds them to the | |
209 passed parent element. | |
210 ''' | |
211 attributes = { | |
212 # The ID must be in sync with ID of the corresponding element in the ADML | |
213 # file. | |
214 'id': name + 'Desc', | |
215 'valuePrefix': '', | |
216 'key': key + '\\' + name, | |
217 } | |
218 self.AddElement(parent, 'list', attributes) | |
219 | |
220 def _AddMainPolicy(self, parent): | |
221 '''Generates ADMX elements for a Main-Policy amd adds them to the | |
222 passed parent element. | |
223 ''' | |
224 enabled_value_elem = self.AddElement(parent, 'enabledValue'); | |
225 self.AddElement(enabled_value_elem, 'decimal', {'value': '1'}) | |
226 disabled_value_elem = self.AddElement(parent, 'disabledValue'); | |
227 self.AddElement(disabled_value_elem, 'decimal', {'value': '0'}) | |
228 | |
229 def _GetElements(self, policy_group_elem): | |
230 '''Returns the ADMX "elements" child from an ADMX "policy" element. If the | |
231 "policy" element has no "elements" child yet, a new child is created. | |
232 | |
233 Args: | |
234 policy_group_elem: The ADMX "policy" element from which the child element | |
235 "elements" is returned. | |
236 | |
237 Raises: | |
238 Exception: The policy_group_elem does not contain a ADMX "policy" element. | |
239 ''' | |
240 if policy_group_elem.tagName != 'policy': | |
241 raise Exception('Expected a "policy" element but got a "%s" element' | |
242 % policy_group_elem.tagName) | |
243 elements_list = policy_group_elem.getElementsByTagName('elements'); | |
244 if len(elements_list) == 0: | |
245 return self.AddElement(policy_group_elem, 'elements') | |
246 elif len(elements_list) == 1: | |
247 return elements_list[0] | |
248 else: | |
249 raise Exception('There is supposed to be only one "elements" node but' | |
250 ' there are %s.' % str(len(elements_list))) | |
251 | |
252 def _WritePolicy(self, policy, name, key, parent): | |
253 '''Generates AMDX elements for a Policy. There are four different policy | |
254 types: Main-Policy, String-Policy, Enum-Policy and List-Policy. | |
255 ''' | |
256 policies_elem = self._active_policies_elem | |
257 policy_type = policy['type'] | |
258 policy_name = policy['name'] | |
259 if policy_type == 'external': | |
260 # This type can only be set through cloud policy. | |
261 return | |
262 | |
263 attributes = { | |
264 'name': name, | |
265 'class': self.config['win_group_policy_class'], | |
266 'displayName': self._AdmlString(policy_name), | |
267 'explainText': self._AdmlStringExplain(policy_name), | |
268 'presentation': self._AdmlPresentation(policy_name), | |
269 'key': key, | |
270 } | |
271 # Store the current "policy" AMDX element in self for later use by the | |
272 # WritePolicy method. | |
273 policy_elem = self.AddElement(policies_elem, 'policy', | |
274 attributes) | |
275 self.AddElement(policy_elem, 'parentCategory', | |
276 {'ref': parent}) | |
277 self.AddElement(policy_elem, 'supportedOn', | |
278 {'ref': self.config['win_supported_os']}) | |
279 if policy_type == 'main': | |
280 self.AddAttribute(policy_elem, 'valueName', policy_name) | |
281 self._AddMainPolicy(policy_elem) | |
282 elif policy_type in ('string', 'dict'): | |
283 # 'dict' policies are configured as JSON-encoded strings on Windows. | |
284 parent = self._GetElements(policy_elem) | |
285 self._AddStringPolicy(parent, policy_name) | |
286 elif policy_type == 'int': | |
287 parent = self._GetElements(policy_elem) | |
288 self._AddIntPolicy(parent, policy_name) | |
289 elif policy_type in ('int-enum', 'string-enum'): | |
290 parent = self._GetElements(policy_elem) | |
291 self._AddEnumPolicy(parent, policy) | |
292 elif policy_type in ('list', 'string-enum-list'): | |
293 parent = self._GetElements(policy_elem) | |
294 self._AddListPolicy(parent, key, policy_name) | |
295 elif policy_type == 'group': | |
296 pass | |
297 else: | |
298 raise Exception('Unknown policy type %s.' % policy_type) | |
299 | |
300 def WritePolicy(self, policy): | |
301 if self.CanBeMandatory(policy): | |
302 self._WritePolicy(policy, | |
303 policy['name'], | |
304 self.config['win_reg_mandatory_key_name'], | |
305 self._active_mandatory_policy_group_name) | |
306 | |
307 def WriteRecommendedPolicy(self, policy): | |
308 self._WritePolicy(policy, | |
309 policy['name'] + '_recommended', | |
310 self.config['win_reg_recommended_key_name'], | |
311 self._active_recommended_policy_group_name) | |
312 | |
313 def _BeginPolicyGroup(self, group, name, parent): | |
314 '''Generates ADMX elements for a Policy-Group. | |
315 ''' | |
316 attributes = { | |
317 'name': name, | |
318 'displayName': self._AdmlString(group['name'] + '_group'), | |
319 } | |
320 category_elem = self.AddElement(self._categories_elem, | |
321 'category', | |
322 attributes) | |
323 attributes = { | |
324 'ref': parent | |
325 } | |
326 self.AddElement(category_elem, 'parentCategory', attributes) | |
327 | |
328 def BeginPolicyGroup(self, group): | |
329 self._BeginPolicyGroup(group, | |
330 group['name'], | |
331 self.config['win_mandatory_category_path'][-1]) | |
332 self._active_mandatory_policy_group_name = group['name'] | |
333 | |
334 def EndPolicyGroup(self): | |
335 self._active_mandatory_policy_group_name = \ | |
336 self.config['win_mandatory_category_path'][-1] | |
337 | |
338 def BeginRecommendedPolicyGroup(self, group): | |
339 self._BeginPolicyGroup(group, | |
340 group['name'] + '_recommended', | |
341 self.config['win_recommended_category_path'][-1]) | |
342 self._active_recommended_policy_group_name = group['name'] + '_recommended' | |
343 | |
344 def EndRecommendedPolicyGroup(self): | |
345 self._active_recommended_policy_group_name = \ | |
346 self.config['win_recommended_category_path'][-1] | |
347 | |
348 def BeginTemplate(self): | |
349 '''Generates the skeleton of the ADMX template. An ADMX template contains | |
350 an ADMX "PolicyDefinitions" element with four child nodes: "policies" | |
351 "policyNamspaces", "resources", "supportedOn" and "categories" | |
352 ''' | |
353 dom_impl = minidom.getDOMImplementation('') | |
354 self._doc = dom_impl.createDocument(None, 'policyDefinitions', None) | |
355 if self._GetChromiumVersionString() is not None: | |
356 self.AddComment(self._doc.documentElement, self.config['build'] + \ | |
357 ' version: ' + self._GetChromiumVersionString()) | |
358 policy_definitions_elem = self._doc.documentElement | |
359 | |
360 policy_definitions_elem.attributes['revision'] = '1.0' | |
361 policy_definitions_elem.attributes['schemaVersion'] = '1.0' | |
362 | |
363 self._AddPolicyNamespaces(policy_definitions_elem, | |
364 self.config['admx_prefix'], | |
365 self.config['admx_namespace']) | |
366 self.AddElement(policy_definitions_elem, 'resources', | |
367 {'minRequiredRevision' : '1.0'}) | |
368 self._AddSupportedOn(policy_definitions_elem, | |
369 self.config['win_supported_os']) | |
370 self._categories_elem = self.AddElement(policy_definitions_elem, | |
371 'categories') | |
372 self._AddCategories(self.config['win_mandatory_category_path']) | |
373 self._AddCategories(self.config['win_recommended_category_path']) | |
374 self._active_policies_elem = self.AddElement(policy_definitions_elem, | |
375 'policies') | |
376 self._active_mandatory_policy_group_name = \ | |
377 self.config['win_mandatory_category_path'][-1] | |
378 self._active_recommended_policy_group_name = \ | |
379 self.config['win_recommended_category_path'][-1] | |
380 | |
381 def GetTemplateText(self): | |
382 return self.ToPrettyXml(self._doc) | |
OLD | NEW |