Commit b420cc51 authored by David Zeuthen's avatar David Zeuthen

don't fail on unknown XML tags, just skip them

This change will futureproof libpolkit for extensions; e.g. if there's
an OS upgrade where

 a) the PolicyKit package is upgraded to a version where support for a
    new tag <allow_foo> is added; and

 b) another package, using PolicyKit, is upgraded dropping a .policy
    file using the new <allow_foo> tag; then

existing running processes using libpolkit will not fail. They will,
however, not honor the new tags until the daemon process itself is
restarted using e.g. condrestart.

We also log to the system logger whenever we encouter unknown tags.
parent 4714fe72
- Make both XML parsers cope with unknown elements; this is necessary
to keep old processes linking in libpolkit work when doing upgrade
of PolicyKit where e.g. .policy files with new elements are added.
- Have someone review the external API
- Verify the security model
......
......@@ -37,6 +37,7 @@
#include <errno.h>
#include <sys/inotify.h>
#include <regex.h>
#include <syslog.h>
#include <expat.h>
......@@ -58,6 +59,7 @@
enum {
STATE_NONE,
STATE_UNKNOWN_TAG,
STATE_IN_CONFIG,
STATE_IN_MATCH,
STATE_IN_RETURN,
......@@ -87,6 +89,7 @@ typedef struct {
XML_Parser parser;
int state;
PolKitConfig *pk_config;
const char *path;
int state_stack[PARSER_MAX_DEPTH];
ConfigNode *node_stack[PARSER_MAX_DEPTH];
......@@ -95,6 +98,7 @@ typedef struct {
} ParserData;
enum {
NODE_TYPE_NOP,
NODE_TYPE_TOP,
NODE_TYPE_MATCH,
NODE_TYPE_RETURN,
......@@ -165,6 +169,9 @@ config_node_dump_real (ConfigNode *node, unsigned int indent)
buf[n] = '\0';
switch (node->node_type) {
case NODE_TYPE_NOP:
_pk_debug ("%sNOP", buf);
break;
case NODE_TYPE_TOP:
_pk_debug ("%sTOP", buf);
break;
......@@ -210,6 +217,8 @@ config_node_unref (ConfigNode *node)
GSList *i;
switch (node->node_type) {
case NODE_TYPE_NOP:
break;
case NODE_TYPE_TOP:
break;
case NODE_TYPE_MATCH:
......@@ -245,7 +254,8 @@ _start (void *data, const char *el, const char **attr)
;
state = STATE_NONE;
node = NULL;
node = config_node_new ();
node->node_type = NODE_TYPE_NOP;
switch (pd->state) {
case STATE_NONE:
......@@ -258,7 +268,6 @@ _start (void *data, const char *el, const char **attr)
goto error;
}
node = config_node_new ();
node->node_type = NODE_TYPE_TOP;
pd->pk_config->top_config_node = node;
}
......@@ -267,7 +276,6 @@ _start (void *data, const char *el, const char **attr)
case STATE_IN_MATCH:
if ((strcmp (el, "match") == 0) && (num_attr == 2)) {
node = config_node_new ();
node->node_type = NODE_TYPE_MATCH;
if (strcmp (attr[0], "action") == 0) {
node->data.node_match.match_type = MATCH_TYPE_ACTION;
......@@ -292,7 +300,6 @@ _start (void *data, const char *el, const char **attr)
} else if ((strcmp (el, "return") == 0) && (num_attr == 2)) {
node = config_node_new ();
node->node_type = NODE_TYPE_RETURN;
if (strcmp (attr[0], "result") == 0) {
......@@ -313,7 +320,6 @@ _start (void *data, const char *el, const char **attr)
node->data.node_return.result);
} else if ((strcmp (el, "define_admin_auth") == 0) && (num_attr == 2)) {
node = config_node_new ();
node->node_type = NODE_TYPE_DEFINE_ADMIN_AUTH;
if (strcmp (attr[0], "user") == 0) {
node->data.node_define_admin_auth.admin_type = POLKIT_CONFIG_ADMIN_AUTH_TYPE_USER;
......@@ -337,8 +343,13 @@ _start (void *data, const char *el, const char **attr)
break;
}
if (state == STATE_NONE || node == NULL)
goto error;
if (state == STATE_NONE || node == NULL) {
g_warning ("skipping unknown tag <%s> at line %d of %s",
el, (int) XML_GetCurrentLineNumber (pd->parser), pd->path);
syslog (LOG_ALERT, "libpolkit: skipping unknown tag <%s> at line %d of %s",
el, (int) XML_GetCurrentLineNumber (pd->parser), pd->path);
state = STATE_UNKNOWN_TAG;
}
if (pd->stack_depth < 0 || pd->stack_depth >= PARSER_MAX_DEPTH) {
_pk_debug ("reached max depth?");
......@@ -442,6 +453,7 @@ polkit_config_new (const char *path, PolKitError **error)
pd.pk_config = pk_config;
pd.node_stack[0] = NULL;
pd.stack_depth = 0;
pd.path = path;
xml_res = XML_Parse (pd.parser, buf, buflen, 1);
......@@ -588,6 +600,9 @@ config_node_test (ConfigNode *node,
result = POLKIT_RESULT_UNKNOWN;
switch (node->node_type) {
case NODE_TYPE_NOP:
recurse = FALSE;
break;
case NODE_TYPE_TOP:
recurse = TRUE;
break;
......@@ -682,6 +697,9 @@ config_node_determine_admin_auth (ConfigNode *node,
result_set = FALSE;
switch (node->node_type) {
case NODE_TYPE_NOP:
recurse = FALSE;
break;
case NODE_TYPE_TOP:
recurse = TRUE;
break;
......
......@@ -35,6 +35,7 @@
#include <grp.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <expat.h>
......@@ -73,6 +74,7 @@ extern PolKitPolicyFileEntry *_polkit_policy_file_entry_new (const char *actio
enum {
STATE_NONE,
STATE_UNKNOWN_TAG,
STATE_IN_POLICY_CONFIG,
STATE_IN_ACTION,
STATE_IN_ACTION_DESCRIPTION,
......@@ -84,9 +86,15 @@ enum {
STATE_IN_ANNOTATE
};
#define PARSER_MAX_DEPTH 32
typedef struct {
XML_Parser parser;
int state;
int state_stack[PARSER_MAX_DEPTH];
int stack_depth;
const char *path;
char *action_id;
......@@ -223,11 +231,17 @@ _start (void *data, const char *el, const char **attr)
break;
}
if (state == STATE_NONE)
goto error;
if (state == STATE_NONE) {
g_warning ("skipping unknown tag <%s> at line %d of %s",
el, (int) XML_GetCurrentLineNumber (pd->parser), pd->path);
syslog (LOG_ALERT, "libpolkit: skipping unknown tag <%s> at line %d of %s",
el, (int) XML_GetCurrentLineNumber (pd->parser), pd->path);
state = STATE_UNKNOWN_TAG;
}
pd->state = state;
pd->state_stack[pd->stack_depth] = pd->state;
pd->stack_depth++;
return;
error:
XML_StopParser (pd->parser, FALSE);
......@@ -349,20 +363,12 @@ out:
static void
_end (void *data, const char *el)
{
int state;
ParserData *pd = data;
state = STATE_NONE;
g_free (pd->elem_lang);
pd->elem_lang = NULL;
switch (pd->state) {
case STATE_NONE:
break;
case STATE_IN_POLICY_CONFIG:
state = STATE_NONE;
break;
case STATE_IN_ACTION:
{
const char *policy_description;
......@@ -394,36 +400,21 @@ _end (void *data, const char *el)
policy_message);
pd->pf->entries = g_slist_prepend (pd->pf->entries, pfe);
state = STATE_IN_POLICY_CONFIG;
break;
}
case STATE_IN_ACTION_DESCRIPTION:
state = STATE_IN_ACTION;
break;
case STATE_IN_ACTION_MESSAGE:
state = STATE_IN_ACTION;
break;
case STATE_IN_DEFAULTS:
state = STATE_IN_ACTION;
break;
case STATE_IN_DEFAULTS_ALLOW_ANY:
state = STATE_IN_DEFAULTS;
break;
case STATE_IN_DEFAULTS_ALLOW_INACTIVE:
state = STATE_IN_DEFAULTS;
break;
case STATE_IN_DEFAULTS_ALLOW_ACTIVE:
state = STATE_IN_DEFAULTS;
break;
case STATE_IN_ANNOTATE:
state = STATE_IN_ACTION;
break;
default:
break;
}
pd->state = state;
--pd->stack_depth;
if (pd->stack_depth < 0 || pd->stack_depth >= PARSER_MAX_DEPTH) {
_pk_debug ("reached max depth?");
goto error;
}
if (pd->stack_depth > 0)
pd->state = pd->state_stack[pd->stack_depth - 1];
else
pd->state = STATE_NONE;
return;
error:
......@@ -474,7 +465,9 @@ polkit_policy_file_new (const char *path, polkit_bool_t load_descriptions, PolKi
/* clear parser data */
memset (&pd, 0, sizeof (ParserData));
pd.path = path;
pd.parser = XML_ParserCreate (NULL);
pd.stack_depth = 0;
if (pd.parser == NULL) {
polkit_error_set_error (error, POLKIT_ERROR_OUT_OF_MEMORY,
"Cannot load PolicyKit policy file at '%s': %s",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment