pacemaker  2.1.9-49aab99839
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) {
59  // @COMPAT Deprecated since 1.1.12 (needed for rolling upgrades)
60  tag = crm_element_value(xml, PCMK_XA_TAG);
61  }
62  if (ref == NULL) {
63  // @COMPAT Deprecated since 1.1.12 (needed for rolling upgrades)
64  ref = crm_element_value(xml, PCMK__XA_REF);
65  }
66 
67  if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
68  // Schema should prevent this, but to be safe ...
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  // NOTE: schema currently does not allow this
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 
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  /* @COMPAT PCMK__XE_ROLE_REF was deprecated in Pacemaker 1.1.12 (needed
143  * for rolling upgrades)
144  */
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  /* @COMPAT Use of a tag instead of a PCMK_XA_KIND attribute was
169  * deprecated in 1.1.12. We still need to look for tags named
170  * PCMK_VALUE_READ, etc., to support rolling upgrades. However,
171  * eventually we can clean this up and make the variables more intuitive
172  * (for example, don't assign a PCMK_XA_KIND value to the tag variable).
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  <acls>
194  <acl_target id="l33t-haxor"><role id="auto-l33t-haxor"/></acl_target>
195  <acl_role id="auto-l33t-haxor">
196  <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
197  </acl_role>
198  <acl_target id="niceguy">
199  <role id="observer"/>
200  </acl_target>
201  <acl_role id="observer">
202  <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
203  <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name='stonith-enabled']"/>
204  <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name='target-role']"/>
205  </acl_role>
206  <acl_target id="badidea"><role id="auto-badidea"/></acl_target>
207  <acl_role id="auto-badidea">
208  <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
209  <acl_permission id="badidea-resources-2" kind="deny" reference="dummy-meta_attributes"/>
210  </acl_role>
211  </acls>
212 */
213 
214 static const char *
215 acl_to_text(enum xml_private_flags flags)
216 {
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  // Build a GString only if tracing is enabled
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 
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  /* @COMPAT PCMK__XE_ACL_USER was deprecated in Pacemaker 1.1.12
314  * (needed for rolling upgrades)
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 
353 void
354 pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
355 {
356  pcmk__unpack_acl(acl_source, target, user);
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 
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); /* Nothing readable under here, purge completely */
429  }
430  return readable_children;
431 }
432 
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  /* Nothing to do */
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 
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 
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));
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); /* In case it is free'd */
604  pcmk__apply_creation_acl(child, true);
605  }
606 }
607 
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  /* Catch anything that was created but shouldn't have been */
633  pcmk__apply_acl(xml);
634  pcmk__apply_creation_acl(xml, false);
636  }
637 }
638 
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) {
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  /* Walk the tree upwards looking for xml_acl_* flags
687  * - Creating an attribute requires write permissions for the node
688  * - Creating a child requires write permissions for the parent
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)) {
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 
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 
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 *
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 
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  /* @COMPAT rolling upgrades <=1.1.11
816  *
817  * field is checked for backward compatibility with older versions that
818  * did not use PCMK_XE_ACL_TARGET.
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_XE_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_XE_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_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 }
#define LOG_TRACE
Definition: logging.h:38
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:627
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:974
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:397
#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
#define PCMK__XE_ACL_USER
const char * name
Definition: cib.c:26
#define PCMK_XA_TAG
Definition: xml_names.h:417
#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:753
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:313
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
Definition: acl.c:573
G_GNUC_INTERNAL bool pcmk__is_user_in_group(const char *user, const char *group)
Definition: utils.c:51
#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:94
#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
char * pcmk__uid2username(uid_t uid)
Definition: acl.c:768
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:445
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
Definition: acl.c:658
#define PCMK_VALUE_DENY
Definition: options.h:146
#define crm_warn(fmt, args...)
Definition: logging.h:394
void pcmk_free_xml_subtree(xmlNode *xml)
Definition: xml.c:885
#define crm_debug(fmt, args...)
Definition: logging.h:402
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
#define PCMK__XA_REF
#define crm_trace(fmt, args...)
Definition: logging.h:404
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1308
#define PCMK__XE_ROLE_REF
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:94
void pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
Definition: acl.c:354
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1289
Wrappers for and extensions to libxml2.
#define display_id(xml)
Definition: acl.c:555
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition: acl.c:798
#define CRM_DAEMON_USER
Definition: config.h:30
#define PCMK_XA_ID
Definition: xml_names.h:301
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
Definition: acl.c:288
void free_xml(xmlNode *child)
Definition: xml.c:958
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1062
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:616
#define pcmk__str_copy(str)
const xmlChar * pcmkXmlStr
Definition: xml.h:41
#define pcmk__assert(expr)
xml_private_flags
Definition: xml_internal.h:524
const char * target
Definition: pcmk_fence.c:29
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:35
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:331
const char * path
Definition: cib.c:28
#define crm_err(fmt, args...)
Definition: logging.h:391
#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:230
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:647
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:67
#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:220
#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:297
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:215
#define PCMK_VALUE_READ
Definition: options.h:196