This source file includes following definitions.
- free_acl
- pcmk__free_acls
- create_acl
- parse_acl_entry
- acl_to_text
- pcmk__apply_acl
- pcmk__unpack_acl
- pcmk__enable_acl
- test_acl_mode
- purge_xml_attributes
- xml_acl_filtered_copy
- implicitly_allowed
- pcmk__apply_creation_acl
- xml_acl_denied
- xml_acl_disable
- xml_acl_enabled
- pcmk__check_acl
- pcmk_acl_required
- pcmk__uid2username
- pcmk__update_acl_user
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/tree.h>
20
21 #include <crm/crm.h>
22 #include <crm/msg_xml.h>
23 #include <crm/common/xml.h>
24 #include <crm/common/xml_internal.h>
25 #include "crmcommon_private.h"
26
27 typedef struct xml_acl_s {
28 enum xml_private_flags mode;
29 char *xpath;
30 } xml_acl_t;
31
32 static void
33 free_acl(void *data)
34 {
35 if (data) {
36 xml_acl_t *acl = data;
37
38 free(acl->xpath);
39 free(acl);
40 }
41 }
42
43 void
44 pcmk__free_acls(GList *acls)
45 {
46 g_list_free_full(acls, free_acl);
47 }
48
49 static GList *
50 create_acl(const xmlNode *xml, GList *acls, enum xml_private_flags mode)
51 {
52 xml_acl_t *acl = NULL;
53
54 const char *tag = crm_element_value(xml, XML_ACL_ATTR_TAG);
55 const char *ref = crm_element_value(xml, XML_ACL_ATTR_REF);
56 const char *xpath = crm_element_value(xml, XML_ACL_ATTR_XPATH);
57 const char *attr = crm_element_value(xml, XML_ACL_ATTR_ATTRIBUTE);
58
59 if (tag == NULL) {
60
61 tag = crm_element_value(xml, XML_ACL_ATTR_TAGv1);
62 }
63 if (ref == NULL) {
64
65 ref = crm_element_value(xml, XML_ACL_ATTR_REFv1);
66 }
67
68 if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
69
70 crm_trace("Ignoring ACL <%s> element without selection criteria",
71 crm_element_name(xml));
72 return NULL;
73 }
74
75 acl = calloc(1, sizeof (xml_acl_t));
76 CRM_ASSERT(acl != NULL);
77
78 acl->mode = mode;
79 if (xpath) {
80 acl->xpath = strdup(xpath);
81 CRM_ASSERT(acl->xpath != NULL);
82 crm_trace("Unpacked ACL <%s> element using xpath: %s",
83 crm_element_name(xml), acl->xpath);
84
85 } else {
86 GString *buf = g_string_sized_new(128);
87
88 if ((ref != NULL) && (attr != NULL)) {
89
90 pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@" XML_ATTR_ID "='",
91 ref, "' and @", attr, "]", NULL);
92
93 } else if (ref != NULL) {
94 pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@" XML_ATTR_ID "='",
95 ref, "']", NULL);
96
97 } else if (attr != NULL) {
98 pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@", attr, "]", NULL);
99
100 } else {
101 pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), NULL);
102 }
103
104 acl->xpath = strdup((const char *) buf->str);
105 CRM_ASSERT(acl->xpath != NULL);
106
107 g_string_free(buf, TRUE);
108 crm_trace("Unpacked ACL <%s> element as xpath: %s",
109 crm_element_name(xml), acl->xpath);
110 }
111
112 return g_list_append(acls, acl);
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127 static GList *
128 parse_acl_entry(const xmlNode *acl_top, const xmlNode *acl_entry, GList *acls)
129 {
130 xmlNode *child = NULL;
131
132 for (child = pcmk__xe_first_child(acl_entry); child;
133 child = pcmk__xe_next(child)) {
134 const char *tag = crm_element_name(child);
135 const char *kind = crm_element_value(child, XML_ACL_ATTR_KIND);
136
137 if (strcmp(XML_ACL_TAG_PERMISSION, tag) == 0){
138 CRM_ASSERT(kind != NULL);
139 crm_trace("Unpacking ACL <%s> element of kind '%s'", tag, kind);
140 tag = kind;
141 } else {
142 crm_trace("Unpacking ACL <%s> element", tag);
143 }
144
145 if (strcmp(XML_ACL_TAG_ROLE_REF, tag) == 0
146 || strcmp(XML_ACL_TAG_ROLE_REFv1, tag) == 0) {
147 const char *ref_role = crm_element_value(child, XML_ATTR_ID);
148
149 if (ref_role) {
150 xmlNode *role = NULL;
151
152 for (role = pcmk__xe_first_child(acl_top); role;
153 role = pcmk__xe_next(role)) {
154 if (!strcmp(XML_ACL_TAG_ROLE, (const char *) role->name)) {
155 const char *role_id = crm_element_value(role,
156 XML_ATTR_ID);
157
158 if (role_id && strcmp(ref_role, role_id) == 0) {
159 crm_trace("Unpacking referenced role '%s' in ACL <%s> element",
160 role_id, crm_element_name(acl_entry));
161 acls = parse_acl_entry(acl_top, role, acls);
162 break;
163 }
164 }
165 }
166 }
167
168 } else if (strcmp(XML_ACL_TAG_READ, tag) == 0) {
169 acls = create_acl(child, acls, pcmk__xf_acl_read);
170
171 } else if (strcmp(XML_ACL_TAG_WRITE, tag) == 0) {
172 acls = create_acl(child, acls, pcmk__xf_acl_write);
173
174 } else if (strcmp(XML_ACL_TAG_DENY, tag) == 0) {
175 acls = create_acl(child, acls, pcmk__xf_acl_deny);
176
177 } else {
178 crm_warn("Ignoring unknown ACL %s '%s'",
179 (kind? "kind" : "element"), tag);
180 }
181 }
182
183 return acls;
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 static const char *
209 acl_to_text(enum xml_private_flags flags)
210 {
211 if (pcmk_is_set(flags, pcmk__xf_acl_deny)) {
212 return "deny";
213
214 } else if (pcmk_any_flags_set(flags, pcmk__xf_acl_write|pcmk__xf_acl_create)) {
215 return "read/write";
216
217 } else if (pcmk_is_set(flags, pcmk__xf_acl_read)) {
218 return "read";
219 }
220 return "none";
221 }
222
223 void
224 pcmk__apply_acl(xmlNode *xml)
225 {
226 GList *aIter = NULL;
227 xml_doc_private_t *docpriv = xml->doc->_private;
228 xml_node_private_t *nodepriv;
229 xmlXPathObjectPtr xpathObj = NULL;
230
231 if (!xml_acl_enabled(xml)) {
232 crm_trace("Skipping ACLs for user '%s' because not enabled for this XML",
233 docpriv->user);
234 return;
235 }
236
237 for (aIter = docpriv->acls; aIter != NULL; aIter = aIter->next) {
238 int max = 0, lpc = 0;
239 xml_acl_t *acl = aIter->data;
240
241 xpathObj = xpath_search(xml, acl->xpath);
242 max = numXpathResults(xpathObj);
243
244 for (lpc = 0; lpc < max; lpc++) {
245 xmlNode *match = getXpathResult(xpathObj, lpc);
246
247 nodepriv = match->_private;
248 pcmk__set_xml_flags(nodepriv, acl->mode);
249
250
251 pcmk__if_tracing(
252 {
253 GString *path = pcmk__element_xpath(match);
254 crm_trace("Applying %s ACL to %s matched by %s",
255 acl_to_text(acl->mode), path->str, acl->xpath);
256 g_string_free(path, TRUE);
257 },
258 {}
259 );
260 }
261 crm_trace("Applied %s ACL %s (%d match%s)",
262 acl_to_text(acl->mode), acl->xpath, max,
263 ((max == 1)? "" : "es"));
264 freeXpathObject(xpathObj);
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 void
282 pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
283 {
284 xml_doc_private_t *docpriv = NULL;
285
286 if ((target == NULL) || (target->doc == NULL)
287 || (target->doc->_private == NULL)) {
288 return;
289 }
290
291 docpriv = target->doc->_private;
292 if (!pcmk_acl_required(user)) {
293 crm_trace("Not unpacking ACLs because not required for user '%s'",
294 user);
295
296 } else if (docpriv->acls == NULL) {
297 xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS,
298 source, LOG_NEVER);
299
300 pcmk__str_update(&docpriv->user, user);
301
302 if (acls) {
303 xmlNode *child = NULL;
304
305 for (child = pcmk__xe_first_child(acls); child;
306 child = pcmk__xe_next(child)) {
307 const char *tag = crm_element_name(child);
308
309 if (!strcmp(tag, XML_ACL_TAG_USER)
310 || !strcmp(tag, XML_ACL_TAG_USERv1)) {
311 const char *id = crm_element_value(child, XML_ATTR_NAME);
312
313 if (id == NULL) {
314 id = crm_element_value(child, XML_ATTR_ID);
315 }
316
317 if (id && strcmp(id, user) == 0) {
318 crm_debug("Unpacking ACLs for user '%s'", id);
319 docpriv->acls = parse_acl_entry(acls, child, docpriv->acls);
320 }
321 } else if (!strcmp(tag, XML_ACL_TAG_GROUP)) {
322 const char *id = crm_element_value(child, XML_ATTR_NAME);
323
324 if (id == NULL) {
325 id = crm_element_value(child, XML_ATTR_ID);
326 }
327
328 if (id && pcmk__is_user_in_group(user,id)) {
329 crm_debug("Unpacking ACLs for group '%s'", id);
330 docpriv->acls = parse_acl_entry(acls, child, docpriv->acls);
331 }
332 }
333 }
334 }
335 }
336 }
337
338
339
340
341
342
343
344
345
346 void
347 pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
348 {
349 pcmk__unpack_acl(acl_source, target, user);
350 pcmk__set_xml_doc_flag(target, pcmk__xf_acl_enabled);
351 pcmk__apply_acl(target);
352 }
353
354 static inline bool
355 test_acl_mode(enum xml_private_flags allowed, enum xml_private_flags requested)
356 {
357 if (pcmk_is_set(allowed, pcmk__xf_acl_deny)) {
358 return false;
359
360 } else if (pcmk_all_flags_set(allowed, requested)) {
361 return true;
362
363 } else if (pcmk_is_set(requested, pcmk__xf_acl_read)
364 && pcmk_is_set(allowed, pcmk__xf_acl_write)) {
365 return true;
366
367 } else if (pcmk_is_set(requested, pcmk__xf_acl_create)
368 && pcmk_any_flags_set(allowed, pcmk__xf_acl_write|pcmk__xf_created)) {
369 return true;
370 }
371 return false;
372 }
373
374
375
376
377
378
379
380
381
382
383
384
385 static bool
386 purge_xml_attributes(xmlNode *xml)
387 {
388 xmlNode *child = NULL;
389 xmlAttr *xIter = NULL;
390 bool readable_children = false;
391 xml_node_private_t *nodepriv = xml->_private;
392
393 if (test_acl_mode(nodepriv->flags, pcmk__xf_acl_read)) {
394 crm_trace("%s[@" XML_ATTR_ID "=%s] is readable",
395 crm_element_name(xml), ID(xml));
396 return true;
397 }
398
399 xIter = xml->properties;
400 while (xIter != NULL) {
401 xmlAttr *tmp = xIter;
402 const char *prop_name = (const char *)xIter->name;
403
404 xIter = xIter->next;
405 if (strcmp(prop_name, XML_ATTR_ID) == 0) {
406 continue;
407 }
408
409 xmlUnsetProp(xml, tmp->name);
410 }
411
412 child = pcmk__xml_first_child(xml);
413 while ( child != NULL ) {
414 xmlNode *tmp = child;
415
416 child = pcmk__xml_next(child);
417 readable_children |= purge_xml_attributes(tmp);
418 }
419
420 if (!readable_children) {
421 free_xml(xml);
422 }
423 return readable_children;
424 }
425
426
427
428
429
430
431
432
433
434
435
436
437 bool
438 xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
439 xmlNode **result)
440 {
441 GList *aIter = NULL;
442 xmlNode *target = NULL;
443 xml_doc_private_t *docpriv = NULL;
444
445 *result = NULL;
446 if ((xml == NULL) || !pcmk_acl_required(user)) {
447 crm_trace("Not filtering XML because ACLs not required for user '%s'",
448 user);
449 return false;
450 }
451
452 crm_trace("Filtering XML copy using user '%s' ACLs", user);
453 target = copy_xml(xml);
454 if (target == NULL) {
455 return true;
456 }
457
458 pcmk__enable_acl(acl_source, target, user);
459
460 docpriv = target->doc->_private;
461 for(aIter = docpriv->acls; aIter != NULL && target; aIter = aIter->next) {
462 int max = 0;
463 xml_acl_t *acl = aIter->data;
464
465 if (acl->mode != pcmk__xf_acl_deny) {
466
467
468 } else if (acl->xpath) {
469 int lpc = 0;
470 xmlXPathObjectPtr xpathObj = xpath_search(target, acl->xpath);
471
472 max = numXpathResults(xpathObj);
473 for(lpc = 0; lpc < max; lpc++) {
474 xmlNode *match = getXpathResult(xpathObj, lpc);
475
476 if (!purge_xml_attributes(match) && (match == target)) {
477 crm_trace("ACLs deny user '%s' access to entire XML document",
478 user);
479 freeXpathObject(xpathObj);
480 return true;
481 }
482 }
483 crm_trace("ACLs deny user '%s' access to %s (%d %s)",
484 user, acl->xpath, max,
485 pcmk__plural_alt(max, "match", "matches"));
486 freeXpathObject(xpathObj);
487 }
488 }
489
490 if (!purge_xml_attributes(target)) {
491 crm_trace("ACLs deny user '%s' access to entire XML document", user);
492 return true;
493 }
494
495 if (docpriv->acls) {
496 g_list_free_full(docpriv->acls, free_acl);
497 docpriv->acls = NULL;
498
499 } else {
500 crm_trace("User '%s' without ACLs denied access to entire XML document",
501 user);
502 free_xml(target);
503 target = NULL;
504 }
505
506 if (target) {
507 *result = target;
508 }
509
510 return true;
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524
525 static bool
526 implicitly_allowed(const xmlNode *xml)
527 {
528 GString *path = NULL;
529
530 for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
531 if (strcmp((const char *) prop->name, XML_ATTR_ID) != 0) {
532 return false;
533 }
534 }
535
536 path = pcmk__element_xpath(xml);
537 CRM_ASSERT(path != NULL);
538
539 if (strstr((const char *) path->str, "/" XML_CIB_TAG_ACLS "/") != NULL) {
540 g_string_free(path, TRUE);
541 return false;
542 }
543
544 g_string_free(path, TRUE);
545 return true;
546 }
547
548 #define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565 void
566 pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
567 {
568 xml_node_private_t *nodepriv = xml->_private;
569
570 if (pcmk_is_set(nodepriv->flags, pcmk__xf_created)) {
571 if (implicitly_allowed(xml)) {
572 crm_trace("Creation of <%s> scaffolding with id=\"%s\""
573 " is implicitly allowed",
574 crm_element_name(xml), display_id(xml));
575
576 } else if (pcmk__check_acl(xml, NULL, pcmk__xf_acl_write)) {
577 crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
578 crm_element_name(xml), display_id(xml));
579
580 } else if (check_top) {
581 crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
582 crm_element_name(xml), display_id(xml));
583 pcmk_free_xml_subtree(xml);
584 return;
585
586 } else {
587 crm_notice("ACLs would disallow creation of %s<%s> with id=\"%s\"",
588 ((xml == xmlDocGetRootElement(xml->doc))? "root element " : ""),
589 crm_element_name(xml), display_id(xml));
590 }
591 }
592
593 for (xmlNode *cIter = pcmk__xml_first_child(xml); cIter != NULL; ) {
594 xmlNode *child = cIter;
595 cIter = pcmk__xml_next(cIter);
596 pcmk__apply_creation_acl(child, true);
597 }
598 }
599
600
601
602
603
604
605
606
607 bool
608 xml_acl_denied(const xmlNode *xml)
609 {
610 if (xml && xml->doc && xml->doc->_private){
611 xml_doc_private_t *docpriv = xml->doc->_private;
612
613 return pcmk_is_set(docpriv->flags, pcmk__xf_acl_denied);
614 }
615 return false;
616 }
617
618 void
619 xml_acl_disable(xmlNode *xml)
620 {
621 if (xml_acl_enabled(xml)) {
622 xml_doc_private_t *docpriv = xml->doc->_private;
623
624
625 pcmk__apply_acl(xml);
626 pcmk__apply_creation_acl(xml, false);
627 pcmk__clear_xml_flags(docpriv, pcmk__xf_acl_enabled);
628 }
629 }
630
631
632
633
634
635
636
637
638 bool
639 xml_acl_enabled(const xmlNode *xml)
640 {
641 if (xml && xml->doc && xml->doc->_private){
642 xml_doc_private_t *docpriv = xml->doc->_private;
643
644 return pcmk_is_set(docpriv->flags, pcmk__xf_acl_enabled);
645 }
646 return false;
647 }
648
649 bool
650 pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
651 {
652 CRM_ASSERT(xml);
653 CRM_ASSERT(xml->doc);
654 CRM_ASSERT(xml->doc->_private);
655
656 if (pcmk__tracking_xml_changes(xml, false) && xml_acl_enabled(xml)) {
657 xmlNode *parent = xml;
658 xml_doc_private_t *docpriv = xml->doc->_private;
659 GString *xpath = NULL;
660
661 if (docpriv->acls == NULL) {
662 pcmk__set_xml_doc_flag(xml, pcmk__xf_acl_denied);
663
664 pcmk__if_tracing({}, return false);
665 xpath = pcmk__element_xpath(xml);
666 if (name != NULL) {
667 pcmk__g_strcat(xpath, "[@", name, "]", NULL);
668 }
669
670 qb_log_from_external_source(__func__, __FILE__,
671 "User '%s' without ACLs denied %s "
672 "access to %s", LOG_TRACE, __LINE__, 0,
673 docpriv->user, acl_to_text(mode),
674 (const char *) xpath->str);
675 g_string_free(xpath, TRUE);
676 return false;
677 }
678
679
680
681
682
683
684 if (name) {
685 xmlAttr *attr = xmlHasProp(xml, (pcmkXmlStr) name);
686
687 if (attr && mode == pcmk__xf_acl_create) {
688 mode = pcmk__xf_acl_write;
689 }
690 }
691
692 while (parent && parent->_private) {
693 xml_node_private_t *nodepriv = parent->_private;
694 if (test_acl_mode(nodepriv->flags, mode)) {
695 return true;
696
697 } else if (pcmk_is_set(nodepriv->flags, pcmk__xf_acl_deny)) {
698 pcmk__set_xml_doc_flag(xml, pcmk__xf_acl_denied);
699
700 pcmk__if_tracing({}, return false);
701 xpath = pcmk__element_xpath(xml);
702 if (name != NULL) {
703 pcmk__g_strcat(xpath, "[@", name, "]", NULL);
704 }
705
706 qb_log_from_external_source(__func__, __FILE__,
707 "%sACL denies user '%s' %s access "
708 "to %s", LOG_TRACE, __LINE__, 0,
709 (parent != xml)? "Parent ": "",
710 docpriv->user, acl_to_text(mode),
711 (const char *) xpath->str);
712 g_string_free(xpath, TRUE);
713 return false;
714 }
715 parent = parent->parent;
716 }
717
718 pcmk__set_xml_doc_flag(xml, pcmk__xf_acl_denied);
719
720 pcmk__if_tracing({}, return false);
721 xpath = pcmk__element_xpath(xml);
722 if (name != NULL) {
723 pcmk__g_strcat(xpath, "[@", name, "]", NULL);
724 }
725
726 qb_log_from_external_source(__func__, __FILE__,
727 "Default ACL denies user '%s' %s access to "
728 "%s", LOG_TRACE, __LINE__, 0,
729 docpriv->user, acl_to_text(mode),
730 (const char *) xpath->str);
731 g_string_free(xpath, TRUE);
732 return false;
733 }
734
735 return true;
736 }
737
738
739
740
741
742
743
744
745 bool
746 pcmk_acl_required(const char *user)
747 {
748 if (pcmk__str_empty(user)) {
749 crm_trace("ACLs not required because no user set");
750 return false;
751
752 } else if (!strcmp(user, CRM_DAEMON_USER) || !strcmp(user, "root")) {
753 crm_trace("ACLs not required for privileged user %s", user);
754 return false;
755 }
756 crm_trace("ACLs required for %s", user);
757 return true;
758 }
759
760 char *
761 pcmk__uid2username(uid_t uid)
762 {
763 char *result = NULL;
764 struct passwd *pwent = getpwuid(uid);
765
766 if (pwent == NULL) {
767 crm_perror(LOG_INFO, "Cannot get user details for user ID %d", uid);
768 return NULL;
769 }
770 pcmk__str_update(&result, pwent->pw_name);
771 return result;
772 }
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792 const char *
793 pcmk__update_acl_user(xmlNode *request, const char *field,
794 const char *peer_user)
795 {
796 static const char *effective_user = NULL;
797 const char *requested_user = NULL;
798 const char *user = NULL;
799
800 if (effective_user == NULL) {
801 effective_user = pcmk__uid2username(geteuid());
802 if (effective_user == NULL) {
803 effective_user = strdup("#unprivileged");
804 CRM_CHECK(effective_user != NULL, return NULL);
805 crm_err("Unable to determine effective user, assuming unprivileged for ACLs");
806 }
807 }
808
809 requested_user = crm_element_value(request, XML_ACL_TAG_USER);
810 if (requested_user == NULL) {
811
812
813
814
815
816 requested_user = crm_element_value(request, field);
817 }
818
819 if (!pcmk__is_privileged(effective_user)) {
820
821
822
823 user = effective_user;
824
825 } else if (peer_user == NULL && requested_user == NULL) {
826
827
828
829 user = effective_user;
830
831 } else if (peer_user == NULL) {
832
833 user = requested_user;
834
835 } else if (!pcmk__is_privileged(peer_user)) {
836
837
838
839 user = peer_user;
840
841 } else if (requested_user == NULL) {
842
843 user = peer_user;
844
845 } else {
846
847 user = requested_user;
848 }
849
850
851 if (user != crm_element_value(request, XML_ACL_TAG_USER)) {
852 crm_xml_add(request, XML_ACL_TAG_USER, user);
853 }
854
855 if (field != NULL && user != crm_element_value(request, field)) {
856 crm_xml_add(request, field, user);
857 }
858
859 return requested_user;
860 }