add support for an /etc/PolicyKit/PolicyKit.conf config file
authorDavid Zeuthen <davidz@redhat.com>
Tue, 24 Jul 2007 02:22:38 +0000 (22:22 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Tue, 24 Jul 2007 02:22:38 +0000 (22:22 -0400)
With this, system administrators can override policy. Partial support,
more to come (including manual pages and documentation) later.

data/Makefile.am
polkit-dbus/Makefile.am
polkit-grant/Makefile.am
polkit-grant/polkit-grant-helper.c
polkit/Makefile.am
polkit/polkit-config.c [new file with mode: 0644]
polkit/polkit-config.h [new file with mode: 0644]
polkit/polkit-context.c
polkit/polkit-grant-database.c [moved from polkit-grant/polkit-grant-database.c with 98% similarity]
polkit/polkit-grant-database.h [moved from polkit-grant/polkit-grant-database.h with 100% similarity]

index 0de382e..8ff233c 100644 (file)
@@ -6,9 +6,24 @@ pam_DATA = polkit
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = polkit.pc polkit-dbus.pc polkit-grant.pc
 
-DISTCLEANFILES = polkit.pc polkit-dbus.pc polkit-grant.pc
+confdir = $(sysconfdir)/PolicyKit
+conf_DATA = PolicyKit.conf
 
-EXTRA_DIST = polkit.in polkit.pc.in polkit-dbus.pc.in polkit-grant.pc.in
+dtddir = $(datadir)/PolicyKit
+dtd_DATA = config.dtd
+
+DISTCLEANFILES = polkit.pc polkit-dbus.pc polkit-grant.pc PolicyKit.conf
+
+EXTRA_DIST = polkit.in polkit.pc.in polkit-dbus.pc.in polkit-grant.pc.in PolicyKit.conf.in
 
 clean-local :
        rm -f *~
+
+PolicyKit.conf: PolicyKit.conf.in Makefile
+       $(edit) $< >$@
+
+edit = sed \
+       -e 's|@docdir[@]|$(docdir)|g' \
+       -e 's|@sbindir[@]|$(sbindir)|g' \
+       -e 's|@sysconfdir[@]|$(sysconfdir)|g' \
+       -e 's|@datadir[@]|$(datadir)|g'
index 0cee725..3b16b60 100644 (file)
@@ -22,7 +22,7 @@ libpolkit_dbusinclude_HEADERS =                               \
 libpolkit_dbus_la_SOURCES =                                    \
        polkit-dbus.h           polkit-dbus.c
 
-libpolkit_dbus_la_LIBADD = @DBUS_LIBS@ $(top_builddir)/polkit/libpolkit.la
+libpolkit_dbus_la_LIBADD = @DBUS_LIBS@ $(top_builddir)/polkit/libpolkit.la $(SELINUX_LIBS)
 
 libpolkit_dbus_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
index 4e1bc1c..9dc626c 100644 (file)
@@ -12,11 +12,6 @@ INCLUDES = \
        -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
        @GLIB_CFLAGS@ @DBUS_CFLAGS@
 
-noinst_LTLIBRARIES=libpolkit-grant-private.la
-
-libpolkit_grant_private_la_SOURCES =                           \
-       polkit-grant-database.h polkit-grant-database.c
-
 lib_LTLIBRARIES=libpolkit-grant.la
 
 libpolkit_grantincludedir=$(includedir)/PolicyKit/polkit-grant
@@ -34,7 +29,7 @@ libpolkit_grant_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE
 libexec_PROGRAMS = polkit-grant-helper
 
 polkit_grant_helper_SOURCES = polkit-grant-helper.c
-polkit_grant_helper_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @AUTH_LIBS@ $(top_builddir)/polkit/libpolkit.la $(top_builddir)/polkit-dbus/libpolkit-dbus.la $(top_builddir)/polkit-grant/libpolkit-grant-private.la
+polkit_grant_helper_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @AUTH_LIBS@ $(top_builddir)/polkit/libpolkit.la $(top_builddir)/polkit-dbus/libpolkit-dbus.la $(top_builddir)/polkit/libpolkit-grant-private.la
 
 polkit_grant_alwaysdir = $(localstatedir)/lib/PolicyKit
 dist_polkit_grant_always_DATA =
index 8d12f40..f428dab 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <polkit-dbus/polkit-dbus.h>
 
-#include "polkit-grant-database.h"
+#include <polkit/polkit-grant-database.h>
 
 static int
 conversation_function (int n,
index 36fae4c..d0bbd1f 100644 (file)
@@ -6,13 +6,19 @@ INCLUDES = \
        -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
        -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
        -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
-       -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
+       -DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \
        -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
        -DPACKAGE_LIB_DIR=\""$(libdir)"\" \
        -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
        -DPOLKIT_COMPILATION \
        @GLIB_CFLAGS@
 
+
+noinst_LTLIBRARIES=libpolkit-grant-private.la
+
+libpolkit_grant_private_la_SOURCES =                           \
+       polkit-grant-database.h polkit-grant-database.c
+
 lib_LTLIBRARIES=libpolkit.la
 
 libpolkitincludedir=$(includedir)/PolicyKit/polkit
@@ -47,9 +53,10 @@ libpolkit_la_SOURCES =                                                       \
        polkit-policy-cache.h           polkit-policy-cache.c           \
        polkit-policy-default.h         polkit-policy-default.c         \
        polkit-debug.h                  polkit-debug.c                  \
-       polkit-utils.h                  polkit-utils.c
+       polkit-utils.h                  polkit-utils.c                  \
+       polkit-config.h                 polkit-config.c
 
-libpolkit_la_LIBADD = @GLIB_LIBS@ @EXPAT_LIBS@ -ldl
+libpolkit_la_LIBADD = @GLIB_LIBS@ @EXPAT_LIBS@ libpolkit-grant-private.la
 
 libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
@@ -60,5 +67,5 @@ clean-local :
 # for config file changes.
 install-data-local:
        touch $(DESTDIR)$(localstatedir)/lib/PolicyKit/reload
-       -chmod 700 $(DESTDIR)$(localstatedir)/lib/PolicyKit/reload
+       -chmod 755 $(DESTDIR)$(localstatedir)/lib/PolicyKit/reload
 
diff --git a/polkit/polkit-config.c b/polkit/polkit-config.c
new file mode 100644 (file)
index 0000000..aff9fb4
--- /dev/null
@@ -0,0 +1,536 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/***************************************************************************
+ *
+ * polkit-config.h : Configuration file
+ *
+ * Copyright (C) 2007 David Zeuthen, <david@fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307         USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/inotify.h>
+#include <regex.h>
+
+#include <expat.h>
+
+#include <glib.h>
+#include "polkit-config.h"
+#include "polkit-debug.h"
+#include "polkit-error.h"
+
+enum {
+        STATE_NONE,
+        STATE_IN_CONFIG,
+        STATE_IN_MATCH,
+        STATE_IN_RETURN,
+};
+
+struct ConfigNode;
+typedef struct ConfigNode ConfigNode;
+
+struct PolKitConfig
+{
+        int refcount;
+        ConfigNode *top_config_node;
+};
+
+#define PARSER_MAX_DEPTH 32
+
+typedef struct {
+        XML_Parser parser;
+        int state;
+        PolKitConfig *pk_config;
+
+        int state_stack[PARSER_MAX_DEPTH];
+        ConfigNode *node_stack[PARSER_MAX_DEPTH];
+
+        int stack_depth;
+} ParserData;
+
+enum {
+        NODE_TYPE_TOP,
+        NODE_TYPE_MATCH,
+        NODE_TYPE_RETURN,
+};
+
+enum {
+        MATCH_TYPE_ACTION,
+        MATCH_TYPE_USER,
+};
+
+static const char * const match_names[] = 
+{
+        "action",
+        "user",
+};
+
+struct ConfigNode
+{
+        int node_type;
+
+        union {
+
+                struct {
+                        int match_type;
+                        char *data;
+                        regex_t preq;
+                } node_match;
+
+                struct {
+                        PolKitResult result;
+                } node_return;
+
+        } data;
+
+        GSList *children;
+};
+
+static ConfigNode *
+config_node_new (void)
+{
+        ConfigNode *node;
+        node = g_new0 (ConfigNode, 1);
+        return node;
+}
+
+static void
+config_node_dump_real (ConfigNode *node, unsigned int indent)
+{
+        GSList *i;
+        unsigned int n;
+        char buf[128];
+
+        for (n = 0; n < indent && n < sizeof (buf) - 1; n++)
+                buf[n] = ' ';
+        buf[n] = '\0';
+        
+        switch (node->node_type) {
+        case NODE_TYPE_TOP:
+                _pk_debug ("%sTOP", buf);
+                break;
+        case NODE_TYPE_MATCH:
+                _pk_debug ("%sMATCH %s (%d) with '%s'", 
+                           buf, 
+                           match_names[node->data.node_match.match_type],
+                           node->data.node_match.match_type,
+                           node->data.node_match.data);
+                break;
+        case NODE_TYPE_RETURN:
+                _pk_debug ("%sRETURN %s (%d)",
+                           buf,
+                           polkit_result_to_string_representation (node->data.node_return.result),
+                           node->data.node_return.result);
+                break;
+        }
+
+        for (i = node->children; i != NULL; i = g_slist_next (i)) {
+                ConfigNode *child = i->data;
+                config_node_dump_real (child, indent + 2);
+        }
+}
+
+static void
+config_node_dump (ConfigNode *node)
+{
+        
+        config_node_dump_real (node, 0);
+}
+
+static void
+config_node_unref (ConfigNode *node)
+{
+        GSList *i;
+
+        switch (node->node_type) {
+        case NODE_TYPE_TOP:
+                break;
+        case NODE_TYPE_MATCH:
+                g_free (node->data.node_match.data);
+                regfree (&(node->data.node_match.preq));
+                break;
+        case NODE_TYPE_RETURN:
+                break;
+        }
+
+        for (i = node->children; i != NULL; i = g_slist_next (i)) {
+                ConfigNode *child = i->data;
+                config_node_unref (child);
+        }
+        g_slist_free (node->children);
+        g_free (node);
+}
+
+static void
+_start (void *data, const char *el, const char **attr)
+{
+        int state;
+        int num_attr;
+        ParserData *pd = data;
+        ConfigNode *node;
+
+        _pk_debug ("_start for node '%s'", el);
+
+        for (num_attr = 0; attr[num_attr] != NULL; num_attr++)
+                ;
+
+        state = STATE_NONE;
+        node = NULL;
+
+        switch (pd->state) {
+        case STATE_NONE:
+                if (strcmp (el, "config") == 0) {
+                        state = STATE_IN_CONFIG;
+                        _pk_debug ("parsed config node");
+
+                        if (pd->pk_config->top_config_node != NULL) {
+                                _pk_debug ("Multiple config nodes?");
+                                goto error;
+                        }
+
+                        node = config_node_new ();
+                        node->node_type = NODE_TYPE_TOP;
+                        pd->pk_config->top_config_node = node;
+                }
+                break;
+        case STATE_IN_CONFIG: /* explicit fallthrough */
+        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;
+                        } else if (strcmp (attr[0], "user") == 0) {
+                                node->data.node_match.match_type = MATCH_TYPE_USER;
+                        } else {
+                                _pk_debug ("Unknown match rule '%s'", attr[0]);
+                                goto error;
+                        }
+
+                        node->data.node_match.data = g_strdup (attr[1]);
+                        if (regcomp (&(node->data.node_match.preq), node->data.node_match.data, REG_NOSUB|REG_EXTENDED) != 0) {
+                                _pk_debug ("Invalid expression '%s'", node->data.node_match.data);
+                                goto error;
+                        }
+
+                        state = STATE_IN_MATCH;
+                        _pk_debug ("parsed match node ('%s' (%d) -> '%s')", 
+                                   attr[0], 
+                                   node->data.node_match.match_type,
+                                   node->data.node_match.data);
+
+                } 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) {
+                                PolKitResult r;
+                                if (!polkit_result_from_string_representation (attr[1], &r)) {
+                                        _pk_debug ("Unknown return result '%s'", attr[1]);
+                                        goto error;
+                                }
+                                node->data.node_return.result = r;
+                        } else {
+                                _pk_debug ("Unknown return rule '%s'", attr[0]);
+                                goto error;
+                        }
+
+                        state = STATE_IN_RETURN;
+                        _pk_debug ("parsed return node ('%s' (%d))",
+                                   attr[1],
+                                   node->data.node_return.result);
+                }
+                break;
+        }
+
+        if (state == STATE_NONE || node == NULL)
+                goto error;
+
+        if (pd->stack_depth < 0 || pd->stack_depth >= PARSER_MAX_DEPTH) {
+                _pk_debug ("reached max depth?");
+                goto error;
+        }
+        pd->state = state;
+        pd->state_stack[pd->stack_depth] = pd->state;
+        pd->node_stack[pd->stack_depth] = node;
+
+        if (pd->stack_depth > 0) {
+                pd->node_stack[pd->stack_depth - 1]->children = 
+                        g_slist_append (pd->node_stack[pd->stack_depth - 1]->children, node);
+        }
+
+        pd->stack_depth++;
+        _pk_debug ("state = %d", pd->state);
+        return;
+
+error:
+        if (node != NULL) {
+                config_node_unref (node);
+        }
+        XML_StopParser (pd->parser, FALSE);
+}
+
+static void
+_cdata (void *data, const char *s, int len)
+{
+}
+
+static void
+_end (void *data, const char *el)
+{
+        ParserData *pd = data;
+
+        _pk_debug ("_end for node '%s'", el);
+
+        --pd->stack_depth;
+        if (pd->stack_depth < 0 || pd->stack_depth >= PARSER_MAX_DEPTH) {
+                _pk_debug ("reached max depth?");
+                goto error;
+        }
+        pd->state = pd->state_stack[pd->stack_depth];
+        _pk_debug ("state = %d", pd->state);
+        return;
+error:
+        XML_StopParser (pd->parser, FALSE);
+}
+
+PolKitConfig *
+polkit_config_new (PolKitError **error)
+{
+        ParserData pd;
+        int xml_res;
+        PolKitConfig *pk_config;
+       char *buf;
+       gsize buflen;
+        GError *g_error;
+        const char *path;
+
+        /* load and parse the configuration file */
+        pk_config = NULL;
+
+        path = PACKAGE_SYSCONF_DIR "/PolicyKit/PolicyKit.conf";
+
+        g_error = NULL;
+       if (!g_file_get_contents (path, &buf, &buflen, &g_error)) {
+                polkit_error_set_error (error, POLKIT_ERROR_POLICY_FILE_INVALID,
+                                        "Cannot load PolicyKit policy file at '%s': %s",
+                                        path,
+                                        g_error->message);
+                g_error_free (g_error);
+               goto error;
+        }
+
+        pd.parser = XML_ParserCreate (NULL);
+        if (pd.parser == NULL) {
+                polkit_error_set_error (error, POLKIT_ERROR_OUT_OF_MEMORY,
+                                        "Cannot load PolicyKit policy file at '%s': %s",
+                                        path,
+                                        "No memory for parser");
+                goto error;
+        }
+       XML_SetUserData (pd.parser, &pd);
+       XML_SetElementHandler (pd.parser, _start, _end);
+       XML_SetCharacterDataHandler (pd.parser, _cdata);
+
+        pk_config = g_new0 (PolKitConfig, 1);
+        pk_config->refcount = 1;
+
+        pd.state = STATE_NONE;
+        pd.pk_config = pk_config;
+        pd.node_stack[0] = NULL;
+        pd.stack_depth = 0;
+
+        xml_res = XML_Parse (pd.parser, buf, buflen, 1);
+
+       if (xml_res == 0) {
+                polkit_error_set_error (error, POLKIT_ERROR_POLICY_FILE_INVALID,
+                                        "%s:%d: parse error: %s",
+                                        path, 
+                                        (int) XML_GetCurrentLineNumber (pd.parser),
+                                        XML_ErrorString (XML_GetErrorCode (pd.parser)));
+
+               XML_ParserFree (pd.parser);
+               g_free (buf);
+               goto error;
+       }
+       XML_ParserFree (pd.parser);
+       g_free (buf);
+
+        _pk_debug ("Loaded configuration file %s", path);
+
+        if (pk_config->top_config_node != NULL)
+                config_node_dump (pk_config->top_config_node);
+
+        return pk_config;
+
+error:
+        if (pk_config != NULL)
+                polkit_config_unref (pk_config);
+        return NULL;
+}
+
+PolKitConfig *
+polkit_config_ref (PolKitConfig *pk_config)
+{
+        g_return_val_if_fail (pk_config != NULL, pk_config);
+        pk_config->refcount++;
+        return pk_config;
+}
+
+void
+polkit_config_unref (PolKitConfig *pk_config)
+{
+        g_return_if_fail (pk_config != NULL);
+        pk_config->refcount--;
+        if (pk_config->refcount > 0) 
+                return;
+
+        if (pk_config->top_config_node != NULL)
+                config_node_unref (pk_config->top_config_node);
+
+        g_free (pk_config);
+}
+
+/* exactly one of the parameters caller and session must be NULL */
+static PolKitResult
+config_node_test (ConfigNode *node, PolKitAction *action, PolKitCaller *caller, PolKitSession *session)
+{
+        gboolean match;
+        gboolean recurse;
+        PolKitResult result;
+        char *str;
+        char *str1;
+        char *str2;
+        uid_t uid;
+
+        result = POLKIT_RESULT_UNKNOWN_ACTION;
+        recurse = FALSE;
+
+        switch (node->node_type) {
+        case NODE_TYPE_TOP:
+                recurse = TRUE;
+                break;
+        case NODE_TYPE_MATCH:
+                match = FALSE;
+                str1 = NULL;
+                str2 = NULL;
+                switch (node->data.node_match.match_type) {
+                case MATCH_TYPE_ACTION:
+                        if (!polkit_action_get_action_id (action, &str))
+                                goto out;
+                        str1 = g_strdup (str);
+                        break;
+                case MATCH_TYPE_USER:
+                        if (caller != NULL) {
+                                if (!polkit_caller_get_uid (caller, &uid))
+                                        goto out;
+                        } else if (session != NULL) {
+                                if (!polkit_session_get_uid (session, &uid))
+                                        goto out;
+                        } else
+                                goto out;
+
+                        str1 = g_strdup_printf ("%d", uid);
+                        {
+                                struct passwd pd;
+                                struct passwd* pwdptr=&pd;
+                                struct passwd* tempPwdPtr;
+                                char pwdbuffer[256];
+                                int  pwdlinelen = sizeof(pwdbuffer);
+
+                                if ((getpwuid_r (uid, pwdptr, pwdbuffer, pwdlinelen, &tempPwdPtr)) !=0 )
+                                        goto out;
+                                str2 = g_strdup (pd.pw_name);
+                        }
+                        break;
+                }
+
+                if (str1 != NULL) {
+                        if (regexec (&(node->data.node_match.preq), str1, 0, NULL, 0) == 0)
+                                match = TRUE;
+                }
+                if (!match && str2 != NULL) {
+                        if (regexec (&(node->data.node_match.preq), str2, 0, NULL, 0) == 0)
+                                match = TRUE;
+                }
+              
+
+                if (match)
+                        recurse = TRUE;
+
+                g_free (str1);
+                g_free (str2);
+                break;
+        case NODE_TYPE_RETURN:
+                result = node->data.node_return.result;
+                break;
+        }
+
+        if (recurse) {
+                GSList *i;
+                for (i = node->children; i != NULL; i = g_slist_next (i)) {
+                        ConfigNode *child_node = i->data;
+                        result = config_node_test (child_node, action, caller, session);
+                        if (result != POLKIT_RESULT_UNKNOWN_ACTION) {
+                                goto out;
+                        }
+                }
+        }
+
+out:
+        return result;
+}
+
+PolKitResult
+polkit_config_can_session_do_action (PolKitConfig   *pk_config,
+                                     PolKitAction   *action,
+                                     PolKitSession  *session)
+{
+        PolKitResult result;
+        if (pk_config->top_config_node != NULL)
+                result = config_node_test (pk_config->top_config_node, action, NULL, session);
+        else
+                result = POLKIT_RESULT_UNKNOWN_ACTION;
+        return result;
+}
+
+PolKitResult
+polkit_config_can_caller_do_action (PolKitConfig   *pk_config,
+                                    PolKitAction   *action,
+                                    PolKitCaller   *caller)
+{
+        PolKitResult result;
+        if (pk_config->top_config_node != NULL)
+                result = config_node_test (pk_config->top_config_node, action, caller, NULL);
+        else
+                result = POLKIT_RESULT_UNKNOWN_ACTION;
+        return result;
+}
diff --git a/polkit/polkit-config.h b/polkit/polkit-config.h
new file mode 100644 (file)
index 0000000..24f5658
--- /dev/null
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/***************************************************************************
+ *
+ * polkit-config.h : Configuration file
+ *
+ * Copyright (C) 2007 David Zeuthen, <david@fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#if !defined (POLKIT_COMPILATION) && !defined(_POLKIT_INSIDE_POLKIT_H)
+#error "Only <polkit/polkit.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef POLKIT_CONFIG_H
+#define POLKIT_CONFIG_H
+
+#include <polkit/polkit-error.h>
+#include <polkit/polkit-types.h>
+#include <polkit/polkit-result.h>
+#include <polkit/polkit-context.h>
+#include <polkit/polkit-action.h>
+#include <polkit/polkit-session.h>
+#include <polkit/polkit-caller.h>
+
+struct PolKitConfig;
+typedef struct PolKitConfig PolKitConfig;
+
+PolKitConfig  *polkit_config_new                    (PolKitError **error);
+PolKitConfig  *polkit_config_ref                    (PolKitConfig *pk_config);
+void           polkit_config_unref                  (PolKitConfig *pk_config);
+
+PolKitResult
+polkit_config_can_session_do_action                 (PolKitConfig   *pk_config,
+                                                     PolKitAction    *action,
+                                                     PolKitSession   *session);
+
+PolKitResult
+polkit_config_can_caller_do_action                  (PolKitConfig   *pk_config,
+                                                     PolKitAction    *action,
+                                                     PolKitCaller    *caller);
+
+#endif /* POLKIT_CONFIG_H */
+
+
index 19ba81d..7224b76 100644 (file)
 #include <sys/inotify.h>
 
 #include <glib.h>
