summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-04-28 18:38:01 +0200
committerThomas Haller <thaller@redhat.com>2020-04-28 18:38:01 +0200
commitdaee41b82af023d72bbaa55ca213e31a3a43d35d (patch)
treece4d2ed3bef8101b314053fa1537c67f5c474b15
parentc8a97031308f3308f7983eabce390e758f9cf11d (diff)
parentf6e438860bdb03166bbf38d61e115e960e5c60c7 (diff)
downloadNetworkManager-daee41b82af023d72bbaa55ca213e31a3a43d35d.tar.gz
wifi: merge branch 'th/wifi-scan' (part 1)
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/479
-rw-r--r--shared/nm-glib-aux/nm-glib.h8
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.c11
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.h3
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c18
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h2
-rw-r--r--src/devices/nm-device-private.h13
-rw-r--r--src/devices/nm-device.c115
-rw-r--r--src/devices/nm-device.h7
-rw-r--r--src/devices/wifi/nm-device-iwd.c16
-rw-r--r--src/devices/wifi/nm-device-wifi.c20
-rw-r--r--src/nm-auth-utils.c250
-rw-r--r--src/nm-auth-utils.h4
-rw-r--r--src/nm-manager.c115
-rw-r--r--src/nm-manager.h12
-rw-r--r--src/nm-types.h6
-rw-r--r--src/supplicant/nm-supplicant-interface.c11
16 files changed, 427 insertions, 184 deletions
diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h
index 4ecba9ffca..7a5b8edd7d 100644
--- a/shared/nm-glib-aux/nm-glib.h
+++ b/shared/nm-glib-aux/nm-glib.h
@@ -622,4 +622,12 @@ g_hash_table_steal_extended (GHashTable *hash_table,
/*****************************************************************************/
+__attribute__((__deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead.")))
+void _nm_g_cancellable_reset (GCancellable *cancellable);
+
+#undef g_cancellable_reset
+#define g_cancellable_reset(cancellable) _nm_g_cancellable_reset(cancellable)
+
+/*****************************************************************************/
+
#endif /* __NM_GLIB_H__ */
diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c
index 0a701d06e1..232c62c036 100644
--- a/shared/nm-glib-aux/nm-hash-utils.c
+++ b/shared/nm-glib-aux/nm-hash-utils.c
@@ -265,6 +265,17 @@ nm_ppdirect_equal (gconstpointer a, gconstpointer b)
/*****************************************************************************/
guint
+nm_gbytes_hash (gconstpointer p)
+{
+ GBytes *ptr = (GBytes *) p;
+ gconstpointer arr;
+ gsize len;
+
+ arr = g_bytes_get_data (ptr, &len);
+ return nm_hash_mem (792701303u, arr, len);
+}
+
+guint
nm_pgbytes_hash (gconstpointer p)
{
GBytes *const*ptr = p;
diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h
index 9f2e976678..be69bfa8dc 100644
--- a/shared/nm-glib-aux/nm-hash-utils.h
+++ b/shared/nm-glib-aux/nm-hash-utils.h
@@ -315,6 +315,9 @@ gboolean nm_ppdirect_equal (gconstpointer a, gconstpointer b);
/*****************************************************************************/
+guint nm_gbytes_hash (gconstpointer p);
+#define nm_gbytes_equal g_bytes_equal
+
guint nm_pgbytes_hash (gconstpointer p);
gboolean nm_pgbytes_equal (gconstpointer a, gconstpointer b);
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 61e3e26716..5dd099a7c9 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -397,6 +397,24 @@ truncate:
/*****************************************************************************/
+GBytes *
+nm_gbytes_get_empty (void)
+{
+ static GBytes *bytes = NULL;
+ GBytes *b;
+
+again:
+ b = g_atomic_pointer_get (&bytes);
+ if (G_UNLIKELY (!b)) {
+ b = g_bytes_new_static ("", 0);
+ if (!g_atomic_pointer_compare_and_exchange (&bytes, NULL, b)) {
+ g_bytes_unref (b);
+ goto again;
+ }
+ }
+ return b;
+}
+
/**
* nm_utils_gbytes_equals:
* @bytes: (allow-none): a #GBytes array to compare. Note that
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index 9200f80fdf..d5990c2d54 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -389,6 +389,8 @@ nm_utils_is_separator (const char c)
/*****************************************************************************/
+GBytes *nm_gbytes_get_empty (void);
+
static inline gboolean
nm_gbytes_equal0 (GBytes *a, GBytes *b)
{
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index 8d539026e7..4e260da2f3 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -46,6 +46,8 @@ void nm_device_arp_announce (NMDevice *self);
NMSettings *nm_device_get_settings (NMDevice *self);
+NMManager *nm_device_get_manager (NMDevice *self);
+
gboolean nm_device_set_ip_ifindex (NMDevice *self, int ifindex);
gboolean nm_device_set_ip_iface (NMDevice *self, const char *iface);
@@ -203,4 +205,15 @@ gboolean nm_device_match_parent_hwaddr (NMDevice *device,
NMConnection *connection,
gboolean fail_if_no_hwaddr);
+/*****************************************************************************/
+
+void nm_device_auth_request (NMDevice *self,
+ GDBusMethodInvocation *context,
+ NMConnection *connection,
+ const char *permission,
+ gboolean allow_interaction,
+ GCancellable *cancellable,
+ NMManagerDeviceAuthRequestFunc callback,
+ gpointer user_data);
+
#endif /* NM_DEVICE_PRIVATE_H */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d400d90617..27b1b600b1 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -192,7 +192,6 @@ typedef struct {
enum {
STATE_CHANGED,
AUTOCONNECT_ALLOWED,
- AUTH_REQUEST,
IP4_CONFIG_CHANGED,
IP6_CONFIG_CHANGED,
IP6_PREFIX_DELEGATED,
@@ -578,6 +577,7 @@ typedef struct _NMDevicePrivate {
NMMetered metered;
NMSettings *settings;
+ NMManager *manager;
NMNetns *netns;
@@ -913,6 +913,12 @@ nm_device_get_settings (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->settings;
}
+NMManager *
+nm_device_get_manager (NMDevice *self)
+{
+ return NM_DEVICE_GET_PRIVATE (self)->manager;
+}
+
NMNetns *
nm_device_get_netns (NMDevice *self)
{
@@ -6258,6 +6264,27 @@ dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer us
}
}
+void
+nm_device_auth_request (NMDevice *self,
+ GDBusMethodInvocation *context,
+ NMConnection *connection,
+ const char *permission,
+ gboolean allow_interaction,
+ GCancellable *cancellable,
+ NMManagerDeviceAuthRequestFunc callback,
+ gpointer user_data)
+{
+ nm_manager_device_auth_request (nm_device_get_manager (self),
+ self,
+ context,
+ connection,
+ permission,
+ allow_interaction,
+ cancellable,
+ callback,
+ user_data);
+}
+
/*****************************************************************************/
static void
@@ -12296,13 +12323,14 @@ impl_device_reapply (NMDBusObject *obj,
} else
reapply_data = NULL;
- g_signal_emit (self, signals[AUTH_REQUEST], 0,
- invocation,
- nm_device_get_applied_connection (self),
- NM_AUTH_PERMISSION_NETWORK_CONTROL,
- TRUE,
- reapply_cb,
- reapply_data);
+ nm_device_auth_request (self,
+ invocation,
+ nm_device_get_applied_connection (self),
+ NM_AUTH_PERMISSION_NETWORK_CONTROL,
+ TRUE,
+ NULL,
+ reapply_cb,
+ reapply_data);
}
/*****************************************************************************/
@@ -12339,13 +12367,14 @@ get_applied_connection_cb (NMDevice *self,
if (applied_connection != user_data) {
/* The applied connection changed due to a race. Reauthenticate. */
- g_signal_emit (self, signals[AUTH_REQUEST], 0,
- context,
- applied_connection,
- NM_AUTH_PERMISSION_NETWORK_CONTROL,
- TRUE,
- get_applied_connection_cb,
- applied_connection /* no need take a ref. We will not dereference this pointer. */);
+ nm_device_auth_request (self,
+ context,
+ applied_connection,
+ NM_AUTH_PERMISSION_NETWORK_CONTROL,
+ TRUE,
+ NULL,
+ get_applied_connection_cb,
+ applied_connection /* no need take a ref. We will not dereference this pointer. */);
return;
}
@@ -12392,13 +12421,14 @@ impl_device_get_applied_connection (NMDBusObject *obj,
return;
}
- g_signal_emit (self, signals[AUTH_REQUEST], 0,
- invocation,
- applied_connection,
- NM_AUTH_PERMISSION_NETWORK_CONTROL,
- TRUE,
- get_applied_connection_cb,
- applied_connection /* no need take a ref. We will not dereference this pointer. */);
+ nm_device_auth_request (self,
+ invocation,
+ applied_connection,
+ NM_AUTH_PERMISSION_NETWORK_CONTROL,
+ TRUE,
+ NULL,
+ get_applied_connection_cb,
+ applied_connection /* no need take a ref. We will not dereference this pointer. */);
}
/*****************************************************************************/
@@ -12566,13 +12596,14 @@ impl_device_disconnect (NMDBusObject *obj,
connection = nm_device_get_applied_connection (self);
nm_assert (connection);
- g_signal_emit (self, signals[AUTH_REQUEST], 0,
- invocation,
- connection,
- NM_AUTH_PERMISSION_NETWORK_CONTROL,
- TRUE,
- disconnect_cb,
- NULL);
+ nm_device_auth_request (self,
+ invocation,
+ connection,
+ NM_AUTH_PERMISSION_NETWORK_CONTROL,
+ TRUE,
+ NULL,
+ disconnect_cb,
+ NULL);
}
static void
@@ -12618,13 +12649,14 @@ impl_device_delete (NMDBusObject *obj,
return;
}
- g_signal_emit (self, signals[AUTH_REQUEST], 0,
- invocation,
- NULL,
- NM_AUTH_PERMISSION_NETWORK_CONTROL,
- TRUE,
- delete_cb,
- NULL);
+ nm_device_auth_request (self,
+ invocation,
+ NULL,
+ NM_AUTH_PERMISSION_NETWORK_CONTROL,
+ TRUE,
+ NULL,
+ delete_cb,
+ NULL);
}
static void
@@ -17452,8 +17484,8 @@ constructed (GObject *object)
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self);
+ priv->manager = g_object_ref (NM_MANAGER_GET);
priv->settings = g_object_ref (NM_SETTINGS_GET);
- g_assert (priv->settings);
g_signal_connect (priv->settings,
NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
@@ -17610,6 +17642,7 @@ finalize (GObject *object)
/* for testing, NMDeviceTest does not invoke NMDevice::constructed,
* and thus @settings might be unset. */
nm_g_object_unref (priv->settings);
+ nm_g_object_unref (priv->manager);
nm_g_object_unref (priv->concheck_mgr);
@@ -18006,14 +18039,6 @@ nm_device_class_init (NMDeviceClass *klass)
autoconnect_allowed_accumulator, NULL, NULL,
G_TYPE_BOOLEAN, 0);
- signals[AUTH_REQUEST] =
- g_signal_new (NM_DEVICE_AUTH_REQUEST,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL,
- /* context, connection, permission, allow_interaction, callback, user_data */
- G_TYPE_NONE, 6, G_TYPE_DBUS_METHOD_INVOCATION, NM_TYPE_CONNECTION, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
-
signals[IP4_CONFIG_CHANGED] =
g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index c18301b275..8d51c707dd 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -115,7 +115,6 @@ nm_device_state_reason_check (NMDeviceStateReason reason)
#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */
/* Internal signals */
-#define NM_DEVICE_AUTH_REQUEST "auth-request"
#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed"
#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed"
#define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated"
@@ -455,12 +454,6 @@ typedef struct _NMDeviceClass {
} NMDeviceClass;
-typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
- GDBusMethodInvocation *context,
- NMAuthSubject *subject,
- GError *error,
- gpointer user_data);
-
GType nm_device_get_type (void);
struct _NMDedupMultiIndex *nm_device_get_multi_index (NMDevice *self);
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 3dccd1cb94..e2e705fd2e 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -1061,14 +1061,14 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self,
return;
}
- g_signal_emit_by_name (device,
- NM_DEVICE_AUTH_REQUEST,
- invocation,
- NULL,
- NM_AUTH_PERMISSION_WIFI_SCAN,
- TRUE,
- dbus_request_scan_cb,
- options ? g_variant_ref (options) : NULL);
+ nm_device_auth_request (device,
+ invocation,
+ NULL,
+ NM_AUTH_PERMISSION_WIFI_SCAN,
+ TRUE,
+ NULL,
+ dbus_request_scan_cb,
+ nm_g_variant_ref (options));
}
static gboolean
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index bf3e6ad27a..f14e2b25e7 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -48,7 +48,7 @@ _LOG_DECLARE_SELF(NMDeviceWifi);
#define SCAN_INTERVAL_SEC_STEP 20
#define SCAN_INTERVAL_SEC_MAX 120
-#define SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN 5
+#define SCAN_RAND_MAC_ADDRESS_EXPIRE_SEC (5*60)
/*****************************************************************************/
@@ -1169,7 +1169,7 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset)
* We don't bother with to update the MAC address exactly when
* it expires, instead on the next scan request, we will generate
* a new one.*/
- priv->hw_addr_scan_expire = now + (SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN * 60);
+ priv->hw_addr_scan_expire = now + SCAN_RAND_MAC_ADDRESS_EXPIRE_SEC;
generate_mac_address_mask = nm_config_data_get_device_config (NM_CONFIG_GET_DATA,
"wifi.scan-generate-mac-address-mask",
@@ -1323,14 +1323,14 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self,
return;
}
- g_signal_emit_by_name (device,
- NM_DEVICE_AUTH_REQUEST,
- invocation,
- NULL,
- NM_AUTH_PERMISSION_WIFI_SCAN,
- TRUE,
- dbus_request_scan_cb,
- g_steal_pointer (&ssids));
+ nm_device_auth_request (device,
+ invocation,
+ NULL,
+ NM_AUTH_PERMISSION_WIFI_SCAN,
+ TRUE,
+ NULL,
+ dbus_request_scan_cb,
+ g_steal_pointer (&ssids));
}
static gboolean
diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c
index ca2870db72..b9efff4805 100644
--- a/src/nm-auth-utils.c
+++ b/src/nm-auth-utils.c
@@ -16,22 +16,38 @@
/*****************************************************************************/
+typedef struct {
+ const char *tag;
+ gpointer data;
+ GDestroyNotify destroy;
+} ChainData;
+
struct _NMAuthChain {
CList parent_lst;
- CList data_lst_head;
+ ChainData *data_arr;
+ guint data_len;
+ guint data_alloc;
CList auth_call_lst_head;
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 +94,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 +179,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 *
@@ -104,29 +196,16 @@ _find_auth_call (NMAuthChain *self, const char *permission)
/*****************************************************************************/
-typedef struct {
- CList data_lst;
- const char *tag;
- gpointer data;
- GDestroyNotify destroy;
-} ChainData;
-
-static void
-chain_data_free (ChainData *chain_data)
-{
- c_list_unlink_stale (&chain_data->data_lst);
- if (chain_data->destroy)
- chain_data->destroy (chain_data->data);
- g_slice_free (ChainData, chain_data);
-}
-
static ChainData *
_get_data (NMAuthChain *self, const char *tag)
{
- ChainData *chain_data;
+ guint i;
- c_list_for_each_entry (chain_data, &self->data_lst_head, data_lst) {
- if (nm_streq (chain_data->tag, tag))
+ for (i = 0; i < self->data_len; i++) {
+ ChainData *chain_data = &self->data_arr[i];
+
+ if ( chain_data->tag
+ && nm_streq (chain_data->tag, tag))
return chain_data;
}
return NULL;
@@ -159,7 +238,6 @@ gpointer
nm_auth_chain_steal_data (NMAuthChain *self, const char *tag)
{
ChainData *chain_data;
- gpointer value;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (tag, NULL);
@@ -168,12 +246,13 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag)
if (!chain_data)
return NULL;
- value = chain_data->data;
-
- /* Make sure the destroy handler isn't called when freeing */
+ /* Make sure the destroy handler isn't called when freeing.
+ *
+ * We don't bother to really remove the element from the array.
+ * Just mark the entry as unused by clearing the tag. */
chain_data->destroy = NULL;
- chain_data_free (chain_data);
- return value;
+ chain_data->tag = NULL;
+ return chain_data->data;
}
/**
@@ -184,7 +263,7 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag)
* and nothing is attached.
* @data_destroy: (allow-none): the destroy function for the data pointer.
*
- * @tag string is not cloned and must outlife @self. That is why
+ * @tag string is not cloned and must outlive @self. That is why
* the function is "unsafe". Use nm_auth_chain_set_data() with a C literal
* instead.
*
@@ -201,12 +280,8 @@ nm_auth_chain_set_data_unsafe (NMAuthChain *self,
g_return_if_fail (self);
g_return_if_fail (tag);
- /* we should not track a large number of elements via a linked list. If this becomes
- * necessary, revert the code to use GHashTable again. */
- nm_assert (c_list_length (&self->data_lst_head) < 25);
-
- /* The tag must not yet exist. Otherwise we'd have to first search the linked
- * list for an existing entry. */
+ /* The tag must not yet exist. Otherwise we'd have to first search the
+ * list for an existing entry. That usage pattern is not supported. */
nm_assert (!_get_data (self, tag));
if (!data) {
@@ -218,17 +293,20 @@ nm_auth_chain_set_data_unsafe (NMAuthChain *self,
return;
}
- chain_data = g_slice_new (ChainData);
+ if (self->data_len + 1 > self->data_alloc) {
+ if (self->data_alloc == 0)
+ self->data_alloc = 8;
+ else
+ self->data_alloc *= 2;
+ self->data_arr = g_realloc (self->data_arr, sizeof (self->data_arr[0]) * self->data_alloc);
+ }
+
+ chain_data = &self->data_arr[self->data_len++];
*chain_data = (ChainData) {
.tag = tag,
.data = data,
.destroy = data_destroy,
};
-
- /* we assert that no duplicate tags are added. But still, add the new
- * element to the front, so that it would shadow the duplicate element
- * in the list. */
- c_list_link_front (&self->data_lst_head, &chain_data->data_lst);
}
/*****************************************************************************/
@@ -255,6 +333,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 +398,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 +431,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,21 +469,27 @@ 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);
/* we track auth-calls in a linked list. If we end up requesting too many permissions this
* becomes inefficient. If that ever happens, consider a more efficient data structure for
* a large number of requests. */
- nm_assert (self->num_pending_auth_calls < 25);
+ nm_assert (c_list_length (&self->auth_call_lst_head) < 25);
+ G_STATIC_ASSERT_EXPR (NM_CLIENT_PERMISSION_LAST < 25);
}
/*****************************************************************************/
@@ -427,10 +527,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);
@@ -440,7 +538,6 @@ nm_auth_chain_new_subject (NMAuthSubject *subject,
.context = nm_g_object_ref (context),
.subject = g_object_ref (subject),
.parent_lst = C_LIST_INIT (self->parent_lst),
- .data_lst_head = C_LIST_INIT (self->data_lst_head),
.auth_call_lst_head = C_LIST_INIT (self->auth_call_lst_head),
};
return self;
@@ -482,24 +579,33 @@ static void
_auth_chain_destroy (NMAuthChain *self)
{
AuthCall *call;
- ChainData *chain_data;
c_list_unlink (&self->parent_lst);
nm_clear_g_object (&self->subject);
nm_clear_g_object (&self->context);
- /* we must first destry all AuthCall instances before ChainData. The reason is
+ nm_clear_g_signal_handler (self->cancellable, &self->cancellable_id);
+ nm_clear_g_source_inst (&self->cancellable_idle_source);
+
+ /* we must first destroy 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
* permission string via nm_auth_chain_set_data(). Hence, first free the AuthCall. */
while ((call = c_list_first_entry (&self->auth_call_lst_head, AuthCall, auth_call_lst)))
auth_call_free (call);
- while ((chain_data = c_list_first_entry (&self->data_lst_head, ChainData, data_lst)))
- chain_data_free (chain_data);
+ while (self->data_len > 0) {
+ ChainData *chain_data = &self->data_arr[--self->data_len];
+
+ if (chain_data->destroy)
+ chain_data->destroy (chain_data->data);
+ }
+ g_free (self->data_arr);
+
+ nm_g_object_unref (self->cancellable);
- g_slice_free (NMAuthChain, self);
+ nm_g_slice_free (self);
}
/******************************************************************************
@@ -517,10 +623,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);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 1f3ba1f661..bbe501259f 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2375,8 +2375,9 @@ device_auth_done_cb (NMAuthChain *chain,
gs_free_error GError *error = NULL;
NMAuthCallResult result;
NMDevice *device;
+ GCancellable *cancellable;
const char *permission;
- NMDeviceAuthRequestFunc callback;
+ NMManagerDeviceAuthRequestFunc callback;
NMAuthSubject *subject;
nm_assert (G_IS_DBUS_METHOD_INVOCATION (context));
@@ -2390,18 +2391,26 @@ device_auth_done_cb (NMAuthChain *chain,
device = nm_auth_chain_get_data (chain, "device");
nm_assert (NM_IS_DEVICE (device));
+ cancellable = nm_auth_chain_get_cancellable (chain);
+ nm_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
result = nm_auth_chain_get_result (chain, permission);
subject = nm_auth_chain_get_subject (chain);
- if (result != NM_AUTH_CALL_RESULT_YES) {
- _LOGD (LOGD_CORE, "%s request failed: not authorized", permission);
- error = g_error_new (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "%s request failed: not authorized",
- permission);
- }
+ if ( cancellable
+ && g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ /* pass. */
+ } else {
+ if (result != NM_AUTH_CALL_RESULT_YES) {
+ _LOGD (LOGD_CORE, "%s request failed: not authorized", permission);
+ error = g_error_new (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "%s request failed: not authorized",
+ permission);
+ }
- nm_assert (error || (result == NM_AUTH_CALL_RESULT_YES));
+ nm_assert (error || (result == NM_AUTH_CALL_RESULT_YES));
+ }
callback (device,
context,
@@ -2411,28 +2420,53 @@ device_auth_done_cb (NMAuthChain *chain,
}
static void
-device_auth_request_cb (NMDevice *device,
- GDBusMethodInvocation *context,
- NMConnection *connection,
- const char *permission,
- gboolean allow_interaction,
- NMDeviceAuthRequestFunc callback,
- gpointer user_data,
- NMManager *self)
+_device_auth_done_fail_on_idle (gpointer user_data, GCancellable *cancellable)
+{
+ gs_unref_object NMManager *self = NULL;
+ gs_unref_object NMDevice *device = NULL;
+ gs_unref_object GDBusMethodInvocation *context = NULL;
+ gs_unref_object NMAuthSubject *subject = NULL;
+ gs_free_error GError *error_original = NULL;
+ gs_free_error GError *error_cancelled = NULL;
+ NMManagerDeviceAuthRequestFunc callback;
+ gpointer callback_user_data;
+
+ nm_utils_user_data_unpack (&self, &device, &context, &subject, &error_original, &callback, &callback_user_data);
+
+ g_cancellable_set_error_if_cancelled (cancellable, &error_cancelled);
+
+ callback (device,
+ context,
+ subject,
+ error_cancelled ?: error_original,
+ callback_user_data);
+}
+
+void
+nm_manager_device_auth_request (NMManager *self,
+ NMDevice *device,
+ GDBusMethodInvocation *context,
+ NMConnection *connection,
+ const char *permission,
+ gboolean allow_interaction,
+ GCancellable *cancellable,
+ NMManagerDeviceAuthRequestFunc callback,
+ gpointer user_data)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GError *error = NULL;
- NMAuthSubject *subject = NULL;
+ gs_free_error GError *error = NULL;
+ gs_unref_object NMAuthSubject *subject = NULL;
NMAuthChain *chain;
char *permission_dup;
/* Validate the caller */
subject = nm_dbus_manager_new_auth_subject_from_context (context);
if (!subject) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN);
- goto done;
+ g_set_error_literal (&error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN);
+ goto fail_on_idle;
}
/* Ensure the subject has permissions for this connection */
@@ -2442,17 +2476,21 @@ device_auth_request_cb (NMDevice *device,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
&error))
- goto done;
+ goto fail_on_idle;
/* Validate the request */
chain = nm_auth_chain_new_subject (subject, context, device_auth_done_cb, self);
if (!chain) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- NM_UTILS_ERROR_MSG_REQ_AUTH_FAILED);
- goto done;
+ g_set_error (&error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ NM_UTILS_ERROR_MSG_REQ_AUTH_FAILED);
+ goto fail_on_idle;
}
+ if (cancellable)
+ nm_auth_chain_set_cancellable (chain, cancellable);
+
permission_dup = g_strdup (permission);
c_list_link_tail (&priv->auth_lst_head, nm_auth_chain_parent_lst_list (chain));
@@ -2461,13 +2499,18 @@ device_auth_request_cb (NMDevice *device,
nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
nm_auth_chain_set_data (chain, "perm", permission_dup /* transfer ownership */, g_free);
nm_auth_chain_add_call_unsafe (chain, permission_dup, allow_interaction);
+ return;
-done:
- if (error)
- callback (device, context, subject, error, user_data);
-
- g_clear_object (&subject);
- g_clear_error (&error);
+fail_on_idle:
+ nm_utils_invoke_on_idle (cancellable,
+ _device_auth_done_fail_on_idle,
+ nm_utils_user_data_pack (g_object_ref (self),
+ g_object_ref (device),
+ g_object_ref (context),
+ g_steal_pointer (&subject),
+ g_steal_pointer (&error),
+ callback,
+ user_data));
}
static gboolean
@@ -3130,10 +3173,6 @@ add_device (NMManager *self, NMDevice *device, GError **error)
G_CALLBACK (manager_device_state_changed),
self);
- g_signal_connect (device, NM_DEVICE_AUTH_REQUEST,
- G_CALLBACK (device_auth_request_cb),
- self);
-
g_signal_connect (device, NM_DEVICE_REMOVED,
G_CALLBACK (device_removed_cb),
self);
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 5873abd24b..ab08eaa839 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -193,4 +193,16 @@ NMMetered nm_manager_get_metered (NMManager *self);
void nm_manager_notify_device_availibility_maybe_changed (NMManager *self);
+/*****************************************************************************/
+
+void nm_manager_device_auth_request (NMManager *self,
+ NMDevice *device,
+ GDBusMethodInvocation *context,
+ NMConnection *connection,
+ const char *permission,
+ gboolean allow_interaction,
+ GCancellable *cancellable,
+ NMManagerDeviceAuthRequestFunc callback,
+ gpointer user_data);
+
#endif /* __NETWORKMANAGER_MANAGER_H__ */
diff --git a/src/nm-types.h b/src/nm-types.h
index d2f6fb4093..d2c999fada 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -40,6 +40,12 @@ typedef struct _NMSleepMonitor NMSleepMonitor;
typedef struct _NMLldpListener NMLldpListener;
typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData;
+typedef void (*NMManagerDeviceAuthRequestFunc) (NMDevice *device,
+ GDBusMethodInvocation *context,
+ NMAuthSubject *subject,
+ GError *error,
+ gpointer user_data);
+
struct _NMDedupMultiIndex;
typedef struct _NMRefString NMRefString;
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index 099c3bf2ca..700563624a 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -1204,13 +1204,18 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
if (g_variant_lookup (capabilities, "MaxScanSSID", "i", &max_scan_ssids)) {
/* We need active scan and SSID probe capabilities to care about MaxScanSSIDs */
- if (max_scan_ssids > 0 && have_active && have_ssid) {
+ if ( max_scan_ssids > 0
+ && have_active
+ && have_ssid) {
/* wpa_supplicant's NM_WPAS_MAX_SCAN_SSIDS value is 16, but for speed
* and to ensure we don't disclose too many SSIDs from the hidden
* list, we'll limit to 5.
*/
- priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
- _LOGD ("supports %d scan SSIDs", priv->max_scan_ssids);
+ max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
+ if (max_scan_ssids != priv->max_scan_ssids) {
+ priv->max_scan_ssids = max_scan_ssids;
+ _LOGD ("supports %d scan SSIDs", priv->max_scan_ssids);
+ }
}
}
}