From 49814f87442dd99d0021c41a3938c4e230888d4d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 19 Dec 2011 22:37:05 -0500 Subject: [PATCH] Add optional systemd support When configured with --enable-systemd, this patch makes polkit use systemd for session tracking instead of ConsoleKit. --- configure.ac | 24 +- src/polkit/Makefile.am | 11 +- src/polkit/polkitunixsession-systemd.c | 481 ++++++++++++++++++++ src/polkitbackend/Makefile.am | 11 +- .../polkitbackendsessionmonitor-systemd.c | 414 +++++++++++++++++ 5 files changed, 937 insertions(+), 4 deletions(-) create mode 100644 src/polkit/polkitunixsession-systemd.c create mode 100644 src/polkitbackend/polkitbackendsessionmonitor-systemd.c diff --git a/configure.ac b/configure.ac index a1650ef..a6aa078 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,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 --------------------------------------------------------------------------- @@ -443,7 +463,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 @@ -453,7 +474,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 9d7c4ce..3b5e2d5 100644 --- a/src/polkit/Makefile.am +++ b/src/polkit/Makefile.am @@ -68,7 +68,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 \ @@ -80,13 +79,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 +#include "polkitunixsession.h" +#include "polkitsubject.h" +#include "polkiterror.h" +#include "polkitprivate.h" + +#include + +/** + * 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 + * thread-default + * main loop 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 +#include +#include +#include +#include +#include +#include + +#include +#include "polkitbackendsessionmonitor.h" + +/* + * 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))); +} + -- 1.7.7.4