diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml
index 88da3c0..eea05ae 100644
--- a/data/org.freedesktop.PolicyKit1.Authority.xml
+++ b/data/org.freedesktop.PolicyKit1.Authority.xml
@@ -431,7 +431,7 @@ Must match the effective UID of the caller of org.freedesktop.PolicyKit1.Authori
-
+
diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
index 71d527c..93691b6 100644
--- a/src/polkit/polkitauthority.c
+++ b/src/polkit/polkitauthority.c
@@ -84,6 +84,7 @@ static PolkitAuthority *the_authority = NULL;
enum
{
CHANGED_SIGNAL,
+ SESSIONS_CHANGED_SIGNAL,
LAST_SIGNAL,
};
@@ -113,9 +114,19 @@ on_proxy_signal (GDBusProxy *proxy,
gpointer user_data)
{
PolkitAuthority *authority = POLKIT_AUTHORITY (user_data);
+ guint16 msg_mask;
+
if (g_strcmp0 (signal_name, "Changed") == 0)
{
- g_signal_emit_by_name (authority, "changed");
+ if ((parameters != NULL) && g_variant_check_format_string(parameters, "(q)", FALSE ) )
+ {
+ g_variant_get(parameters, "(q)", &msg_mask);
+ g_signal_emit (authority, signals[msg_mask], 0);
+ }
+ else
+ {
+ g_signal_emit_by_name (authority, "changed");
+ }
}
}
@@ -287,6 +298,21 @@ polkit_authority_class_init (PolkitAuthorityClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+ /**
+ * PolkitAuthority::sessions-changed:
+ * @authority: A #PolkitAuthority.
+ *
+ * Emitted when sessions change
+ */
+ signals[SESSIONS_CHANGED_SIGNAL] = g_signal_new ("sessions-changed",
+ POLKIT_TYPE_AUTHORITY,
+ G_SIGNAL_RUN_LAST,
+ 0, /* class offset */
+ NULL, /* accumulator */
+ NULL, /* accumulator data */
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/polkit/polkitpermission.c b/src/polkit/polkitpermission.c
index f264094..3231bf2 100644
--- a/src/polkit/polkitpermission.c
+++ b/src/polkit/polkitpermission.c
@@ -24,6 +24,10 @@
# include "config.h"
#endif
+#ifdef HAVE_LIBSYSTEMD
+# include
+#endif
+
#include
#include
@@ -60,6 +64,8 @@ struct _PolkitPermission
gchar *action_id;
+ gchar *session_state;
+
/* non-NULL exactly when authorized with a temporary authorization */
gchar *tmp_authz_id;
};
@@ -74,9 +80,14 @@ enum
static void process_result (PolkitPermission *permission,
PolkitAuthorizationResult *result);
+static char *get_session_state();
+
static void on_authority_changed (PolkitAuthority *authority,
gpointer user_data);
+static void on_sessions_changed (PolkitAuthority *authority,
+ gpointer user_data);
+
static gboolean acquire (GPermission *permission,
GCancellable *cancellable,
GError **error);
@@ -126,6 +137,8 @@ polkit_permission_constructed (GObject *object)
if (G_OBJECT_CLASS (polkit_permission_parent_class)->constructed != NULL)
G_OBJECT_CLASS (polkit_permission_parent_class)->constructed (object);
+
+ permission->session_state = get_session_state();
}
static void
@@ -135,11 +148,15 @@ polkit_permission_finalize (GObject *object)
g_free (permission->action_id);
g_free (permission->tmp_authz_id);
+ g_free (permission->session_state);
g_object_unref (permission->subject);
g_signal_handlers_disconnect_by_func (permission->authority,
on_authority_changed,
permission);
+ g_signal_handlers_disconnect_by_func (permission->authority,
+ on_sessions_changed,
+ permission);
g_object_unref (permission->authority);
if (G_OBJECT_CLASS (polkit_permission_parent_class)->finalize != NULL)
@@ -417,6 +434,11 @@ polkit_permission_initable_init (GInitable *initable,
G_CALLBACK (on_authority_changed),
permission);
+ g_signal_connect (permission->authority,
+ "sessions-changed",
+ G_CALLBACK (on_sessions_changed),
+ permission);
+
result = polkit_authority_check_authorization_sync (permission->authority,
permission->subject,
permission->action_id,
@@ -469,6 +491,37 @@ changed_check_cb (GObject *source_object,
g_object_unref (permission);
}
+static char *get_session_state()
+{
+#ifdef HAVE_LIBSYSTEMD
+ char *session = NULL;
+ char *state = NULL;
+ uid_t uid;
+
+ if ( sd_pid_get_session(getpid(), &session) < 0 )
+ {
+ if ( sd_pid_get_owner_uid(getpid(), &uid) < 0)
+ {
+ goto out;
+ }
+ if (sd_uid_get_display(uid, &session) < 0)
+ {
+ goto out;
+ }
+ }
+
+ if (session != NULL)
+ {
+ sd_session_get_state(session, &state);
+ }
+out:
+ g_free(session);
+ return state;
+#else
+ return NULL;
+#endif
+}
+
static void
on_authority_changed (PolkitAuthority *authority,
gpointer user_data)
@@ -485,6 +538,40 @@ on_authority_changed (PolkitAuthority *authority,
g_object_ref (permission));
}
+
+static void on_sessions_changed (PolkitAuthority *authority,
+ gpointer user_data)
+{
+#ifdef HAVE_LIBSYSTEMD
+ char *new_session_state = NULL;
+ char *last_state = NULL;
+
+ PolkitPermission *permission = POLKIT_PERMISSION (user_data);
+
+ new_session_state = get_session_state();
+
+ /* if we cannot tell the session state, we should do CheckAuthorization anyway */
+ if ((new_session_state == NULL) || ( g_strcmp0(new_session_state, permission->session_state) != 0 ))
+ {
+ last_state = permission->session_state;
+ permission->session_state = new_session_state;
+ g_free(last_state);
+
+ polkit_authority_check_authorization (permission->authority,
+ permission->subject,
+ permission->action_id,
+ NULL, /* PolkitDetails */
+ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
+ NULL /* cancellable */,
+ changed_check_cb,
+ g_object_ref (permission));
+ }
+#else
+ on_authority_changed(authority, user_data); /* TODO: resolve the "too many session signals" issue for non-systemd systems later */
+#endif
+}
+
+
static void
process_result (PolkitPermission *permission,
PolkitAuthorizationResult *result)
diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c
index 0d1fac4..6d21af9 100644
--- a/src/polkitbackend/polkitbackendauthority.c
+++ b/src/polkitbackend/polkitbackendauthority.c
@@ -48,6 +48,7 @@
enum
{
CHANGED_SIGNAL,
+ SESSIONS_CHANGED_SIGNAL,
LAST_SIGNAL,
};
@@ -78,6 +79,15 @@ polkit_backend_authority_class_init (PolkitBackendAuthorityClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+ signals[SESSIONS_CHANGED_SIGNAL] = g_signal_new ("sessions-changed",
+ POLKIT_BACKEND_TYPE_AUTHORITY,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PolkitBackendAuthorityClass, changed),
+ NULL, /* accumulator */
+ NULL, /* accumulator data */
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
/**
@@ -501,6 +511,8 @@ typedef struct
gulong authority_changed_id;
+ gulong authority_session_monitor_signaller;
+
gchar *object_path;
GHashTable *cancellation_id_to_check_auth_data;
@@ -523,6 +535,9 @@ server_free (Server *server)
if (server->authority != NULL && server->authority_changed_id > 0)
g_signal_handler_disconnect (server->authority, server->authority_changed_id);
+ if (server->authority != NULL && server->authority_session_monitor_signaller > 0)
+ g_signal_handler_disconnect (server->authority, server->authority_session_monitor_signaller);
+
if (server->cancellation_id_to_check_auth_data != NULL)
g_hash_table_unref (server->cancellation_id_to_check_auth_data);
@@ -531,20 +546,23 @@ server_free (Server *server)
g_free (server);
}
-static void
-on_authority_changed (PolkitBackendAuthority *authority,
- gpointer user_data)
+static void changed_dbus_call_handler(PolkitBackendAuthority *authority,
+ gpointer user_data,
+ guint16 msg_mask)
{
Server *server = user_data;
GError *error;
+ GVariant *parameters;
error = NULL;
+
+ parameters = g_variant_new("(q)", msg_mask);
if (!g_dbus_connection_emit_signal (server->connection,
NULL, /* destination bus name */
server->object_path,
"org.freedesktop.PolicyKit1.Authority",
"Changed",
- NULL,
+ parameters,
&error))
{
g_warning ("Error emitting Changed() signal: %s", error->message);
@@ -552,6 +570,29 @@ on_authority_changed (PolkitBackendAuthority *authority,
}
}
+
+static void
+on_authority_changed (PolkitBackendAuthority *authority,
+ gpointer user_data)
+{
+ guint16 msg_mask = 0;
+
+ msg_mask = (guint16) CHANGED_SIGNAL;
+ changed_dbus_call_handler(authority, user_data, msg_mask);
+}
+
+
+static void
+on_sessions_changed (PolkitBackendAuthority *authority,
+ gpointer user_data)
+{
+ guint16 msg_mask = 0;
+
+ msg_mask = (guint16) SESSIONS_CHANGED_SIGNAL;
+ changed_dbus_call_handler(authority, user_data, msg_mask);
+}
+
+
static const gchar *server_introspection_data =
""
" "
@@ -1397,6 +1438,11 @@ polkit_backend_authority_register (PolkitBackendAuthority *authority,
G_CALLBACK (on_authority_changed),
server);
+ server->authority_session_monitor_signaller = g_signal_connect (server->authority,
+ "sessions-changed",
+ G_CALLBACK (on_sessions_changed),
+ server);
+
return server;
error:
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index 08d439e..40376dd 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -284,7 +284,7 @@ on_session_monitor_changed (PolkitBackendSessionMonitor *monitor,
gpointer user_data)
{
PolkitBackendInteractiveAuthority *authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (user_data);
- g_signal_emit_by_name (authority, "changed");
+ g_signal_emit_by_name (authority, "sessions-changed");
}
static void