Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4149380
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pacemaker/pcmk_acl.c b/lib/pacemaker/pcmk_acl.c
index d218101ca4..f9c2797765 100644
--- a/lib/pacemaker/pcmk_acl.c
+++ b/lib/pacemaker/pcmk_acl.c
@@ -1,389 +1,318 @@
/*
* Copyright 2004-2021 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#if HAVE_LIBXSLT
# include <libxslt/transform.h>
# include <libxslt/variables.h>
# include <libxslt/xsltutils.h>
#endif
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h>
#include <crm/common/internal.h>
#include <pcmki/pcmki_acl.h>
#define ACL_NS_PREFIX "http://clusterlabs.org/ns/pacemaker/access/"
#define ACL_NS_Q_PREFIX "pcmk-access-"
#define ACL_NS_Q_WRITABLE (const xmlChar *) ACL_NS_Q_PREFIX "writable"
#define ACL_NS_Q_READABLE (const xmlChar *) ACL_NS_Q_PREFIX "readable"
#define ACL_NS_Q_DENIED (const xmlChar *) ACL_NS_Q_PREFIX "denied"
static const xmlChar *NS_WRITABLE = (const xmlChar *) ACL_NS_PREFIX "writable";
static const xmlChar *NS_READABLE = (const xmlChar *) ACL_NS_PREFIX "readable";
static const xmlChar *NS_DENIED = (const xmlChar *) ACL_NS_PREFIX "denied";
static int
pcmk__eval_acl_as_namespaces_2(xmlNode *xml_modify)
{
static xmlNs *ns_recycle_writable = NULL,
*ns_recycle_readable = NULL,
*ns_recycle_denied = NULL;
static const xmlDoc *prev_doc = NULL;
xmlNode *i_node = NULL;
const xmlChar *ns;
int ret = 0;
if (prev_doc == NULL || prev_doc != xml_modify->doc) {
prev_doc = xml_modify->doc;
ns_recycle_writable = ns_recycle_readable = ns_recycle_denied = NULL;
}
for (i_node = xml_modify; i_node != NULL; i_node = i_node->next) {
switch (i_node->type) {
case XML_ELEMENT_NODE:
pcmk__set_xml_doc_flag(i_node, pcmk__xf_tracking);
if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_read)) {
ns = NS_DENIED;
} else if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_write)) {
ns = NS_READABLE;
} else {
ns = NS_WRITABLE;
}
if (ns == NS_WRITABLE) {
if (ns_recycle_writable == NULL) {
ns_recycle_writable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_WRITABLE, ACL_NS_Q_WRITABLE);
}
xmlSetNs(i_node, ns_recycle_writable);
ret = pcmk_rc_ok;
} else if (ns == NS_READABLE) {
if (ns_recycle_readable == NULL) {
ns_recycle_readable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_READABLE, ACL_NS_Q_READABLE);
}
xmlSetNs(i_node, ns_recycle_readable);
ret = pcmk_rc_ok;
} else if (ns == NS_DENIED) {
if (ns_recycle_denied == NULL) {
ns_recycle_denied = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_DENIED, ACL_NS_Q_DENIED);
};
xmlSetNs(i_node, ns_recycle_denied);
ret = pcmk_rc_ok;
}
/* XXX recursion can be turned into plain iteration to save stack */
if (i_node->properties != NULL) {
/* this is not entirely clear, but relies on the very same
class-hierarchy emulation that libxml2 has firmly baked in
its API/ABI */
ret |= pcmk__eval_acl_as_namespaces_2((xmlNodePtr) i_node->properties);
}
if (i_node->children != NULL) {
ret |= pcmk__eval_acl_as_namespaces_2(i_node->children);
}
break;
case XML_ATTRIBUTE_NODE:
/* we can utilize that parent has already been assigned the ns */
if (!pcmk__check_acl(i_node->parent,
(const char *) i_node->name,
pcmk__xf_acl_read)) {
ns = NS_DENIED;
} else if (!pcmk__check_acl(i_node,
(const char *) i_node->name,
pcmk__xf_acl_write)) {
ns = NS_READABLE;
} else {
ns = NS_WRITABLE;
}
if (ns == NS_WRITABLE) {
if (ns_recycle_writable == NULL) {
ns_recycle_writable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_WRITABLE, ACL_NS_Q_WRITABLE);
}
xmlSetNs(i_node, ns_recycle_writable);
ret = pcmk_rc_ok;
} else if (ns == NS_READABLE) {
if (ns_recycle_readable == NULL) {
ns_recycle_readable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_READABLE, ACL_NS_Q_READABLE);
}
xmlSetNs(i_node, ns_recycle_readable);
ret = pcmk_rc_ok;
} else if (ns == NS_DENIED) {
if (ns_recycle_denied == NULL) {
ns_recycle_denied = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_DENIED, ACL_NS_Q_DENIED);
}
xmlSetNs(i_node, ns_recycle_denied);
ret = pcmk_rc_ok;
}
break;
default:
break;
}
}
return ret;
}
int
pcmk__acl_evaled_as_namespaces(const char *cred, xmlDoc *cib_doc,
xmlDoc **acl_evaled_doc)
{
int ret, version;
xmlNode *target;
const char *validation;
CRM_CHECK(cred != NULL, return EINVAL);
CRM_CHECK(cib_doc != NULL, return EINVAL);
CRM_CHECK(acl_evaled_doc != NULL, return EINVAL);
/* avoid trivial accidental XML injection */
if (strpbrk(cred, "<>&") != NULL) {
return EINVAL;
}
if (!pcmk_acl_required(cred)) {
/* nothing to evaluate */
return pcmk_rc_already;
}
/* XXX see the comment for this function, pacemaker-4.0 may need
updating respectively in the future */
validation = crm_element_value(xmlDocGetRootElement(cib_doc),
XML_ATTR_VALIDATION);
version = get_schema_version(validation);
if (get_schema_version(PCMK__COMPAT_ACL_2_MIN_INCL) > version) {
return pcmk_rc_schema_validation;
}
target = copy_xml(xmlDocGetRootElement(cib_doc));
if (target == NULL) {
return EINVAL;
}
ret = pcmk__eval_acl_as_namespaces_2(target); /* XXX may need "switch" */
if (ret > 0) {
*acl_evaled_doc = target->doc;
} else {
xmlFreeNode(target);
}
return pcmk_rc_ok;
}
-/* this is used to dynamically adapt to user-modified stylesheet */
-static const char **
-parse_params(xmlDoc *doc, const char **fallback)
-{
- xmlXPathContext *xpath_ctxt;
- xmlXPathObject *xpath_obj;
- const char **ret = NULL;
- size_t ret_cnt = 0, ret_iter = 0;
-
- if (doc == NULL) {
- return fallback;
- }
-
- xpath_ctxt = xmlXPathNewContext(doc);
- CRM_ASSERT(xpath_ctxt != NULL);
-
- if (xmlXPathRegisterNs(xpath_ctxt, (pcmkXmlStr) "xsl",
- (pcmkXmlStr) "http://www.w3.org/1999/XSL/Transform") != 0) {
- return fallback;
- }
-
- while (*fallback != NULL) {
- char xpath_query[1024];
- const char *key = *fallback++;
- const char *value = *fallback++;
- CRM_ASSERT(value != NULL);
-
- if (ret_iter + 1 >= ret_cnt) {
- ret_cnt = ret_cnt ? ret_cnt : 1;
- ret_cnt *= 2;
- ret_cnt += 1;
- ret = realloc(ret, ret_cnt * sizeof(*ret));
- CRM_ASSERT(ret != NULL);
- }
-
- key = strdup(key);
- CRM_ASSERT(key != NULL);
- ret[ret_iter++] = key;
-
- snprintf(xpath_query, sizeof(xpath_query),
- "substring("
- "/xsl:stylesheet/xsl:param[@name = '%s']/xsl:value-of/@select,"
- "2,"
- "string-length(/xsl:stylesheet/xsl:param[@name = '%s']/xsl:value-of/@select) - 2"
- ")",
- key, key);
- xpath_obj = xmlXPathEvalExpression((pcmkXmlStr) xpath_query, xpath_ctxt);
- if (xpath_obj != NULL && xpath_obj->type == XPATH_STRING
- && *xpath_obj->stringval != '\0') {
- /* XXX convert first! */
- char *origval = strdup((const char *) xpath_obj->stringval);
- size_t reminder = strlen(origval) + 1;
- xmlXPathFreeObject(xpath_obj);
- value = origval;
- /* reconcile "\x1b" (3 chars) -> '\x1b' (single char) */
- while ((origval = strstr(origval, "\\x1b")) != NULL) {
- origval[0] = '\x1b';
- memmove(origval + 1, origval + (sizeof("\\x1b") - 1),
- (reminder -= (sizeof("\\x1b") - 1)));
- }
- } else {
- value = strdup(value);
- }
- CRM_ASSERT(value != NULL);
- ret[ret_iter++] = value;
- }
- ret[ret_iter] = NULL;
-
- return ret;
-}
-
int
pcmk__acl_evaled_render(xmlDoc *annotated_doc, enum pcmk__acl_render_how how,
xmlChar **doc_txt_ptr)
{
#if HAVE_LIBXSLT
xmlDoc *xslt_doc;
xsltStylesheet *xslt;
xsltTransformContext *xslt_ctxt;
xmlDoc *res;
char *sfile;
static const char *params_ns_simple[] = {
"accessrendercfg:c-writable", ACL_NS_Q_PREFIX "writable:",
"accessrendercfg:c-readable", ACL_NS_Q_PREFIX "readable:",
"accessrendercfg:c-denied", ACL_NS_Q_PREFIX "denied:",
"accessrendercfg:c-reset", "",
"accessrender:extra-spacing", "no",
"accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
NULL
}, *params_useansi[] = {
/* start with hard-coded defaults, then adapt per the template ones */
"accessrendercfg:c-writable", "\x1b[32m",
"accessrendercfg:c-readable", "\x1b[34m",
"accessrendercfg:c-denied", "\x1b[31m",
"accessrendercfg:c-reset", "\x1b[0m",
"accessrender:extra-spacing", "no",
"accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
NULL
}, *params_noansi[] = {
"accessrendercfg:c-writable", "vvv---[ WRITABLE ]---vvv",
"accessrendercfg:c-readable", "vvv---[ READABLE ]---vvv",
"accessrendercfg:c-denied", "vvv---[ ~DENIED~ ]---vvv",
"accessrendercfg:c-reset", "",
"accessrender:extra-spacing", "yes",
"accessrender:self-reproducing-prefix", "",
NULL
};
const char **params;
int ret;
xmlParserCtxtPtr parser_ctxt;
/* unfortunately, the input (coming from CIB originally) was parsed with
blanks ignored, and since the output is a conversion of XML to text
format (we would be covered otherwise thanks to implicit
pretty-printing), we need to dump the tree to string output first,
only to subsequently reparse it -- this time with blanks honoured */
xmlChar *annotated_dump;
int dump_size;
xmlDocDumpFormatMemory(annotated_doc, &annotated_dump, &dump_size, 1);
res = xmlReadDoc(annotated_dump, "on-the-fly-access-render", NULL,
XML_PARSE_NONET);
CRM_ASSERT(res != NULL);
xmlFree(annotated_dump);
xmlFreeDoc(annotated_doc);
annotated_doc = res;
sfile = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_base_xslt,
"access-render-2");
parser_ctxt = xmlNewParserCtxt();
CRM_ASSERT(sfile != NULL);
CRM_ASSERT(parser_ctxt != NULL);
xslt_doc = xmlCtxtReadFile(parser_ctxt, sfile, NULL, XML_PARSE_NONET);
xslt = xsltParseStylesheetDoc(xslt_doc); /* acquires xslt_doc! */
if (xslt == NULL) {
crm_crit("Problem in parsing %s", sfile);
return EINVAL;
}
free(sfile);
sfile = NULL;
xmlFreeParserCtxt(parser_ctxt);
xslt_ctxt = xsltNewTransformContext(xslt, annotated_doc);
CRM_ASSERT(xslt_ctxt != NULL);
if (how == pcmk__acl_render_ns_simple) {
params = params_ns_simple;
} else if (how == pcmk__acl_render_text) {
params = params_noansi;
} else {
- params = parse_params(xslt_doc, params_useansi);
+ params = params_useansi;
}
xsltQuoteUserParams(xslt_ctxt, params);
res = xsltApplyStylesheetUser(xslt, annotated_doc, NULL,
NULL, NULL, xslt_ctxt);
xmlFreeDoc(annotated_doc);
annotated_doc = NULL;
xsltFreeTransformContext(xslt_ctxt);
xslt_ctxt = NULL;
if (how == pcmk__acl_render_color && params != params_useansi) {
char **param_i = (char **) params;
do {
free(*param_i);
} while (*param_i++ != NULL);
free(params);
}
if (res == NULL) {
ret = EINVAL;
} else {
int doc_txt_len;
int temp = xsltSaveResultToString(doc_txt_ptr, &doc_txt_len, res, xslt);
xmlFreeDoc(res);
if (temp == 0) {
ret = pcmk_rc_ok;
} else {
ret = EINVAL;
}
}
xsltFreeStylesheet(xslt);
return ret;
#else
return -1;
#endif
}
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 4, 6:03 AM (6 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1854717
Default Alt Text
(13 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment