This source file includes following definitions.
- pcmk__acl_mark_node_with_namespace
- pcmk__acl_annotate_permissions_recursive
- pcmk__acl_annotate_permissions
- pcmk__acl_evaled_render
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <pwd.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18
19 #include <libxml/parser.h>
20 #include <libxml/tree.h>
21 #include <libxml/xpath.h>
22 #include <libxslt/transform.h>
23 #include <libxslt/variables.h>
24 #include <libxslt/xsltutils.h>
25
26 #include <crm/crm.h>
27 #include <crm/msg_xml.h>
28 #include <crm/common/xml.h>
29 #include <crm/common/xml_internal.h>
30 #include <crm/common/internal.h>
31
32 #include <pacemaker-internal.h>
33
34 #define ACL_NS_PREFIX "http://clusterlabs.org/ns/pacemaker/access/"
35 #define ACL_NS_Q_PREFIX "pcmk-access-"
36 #define ACL_NS_Q_WRITABLE (const xmlChar *) ACL_NS_Q_PREFIX "writable"
37 #define ACL_NS_Q_READABLE (const xmlChar *) ACL_NS_Q_PREFIX "readable"
38 #define ACL_NS_Q_DENIED (const xmlChar *) ACL_NS_Q_PREFIX "denied"
39
40 static const xmlChar *NS_WRITABLE = (const xmlChar *) ACL_NS_PREFIX "writable";
41 static const xmlChar *NS_READABLE = (const xmlChar *) ACL_NS_PREFIX "readable";
42 static const xmlChar *NS_DENIED = (const xmlChar *) ACL_NS_PREFIX "denied";
43
44
45
46
47
48
49
50
51
52
53
54
55 static void
56 pcmk__acl_mark_node_with_namespace(xmlNode *i_node, const xmlChar *ns, int *ret, xmlNs **ns_recycle_writable, xmlNs **ns_recycle_readable, xmlNs **ns_recycle_denied)
57 {
58 if (ns == NS_WRITABLE)
59 {
60 if (*ns_recycle_writable == NULL)
61 {
62 *ns_recycle_writable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
63 NS_WRITABLE, ACL_NS_Q_WRITABLE);
64 }
65 xmlSetNs(i_node, *ns_recycle_writable);
66 *ret = pcmk_rc_ok;
67 }
68 else if (ns == NS_READABLE)
69 {
70 if (*ns_recycle_readable == NULL)
71 {
72 *ns_recycle_readable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
73 NS_READABLE, ACL_NS_Q_READABLE);
74 }
75 xmlSetNs(i_node, *ns_recycle_readable);
76 *ret = pcmk_rc_ok;
77 }
78 else if (ns == NS_DENIED)
79 {
80 if (*ns_recycle_denied == NULL)
81 {
82 *ns_recycle_denied = xmlNewNs(xmlDocGetRootElement(i_node->doc),
83 NS_DENIED, ACL_NS_Q_DENIED);
84 };
85 xmlSetNs(i_node, *ns_recycle_denied);
86 *ret = pcmk_rc_ok;
87 }
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 static int
105 pcmk__acl_annotate_permissions_recursive(xmlNode *xml_modify)
106 {
107
108 static xmlNs *ns_recycle_writable = NULL,
109 *ns_recycle_readable = NULL,
110 *ns_recycle_denied = NULL;
111 static const xmlDoc *prev_doc = NULL;
112
113 xmlNode *i_node = NULL;
114 const xmlChar *ns;
115 int ret = EINVAL;
116
117 if (prev_doc == NULL || prev_doc != xml_modify->doc) {
118 prev_doc = xml_modify->doc;
119 ns_recycle_writable = ns_recycle_readable = ns_recycle_denied = NULL;
120 }
121
122 for (i_node = xml_modify; i_node != NULL; i_node = i_node->next) {
123 switch (i_node->type) {
124 case XML_ELEMENT_NODE:
125 pcmk__set_xml_doc_flag(i_node, pcmk__xf_tracking);
126
127 if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_read)) {
128 ns = NS_DENIED;
129 } else if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_write)) {
130 ns = NS_READABLE;
131 } else {
132 ns = NS_WRITABLE;
133 }
134 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
135
136 if (i_node->properties != NULL) {
137
138
139
140 ret |= pcmk__acl_annotate_permissions_recursive((xmlNodePtr) i_node->properties);
141 }
142 if (i_node->children != NULL) {
143 ret |= pcmk__acl_annotate_permissions_recursive(i_node->children);
144 }
145 break;
146 case XML_ATTRIBUTE_NODE:
147
148 if (!pcmk__check_acl(i_node->parent,
149 (const char *) i_node->name,
150 pcmk__xf_acl_read)) {
151 ns = NS_DENIED;
152 } else if (!pcmk__check_acl(i_node,
153 (const char *) i_node->name,
154 pcmk__xf_acl_write)) {
155 ns = NS_READABLE;
156 } else {
157 ns = NS_WRITABLE;
158 }
159 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
160 break;
161 case XML_COMMENT_NODE:
162
163 if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_read))
164 {
165 ns = NS_DENIED;
166 }
167 else if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_write))
168 {
169 ns = NS_READABLE;
170 }
171 else
172 {
173 ns = NS_WRITABLE;
174 }
175 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
176 break;
177 default:
178 break;
179 }
180 }
181
182 return ret;
183 }
184
185 int
186 pcmk__acl_annotate_permissions(const char *cred, xmlDoc *cib_doc,
187 xmlDoc **acl_evaled_doc)
188 {
189 int ret, version;
190 xmlNode *target, *comment;
191 const char *validation;
192
193 CRM_CHECK(cred != NULL, return EINVAL);
194 CRM_CHECK(cib_doc != NULL, return EINVAL);
195 CRM_CHECK(acl_evaled_doc != NULL, return EINVAL);
196
197
198 if (strpbrk(cred, "<>&") != NULL) {
199 return EINVAL;
200 }
201
202 if (!pcmk_acl_required(cred)) {
203
204 return pcmk_rc_already;
205 }
206
207 validation = crm_element_value(xmlDocGetRootElement(cib_doc),
208 XML_ATTR_VALIDATION);
209 version = get_schema_version(validation);
210 if (get_schema_version(PCMK__COMPAT_ACL_2_MIN_INCL) > version) {
211 return pcmk_rc_schema_validation;
212 }
213
214 target = copy_xml(xmlDocGetRootElement(cib_doc));
215 if (target == NULL) {
216 return EINVAL;
217 }
218
219 pcmk__enable_acl(target, target, cred);
220
221 ret = pcmk__acl_annotate_permissions_recursive(target);
222
223 if (ret == pcmk_rc_ok) {
224 char* credentials = crm_strdup_printf("ACLs as evaluated for user %s", cred);
225 comment = xmlNewDocComment(target->doc, (pcmkXmlStr) credentials);
226 free(credentials);
227 if (comment == NULL) {
228 xmlFreeNode(target);
229 return EINVAL;
230 }
231 xmlAddPrevSibling(xmlDocGetRootElement(target->doc), comment);
232 *acl_evaled_doc = target->doc;
233 return pcmk_rc_ok;
234 } else {
235 xmlFreeNode(target);
236 return ret;
237 }
238 }
239
240 int
241 pcmk__acl_evaled_render(xmlDoc *annotated_doc, enum pcmk__acl_render_how how,
242 xmlChar **doc_txt_ptr)
243 {
244 xmlDoc *xslt_doc;
245 xsltStylesheet *xslt;
246 xsltTransformContext *xslt_ctxt;
247 xmlDoc *res;
248 char *sfile;
249 static const char *params_namespace[] = {
250 "accessrendercfg:c-writable", ACL_NS_Q_PREFIX "writable:",
251 "accessrendercfg:c-readable", ACL_NS_Q_PREFIX "readable:",
252 "accessrendercfg:c-denied", ACL_NS_Q_PREFIX "denied:",
253 "accessrendercfg:c-reset", "",
254 "accessrender:extra-spacing", "no",
255 "accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
256 NULL
257 }, *params_useansi[] = {
258
259 "accessrendercfg:c-writable", "\x1b[32m",
260 "accessrendercfg:c-readable", "\x1b[34m",
261 "accessrendercfg:c-denied", "\x1b[31m",
262 "accessrendercfg:c-reset", "\x1b[0m",
263 "accessrender:extra-spacing", "no",
264 "accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
265 NULL
266 }, *params_noansi[] = {
267 "accessrendercfg:c-writable", "vvv---[ WRITABLE ]---vvv",
268 "accessrendercfg:c-readable", "vvv---[ READABLE ]---vvv",
269 "accessrendercfg:c-denied", "vvv---[ ~DENIED~ ]---vvv",
270 "accessrendercfg:c-reset", "",
271 "accessrender:extra-spacing", "yes",
272 "accessrender:self-reproducing-prefix", "",
273 NULL
274 };
275 const char **params;
276 int ret;
277 xmlParserCtxtPtr parser_ctxt;
278
279
280
281
282
283
284 xmlChar *annotated_dump;
285 int dump_size;
286
287 xmlDocDumpFormatMemory(annotated_doc, &annotated_dump, &dump_size, 1);
288 res = xmlReadDoc(annotated_dump, "on-the-fly-access-render", NULL,
289 XML_PARSE_NONET);
290 CRM_ASSERT(res != NULL);
291 xmlFree(annotated_dump);
292 xmlFreeDoc(annotated_doc);
293 annotated_doc = res;
294
295 sfile = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_base_xslt,
296 "access-render-2");
297 parser_ctxt = xmlNewParserCtxt();
298
299 CRM_ASSERT(sfile != NULL);
300 CRM_ASSERT(parser_ctxt != NULL);
301
302 xslt_doc = xmlCtxtReadFile(parser_ctxt, sfile, NULL, XML_PARSE_NONET);
303
304 xslt = xsltParseStylesheetDoc(xslt_doc);
305 if (xslt == NULL) {
306 crm_crit("Problem in parsing %s", sfile);
307 return EINVAL;
308 }
309 free(sfile);
310 sfile = NULL;
311 xmlFreeParserCtxt(parser_ctxt);
312
313 xslt_ctxt = xsltNewTransformContext(xslt, annotated_doc);
314 CRM_ASSERT(xslt_ctxt != NULL);
315
316 if (how == pcmk__acl_render_text) {
317 params = params_noansi;
318 } else if (how == pcmk__acl_render_namespace) {
319 params = params_namespace;
320 } else {
321 params = params_useansi;
322 }
323
324 xsltQuoteUserParams(xslt_ctxt, params);
325
326 res = xsltApplyStylesheetUser(xslt, annotated_doc, NULL,
327 NULL, NULL, xslt_ctxt);
328
329 xmlFreeDoc(annotated_doc);
330 annotated_doc = NULL;
331 xsltFreeTransformContext(xslt_ctxt);
332 xslt_ctxt = NULL;
333
334 if (how == pcmk__acl_render_color && params != params_useansi) {
335 char **param_i = (char **) params;
336 do {
337 free(*param_i);
338 } while (*param_i++ != NULL);
339 free(params);
340 }
341
342 if (res == NULL) {
343 ret = EINVAL;
344 } else {
345 int doc_txt_len;
346 int temp = xsltSaveResultToString(doc_txt_ptr, &doc_txt_len, res, xslt);
347 xmlFreeDoc(res);
348 if (temp == 0) {
349 ret = pcmk_rc_ok;
350 } else {
351 ret = EINVAL;
352 }
353 }
354 xsltFreeStylesheet(xslt);
355 return ret;
356 }