pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
acl.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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>
25#include "crmcommon_private.h"
26
27#define MAX_XPATH_LEN 4096
28
29typedef struct xml_acl_s {
30 enum xml_private_flags mode;
31 char *xpath;
33
34static void
35free_acl(void *data)
36{
37 if (data) {
38 xml_acl_t *acl = data;
39
40 free(acl->xpath);
41 free(acl);
42 }
43}
44
45void
46pcmk__free_acls(GList *acls)
47{
48 g_list_free_full(acls, free_acl);
49}
50
51static GList *
52create_acl(xmlNode *xml, GList *acls, enum xml_private_flags mode)
53{
54 xml_acl_t *acl = NULL;
55
56 const char *tag = crm_element_value(xml, XML_ACL_ATTR_TAG);
57 const char *ref = crm_element_value(xml, XML_ACL_ATTR_REF);
58 const char *xpath = crm_element_value(xml, XML_ACL_ATTR_XPATH);
59 const char *attr = crm_element_value(xml, XML_ACL_ATTR_ATTRIBUTE);
60
61 if (tag == NULL) {
62 // @COMPAT rolling upgrades <=1.1.11
64 }
65 if (ref == NULL) {
66 // @COMPAT rolling upgrades <=1.1.11
68 }
69
70 if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
71 // Schema should prevent this, but to be safe ...
72 crm_trace("Ignoring ACL <%s> element without selection criteria",
73 crm_element_name(xml));
74 return NULL;
75 }
76
77 acl = calloc(1, sizeof (xml_acl_t));
78 CRM_ASSERT(acl != NULL);
79
80 acl->mode = mode;
81 if (xpath) {
82 acl->xpath = strdup(xpath);
83 CRM_ASSERT(acl->xpath != NULL);
84 crm_trace("Unpacked ACL <%s> element using xpath: %s",
85 crm_element_name(xml), acl->xpath);
86
87 } else {
88 int offset = 0;
89 char buffer[MAX_XPATH_LEN];
90
91 if (tag) {
92 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
93 "//%s", tag);
94 } else {
95 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
96 "//*");
97 }
98
99 if (ref || attr) {
100 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
101 "[");
102 }
103
104 if (ref) {
105 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
106 "@id='%s'", ref);
107 }
108
109 // NOTE: schema currently does not allow this
110 if (ref && attr) {
111 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
112 " and ");
113 }
114
115 if (attr) {
116 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
117 "@%s", attr);
118 }
119
120 if (ref || attr) {
121 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
122 "]");
123 }
124
125 CRM_LOG_ASSERT(offset > 0);
126 acl->xpath = strdup(buffer);
127 CRM_ASSERT(acl->xpath != NULL);
128
129 crm_trace("Unpacked ACL <%s> element as xpath: %s",
130 crm_element_name(xml), acl->xpath);
131 }
132
133 return g_list_append(acls, acl);
134}
135
146static GList *
147parse_acl_entry(xmlNode *acl_top, xmlNode *acl_entry, GList *acls)
148{
149 xmlNode *child = NULL;
150
151 for (child = pcmk__xe_first_child(acl_entry); child;
152 child = pcmk__xe_next(child)) {
153 const char *tag = crm_element_name(child);
154 const char *kind = crm_element_value(child, XML_ACL_ATTR_KIND);
155
156 if (strcmp(XML_ACL_TAG_PERMISSION, tag) == 0){
157 CRM_ASSERT(kind != NULL);
158 crm_trace("Unpacking ACL <%s> element of kind '%s'", tag, kind);
159 tag = kind;
160 } else {
161 crm_trace("Unpacking ACL <%s> element", tag);
162 }
163
164 if (strcmp(XML_ACL_TAG_ROLE_REF, tag) == 0
165 || strcmp(XML_ACL_TAG_ROLE_REFv1, tag) == 0) {
166 const char *ref_role = crm_element_value(child, XML_ATTR_ID);
167
168 if (ref_role) {
169 xmlNode *role = NULL;
170
171 for (role = pcmk__xe_first_child(acl_top); role;
172 role = pcmk__xe_next(role)) {
173 if (!strcmp(XML_ACL_TAG_ROLE, (const char *) role->name)) {
174 const char *role_id = crm_element_value(role,
176
177 if (role_id && strcmp(ref_role, role_id) == 0) {
178 crm_trace("Unpacking referenced role '%s' in ACL <%s> element",
179 role_id, crm_element_name(acl_entry));
180 acls = parse_acl_entry(acl_top, role, acls);
181 break;
182 }
183 }
184 }
185 }
186
187 } else if (strcmp(XML_ACL_TAG_READ, tag) == 0) {
188 acls = create_acl(child, acls, pcmk__xf_acl_read);
189
190 } else if (strcmp(XML_ACL_TAG_WRITE, tag) == 0) {
191 acls = create_acl(child, acls, pcmk__xf_acl_write);
192
193 } else if (strcmp(XML_ACL_TAG_DENY, tag) == 0) {
194 acls = create_acl(child, acls, pcmk__xf_acl_deny);
195
196 } else {
197 crm_warn("Ignoring unknown ACL %s '%s'",
198 (kind? "kind" : "element"), tag);
199 }
200 }
201
202 return acls;
203}
204
205/*
206 <acls>
207 <acl_target id="l33t-haxor"><role id="auto-l33t-haxor"/></acl_target>
208 <acl_role id="auto-l33t-haxor">
209 <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
210 </acl_role>
211 <acl_target id="niceguy">
212 <role id="observer"/>
213 </acl_target>
214 <acl_role id="observer">
215 <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
216 <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name='stonith-enabled']"/>
217 <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name='target-role']"/>
218 </acl_role>
219 <acl_target id="badidea"><role id="auto-badidea"/></acl_target>
220 <acl_role id="auto-badidea">
221 <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
222 <acl_permission id="badidea-resources-2" kind="deny" reference="dummy-meta_attributes"/>
223 </acl_role>
224 </acls>
225*/
226
227static const char *
228acl_to_text(enum xml_private_flags flags)
229{
231 return "deny";
232
233 } else if (pcmk_any_flags_set(flags, pcmk__xf_acl_write|pcmk__xf_acl_create)) {
234 return "read/write";
235
236 } else if (pcmk_is_set(flags, pcmk__xf_acl_read)) {
237 return "read";
238 }
239 return "none";
240}
241
242void
243pcmk__apply_acl(xmlNode *xml)
244{
245 GList *aIter = NULL;
246 xml_private_t *p = xml->doc->_private;
247 xmlXPathObjectPtr xpathObj = NULL;
248
249 if (!xml_acl_enabled(xml)) {
250 crm_trace("Skipping ACLs for user '%s' because not enabled for this XML",
251 p->user);
252 return;
253 }
254
255 for (aIter = p->acls; aIter != NULL; aIter = aIter->next) {
256 int max = 0, lpc = 0;
257 xml_acl_t *acl = aIter->data;
258
259 xpathObj = xpath_search(xml, acl->xpath);
260 max = numXpathResults(xpathObj);
261
262 for (lpc = 0; lpc < max; lpc++) {
263 xmlNode *match = getXpathResult(xpathObj, lpc);
264 char *path = xml_get_path(match);
265
266 p = match->_private;
267 crm_trace("Applying %s ACL to %s matched by %s",
268 acl_to_text(acl->mode), path, acl->xpath);
269 pcmk__set_xml_flags(p, acl->mode);
270 free(path);
271 }
272 crm_trace("Applied %s ACL %s (%d match%s)",
273 acl_to_text(acl->mode), acl->xpath, max,
274 ((max == 1)? "" : "es"));
275 freeXpathObject(xpathObj);
276 }
277}
278
287void
288pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
289{
290 xml_private_t *p = NULL;
291
292 if ((target == NULL) || (target->doc == NULL)
293 || (target->doc->_private == NULL)) {
294 return;
295 }
296
297 p = 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 (p->acls == NULL) {
303 xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS,
304 source, LOG_NEVER);
305
306 pcmk__str_update(&p->user, user);
307
308 if (acls) {
309 xmlNode *child = NULL;
310
311 for (child = pcmk__xe_first_child(acls); child;
312 child = pcmk__xe_next(child)) {
313 const char *tag = crm_element_name(child);
314
315 if (!strcmp(tag, XML_ACL_TAG_USER)
316 || !strcmp(tag, XML_ACL_TAG_USERv1)) {
317 const char *id = crm_element_value(child, XML_ATTR_ID);
318
319 if (id && strcmp(id, user) == 0) {
320 crm_debug("Unpacking ACLs for user '%s'", id);
321 p->acls = parse_acl_entry(acls, child, p->acls);
322 }
323 }
324 }
325 }
326 }
327}
328
337void
338pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
339{
340 pcmk__unpack_acl(acl_source, target, user);
343}
344
345static inline bool
346test_acl_mode(enum xml_private_flags allowed, enum xml_private_flags requested)
347{
348 if (pcmk_is_set(allowed, pcmk__xf_acl_deny)) {
349 return false;
350
351 } else if (pcmk_all_flags_set(allowed, requested)) {
352 return true;
353
354 } else if (pcmk_is_set(requested, pcmk__xf_acl_read)
355 && pcmk_is_set(allowed, pcmk__xf_acl_write)) {
356 return true;
357
358 } else if (pcmk_is_set(requested, pcmk__xf_acl_create)
359 && pcmk_any_flags_set(allowed, pcmk__xf_acl_write|pcmk__xf_created)) {
360 return true;
361 }
362 return false;
363}
364
365static bool
366purge_xml_attributes(xmlNode *xml)
367{
368 xmlNode *child = NULL;
369 xmlAttr *xIter = NULL;
370 bool readable_children = false;
371 xml_private_t *p = xml->_private;
372
373 if (test_acl_mode(p->flags, pcmk__xf_acl_read)) {
374 crm_trace("%s[@id=%s] is readable", crm_element_name(xml), ID(xml));
375 return true;
376 }
377
378 xIter = xml->properties;
379 while (xIter != NULL) {
380 xmlAttr *tmp = xIter;
381 const char *prop_name = (const char *)xIter->name;
382
383 xIter = xIter->next;
384 if (strcmp(prop_name, XML_ATTR_ID) == 0) {
385 continue;
386 }
387
388 xmlUnsetProp(xml, tmp->name);
389 }
390
391 child = pcmk__xml_first_child(xml);
392 while ( child != NULL ) {
393 xmlNode *tmp = child;
394
395 child = pcmk__xml_next(child);
396 readable_children |= purge_xml_attributes(tmp);
397 }
398
399 if (!readable_children) {
400 free_xml(xml); /* Nothing readable under here, purge completely */
401 }
402 return readable_children;
403}
404
416bool
417xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
418 xmlNode **result)
419{
420 GList *aIter = NULL;
421 xmlNode *target = NULL;
422 xml_private_t *doc = NULL;
423
424 *result = NULL;
425 if ((xml == NULL) || !pcmk_acl_required(user)) {
426 crm_trace("Not filtering XML because ACLs not required for user '%s'",
427 user);
428 return false;
429 }
430
431 crm_trace("Filtering XML copy using user '%s' ACLs", user);
432 target = copy_xml(xml);
433 if (target == NULL) {
434 return true;
435 }
436
437 pcmk__enable_acl(acl_source, target, user);
438
439 doc = target->doc->_private;
440 for(aIter = doc->acls; aIter != NULL && target; aIter = aIter->next) {
441 int max = 0;
442 xml_acl_t *acl = aIter->data;
443
444 if (acl->mode != pcmk__xf_acl_deny) {
445 /* Nothing to do */
446
447 } else if (acl->xpath) {
448 int lpc = 0;
449 xmlXPathObjectPtr xpathObj = xpath_search(target, acl->xpath);
450
451 max = numXpathResults(xpathObj);
452 for(lpc = 0; lpc < max; lpc++) {
453 xmlNode *match = getXpathResult(xpathObj, lpc);
454
455 if (!purge_xml_attributes(match) && (match == target)) {
456 crm_trace("ACLs deny user '%s' access to entire XML document",
457 user);
458 freeXpathObject(xpathObj);
459 return true;
460 }
461 }
462 crm_trace("ACLs deny user '%s' access to %s (%d %s)",
463 user, acl->xpath, max,
464 pcmk__plural_alt(max, "match", "matches"));
465 freeXpathObject(xpathObj);
466 }
467 }
468
469 if (!purge_xml_attributes(target)) {
470 crm_trace("ACLs deny user '%s' access to entire XML document", user);
471 return true;
472 }
473
474 if (doc->acls) {
475 g_list_free_full(doc->acls, free_acl);
476 doc->acls = NULL;
477
478 } else {
479 crm_trace("User '%s' without ACLs denied access to entire XML document",
480 user);
482 target = NULL;
483 }
484
485 if (target) {
486 *result = target;
487 }
488
489 return true;
490}
491
504static bool
505implicitly_allowed(xmlNode *xml)
506{
507 char *path = NULL;
508
509 for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
510 if (strcmp((const char *) prop->name, XML_ATTR_ID) != 0) {
511 return false;
512 }
513 }
514
515 path = xml_get_path(xml);
516 if (strstr(path, "/" XML_CIB_TAG_ACLS "/") != NULL) {
517 free(path);
518 return false;
519 }
520 free(path);
521
522 return true;
523}
524
525#define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
526
540void
541pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
542{
543 xml_private_t *p = xml->_private;
544
546 if (implicitly_allowed(xml)) {
547 crm_trace("Creation of <%s> scaffolding with id=\"%s\""
548 " is implicitly allowed",
549 crm_element_name(xml), display_id(xml));
550
551 } else if (pcmk__check_acl(xml, NULL, pcmk__xf_acl_write)) {
552 crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
553 crm_element_name(xml), display_id(xml));
554
555 } else if (check_top) {
556 crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
557 crm_element_name(xml), display_id(xml));
559 return;
560
561 } else {
562 crm_notice("ACLs would disallow creation of %s<%s> with id=\"%s\" ",
563 ((xml == xmlDocGetRootElement(xml->doc))? "root element " : ""),
564 crm_element_name(xml), display_id(xml));
565 }
566 }
567
568 for (xmlNode *cIter = pcmk__xml_first_child(xml); cIter != NULL; ) {
569 xmlNode *child = cIter;
570 cIter = pcmk__xml_next(cIter); /* In case it is free'd */
571 pcmk__apply_creation_acl(child, true);
572 }
573}
574
575bool
576xml_acl_denied(xmlNode *xml)
577{
578 if (xml && xml->doc && xml->doc->_private){
579 xml_private_t *p = xml->doc->_private;
580
582 }
583 return false;
584}
585
586void
587xml_acl_disable(xmlNode *xml)
588{
589 if (xml_acl_enabled(xml)) {
590 xml_private_t *p = xml->doc->_private;
591
592 /* Catch anything that was created but shouldn't have been */
593 pcmk__apply_acl(xml);
594 pcmk__apply_creation_acl(xml, false);
596 }
597}
598
599bool
600xml_acl_enabled(xmlNode *xml)
601{
602 if (xml && xml->doc && xml->doc->_private){
603 xml_private_t *p = xml->doc->_private;
604
606 }
607 return false;
608}
609
610bool
611pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
612{
613 CRM_ASSERT(xml);
614 CRM_ASSERT(xml->doc);
615 CRM_ASSERT(xml->doc->_private);
616
617 if (pcmk__tracking_xml_changes(xml, false) && xml_acl_enabled(xml)) {
618 int offset = 0;
619 xmlNode *parent = xml;
620 char buffer[MAX_XPATH_LEN];
621 xml_private_t *docp = xml->doc->_private;
622
623 offset = pcmk__element_xpath(NULL, xml, buffer, offset,
624 sizeof(buffer));
625 if (name) {
626 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
627 "[@%s]", name);
628 }
629 CRM_LOG_ASSERT(offset > 0);
630
631 if (docp->acls == NULL) {
632 crm_trace("User '%s' without ACLs denied %s access to %s",
633 docp->user, acl_to_text(mode), buffer);
635 return false;
636 }
637
638 /* Walk the tree upwards looking for xml_acl_* flags
639 * - Creating an attribute requires write permissions for the node
640 * - Creating a child requires write permissions for the parent
641 */
642
643 if (name) {
644 xmlAttr *attr = xmlHasProp(xml, (pcmkXmlStr) name);
645
646 if (attr && mode == pcmk__xf_acl_create) {
647 mode = pcmk__xf_acl_write;
648 }
649 }
650
651 while (parent && parent->_private) {
652 xml_private_t *p = parent->_private;
653 if (test_acl_mode(p->flags, mode)) {
654 return true;
655
656 } else if (pcmk_is_set(p->flags, pcmk__xf_acl_deny)) {
657 crm_trace("%sACL denies user '%s' %s access to %s",
658 (parent != xml) ? "Parent " : "", docp->user,
659 acl_to_text(mode), buffer);
661 return false;
662 }
663 parent = parent->parent;
664 }
665
666 crm_trace("Default ACL denies user '%s' %s access to %s",
667 docp->user, acl_to_text(mode), buffer);
669 return false;
670 }
671
672 return true;
673}
674
682bool
683pcmk_acl_required(const char *user)
684{
685 if (pcmk__str_empty(user)) {
686 crm_trace("ACLs not required because no user set");
687 return false;
688
689 } else if (!strcmp(user, CRM_DAEMON_USER) || !strcmp(user, "root")) {
690 crm_trace("ACLs not required for privileged user %s", user);
691 return false;
692 }
693 crm_trace("ACLs required for %s", user);
694 return true;
695}
696
697char *
699{
700 struct passwd *pwent = getpwuid(uid);
701
702 if (pwent == NULL) {
703 crm_perror(LOG_INFO, "Cannot get user details for user ID %d", uid);
704 return NULL;
705 }
706 return strdup(pwent->pw_name);
707}
708
727const char *
728pcmk__update_acl_user(xmlNode *request, const char *field,
729 const char *peer_user)
730{
731 static const char *effective_user = NULL;
732 const char *requested_user = NULL;
733 const char *user = NULL;
734
735 if (effective_user == NULL) {
736 effective_user = pcmk__uid2username(geteuid());
737 if (effective_user == NULL) {
738 effective_user = strdup("#unprivileged");
739 CRM_CHECK(effective_user != NULL, return NULL);
740 crm_err("Unable to determine effective user, assuming unprivileged for ACLs");
741 }
742 }
743
744 requested_user = crm_element_value(request, XML_ACL_TAG_USER);
745 if (requested_user == NULL) {
746 /* @COMPAT rolling upgrades <=1.1.11
747 *
748 * field is checked for backward compatibility with older versions that
749 * did not use XML_ACL_TAG_USER.
750 */
751 requested_user = crm_element_value(request, field);
752 }
753
754 if (!pcmk__is_privileged(effective_user)) {
755 /* We're not running as a privileged user, set or overwrite any existing
756 * value for $XML_ACL_TAG_USER
757 */
758 user = effective_user;
759
760 } else if (peer_user == NULL && requested_user == NULL) {
761 /* No user known or requested, use 'effective_user' and make sure one is
762 * set for the request
763 */
764 user = effective_user;
765
766 } else if (peer_user == NULL) {
767 /* No user known, trusting 'requested_user' */
768 user = requested_user;
769
770 } else if (!pcmk__is_privileged(peer_user)) {
771 /* The peer is not a privileged user, set or overwrite any existing
772 * value for $XML_ACL_TAG_USER
773 */
774 user = peer_user;
775
776 } else if (requested_user == NULL) {
777 /* Even if we're privileged, make sure there is always a value set */
778 user = peer_user;
779
780 } else {
781 /* Legal delegation to 'requested_user' */
782 user = requested_user;
783 }
784
785 // This requires pointer comparison, not string comparison
786 if (user != crm_element_value(request, XML_ACL_TAG_USER)) {
787 crm_xml_add(request, XML_ACL_TAG_USER, user);
788 }
789
790 if (field != NULL && user != crm_element_value(request, field)) {
791 crm_xml_add(request, field, user);
792 }
793
794 return requested_user;
795}
#define display_id(xml)
Definition: acl.c:525
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
Definition: acl.c:611
void pcmk__free_acls(GList *acls)
Definition: acl.c:46
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition: acl.c:683
#define MAX_XPATH_LEN
Definition: acl.c:27
char * pcmk__uid2username(uid_t uid)
Definition: acl.c:698
bool xml_acl_denied(xmlNode *xml)
Definition: acl.c:576
struct xml_acl_s xml_acl_t
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:587
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
Definition: acl.c:288
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition: acl.c:728
void pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
Definition: acl.c:338
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
Copy ACL-allowed portions of specified XML.
Definition: acl.c:417
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
Definition: acl.c:541
bool xml_acl_enabled(xmlNode *xml)
Definition: acl.c:600
void pcmk__apply_acl(xmlNode *xml)
Definition: acl.c:243
const char * parent
Definition: cib.c:25
const char * path
Definition: cib.c:26
const char * name
Definition: cib.c:24
uint64_t flags
Definition: remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
#define CRM_DAEMON_USER
Definition: config.h:30
char data[0]
Definition: cpg.c:10
A dumping ground.
G_GNUC_INTERNAL int pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer, int offset, size_t buffer_size)
Definition: xpath.c:269
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
G_GNUC_INTERNAL bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
Definition: xml.c:51
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
#define crm_warn(fmt, args...)
Definition: logging.h:359
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
#define crm_notice(fmt, args...)
Definition: logging.h:360
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:309
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
#define crm_debug(fmt, args...)
Definition: logging.h:363
#define crm_err(fmt, args...)
Definition: logging.h:358
#define LOG_NEVER
Definition: logging.h:47
#define crm_trace(fmt, args...)
Definition: logging.h:364
#define XML_ACL_TAG_ROLE
Definition: msg_xml.h:417
#define XML_ACL_TAG_PERMISSION
Definition: msg_xml.h:418
#define XML_ACL_TAG_USERv1
Definition: msg_xml.h:415
#define XML_ACL_ATTR_TAG
Definition: msg_xml.h:427
#define ID(x)
Definition: msg_xml.h:460
#define XML_ACL_ATTR_ATTRIBUTE
Definition: msg_xml.h:430
#define XML_ACL_TAG_USER
Definition: msg_xml.h:414
#define XML_ACL_TAG_WRITE
Definition: msg_xml.h:423
#define XML_ACL_TAG_ROLE_REF
Definition: msg_xml.h:419
#define XML_CIB_TAG_ACLS
Definition: msg_xml.h:193
#define XML_ACL_TAG_DENY
Definition: msg_xml.h:424
#define XML_ACL_TAG_READ
Definition: msg_xml.h:422
#define XML_ATTR_ID
Definition: msg_xml.h:135
#define XML_ACL_ATTR_XPATH
Definition: msg_xml.h:429
#define XML_ACL_ATTR_KIND
Definition: msg_xml.h:421
#define XML_ACL_ATTR_TAGv1
Definition: msg_xml.h:428
#define XML_ACL_TAG_ROLE_REFv1
Definition: msg_xml.h:420
#define XML_ACL_ATTR_REF
Definition: msg_xml.h:425
#define XML_ACL_ATTR_REFv1
Definition: msg_xml.h:426
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
pcmk__action_result_t result
Definition: pcmk_fence.c:34
const char * target
Definition: pcmk_fence.c:28
#define CRM_ASSERT(expr)
Definition: results.h:42
#define pcmk__plural_alt(i, s1, s2)
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1188
Wrappers for and extensions to libxml2.
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:139
char * xml_get_path(xmlNode *xml)
Definition: xpath.c:291
const xmlChar * pcmkXmlStr
Definition: xml.h:52
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
void free_xml(xmlNode *child)
Definition: xml.c:824
void pcmk_free_xml_subtree(xmlNode *xml)
Definition: xml.c:755
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:830
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
Definition: xml.c:117
xml_private_flags
Definition: xml_internal.h:315
@ pcmk__xf_acl_create
Definition: xml_internal.h:332
@ pcmk__xf_acl_enabled
Definition: xml_internal.h:327
@ pcmk__xf_created
Definition: xml_internal.h:319
@ pcmk__xf_acl_denied
Definition: xml_internal.h:333
@ pcmk__xf_acl_deny
Definition: xml_internal.h:330
@ pcmk__xf_acl_write
Definition: xml_internal.h:329
@ pcmk__xf_acl_read
Definition: xml_internal.h:328