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
105
106 static int
107 pcmk__acl_annotate_permissions_recursive(xmlNode *xml_modify)
108 {
109
110 static xmlNs *ns_recycle_writable = NULL,
111 *ns_recycle_readable = NULL,
112 *ns_recycle_denied = NULL;
113 static const xmlDoc *prev_doc = NULL;
114
115 xmlNode *i_node = NULL;
116 const xmlChar *ns;
117 int ret = EINVAL;
118
119 if (prev_doc == NULL || prev_doc != xml_modify->doc) {
120 prev_doc = xml_modify->doc;
121 ns_recycle_writable = ns_recycle_readable = ns_recycle_denied = NULL;
122 }
123
124 for (i_node = xml_modify; i_node != NULL; i_node = i_node->next) {
125 switch (i_node->type) {
126 case XML_ELEMENT_NODE:
127 pcmk__set_xml_doc_flag(i_node, pcmk__xf_tracking);
128
129 if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_read)) {
130 ns = NS_DENIED;
131 } else if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_write)) {
132 ns = NS_READABLE;
133 } else {
134 ns = NS_WRITABLE;
135 }
136 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
137
138 if (i_node->properties != NULL) {
139
140
141
142 ret |= pcmk__acl_annotate_permissions_recursive((xmlNodePtr) i_node->properties);
143 }
144 if (i_node->children != NULL) {
145 ret |= pcmk__acl_annotate_permissions_recursive(i_node->children);
146 }
147 break;
148 case XML_ATTRIBUTE_NODE:
149
150 if (!pcmk__check_acl(i_node->parent,
151 (const char *) i_node->name,
152 pcmk__xf_acl_read)) {
153 ns = NS_DENIED;
154 } else if (!pcmk__check_acl(i_node,
155 (const char *) i_node->name,
156 pcmk__xf_acl_write)) {
157 ns = NS_READABLE;
158 } else {
159 ns = NS_WRITABLE;
160 }
161 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
162 break;
163 case XML_COMMENT_NODE:
164
165 if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_read))
166 {
167 ns = NS_DENIED;
168 }
169 else if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_write))
170 {
171 ns = NS_READABLE;
172 }
173 else
174 {
175 ns = NS_WRITABLE;
176 }
177 pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
178 break;
179 default:
180 break;
181 }
182 }
183
184 return ret;
185 }
186
187 int
188 pcmk__acl_annotate_permissions(const char *cred, xmlDoc *cib_doc,
189 xmlDoc **acl_evaled_doc)
190 {
191 int ret, version;
192 xmlNode *target, *comment;
193 const char *validation;
194
195 CRM_CHECK(cred != NULL, return EINVAL);
196 CRM_CHECK(cib_doc != NULL, return EINVAL);
197 CRM_CHECK(acl_evaled_doc != NULL, return EINVAL);
198
199
200 if (strpbrk(cred, "<>&") != NULL) {
201 return EINVAL;
202 }
203
204 if (!pcmk_acl_required(cred)) {
205
206 return pcmk_rc_already;
207 }
208
209 validation = crm_element_value(xmlDocGetRootElement(cib_doc),
210 XML_ATTR_VALIDATION);
211 version = get_schema_version(validation);
212 if (get_schema_version(PCMK__COMPAT_ACL_2_MIN_INCL) > version) {
213 return pcmk_rc_schema_validation;
214 }
215
216 target = copy_xml(xmlDocGetRootElement(cib_doc));
217 if (target == NULL) {
218 return EINVAL;
219 }
220
221 pcmk__enable_acl(target, target, cred);
222
223 ret = pcmk__acl_annotate_permissions_recursive(target);
224
225 if (ret == pcmk_rc_ok) {
226 char* credentials = crm_strdup_printf("ACLs as evaluated for user %s", cred);
227 comment = xmlNewDocComment(target->doc, (pcmkXmlStr) credentials);
228 free(credentials);
229 if (comment == NULL) {
230 xmlFreeNode(target);
231 return EINVAL;
232 }
233 xmlAddPrevSibling(xmlDocGetRootElement(target->doc), comment);
234 *acl_evaled_doc = target->doc;
235 return pcmk_rc_ok;
236 } else {
237 xmlFreeNode(target);
238 return ret;
239 }
240 }
241
242 int
243 pcmk__acl_evaled_render(xmlDoc *annotated_doc, enum pcmk__acl_render_how how,
244 xmlChar **doc_txt_ptr)
245 {
246 xmlDoc *xslt_doc;
247 xsltStylesheet *xslt;
248 xsltTransformContext *xslt_ctxt;
249 xmlDoc *res;
250 char *sfile;
251 static const char *params_namespace[] = {
252 "accessrendercfg:c-writable", ACL_NS_Q_PREFIX "writable:",
253 "accessrendercfg:c-readable", ACL_NS_Q_PREFIX "readable:",
254 "accessrendercfg:c-denied", ACL_NS_Q_PREFIX "denied:",
255 "accessrendercfg:c-reset", "",
256 "accessrender:extra-spacing", "no",
257 "accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
258 NULL
259 }, *params_useansi[] = {
260
261 "accessrendercfg:c-writable", "\x1b[32m",
262 "accessrendercfg:c-readable", "\x1b[34m",
263 "accessrendercfg:c-denied", "\x1b[31m",
264 "accessrendercfg:c-reset", "\x1b[0m",
265 "accessrender:extra-spacing", "no",
266 "accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
267 NULL
268 }, *params_noansi[] = {
269 "accessrendercfg:c-writable", "vvv---[ WRITABLE ]---vvv",
270 "accessrendercfg:c-readable", "vvv---[ READABLE ]---vvv",
271 "accessrendercfg:c-denied", "vvv---[ ~DENIED~ ]---vvv",
272 "accessrendercfg:c-reset", "",
273 "accessrender:extra-spacing", "yes",
274 "accessrender:self-reproducing-prefix", "",
275 NULL
276 };
277 const char **params;
278 int ret;
279 xmlParserCtxtPtr parser_ctxt;
280
281
282
283
284
285
286 xmlChar *annotated_dump;
287 int dump_size;
288
289 xmlDocDumpFormatMemory(annotated_doc, &annotated_dump, &dump_size, 1);
290 res = xmlReadDoc(annotated_dump, "on-the-fly-access-render", NULL,
291 XML_PARSE_NONET);
292 CRM_ASSERT(res != NULL);
293 xmlFree(annotated_dump);
294 xmlFreeDoc(annotated_doc);
295 annotated_doc = res;
296
297 sfile = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_base_xslt,
298 "access-render-2");
299 parser_ctxt = xmlNewParserCtxt();
300
301 CRM_ASSERT(sfile != NULL);
302 CRM_ASSERT(parser_ctxt != NULL);
303
304 xslt_doc = xmlCtxtReadFile(parser_ctxt, sfile, NULL, XML_PARSE_NONET);
305
306 xslt = xsltParseStylesheetDoc(xslt_doc);
307 if (xslt == NULL) {
308 crm_crit("Problem in parsing %s", sfile);
309 return EINVAL;
310 }
311 free(sfile);
312 sfile = NULL;
313 xmlFreeParserCtxt(parser_ctxt);
314
315 xslt_ctxt = xsltNewTransformContext(xslt, annotated_doc);
316 CRM_ASSERT(xslt_ctxt != NULL);
317
318 if (how == pcmk__acl_render_text) {
319 params = params_noansi;
320 } else if (how == pcmk__acl_render_namespace) {
321 params = params_namespace;
322 } else {
323 params = params_useansi;
324 }
325
326 xsltQuoteUserParams(xslt_ctxt, params);
327
328 res = xsltApplyStylesheetUser(xslt, annotated_doc, NULL,
329 NULL, NULL, xslt_ctxt);
330
331 xmlFreeDoc(annotated_doc);
332 annotated_doc = NULL;
333 xsltFreeTransformContext(xslt_ctxt);
334 xslt_ctxt = NULL;
335
336 if (how == pcmk__acl_render_color && params != params_useansi) {
337 char **param_i = (char **) params;
338 do {
339 free(*param_i);
340 } while (*param_i++ != NULL);
341 free(params);
342 }
343
344 if (res == NULL) {
345 ret = EINVAL;
346 } else {
347 int doc_txt_len;
348 int temp = xsltSaveResultToString(doc_txt_ptr, &doc_txt_len, res, xslt);
349 xmlFreeDoc(res);
350 if (temp == 0) {
351 ret = pcmk_rc_ok;
352 } else {
353 ret = EINVAL;
354 }
355 }
356 xsltFreeStylesheet(xslt);
357 return ret;
358 }