summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2009-08-12 11:52:46 -0400
committerDavid Zeuthen <davidz@redhat.com>2009-08-12 11:52:46 -0400
commitf1e312653c7c7d3eafcfb6a55b884faa19e5ea5d (patch)
treeef56d22c4ae9fbf41dba160b31d3d69d03bb1a13 /src
parent6806b4883077745c3f288cfe679181a61849f97f (diff)
downloadpolkit-f1e312653c7c7d3eafcfb6a55b884faa19e5ea5d.tar.gz
Remove temporary authorization when the subject it applies to vanishes
This makes it easier to write the desktop component showing a notification icon - said component now only needs to watch ::changed and reenumerate temporary authorizations. If this is done, then the notification icon is updated in near-realtime. Also emit ::changed on ConsoleKit changes. This helps remind Mechanisms that they should redo an authorization check (if this is how the Mechanism decides to cache authorizations).
Diffstat (limited to 'src')
-rw-r--r--src/polkitbackend/polkitbackendinteractiveauthority.c150
-rw-r--r--src/polkitbackend/polkitbackendsessionmonitor.c37
2 files changed, 184 insertions, 3 deletions
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index c5cf4d2..811d169 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -63,6 +63,9 @@ static const gchar *temporary_authorization_store_add_authorization (TemporaryAu
PolkitSubject *session,
const gchar *action_id);
+static void temporary_authorization_store_remove_authorizations_for_system_bus_name (TemporaryAuthorizationStore *store,
+ const gchar *name);
+
/* ---------------------------------------------------------------------------------------------------- */
struct AuthenticationAgent;
@@ -214,6 +217,14 @@ action_pool_changed (PolkitBackendActionPool *action_pool,
/* ---------------------------------------------------------------------------------------------------- */
static void
+on_session_monitor_changed (PolkitBackendSessionMonitor *monitor,
+ gpointer user_data)
+{
+ PolkitBackendInteractiveAuthority *authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (user_data);
+ g_signal_emit_by_name (authority, "changed");
+}
+
+static void
polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *authority)
{
PolkitBackendInteractiveAuthorityPrivate *priv;
@@ -237,6 +248,10 @@ polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *au
(GDestroyNotify) authentication_agent_free);
priv->session_monitor = polkit_backend_session_monitor_new ();
+ g_signal_connect (priv->session_monitor,
+ "changed",
+ G_CALLBACK (on_session_monitor_changed),
+ authority);
}
static void
@@ -1868,6 +1883,12 @@ polkit_backend_interactive_authority_system_bus_name_owner_changed (PolkitBacken
}
g_list_free (sessions);
+ /* remove all temporary authorizations that applies to the vanished name
+ * (temporary_authorization_store_add_authorization for the code path for handling processes)
+ */
+ temporary_authorization_store_remove_authorizations_for_system_bus_name (priv->temporary_authorization_store,
+ name);
+
}
}
@@ -1893,6 +1914,7 @@ struct TemporaryAuthorization
guint64 time_granted;
guint64 time_expires;
guint expiration_timeout_id;
+ guint check_vanished_timeout_id;
};
static void
@@ -1904,6 +1926,8 @@ temporary_authorization_free (TemporaryAuthorization *authorization)
g_free (authorization->action_id);
if (authorization->expiration_timeout_id > 0)
g_source_remove (authorization->expiration_timeout_id);
+ if (authorization->check_vanished_timeout_id > 0)
+ g_source_remove (authorization->check_vanished_timeout_id);
g_free (authorization);
}
@@ -1963,6 +1987,15 @@ static gboolean
on_expiration_timeout (gpointer user_data)
{
TemporaryAuthorization *authorization = user_data;
+ gchar *s;
+
+ s = polkit_subject_to_string (authorization->subject);
+ g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
+ "authorization has expired",
+ authorization->id,
+ authorization->action_id,
+ s);
+ g_free (s);
authorization->store->authorizations = g_list_remove (authorization->store->authorizations,
authorization);
@@ -1974,6 +2007,86 @@ on_expiration_timeout (gpointer user_data)
return FALSE;
}
+static gboolean
+on_unix_process_check_vanished_timeout (gpointer user_data)
+{
+ TemporaryAuthorization *authorization = user_data;
+ GError *error;
+
+ /* we know that this is a PolkitUnixProcess so the check is fast (no IPC involved) */
+ error = NULL;
+ if (!polkit_subject_exists_sync (authorization->subject,
+ NULL,
+ &error))
+ {
+ if (error != NULL)
+ {
+ g_warning ("Error checking if process exists: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ gchar *s;
+
+ s = polkit_subject_to_string (authorization->subject);
+ g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
+ "subject has vanished",
+ authorization->id,
+ authorization->action_id,
+ s);
+ g_free (s);
+
+ authorization->store->authorizations = g_list_remove (authorization->store->authorizations,
+ authorization);
+ g_signal_emit_by_name (authorization->store->authority, "changed");
+ temporary_authorization_free (authorization);
+ }
+ }
+
+ /* keep source around */
+ return TRUE;
+}
+
+static void
+temporary_authorization_store_remove_authorizations_for_system_bus_name (TemporaryAuthorizationStore *store,
+ const gchar *name)
+{
+ guint num_removed;
+ GList *l, *ll;
+
+ num_removed = 0;
+ for (l = store->authorizations; l != NULL; l = ll)
+ {
+ TemporaryAuthorization *ta = l->data;
+ gchar *s;
+
+ ll = l->next;
+
+ if (!POLKIT_IS_SYSTEM_BUS_NAME (ta->subject))
+ continue;
+
+ if (g_strcmp0 (name, polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (ta->subject))) != 0)
+ continue;
+
+
+ s = polkit_subject_to_string (ta->subject);
+ g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
+ "subject has vanished",
+ ta->id,
+ ta->action_id,
+ s);
+ g_free (s);
+
+ store->authorizations = g_list_remove (store->authorizations, ta);
+ temporary_authorization_free (ta);
+
+ num_removed++;
+ }
+
+ if (num_removed > 0)
+ g_signal_emit_by_name (store->authority, "changed");
+}
+
static const gchar *
temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store,
PolkitSubject *subject,
@@ -1988,9 +2101,10 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st
g_return_val_if_fail (action_id != NULL, NULL);
g_return_val_if_fail (!temporary_authorization_store_has_authorization (store, subject, action_id, NULL), NULL);
- /* TODO: right now this is hard-coded - we could make it a propery on the
- * PolkitBackendInteractiveAuthority class. Or we could even read
- * it per action from an annotation.
+ /* TODO: right now the time the temporary authorization is kept is hard-coded - we
+ * could make it a propery on the PolkitBackendInteractiveAuthority class (so
+ * the local authority could read it from a config file) or a vfunc
+ * (so the local authority could read it from an annotation on the action).
*/
expiration_seconds = 5 * 60;
@@ -2006,6 +2120,36 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st
on_expiration_timeout,
authorization);
+ if (POLKIT_IS_UNIX_PROCESS (authorization->subject))
+ {
+ /* For now, set up a timer to poll every two seconds - this is used to determine
+ * when the process vanishes. We want to do this so we can remove the temporary
+ * authorization - this is because we want agents to update e.g. a notification
+ * area icon saying the user has temporary authorizations (e.g. remove the icon).
+ *
+ * Ideally we'd just do
+ *
+ * g_signal_connect (kernel, "process-exited", G_CALLBACK (on_process_exited), user_data);
+ *
+ * but that is not how things work right now (and, hey, it's not like the kernel
+ * is a GObject either!) - so we poll.
+ *
+ * TODO: On Linux, it might be possible to obtain notifications by connecting
+ * to the netlink socket. Needs looking into.
+ */
+
+ authorization->check_vanished_timeout_id = g_timeout_add_seconds (2,
+ on_unix_process_check_vanished_timeout,
+ authorization);
+ }
+#if 0
+ else if (POLKIT_IS_SYSTEM_BUS_NAME (authorization->subject))
+ {
+ /* This is currently handled in polkit_backend_interactive_authority_system_bus_name_owner_changed() */
+ }
+#endif
+
+
store->authorizations = g_list_prepend (store->authorizations, authorization);
return authorization->id;
diff --git a/src/polkitbackend/polkitbackendsessionmonitor.c b/src/polkitbackend/polkitbackendsessionmonitor.c
index eca8bd8..ecdd6a6 100644
--- a/src/polkitbackend/polkitbackendsessionmonitor.c
+++ b/src/polkitbackend/polkitbackendsessionmonitor.c
@@ -55,8 +55,18 @@ struct _PolkitBackendSessionMonitorClass
{
GObjectClass parent_class;
+ void (*changed) (PolkitBackendSessionMonitor *monitor);
};
+
+enum
+{
+ CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
static void seat_session_added (CkSeat *seat,
const gchar *object_path,
gpointer user_data);
@@ -154,6 +164,8 @@ manager_seat_added (CkManager *manager,
//g_debug ("seat %s added", object_path);
add_seat (monitor, object_path);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
}
static void
@@ -166,6 +178,8 @@ manager_seat_removed (CkManager *manager,
//g_debug ("seat %s removed", object_path);
remove_seat (monitor, object_path);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
}
static void
@@ -178,6 +192,8 @@ seat_session_added (CkSeat *seat,
//g_debug ("session %s added", object_path);
add_session (monitor, object_path);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
}
static void
@@ -190,6 +206,8 @@ seat_session_removed (CkSeat *seat,
//g_debug ("session %s removed", object_path);
remove_session (monitor, object_path);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
}
static void
@@ -197,6 +215,7 @@ session_active_changed (CkSession *session,
gboolean is_active,
gpointer user_data)
{
+ PolkitBackendSessionMonitor *monitor = POLKIT_BACKEND_SESSION_MONITOR (user_data);
EggDBusObjectProxy *object_proxy;
object_proxy = egg_dbus_interface_proxy_get_object_proxy (EGG_DBUS_INTERFACE_PROXY (session));
@@ -204,6 +223,8 @@ session_active_changed (CkSession *session,
//g_debug ("session %s active changed to %d", egg_dbus_object_proxy_get_object_path (object_proxy), is_active);
egg_dbus_object_proxy_invalidate_properties (object_proxy);
+
+ g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -307,6 +328,22 @@ polkit_backend_session_monitor_class_init (PolkitBackendSessionMonitorClass *kla
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 *