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