pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
acl.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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/common/xml.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) && (ref == NULL) && (xpath == NULL)) {
59  // Schema should prevent this, but to be safe ...
60  crm_trace("Ignoring ACL <%s> element without selection criteria",
61  xml->name);
62  return NULL;
63  }
64 
65  acl = pcmk__assert_alloc(1, sizeof (xml_acl_t));
66 
67  acl->mode = mode;
68  if (xpath) {
69  acl->xpath = g_strdup(xpath);
70  crm_trace("Unpacked ACL <%s> element using xpath: %s",
71  xml->name, acl->xpath);
72 
73  } else {
74  GString *buf = g_string_sized_new(128);
75 
76  if ((ref != NULL) && (attr != NULL)) {
77  // NOTE: schema currently does not allow this
78  pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@" PCMK_XA_ID "='",
79  ref, "' and @", attr, "]", NULL);
80 
81  } else if (ref != NULL) {
82  pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@" PCMK_XA_ID "='",
83  ref, "']", NULL);
84 
85  } else if (attr != NULL) {
86  pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), "[@", attr, "]", NULL);
87 
88  } else {
89  pcmk__g_strcat(buf, "//", pcmk__s(tag, "*"), NULL);
90  }
91 
92  acl->xpath = buf->str;
93 
94  g_string_free(buf, FALSE);
95  crm_trace("Unpacked ACL <%s> element as xpath: %s",
96  xml->name, acl->xpath);
97  }
98 
99  return g_list_append(acls, acl);
100 }
101 
114 static GList *
115 parse_acl_entry(const xmlNode *acl_top, const xmlNode *acl_entry, GList *acls)
116 {
117  for (const xmlNode *child = pcmk__xe_first_child(acl_entry, NULL, NULL,
118  NULL);
119  child != NULL; child = pcmk__xe_next(child, NULL)) {
120 
121  if (pcmk__xe_is(child, PCMK_XE_ACL_PERMISSION)) {
122  const char *kind = crm_element_value(child, PCMK_XA_KIND);
123 
124  pcmk__assert(kind != NULL);
125  crm_trace("Unpacking <" PCMK_XE_ACL_PERMISSION "> element of "
126  "kind '%s'",
127  kind);
128 
129  if (pcmk__str_eq(kind, PCMK_VALUE_READ, pcmk__str_none)) {
130  acls = create_acl(child, acls, pcmk__xf_acl_read);
131 
132  } else if (pcmk__str_eq(kind, PCMK_VALUE_WRITE, pcmk__str_none)) {
133  acls = create_acl(child, acls, pcmk__xf_acl_write);
134 
135  } else if (pcmk__str_eq(kind, PCMK_VALUE_DENY, pcmk__str_none)) {
136  acls = create_acl(child, acls, pcmk__xf_acl_deny);
137 
138  } else {
139  crm_warn("Ignoring unknown ACL kind '%s'", kind);
140  }
141 
142  } else if (pcmk__xe_is(child, PCMK_XE_ROLE)) {
143  const char *ref_role = crm_element_value(child, PCMK_XA_ID);
144 
145  crm_trace("Unpacking <" PCMK_XE_ROLE "> element");
146 
147  if (ref_role == NULL) {
148  continue;
149  }
150 
151  for (xmlNode *role = pcmk__xe_first_child(acl_top, NULL, NULL,
152  NULL);
153  role != NULL; role = pcmk__xe_next(role, NULL)) {
154 
155  const char *role_id = NULL;
156 
157  if (!pcmk__xe_is(role, PCMK_XE_ACL_ROLE)) {
158  continue;
159  }
160 
161  role_id = crm_element_value(role, PCMK_XA_ID);
162 
163  if (pcmk__str_eq(ref_role, role_id, pcmk__str_none)) {
164  crm_trace("Unpacking referenced role '%s' in <%s> element",
165  role_id, acl_entry->name);
166  acls = parse_acl_entry(acl_top, role, acls);
167  break;
168  }
169  }
170  }
171  }
172 
173  return acls;
174 }
175 
176 /*
177  <acls>
178  <acl_target id="l33t-haxor"><role id="auto-l33t-haxor"/></acl_target>
179  <acl_role id="auto-l33t-haxor">
180  <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
181  </acl_role>
182  <acl_target id="niceguy">
183  <role id="observer"/>
184  </acl_target>
185  <acl_role id="observer">
186  <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
187  <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name='stonith-enabled']"/>
188  <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name='target-role']"/>
189  </acl_role>
190  <acl_target id="badidea"><role id="auto-badidea"/></acl_target>
191  <acl_role id="auto-badidea">
192  <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
193  <acl_permission id="badidea-resources-2" kind="deny" reference="dummy-meta_attributes"/>
194  </acl_role>
195  </acls>
196 */
197 
198 static const char *
199 acl_to_text(enum xml_private_flags flags)
200 {
202  return "deny";
203 
204  } else if (pcmk_any_flags_set(flags, pcmk__xf_acl_write|pcmk__xf_acl_create)) {
205  return "read/write";
206 
207  } else if (pcmk_is_set(flags, pcmk__xf_acl_read)) {
208  return "read";
209  }
210  return "none";
211 }
212 
213 void
214 pcmk__apply_acl(xmlNode *xml)
215 {
216  GList *aIter = NULL;
217  xml_doc_private_t *docpriv = xml->doc->_private;
218  xml_node_private_t *nodepriv;
219  xmlXPathObjectPtr xpathObj = NULL;
220 
221  if (!xml_acl_enabled(xml)) {
222  crm_trace("Skipping ACLs for user '%s' because not enabled for this XML",
223  docpriv->user);
224  return;
225  }
226 
227  for (aIter = docpriv->acls; aIter != NULL; aIter = aIter->next) {
228  int max = 0, lpc = 0;
229  xml_acl_t *acl = aIter->data;
230 
231  xpathObj = xpath_search(xml, acl->xpath);
232  max = numXpathResults(xpathObj);
233 
234  for (lpc = 0; lpc < max; lpc++) {
235  xmlNode *match = getXpathResult(xpathObj, lpc);
236 
237  nodepriv = match->_private;
238  pcmk__set_xml_flags(nodepriv, acl->mode);
239 
240  // Build a GString only if tracing is enabled
242  {
243  GString *path = pcmk__element_xpath(match);
244  crm_trace("Applying %s ACL to %s matched by %s",
245  acl_to_text(acl->mode), path->str, acl->xpath);
246  g_string_free(path, TRUE);
247  },
248  {}
249  );
250  }
251  crm_trace("Applied %s ACL %s (%d match%s)",
252  acl_to_text(acl->mode), acl->xpath, max,
253  ((max == 1)? "" : "es"));
254  freeXpathObject(xpathObj);
255  }
256 }
257 
271 void
272 pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
273 {
274  xml_doc_private_t *docpriv = NULL;
275 
276  if ((target == NULL) || (target->doc == NULL)
277  || (target->doc->_private == NULL)) {
278  return;
279  }
280 
281  docpriv = target->doc->_private;
282  if (!pcmk_acl_required(user)) {
283  crm_trace("Not unpacking ACLs because not required for user '%s'",
284  user);
285 
286  } else if (docpriv->acls == NULL) {
287  xmlNode *acls = get_xpath_object("//" PCMK_XE_ACLS, source, LOG_NEVER);
288 
289  pcmk__str_update(&docpriv->user, user);
290 
291  if (acls) {
292  xmlNode *child = NULL;
293 
294  for (child = pcmk__xe_first_child(acls, NULL, NULL, NULL);
295  child != NULL; child = pcmk__xe_next(child, NULL)) {
296 
297  if (pcmk__xe_is(child, PCMK_XE_ACL_TARGET)) {
298  const char *id = crm_element_value(child, PCMK_XA_NAME);
299 
300  if (id == NULL) {
301  id = crm_element_value(child, PCMK_XA_ID);
302  }
303 
304  if (id && strcmp(id, user) == 0) {
305  crm_debug("Unpacking ACLs for user '%s'", id);
306  docpriv->acls = parse_acl_entry(acls, child, docpriv->acls);
307  }
308  } else if (pcmk__xe_is(child, PCMK_XE_ACL_GROUP)) {
309  const char *id = crm_element_value(child, PCMK_XA_NAME);
310 
311  if (id == NULL) {
312  id = crm_element_value(child, PCMK_XA_ID);
313  }
314 
315  if (id && pcmk__is_user_in_group(user,id)) {
316  crm_debug("Unpacking ACLs for group '%s'", id);
317  docpriv->acls = parse_acl_entry(acls, child, docpriv->acls);
318  }
319  }
320  }
321  }
322  }
323 }
324 
333 void
334 pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
335 {
336  pcmk__unpack_acl(acl_source, target, user);
339 }
340 
341 static inline bool
342 test_acl_mode(enum xml_private_flags allowed, enum xml_private_flags requested)
343 {
344  if (pcmk_is_set(allowed, pcmk__xf_acl_deny)) {
345  return false;
346 
347  } else if (pcmk_all_flags_set(allowed, requested)) {
348  return true;
349 
350  } else if (pcmk_is_set(requested, pcmk__xf_acl_read)
351  && pcmk_is_set(allowed, pcmk__xf_acl_write)) {
352  return true;
353 
354  } else if (pcmk_is_set(requested, pcmk__xf_acl_create)
355  && pcmk_any_flags_set(allowed, pcmk__xf_acl_write|pcmk__xf_created)) {
356  return true;
357  }
358  return false;
359 }
360 
372 static bool
373 purge_xml_attributes(xmlNode *xml)
374 {
375  xmlNode *child = NULL;
376  xmlAttr *xIter = NULL;
377  bool readable_children = false;
378  xml_node_private_t *nodepriv = xml->_private;
379 
380  if (test_acl_mode(nodepriv->flags, pcmk__xf_acl_read)) {
381  crm_trace("%s[@" PCMK_XA_ID "=%s] is readable",
382  xml->name, pcmk__xe_id(xml));
383  return true;
384  }
385 
386  xIter = xml->properties;
387  while (xIter != NULL) {
388  xmlAttr *tmp = xIter;
389  const char *prop_name = (const char *)xIter->name;
390 
391  xIter = xIter->next;
392  if (strcmp(prop_name, PCMK_XA_ID) == 0) {
393  continue;
394  }
395 
396  pcmk__xa_remove(tmp, true);
397  }
398 
399  child = pcmk__xml_first_child(xml);
400  while ( child != NULL ) {
401  xmlNode *tmp = child;
402 
403  child = pcmk__xml_next(child);
404  readable_children |= purge_xml_attributes(tmp);
405  }
406 
407  if (!readable_children) {
408  // Nothing readable under here, so purge completely
409  pcmk__xml_free(xml);
410  }
411  return readable_children;
412 }
413 
425 bool
426 xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
427  xmlNode **result)
428 {
429  GList *aIter = NULL;
430  xmlNode *target = NULL;
431  xml_doc_private_t *docpriv = NULL;
432 
433  *result = NULL;
434  if ((xml == NULL) || !pcmk_acl_required(user)) {
435  crm_trace("Not filtering XML because ACLs not required for user '%s'",
436  user);
437  return false;
438  }
439 
440  crm_trace("Filtering XML copy using user '%s' ACLs", user);
441  target = pcmk__xml_copy(NULL, xml);
442  if (target == NULL) {
443  return true;
444  }
445 
446  pcmk__enable_acl(acl_source, target, user);
447 
448  docpriv = target->doc->_private;
449  for(aIter = docpriv->acls; aIter != NULL && target; aIter = aIter->next) {
450  int max = 0;
451  xml_acl_t *acl = aIter->data;
452 
453  if (acl->mode != pcmk__xf_acl_deny) {
454  /* Nothing to do */
455 
456  } else if (acl->xpath) {
457  int lpc = 0;
458  xmlXPathObjectPtr xpathObj = xpath_search(target, acl->xpath);
459 
460  max = numXpathResults(xpathObj);
461  for(lpc = 0; lpc < max; lpc++) {
462  xmlNode *match = getXpathResult(xpathObj, lpc);
463 
464  if (!purge_xml_attributes(match) && (match == target)) {
465  crm_trace("ACLs deny user '%s' access to entire XML document",
466  user);
467  freeXpathObject(xpathObj);
468  return true;
469  }
470  }
471  crm_trace("ACLs deny user '%s' access to %s (%d %s)",
472  user, acl->xpath, max,
473  pcmk__plural_alt(max, "match", "matches"));
474  freeXpathObject(xpathObj);
475  }
476  }
477 
478  if (!purge_xml_attributes(target)) {
479  crm_trace("ACLs deny user '%s' access to entire XML document", user);
480  return true;
481  }
482 
483  if (docpriv->acls) {
484  g_list_free_full(docpriv->acls, free_acl);
485  docpriv->acls = NULL;
486 
487  } else {
488  crm_trace("User '%s' without ACLs denied access to entire XML document",
489  user);
491  target = NULL;
492  }
493 
494  if (target) {
495  *result = target;
496  }
497 
498  return true;
499 }
500 
513 static bool
514 implicitly_allowed(const xmlNode *xml)
515 {
516  GString *path = NULL;
517 
518  for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
519  if (strcmp((const char *) prop->name, PCMK_XA_ID) != 0) {
520  return false;
521  }
522  }
523 
524  path = pcmk__element_xpath(xml);
525  pcmk__assert(path != NULL);
526 
527  if (strstr((const char *) path->str, "/" PCMK_XE_ACLS "/") != NULL) {
528  g_string_free(path, TRUE);
529  return false;
530  }
531 
532  g_string_free(path, TRUE);
533  return true;
534 }
535 
536 #define display_id(xml) pcmk__s(pcmk__xe_id(xml), "<unset>")
537 
553 void
554 pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
555 {
556  xml_node_private_t *nodepriv = xml->_private;
557 
558  if (pcmk_is_set(nodepriv->flags, pcmk__xf_created)) {
559  if (implicitly_allowed(xml)) {
560  crm_trace("Creation of <%s> scaffolding with " PCMK_XA_ID "=\"%s\""
561  " is implicitly allowed",
562  xml->name, display_id(xml));
563 
564  } else if (pcmk__check_acl(xml, NULL, pcmk__xf_acl_write)) {
565  crm_trace("ACLs allow creation of <%s> with " PCMK_XA_ID "=\"%s\"",
566  xml->name, display_id(xml));
567 
568  } else if (check_top) {
569  /* is_root=true should be impossible with check_top=true, but check
570  * for sanity
571  */
572  bool is_root = (xmlDocGetRootElement(xml->doc) == xml);
573  xml_doc_private_t *docpriv = xml->doc->_private;
574 
575  crm_trace("ACLs disallow creation of %s<%s> with "
576  PCMK_XA_ID "=\"%s\"",
577  (is_root? "root element " : ""), xml->name,
578  display_id(xml));
579 
580  // pcmk__xml_free() checks ACLs if enabled, which would fail
582  pcmk__xml_free(xml);
583 
584  if (!is_root) {
585  // If root, the document was freed. Otherwise re-enable ACLs.
587  }
588  return;
589 
590  } else {
591  crm_notice("ACLs would disallow creation of %s<%s> with "
592  PCMK_XA_ID "=\"%s\"",
593  ((xml == xmlDocGetRootElement(xml->doc))? "root element " : ""),
594  xml->name, display_id(xml));
595  }
596  }
597 
598  for (xmlNode *cIter = pcmk__xml_first_child(xml); cIter != NULL; ) {
599  xmlNode *child = cIter;
600  cIter = pcmk__xml_next(cIter); /* In case it is free'd */
601  pcmk__apply_creation_acl(child, true);
602  }
603 }
604 
612 bool
613 xml_acl_denied(const xmlNode *xml)
614 {
615  if (xml && xml->doc && xml->doc->_private){
616  xml_doc_private_t *docpriv = xml->doc->_private;
617 
618  return pcmk_is_set(docpriv->flags, pcmk__xf_acl_denied);
619  }
620  return false;
621 }
622 
623 void
624 xml_acl_disable(xmlNode *xml)
625 {
626  if (xml_acl_enabled(xml)) {
627  xml_doc_private_t *docpriv = xml->doc->_private;
628 
629  /* Catch anything that was created but shouldn't have been */
630  pcmk__apply_acl(xml);
631  pcmk__apply_creation_acl(xml, false);
633  }
634 }
635 
643 bool
644 xml_acl_enabled(const xmlNode *xml)
645 {
646  if (xml && xml->doc && xml->doc->_private){
647  xml_doc_private_t *docpriv = xml->doc->_private;
648 
649  return pcmk_is_set(docpriv->flags, pcmk__xf_acl_enabled);
650  }
651  return false;
652 }
653 
654 bool
655 pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
656 {
657  pcmk__assert((xml != NULL) && (xml->doc != NULL)
658  && (xml->doc->_private != NULL));
659 
660  if (pcmk__tracking_xml_changes(xml, false) && xml_acl_enabled(xml)) {
661  xmlNode *parent = xml;
662  xml_doc_private_t *docpriv = xml->doc->_private;
663  GString *xpath = NULL;
664 
665  if (docpriv->acls == NULL) {
667 
668  pcmk__if_tracing({}, return false);
669  xpath = pcmk__element_xpath(xml);
670  if (name != NULL) {
671  pcmk__g_strcat(xpath, "[@", name, "]", NULL);
672  }
673 
674  qb_log_from_external_source(__func__, __FILE__,
675  "User '%s' without ACLs denied %s "
676  "access to %s", LOG_TRACE, __LINE__, 0,
677  docpriv->user, acl_to_text(mode),
678  (const char *) xpath->str);
679  g_string_free(xpath, TRUE);
680  return false;
681  }
682 
683  /* Walk the tree upwards looking for xml_acl_* flags
684  * - Creating an attribute requires write permissions for the node
685  * - Creating a child requires write permissions for the parent
686  */
687 
688  if (name) {
689  xmlAttr *attr = xmlHasProp(xml, (pcmkXmlStr) name);
690 
691  if (attr && mode == pcmk__xf_acl_create) {
692  mode = pcmk__xf_acl_write;
693  }
694  }
695 
696  while (parent && parent->_private) {
697  xml_node_private_t *nodepriv = parent->_private;
698  if (test_acl_mode(nodepriv->flags, mode)) {
699  return true;
700 
701  } else if (pcmk_is_set(nodepriv->flags, pcmk__xf_acl_deny)) {
703 
704  pcmk__if_tracing({}, return false);
705  xpath = pcmk__element_xpath(xml);
706  if (name != NULL) {
707  pcmk__g_strcat(xpath, "[@", name, "]", NULL);
708  }
709 
710  qb_log_from_external_source(__func__, __FILE__,
711  "%sACL denies user '%s' %s access "
712  "to %s", LOG_TRACE, __LINE__, 0,
713  (parent != xml)? "Parent ": "",
714  docpriv->user, acl_to_text(mode),
715  (const char *) xpath->str);
716  g_string_free(xpath, TRUE);
717  return false;
718  }
719  parent = parent->parent;
720  }
721 
723 
724  pcmk__if_tracing({}, return false);
725  xpath = pcmk__element_xpath(xml);
726  if (name != NULL) {
727  pcmk__g_strcat(xpath, "[@", name, "]", NULL);
728  }
729 
730  qb_log_from_external_source(__func__, __FILE__,
731  "Default ACL denies user '%s' %s access to "
732  "%s", LOG_TRACE, __LINE__, 0,
733  docpriv->user, acl_to_text(mode),
734  (const char *) xpath->str);
735  g_string_free(xpath, TRUE);
736  return false;
737  }
738 
739  return true;
740 }
741 
749 bool
750 pcmk_acl_required(const char *user)
751 {
752  if (pcmk__str_empty(user)) {
753  crm_trace("ACLs not required because no user set");
754  return false;
755 
756  } else if (!strcmp(user, CRM_DAEMON_USER) || !strcmp(user, "root")) {
757  crm_trace("ACLs not required for privileged user %s", user);
758  return false;
759  }
760  crm_trace("ACLs required for %s", user);
761  return true;
762 }
763 
764 char *
766 {
767  struct passwd *pwent = getpwuid(uid);
768 
769  if (pwent == NULL) {
770  crm_perror(LOG_INFO, "Cannot get user details for user ID %d", uid);
771  return NULL;
772  }
773  return pcmk__str_copy(pwent->pw_name);
774 }
775 
794 const char *
795 pcmk__update_acl_user(xmlNode *request, const char *field,
796  const char *peer_user)
797 {
798  static const char *effective_user = NULL;
799  const char *requested_user = NULL;
800  const char *user = NULL;
801 
802  if (effective_user == NULL) {
803  effective_user = pcmk__uid2username(geteuid());
804  if (effective_user == NULL) {
805  effective_user = pcmk__str_copy("#unprivileged");
806  crm_err("Unable to determine effective user, assuming unprivileged for ACLs");
807  }
808  }
809 
810  requested_user = crm_element_value(request, PCMK__XA_ACL_TARGET);
811  if (requested_user == NULL) {
812  /* Currently, different XML attribute names are used for the ACL user in
813  * different contexts (PCMK__XA_ATTR_USER, PCMK__XA_CIB_USER, etc.).
814  * The caller may specify that name as the field argument.
815  *
816  * @TODO Standardize on PCMK__XA_ACL_TARGET and eventually drop the
817  * others once rolling upgrades from versions older than that are no
818  * longer supported.
819  */
820  requested_user = crm_element_value(request, field);
821  }
822 
823  if (!pcmk__is_privileged(effective_user)) {
824  /* We're not running as a privileged user, set or overwrite any existing
825  * value for PCMK__XA_ACL_TARGET
826  */
827  user = effective_user;
828 
829  } else if (peer_user == NULL && requested_user == NULL) {
830  /* No user known or requested, use 'effective_user' and make sure one is
831  * set for the request
832  */
833  user = effective_user;
834 
835  } else if (peer_user == NULL) {
836  /* No user known, trusting 'requested_user' */
837  user = requested_user;
838 
839  } else if (!pcmk__is_privileged(peer_user)) {
840  /* The peer is not a privileged user, set or overwrite any existing
841  * value for PCMK__XA_ACL_TARGET
842  */
843  user = peer_user;
844 
845  } else if (requested_user == NULL) {
846  /* Even if we're privileged, make sure there is always a value set */
847  user = peer_user;
848 
849  } else {
850  /* Legal delegation to 'requested_user' */
851  user = requested_user;
852  }
853 
854  // This requires pointer comparison, not string comparison
855  if (user != crm_element_value(request, PCMK__XA_ACL_TARGET)) {
856  crm_xml_add(request, PCMK__XA_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 }
#define LOG_TRACE
Definition: logging.h:38
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:624
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
A dumping ground.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
#define crm_notice(fmt, args...)
Definition: logging.h:365
#define PCMK_XA_NAME
Definition: xml_names.h:330
char data[0]
Definition: cpg.c:58
#define pcmk__if_tracing(if_action, else_action)
void pcmk__free_acls(GList *acls)
Definition: acl.c:43
const char * name
Definition: cib.c:26
#define PCMK_XE_ACLS
Definition: xml_names.h:59
#define PCMK_XA_REFERENCE
Definition: xml_names.h:372
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition: acl.c:750
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
Definition: acl.c:554
G_GNUC_INTERNAL bool pcmk__is_user_in_group(const char *user, const char *group)
Definition: utils.c:67
#define PCMK_XE_ACL_ROLE
Definition: xml_names.h:57
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
Definition: xml.c:96
#define LOG_NEVER
Definition: logging.h:48
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
#define PCMK_XE_ACL_PERMISSION
Definition: xml_names.h:56
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
char * pcmk__uid2username(uid_t uid)
Definition: acl.c:765
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:426
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
Definition: acl.c:655
#define PCMK_VALUE_DENY
Definition: options.h:147
#define crm_warn(fmt, args...)
Definition: logging.h:362
#define crm_debug(fmt, args...)
Definition: logging.h:370
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1297
#define PCMK__XA_ACL_TARGET
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
void pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
Definition: acl.c:334
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1278
Wrappers for and extensions to libxml2.
#define display_id(xml)
Definition: acl.c:536
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition: acl.c:795
#define CRM_DAEMON_USER
Definition: config.h:27
#define PCMK_XA_ID
Definition: xml_names.h:301
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
Definition: acl.c:272
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:613
#define pcmk__str_copy(str)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
const xmlChar * pcmkXmlStr
Definition: xml.h:41
#define pcmk__assert(expr)
xml_private_flags
Definition: xml_internal.h:404
const char * target
Definition: pcmk_fence.c:31
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
#define PCMK_XE_ACL_TARGET
Definition: xml_names.h:58
pcmk__action_result_t result
Definition: pcmk_fence.c:37
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:299
const char * path
Definition: cib.c:28
#define crm_err(fmt, args...)
Definition: logging.h:359
#define pcmk__plural_alt(i, s1, s2)
#define PCMK_XE_ACL_GROUP
Definition: xml_names.h:55
void pcmk__apply_acl(xmlNode *xml)
Definition: acl.c:214
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
#define PCMK_XA_ATTRIBUTE
Definition: xml_names.h:236
bool xml_acl_enabled(const xmlNode *xml)
Check whether or not an XML node is ACL-enabled.
Definition: acl.c:644
GString * pcmk__element_xpath(const xmlNode *xml)
Definition: xpath.c:256
#define PCMK_XE_ROLE
Definition: xml_names.h:183
G_GNUC_INTERNAL bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
Definition: xml.c:69
#define PCMK_XA_KIND
Definition: xml_names.h:312
const char * parent
Definition: cib.c:27
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
#define PCMK_VALUE_WRITE
Definition: options.h:223
#define PCMK_XA_XPATH
Definition: xml_names.h:454
#define PCMK_XA_OBJECT_TYPE
Definition: xml_names.h:344
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
struct xml_acl_s xml_acl_t
G_GNUC_INTERNAL int pcmk__xa_remove(xmlAttr *attr, bool force)
Definition: xml_attr.c:45
uint64_t flags
Definition: remote.c:211
#define PCMK_VALUE_READ
Definition: options.h:198