+#include "polkit-config.h"
 #include "polkit-debug.h"
 #include "polkit-context.h"
 #include "polkit-policy-cache.h"
+#include "polkit-grant-database.h"
 
 /**
  * SECTION:polkit
@@ -75,11 +77,12 @@ struct PolKitContext
 
         PolKitPolicyCache *priv_cache;
 
+        PolKitConfig *config;
+
         polkit_bool_t load_descriptions;
 
         int inotify_fd;
         int inotify_fd_watch_id;
-
         int inotify_reload_wd;
 };
 
@@ -122,7 +125,17 @@ polkit_context_init (PolKitContext *pk_context, PolKitError **error)
         }
         _pk_debug ("Using policy files from directory %s", pk_context->policy_dir);
 
-        /* we don't populate the cache until it's needed.. */
+        /* NOTE: we don't populate the cache until it's needed.. */
+
+        /* Load configuration file */
+        pk_context->config = polkit_config_new (error);
+        if (pk_context->config == NULL) {
+                _pk_debug ("failed to load configuration file: %s", strerror (errno));
+                /* TODO: set error. TODO: should we error out if the config file is bad?!? Or recover and go without a config file? */
+                goto error;
+        }
+
+        /* if the client provided watch functions, use inotify to create a watch on /var/lib/PolicyKit/reload */
         if (pk_context->io_add_watch_func != NULL) {
                 pk_context->inotify_fd = inotify_init ();
                 if (pk_context->inotify_fd < 0) {
@@ -131,12 +144,11 @@ polkit_context_init (PolKitContext *pk_context, PolKitError **error)
                         goto error;
                 }
 
-                /* create a watch on /var/lib/PolicyKit/reload */
                 pk_context->inotify_reload_wd = inotify_add_watch (pk_context->inotify_fd, 
-                                                                   PACKAGE_LOCALSTATEDIR "/lib/PolicyKit/reload", 
+                                                                   PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/reload", 
                                                                    IN_MODIFY | IN_CREATE | IN_ATTRIB);
                 if (pk_context->inotify_reload_wd < 0) {
-                        _pk_debug ("failed to add watch on file '" PACKAGE_LOCALSTATEDIR "/lib/PolicyKit/reload': %s",
+                        _pk_debug ("failed to add watch on file '" PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/reload': %s",
                                    strerror (errno));
                         /* TODO: set error */
                         goto error;
@@ -371,10 +383,11 @@ polkit_context_can_session_do_action (PolKitContext   *pk_context,
 {
         PolKitPolicyCache *cache;
         PolKitPolicyFileEntry *pfe;
-        PolKitResult current_result;
+        PolKitPolicyDefault *policy_default;
+        PolKitResult result;
 
-        current_result = POLKIT_RESULT_NO;
-        g_return_val_if_fail (pk_context != NULL, current_result);
+        result = POLKIT_RESULT_NO;
+        g_return_val_if_fail (pk_context != NULL, result);
 
         if (action == NULL || session == NULL)
                 goto out;
@@ -401,81 +414,33 @@ polkit_context_can_session_do_action (PolKitContext   *pk_context,
                 } else {
                         g_warning ("no action with name '%s'", action_name);
                 }
-                current_result = POLKIT_RESULT_UNKNOWN_ACTION;
+                result = POLKIT_RESULT_UNKNOWN_ACTION;
                 goto out;
         }
 
         polkit_policy_file_entry_debug (pfe);
 
-        current_result = POLKIT_RESULT_UNKNOWN_ACTION;
-
-#if 0
-        /* visit modules */
-        for (i = pk_context->modules; i != NULL; i = g_slist_next (i)) {
-                PolKitModuleInterface *module_interface = i->data;
-                PolKitModuleCanSessionDoAction func;
-
-                func = polkit_module_get_func_can_session_do_action (module_interface);
-                if (func != NULL) {
-                        PolKitModuleControl module_control;
-                        PolKitResult module_result;
-
-                        _pk_debug ("Asking module '%s'", polkit_module_get_name (module_interface));
+        /* check if the config file specifies a result */
+        result = polkit_config_can_session_do_action (pk_context->config, action, session);
+        if (result != POLKIT_RESULT_UNKNOWN_ACTION)
+                goto found;
 
-                        module_control = polkit_module_interface_get_control (module_interface);
-
-                        if (polkit_module_interface_check_builtin_confinement_for_session (
-                                    module_interface,
-                                    pk_context,
-                                    action,
-                                    session)) {
-                                /* module is confined by built-in options */
-                                module_result = POLKIT_RESULT_UNKNOWN_ACTION;
-                                _pk_debug ("Module '%s' confined by built-in's", 
-                                           polkit_module_get_name (module_interface));
-                        } else {
-                                module_result = func (module_interface,
-                                                      pk_context,
-                                                      action, 
-                                                      session);
-                        }
-
-                        /* if a module returns _UNKNOWN_ACTION, it means that it doesn't
-                         * have an opinion about the query; e.g. polkit-module-allow-all(8)
-                         * will return this if it's confined to only consider certain actions
-                         * or certain users.
-                         */
-                        if (module_result != POLKIT_RESULT_UNKNOWN_ACTION) {
-
-                                if (current_control == POLKIT_MODULE_CONTROL_ADVISE &&
-                                    module_control == POLKIT_MODULE_CONTROL_ADVISE) {
-
-                                        /* take the less strict result */
-                                        if (current_result < module_result) {
-                                                current_result = module_result;
-                                        }
-
-                                } else if (current_control == POLKIT_MODULE_CONTROL_ADVISE &&
-                                           module_control == POLKIT_MODULE_CONTROL_MANDATORY) {
-                                        
-                                        /* here we just override */
-                                        current_result = module_result;
-
-                                        /* we are now in mandatory mode */
-                                        current_control = POLKIT_MODULE_CONTROL_MANDATORY;
-                                }
-                        }
-                }
+        /* if no, just use the defaults */
+        policy_default = polkit_policy_file_entry_get_default (pfe);
+        if (policy_default == NULL) {
+                g_warning ("no default policy for action!");
+                goto out;
         }
-#endif
+        result = polkit_policy_default_can_session_do_action (policy_default, action, session);
 
+found:
         /* Never return UNKNOWN_ACTION to user */
-        if (current_result == POLKIT_RESULT_UNKNOWN_ACTION)
-                current_result = POLKIT_RESULT_NO;
+        if (result == POLKIT_RESULT_UNKNOWN_ACTION)
+                result = POLKIT_RESULT_NO;
 
 out:
-        _pk_debug ("... result was %s", polkit_result_to_string_representation (current_result));
-        return current_result;
+        _pk_debug ("... result was %s", polkit_result_to_string_representation (result));
+        return result;
 }
 
 /**
@@ -496,10 +461,11 @@ polkit_context_can_caller_do_action (PolKitContext   *pk_context,
 {
         PolKitPolicyCache *cache;
         PolKitPolicyFileEntry *pfe;
-        PolKitResult current_result;
+        PolKitResult result;
+        PolKitPolicyDefault *policy_default;
 
-        current_result = POLKIT_RESULT_NO;
-        g_return_val_if_fail (pk_context != NULL, current_result);
+        result = POLKIT_RESULT_NO;
+        g_return_val_if_fail (pk_context != NULL, result);
 
         if (action == NULL || caller == NULL)
                 goto out;
@@ -526,78 +492,36 @@ polkit_context_can_caller_do_action (PolKitContext   *pk_context,
                 } else {
                         g_warning ("no action with name '%s'", action_name);
                 }
-                current_result = POLKIT_RESULT_UNKNOWN_ACTION;
+                result = POLKIT_RESULT_UNKNOWN_ACTION;
                 goto out;
         }
 
         polkit_policy_file_entry_debug (pfe);
 
-        current_result = POLKIT_RESULT_UNKNOWN_ACTION;
-
-#if 0
-        /* visit modules */
-        for (i = pk_context->modules; i != NULL; i = g_slist_next (i)) {
-                PolKitModuleInterface *module_interface = i->data;
-                PolKitModuleCanCallerDoAction func;
-
-                func = polkit_module_get_func_can_caller_do_action (module_interface);
-                if (func != NULL) {
-                        PolKitModuleControl module_control;
-                        PolKitResult module_result;
+        /* first, check if the grant database specifies a result */
+        result = _polkit_grantdb_check_can_caller_do_action (pk_context, action, caller);
+        if (result != POLKIT_RESULT_UNKNOWN_ACTION)
+                goto found;
 
-                        _pk_debug ("Asking module '%s'", polkit_module_get_name (module_interface));
-
-                        module_control = polkit_module_interface_get_control (module_interface);
-
-                        if (polkit_module_interface_check_builtin_confinement_for_caller (
-                                    module_interface,
-                                    pk_context,
-                                    action,
-                                    caller)) {
-                                /* module is confined by built-in options */
-                                module_result = POLKIT_RESULT_UNKNOWN_ACTION;
-                                _pk_debug ("Module '%s' confined by built-in's", 
-                                           polkit_module_get_name (module_interface));
-                        } else {
-                                module_result = func (module_interface,
-                                                      pk_context,
-                                                      action, 
-                                                      caller);
-                        }
+        /* second, check if the config file specifies a result */
+        result = polkit_config_can_caller_do_action (pk_context->config, action, caller);
+        if (result != POLKIT_RESULT_UNKNOWN_ACTION)
+                goto found;
 
-                        /* if a module returns _UNKNOWN_ACTION, it means that it doesn't
-                         * have an opinion about the query; e.g. polkit-module-allow-all(8)
-                         * will return this if it's confined to only consider certain actions
-                         * or certain users.
-                         */
-                        if (module_result != POLKIT_RESULT_UNKNOWN_ACTION) {
-
-                                if (current_control == POLKIT_MODULE_CONTROL_ADVISE &&
-                                    module_control == POLKIT_MODULE_CONTROL_ADVISE) {
-
-                                        /* take the less strict result */
-                                        if (current_result < module_result) {
-                                                current_result = module_result;
-                                        }
-
-                                } else if (current_control == POLKIT_MODULE_CONTROL_ADVISE &&
-                                           module_control == POLKIT_MODULE_CONTROL_MANDATORY) {
-                                        
-                                        /* here we just override */
-                                        current_result = module_result;
-
-                                        /* we are now in mandatory mode */
-                                        current_control = POLKIT_MODULE_CONTROL_MANDATORY;
-                                }
-                        }
-                }
+        /* if no, just use the defaults */
+        policy_default = polkit_policy_file_entry_get_default (pfe);
+        if (policy_default == NULL) {
+                g_warning ("no default policy for action!");
+                goto out;
         }
-#endif
+        result = polkit_policy_default_can_caller_do_action (policy_default, action, caller);
+
+found:
 
         /* Never return UNKNOWN_ACTION to user */
-        if (current_result == POLKIT_RESULT_UNKNOWN_ACTION)
-                current_result = POLKIT_RESULT_NO;
+        if (result == POLKIT_RESULT_UNKNOWN_ACTION)
+                result = POLKIT_RESULT_NO;
 out:
-        _pk_debug ("... result was %s", polkit_result_to_string_representation (current_result));
-        return current_result;
+        _pk_debug ("... result was %s", polkit_result_to_string_representation (result));
+        return result;
 }
similarity index 98%
rename from polkit-grant/polkit-grant-database.c
rename to polkit/polkit-grant-database.c
index 71feea7..c936e98 100644 (file)
  *
  **************************************************************************/
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
@@ -34,7 +38,7 @@
 
 #include <glib.h>
 
-#include <polkit-grant/polkit-grant-database.h>
+#include <polkit/polkit-grant-database.h>
 
 /* TODO FIXME: this is Linux specific */
 static unsigned long long