summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2011-12-19 22:37:05 -0500
committerDavid Zeuthen <davidz@redhat.com>2012-01-03 10:03:47 -0500
commit2027302e803a9569a370b429a475dae5ef8afe34 (patch)
treee752e6a1feb5936c8f7f7b8f19203526a6d10544
parent674357c20c1b6cb421fea6eb6924b274ec477c0e (diff)
downloadpolkit-2027302e803a9569a370b429a475dae5ef8afe34.tar.gz
Add optional systemd support
When configured with --enable-systemd, this patch makes polkit use systemd for session tracking instead of ConsoleKit. Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--configure.ac24
-rw-r--r--src/polkit/Makefile.am11
-rw-r--r--src/polkit/polkitunixsession-systemd.c481
-rw-r--r--src/polkitbackend/Makefile.am11
-rw-r--r--src/polkitbackend/polkitbackendsessionmonitor-systemd.c414
5 files changed, 937 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 2ed8401..51d6890 100644
--- a/configure.ac
+++ b/configure.ac
@@ -148,6 +148,26 @@ if test "x$GCC" = "xyes"; then
fi
dnl ---------------------------------------------------------------------------
+dnl - Select wether to use systemd or ConsoleKit for session tracking
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE([systemd],
+ AS_HELP_STRING([--enable-systemd], [Use systemd]),
+ [with_systemd=$enableval],
+ [with_systemd=no])
+if test "$with_systemd" = "yes" ; then
+ PKG_CHECK_MODULES(SYSTEMD, [libsystemd-login])
+ SESSION_TRACKING=systemd
+else
+ SESSION_TRACKING=ConsoleKit
+fi
+
+AC_SUBST(SYSTEMD_CFLAGS)
+AC_SUBST(SYSTEMD_LIBS)
+
+AM_CONDITIONAL(HAVE_SYSTEMD, [test "$with_systemd" = "yes"], [Using systemd])
+
+dnl ---------------------------------------------------------------------------
dnl - Select which authentication framework to use
dnl ---------------------------------------------------------------------------
@@ -449,7 +469,8 @@ echo "
introspection: ${found_introspection}
Distribution/OS: ${with_os_type}
- authentication framework: ${POLKIT_AUTHFW}
+ Authentication framework: ${POLKIT_AUTHFW}
+ Session tracking: ${SESSION_TRACKING}
PAM support: ${have_pam}"
if test "$have_pam" = yes ; then
@@ -459,7 +480,6 @@ echo "
PAM file password: ${PAM_FILE_INCLUDE_PASSWORD}
PAM file session: ${PAM_FILE_INCLUDE_SESSION}"
fi
-
echo "
Maintainer mode: ${USE_MAINTAINER_MODE}
Building verbose mode: ${enable_verbose_mode}
diff --git a/src/polkit/Makefile.am b/src/polkit/Makefile.am
index 6c5a586..0c37151 100644
--- a/src/polkit/Makefile.am
+++ b/src/polkit/Makefile.am
@@ -69,7 +69,6 @@ libpolkit_gobject_1_la_SOURCES = \
polkiterror.c polkiterror.h \
polkitsubject.c polkitsubject.h \
polkitunixprocess.c polkitunixprocess.h \
- polkitunixsession.c polkitunixsession.h \
polkitsystembusname.c polkitsystembusname.h \
polkitidentity.c polkitidentity.h \
polkitunixuser.c polkitunixuser.h \
@@ -82,13 +81,23 @@ libpolkit_gobject_1_la_SOURCES = \
polkitpermission.c polkitpermission.h \
$(NULL)
+if HAVE_SYSTEMD
+libpolkit_gobject_1_la_SOURCES += \
+ polkitunixsession-systemd.c polkitunixsession.h
+else
+libpolkit_gobject_1_la_SOURCES += \
+ polkitunixsession.c polkitunixsession.h
+endif
+
libpolkit_gobject_1_la_CFLAGS = \
-D_POLKIT_COMPILATION \
$(GLIB_CFLAGS) \
+ $(SYSTEMD_CFLAGS) \
$(NULL)
libpolkit_gobject_1_la_LIBADD = \
$(GLIB_LIBS) \
+ $(SYSTEMD_LIBS) \
$(NULL)
libpolkit_gobject_1_la_LDFLAGS = -export-symbols-regex '(^polkit_.*)'
diff --git a/src/polkit/polkitunixsession-systemd.c b/src/polkit/polkitunixsession-systemd.c
new file mode 100644
index 0000000..e7e913f
--- /dev/null
+++ b/src/polkit/polkitunixsession-systemd.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include "polkitunixsession.h"
+#include "polkitsubject.h"
+#include "polkiterror.h"
+#include "polkitprivate.h"
+
+#include <systemd/sd-login.h>
+
+/**
+ * SECTION:polkitunixsession
+ * @title: PolkitUnixSession
+ * @short_description: Unix sessions
+ *
+ * An object that represents an user session.
+ *
+ * The session id is an opaque string obtained from ConsoleKit.
+ */
+
+/**
+ * PolkitUnixSession:
+ *
+ * The #PolkitUnixSession struct should not be accessed directly.
+ */
+struct _PolkitUnixSession
+{
+ GObject parent_instance;
+
+ gchar *session_id;
+
+ gint pid;
+};
+
+struct _PolkitUnixSessionClass
+{
+ GObjectClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+ PROP_SESSION_ID,
+ PROP_PID,
+};
+
+static void subject_iface_init (PolkitSubjectIface *subject_iface);
+static void initable_iface_init (GInitableIface *initable_iface);
+static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (PolkitUnixSession, polkit_unix_session, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (POLKIT_TYPE_SUBJECT, subject_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
+ );
+
+static void
+polkit_unix_session_init (PolkitUnixSession *session)
+{
+}
+
+static void
+polkit_unix_session_finalize (GObject *object)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (object);
+
+ g_free (session->session_id);
+
+ if (G_OBJECT_CLASS (polkit_unix_session_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (polkit_unix_session_parent_class)->finalize (object);
+}
+
+static void
+polkit_unix_session_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_SESSION_ID:
+ g_value_set_string (value, session->session_id);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+polkit_unix_session_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_SESSION_ID:
+ polkit_unix_session_set_session_id (session, g_value_get_string (value));
+ break;
+
+ case PROP_PID:
+ session->pid = g_value_get_int (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+polkit_unix_session_class_init (PolkitUnixSessionClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = polkit_unix_session_finalize;
+ gobject_class->get_property = polkit_unix_session_get_property;
+ gobject_class->set_property = polkit_unix_session_set_property;
+
+ /**
+ * PolkitUnixSession:session-id:
+ *
+ * The UNIX session id.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_SESSION_ID,
+ g_param_spec_string ("session-id",
+ "Session ID",
+ "The UNIX session ID",
+ NULL,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+
+ /**
+ * PolkitUnixSession:pid:
+ *
+ * The UNIX process id to look up the session.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PID,
+ g_param_spec_int ("pid",
+ "Process ID",
+ "Process ID to use for looking up the session",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+}
+
+/**
+ * polkit_unix_session_get_session_id:
+ * @session: A #PolkitUnixSession.
+ *
+ * Gets the session id for @session.
+ *
+ * Returns: The session id for @session. Do not free this string, it
+ * is owned by @session.
+ **/
+const gchar *
+polkit_unix_session_get_session_id (PolkitUnixSession *session)
+{
+ g_return_val_if_fail (POLKIT_IS_UNIX_SESSION (session), NULL);
+ return session->session_id;
+}
+
+/**
+ * polkit_unix_session_set_session_id:
+ * @session: A #PolkitUnixSession.
+ * @session_id: The session id.
+ *
+ * Sets the session id for @session to @session_id.
+ **/
+void
+polkit_unix_session_set_session_id (PolkitUnixSession *session,
+ const gchar *session_id)
+{
+ g_return_if_fail (POLKIT_IS_UNIX_SESSION (session));
+ /*g_return_if_fail (session_id != NULL);*/
+ g_free (session->session_id);
+ session->session_id = g_strdup (session_id);
+}
+
+/**
+ * polkit_unix_session_new:
+ * @session_id: The session id.
+ *
+ * Creates a new #PolkitUnixSession for @session_id.
+ *
+ * Returns: (transfer full): A #PolkitUnixSession. Free with g_object_unref().
+ **/
+PolkitSubject *
+polkit_unix_session_new (const gchar *session_id)
+{
+ return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_SESSION,
+ "session-id", session_id,
+ NULL));
+}
+
+/**
+ * polkit_unix_session_new_for_process:
+ * @pid: The process id of the process to get the session for.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: The data to pass to @callback.
+ *
+ * Asynchronously creates a new #PolkitUnixSession object for the
+ * process with process id @pid.
+ *
+ * When the operation is finished, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default
+ * main loop</link> of the thread you are calling this method
+ * from. You can then call
+ * polkit_unix_session_new_for_process_finish() to get the result of
+ * the operation.
+ *
+ * This method constructs the object asynchronously, for the synchronous and blocking version
+ * use polkit_unix_session_new_for_process_sync().
+ **/
+void
+polkit_unix_session_new_for_process (gint pid,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (POLKIT_TYPE_UNIX_SESSION,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ "pid", pid,
+ NULL);
+}
+
+/**
+ * polkit_unix_session_new_for_process_finish:
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to polkit_unix_session_new_for_process().
+ * @error: (allow-none): Return location for error.
+ *
+ * Finishes constructing a #PolkitSubject for a process id.
+ *
+ * Returns: (transfer full) (allow-none): A #PolkitUnixSession for the @pid passed to
+ * polkit_unix_session_new_for_process() or %NULL if @error is
+ * set. Free with g_object_unref().
+ **/
+PolkitSubject *
+polkit_unix_session_new_for_process_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *object;
+ GObject *source_object;
+
+ source_object = g_async_result_get_source_object (res);
+ g_assert (source_object != NULL);
+
+ object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
+ res,
+ error);
+ g_object_unref (source_object);
+
+ if (object != NULL)
+ return POLKIT_SUBJECT (object);
+ else
+ return NULL;
+}
+
+
+/**
+ * polkit_unix_session_new_for_process_sync:
+ * @pid: The process id of the process to get the session for.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: (allow-none): Return location for error.
+ *
+ * Creates a new #PolkitUnixSession for the process with process id @pid.
+ *
+ * This is a synchronous call - the calling thread is blocked until a
+ * reply is received. For the asynchronous version, see
+ * polkit_unix_session_new_for_process().
+ *
+ * Returns: (allow-none) (transfer full): A #PolkitUnixSession for
+ * @pid or %NULL if @error is set. Free with g_object_unref().
+ **/
+PolkitSubject *
+polkit_unix_session_new_for_process_sync (gint pid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return POLKIT_SUBJECT (g_initable_new (POLKIT_TYPE_UNIX_SESSION,
+ cancellable,
+ error,
+ "pid", pid,
+ NULL));
+}
+
+static guint
+polkit_unix_session_hash (PolkitSubject *subject)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject);
+
+ return g_str_hash (session->session_id);
+}
+
+static gboolean
+polkit_unix_session_equal (PolkitSubject *a,
+ PolkitSubject *b)
+{
+ PolkitUnixSession *session_a;
+ PolkitUnixSession *session_b;
+
+ session_a = POLKIT_UNIX_SESSION (a);
+ session_b = POLKIT_UNIX_SESSION (b);
+
+ return g_strcmp0 (session_a->session_id, session_b->session_id) == 0;
+}
+
+static gchar *
+polkit_unix_session_to_string (PolkitSubject *subject)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject);
+
+ return g_strdup_printf ("unix-session:%s", session->session_id);
+}
+
+static gboolean
+polkit_unix_session_exists_sync (PolkitSubject *subject,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject);
+ gboolean ret;
+ uid_t uid;
+
+ ret = FALSE;
+
+ if (!sd_session_get_uid (session->session_id, &uid))
+ ret = FALSE;
+
+ return ret;
+}
+
+static void
+exists_in_thread_func (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error;
+ error = NULL;
+ if (!polkit_unix_session_exists_sync (POLKIT_SUBJECT (object),
+ cancellable,
+ &error))
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+}
+
+static void
+polkit_unix_session_exists (PolkitSubject *subject,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (POLKIT_IS_UNIX_SESSION (subject));
+
+ simple = g_simple_async_result_new (G_OBJECT (subject),
+ callback,
+ user_data,
+ polkit_unix_session_exists);
+ g_simple_async_result_run_in_thread (simple,
+ exists_in_thread_func,
+ G_PRIORITY_DEFAULT,
+ cancellable);
+ g_object_unref (simple);
+}
+
+static gboolean
+polkit_unix_session_exists_finish (PolkitSubject *subject,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ gboolean ret;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_unix_session_exists);
+
+ ret = FALSE;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = g_simple_async_result_get_op_res_gboolean (simple);
+
+ out:
+ return ret;
+}
+
+static void
+subject_iface_init (PolkitSubjectIface *subject_iface)
+{
+ subject_iface->hash = polkit_unix_session_hash;
+ subject_iface->equal = polkit_unix_session_equal;
+ subject_iface->to_string = polkit_unix_session_to_string;
+ subject_iface->exists = polkit_unix_session_exists;
+ subject_iface->exists_finish = polkit_unix_session_exists_finish;
+ subject_iface->exists_sync = polkit_unix_session_exists_sync;
+}
+
+static gboolean
+polkit_unix_session_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PolkitUnixSession *session = POLKIT_UNIX_SESSION (initable);
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (session->session_id != NULL)
+ {
+ /* already set, nothing to do */
+ ret = TRUE;
+ goto out;
+ }
+
+ if (!sd_pid_get_session (session->pid, &session->session_id))
+ ret = TRUE;
+
+out:
+ return ret;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+ initable_iface->init = polkit_unix_session_initable_init;
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
+{
+ /* use default implementation to run GInitable code in a thread */
+}
diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am
index 168ea63..b91cafa 100644
--- a/src/polkitbackend/Makefile.am
+++ b/src/polkitbackend/Makefile.am
@@ -38,20 +38,29 @@ libpolkit_backend_1_la_SOURCES = \
polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \
polkitbackendlocalauthority.h polkitbackendlocalauthority.c \
polkitbackendactionpool.h polkitbackendactionpool.c \
- polkitbackendsessionmonitor.h polkitbackendsessionmonitor.c \
polkitbackendconfigsource.h polkitbackendconfigsource.c \
polkitbackendactionlookup.h polkitbackendactionlookup.c \
polkitbackendlocalauthorizationstore.h polkitbackendlocalauthorizationstore.c \
$(NULL)
+if HAVE_SYSTEMD
+libpolkit_backend_1_la_SOURCES += \
+ polkitbackendsessionmonitor.h polkitbackendsessionmonitor-systemd.c
+else
+libpolkit_backend_1_la_SOURCES += \
+ polkitbackendsessionmonitor.h polkitbackendsessionmonitor.c
+endif
+
libpolkit_backend_1_la_CFLAGS = \
-D_POLKIT_COMPILATION \
-D_POLKIT_BACKEND_COMPILATION \
$(GLIB_CFLAGS) \
+ $(SYSTEMD_CFLAGS) \
$(NULL)
libpolkit_backend_1_la_LIBADD = \
$(GLIB_LIBS) \
+ $(SYSTEMD_LIBS) \
$(top_builddir)/src/polkit/libpolkit-gobject-1.la \
$(EXPAT_LIBS) \
$(NULL)
diff --git a/src/polkitbackend/polkitbackendsessionmonitor-systemd.c b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c
new file mode 100644
index 0000000..58593c3
--- /dev/null
+++ b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include <systemd/sd-login.h>
+#include <stdlib.h>
+
+#include <polkit/polkit.h>
+#include "polkitbackendsessionmonitor.h"
+
+/* <internal>
+ * SECTION:polkitbackendsessionmonitor
+ * @title: PolkitBackendSessionMonitor
+ * @short_description: Monitor sessions
+ *
+ * The #PolkitBackendSessionMonitor class is a utility class to track and monitor sessions.
+ */
+
+typedef struct
+{
+ GSource source;
+ GPollFD pollfd;
+ sd_login_monitor *monitor;
+} SdSource;
+
+static gboolean
+sd_source_prepare (GSource *source,
+ gint *timeout)
+{
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+sd_source_check (GSource *source)
+{
+ SdSource *sd_source = (SdSource *)source;
+
+ return sd_source->pollfd.revents != 0;
+}
+
+static gboolean
+sd_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+
+{
+ SdSource *sd_source = (SdSource *)source;
+ gboolean ret;
+
+ g_warn_if_fail (callback != NULL);
+
+ ret = (*callback) (user_data);
+
+ sd_login_monitor_flush (sd_source->monitor);
+
+ return ret;
+}
+
+static void
+sd_source_finalize (GSource *source)
+{
+ SdSource *sd_source = (SdSource*)source;
+
+ sd_login_monitor_unref (sd_source->monitor);
+}
+
+static GSourceFuncs sd_source_funcs = {
+ sd_source_prepare,
+ sd_source_check,
+ sd_source_dispatch,
+ sd_source_finalize
+};
+
+static GSource *
+sd_source_new (void)
+{
+ GSource *source;
+ SdSource *sd_source;
+ int ret;
+
+ source = g_source_new (&sd_source_funcs, sizeof (SdSource));
+ sd_source = (SdSource *)source;
+
+ if ((ret = sd_login_monitor_new (NULL, &sd_source->monitor)) < 0)
+ {
+ g_printerr ("Error getting login monitor: %d", ret);
+ }
+ else
+ {
+ sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor);
+ sd_source->pollfd.events = G_IO_IN;
+ g_source_add_poll (source, &sd_source->pollfd);
+ }
+
+ return source;
+}
+
+struct _PolkitBackendSessionMonitor
+{
+ GObject parent_instance;
+
+ GDBusConnection *system_bus;
+
+ GSource *sd_source;
+};
+
+struct _PolkitBackendSessionMonitorClass
+{
+ GObjectClass parent_class;
+
+ void (*changed) (PolkitBackendSessionMonitor *monitor);
+};
+
+
+enum
+{
+ CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (PolkitBackendSessionMonitor, polkit_backend_session_monitor, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+sessions_changed (gpointer user_data)
+{
+ PolkitBackendSessionMonitor *monitor = POLKIT_BACKEND_SESSION_MONITOR (user_data);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
+
+ return TRUE;
+}
+
+
+static void
+polkit_backend_session_monitor_init (PolkitBackendSessionMonitor *monitor)
+{
+ GError *error;
+
+ error = NULL;
+ monitor->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (monitor->system_bus == NULL)
+ {
+ g_printerr ("Error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+
+ monitor->sd_source = sd_source_new ();
+ g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL);
+ g_source_attach (monitor->sd_source, NULL);
+}
+
+static void
+polkit_backend_session_monitor_finalize (GObject *object)
+{
+ PolkitBackendSessionMonitor *monitor = POLKIT_BACKEND_SESSION_MONITOR (object);
+
+ if (monitor->system_bus != NULL)
+ g_object_unref (monitor->system_bus);
+
+ if (monitor->sd_source != NULL)
+ {
+ g_source_destroy (monitor->sd_source);
+ g_source_unref (monitor->sd_source);
+ }
+
+ if (G_OBJECT_CLASS (polkit_backend_session_monitor_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (polkit_backend_session_monitor_parent_class)->finalize (object);
+}
+
+static void
+polkit_backend_session_monitor_class_init (PolkitBackendSessionMonitorClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = polkit_backend_session_monitor_finalize;
+
+ /**
+ * PolkitBackendSessionMonitor::changed:
+ * @monitor: A #PolkitBackendSessionMonitor
+ *
+ * Emitted when something changes.
+ */
+ signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+ POLKIT_BACKEND_TYPE_SESSION_MONITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PolkitBackendSessionMonitorClass, changed),
+ NULL, /* accumulator */
+ NULL, /* accumulator data */
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+PolkitBackendSessionMonitor *
+polkit_backend_session_monitor_new (void)
+{
+ PolkitBackendSessionMonitor *monitor;
+
+ monitor = POLKIT_BACKEND_SESSION_MONITOR (g_object_new (POLKIT_BACKEND_TYPE_SESSION_MONITOR, NULL));
+
+ return monitor;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+GList *
+polkit_backend_session_monitor_get_sessions (PolkitBackendSessionMonitor *monitor)
+{
+ /* TODO */
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * polkit_backend_session_monitor_get_user:
+ * @monitor: A #PolkitBackendSessionMonitor.
+ * @subject: A #PolkitSubject.
+ * @error: Return location for error.
+ *
+ * Gets the user corresponding to @subject or %NULL if no user exists.
+ *
+ * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref().
+ */
+PolkitIdentity *
+polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor *monitor,
+ PolkitSubject *subject,
+ GError **error)
+{
+ PolkitIdentity *ret;
+ guint32 uid;
+
+ ret = NULL;
+
+ if (POLKIT_IS_UNIX_PROCESS (subject))
+ {
+ uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
+ if ((gint) uid == -1)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Unix process subject does not have uid set");
+ goto out;
+ }
+ ret = polkit_unix_user_new (uid);
+ }
+ else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
+ {
+ GVariant *result;
+
+ result = g_dbus_connection_call_sync (monitor->system_bus,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixUser",
+ g_variant_new ("(s)", polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject))),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout_msec */
+ NULL, /* GCancellable */
+ error);
+ if (result == NULL)
+ goto out;
+ g_variant_get (result, "(u)", &uid);
+ g_variant_unref (result);
+
+ ret = polkit_unix_user_new (uid);
+ }
+ else if (POLKIT_IS_UNIX_SESSION (subject))
+ {
+
+ if (sd_session_get_uid (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (subject)), &uid) < 0)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Error getting uid for session");
+ goto out;
+ }
+
+ ret = polkit_unix_user_new (uid);
+ }
+
+ out:
+ return ret;
+}
+
+/**
+ * polkit_backend_session_monitor_get_session_for_subject:
+ * @monitor: A #PolkitBackendSessionMonitor.
+ * @subject: A #PolkitSubject.
+ * @error: Return location for error.
+ *
+ * Gets the session corresponding to @subject or %NULL if no session exists.
+ *
+ * Returns: %NULL if @error is set otherwise a #PolkitUnixSession that should be freed with g_object_unref().
+ */
+PolkitSubject *
+polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMonitor *monitor,
+ PolkitSubject *subject,
+ GError **error)
+{
+ PolkitSubject *session;
+
+ session = NULL;
+
+ if (POLKIT_IS_UNIX_PROCESS (subject))
+ {
+ gchar *session_id;
+ pid_t pid;
+
+ pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject));
+ if (sd_pid_get_session (pid, &session_id) < 0)
+ goto out;
+
+ session = polkit_unix_session_new (session_id);
+ free (session_id);
+ }
+ else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
+ {
+ guint32 pid;
+ gchar *session_id;
+ GVariant *result;
+
+ result = g_dbus_connection_call_sync (monitor->system_bus,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID",
+ g_variant_new ("(s)", polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject))),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout_msec */
+ NULL, /* GCancellable */
+ error);
+ if (result == NULL)
+ goto out;
+ g_variant_get (result, "(u)", &pid);
+ g_variant_unref (result);
+
+ if (sd_pid_get_session (pid, &session_id) < 0)
+ goto out;
+
+ session = polkit_unix_session_new (session_id);
+ free (session_id);
+ }
+ else
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_NOT_SUPPORTED,
+ "Cannot get user for subject of type %s",
+ g_type_name (G_TYPE_FROM_INSTANCE (subject)));
+ }
+
+ out:
+
+ return session;
+}
+
+gboolean
+polkit_backend_session_monitor_is_session_local (PolkitBackendSessionMonitor *monitor,
+ PolkitSubject *session)
+{
+ char *seat;
+
+ if (!sd_session_get_seat (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (session)), &seat))
+ {
+ free (seat);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+gboolean
+polkit_backend_session_monitor_is_session_active (PolkitBackendSessionMonitor *monitor,
+ PolkitSubject *session)
+{
+ return sd_session_is_active (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (session)));
+}
+