PolicyKit: Branch 'master' - 2 commits

David Zeuthen david at kemper.freedesktop.org
Tue Jul 24 05:22:40 EEST 2007


 configure.in                       |   41 ++
 data/Makefile.am                   |   19 +
 polkit-dbus/Makefile.am            |    2 
 polkit-dbus/polkit-dbus.c          |   38 ++
 polkit-grant/Makefile.am           |    7 
 polkit-grant/polkit-grant-helper.c |    2 
 polkit/Makefile.am                 |   15 -
 polkit/polkit-config.c             |  536 +++++++++++++++++++++++++++++++++++++
 polkit/polkit-config.h             |   60 ++++
 polkit/polkit-context.c            |  206 ++++----------
 polkit/polkit-grant-database.c     |    6 
 polkit/polkit-grant-database.h     |    0 
 12 files changed, 769 insertions(+), 163 deletions(-)

New commits:
diff-tree 600bca82cfeebdcde832d330a2c896c18026bf89 (from 42a6a076f7b04522bcfa51c74f6e7f5705ea5009)
Author: David Zeuthen <davidz at redhat.com>
Date:   Mon Jul 23 22:22:38 2007 -0400

    add support for an /etc/PolicyKit/PolicyKit.conf config file
    
    With this, system administrators can override policy. Partial support,
    more to come (including manual pages and documentation) later.

diff --git a/data/Makefile.am b/data/Makefile.am
index 0de382e..8ff233c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -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'
diff --git a/polkit-dbus/Makefile.am b/polkit-dbus/Makefile.am
index 0cee725..3b16b60 100644
--- a/polkit-dbus/Makefile.am
+++ b/polkit-dbus/Makefile.am
@@ -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)
 
diff --git a/polkit-grant/Makefile.am b/polkit-grant/Makefile.am
index 4e1bc1c..9dc626c 100644
--- a/polkit-grant/Makefile.am
+++ b/polkit-grant/Makefile.am
@@ -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-in
 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 =
