PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Tue Oct 30 18:19:04 PDT 2007


 Makefile.am                                  |    2 
 configure.in                                 |    5 
 polkit-dbus/polkit-read-auth-helper.c        |   13 
 polkitd/Makefile.am                          |   61 +++
 polkitd/main.c                               |  193 +++++++++
 polkitd/org.freedesktop.PolicyKit.conf.in    |   11 
 polkitd/org.freedesktop.PolicyKit.service.in |   11 
 polkitd/org.freedesktop.PolicyKit.xml        |   27 +
 polkitd/polkit-daemon.c                      |  527 +++++++++++++++++++++++++++
 polkitd/polkit-daemon.h                      |   72 +++
 10 files changed, 919 insertions(+), 3 deletions(-)

New commits:
commit 871e4c93e96e5ae9782f1aafddc2f47cc2c34b78
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 30 21:17:08 2007 -0400

    provide a polkit D-Bus service that is activated on demand
    
    Right now we provide two methods
    
     IsProcessAuthorized
     IsSystemBusNameAuthorized
    
    This is useful for a couple of reasons
    
     - some mechanisms (e.g. Avahi) runs in a chroot and their only
       life-line to the world is a system bus connection. If it were to
       use libpolkit (and Lennart says he wants it to, yay!) it would need
       to bindmount crazy stuff into the chroot.
    
     - languages for which libpolkit bindings not yet exist can use
       this interface
    
    Going forward, this service can expose a private interface meaning we
    can get rid of (almost) all of our setgid helpers.

diff --git a/Makefile.am b/Makefile.am
index 23d971f..b5d36ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = data polkit polkit-dbus polkit-grant doc tools policy po
+SUBDIRS = data polkit polkit-dbus polkit-grant polkitd doc tools policy po
 
 # Creating ChangeLog from git log (taken from cairo/Makefile.am):
 ChangeLog: $(srcdir)/ChangeLog
diff --git a/configure.in b/configure.in
index 9ab5d4b..17694a2 100644
--- a/configure.in
+++ b/configure.in
@@ -136,6 +136,10 @@ PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.0])
 AC_SUBST(DBUS_CFLAGS)
 AC_SUBST(DBUS_LIBS)
 
+PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.73])
+AC_SUBST(DBUS_GLIB_CFLAGS)
+AC_SUBST(DBUS_GLIB_LIBS)
+
 AC_CHECK_FUNCS(getgrouplist)
 
 EXPAT_LIB=""
@@ -429,6 +433,7 @@ data/polkit-grant.pc
 polkit/Makefile
 polkit-dbus/Makefile
 polkit-grant/Makefile
+polkitd/Makefile
 tools/Makefile
 doc/Makefile
 doc/version.xml
diff --git a/polkit-dbus/polkit-read-auth-helper.c b/polkit-dbus/polkit-read-auth-helper.c
index 385c75d..2701634 100644
--- a/polkit-dbus/polkit-read-auth-helper.c
+++ b/polkit-dbus/polkit-read-auth-helper.c
@@ -341,6 +341,8 @@ main (int argc, char *argv[])
         uid_t caller_uid;
         uid_t requesting_info_for_uid;
         char *endp;
+        struct passwd *pw;
+        uid_t uid_for_polkit_user;
 
         ret = 1;
         /* clear the entire environment to avoid attacks using with libraries honoring environment variables */
@@ -379,6 +381,13 @@ main (int argc, char *argv[])
                 goto out;
         }
 
+        pw = getpwnam (POLKIT_USER);
+        if (pw == NULL) {
+                fprintf (stderr, "polkit-read-auth-helper: cannot lookup uid for " POLKIT_USER "\n");
+                goto out;
+        }
+        uid_for_polkit_user = pw->pw_uid;
+
         /*----------------------------------------------------------------------------------------------------*/
 
         requesting_info_for_uid = strtoul (argv[1], &endp, 10);
@@ -387,8 +396,8 @@ main (int argc, char *argv[])
                 goto out;
         }
 
