1 /*
2 * Copyright 2004-2019 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>
24 #include "crmcommon_private.h"
25
26 #define MAX_XPATH_LEN 4096
27
28 typedef struct xml_acl_s {
29 enum xml_private_flags mode;
30 char *xpath;
31 } xml_acl_t;
32
33 static void
__xml_acl_free(void * data)34 __xml_acl_free(void *data)
35 {
36 if (data) {
37 xml_acl_t *acl = data;
38
39 free(acl->xpath);
40 free(acl);
41 }
42 }
43
44 void
pcmk__free_acls(GList * acls)45 pcmk__free_acls(GList *acls)
46 {
47 g_list_free_full(acls, __xml_acl_free);
48 }
49
50 static GList *
__xml_acl_create(xmlNode * xml,GList * acls,enum xml_private_flags mode)51 __xml_acl_create(xmlNode *xml, GList *acls, enum xml_private_flags mode)
52 {
53 xml_acl_t *acl = NULL;
54
55 const char *tag = crm_element_value(xml, XML_ACL_ATTR_TAG);
56 const char *ref = crm_element_value(xml, XML_ACL_ATTR_REF);
57 const char *xpath = crm_element_value(xml, XML_ACL_ATTR_XPATH);
58
59 if (tag == NULL) {
60 // @COMPAT rolling upgrades <=1.1.11
61 tag = crm_element_value(xml, XML_ACL_ATTR_TAGv1);
62 }
63 if (ref == NULL) {
64 // @COMPAT rolling upgrades <=1.1.11
65 ref = crm_element_value(xml, XML_ACL_ATTR_REFv1);
66 }
67
68 if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
69 crm_trace("No criteria %p", xml);
70 return NULL;
71 }
72
73 acl = calloc(1, sizeof (xml_acl_t));
74 if (acl) {
75 const char *attr = crm_element_value(xml, XML_ACL_ATTR_ATTRIBUTE);
76
77 acl->mode = mode;
78 if (xpath) {
79 acl->xpath = strdup(xpath);
80 crm_trace("Using xpath: %s", acl->xpath);
81
82 } else {
83 int offset = 0;
84 char buffer[MAX_XPATH_LEN];
85
86 if (tag) {
87 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
88 "//%s", tag);
89 } else {
90 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
91 "//*");
92 }
93
94 if (ref || attr) {
95 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
96 "[");
97 }
98
99 if (ref) {
100 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
101 "@id='%s'", ref);
102 }
103
104 if (ref && attr) {
105 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
106 " and ");
107 }
108
109 if (attr) {
110 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
111 "@%s", attr);
112 }
113
114 if (ref || attr) {
115 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
116 "]");
117 }
118
119 CRM_LOG_ASSERT(offset > 0);
120 acl->xpath = strdup(buffer);
121 crm_trace("Built xpath: %s", acl->xpath);
122 }
123
124 acls = g_list_append(acls, acl);
125 }
126 return acls;
127 }
128
129 static GList *
__xml_acl_parse_entry(xmlNode * acl_top,xmlNode * acl_entry,GList * acls)130 __xml_acl_parse_entry(xmlNode *acl_top, xmlNode *acl_entry, GList *acls)
131 {
132 xmlNode *child = NULL;
133
134 for (child = __xml_first_child_element(acl_entry); child;
135 child = __xml_next_element(child)) {
136 const char *tag = crm_element_name(child);
137 const char *kind = crm_element_value(child, XML_ACL_ATTR_KIND);
138
139 if (strcmp(XML_ACL_TAG_PERMISSION, tag) == 0){
140 tag = kind;
141 }
142
143 crm_trace("Processing %s %p", tag, child);
144 if (tag == NULL) {
145 CRM_ASSERT(tag != NULL);
146
147 } else if (strcmp(XML_ACL_TAG_ROLE_REF, tag) == 0
148 || strcmp(XML_ACL_TAG_ROLE_REFv1, tag) == 0) {
149 const char *ref_role = crm_element_value(child, XML_ATTR_ID);
150
151 if (ref_role) {
152 xmlNode *role = NULL;
153
154 for (role = __xml_first_child_element(acl_top); role;
155 role = __xml_next_element(role)) {
156 if (!strcmp(XML_ACL_TAG_ROLE, (const char *) role->name)) {
157 const char *role_id = crm_element_value(role,
158 XML_ATTR_ID);
159
160 if (role_id && strcmp(ref_role, role_id) == 0) {
161 crm_debug("Unpacking referenced role: %s", role_id);
162 acls = __xml_acl_parse_entry(acl_top, role, acls);
163 break;
164 }
165 }
166 }
167 }
168
169 } else if (strcmp(XML_ACL_TAG_READ, tag) == 0) {
170 acls = __xml_acl_create(child, acls, xpf_acl_read);
171
172 } else if (strcmp(XML_ACL_TAG_WRITE, tag) == 0) {
173 acls = __xml_acl_create(child, acls, xpf_acl_write);
174
175 } else if (strcmp(XML_ACL_TAG_DENY, tag) == 0) {
176 acls = __xml_acl_create(child, acls, xpf_acl_deny);
177
178 } else {
179 crm_warn("Unknown ACL entry: %s/%s", tag, kind);
180 }
181 }
182
183 return acls;
184 }
185
186 /*
187 <acls>
188 <acl_target id="l33t-haxor"><role id="auto-l33t-haxor"/></acl_target>
189 <acl_role id="auto-l33t-haxor">
190 <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
191 </acl_role>
192 <acl_target id="niceguy">
193 <role id="observer"/>
194 </acl_target>
195 <acl_role id="observer">
196 <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
197 <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name='stonith-enabled']"/>
198 <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name='target-role']"/>
199 </acl_role>
200 <acl_target id="badidea"><role id="auto-badidea"/></acl_target>
201 <acl_role id="auto-badidea">
202 <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
203 <acl_permission id="badidea-resources-2" kind="deny" reference="dummy-meta_attributes"/>
204 </acl_role>
205 </acls>
206 */
207
208 #ifdef SUSE_ACL_COMPAT
209 static const char *
__xml_acl_to_text(enum xml_private_flags flags)210 __xml_acl_to_text(enum xml_private_flags flags)
211 {
212 if (is_set(flags, xpf_acl_deny)) {
213 return "deny";
214
215 } else if (is_set(flags, xpf_acl_write)) {
216 return "read/write";
217
218 } else if (is_set(flags, xpf_acl_read)) {
219 return "read";
220 }
221 return "none";
222 }
223 #endif
224
225 void
pcmk__apply_acl(xmlNode * xml)226 pcmk__apply_acl(xmlNode *xml)
227 {
228 GListPtr aIter = NULL;
229 xml_private_t *p = xml->doc->_private;
230 xmlXPathObjectPtr xpathObj = NULL;
231
232 if (xml_acl_enabled(xml) == FALSE) {
233 crm_trace("Not applying ACLs for %s", p->user);
234 return;
235 }
236
237 for (aIter = p->acls; aIter != NULL; aIter = aIter->next) {
238 int max = 0, lpc = 0;
239 xml_acl_t *acl = aIter->data;
240
241 xpathObj = xpath_search(xml, acl->xpath);
242 max = numXpathResults(xpathObj);
243
244 for (lpc = 0; lpc < max; lpc++) {
245 xmlNode *match = getXpathResult(xpathObj, lpc);
246 char *path = xml_get_path(match);
247
248 p = match->_private;
249 crm_trace("Applying %x to %s for %s", acl->mode, path, acl->xpath);
250
251 #ifdef SUSE_ACL_COMPAT
252 if (is_not_set(p->flags, acl->mode)
253 && (is_set(p->flags, xpf_acl_read)
254 || is_set(p->flags, xpf_acl_write)
255 || is_set(p->flags, xpf_acl_deny))) {
256 crm_config_warn("Configuration element %s is matched by "
257 "multiple ACL rules, only the first applies "
258 "('%s' wins over '%s')",
259 path, __xml_acl_to_text(p->flags),
260 __xml_acl_to_text(acl->mode));
261 free(path);
262 continue;
263 }
264 #endif
265 p->flags |= acl->mode;
266 free(path);
267 }
268 crm_trace("Now enforcing ACL: %s (%d matches)", acl->xpath, max);
269 freeXpathObject(xpathObj);
270 }
271
272 p = xml->_private;
273 if (is_not_set(p->flags, xpf_acl_read)
274 && is_not_set(p->flags, xpf_acl_write)) {
275
276 p->flags |= xpf_acl_deny;
277 p = xml->doc->_private;
278 crm_info("Enforcing default ACL for %s to %s",
279 p->user, crm_element_name(xml));
280 }
281
282 }
283
284 void
pcmk__unpack_acl(xmlNode * source,xmlNode * target,const char * user)285 pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
286 {
287 #if ENABLE_ACL
288 xml_private_t *p = NULL;
289
290 if ((target == NULL) || (target->doc == NULL)
291 || (target->doc->_private == NULL)) {
292 return;
293 }
294
295 p = target->doc->_private;
296 if (pcmk_acl_required(user) == FALSE) {
297 crm_trace("no acls needed for '%s'", user);
298
299 } else if (p->acls == NULL) {
300 xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS,
301 source, LOG_TRACE);
302
303 free(p->user);
304 p->user = strdup(user);
305
306 if (acls) {
307 xmlNode *child = NULL;
308
309 for (child = __xml_first_child_element(acls); child;
310 child = __xml_next_element(child)) {
311 const char *tag = crm_element_name(child);
312
313 if (!strcmp(tag, XML_ACL_TAG_USER)
314 || !strcmp(tag, XML_ACL_TAG_USERv1)) {
315 const char *id = crm_element_value(child, XML_ATTR_ID);
316
317 if (id && strcmp(id, user) == 0) {
318 crm_debug("Unpacking ACLs for %s", id);
319 p->acls = __xml_acl_parse_entry(acls, child, p->acls);
320 }
321 }
322 }
323 }
324 }
325 #endif
326 }
327
328 static inline bool
__xml_acl_mode_test(enum xml_private_flags allowed,enum xml_private_flags requested)329 __xml_acl_mode_test(enum xml_private_flags allowed,
330 enum xml_private_flags requested)
331 {
332 if (is_set(allowed, xpf_acl_deny)) {
333 return FALSE;
334
335 } else if (is_set(allowed, requested)) {
336 return TRUE;
337
338 } else if (is_set(requested, xpf_acl_read)
339 && is_set(allowed, xpf_acl_write)) {
340 return TRUE;
341
342 } else if (is_set(requested, xpf_acl_create)
343 && is_set(allowed, xpf_acl_write)) {
344 return TRUE;
345
346 } else if (is_set(requested, xpf_acl_create)
347 && is_set(allowed, xpf_created)) {
348 return TRUE;
349 }
350 return FALSE;
351 }
352
353 /* rc = TRUE if orig_cib has been filtered
354 * That means '*result' rather than 'xml' should be exploited afterwards
355 */
356 static bool
__xml_purge_attributes(xmlNode * xml)357 __xml_purge_attributes(xmlNode *xml)
358 {
359 xmlNode *child = NULL;
360 xmlAttr *xIter = NULL;
361 bool readable_children = FALSE;
362 xml_private_t *p = xml->_private;
363
364 if (__xml_acl_mode_test(p->flags, xpf_acl_read)) {
365 crm_trace("%s[@id=%s] is readable", crm_element_name(xml), ID(xml));
366 return TRUE;
367 }
368
369 xIter = xml->properties;
370 while (xIter != NULL) {
371 xmlAttr *tmp = xIter;
372 const char *prop_name = (const char *)xIter->name;
373
374 xIter = xIter->next;
375 if (strcmp(prop_name, XML_ATTR_ID) == 0) {
376 continue;
377 }
378
379 xmlUnsetProp(xml, tmp->name);
380 }
381
382 child = __xml_first_child(xml);
383 while ( child != NULL ) {
384 xmlNode *tmp = child;
385
386 child = __xml_next(child);
387 readable_children |= __xml_purge_attributes(tmp);
388 }
389
390 if (readable_children == FALSE) {
391 free_xml(xml); /* Nothing readable under here, purge completely */
392 }
393 return readable_children;
394 }
395
396 bool
xml_acl_filtered_copy(const char * user,xmlNode * acl_source,xmlNode * xml,xmlNode ** result)397 xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
398 xmlNode **result)
399 {
400 GListPtr aIter = NULL;
401 xmlNode *target = NULL;
402 xml_private_t *p = NULL;
403 xml_private_t *doc = NULL;
404
405 *result = NULL;
406 if (xml == NULL || pcmk_acl_required(user) == FALSE) {
407 crm_trace("no acls needed for '%s'", user);
408 return FALSE;
409 }
410
411 crm_trace("filtering copy of %p for '%s'", xml, user);
412 target = copy_xml(xml);
413 if (target == NULL) {
414 return TRUE;
415 }
416
417 pcmk__unpack_acl(acl_source, target, user);
418 pcmk__set_xml_flag(target, xpf_acl_enabled);
419 pcmk__apply_acl(target);
420
421 doc = target->doc->_private;
422 for(aIter = doc->acls; aIter != NULL && target; aIter = aIter->next) {
423 int max = 0;
424 xml_acl_t *acl = aIter->data;
425
426 if (acl->mode != xpf_acl_deny) {
427 /* Nothing to do */
428
429 } else if (acl->xpath) {
430 int lpc = 0;
431 xmlXPathObjectPtr xpathObj = xpath_search(target, acl->xpath);
432
433 max = numXpathResults(xpathObj);
434 for(lpc = 0; lpc < max; lpc++) {
435 xmlNode *match = getXpathResult(xpathObj, lpc);
436
437 crm_trace("Purging attributes from %s", acl->xpath);
438 if (__xml_purge_attributes(match) == FALSE && match == target) {
439 crm_trace("No access to the entire document for %s", user);
440 freeXpathObject(xpathObj);
441 return TRUE;
442 }
443 }
444 crm_trace("Enforced ACL %s (%d matches)", acl->xpath, max);
445 freeXpathObject(xpathObj);
446 }
447 }
448
449 p = target->_private;
450 if (is_set(p->flags, xpf_acl_deny)
451 && (__xml_purge_attributes(target) == FALSE)) {
452 crm_trace("No access to the entire document for %s", user);
453 return TRUE;
454 }
455
456 if (doc->acls) {
457 g_list_free_full(doc->acls, __xml_acl_free);
458 doc->acls = NULL;
459
460 } else {
461 crm_trace("Ordinary user '%s' cannot access the CIB without any defined ACLs",
462 doc->user);
463 free_xml(target);
464 target = NULL;
465 }
466
467 if (target) {
468 *result = target;
469 }
470
471 return TRUE;
472 }
473
474 /*!
475 * \internal
476 * \brief Check whether creation of an XML element is implicitly allowed
477 *
478 * Check whether XML is a "scaffolding" element whose creation is implicitly
479 * allowed regardless of ACLs (that is, it is not in the ACL section and has
480 * no attributes other than "id").
481 *
482 * \param[in] xml XML element to check
483 *
484 * \return TRUE if XML element is implicitly allowed, FALSE otherwise
485 */
486 static bool
implicitly_allowed(xmlNode * xml)487 implicitly_allowed(xmlNode *xml)
488 {
489 char *path = NULL;
490
491 for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
492 if (strcmp((const char *) prop->name, XML_ATTR_ID) != 0) {
493 return FALSE;
494 }
495 }
496
497 path = xml_get_path(xml);
498 if (strstr(path, "/" XML_CIB_TAG_ACLS "/") != NULL) {
499 free(path);
500 return FALSE;
501 }
502 free(path);
503
504 return TRUE;
505 }
506
507 #define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
508
509 /*!
510 * \internal
511 * \brief Drop XML nodes created in violation of ACLs
512 *
513 * Given an XML element, free all of its descendent nodes created in violation
514 * of ACLs, with the exception of allowing "scaffolding" elements (i.e. those
515 * that aren't in the ACL section and don't have any attributes other than
516 * "id").
517 *
518 * \param[in,out] xml XML to check
519 * \param[in] check_top Whether to apply checks to argument itself
520 * (if TRUE, xml might get freed)
521 */
522 void
pcmk__post_process_acl(xmlNode * xml,bool check_top)523 pcmk__post_process_acl(xmlNode *xml, bool check_top)
524 {
525 xml_private_t *p = xml->_private;
526
527 if (is_set(p->flags, xpf_created)) {
528 if (implicitly_allowed(xml)) {
529 crm_trace("Creation of <%s> scaffolding with id=\"%s\""
530 " is implicitly allowed",
531 crm_element_name(xml), display_id(xml));
532
533 } else if (pcmk__check_acl(xml, NULL, xpf_acl_write)) {
534 crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
535 crm_element_name(xml), display_id(xml));
536
537 } else if (check_top) {
538 crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
539 crm_element_name(xml), display_id(xml));
540 pcmk_free_xml_subtree(xml);
541 return;
542
543 } else {
544 crm_trace("ACLs would disallow creation of <%s> with id=\"%s\"",
545 crm_element_name(xml), display_id(xml));
546 }
547 }
548
549 for (xmlNode *cIter = __xml_first_child(xml); cIter != NULL; ) {
550 xmlNode *child = cIter;
551 cIter = __xml_next(cIter); /* In case it is free'd */
552 pcmk__post_process_acl(child, TRUE);
553 }
554 }
555
556 bool
xml_acl_denied(xmlNode * xml)557 xml_acl_denied(xmlNode *xml)
558 {
559 if (xml && xml->doc && xml->doc->_private){
560 xml_private_t *p = xml->doc->_private;
561
562 return is_set(p->flags, xpf_acl_denied);
563 }
564 return FALSE;
565 }
566
567 void
xml_acl_disable(xmlNode * xml)568 xml_acl_disable(xmlNode *xml)
569 {
570 if (xml_acl_enabled(xml)) {
571 xml_private_t *p = xml->doc->_private;
572
573 /* Catch anything that was created but shouldn't have been */
574 pcmk__apply_acl(xml);
575 pcmk__post_process_acl(xml, FALSE);
576 clear_bit(p->flags, xpf_acl_enabled);
577 }
578 }
579
580 bool
xml_acl_enabled(xmlNode * xml)581 xml_acl_enabled(xmlNode *xml)
582 {
583 if (xml && xml->doc && xml->doc->_private){
584 xml_private_t *p = xml->doc->_private;
585
586 return is_set(p->flags, xpf_acl_enabled);
587 }
588 return FALSE;
589 }
590
591 bool
pcmk__check_acl(xmlNode * xml,const char * name,enum xml_private_flags mode)592 pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
593 {
594 CRM_ASSERT(xml);
595 CRM_ASSERT(xml->doc);
596 CRM_ASSERT(xml->doc->_private);
597
598 #if ENABLE_ACL
599 if (pcmk__tracking_xml_changes(xml, FALSE) && xml_acl_enabled(xml)) {
600 int offset = 0;
601 xmlNode *parent = xml;
602 char buffer[MAX_XPATH_LEN];
603 xml_private_t *docp = xml->doc->_private;
604
605 if (docp->acls == NULL) {
606 crm_trace("Ordinary user %s cannot access the CIB without any defined ACLs",
607 docp->user);
608 pcmk__set_xml_flag(xml, xpf_acl_denied);
609 return FALSE;
610 }
611
612 offset = pcmk__element_xpath(NULL, xml, buffer, offset,
613 sizeof(buffer));
614 if (name) {
615 offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
616 "[@%s]", name);
617 }
618 CRM_LOG_ASSERT(offset > 0);
619
620 /* Walk the tree upwards looking for xml_acl_* flags
621 * - Creating an attribute requires write permissions for the node
622 * - Creating a child requires write permissions for the parent
623 */
624
625 if (name) {
626 xmlAttr *attr = xmlHasProp(xml, (const xmlChar *)name);
627
628 if (attr && mode == xpf_acl_create) {
629 mode = xpf_acl_write;
630 }
631 }
632
633 while (parent && parent->_private) {
634 xml_private_t *p = parent->_private;
635 if (__xml_acl_mode_test(p->flags, mode)) {
636 return TRUE;
637
638 } else if (is_set(p->flags, xpf_acl_deny)) {
639 crm_trace("%x access denied to %s: parent", mode, buffer);
640 pcmk__set_xml_flag(xml, xpf_acl_denied);
641 return FALSE;
642 }
643 parent = parent->parent;
644 }
645
646 crm_trace("%x access denied to %s: default", mode, buffer);
647 pcmk__set_xml_flag(xml, xpf_acl_denied);
648 return FALSE;
649 }
650 #endif
651
652 return TRUE;
653 }
654
655 bool
pcmk_acl_required(const char * user)656 pcmk_acl_required(const char *user)
657 {
658 #if ENABLE_ACL
659 if (user == NULL || strlen(user) == 0) {
660 crm_trace("no user set");
661 return FALSE;
662
663 } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
664 return FALSE;
665
666 } else if (strcmp(user, "root") == 0) {
667 return FALSE;
668 }
669 crm_trace("ACLs required for %s", user);
670 return TRUE;
671 #else
672 crm_trace("ACLs not supported");
673 return FALSE;
674 #endif
675 }
676
677 #if ENABLE_ACL
678 char *
uid2username(uid_t uid)679 uid2username(uid_t uid)
680 {
681 struct passwd *pwent = getpwuid(uid);
682
683 if (pwent == NULL) {
684 crm_perror(LOG_INFO, "Cannot get user details for user ID %d", uid);
685 return NULL;
686 }
687 return strdup(pwent->pw_name);
688 }
689
690 const char *
crm_acl_get_set_user(xmlNode * request,const char * field,const char * peer_user)691 crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
692 {
693 static const char *effective_user = NULL;
694 const char *requested_user = NULL;
695 const char *user = NULL;
696
697 if (effective_user == NULL) {
698 effective_user = uid2username(geteuid());
699 if (effective_user == NULL) {
700 effective_user = strdup("#unprivileged");
701 CRM_CHECK(effective_user != NULL, return NULL);
702 crm_err("Unable to determine effective user, assuming unprivileged for ACLs");
703 }
704 }
705
706 requested_user = crm_element_value(request, XML_ACL_TAG_USER);
707 if (requested_user == NULL) {
708 /* @COMPAT rolling upgrades <=1.1.11
709 *
710 * field is checked for backward compatibility with older versions that
711 * did not use XML_ACL_TAG_USER.
712 */
713 requested_user = crm_element_value(request, field);
714 }
715
716 if (is_privileged(effective_user) == FALSE) {
717 /* We're not running as a privileged user, set or overwrite any existing
718 * value for $XML_ACL_TAG_USER
719 */
720 user = effective_user;
721
722 } else if (peer_user == NULL && requested_user == NULL) {
723 /* No user known or requested, use 'effective_user' and make sure one is
724 * set for the request
725 */
726 user = effective_user;
727
728 } else if (peer_user == NULL) {
729 /* No user known, trusting 'requested_user' */
730 user = requested_user;
731
732 } else if (is_privileged(peer_user) == FALSE) {
733 /* The peer is not a privileged user, set or overwrite any existing
734 * value for $XML_ACL_TAG_USER
735 */
736 user = peer_user;
737
738 } else if (requested_user == NULL) {
739 /* Even if we're privileged, make sure there is always a value set */
740 user = peer_user;
741
742 } else {
743 /* Legal delegation to 'requested_user' */
744 user = requested_user;
745 }
746
747 // This requires pointer comparison, not string comparison
748 if (user != crm_element_value(request, XML_ACL_TAG_USER)) {
749 crm_xml_add(request, XML_ACL_TAG_USER, user);
750 }
751
752 if (field != NULL && user != crm_element_value(request, field)) {
753 crm_xml_add(request, field, user);
754 }
755
756 return requested_user;
757 }
758 #endif
759