diff --git a/polkit-grant/polkit-grant-database.c b/polkit-grant/polkit-grant-database.c
deleted file mode 100644
index 71feea7..0000000
--- a/polkit-grant/polkit-grant-database.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/***************************************************************************
- *
- * polkit-grant-database.c : simple interface for storing and checking grants
- * 
- * (This is an internal and private interface to PolicyKit. Do not use.)
- *
- * Copyright (C) 2007 David Zeuthen, <david at fubar.dk>
- *
- * 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
- *
- **************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <glib.h>
-
-#include <polkit-grant/polkit-grant-database.h>
-
-/* TODO FIXME: this is Linux specific */
-static unsigned long long 
-get_start_time_for_pid (pid_t pid)
-{
-        char *filename;
-        char *contents;
-        gsize length;
-        unsigned long long start_time;
-        GError *error = NULL;
-        char **tokens;
-        char *p;
-        char *endp;
-
-        start_time = 0;
-        contents = NULL;
-
-        filename = g_strdup_printf ("/proc/%d/stat", pid);
-        if (filename == NULL) {
-                fprintf (stderr, "Out of memory\n");
-                goto out;
-        }
-
-        if (!g_file_get_contents (filename, &contents, &length, &error)) {
-                fprintf (stderr, "Cannot get contents of '%s': %s\n", filename, error->message);
-                g_error_free (error);
-                goto out;
-        }
-
-        /* start time is the 19th token after the '(process name)' entry */
-
-        p = strchr (contents, ')');
-        if (p == NULL) {
-                goto out;
-        }
-        p += 2; /* skip ') ' */
-        if (p - contents >= (int) length) {
-                goto out;
-        }
-
-        tokens = g_strsplit (p, " ", 0);
-        if (g_strv_length (tokens) < 20) {
-                goto out;
-        }
-
-        start_time = strtoll (tokens[19], &endp, 10);
-        if (endp == tokens[19]) {
-                goto out;
-        }
-
-        g_strfreev (tokens);
-
-out:
-        g_free (filename);
-        g_free (contents);
-        return start_time;
-}
-
-#if 0
-static polkit_bool_t
-ensure_dir (const char *file)
-{
-        char *dirname;
-        polkit_bool_t ret;
-
-        ret = FALSE;
-
-        dirname = g_path_get_dirname (file);
-        if (dirname == NULL)
-                goto out;
-
-        if (g_file_test (dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
-                /* TODO: check permissions? */
-                ret = TRUE;
-                goto out;
-        }
-
-        if (mkdir (dirname, 0570) != 0) {
-                fprintf (stderr, "Cannot create directory '%s': %s\n", dirname, strerror (errno));
-                goto out;
-        }
-
-        ret = TRUE;
-
-out:
-        return ret;
-}
-#endif
-
-static polkit_bool_t 
-_polkit_grantdb_write (const char *grant_file)
-{
-        int fd;
-        polkit_bool_t ret;
-
-        ret = FALSE;
-
-#if 0
-        if (!ensure_dir (grant_file))
-                goto out;
-#endif
-
-        fd = open (grant_file, O_CREAT | O_RDWR, 0460);
-        if (fd < 0) {
-                fprintf (stderr, "Cannot create file '%s': %s\n", grant_file, strerror (errno));
-                goto out;
-        }
-        /* Yessir, the file is empty */
-        close (fd);
-
-        ret = TRUE;
-
-out:
-        return ret;
-}
-
-polkit_bool_t 
-_polkit_grantdb_write_pid (const char *action_id, pid_t pid)
-{
-        char *grant_file;
-        polkit_bool_t ret = FALSE;
-        unsigned long long pid_start_time;
-
-        pid_start_time = get_start_time_for_pid (pid);
-        if (pid_start_time == 0)
-                goto out;
-
-        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-pid-%d@%Lu-%s.grant", 
-                                      getuid(), pid, pid_start_time, action_id);
-        if (grant_file == NULL) {
-                fprintf (stderr, "Out of memory\n");
-                goto out;
-        }
-
-        ret = _polkit_grantdb_write (grant_file);
-out:
-        return ret;
-}
-
-polkit_bool_t 
-_polkit_grantdb_write_keep_session (const char *action_id, const char *session_id)
-{
-        char *grant_file;
-        polkit_bool_t ret = FALSE;
-
-        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-session-%s-%s.grant", 
-                                      getuid(), g_basename (session_id), action_id);
-        if (grant_file == NULL) {
-                fprintf (stderr, "Out of memory\n");
-                goto out;
-        }
-
-        ret = _polkit_grantdb_write (grant_file);
-out:
-        return ret;
-}
-
-polkit_bool_t
-_polkit_grantdb_write_keep_always (const char *action_id, uid_t uid)
-{
-        char *grant_file;
-        polkit_bool_t ret = FALSE;
-
-        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/uid%d-%s.grant", 
-                                      getuid(), action_id);
-        if (grant_file == NULL) {
-                fprintf (stderr, "Out of memory\n");
-                goto out;
-        }
-
-        ret = _polkit_grantdb_write (grant_file);
-out:
-        return ret;
-}
-
-PolKitResult 
-_polkit_grantdb_check_can_caller_do_action (PolKitContext         *pk_context,
-                                            PolKitAction          *action,
-                                            PolKitCaller          *caller)
-{
-        char *grant_file;
-        PolKitResult result;
-        char *action_id;
-        uid_t invoking_user_id;
-        pid_t invoking_process_id;
-        PolKitSession *session;
-        char *session_objpath;
-        unsigned long long pid_start_time;
-
-        grant_file = NULL;
-        result = POLKIT_RESULT_UNKNOWN_ACTION;
-
-        if (caller == NULL)
-                goto out;
-
-        if (!polkit_action_get_action_id (action, &action_id))
-                goto out;
-
-        if (!polkit_caller_get_uid (caller, &invoking_user_id))
-                goto out;
-
-        if (!polkit_caller_get_pid (caller, &invoking_process_id))
-                goto out;
-
-        session_objpath = NULL;
-        if (polkit_caller_get_ck_session (caller, &session)) {
-                if (!polkit_session_get_ck_objref (session, &session_objpath))
-                        session_objpath = NULL;
-        }
-
-        pid_start_time = get_start_time_for_pid (invoking_process_id);
-        if (pid_start_time == 0)
-                goto out;
-
-        /* first check what _write_pid may have left */
-        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-pid-%d@%Lu-%s.grant", 
-                                      invoking_user_id, invoking_process_id, pid_start_time, action_id);
-        if (grant_file == NULL) {
-                fprintf (stderr, "Out of memory\n");
-                g_free (grant_file);
-                goto out;
-        }
-        if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
-                result = POLKIT_RESULT_YES;
-                g_free (grant_file);
-                goto out;
-        }
-        g_free (grant_file);
-
-        /* second, check what _keep_session may have left */
-        if (session_objpath != NULL) {
-                grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-session-%s-%s.grant", 
-                                              invoking_user_id, g_basename (session_objpath), action_id);
-                if (grant_file == NULL) {
-                        fprintf (stderr, "Out of memory\n");
-                        g_free (grant_file);
-                        goto out;
-                }
-                if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
-                        result = POLKIT_RESULT_YES;
-                        g_free (grant_file);
-                        goto out;
-                }
-                g_free (grant_file);
-        }
-
-        /* finally, check what _keep_always may have left */
-        if (session_objpath != NULL) {
-                grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/uid%d-%s.grant", 
-                                              invoking_user_id, action_id);
-                if (grant_file == NULL) {
-                        fprintf (stderr, "Out of memory\n");
-                        g_free (grant_file);
-                        goto out;
-                }
-                if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
-                        result = POLKIT_RESULT_YES;
-                        g_free (grant_file);
-                        goto out;
-                }
-                g_free (grant_file);
-        }
-
-out:
-        return result;
-}
diff --git a/polkit-grant/polkit-grant-database.h b/polkit-grant/polkit-grant-database.h
deleted file mode 100644
index dd53e8e..0000000
--- a/polkit-grant/polkit-grant-database.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/***************************************************************************
- *
- * polkit-grant-database.h : simple interface for storing and checking grants
- * 
- * (This is an internal and private interface to PolicyKit. Do not use.)
- *
- * Copyright (C) 2007 David Zeuthen, <david at fubar.dk>
- *
- * 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
- *
- **************************************************************************/
-
-#ifndef POLKIT_GRANT_DATABASE_H
-#define POLKIT_GRANT_DATABASE_H
-
-#include <polkit/polkit.h>
-
-PolKitResult _polkit_grantdb_check_can_caller_do_action (PolKitContext         *pk_context,
-                                                         PolKitAction          *action,
-                                                         PolKitCaller          *caller);
-
-polkit_bool_t _polkit_grantdb_write_keep_always (const char *action_id, uid_t uid);
-
-polkit_bool_t _polkit_grantdb_write_keep_session (const char *action_id, const char *session_id);
-
-polkit_bool_t _polkit_grantdb_write_pid (const char *action_id, pid_t pid);
-
-#endif /* POLKIT_GRANT_DATABASE_H */
diff --git a/polkit-grant/polkit-grant-helper.c b/polkit-grant/polkit-grant-helper.c
index 8d12f40..f428dab 100644
--- a/polkit-grant/polkit-grant-helper.c
+++ b/polkit-grant/polkit-grant-helper.c
@@ -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,
diff --git a/polkit/Makefile.am b/polkit/Makefile.am
index 36fae4c..d0bbd1f 100644
--- a/polkit/Makefile.am
+++ b/polkit/Makefile.am
@@ -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
index 0000000..aff9fb4
--- /dev/null
+++ b/polkit/polkit-config.c
@@ -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 at 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
index 0000000..24f5658
--- /dev/null
+++ b/polkit/polkit-config.h
@@ -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 at 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 */
+
+
diff --git a/polkit/polkit-context.c b/polkit/polkit-context.c
index 19ba81d..7224b76 100644
--- a/polkit/polkit-context.c
+++ b/polkit/polkit-context.c
@@ -38,9 +38,11 @@
 #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_c
         }
         _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_c
                         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 (Po
 {
         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 (Po
                 } 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));
-
-                        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;
-                                }
-                        }
-                }
+        /* 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;
+
+        /* 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 (Pol
 {
         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 (Pol
                 } 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;
-
-                        _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);
-                        }
-
-                        /* 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;
-                                }
-                        }
-                }
+        /* 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;
+
+        /* 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 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;
 }
diff --git a/polkit/polkit-grant-database.c b/polkit/polkit-grant-database.c
new file mode 100644
index 0000000..c936e98
--- /dev/null
+++ b/polkit/polkit-grant-database.c
@@ -0,0 +1,307 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/***************************************************************************
+ *
+ * polkit-grant-database.c : simple interface for storing and checking grants
+ * 
+ * (This is an internal and private interface to PolicyKit. Do not use.)
+ *
+ * Copyright (C) 2007 David Zeuthen, <david at fubar.dk>
+ *
+ * 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 <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <polkit/polkit-grant-database.h>
+
+/* TODO FIXME: this is Linux specific */
+static unsigned long long 
+get_start_time_for_pid (pid_t pid)
+{
+        char *filename;
+        char *contents;
+        gsize length;
+        unsigned long long start_time;
+        GError *error = NULL;
+        char **tokens;
+        char *p;
+        char *endp;
+
+        start_time = 0;
+        contents = NULL;
+
+        filename = g_strdup_printf ("/proc/%d/stat", pid);
+        if (filename == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                goto out;
+        }
+
+        if (!g_file_get_contents (filename, &contents, &length, &error)) {
+                fprintf (stderr, "Cannot get contents of '%s': %s\n", filename, error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* start time is the 19th token after the '(process name)' entry */
+
+        p = strchr (contents, ')');
+        if (p == NULL) {
+                goto out;
+        }
+        p += 2; /* skip ') ' */
+        if (p - contents >= (int) length) {
+                goto out;
+        }
+
+        tokens = g_strsplit (p, " ", 0);
+        if (g_strv_length (tokens) < 20) {
+                goto out;
+        }
+
+        start_time = strtoll (tokens[19], &endp, 10);
+        if (endp == tokens[19]) {
+                goto out;
+        }
+
+        g_strfreev (tokens);
+
+out:
+        g_free (filename);
+        g_free (contents);
+        return start_time;
+}
+
+#if 0
+static polkit_bool_t
+ensure_dir (const char *file)
+{
+        char *dirname;
+        polkit_bool_t ret;
+
+        ret = FALSE;
+
+        dirname = g_path_get_dirname (file);
+        if (dirname == NULL)
+                goto out;
+
+        if (g_file_test (dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+                /* TODO: check permissions? */
+                ret = TRUE;
+                goto out;
+        }
+
+        if (mkdir (dirname, 0570) != 0) {
+                fprintf (stderr, "Cannot create directory '%s': %s\n", dirname, strerror (errno));
+                goto out;
+        }
+
+        ret = TRUE;
+
+out:
+        return ret;
+}
+#endif
+
+static polkit_bool_t 
+_polkit_grantdb_write (const char *grant_file)
+{
+        int fd;
+        polkit_bool_t ret;
+
+        ret = FALSE;
+
+#if 0
+        if (!ensure_dir (grant_file))
+                goto out;
+#endif
+
+        fd = open (grant_file, O_CREAT | O_RDWR, 0460);
+        if (fd < 0) {
+                fprintf (stderr, "Cannot create file '%s': %s\n", grant_file, strerror (errno));
+                goto out;
+        }
+        /* Yessir, the file is empty */
+        close (fd);
+
+        ret = TRUE;
+
+out:
+        return ret;
+}
+
+polkit_bool_t 
+_polkit_grantdb_write_pid (const char *action_id, pid_t pid)
+{
+        char *grant_file;
+        polkit_bool_t ret = FALSE;
+        unsigned long long pid_start_time;
+
+        pid_start_time = get_start_time_for_pid (pid);
+        if (pid_start_time == 0)
+                goto out;
+
+        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-pid-%d@%Lu-%s.grant", 
+                                      getuid(), pid, pid_start_time, action_id);
+        if (grant_file == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                goto out;
+        }
+
+        ret = _polkit_grantdb_write (grant_file);
+out:
+        return ret;
+}
+
+polkit_bool_t 
+_polkit_grantdb_write_keep_session (const char *action_id, const char *session_id)
+{
+        char *grant_file;
+        polkit_bool_t ret = FALSE;
+
+        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-session-%s-%s.grant", 
+                                      getuid(), g_basename (session_id), action_id);
+        if (grant_file == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                goto out;
+        }
+
+        ret = _polkit_grantdb_write (grant_file);
+out:
+        return ret;
+}
+
+polkit_bool_t
+_polkit_grantdb_write_keep_always (const char *action_id, uid_t uid)
+{
+        char *grant_file;
+        polkit_bool_t ret = FALSE;
+
+        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/uid%d-%s.grant", 
+                                      getuid(), action_id);
+        if (grant_file == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                goto out;
+        }
+
+        ret = _polkit_grantdb_write (grant_file);
+out:
+        return ret;
+}
+
+PolKitResult 
+_polkit_grantdb_check_can_caller_do_action (PolKitContext         *pk_context,
+                                            PolKitAction          *action,
+                                            PolKitCaller          *caller)
+{
+        char *grant_file;
+        PolKitResult result;
+        char *action_id;
+        uid_t invoking_user_id;
+        pid_t invoking_process_id;
+        PolKitSession *session;
+        char *session_objpath;
+        unsigned long long pid_start_time;
+
+        grant_file = NULL;
+        result = POLKIT_RESULT_UNKNOWN_ACTION;
+
+        if (caller == NULL)
+                goto out;
+
+        if (!polkit_action_get_action_id (action, &action_id))
+                goto out;
+
+        if (!polkit_caller_get_uid (caller, &invoking_user_id))
+                goto out;
+
+        if (!polkit_caller_get_pid (caller, &invoking_process_id))
+                goto out;
+
+        session_objpath = NULL;
+        if (polkit_caller_get_ck_session (caller, &session)) {
+                if (!polkit_session_get_ck_objref (session, &session_objpath))
+                        session_objpath = NULL;
+        }
+
+        pid_start_time = get_start_time_for_pid (invoking_process_id);
+        if (pid_start_time == 0)
+                goto out;
+
+        /* first check what _write_pid may have left */
+        grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-pid-%d@%Lu-%s.grant", 
+                                      invoking_user_id, invoking_process_id, pid_start_time, action_id);
+        if (grant_file == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                g_free (grant_file);
+                goto out;
+        }
+        if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
+                result = POLKIT_RESULT_YES;
+                g_free (grant_file);
+                goto out;
+        }
+        g_free (grant_file);
+
+        /* second, check what _keep_session may have left */
+        if (session_objpath != NULL) {
+                grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/run/PolicyKit/uid%d-session-%s-%s.grant", 
+                                              invoking_user_id, g_basename (session_objpath), action_id);
+                if (grant_file == NULL) {
+                        fprintf (stderr, "Out of memory\n");
+                        g_free (grant_file);
+                        goto out;
+                }
+                if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
+                        result = POLKIT_RESULT_YES;
+                        g_free (grant_file);
+                        goto out;
+                }
+                g_free (grant_file);
+        }
+
+        /* finally, check what _keep_always may have left */
+        if (session_objpath != NULL) {
+                grant_file = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit/uid%d-%s.grant", 
+                                              invoking_user_id, action_id);
+                if (grant_file == NULL) {
+                        fprintf (stderr, "Out of memory\n");
+                        g_free (grant_file);
+                        goto out;
+                }
+                if (g_file_test (grant_file, G_FILE_TEST_EXISTS)) {
+                        result = POLKIT_RESULT_YES;
+                        g_free (grant_file);
+                        goto out;
+                }
+                g_free (grant_file);
+        }
+
+out:
+        return result;
+}
diff --git a/polkit/polkit-grant-database.h b/polkit/polkit-grant-database.h
new file mode 100644
index 0000000..dd53e8e
--- /dev/null
+++ b/polkit/polkit-grant-database.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/***************************************************************************
+ *
+ * polkit-grant-database.h : simple interface for storing and checking grants
+ * 
+ * (This is an internal and private interface to PolicyKit. Do not use.)
+ *
+ * Copyright (C) 2007 David Zeuthen, <david at fubar.dk>
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef POLKIT_GRANT_DATABASE_H
+#define POLKIT_GRANT_DATABASE_H
+
+#include <polkit/polkit.h>
+
+PolKitResult _polkit_grantdb_check_can_caller_do_action (PolKitContext         *pk_context,
+                                                         PolKitAction          *action,
+                                                         PolKitCaller          *caller);
+
+polkit_bool_t _polkit_grantdb_write_keep_always (const char *action_id, uid_t uid);
+
+polkit_bool_t _polkit_grantdb_write_keep_session (const char *action_id, const char *session_id);
+
+polkit_bool_t _polkit_grantdb_write_pid (const char *action_id, pid_t pid);
+
+#endif /* POLKIT_GRANT_DATABASE_H */
diff-tree 42a6a076f7b04522bcfa51c74f6e7f5705ea5009 (from b22ebaba2a6c077a7f09bd6567177197b63fff11)
Author: David Zeuthen <davidz at redhat.com>
Date:   Mon Jul 23 22:21:24 2007 -0400

    get proper pid and SELinux context