-        /* uid 0 is allowed to read anything */
-        if (caller_uid != 0) {
+        /* uid 0 and user polkituser is allowed to read anything */
+        if (caller_uid != 0 && caller_uid != uid_for_polkit_user) {
                 if (caller_uid != requesting_info_for_uid) {
 
                         /* see if calling user has the
diff --git a/polkitd/Makefile.am b/polkitd/Makefile.am
new file mode 100644
index 0000000..815e72a
--- /dev/null
+++ b/polkitd/Makefile.am
@@ -0,0 +1,61 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = \
+	-I$(top_builddir) -I$(top_srcdir) \
+	-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
+	-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+	-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+	-DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \
+	-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
+	-DPACKAGE_LIB_DIR=\""$(libdir)"\" \
+	-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT	\
+	-DPOLKIT_COMPILATION \
+	$(DBUS_GLIB_CFLAGS) \
+	@GLIB_CFLAGS@
+
+BUILT_SOURCES =						\
+	polkit-daemon-glue.h
+
+polkit-daemon-glue.h: org.freedesktop.PolicyKit.xml Makefile.am
+	dbus-binding-tool --prefix=polkit_daemon --mode=glib-server --output=polkit-daemon-glue.h org.freedesktop.PolicyKit.xml
+
+libexec_PROGRAMS = polkitd
+
+polkitd_SOURCES = 					\
+	polkit-daemon.h		polkit-daemon.c		\
+	main.c						\
+	$(BUILT_SOURCES)
+
+polkitd_CPPFLAGS = 					\
+	-I$(top_srcdir)					\
+	-DG_LOG_DOMAIN=\"polkitd\"			\
+	-DDATADIR=\""$(pkgdatadir)"\"			\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"	\
+	$(DISABLE_DEPRECATED)				\
+	$(AM_CPPFLAGS)
+
+polkitd_LDADD = 				        \
+	$(DBUS_GLIB_LIBS) $(top_builddir)/polkit/libpolkit.la $(top_builddir)/polkit-dbus/libpolkit-dbus.la $(top_builddir)/polkit-grant/libpolkit-grant.la
+
+
+servicedir       = $(datadir)/dbus-1/system-services
+service_in_files = org.freedesktop.PolicyKit.service.in
+service_DATA     = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+	@sed -e "s|\@polkituser\@|$(POLKIT_USER)|" -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+dbusconfdir = $(sysconfdir)/dbus-1/system.d
+dbusconf_in_files = org.freedesktop.PolicyKit.conf.in
+dbusconf_DATA = $(dbusconf_in_files:.conf.in=.conf)
+
+$(dbusconf_DATA): $(dbusconf_in_files) Makefile
+	@sed -e "s|\@polkituser\@|$(POLKIT_USER)|" $< > $@
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = org.freedesktop.PolicyKit.xml $(service_in_files) $(dbusconf_in_files)
+
+clean-local :
+	rm -f *~ $(service_DATA) $(dbusconf_DATA)
diff --git a/polkitd/main.c b/polkitd/main.c
new file mode 100644
index 0000000..fe7b626
--- /dev/null
+++ b/polkitd/main.c
@@ -0,0 +1,193 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "polkit-daemon.h"
+
+#define NAME_TO_CLAIM "org.freedesktop.PolicyKit"
+
+static gboolean
+acquire_name_on_proxy (DBusGProxy *bus_proxy)
+{
+        GError     *error;
+        guint       result;
+        gboolean    res;
+        gboolean    ret;
+
+        ret = FALSE;
+
+        if (bus_proxy == NULL) {
+                goto out;
+        }
+
+        error = NULL;
+	res = dbus_g_proxy_call (bus_proxy,
+                                 "RequestName",
+                                 &error,
+                                 G_TYPE_STRING, NAME_TO_CLAIM,
+                                 G_TYPE_UINT, 0,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_UINT, &result,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                if (error != NULL) {
+                        g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
+                }
+                goto out;
+	}
+
+ 	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+                if (error != NULL) {
+                        g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
+                }
+                goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+        GError              *error;
+        GMainLoop           *loop;
+        PolKitDaemon        *daemon;
+        GOptionContext      *context;
+        DBusGProxy          *bus_proxy;
+        DBusGConnection     *bus;
+        int                  ret;
+	struct passwd *pw = NULL;
+	struct group *gr = NULL;
+        static gboolean     no_exit      = FALSE;
+        static GOptionEntry entries []   = {
+                { "no-exit", 0, 0, G_OPTION_ARG_NONE, &no_exit, "Don't exit after 30 seconds of inactivity", NULL },
+                { NULL }
+        };
+
+        ret = 1;
+
+	pw = getpwnam (POLKIT_USER);
+	if (pw == NULL)  {
+		g_warning ("polkitd: user " POLKIT_USER " does not exist");
+                goto out;
+	}
+
+	gr = getgrnam (POLKIT_GROUP);
+	if (gr == NULL) {
+		g_warning ("polkitd: group " POLKIT_GROUP " does not exist");
+		goto out;
+	}
+
+        if (initgroups (POLKIT_USER, gr->gr_gid)) {
+                g_warning ("polkitd: could not initialize groups");
+                goto out;
+        }
+
+	if (setgid (gr->gr_gid)) {
+		g_warning ("polkitd: could not set group id");
+		goto out;
+	}
+
+	if (setuid (pw->pw_uid)) {
+		g_warning ("polkitd: could not set user id");
+		goto out;
+	}
+
+
+        g_type_init ();
+
+        context = g_option_context_new ("PolicyKit daemon");
+        g_option_context_add_main_entries (context, entries, NULL);
+        g_option_context_parse (context, &argc, &argv, NULL);
+        g_option_context_free (context);
+
+        error = NULL;
+        bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (bus == NULL) {
+                g_warning ("Couldn't connect to session bus: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+	bus_proxy = dbus_g_proxy_new_for_name (bus,
+                                               DBUS_SERVICE_DBUS,
+                                               DBUS_PATH_DBUS,
+                                               DBUS_INTERFACE_DBUS);
+        if (bus_proxy == NULL) {
+                g_warning ("Could not construct bus_proxy object; bailing out");
+                goto out;
+        }
+
+        if (!acquire_name_on_proxy (bus_proxy) ) {
+                g_warning ("Could not acquire name; bailing out");
+                goto out;
+        }
+
+        g_debug ("Starting polkitd version %s", VERSION);
+
+        daemon = polkit_daemon_new (no_exit);
+
+        if (daemon == NULL) {
+                goto out;
+        }
+
+        loop = g_main_loop_new (NULL, FALSE);
+
+        g_main_loop_run (loop);
+
+        g_object_unref (daemon);
+        g_main_loop_unref (loop);
+        ret = 0;
+
+out:
+        return ret;
+}
diff --git a/polkitd/org.freedesktop.PolicyKit.conf.in b/polkitd/org.freedesktop.PolicyKit.conf.in
new file mode 100644
index 0000000..d7ca4e0
--- /dev/null
+++ b/polkitd/org.freedesktop.PolicyKit.conf.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
+
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <!-- Only @polkituser@ can own the service -->
+  <policy user="@polkituser@">
+    <allow own="org.freedesktop.PolicyKit"/>
+  </policy>
+</busconfig>
diff --git a/polkitd/org.freedesktop.PolicyKit.service.in b/polkitd/org.freedesktop.PolicyKit.service.in
new file mode 100644
index 0000000..ae17b31
--- /dev/null
+++ b/polkitd/org.freedesktop.PolicyKit.service.in
@@ -0,0 +1,11 @@
+[D-BUS Service]
+Name=org.freedesktop.PolicyKit
+Exec=@libexecdir@/polkitd
+User=root
+
+# Hmm when using User=@polkituser@ I get this: 
+#
+#   Error org.freedesktop.DBus.Error.Spawn.ChildExited: Launch helper exited with unknown return code 1
+#
+# Need to investigate
+
diff --git a/polkitd/org.freedesktop.PolicyKit.xml b/polkitd/org.freedesktop.PolicyKit.xml
new file mode 100644
index 0000000..a342847
--- /dev/null
+++ b/polkitd/org.freedesktop.PolicyKit.xml
@@ -0,0 +1,27 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/">
+
+  <interface name="org.freedesktop.PolicyKit">
+
+    <method name="IsProcessAuthorized">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <!-- IN: PolicyKit action identifier -->
+      <arg name="action_id" direction="in" type="s"/>
+      <!-- IN: process id of caller to check for -->
+      <arg name="pid" direction="in" type="u"/>
+      <!-- OUT: the PolKitResult in textual form -->
+      <arg name="result" direction="out" type="s"/>
+    </method>
+
+    <method name="IsSystemBusNameAuthorized">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <!-- IN: PolicyKit action identifier -->
+      <arg name="action_id" direction="in" type="s"/>
+      <!-- IN: Unique name on the system bus of the caller to check for -->
+      <arg name="system_bus_name" direction="in" type="s"/>
+      <!-- OUT: the PolKitResult in textual form -->
+      <arg name="result" direction="out" type="s"/>
+    </method>
+
+  </interface>
+</node>
diff --git a/polkitd/polkit-daemon.c b/polkitd/polkit-daemon.c
new file mode 100644
index 0000000..48353b5
--- /dev/null
+++ b/polkitd/polkit-daemon.c
@@ -0,0 +1,527 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <polkit/polkit.h>
+#include <polkit/polkit-utils.h>
+#include <polkit-dbus/polkit-dbus.h>
+
+#include "polkit-daemon.h"
+
+static gboolean no_exit = FALSE;
+
+/*--------------------------------------------------------------------------------------------------------------*/
+#include "polkit-daemon-glue.h"
+
+static gboolean
+do_exit (gpointer user_data)
+{
+        g_debug ("Exiting due to inactivity");
+        exit (1);
+        return FALSE;
+}
+
+static void
+reset_killtimer (void)
+{
+        static guint timer_id = 0;
+
+        if (no_exit)
+                return;
+
+        if (timer_id > 0) {
+                g_source_remove (timer_id);
+        }
+        g_debug ("Setting killtimer to 30 seconds...");
+        timer_id = g_timeout_add (30 * 1000, do_exit, NULL);
+}
+
+struct PolKitDaemonPrivate
+{
+        DBusGConnection *system_bus_connection;
+        DBusGProxy      *system_bus_proxy;
+        PolKitContext   *pk_context;
+        PolKitTracker   *pk_tracker;
+};
+
+static void     polkit_daemon_class_init  (PolKitDaemonClass *klass);
+static void     polkit_daemon_init        (PolKitDaemon      *seat);
+static void     polkit_daemon_finalize    (GObject     *object);
+
+G_DEFINE_TYPE (PolKitDaemon, polkit_daemon, G_TYPE_OBJECT)
+
+#define POLKIT_DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POLKIT_TYPE_DAEMON, PolKitDaemonPrivate))
+
+GQuark
+polkit_daemon_error_quark (void)
+{
+        static GQuark ret = 0;
+
+        if (ret == 0) {
+                ret = g_quark_from_static_string ("polkit_daemon_error");
+        }
+
+        return ret;
+}
+
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+polkit_daemon_error_get_type (void)
+{
+        static GType etype = 0;
+        
+        if (etype == 0)
+        {
+                static const GEnumValue values[] =
+                        {
+                                ENUM_ENTRY (POLKIT_DAEMON_ERROR_GENERAL, "GeneralError"),
+                                ENUM_ENTRY (POLKIT_DAEMON_ERROR_NOT_AUTHORIZED, "NotAuthorized"),
+                                { 0, 0, 0 }
+                        };
+                
+                g_assert (POLKIT_DAEMON_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+                
+                etype = g_enum_register_static ("PolKitDaemonError", values);
+        }
+        
+        return etype;
+}
+
+
+static GObject *
+polkit_daemon_constructor (GType                  type,
+                                            guint                  n_construct_properties,
+                                            GObjectConstructParam *construct_properties)
+{
+        PolKitDaemon      *daemon;
+        PolKitDaemonClass *klass;
+
+        klass = POLKIT_DAEMON_CLASS (g_type_class_peek (POLKIT_TYPE_DAEMON));
+
+        daemon = POLKIT_DAEMON (
+                G_OBJECT_CLASS (polkit_daemon_parent_class)->constructor (type,
+                                                                                           n_construct_properties,
+                                                                                           construct_properties));
+        
+        return G_OBJECT (daemon);
+}
+
+static void
+polkit_daemon_class_init (PolKitDaemonClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->constructor = polkit_daemon_constructor;
+        object_class->finalize = polkit_daemon_finalize;
+
+        g_type_class_add_private (klass, sizeof (PolKitDaemonPrivate));
+
+        dbus_g_object_type_install_info (POLKIT_TYPE_DAEMON, &dbus_glib_polkit_daemon_object_info);
+
+        dbus_g_error_domain_register (POLKIT_DAEMON_ERROR, NULL, POLKIT_DAEMON_TYPE_ERROR);
+
+}
+
+static void
+polkit_daemon_init (PolKitDaemon *daemon)
+{
+        daemon->priv = POLKIT_DAEMON_GET_PRIVATE (daemon);
+
+}
+
+static void
+polkit_daemon_finalize (GObject *object)
+{
+        PolKitDaemon *daemon;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (POLKIT_IS_DAEMON (object));
+
+        daemon = POLKIT_DAEMON (object);
+
+        g_return_if_fail (daemon->priv != NULL);
+
+        g_object_unref (daemon->priv->system_bus_proxy);
+
+        G_OBJECT_CLASS (polkit_daemon_parent_class)->finalize (object);
+}
+
+static gboolean
+pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
+{
+        int fd;
+        PolKitContext *pk_context = user_data;
+        fd = g_io_channel_unix_get_fd (channel);
+        polkit_context_io_func (pk_context, fd);
+        return TRUE;
+}
+
+static int 
+pk_io_add_watch (PolKitContext *pk_context, int fd)
+{
+        guint id = 0;
+        GIOChannel *channel;
+        channel = g_io_channel_unix_new (fd);
+        if (channel == NULL)
+                goto out;
+        id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
+        if (id == 0) {
+                g_io_channel_unref (channel);
+                goto out;
+        }
+        g_io_channel_unref (channel);
+out:
+        return id;
+}
+
+static void 
+pk_io_remove_watch (PolKitContext *pk_context, int watch_id)
+{
+        g_source_remove (watch_id);
+}
+
+static DBusHandlerResult
+_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+        PolKitDaemon *daemon = POLKIT_DAEMON (user_data);
+
+        /*  pass NameOwnerChanged signals from the bus and ConsoleKit to PolKitTracker */
+        if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged") ||
+            (dbus_message_get_interface (message) != NULL &&
+             g_str_has_prefix (dbus_message_get_interface (message), "org.freedesktop.ConsoleKit"))) {
+                if (polkit_tracker_dbus_func (daemon->priv->pk_tracker, message)) {
+
+                        /* Something has changed! TODO: emit D-Bus signal? */
+                        g_debug ("Something has changed!");
+                }
+        }
+
+        /* other filters might want to process this message too */
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean
+register_daemon (PolKitDaemon *daemon)
+{
+        DBusConnection *connection;
+        DBusError dbus_error;
+        GError *error = NULL;
+
+        daemon->priv->pk_context = polkit_context_new ();
+        polkit_context_set_io_watch_functions (daemon->priv->pk_context, pk_io_add_watch, pk_io_remove_watch);
+        if (!polkit_context_init (daemon->priv->pk_context, NULL)) {
+                g_critical ("cannot initialize libpolkit");
+                goto error;
+        }
+
+        error = NULL;
+        daemon->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (daemon->priv->system_bus_connection == NULL) {
+                if (error != NULL) {
+                        g_critical ("error getting system bus: %s", error->message);
+                        g_error_free (error);
+                }
+                goto error;
+        }
+        connection = dbus_g_connection_get_connection (daemon->priv->system_bus_connection);
+
+        daemon->priv->pk_tracker = polkit_tracker_new ();
+        polkit_tracker_set_system_bus_connection (daemon->priv->pk_tracker, connection);
+        polkit_tracker_init (daemon->priv->pk_tracker);
+
+        dbus_g_connection_register_g_object (daemon->priv->system_bus_connection, "/", 
+                                             G_OBJECT (daemon));
+
+        daemon->priv->system_bus_proxy = dbus_g_proxy_new_for_name (daemon->priv->system_bus_connection,
+                                                                      DBUS_SERVICE_DBUS,
+                                                                      DBUS_PATH_DBUS,
+                                                                      DBUS_INTERFACE_DBUS);
+
+        /* TODO FIXME: I'm pretty sure dbus-glib blows in a way that
+         * we can't say we're interested in all signals from all
+         * members on all interfaces for a given service... So we do
+         * this..
+         */
+
+        dbus_error_init (&dbus_error);
+
+        /* need to listen to NameOwnerChanged */
+	dbus_bus_add_match (connection,
+			    "type='signal'"
+			    ",interface='"DBUS_INTERFACE_DBUS"'"
+			    ",sender='"DBUS_SERVICE_DBUS"'"
+			    ",member='NameOwnerChanged'",
+			    &dbus_error);
+
+        if (dbus_error_is_set (&dbus_error)) {
+                g_warning ("Cannot add match rule: %s: %s", dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                goto error;
+        }
+
+        /* need to listen to ConsoleKit signals */
+	dbus_bus_add_match (connection,
+			    "type='signal',sender='org.freedesktop.ConsoleKit'",
+			    &dbus_error);
+
+        if (dbus_error_is_set (&dbus_error)) {
+                g_warning ("Cannot add match rule: %s: %s", dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                goto error;
+        }
+
+        if (!dbus_connection_add_filter (connection, 
+                                         _filter, 
+                                         daemon, 
+                                         NULL)) {
+                g_warning ("Cannot add D-Bus filter: %s: %s", dbus_error.name, dbus_error.message);
+                goto error;
+        }        
+
+        reset_killtimer ();
+
+        return TRUE;
+
+error:
+        return FALSE;
+}
+
+
+PolKitDaemon *
+polkit_daemon_new (gboolean _no_exit)
+{
+        GObject *object;
+        gboolean res;
+
+        no_exit = _no_exit;
+
+        object = g_object_new (POLKIT_TYPE_DAEMON, NULL);
+
+        res = register_daemon (POLKIT_DAEMON (object));
+        if (! res) {
+                g_object_unref (object);
+                return NULL;
+        }
+
+        return POLKIT_DAEMON (object);
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+/* exported methods */
+
+static PolKitCaller *
+get_caller_from_context (PolKitDaemon *daemon, DBusGMethodInvocation *context)
+{
+        const char *sender;
+        GError *error;
+        DBusError dbus_error;
+        PolKitCaller *pk_caller;
+
+        sender = dbus_g_method_get_sender (context);
+        dbus_error_init (&dbus_error);
+        pk_caller = polkit_tracker_get_caller_from_dbus_name (daemon->priv->pk_tracker,
+                                                              sender, 
+                                                              &dbus_error);
+        if (pk_caller == NULL) {
+                error = g_error_new (POLKIT_DAEMON_ERROR,
+                                     POLKIT_DAEMON_ERROR_GENERAL,
+                                     "Error getting information about caller: %s: %s",
+                                     dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                return NULL;
+        }
+
+        return pk_caller;
+}
+
+
+/* takes ownership of pk_caller */
+static gboolean
+is_caller_authorized (PolKitDaemon          *daemon, 
+                      const char            *action_id, 
+                      PolKitCaller          *pk_caller, 
+                      DBusGMethodInvocation *context)
+{
+        gboolean ret;
+        GError *error;
+        PolKitCaller *pk_caller_who_wants_to_know;
+        uid_t uid_caller;
+        uid_t uid_caller_who_wants_to_know;
+        PolKitAction *pk_action;
+        PolKitResult pk_result;
+
+        ret = FALSE;
+        pk_caller_who_wants_to_know = NULL;
+
+        pk_caller_who_wants_to_know = get_caller_from_context (daemon, context);
+        if (pk_caller_who_wants_to_know == NULL) {
+                goto out;
+        }
+
+        if (!polkit_caller_get_uid (pk_caller_who_wants_to_know, &uid_caller_who_wants_to_know))
+                goto out;
+
+        if (!polkit_caller_get_uid (pk_caller, &uid_caller))
+                goto out;
+
+        if (uid_caller_who_wants_to_know != uid_caller) {
+                /* if the uid's are different, the caller who wants to know need to posses
+                 * the org.freedesktop.policykit.read authorization 
+                 */
+
+                pk_action = polkit_action_new ();
+                polkit_action_set_action_id (pk_action, "org.freedesktop.policykit.read");
+                pk_result = polkit_context_is_caller_authorized (daemon->priv->pk_context, 
+                                                                 pk_action, 
+                                                                 pk_caller_who_wants_to_know, 
+                                                                 FALSE);
+                polkit_action_unref (pk_action);
+                if (pk_result != POLKIT_RESULT_YES) {
+                        error = g_error_new (POLKIT_DAEMON_ERROR,
+                                             POLKIT_DAEMON_ERROR_NOT_AUTHORIZED,
+                                             "uid %d is not authorized to know authorizations for uid %d "
+                                             "(requires org.freedesktop.policykit.read)",
+                                             uid_caller_who_wants_to_know, uid_caller);
+                        dbus_g_method_return_error (context, error);
+                        g_error_free (error);
+                        goto out;
+                }
+        }
+
+        pk_action = polkit_action_new ();
+        polkit_action_set_action_id (pk_action, action_id);
+        pk_result = polkit_context_is_caller_authorized (daemon->priv->pk_context, pk_action, pk_caller, FALSE);
+        polkit_action_unref (pk_action);
+
+        dbus_g_method_return (context, polkit_result_to_string_representation (pk_result));
+
+out:
+        if (pk_caller_who_wants_to_know != NULL)
+                polkit_caller_unref (pk_caller_who_wants_to_know);
+
+        if (pk_caller != NULL)
+                polkit_caller_unref (pk_caller);
+
+        return ret;
+}
+
+gboolean
+polkit_daemon_is_process_authorized (PolKitDaemon          *daemon,
+                                     const char            *action_id, 
+                                     guint32                pid,
+                                     DBusGMethodInvocation *context)
+{
+        gboolean ret;
+        DBusError dbus_error;
+        GError *error;
+        PolKitCaller *pk_caller;
+
+        ret = FALSE;
+        pk_caller = NULL;
+
+        dbus_error_init (&dbus_error);
+        pk_caller = polkit_tracker_get_caller_from_pid (daemon->priv->pk_tracker, (pid_t) pid, &dbus_error);
+        if (pk_caller == NULL) {
+                error = g_error_new (POLKIT_DAEMON_ERROR,
+                                     POLKIT_DAEMON_ERROR_GENERAL,
+                                     "Error getting information about pid %d: %s: %s",
+                                     pid,
+                                     dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                goto out;
+        }
+
+        ret = is_caller_authorized (daemon, action_id, pk_caller, context);
+
+out:
+        return ret;
+}
+
+gboolean
+polkit_daemon_is_system_bus_name_authorized (PolKitDaemon          *daemon,
+                                             const char            *action_id, 
+                                             const char            *system_bus_name,
+                                             DBusGMethodInvocation *context)
+{
+        gboolean ret;
+        DBusError dbus_error;
+        GError *error;
+        PolKitCaller *pk_caller;
+
+        ret = FALSE;
+        pk_caller = NULL;
+
+        if (!_pk_validate_unique_bus_name (system_bus_name)) {
+                error = g_error_new (POLKIT_DAEMON_ERROR,
+                                     POLKIT_DAEMON_ERROR_GENERAL,
+                                     "Given system bus name is not a valid unique system bus name");
+                dbus_error_free (&dbus_error);
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                goto out;
+        }
+
+        dbus_error_init (&dbus_error);
+        pk_caller = polkit_tracker_get_caller_from_dbus_name (daemon->priv->pk_tracker, system_bus_name, &dbus_error);
+        if (pk_caller == NULL) {
+                error = g_error_new (POLKIT_DAEMON_ERROR,
+                                     POLKIT_DAEMON_ERROR_GENERAL,
+                                     "Error getting information about system bus name %s: %s: %s",
+                                     system_bus_name,
+                                     dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                goto out;
+        }
+
+        ret = is_caller_authorized (daemon, action_id, pk_caller, context);
+
+out:
+        return ret;
+}
diff --git a/polkitd/polkit-daemon.h b/polkitd/polkit-daemon.h
new file mode 100644
index 0000000..6031bf5
--- /dev/null
+++ b/polkitd/polkit-daemon.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * 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.
+ *
+ */
+
+#define POLKIT_TYPE_DAEMON         (polkit_daemon_get_type ())
+#define POLKIT_DAEMON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_TYPE_DAEMON, PolKitDaemon))
+#define POLKIT_DAEMON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), POLKIT_TYPE_DAEMON, PolKitDaemonClass))
+#define POLKIT_IS_DAEMON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_TYPE_DAEMON))
+#define POLKIT_IS_DAEMON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_TYPE_DAEMON))
+#define POLKIT_DAEMON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_TYPE_DAEMON, PolKitDaemonClass))
+
+typedef struct PolKitDaemonPrivate PolKitDaemonPrivate;
+
+typedef struct
+{
+        GObject        parent;
+        PolKitDaemonPrivate *priv;
+} PolKitDaemon;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} PolKitDaemonClass;
+
+typedef enum
+{
+        POLKIT_DAEMON_ERROR_GENERAL,
+        POLKIT_DAEMON_ERROR_NOT_AUTHORIZED,
+        POLKIT_DAEMON_NUM_ERRORS
+} PolKitDaemonError;
+
+#define POLKIT_DAEMON_ERROR polkit_daemon_error_quark ()
+
+GType polkit_daemon_error_get_type (void);
+#define POLKIT_DAEMON_TYPE_ERROR (polkit_daemon_error_get_type ())
+
+GQuark        polkit_daemon_error_quark         (void);
+GType         polkit_daemon_get_type            (void);
+PolKitDaemon *polkit_daemon_new                 (gboolean no_exit);
+
+/* exported methods */
+
+gboolean polkit_daemon_is_session_authorized         (PolKitDaemon          *daemon, 
+                                                      const char            *action_id, 
+                                                      const char            *ck_session_id,
+                                                      DBusGMethodInvocation *context);
+
+gboolean polkit_daemon_is_process_authorized         (PolKitDaemon          *daemon,
+                                                      const char            *action_id, 
+                                                      guint32                pid,
+                                                      DBusGMethodInvocation *context);
+
+gboolean polkit_daemon_is_system_bus_name_authorized (PolKitDaemon          *daemon,
+                                                      const char            *action_id, 
+                                                      const char            *system_bus_name,
+                                                      DBusGMethodInvocation *context);


More information about the hal-commit mailing list