summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nm-auth-utils.c162
-rw-r--r--src/nm-auth-utils.h4
2 files changed, 138 insertions, 28 deletions
diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c
index ca2870db72..663739b457 100644
--- a/src/nm-auth-utils.c
+++ b/src/nm-auth-utils.c
@@ -27,11 +27,19 @@ struct _NMAuthChain {
GDBusMethodInvocation *context;
NMAuthSubject *subject;
+ GCancellable *cancellable;
+
+ /* if set, it also means that the chain is already started and was cancelled. */
+ GSource *cancellable_idle_source;
+
NMAuthChainResultFunc done_func;
gpointer user_data;
+ gulong cancellable_id;
+
guint num_pending_auth_calls;
+ bool is_started:1;
bool is_destroyed:1;
bool is_finishing:1;
};
@@ -78,6 +86,82 @@ _ASSERT_call (AuthCall *call)
/*****************************************************************************/
static void
+_done_and_destroy (NMAuthChain *self)
+{
+ self->is_finishing = TRUE;
+ self->done_func (self, self->context, self->user_data);
+ nm_assert (self->is_finishing);
+ _auth_chain_destroy (self);
+}
+
+static gboolean
+_cancellable_idle_cb (gpointer user_data)
+{
+ NMAuthChain *self = user_data;
+ AuthCall *call;
+
+ nm_assert (g_cancellable_is_cancelled (self->cancellable));
+ nm_assert (self->cancellable_idle_source);
+
+ c_list_for_each_entry (call, &self->auth_call_lst_head, auth_call_lst) {
+ if (call->call_id) {
+ self->num_pending_auth_calls--;
+ nm_auth_manager_check_authorization_cancel (g_steal_pointer (&call->call_id));
+ }
+ }
+
+ _done_and_destroy (self);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+_cancellable_on_idle (NMAuthChain *self)
+{
+ if (self->cancellable_idle_source)
+ return;
+
+ self->cancellable_idle_source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
+ _cancellable_idle_cb,
+ self,
+ NULL);
+ g_source_attach (self->cancellable_idle_source, NULL);
+}
+
+GCancellable *
+nm_auth_chain_get_cancellable (NMAuthChain *self)
+{
+ return self->cancellable;
+}
+
+static void
+_cancellable_cancelled (GCancellable *cancellable,
+ NMAuthChain *self)
+{
+ _cancellable_on_idle (self);
+}
+
+void
+nm_auth_chain_set_cancellable (NMAuthChain *self,
+ GCancellable *cancellable)
+{
+ g_return_if_fail (self);
+ g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+ /* after the chain is started, the cancellable can no longer be changed.
+ * No need to handle the complexity of swapping the cancellable *after*
+ * requests are already started. */
+ g_return_if_fail (!self->is_started);
+ nm_assert (c_list_is_empty (&self->auth_call_lst_head));
+
+ /* also no need to allow setting different cancellables. */
+ g_return_if_fail (!self->cancellable);
+
+ self->cancellable = g_object_ref (cancellable);
+}
+
+/*****************************************************************************/
+
+static void
auth_call_free (AuthCall *call)
{
_ASSERT_call (call);
@@ -87,7 +171,7 @@ auth_call_free (AuthCall *call)
call->chain->num_pending_auth_calls--;
nm_auth_manager_check_authorization_cancel (call->call_id);
}
- g_slice_free (AuthCall, call);
+ nm_g_slice_free (call);
}
static AuthCall *
@@ -255,6 +339,12 @@ nm_auth_chain_get_result (NMAuthChain *self, const char *permission)
nm_assert (!auth_call->call_id);
+ if (self->cancellable_idle_source) {
+ /* already cancelled. We always return unknown (even if we happen to
+ * have already received the response. */
+ return NM_AUTH_CALL_RESULT_UNKNOWN;
+ }
+
return auth_call->result;
}
@@ -314,10 +404,7 @@ pk_call_cb (NMAuthManager *auth_manager,
if (call->chain->num_pending_auth_calls == 0) {
/* we are on an idle-handler or a clean call-stack (non-reentrant) so it's safe
* to invoke the callback right away. */
- self->is_finishing = TRUE;
- self->done_func (self, self->context, self->user_data);
- nm_assert (self->is_finishing);
- _auth_chain_destroy (self);
+ _done_and_destroy (self);
}
}
@@ -350,23 +437,36 @@ nm_auth_chain_add_call_unsafe (NMAuthChain *self,
g_return_if_fail (!self->is_finishing);
g_return_if_fail (!self->is_destroyed);
g_return_if_fail (permission && *permission);
- nm_assert ( nm_auth_subject_get_subject_type (self->subject)
- == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS
- || nm_auth_subject_get_subject_type (self->subject)
- == NM_AUTH_SUBJECT_TYPE_INTERNAL);
+ nm_assert (NM_IN_SET (nm_auth_subject_get_subject_type (self->subject), NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
+ NM_AUTH_SUBJECT_TYPE_INTERNAL));
/* duplicate permissions are not supported, also because nm_auth_chain_get_result()
* can only return one-permission. */
nm_assert (!_find_auth_call (self, permission));
- call = g_slice_new (AuthCall);
+ if (!self->is_started) {
+ self->is_started = TRUE;
+ nm_assert (!self->cancellable_id);
+ if (self->cancellable) {
+ if (g_cancellable_is_cancelled (self->cancellable)) {
+ /* the operation is already cancelled. Schedule the callback on idle. */
+ _cancellable_on_idle (self);
+ } else {
+ self->cancellable_id = g_signal_connect (self->cancellable,
+ "cancelled",
+ G_CALLBACK (_cancellable_cancelled),
+ self);
+ }
+ }
+ }
+ call = g_slice_new (AuthCall);
*call = (AuthCall) {
.chain = self,
.call_id = NULL,
.result = NM_AUTH_CALL_RESULT_UNKNOWN,
- /* we don't clone the permission string. It's the callers responsiblity. */
+ /* we don't clone the permission string. It's the callers responsibility. */
.permission = permission,
};
@@ -375,14 +475,19 @@ nm_auth_chain_add_call_unsafe (NMAuthChain *self,
* call. */
c_list_link_front (&self->auth_call_lst_head, &call->auth_call_lst);
- call->call_id = nm_auth_manager_check_authorization (nm_auth_manager_get (),
- self->subject,
- permission,
- allow_interaction,
- pk_call_cb,
- call);
-
- self->num_pending_auth_calls++;
+ if (self->cancellable_idle_source) {
+ /* already cancelled. No need to actually start the request. */
+ nm_assert (call->result == NM_AUTH_CALL_RESULT_UNKNOWN);
+ } else {
+ call->call_id = nm_auth_manager_check_authorization (nm_auth_manager_get (),
+ self->subject,
+ permission,
+ allow_interaction,
+ pk_call_cb,
+ call);
+
+ self->num_pending_auth_calls++;
+ }
_ASSERT_call (call);
@@ -427,10 +532,8 @@ nm_auth_chain_new_subject (NMAuthSubject *subject,
NMAuthChain *self;
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
- nm_assert ( nm_auth_subject_get_subject_type (subject)
- == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS
- || nm_auth_subject_get_subject_type (subject)
- == NM_AUTH_SUBJECT_TYPE_INTERNAL);
+ nm_assert (NM_IN_SET (nm_auth_subject_get_subject_type (subject), NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
+ NM_AUTH_SUBJECT_TYPE_INTERNAL));
nm_assert (done_func);
self = g_slice_new (NMAuthChain);
@@ -489,6 +592,9 @@ _auth_chain_destroy (NMAuthChain *self)
nm_clear_g_object (&self->subject);
nm_clear_g_object (&self->context);
+ nm_clear_g_signal_handler (self->cancellable, &self->cancellable_id);
+ nm_clear_g_source_inst (&self->cancellable_idle_source);
+
/* we must first destry all AuthCall instances before ChainData. The reason is
* that AuthData.permission is not cloned and the lifetime of the string must
* be ensured by the caller. A sensible thing to do for the caller is attach the
@@ -499,7 +605,9 @@ _auth_chain_destroy (NMAuthChain *self)
while ((chain_data = c_list_first_entry (&self->data_lst_head, ChainData, data_lst)))
chain_data_free (chain_data);
- g_slice_free (NMAuthChain, self);
+ nm_g_object_unref (self->cancellable);
+
+ nm_g_slice_free (self);
}
/******************************************************************************
@@ -517,10 +625,8 @@ nm_auth_is_subject_in_acl (NMConnection *connection,
g_return_val_if_fail (connection, FALSE);
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), FALSE);
- nm_assert ( nm_auth_subject_get_subject_type (subject)
- == NM_AUTH_SUBJECT_TYPE_INTERNAL
- || nm_auth_subject_get_subject_type (subject)
- == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
+ nm_assert (NM_IN_SET (nm_auth_subject_get_subject_type (subject), NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
+ NM_AUTH_SUBJECT_TYPE_INTERNAL));
if (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL)
return TRUE;
diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h
index 978d607aed..a6c6d65965 100644
--- a/src/nm-auth-utils.h
+++ b/src/nm-auth-utils.h
@@ -27,6 +27,10 @@ NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject,
NMAuthChainResultFunc done_func,
gpointer user_data);
+GCancellable *nm_auth_chain_get_cancellable (NMAuthChain *self);
+void nm_auth_chain_set_cancellable (NMAuthChain *self,
+ GCancellable *cancellable);
+
gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag);
gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag);