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