wifi: merge branch 'th/wifi-scan' (part 1)

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/479
This commit is contained in:
Thomas Haller 2020-04-28 18:38:01 +02:00
commit daee41b82a
16 changed files with 426 additions and 183 deletions

View file

@ -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__ */

View file

@ -264,6 +264,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)
{

View file

@ -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);

View file

@ -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

View file

@ -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)
{

View file

@ -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 */

View file

@ -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),

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;
};
@ -77,6 +93,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)
{
@ -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);
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++;
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];
g_slice_free (NMAuthChain, self);
if (chain_data->destroy)
chain_data->destroy (chain_data->data);
}
g_free (self->data_arr);
nm_g_object_unref (self->cancellable);
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;

View file

@ -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);

View file

@ -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);

View file

@ -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__ */

View file

@ -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;

View file

@ -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);
}
}
}
}