19#include <libxml/tree.h>
20#include <libxml/xmlstring.h>
21#include <libxml/xpath.h>
28typedef struct xml_acl_s {
47 g_list_free_full(acls, free_acl);
60 if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
62 crm_trace(
"Ignoring ACL <%s> element without selection criteria",
71 acl->xpath = g_strdup(xpath);
72 crm_trace(
"Unpacked ACL <%s> element using xpath: %s",
73 xml->name, acl->xpath);
76 GString *buf = g_string_sized_new(128);
78 if ((ref != NULL) && (attr != NULL)) {
81 ref,
"' and @", attr,
"]", NULL);
83 }
else if (ref != NULL) {
87 }
else if (attr != NULL) {
88 pcmk__g_strcat(buf,
"//", pcmk__s(tag,
"*"),
"[@", attr,
"]", NULL);
94 acl->xpath = buf->str;
96 g_string_free(buf, FALSE);
97 crm_trace(
"Unpacked ACL <%s> element as xpath: %s",
98 xml->name, acl->xpath);
101 return g_list_append(acls, acl);
117parse_acl_entry(
const xmlNode *acl_top,
const xmlNode *acl_entry, GList *acls)
141 crm_warn(
"Ignoring unknown ACL kind '%s'", kind);
149 if (ref_role == NULL) {
157 const char *role_id = NULL;
166 crm_trace(
"Unpacking referenced role '%s' in <%s> element",
167 role_id, acl_entry->name);
168 acls = parse_acl_entry(acl_top, role, acls);
221 xmlXPathObject *xpathObj = NULL;
224 crm_trace(
"Skipping ACLs for user '%s' because not enabled for this XML",
229 for (aIter = docpriv->
acls; aIter != NULL; aIter = aIter->next) {
230 int max = 0, lpc = 0;
234 max = pcmk__xpath_num_results(xpathObj);
236 for (lpc = 0; lpc < max; lpc++) {
280 nodepriv = match->_private;
287 crm_trace(
"Applying %s ACL to %s matched by %s",
288 acl_to_text(acl->mode),
path->str, acl->xpath);
289 g_string_free(
path, TRUE);
294 crm_trace(
"Applied %s ACL %s (%d match%s)",
295 acl_to_text(acl->mode), acl->xpath, max,
296 ((max == 1)?
"" :
"es"));
297 xmlXPathFreeObject(xpathObj);
320 || (
target->doc->_private == NULL)) {
324 docpriv =
target->doc->_private;
326 crm_trace(
"Not unpacking ACLs because not required for user '%s'",
329 }
else if (docpriv->
acls == NULL) {
336 xmlNode *child = NULL;
348 if (
id && strcmp(
id, user) == 0) {
349 crm_debug(
"Unpacking ACLs for user '%s'",
id);
350 docpriv->
acls = parse_acl_entry(acls, child, docpriv->
acls);
360 crm_debug(
"Unpacking ACLs for group '%s'",
id);
361 docpriv->
acls = parse_acl_entry(acls, child, docpriv->
acls);
394 }
else if (pcmk_all_flags_set(allowed, requested)) {
420purge_xml_attributes(xmlNode *xml)
422 xmlNode *child = NULL;
423 xmlAttr *xIter = NULL;
424 bool readable_children =
false;
429 xml->name, pcmk__xe_id(xml));
433 xIter = xml->properties;
434 while (xIter != NULL) {
435 xmlAttr *tmp = xIter;
436 const char *prop_name = (
const char *)xIter->name;
446 child = pcmk__xml_first_child(xml);
447 while ( child != NULL ) {
448 xmlNode *tmp = child;
450 child = pcmk__xml_next(child);
451 readable_children |= purge_xml_attributes(tmp);
454 if (!readable_children) {
458 return readable_children;
482 crm_trace(
"Not filtering XML because ACLs not required for user '%s'",
487 crm_trace(
"Filtering XML copy using user '%s' ACLs", user);
495 docpriv =
target->doc->_private;
496 for(aIter = docpriv->
acls; aIter != NULL &&
target; aIter = aIter->next) {
503 }
else if (acl->xpath) {
508 max = pcmk__xpath_num_results(xpathObj);
509 for(lpc = 0; lpc < max; lpc++) {
522 if (!purge_xml_attributes(match) && (match ==
target)) {
523 crm_trace(
"ACLs deny user '%s' access to entire XML document",
525 xmlXPathFreeObject(xpathObj);
529 crm_trace(
"ACLs deny user '%s' access to %s (%d %s)",
530 user, acl->xpath, max,
532 xmlXPathFreeObject(xpathObj);
536 if (!purge_xml_attributes(
target)) {
537 crm_trace(
"ACLs deny user '%s' access to entire XML document", user);
542 g_list_free_full(docpriv->
acls, free_acl);
543 docpriv->
acls = NULL;
546 crm_trace(
"User '%s' without ACLs denied access to entire XML document",
572implicitly_allowed(
const xmlNode *xml)
574 GString *
path = NULL;
576 for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
577 if (strcmp((
const char *) prop->name,
PCMK_XA_ID) != 0) {
586 g_string_free(
path, TRUE);
590 g_string_free(
path, TRUE);
594#define display_id(xml) pcmk__s(pcmk__xe_id(xml), "<unset>")
617 if (implicitly_allowed(xml)) {
619 " is implicitly allowed",
626 }
else if (check_top) {
630 bool is_root = (xmlDocGetRootElement(xml->doc) == xml);
633 crm_trace(
"ACLs disallow creation of %s<%s> with "
635 (is_root?
"root element " :
""), xml->name,
649 crm_notice(
"ACLs would disallow creation of %s<%s> with "
651 ((xml == xmlDocGetRootElement(xml->doc))?
"root element " :
""),
656 for (xmlNode *cIter = pcmk__xml_first_child(xml); cIter != NULL; ) {
657 xmlNode *child = cIter;
658 cIter = pcmk__xml_next(cIter);
673 if (xml && xml->doc && xml->doc->_private){
704 if (xml && xml->doc && xml->doc->_private){
724#define check_acl_deny(xml, attr_name, prefix, user, mode) do { \
725 xmlNode *tree = xml; \
727 pcmk__xml_doc_set_flags(tree->doc, pcmk__xf_acl_denied); \
730 GString *xpath = pcmk__element_xpath(tree); \
732 if ((attr_name) != NULL) { \
733 pcmk__g_strcat(xpath, "[@", attr_name, "]", NULL); \
735 qb_log_from_external_source(__func__, __FILE__, \
736 "%sACL denies user '%s' %s " \
738 LOG_TRACE, __LINE__, 0 , \
740 acl_to_text(mode), xpath->str); \
741 g_string_free(xpath, TRUE); \
752 pcmk__assert((xml != NULL) && (xml->doc->_private != NULL));
759 docpriv = xml->doc->_private;
760 if (docpriv->
acls == NULL) {
770 if (attr_name != NULL) {
771 xmlAttr *attr = xmlHasProp(xml, (
const xmlChar *) attr_name);
778 for (
const xmlNode *
parent = xml;
784 if (test_acl_mode(nodepriv->
flags, mode)) {
789 const char *pfx = (
parent != xml)?
"Parent " :
"";
810 if (pcmk__str_empty(user)) {
811 crm_trace(
"ACLs not required because no user set");
815 crm_trace(
"ACLs not required for privileged user %s", user);
825 struct passwd *pwent = getpwuid(uid);
828 crm_perror(LOG_INFO,
"Cannot get user details for user ID %d", uid);
854 const char *peer_user)
856 static const char *effective_user = NULL;
857 const char *requested_user = NULL;
858 const char *user = NULL;
860 if (effective_user == NULL) {
862 if (effective_user == NULL) {
864 crm_err(
"Unable to determine effective user, assuming unprivileged for ACLs");
869 if (requested_user == NULL) {
881 if (!pcmk__is_privileged(effective_user)) {
885 user = effective_user;
887 }
else if (peer_user == NULL && requested_user == NULL) {
891 user = effective_user;
893 }
else if (peer_user == NULL) {
895 user = requested_user;
897 }
else if (!pcmk__is_privileged(peer_user)) {
903 }
else if (requested_user == NULL) {
909 user = requested_user;
921 return requested_user;
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
void pcmk__free_acls(GList *acls)
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
char * pcmk__uid2username(uid_t uid)
bool pcmk__check_acl(xmlNode *xml, const char *attr_name, enum pcmk__xml_flags mode)
struct xml_acl_s xml_acl_t
void xml_acl_disable(xmlNode *xml)
#define check_acl_deny(xml, attr_name, prefix, user, mode)
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
void pcmk__enable_acl(xmlNode *acl_source, xmlNode *target, const char *user)
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
Copy ACL-allowed portions of specified XML.
bool xml_acl_enabled(const xmlNode *xml)
Check whether or not an XML node is ACL-enabled.
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
void pcmk__apply_acl(xmlNode *xml)
#define pcmk__assert_alloc(nmemb, size)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
G_GNUC_INTERNAL int pcmk__xa_remove(xmlAttr *attr, bool force)
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
G_GNUC_INTERNAL bool pcmk__is_user_in_group(const char *user, const char *group)
#define crm_warn(fmt, args...)
#define crm_notice(fmt, args...)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define crm_debug(fmt, args...)
#define crm_err(fmt, args...)
#define crm_trace(fmt, args...)
#define pcmk__if_tracing(if_action, else_action)
pcmk__action_result_t result
#define pcmk__assert(expr)
#define pcmk__plural_alt(i, s1, s2)
void pcmk__str_update(char **str, const char *value)
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
#define pcmk__str_copy(str)
char * acl_user
User affected by acls (for logging)
GList * acls
ACLs to check requested changes against (list of xml_acl_t)
uint32_t flags
Group of enum pcmk__xml_flags
uint32_t flags
Group of enum pcmk__xml_flags
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
bool pcmk__xml_doc_all_flags_set(const xmlDoc *xml, uint32_t flags)
void pcmk__xml_doc_set_flags(xmlDoc *doc, uint32_t flags)
@ pcmk__xf_acl_enabled
ACLs are enabled (set for document only)
@ pcmk__xf_created
Node was created.
@ pcmk__xf_acl_denied
ACLs deny the user access (set for document only)
@ pcmk__xf_acl_deny
ACL deny permission (that is, no permission)
@ pcmk__xf_acl_write
ACL write permission (implies read permission in most or all contexts)
@ pcmk__xf_tracking
Tracking is enabled (set for document only)
@ pcmk__xf_acl_read
ACL read permission.
void pcmk__xml_free(xmlNode *xml)
#define PCMK_XE_ACL_GROUP
#define PCMK_XE_ACL_TARGET
#define PCMK_XA_OBJECT_TYPE
#define PCMK_XE_ACL_PERMISSION
#define PCMK_XA_ATTRIBUTE
#define PCMK_XA_REFERENCE
#define PCMK__XA_ACL_TARGET
xmlXPathObject * pcmk__xpath_search(xmlDoc *doc, const char *path)
xmlNode * pcmk__xpath_result(xmlXPathObject *xpath_obj, int index)
GString * pcmk__element_xpath(const xmlNode *xml)
xmlNode * pcmk__xpath_match_element(xmlNode *match)
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)