diff --git a/configure.in b/configure.in
index f28d502..fc33e68 100644
--- a/configure.in
+++ b/configure.in
@@ -198,6 +198,46 @@ AC_SUBST(POLKIT_GROUP)
 AC_DEFINE_UNQUOTED(POLKIT_GROUP,"$POLKIT_GROUP", [Group for PolicyKit])
 
 dnl ---------------------------------------------------------------------------
+dnl - SELinux
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto)
+
+# SELinux detection
+if test x$enable_selinux = xno ; then
+    have_selinux=no;
+else
+    # See if we have SELinux library
+    AC_CHECK_LIB(selinux, is_selinux_enabled, 
+                 have_selinux=yes, have_selinux=no)
+
+    if test x$enable_selinux = xauto ; then
+        if test x$have_selinux = xno ; then
+                AC_MSG_WARN([SELinux library not found])
+        fi
+    else 
+        if test x$have_selinux = xno ; then
+                AC_MSG_ERROR([SElinux explicitly required, and SELinux library not found])
+        fi
+    fi
+fi
+
+AM_CONDITIONAL(HAVE_SELINUX, test x$have_selinux = xyes)
+
+if test x$have_selinux = xyes ; then
+    # the selinux code creates threads
+    # which requires libpthread even on linux
+    AC_CHECK_FUNC(pthread_create,,[AC_CHECK_LIB(pthread,pthread_create,
+                                                [SELINUX_THREAD_LIBS="-lpthread"])])
+
+    SELINUX_LIBS="-lselinux $SELINUX_THREAD_LIBS"
+    AC_DEFINE(HAVE_SELINUX,1,[SELinux support])
+else
+    SELINUX_LIBS=
+fi
+AC_SUBST(SELINUX_LIBS)
+
+dnl ---------------------------------------------------------------------------
 dnl - Check for PAM
 dnl ---------------------------------------------------------------------------
 
