2020-09-29 16:42:22 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
2014-08-29 12:27:47 -04:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2010 - 2014 Red Hat, Inc.
|
2014-08-29 12:27:47 -04:00
|
|
|
*/
|
|
|
|
|
|
2016-02-19 14:57:48 +01:00
|
|
|
#include "nm-default.h"
|
2014-11-13 10:07:02 -05:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
2016-02-19 14:57:48 +01:00
|
|
|
#include "nm-secret-agent-old.h"
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2015-12-20 21:59:13 +01:00
|
|
|
#include "nm-test-libnm-utils.h"
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
SECRET_REQUESTED,
|
2020-01-03 07:32:36 +01:00
|
|
|
LAST_SIGNAL,
|
2014-08-29 12:27:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = {0};
|
|
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
typedef NMSecretAgentOld TestSecretAgent;
|
2014-11-20 11:53:19 -05:00
|
|
|
typedef NMSecretAgentOldClass TestSecretAgentClass;
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
GType test_secret_agent_get_type(void);
|
|
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
G_DEFINE_TYPE(TestSecretAgent, test_secret_agent, NM_TYPE_SECRET_AGENT_OLD)
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
static void
|
2014-11-20 11:53:19 -05:00
|
|
|
test_secret_agent_get_secrets(NMSecretAgentOld * agent,
|
|
|
|
|
NMConnection * connection,
|
|
|
|
|
const char * connection_path,
|
|
|
|
|
const char * setting_name,
|
|
|
|
|
const char ** hints,
|
|
|
|
|
NMSecretAgentGetSecretsFlags flags,
|
|
|
|
|
NMSecretAgentOldGetSecretsFunc callback,
|
|
|
|
|
gpointer callback_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
NMSettingWirelessSecurity *s_wsec;
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariant * secrets = NULL;
|
|
|
|
|
GVariantBuilder secrets_builder, setting_builder;
|
2014-08-29 12:27:47 -04:00
|
|
|
char * secret = NULL;
|
|
|
|
|
GError * error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_assert_cmpstr(setting_name, ==, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
s_wsec = nm_connection_get_setting_wireless_security(connection);
|
|
|
|
|
g_assert(s_wsec);
|
|
|
|
|
g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "wpa-psk");
|
|
|
|
|
g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec), ==, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_signal_emit(agent,
|
|
|
|
|
signals[SECRET_REQUESTED],
|
|
|
|
|
0,
|
|
|
|
|
connection,
|
|
|
|
|
connection_path,
|
|
|
|
|
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
|
|
|
|
|
NM_SETTING_WIRELESS_SECURITY_PSK,
|
|
|
|
|
&secret);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
if (!secret) {
|
|
|
|
|
error = g_error_new(NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_NO_SECRETS, "No secrets");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
if (!strcmp(secret, "CANCEL")) {
|
|
|
|
|
error = g_error_new(NM_SECRET_AGENT_ERROR,
|
|
|
|
|
NM_SECRET_AGENT_ERROR_USER_CANCELED,
|
|
|
|
|
"User canceled");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
g_variant_builder_init(&setting_builder, NM_VARIANT_TYPE_SETTING);
|
|
|
|
|
g_variant_builder_add(&setting_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
NM_SETTING_WIRELESS_SECURITY_PSK,
|
|
|
|
|
g_variant_new_string(secret));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
g_variant_builder_init(&secrets_builder, NM_VARIANT_TYPE_CONNECTION);
|
|
|
|
|
g_variant_builder_add(&secrets_builder, "{sa{sv}}", setting_name, &setting_builder);
|
|
|
|
|
secrets = g_variant_ref_sink(g_variant_builder_end(&secrets_builder));
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
done:
|
2014-08-16 10:09:48 -04:00
|
|
|
callback(agent, connection, secrets, error, callback_data);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_clear_error(&error);
|
all: use nm_clear_pointer() instead of g_clear_pointer()
g_clear_pointer() would always cast the destroy notify function
pointer to GDestroyNotify. That means, it lost some type safety, like
GPtrArray *ptr_arr = ...
g_clear_pointer (&ptr_arr, g_array_unref);
Since glib 2.58 ([1]), g_clear_pointer() is also more type safe. But
this is not used by NetworkManager, because we don't set
GLIB_VERSION_MIN_REQUIRED to 2.58.
[1] https://gitlab.gnome.org/GNOME/glib/-/commit/f9a9902aac826ab4aecc25f6eb533a418a4fa559
We have nm_clear_pointer() to avoid this issue for a long time (pre
1.12.0). Possibly we should redefine in our source tree g_clear_pointer()
as nm_clear_pointer(). However, I don't like to patch glib functions
with our own variant. Arguably, we do patch g_clear_error() in
such a manner. But there the point is to make the function inlinable.
Also, nm_clear_pointer() returns a boolean that indicates whether
anything was cleared. That is sometimes useful. I think we should
just consistently use nm_clear_pointer() instead, which does always
the preferable thing.
Replace:
sed 's/\<g_clear_pointer *(\([^;]*\), *\([a-z_A-Z0-9]\+\) *)/nm_clear_pointer (\1, \2)/g' $(git grep -l g_clear_pointer) -i
2020-03-23 11:09:24 +01:00
|
|
|
nm_clear_pointer(&secrets, g_variant_unref);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_free(secret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-11-20 11:53:19 -05:00
|
|
|
test_secret_agent_cancel_get_secrets(NMSecretAgentOld *agent,
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
const char * connection_path,
|
|
|
|
|
const char * setting_name)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-11-20 11:53:19 -05:00
|
|
|
test_secret_agent_save_secrets(NMSecretAgentOld * agent,
|
|
|
|
|
NMConnection * connection,
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
const char * connection_path,
|
2014-11-20 11:53:19 -05:00
|
|
|
NMSecretAgentOldSaveSecretsFunc callback,
|
|
|
|
|
gpointer callback_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-11-20 11:53:19 -05:00
|
|
|
test_secret_agent_delete_secrets(NMSecretAgentOld * agent,
|
|
|
|
|
NMConnection * connection,
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
const char * connection_path,
|
2014-11-20 11:53:19 -05:00
|
|
|
NMSecretAgentOldDeleteSecretsFunc callback,
|
|
|
|
|
gpointer callback_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-01-03 07:32:36 +01:00
|
|
|
test_secret_agent_init(TestSecretAgent *agent)
|
2014-08-29 12:27:47 -04:00
|
|
|
{}
|
|
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
static NMSecretAgentOld *
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
test_secret_agent_new(gboolean auto_register)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
2020-01-03 10:04:38 +01:00
|
|
|
return nmtstc_context_object_new(test_secret_agent_get_type(),
|
|
|
|
|
TRUE,
|
|
|
|
|
NM_SECRET_AGENT_OLD_IDENTIFIER,
|
|
|
|
|
"test-secret-agent",
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
NM_SECRET_AGENT_OLD_AUTO_REGISTER,
|
|
|
|
|
auto_register,
|
2020-01-03 10:04:38 +01:00
|
|
|
NULL);
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
static void
|
|
|
|
|
test_secret_agent_class_init(TestSecretAgentClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass * object_class = G_OBJECT_CLASS(klass);
|
|
|
|
|
NMSecretAgentOldClass *agent_class = NM_SECRET_AGENT_OLD_CLASS(klass);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
agent_class->get_secrets = test_secret_agent_get_secrets;
|
|
|
|
|
agent_class->cancel_get_secrets = test_secret_agent_cancel_get_secrets;
|
|
|
|
|
agent_class->save_secrets = test_secret_agent_save_secrets;
|
|
|
|
|
agent_class->delete_secrets = test_secret_agent_delete_secrets;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
signals[SECRET_REQUESTED] = g_signal_new("secret-requested",
|
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
G_TYPE_STRING,
|
|
|
|
|
4,
|
|
|
|
|
NM_TYPE_CONNECTION,
|
|
|
|
|
G_TYPE_STRING,
|
|
|
|
|
G_TYPE_STRING,
|
|
|
|
|
G_TYPE_STRING);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
typedef struct {
|
2015-12-21 10:22:33 +01:00
|
|
|
NMTstcServiceInfo *sinfo;
|
2014-08-29 12:27:47 -04:00
|
|
|
NMClient * client;
|
|
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
NMSecretAgentOld *agent;
|
2014-08-29 12:27:47 -04:00
|
|
|
NMDevice * device;
|
|
|
|
|
NMConnection * connection;
|
|
|
|
|
|
|
|
|
|
GMainLoop *loop;
|
2020-01-03 07:32:36 +01:00
|
|
|
GSource * timeout_source;
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
char *ifname;
|
|
|
|
|
char *con_id;
|
|
|
|
|
|
|
|
|
|
int secrets_requested;
|
|
|
|
|
} TestSecretAgentData;
|
|
|
|
|
|
|
|
|
|
static void
|
2014-09-11 16:27:13 -04:00
|
|
|
connection_added_cb(GObject *s, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2014-09-11 16:27:13 -04:00
|
|
|
NMRemoteConnection * connection;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
|
2014-09-29 10:58:16 -04:00
|
|
|
connection = nm_client_add_connection_finish(sadata->client, result, &error);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
g_assert_no_error(error);
|
|
|
|
|
g_assert_cmpstr(nm_connection_get_id(NM_CONNECTION(connection)), ==, sadata->con_id);
|
|
|
|
|
|
|
|
|
|
sadata->connection = NM_CONNECTION(connection);
|
|
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-09-02 21:41:05 -04:00
|
|
|
register_cb(GObject *object, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2014-09-02 21:41:05 -04:00
|
|
|
GError * error = NULL;
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
nm_secret_agent_old_register_finish(sadata->agent, result, &error);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_assert_no_error(error);
|
2014-11-20 11:53:19 -05:00
|
|
|
g_assert(nm_secret_agent_old_get_registered(sadata->agent));
|
2014-09-02 21:41:05 -04:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define TEST_CON_ID_PREFIX "test-secret-agent"
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_setup(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
2020-01-03 07:32:36 +01:00
|
|
|
static int static_counter = 0;
|
|
|
|
|
const int counter = static_counter++;
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
const char * create_agent = test_data;
|
2014-08-29 12:27:47 -04:00
|
|
|
NMConnection * connection;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
NMSettingWireless * s_wireless;
|
|
|
|
|
GBytes * ssid;
|
|
|
|
|
NMSetting * s_wsec;
|
2020-01-03 07:32:36 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
sadata->sinfo = nmtstc_service_init();
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!sadata->sinfo)
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 13:17:56 +01:00
|
|
|
g_assert(nm_g_main_context_is_thread_default(NULL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-11-02 14:20:43 +01:00
|
|
|
sadata->client = nmtstc_client_new(TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 13:17:56 +01:00
|
|
|
g_assert(nm_g_main_context_is_thread_default(NULL));
|
|
|
|
|
g_assert(nm_g_main_context_is_thread_default(nm_client_get_main_context(sadata->client)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
sadata->loop = g_main_loop_new(NULL, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
sadata->timeout_source = g_timeout_source_new_seconds(5);
|
|
|
|
|
g_source_set_callback(sadata->timeout_source, nmtst_g_source_assert_not_called, NULL, NULL);
|
|
|
|
|
g_source_attach(sadata->timeout_source, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
sadata->ifname = g_strdup_printf("wlan%d", counter);
|
|
|
|
|
sadata->con_id = g_strdup_printf("%s-%d", TEST_CON_ID_PREFIX, counter);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
sadata->device =
|
|
|
|
|
nmtstc_service_add_device(sadata->sinfo, sadata->client, "AddWifiDevice", sadata->ifname);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
/* Create the connection */
|
|
|
|
|
connection = nmtst_create_minimal_connection(sadata->con_id,
|
|
|
|
|
NULL,
|
|
|
|
|
NM_SETTING_WIRELESS_SETTING_NAME,
|
|
|
|
|
&s_con);
|
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, sadata->ifname, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
s_wireless = nm_connection_get_setting_wireless(connection);
|
|
|
|
|
ssid = g_bytes_new("foo", 3);
|
|
|
|
|
g_object_set(s_wireless, NM_SETTING_WIRELESS_SSID, ssid, NULL);
|
|
|
|
|
g_bytes_unref(ssid);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
s_wsec = g_object_new(NM_TYPE_SETTING_WIRELESS_SECURITY,
|
|
|
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
|
|
|
|
|
"wpa-psk",
|
|
|
|
|
NULL);
|
|
|
|
|
nm_connection_add_setting(connection, s_wsec);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-29 10:58:16 -04:00
|
|
|
nm_client_add_connection_async(sadata->client,
|
|
|
|
|
connection,
|
|
|
|
|
TRUE,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_added_cb,
|
|
|
|
|
sadata);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_object_unref(connection);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
|
|
|
|
g_assert(sadata->connection);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
if (nm_streq(create_agent, "1")) {
|
|
|
|
|
gboolean auto_register = nmtst_get_rand_bool();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
sadata->agent = test_secret_agent_new(auto_register);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
if (auto_register) {
|
|
|
|
|
g_assert(nm_secret_agent_old_get_registered(sadata->agent));
|
2014-11-20 11:53:19 -05:00
|
|
|
nm_secret_agent_old_register(sadata->agent, NULL, &error);
|
2014-09-02 21:41:05 -04:00
|
|
|
g_assert_no_error(error);
|
|
|
|
|
} else {
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_assert(!nm_secret_agent_old_get_registered(sadata->agent));
|
|
|
|
|
nm_secret_agent_old_register_async(sadata->agent, NULL, register_cb, sadata);
|
2014-09-02 21:41:05 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_assert(nm_secret_agent_old_get_registered(sadata->agent));
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_cleanup(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
|
|
|
|
GVariant * ret;
|
|
|
|
|
GError * error = NULL;
|
2020-01-03 13:17:56 +01:00
|
|
|
NMTstContextBusyWatcherData watcher_data = {};
|
|
|
|
|
|
|
|
|
|
g_assert(nm_g_main_context_is_thread_default(NULL));
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!sadata->sinfo)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-01-03 13:17:56 +01:00
|
|
|
g_assert(nm_g_main_context_is_thread_default(nm_client_get_main_context(sadata->client)));
|
|
|
|
|
|
|
|
|
|
nmtst_context_busy_watcher_add(&watcher_data,
|
|
|
|
|
nm_client_get_context_busy_watcher(sadata->client));
|
|
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
if (sadata->agent) {
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
nmtst_context_busy_watcher_add(&watcher_data,
|
|
|
|
|
nm_secret_agent_old_get_context_busy_watcher(sadata->agent));
|
|
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
if (nm_secret_agent_old_get_registered(sadata->agent)) {
|
|
|
|
|
nm_secret_agent_old_unregister(sadata->agent, NULL, &error);
|
2014-09-02 21:41:05 -04:00
|
|
|
g_assert_no_error(error);
|
|
|
|
|
}
|
2014-08-29 12:27:47 -04:00
|
|
|
g_object_unref(sadata->agent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret =
|
|
|
|
|
g_dbus_proxy_call_sync(sadata->sinfo->proxy,
|
|
|
|
|
"RemoveDevice",
|
2014-10-08 18:14:30 -04:00
|
|
|
g_variant_new("(s)", nm_object_get_path(NM_OBJECT(sadata->device))),
|
2014-08-29 12:27:47 -04:00
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
3000,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
g_assert_no_error(error);
|
|
|
|
|
g_variant_unref(ret);
|
|
|
|
|
|
2014-10-08 18:14:30 -04:00
|
|
|
g_object_unref(sadata->connection);
|
|
|
|
|
g_object_unref(sadata->client);
|
|
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_cleanup(sadata->sinfo);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
nm_clear_g_source_inst(&sadata->timeout_source);
|
|
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_unref(sadata->loop);
|
|
|
|
|
|
|
|
|
|
g_free(sadata->ifname);
|
|
|
|
|
g_free(sadata->con_id);
|
2020-01-03 07:32:36 +01:00
|
|
|
|
|
|
|
|
*sadata = (TestSecretAgentData){};
|
2020-01-03 13:17:56 +01:00
|
|
|
|
|
|
|
|
nmtst_context_busy_watcher_wait(&watcher_data);
|
|
|
|
|
|
|
|
|
|
while (g_main_context_iteration(NULL, FALSE)) {}
|
|
|
|
|
|
|
|
|
|
nmtst_main_context_assert_no_dispatch(NULL, nmtst_get_rand_uint32() % 500);
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
static void
|
2014-09-11 16:27:13 -04:00
|
|
|
connection_activated_none_cb(GObject *c, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2015-02-08 13:34:32 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
2014-09-11 16:27:13 -04:00
|
|
|
|
2017-12-18 08:36:51 +01:00
|
|
|
nm_client_activate_connection_finish(sadata->client, result, &error);
|
2014-10-15 15:27:25 -04:00
|
|
|
g_assert_error(error, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_secret_agent_none(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!nmtstc_service_available(sadata->sinfo))
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-11 16:27:13 -04:00
|
|
|
nm_client_activate_connection_async(sadata->client,
|
|
|
|
|
sadata->connection,
|
|
|
|
|
sadata->device,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_activated_none_cb,
|
|
|
|
|
sadata);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
secrets_requested_no_secrets_cb(TestSecretAgent *agent,
|
|
|
|
|
NMConnection * connection,
|
|
|
|
|
const char * connection_path,
|
|
|
|
|
const char * setting_name,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
|
|
|
|
|
|
|
|
|
g_assert_cmpstr(connection_path, ==, nm_connection_get_path(sadata->connection));
|
|
|
|
|
sadata->secrets_requested++;
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-09-11 16:27:13 -04:00
|
|
|
connection_activated_no_secrets_cb(GObject *c, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2015-02-08 13:34:32 +01:00
|
|
|
gs_unref_object NMActiveConnection *ac = NULL;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
2014-09-11 16:27:13 -04:00
|
|
|
|
|
|
|
|
ac = nm_client_activate_connection_finish(sadata->client, result, &error);
|
2014-10-15 15:27:25 -04:00
|
|
|
g_assert_error(error, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_secret_agent_no_secrets(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!nmtstc_service_available(sadata->sinfo))
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_signal_connect(sadata->agent,
|
|
|
|
|
"secret-requested",
|
|
|
|
|
G_CALLBACK(secrets_requested_no_secrets_cb),
|
|
|
|
|
sadata);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-11 16:27:13 -04:00
|
|
|
nm_client_activate_connection_async(sadata->client,
|
|
|
|
|
sadata->connection,
|
|
|
|
|
sadata->device,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_activated_no_secrets_cb,
|
|
|
|
|
sadata);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_assert_cmpint(sadata->secrets_requested, ==, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
static void
|
2014-09-11 16:27:13 -04:00
|
|
|
connection_activated_cancel_cb(GObject *c, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2015-02-09 15:17:53 +01:00
|
|
|
gs_unref_object NMActiveConnection *ac = NULL;
|
2015-02-08 13:34:32 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
2014-09-11 16:27:13 -04:00
|
|
|
|
|
|
|
|
ac = nm_client_activate_connection_finish(sadata->client, result, &error);
|
2014-10-15 15:27:25 -04:00
|
|
|
g_assert_error(error, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_USER_CANCELED);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
secrets_requested_cancel_cb(TestSecretAgent *agent,
|
|
|
|
|
NMConnection * connection,
|
|
|
|
|
const char * connection_path,
|
|
|
|
|
const char * setting_name,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
|
|
|
|
|
|
|
|
|
g_assert_cmpstr(connection_path, ==, nm_connection_get_path(sadata->connection));
|
|
|
|
|
sadata->secrets_requested++;
|
|
|
|
|
|
|
|
|
|
return g_strdup("CANCEL");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_secret_agent_cancel(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!nmtstc_service_available(sadata->sinfo))
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_signal_connect(sadata->agent,
|
|
|
|
|
"secret-requested",
|
|
|
|
|
G_CALLBACK(secrets_requested_cancel_cb),
|
|
|
|
|
sadata);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-11 16:27:13 -04:00
|
|
|
nm_client_activate_connection_async(sadata->client,
|
|
|
|
|
sadata->connection,
|
|
|
|
|
sadata->device,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_activated_cancel_cb,
|
|
|
|
|
sadata);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_assert_cmpint(sadata->secrets_requested, ==, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
static void
|
2014-09-11 16:27:13 -04:00
|
|
|
connection_activated_good_cb(GObject *c, GAsyncResult *result, gpointer user_data)
|
2014-08-29 12:27:47 -04:00
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
2014-09-11 16:27:13 -04:00
|
|
|
NMActiveConnection * ac;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
|
|
|
|
|
ac = nm_client_activate_connection_finish(sadata->client, result, &error);
|
2014-10-06 13:35:03 -04:00
|
|
|
g_assert_no_error(error);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2014-10-06 13:35:03 -04:00
|
|
|
g_object_unref(ac);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
|
|
|
|
g_main_loop_quit(sadata->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
secrets_requested_good_cb(TestSecretAgent *agent,
|
|
|
|
|
NMConnection * connection,
|
|
|
|
|
const char * connection_path,
|
|
|
|
|
const char * setting_name,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
TestSecretAgentData *sadata = user_data;
|
|
|
|
|
|
|
|
|
|
g_assert_cmpstr(connection_path, ==, nm_connection_get_path(sadata->connection));
|
|
|
|
|
sadata->secrets_requested++;
|
|
|
|
|
|
|
|
|
|
return g_strdup("password");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_secret_agent_good(TestSecretAgentData *sadata, gconstpointer test_data)
|
|
|
|
|
{
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!nmtstc_service_available(sadata->sinfo))
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_signal_connect(sadata->agent,
|
|
|
|
|
"secret-requested",
|
|
|
|
|
G_CALLBACK(secrets_requested_good_cb),
|
|
|
|
|
sadata);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-11 16:27:13 -04:00
|
|
|
nm_client_activate_connection_async(sadata->client,
|
|
|
|
|
sadata->connection,
|
|
|
|
|
sadata->device,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_activated_good_cb,
|
|
|
|
|
sadata);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_main_loop_run(sadata->loop);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
g_assert_cmpint(sadata->secrets_requested, ==, 1);
|
|
|
|
|
}
|
|
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-09-02 21:41:05 -04:00
|
|
|
static void
|
|
|
|
|
async_init_cb(GObject *object, GAsyncResult *result, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GMainLoop * loop = user_data;
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
gs_unref_object GObject *agent = NULL;
|
2014-09-02 21:41:05 -04:00
|
|
|
|
|
|
|
|
agent = g_async_initable_new_finish(G_ASYNC_INITABLE(object), result, &error);
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
nmtst_assert_success(NM_IS_SECRET_AGENT_OLD(agent), error);
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(NM_SECRET_AGENT_OLD(agent)));
|
2014-09-02 21:41:05 -04:00
|
|
|
|
|
|
|
|
g_main_loop_quit(loop);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
static void
|
|
|
|
|
test_secret_agent_nm_not_running(void)
|
|
|
|
|
{
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
gs_unref_object NMSecretAgentOld *agent = NULL;
|
|
|
|
|
nm_auto_unref_gmainloop GMainLoop *loop = NULL;
|
2014-09-02 21:41:05 -04:00
|
|
|
GError * error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
agent = g_initable_new(test_secret_agent_get_type(),
|
|
|
|
|
NULL,
|
|
|
|
|
&error,
|
2014-11-20 11:53:19 -05:00
|
|
|
NM_SECRET_AGENT_OLD_IDENTIFIER,
|
|
|
|
|
"test-secret-agent",
|
2014-09-02 21:41:05 -04:00
|
|
|
NULL);
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
nmtst_assert_success(NM_IS_SECRET_AGENT_OLD(agent), error);
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
g_clear_object(&agent);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-02 21:41:05 -04:00
|
|
|
loop = g_main_loop_new(NULL, FALSE);
|
|
|
|
|
g_async_initable_new_async(test_secret_agent_get_type(),
|
|
|
|
|
G_PRIORITY_DEFAULT,
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
NULL,
|
|
|
|
|
async_init_cb,
|
|
|
|
|
loop,
|
2014-11-20 11:53:19 -05:00
|
|
|
NM_SECRET_AGENT_OLD_IDENTIFIER,
|
|
|
|
|
"test-secret-agent",
|
2014-09-02 21:41:05 -04:00
|
|
|
NULL);
|
|
|
|
|
g_main_loop_run(loop);
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
int step;
|
|
|
|
|
int invoke_count;
|
|
|
|
|
} AutoRegisterData;
|
|
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
static void
|
|
|
|
|
registered_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
|
|
|
{
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
NMSecretAgentOld *agent = NM_SECRET_AGENT_OLD(object);
|
|
|
|
|
AutoRegisterData *data = user_data;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_assert(data);
|
|
|
|
|
g_assert(NM_IS_SECRET_AGENT_OLD(agent));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
data->invoke_count++;
|
|
|
|
|
g_assert_cmpint(data->invoke_count, ==, data->step);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
switch (data->step) {
|
|
|
|
|
case 1:
|
|
|
|
|
case 3:
|
|
|
|
|
g_assert(nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 4:
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_secret_agent_auto_register(void)
|
|
|
|
|
{
|
2015-12-21 10:22:33 +01:00
|
|
|
NMTstcServiceInfo *sinfo;
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
gs_unref_object NMSecretAgentOld *agent = NULL;
|
2014-09-02 21:41:05 -04:00
|
|
|
GError * error = NULL;
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
AutoRegisterData auto_register_data = {
|
|
|
|
|
.step = 0,
|
|
|
|
|
.invoke_count = 0,
|
|
|
|
|
};
|
|
|
|
|
gulong signal_id;
|
|
|
|
|
NMTstContextBusyWatcherData watcher_data = {};
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
sinfo = nmtstc_service_init();
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!nmtstc_service_available(sinfo))
|
|
|
|
|
return;
|
|
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
agent = test_secret_agent_new(FALSE);
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
2014-08-29 12:27:47 -04:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
signal_id = g_signal_connect(agent,
|
|
|
|
|
"notify::" NM_SECRET_AGENT_OLD_REGISTERED,
|
|
|
|
|
G_CALLBACK(registered_changed),
|
|
|
|
|
&auto_register_data);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
if (nmtst_get_rand_bool()) {
|
|
|
|
|
g_object_set(agent, NM_SECRET_AGENT_OLD_AUTO_REGISTER, TRUE, NULL);
|
|
|
|
|
} else
|
|
|
|
|
nm_secret_agent_old_enable(agent, TRUE);
|
2014-11-20 11:53:19 -05:00
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
nm_secret_agent_old_register(agent, NULL, &error);
|
2014-09-02 21:41:05 -04:00
|
|
|
g_assert_no_error(error);
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
auto_register_data.step = 1;
|
|
|
|
|
nmtst_main_context_iterate_until_assert(NULL, 1000, nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
auto_register_data.step = 2;
|
|
|
|
|
nm_secret_agent_old_enable(agent, FALSE);
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
nmtst_main_context_iterate_until(NULL, nmtst_get_rand_uint32() % 200, FALSE);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
2016-10-01 19:28:11 +02:00
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_cleanup(sinfo);
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
nm_secret_agent_old_enable(agent, TRUE);
|
|
|
|
|
|
|
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
nmtst_main_context_iterate_until(NULL, nmtst_get_rand_uint32() % 200, FALSE);
|
|
|
|
|
|
2014-11-20 11:53:19 -05:00
|
|
|
g_assert(!nm_secret_agent_old_get_registered(agent));
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
sinfo = nmtstc_service_init();
|
2018-05-06 08:51:26 +02:00
|
|
|
g_assert(nmtstc_service_available(sinfo));
|
|
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
auto_register_data.step = 3;
|
|
|
|
|
nmtst_main_context_iterate_until_assert(NULL, 1000, nm_secret_agent_old_get_registered(agent));
|
2016-10-01 19:28:11 +02:00
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_cleanup(sinfo);
|
2014-08-29 12:27:47 -04:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
auto_register_data.step = 4;
|
|
|
|
|
nmtst_main_context_iterate_until_assert(NULL, 1000, !nm_secret_agent_old_get_registered(agent));
|
|
|
|
|
|
|
|
|
|
nm_clear_g_signal_handler(agent, &signal_id);
|
|
|
|
|
|
|
|
|
|
nmtst_context_busy_watcher_add(&watcher_data,
|
|
|
|
|
nm_secret_agent_old_get_context_busy_watcher(agent));
|
|
|
|
|
|
|
|
|
|
g_clear_object(&agent);
|
|
|
|
|
|
|
|
|
|
nmtst_context_busy_watcher_wait(&watcher_data);
|
|
|
|
|
|
|
|
|
|
nmtst_main_context_assert_no_dispatch(NULL, nmtst_get_rand_uint32() % 500);
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-08-29 12:27:47 -04:00
|
|
|
|
2015-07-03 15:11:17 +02:00
|
|
|
NMTST_DEFINE();
|
|
|
|
|
|
2014-08-29 12:27:47 -04:00
|
|
|
int
|
|
|
|
|
main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
g_setenv("LIBNM_USE_SESSION_BUS", "1", TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 15:11:17 +02:00
|
|
|
nmtst_init(&argc, &argv, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/secret-agent: rework NMSecretAgentOld
Note that the name "NMSecretAgentOld" comes from when libnm was forked
from libnm-glib. There was a plan to rework the secret agent API and
replace it by a better one. That didn't happen (yet), instead our one
and only agent implementation is still lacking. Don't add a new API, instead
try to improve the existing one, without breaking existing users. Just
get over the fact that the name "NMSecretAgentOld" is ugly.
Also note how nm-applet uses NMSecretAgentOld. It subtypes a class
AppletAgent. The constructor applet_agent_new() is calling the synchronous
g_initable_init() initialization with auto-register enabled. As it was,
g_initable_init() would call nm_secret_agent_old_register(), and if the
"Register" call failed, initialization failed for good. There are even
unit tests that test this behavior. This is bad behavior. It means, when
you start nm-applet without NetworkManager running, it will fail to create
the AppletAgent instance. It would hence be the responsibility of the applet
to recover from this situation (e.g. by retrying after timeout or watching
the D-Bus name owner). Of course, nm-applet doesn't do that and won't recover
from such a failure.
NMSecretAgentOld must try hard not to fail and recover automatically. The
user of the API is not interested in implementing the registration,
unregistration and retry handling. Instead, it should just work best
effort and transparently to the user of the API.
Differences:
- no longer use gdbus-codegen generate bindings. Use GDBusConnection
directly instead. These generated proxies complicate the code by
introducing an additional, stateful layer.
- properly handle GMainContext and synchronous initialization by using an
internal GMainContext.
With this NMSecretAgentOld can be used in a multi threaded context
with separate GMainContext. This does not mean that the object
itself became thread safe, but that the GMainContext gives the means
to coordinate multi-threaded access.
- there are no more blocking calls except g_initiable_init() which
iterates an internal GMainContext until initialization completes.
- obtaining the Unix user ID with "GetConnectionUnixUser" to authenticate
the server is now done asynchronously and only once per name-owner.
- NMSecretAgentOld will now register/export the Agent D-Bus object
already during initialization and stay registered as long as the
instance is alive. This is because usually registering a D-Bus
object would not fail, unless the D-Bus path is already taken.
Such an error would mean that another agent is registered for the same
GDBusConnection, that likely would be a bug in the caller. Hence,
such an issue is truly non-recoverable and should be reported early to
the user. There is a change in behavior compared to before, where previously
the D-Bus object would only be registered while the instance is enabled.
This makes a difference if the user intended to keep the NMSecretAgentOld
instance around in an unregistered state.
Note that nm_secret_agent_old_destroy() was added to really unregister
the D-Bus object. A destroyed instance can no longer be registered.
- the API no longer fully exposes the current registration state. The
user either enables or disables the agent. Then, in the background
NMSecretAgentOld will register, and serve requests as they come. It
will also always automatically re-register and it can de-facto no
longer fail. That is, there might be a failure to register, or the
NetworkManager peer might not be authenticated (non-root) or there
might be some other error, or NetworkManager might not be running.
But such errors are not exposed to the user. The instance is just not
able to provide the secrets in those cases, but it may recover if the
problem can be resolved.
- In particular, it makes no sense that nm_secret_agent_old_register*()
fails, returns an error, or waits until registration is complete. This
API is now only to enable/disable the agent. It is idempotent and
won't fail (there is a catch, see next point).
In particular, nm_secret_agent_old_unregister*() cannot fail anymore.
- However, with the previous point there is a problem/race. When you create
a NMSecretAgentOld instance and immediately afterwards activate a
profile, then you want to be sure that the registration is complete
first. Otherwise, NetworkManager might fail the activation because
no secret agent registered yet. A partial solution for this is
that g_initiable_init()/g_async_initable_init_async() will block
until registration is complete (or with or without success). That means,
if NetworkManager is running, initializing the NMSecretAgentOld will
wait until registration is complete (or failed). However, that does not
solve the race if NetworkManager was not running when creating the
instance.
To solve that race, the user may call nm_secret_agent_old_register_async()
and wait for the command to finish before starting activating. While
async registration no longer fails (in the sense of leaving the agent
permanently disconnected), it will try to ensure that we are
successfully registered and ready to serve requests. By using this
API correctly, a race can be avoided and the user can know that the
instance is now ready to serve request.
2019-12-24 13:26:50 +01:00
|
|
|
g_test_add("/libnm/secret-agent/none",
|
|
|
|
|
TestSecretAgentData,
|
|
|
|
|
"0",
|
|
|
|
|
test_setup,
|
|
|
|
|
test_secret_agent_none,
|
|
|
|
|
test_cleanup);
|
|
|
|
|
g_test_add("/libnm/secret-agent/no-secrets",
|
|
|
|
|
TestSecretAgentData,
|
|
|
|
|
"1",
|
|
|
|
|
test_setup,
|
|
|
|
|
test_secret_agent_no_secrets,
|
|
|
|
|
test_cleanup);
|
|
|
|
|
g_test_add("/libnm/secret-agent/cancel",
|
|
|
|
|
TestSecretAgentData,
|
|
|
|
|
"1",
|
|
|
|
|
test_setup,
|
|
|
|
|
test_secret_agent_cancel,
|
|
|
|
|
test_cleanup);
|
|
|
|
|
g_test_add("/libnm/secret-agent/good",
|
|
|
|
|
TestSecretAgentData,
|
|
|
|
|
"1",
|
|
|
|
|
test_setup,
|
|
|
|
|
test_secret_agent_good,
|
|
|
|
|
test_cleanup);
|
2014-08-29 12:27:47 -04:00
|
|
|
g_test_add_func("/libnm/secret-agent/nm-not-running", test_secret_agent_nm_not_running);
|
|
|
|
|
g_test_add_func("/libnm/secret-agent/auto-register", test_secret_agent_auto_register);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-03 07:32:36 +01:00
|
|
|
return g_test_run();
|
2014-08-29 12:27:47 -04:00
|
|
|
}
|