@@ -388,6 +428,7 @@ echo "
         group for PolicyKit:        ${POLKIT_GROUP}
 
         Distribution/OS:            ${with_os_type}
+        SELinux support:            ${have_selinux}
 
         PAM support:                ${have_pam}
         PAM file auth:              ${PAM_FILE_INCLUDE_AUTH}
diff --git a/polkit-dbus/polkit-dbus.c b/polkit-dbus/polkit-dbus.c
index d0c00f4..07cc53d 100644
--- a/polkit-dbus/polkit-dbus.c
+++ b/polkit-dbus/polkit-dbus.c
@@ -40,10 +40,18 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
 #include <time.h>
 #include <glib.h>
 #include <string.h>
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
 #include "polkit-dbus.h"
 
 
@@ -551,6 +559,11 @@ polkit_caller_new_from_pid (DBusConnecti
         DBusMessage *reply;
         DBusMessageIter iter;
         char *str;
+        char *proc_path;
+        struct stat statbuf;
+#ifdef HAVE_SELINUX
+        security_context_t secon;
+#endif
 
         g_return_val_if_fail (con != NULL, NULL);
         g_return_val_if_fail (error != NULL, NULL);
@@ -558,17 +571,27 @@ polkit_caller_new_from_pid (DBusConnecti
 
         selinux_context = NULL;
         ck_session_objpath = NULL;
-
         caller = NULL;
         session = NULL;
+        proc_path = NULL;
 
-        /* TODO: Verify that PID exists */
-
-        /* TODO: FIXME */
-        uid = 500;
+        proc_path = g_strdup_printf ("/proc/%d", pid);
+        if (stat (proc_path, &statbuf) != 0) {
+                g_warning ("Cannot lookup information for pid %d: %s", pid, strerror (errno));
+                goto out;
+        }
+        uid = statbuf.st_uid;
 
-        /* TODO: FIXME */
-        selinux_context = g_strdup ("user_u:system_r:hald_t");
+#ifdef HAVE_SELINUX
+        if (getpidcon (pid, &secon) != 0) {
+                g_warning ("Cannot lookup SELinux context for pid %d: %s", pid, strerror (errno));
+                goto out;
+        }
+        selinux_context = g_strdup (secon);
+        freecon (secon);
+#else
+        selinux_context = NULL;
+#endif
 
 	message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", 
 						"/org/freedesktop/ConsoleKit/Manager",
@@ -667,5 +690,6 @@ not_in_session:
 out:
         g_free (selinux_context);
         g_free (ck_session_objpath);
+        g_free (proc_path);
         return caller;
 }


More information about the hal-commit mailing list