diff options
Diffstat (limited to 'clients/common/nm-secret-agent-simple.c')
| -rw-r--r-- | clients/common/nm-secret-agent-simple.c | 2224 |
1 files changed, 1132 insertions, 1092 deletions
diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 53217e6f..4aed136f 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2011 - 2015 Red Hat, Inc. * Copyright (C) 2011 Giovanni Campagna <scampa.giovanni@gmail.com> @@ -30,83 +30,84 @@ /*****************************************************************************/ typedef struct { - char *request_id; + char *request_id; - NMSecretAgentSimple *self; + NMSecretAgentSimple *self; - NMConnection *connection; - const char *setting_name; - char **hints; - NMSecretAgentOldGetSecretsFunc callback; - gpointer callback_data; - GCancellable *cancellable; - NMSecretAgentGetSecretsFlags flags; + NMConnection * connection; + const char * setting_name; + char ** hints; + NMSecretAgentOldGetSecretsFunc callback; + gpointer callback_data; + GCancellable * cancellable; + NMSecretAgentGetSecretsFlags flags; } RequestData; enum { - REQUEST_SECRETS, + REQUEST_SECRETS, - LAST_SIGNAL + LAST_SIGNAL }; -static guint signals[LAST_SIGNAL] = { 0 }; +static guint signals[LAST_SIGNAL] = {0}; typedef struct { - GHashTable *requests; + GHashTable *requests; - char *path; - gboolean enabled; + char * path; + gboolean enabled; } NMSecretAgentSimplePrivate; struct _NMSecretAgentSimple { - NMSecretAgentOld parent; - NMSecretAgentSimplePrivate _priv; + NMSecretAgentOld parent; + NMSecretAgentSimplePrivate _priv; }; struct _NMSecretAgentSimpleClass { - NMSecretAgentOldClass parent; + NMSecretAgentOldClass parent; }; -G_DEFINE_TYPE (NMSecretAgentSimple, nm_secret_agent_simple, NM_TYPE_SECRET_AGENT_OLD) +G_DEFINE_TYPE(NMSecretAgentSimple, nm_secret_agent_simple, NM_TYPE_SECRET_AGENT_OLD) -#define NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSecretAgentSimple, NM_IS_SECRET_AGENT_SIMPLE, NMSecretAgentOld) +#define NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSecretAgentSimple, NM_IS_SECRET_AGENT_SIMPLE, NMSecretAgentOld) /*****************************************************************************/ static void -_request_data_free (gpointer data) +_request_data_free(gpointer data) { - RequestData *request = data; + RequestData *request = data; - g_free (request->request_id); - nm_clear_g_cancellable (&request->cancellable); - g_object_unref (request->connection); - g_strfreev (request->hints); + g_free(request->request_id); + nm_clear_g_cancellable(&request->cancellable); + g_object_unref(request->connection); + g_strfreev(request->hints); - g_slice_free (RequestData, request); + g_slice_free(RequestData, request); } static void -_request_data_complete (RequestData *request, - GVariant *secrets, - GError *error, - GHashTableIter *iter_to_remove) +_request_data_complete(RequestData * request, + GVariant * secrets, + GError * error, + GHashTableIter *iter_to_remove) { - NMSecretAgentSimple *self = request->self; - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self); + NMSecretAgentSimple * self = request->self; + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self); - nm_assert ((secrets != NULL) != (error != NULL)); + nm_assert((secrets != NULL) != (error != NULL)); - request->callback (NM_SECRET_AGENT_OLD (request->self), - request->connection, - secrets, - error, - request->callback_data); + request->callback(NM_SECRET_AGENT_OLD(request->self), + request->connection, + secrets, + error, + request->callback_data); - if (iter_to_remove) - g_hash_table_iter_remove (iter_to_remove); - else - g_hash_table_remove (priv->requests, request); + if (iter_to_remove) + g_hash_table_iter_remove(iter_to_remove); + else + g_hash_table_remove(priv->requests, request); } /*****************************************************************************/ @@ -122,935 +123,959 @@ _request_data_complete (RequestData *request, */ typedef struct { - NMSecretAgentSimpleSecret base; - NMSetting *setting; - char *property; + NMSecretAgentSimpleSecret base; + NMSetting * setting; + char * property; } SecretReal; static void -_secret_real_free (NMSecretAgentSimpleSecret *secret) +_secret_real_free(NMSecretAgentSimpleSecret *secret) { - SecretReal *real = (SecretReal *)secret; + SecretReal *real = (SecretReal *) secret; - g_free ((char *) secret->pretty_name); - g_free ((char *) secret->entry_id); - nm_free_secret (secret->value); - g_free ((char *) secret->vpn_type); - g_free (real->property); - g_clear_object (&real->setting); + g_free((char *) secret->pretty_name); + g_free((char *) secret->entry_id); + nm_free_secret(secret->value); + g_free((char *) secret->vpn_type); + g_free(real->property); + g_clear_object(&real->setting); - g_slice_free (SecretReal, real); + g_slice_free(SecretReal, real); } static NMSecretAgentSimpleSecret * -_secret_real_new_plain (NMSecretAgentSecretType secret_type, - const char *pretty_name, - NMSetting *setting, - const char *property) +_secret_real_new_plain(NMSecretAgentSecretType secret_type, + const char * pretty_name, + NMSetting * setting, + const char * property) { - SecretReal *real; - gs_free char *value= NULL; - - nm_assert (property); - nm_assert (NM_IS_SETTING (setting)); - nm_assert (NM_IN_SET (secret_type, NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, NM_SECRET_AGENT_SECRET_TYPE_SECRET)); - nm_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property)); - nm_assert ((secret_type == NM_SECRET_AGENT_SECRET_TYPE_SECRET) == nm_setting_get_secret_flags (setting, property, NULL, NULL)); - - g_object_get (setting, property, &value, NULL); - - real = g_slice_new (SecretReal); - *real = (SecretReal) { - .base.secret_type = secret_type, - .base.pretty_name = g_strdup (pretty_name), - .base.entry_id = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property), - .base.value = g_steal_pointer (&value), - .base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY), - .setting = g_object_ref (setting), - .property = g_strdup (property), - }; - return &real->base; + SecretReal * real; + gs_free char *value = NULL; + + nm_assert(property); + nm_assert(NM_IS_SETTING(setting)); + nm_assert(NM_IN_SET(secret_type, + NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + NM_SECRET_AGENT_SECRET_TYPE_SECRET)); + nm_assert(g_object_class_find_property(G_OBJECT_GET_CLASS(setting), property)); + nm_assert((secret_type == NM_SECRET_AGENT_SECRET_TYPE_SECRET) + == nm_setting_get_secret_flags(setting, property, NULL, NULL)); + + g_object_get(setting, property, &value, NULL); + + real = g_slice_new(SecretReal); + *real = (SecretReal){ + .base.secret_type = secret_type, + .base.pretty_name = g_strdup(pretty_name), + .base.entry_id = g_strdup_printf("%s.%s", nm_setting_get_name(setting), property), + .base.value = g_steal_pointer(&value), + .base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY), + .setting = g_object_ref(setting), + .property = g_strdup(property), + }; + return &real->base; } static NMSecretAgentSimpleSecret * -_secret_real_new_vpn_secret (const char *pretty_name, - NMSetting *setting, - const char *property, - const char *vpn_type) +_secret_real_new_vpn_secret(const char *pretty_name, + NMSetting * setting, + const char *property, + const char *vpn_type) { - SecretReal *real; - const char *value; - - nm_assert (property); - nm_assert (NM_IS_SETTING_VPN (setting)); - nm_assert (vpn_type); - - value = nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), property); - - real = g_slice_new (SecretReal); - *real = (SecretReal) { - .base.secret_type = NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, - .base.pretty_name = g_strdup (pretty_name), - .base.entry_id = g_strdup_printf ("%s%s", NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRETS, property), - .base.value = g_strdup (value), - .base.is_secret = TRUE, - .base.vpn_type = g_strdup (vpn_type), - .setting = g_object_ref (setting), - .property = g_strdup (property), - }; - return &real->base; + SecretReal *real; + const char *value; + + nm_assert(property); + nm_assert(NM_IS_SETTING_VPN(setting)); + nm_assert(vpn_type); + + value = nm_setting_vpn_get_secret(NM_SETTING_VPN(setting), property); + + real = g_slice_new(SecretReal); + *real = (SecretReal){ + .base.secret_type = NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, + .base.pretty_name = g_strdup(pretty_name), + .base.entry_id = + g_strdup_printf("%s%s", NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRETS, property), + .base.value = g_strdup(value), + .base.is_secret = TRUE, + .base.vpn_type = g_strdup(vpn_type), + .setting = g_object_ref(setting), + .property = g_strdup(property), + }; + return &real->base; } static NMSecretAgentSimpleSecret * -_secret_real_new_wireguard_peer_psk (NMSettingWireGuard *s_wg, - const char *public_key, - const char *preshared_key) +_secret_real_new_wireguard_peer_psk(NMSettingWireGuard *s_wg, + const char * public_key, + const char * preshared_key) { - SecretReal *real; - - nm_assert (NM_IS_SETTING_WIREGUARD (s_wg)); - nm_assert (public_key); - - real = g_slice_new (SecretReal); - *real = (SecretReal) { - .base.secret_type = NM_SECRET_AGENT_SECRET_TYPE_WIREGUARD_PEER_PSK, - .base.pretty_name = g_strdup_printf (_("Preshared-key for %s"), - public_key), - .base.entry_id = g_strdup_printf (NM_SETTING_WIREGUARD_SETTING_NAME"."NM_SETTING_WIREGUARD_PEERS".%s."NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, - public_key), - .base.value = g_strdup (preshared_key), - .base.is_secret = TRUE, - .base.no_prompt_entry_id = TRUE, - .setting = NM_SETTING (g_object_ref (s_wg)), - .property = g_strdup (public_key), - }; - return &real->base; + SecretReal *real; + + nm_assert(NM_IS_SETTING_WIREGUARD(s_wg)); + nm_assert(public_key); + + real = g_slice_new(SecretReal); + *real = (SecretReal){ + .base.secret_type = NM_SECRET_AGENT_SECRET_TYPE_WIREGUARD_PEER_PSK, + .base.pretty_name = g_strdup_printf(_("Preshared-key for %s"), public_key), + .base.entry_id = g_strdup_printf(NM_SETTING_WIREGUARD_SETTING_NAME + "." NM_SETTING_WIREGUARD_PEERS + ".%s." NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, + public_key), + .base.value = g_strdup(preshared_key), + .base.is_secret = TRUE, + .base.no_prompt_entry_id = TRUE, + .setting = NM_SETTING(g_object_ref(s_wg)), + .property = g_strdup(public_key), + }; + return &real->base; } /*****************************************************************************/ static gboolean -add_8021x_secrets (RequestData *request, - GPtrArray *secrets) +add_8021x_secrets(RequestData *request, GPtrArray *secrets) { - NMSetting8021x *s_8021x = nm_connection_get_setting_802_1x (request->connection); - const char *eap_method; - NMSecretAgentSimpleSecret *secret; - - /* If hints are given, then always ask for what the hints require */ - if (request->hints && request->hints[0]) { - char **iter; - - for (iter = request->hints; *iter; iter++) { - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _(*iter), - NM_SETTING (s_8021x), - *iter); - g_ptr_array_add (secrets, secret); - } - - return TRUE; - } - - eap_method = nm_setting_802_1x_get_eap_method (s_8021x, 0); - if (!eap_method) - return FALSE; - - if (NM_IN_STRSET (eap_method, "md5", - "leap", - "ttls", - "peap")) { - /* TTLS and PEAP are actually much more complicated, but this complication - * is not visible here since we only care about phase2 authentication - * (and don't even care of which one) - */ - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Username"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_IDENTITY); - g_ptr_array_add (secrets, secret); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_PASSWORD); - g_ptr_array_add (secrets, secret); - return TRUE; - } - - if (nm_streq (eap_method, "tls")) { - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Identity"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_IDENTITY); - g_ptr_array_add (secrets, secret); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Private key password"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); - g_ptr_array_add (secrets, secret); - return TRUE; - } - - return FALSE; + NMSetting8021x * s_8021x = nm_connection_get_setting_802_1x(request->connection); + const char * eap_method; + NMSecretAgentSimpleSecret *secret; + + /* If hints are given, then always ask for what the hints require */ + if (request->hints && request->hints[0]) { + char **iter; + + for (iter = request->hints; *iter; iter++) { + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _(*iter), + NM_SETTING(s_8021x), + *iter); + g_ptr_array_add(secrets, secret); + } + + return TRUE; + } + + eap_method = nm_setting_802_1x_get_eap_method(s_8021x, 0); + if (!eap_method) + return FALSE; + + if (NM_IN_STRSET(eap_method, "md5", "leap", "ttls", "peap")) { + /* TTLS and PEAP are actually much more complicated, but this complication + * is not visible here since we only care about phase2 authentication + * (and don't even care of which one) + */ + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), + NM_SETTING(s_8021x), + NM_SETTING_802_1X_IDENTITY); + g_ptr_array_add(secrets, secret); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_8021x), + NM_SETTING_802_1X_PASSWORD); + g_ptr_array_add(secrets, secret); + return TRUE; + } + + if (nm_streq(eap_method, "tls")) { + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Identity"), + NM_SETTING(s_8021x), + NM_SETTING_802_1X_IDENTITY); + g_ptr_array_add(secrets, secret); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Private key password"), + NM_SETTING(s_8021x), + NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); + g_ptr_array_add(secrets, secret); + return TRUE; + } + + return FALSE; } static gboolean -add_wireless_secrets (RequestData *request, - GPtrArray *secrets) +add_wireless_secrets(RequestData *request, GPtrArray *secrets) { - NMSettingWirelessSecurity *s_wsec = nm_connection_get_setting_wireless_security (request->connection); - const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); - NMSecretAgentSimpleSecret *secret; - - if (!key_mgmt || nm_streq (key_mgmt, "owe")) - return FALSE; - - if (NM_IN_STRSET (key_mgmt, "wpa-psk", "sae")) { - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_PSK); - g_ptr_array_add (secrets, secret); - return TRUE; - } - - if (nm_streq (key_mgmt, "none")) { - guint32 index; - char key[100]; - - index = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Key"), - NM_SETTING (s_wsec), - nm_sprintf_buf (key, "wep-key%u", (guint) index)); - g_ptr_array_add (secrets, secret); - return TRUE; - } - - if (nm_streq (key_mgmt, "iee8021x")) { - if (nm_streq0 (nm_setting_wireless_security_get_auth_alg (s_wsec), "leap")) { - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD); - g_ptr_array_add (secrets, secret); - return TRUE; - } else - return add_8021x_secrets (request, secrets); - } - - if (nm_streq (key_mgmt, "wpa-eap")) - return add_8021x_secrets (request, secrets); - - return FALSE; + NMSettingWirelessSecurity *s_wsec = + nm_connection_get_setting_wireless_security(request->connection); + const char * key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); + NMSecretAgentSimpleSecret *secret; + + if (!key_mgmt || nm_streq(key_mgmt, "owe")) + return FALSE; + + if (NM_IN_STRSET(key_mgmt, "wpa-psk", "sae")) { + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_wsec), + NM_SETTING_WIRELESS_SECURITY_PSK); + g_ptr_array_add(secrets, secret); + return TRUE; + } + + if (nm_streq(key_mgmt, "none")) { + guint32 index; + char key[100]; + + index = nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Key"), + NM_SETTING(s_wsec), + nm_sprintf_buf(key, "wep-key%u", (guint) index)); + g_ptr_array_add(secrets, secret); + return TRUE; + } + + if (nm_streq(key_mgmt, "iee8021x")) { + if (nm_streq0(nm_setting_wireless_security_get_auth_alg(s_wsec), "leap")) { + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_wsec), + NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD); + g_ptr_array_add(secrets, secret); + return TRUE; + } else + return add_8021x_secrets(request, secrets); + } + + if (nm_streq(key_mgmt, "wpa-eap")) + return add_8021x_secrets(request, secrets); + + return FALSE; } static gboolean -add_pppoe_secrets (RequestData *request, - GPtrArray *secrets) +add_pppoe_secrets(RequestData *request, GPtrArray *secrets) { - NMSettingPppoe *s_pppoe = nm_connection_get_setting_pppoe (request->connection); - NMSecretAgentSimpleSecret *secret; - - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Username"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_USERNAME); - g_ptr_array_add (secrets, secret); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Service"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_SERVICE); - g_ptr_array_add (secrets, secret); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_PASSWORD); - g_ptr_array_add (secrets, secret); - return TRUE; + NMSettingPppoe * s_pppoe = nm_connection_get_setting_pppoe(request->connection); + NMSecretAgentSimpleSecret *secret; + + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), + NM_SETTING(s_pppoe), + NM_SETTING_PPPOE_USERNAME); + g_ptr_array_add(secrets, secret); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Service"), + NM_SETTING(s_pppoe), + NM_SETTING_PPPOE_SERVICE); + g_ptr_array_add(secrets, secret); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_pppoe), + NM_SETTING_PPPOE_PASSWORD); + g_ptr_array_add(secrets, secret); + return TRUE; } static NMSettingSecretFlags -get_vpn_secret_flags (NMSettingVpn *s_vpn, const char *secret_name) +get_vpn_secret_flags(NMSettingVpn *s_vpn, const char *secret_name) { - NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - GHashTable *vpn_data; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + GHashTable * vpn_data; - g_object_get (s_vpn, NM_SETTING_VPN_DATA, &vpn_data, NULL); - nm_vpn_service_plugin_get_secret_flags (vpn_data, secret_name, &flags); - g_hash_table_unref (vpn_data); + g_object_get(s_vpn, NM_SETTING_VPN_DATA, &vpn_data, NULL); + nm_vpn_service_plugin_get_secret_flags(vpn_data, secret_name, &flags); + g_hash_table_unref(vpn_data); - return flags; + return flags; } static void -add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name, const char *ui_name) +add_vpn_secret_helper(GPtrArray * secrets, + NMSettingVpn *s_vpn, + const char * name, + const char * ui_name) { - NMSecretAgentSimpleSecret *secret; - NMSettingSecretFlags flags; - int i; - - flags = get_vpn_secret_flags (s_vpn, name); - if ( flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED - || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) { - secret = _secret_real_new_vpn_secret (ui_name, - NM_SETTING (s_vpn), - name, - nm_setting_vpn_get_service_type (s_vpn)); - - /* Check for duplicates */ - for (i = 0; i < secrets->len; i++) { - NMSecretAgentSimpleSecret *s = secrets->pdata[i]; - - if ( s->secret_type == secret->secret_type - && nm_streq0 (s->vpn_type, secret->vpn_type) - && nm_streq0 (s->entry_id, secret->entry_id)) { - _secret_real_free (secret); - return; - } - } - - g_ptr_array_add (secrets, secret); - } + NMSecretAgentSimpleSecret *secret; + NMSettingSecretFlags flags; + int i; + + flags = get_vpn_secret_flags(s_vpn, name); + if (flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) { + secret = _secret_real_new_vpn_secret(ui_name, + NM_SETTING(s_vpn), + name, + nm_setting_vpn_get_service_type(s_vpn)); + + /* Check for duplicates */ + for (i = 0; i < secrets->len; i++) { + NMSecretAgentSimpleSecret *s = secrets->pdata[i]; + + if (s->secret_type == secret->secret_type && nm_streq0(s->vpn_type, secret->vpn_type) + && nm_streq0(s->entry_id, secret->entry_id)) { + _secret_real_free(secret); + return; + } + } + + g_ptr_array_add(secrets, secret); + } } #define VPN_MSG_TAG "x-vpn-message:" static gboolean -add_vpn_secrets (RequestData *request, - GPtrArray *secrets, - char **msg) +add_vpn_secrets(RequestData *request, GPtrArray *secrets, char **msg) { - NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (request->connection); - const NmcVpnPasswordName *p; - const char *vpn_msg = NULL; - char **iter; - - /* If hints are given, then always ask for what the hints require */ - if (request->hints) { - for (iter = request->hints; *iter; iter++) { - if (!vpn_msg && g_str_has_prefix (*iter, VPN_MSG_TAG)) - vpn_msg = &(*iter)[NM_STRLEN (VPN_MSG_TAG)]; - else - add_vpn_secret_helper (secrets, s_vpn, *iter, *iter); - } - } - - NM_SET_OUT (msg, g_strdup (vpn_msg)); - - /* Now add what client thinks might be required, because hints may be empty or incomplete */ - p = nm_vpn_get_secret_names (nm_setting_vpn_get_service_type (s_vpn)); - while (p && p->name) { - add_vpn_secret_helper (secrets, s_vpn, p->name, _(p->ui_name)); - p++; - } - - return TRUE; + NMSettingVpn * s_vpn = nm_connection_get_setting_vpn(request->connection); + const NmcVpnPasswordName *p; + const char * vpn_msg = NULL; + char ** iter; + + /* If hints are given, then always ask for what the hints require */ + if (request->hints) { + for (iter = request->hints; *iter; iter++) { + if (!vpn_msg && g_str_has_prefix(*iter, VPN_MSG_TAG)) + vpn_msg = &(*iter)[NM_STRLEN(VPN_MSG_TAG)]; + else + add_vpn_secret_helper(secrets, s_vpn, *iter, *iter); + } + } + + NM_SET_OUT(msg, g_strdup(vpn_msg)); + + /* Now add what client thinks might be required, because hints may be empty or incomplete */ + p = nm_vpn_get_secret_names(nm_setting_vpn_get_service_type(s_vpn)); + while (p && p->name) { + add_vpn_secret_helper(secrets, s_vpn, p->name, _(p->ui_name)); + p++; + } + + return TRUE; } static gboolean -add_wireguard_secrets (RequestData *request, - GPtrArray *secrets, - char **msg, - GError **error) +add_wireguard_secrets(RequestData *request, GPtrArray *secrets, char **msg, GError **error) { - NMSettingWireGuard *s_wg; - NMSecretAgentSimpleSecret *secret; - guint i; - - s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (request->connection, NM_TYPE_SETTING_WIREGUARD)); - if (!s_wg) { - g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Cannot service a WireGuard secrets request %s for a connection without WireGuard settings", - request->request_id); - return FALSE; - } - - if ( !request->hints - || !request->hints[0] - || g_strv_contains (NM_CAST_STRV_CC (request->hints), NM_SETTING_WIREGUARD_PRIVATE_KEY)) { - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("WireGuard private-key"), - NM_SETTING (s_wg), - NM_SETTING_WIREGUARD_PRIVATE_KEY); - g_ptr_array_add (secrets, secret); - } - - if (request->hints) { - - for (i = 0; request->hints[i]; i++) { - NMWireGuardPeer *peer; - const char *name = request->hints[i]; - gs_free char *public_key = NULL; - - if (nm_streq (name, NM_SETTING_WIREGUARD_PRIVATE_KEY)) - continue; - - if (NM_STR_HAS_PREFIX (name, NM_SETTING_WIREGUARD_PEERS".")) { - const char *tmp; - - tmp = &name[NM_STRLEN (NM_SETTING_WIREGUARD_PEERS".")]; - if (NM_STR_HAS_SUFFIX (tmp, "."NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)) { - public_key = g_strndup (tmp, - strlen (tmp) - NM_STRLEN ("."NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)); - } - } - - if (!public_key) - continue; - - peer = nm_setting_wireguard_get_peer_by_public_key (s_wg, public_key, NULL); - - g_ptr_array_add (secrets, _secret_real_new_wireguard_peer_psk (s_wg, - ( peer - ? nm_wireguard_peer_get_public_key (peer) - : public_key), - ( peer - ? nm_wireguard_peer_get_preshared_key (peer) - : NULL))); - } - } - - *msg = g_strdup_printf (_("Secrets are required to connect WireGuard VPN '%s'"), - nm_connection_get_id (request->connection)); - return TRUE; + NMSettingWireGuard * s_wg; + NMSecretAgentSimpleSecret *secret; + guint i; + + s_wg = NM_SETTING_WIREGUARD( + nm_connection_get_setting(request->connection, NM_TYPE_SETTING_WIREGUARD)); + if (!s_wg) { + g_set_error(error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Cannot service a WireGuard secrets request %s for a connection without " + "WireGuard settings", + request->request_id); + return FALSE; + } + + if (!request->hints || !request->hints[0] + || g_strv_contains(NM_CAST_STRV_CC(request->hints), NM_SETTING_WIREGUARD_PRIVATE_KEY)) { + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("WireGuard private-key"), + NM_SETTING(s_wg), + NM_SETTING_WIREGUARD_PRIVATE_KEY); + g_ptr_array_add(secrets, secret); + } + + if (request->hints) { + for (i = 0; request->hints[i]; i++) { + NMWireGuardPeer *peer; + const char * name = request->hints[i]; + gs_free char * public_key = NULL; + + if (nm_streq(name, NM_SETTING_WIREGUARD_PRIVATE_KEY)) + continue; + + if (NM_STR_HAS_PREFIX(name, NM_SETTING_WIREGUARD_PEERS ".")) { + const char *tmp; + + tmp = &name[NM_STRLEN(NM_SETTING_WIREGUARD_PEERS ".")]; + if (NM_STR_HAS_SUFFIX(tmp, "." NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)) { + public_key = g_strndup( + tmp, + strlen(tmp) - NM_STRLEN("." NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)); + } + } + + if (!public_key) + continue; + + peer = nm_setting_wireguard_get_peer_by_public_key(s_wg, public_key, NULL); + + g_ptr_array_add(secrets, + _secret_real_new_wireguard_peer_psk( + s_wg, + (peer ? nm_wireguard_peer_get_public_key(peer) : public_key), + (peer ? nm_wireguard_peer_get_preshared_key(peer) : NULL))); + } + } + + *msg = g_strdup_printf(_("Secrets are required to connect WireGuard VPN '%s'"), + nm_connection_get_id(request->connection)); + return TRUE; } typedef struct { - GPid auth_dialog_pid; - GString *auth_dialog_response; - RequestData *request; - GPtrArray *secrets; - GCancellable *cancellable; - gulong cancellable_id; - guint child_watch_id; - GInputStream *input_stream; - GOutputStream *output_stream; - char read_buf[5]; + GPid auth_dialog_pid; + GString * auth_dialog_response; + RequestData * request; + GPtrArray * secrets; + GCancellable * cancellable; + gulong cancellable_id; + guint child_watch_id; + GInputStream * input_stream; + GOutputStream *output_stream; + char read_buf[5]; } AuthDialogData; static void -_auth_dialog_data_free (AuthDialogData *data) +_auth_dialog_data_free(AuthDialogData *data) { - nm_clear_g_signal_handler (data->cancellable, &data->cancellable_id); - g_clear_object (&data->cancellable); - nm_clear_g_source (&data->child_watch_id); - g_ptr_array_unref (data->secrets); - g_spawn_close_pid (data->auth_dialog_pid); - g_string_free (data->auth_dialog_response, TRUE); - g_object_unref (data->input_stream); - g_object_unref (data->output_stream); - g_slice_free (AuthDialogData, data); + nm_clear_g_signal_handler(data->cancellable, &data->cancellable_id); + g_clear_object(&data->cancellable); + nm_clear_g_source(&data->child_watch_id); + g_ptr_array_unref(data->secrets); + g_spawn_close_pid(data->auth_dialog_pid); + g_string_free(data->auth_dialog_response, TRUE); + g_object_unref(data->input_stream); + g_object_unref(data->output_stream); + g_slice_free(AuthDialogData, data); } static void -_auth_dialog_exited (GPid pid, int status, gpointer user_data) +_auth_dialog_exited(GPid pid, int status, gpointer user_data) { - AuthDialogData *data = user_data; - RequestData *request = data->request; - GPtrArray *secrets = data->secrets; - NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (request->connection); - gs_unref_keyfile GKeyFile *keyfile = NULL; - gs_strfreev char **groups = NULL; - gs_free char *title = NULL; - gs_free char *message = NULL; - int i; - gs_free_error GError *error = NULL; - - data->child_watch_id = 0; - - nm_clear_g_cancellable_disconnect (data->cancellable, &data->cancellable_id); - - if (status != 0) { - g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Auth dialog failed with error code %d\n", status); - goto out; - } - - keyfile = g_key_file_new (); - if (!g_key_file_load_from_data (keyfile, - data->auth_dialog_response->str, - data->auth_dialog_response->len, G_KEY_FILE_NONE, - &error)) { - goto out; - } - - groups = g_key_file_get_groups (keyfile, NULL); - if (!nm_streq0 (groups[0], "VPN Plugin UI")) { - g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Expected [VPN Plugin UI] in auth dialog response"); - goto out; - } - - title = g_key_file_get_string (keyfile, "VPN Plugin UI", "Title", &error); - if (!title) - goto out; - - message = g_key_file_get_string (keyfile, "VPN Plugin UI", "Description", &error); - if (!message) - goto out; - - for (i = 1; groups[i]; i++) { - gs_free char *pretty_name = NULL; - - if (!g_key_file_get_boolean (keyfile, groups[i], "IsSecret", NULL)) - continue; - if (!g_key_file_get_boolean (keyfile, groups[i], "ShouldAsk", NULL)) - continue; - - pretty_name = g_key_file_get_string (keyfile, groups[i], "Label", NULL); - g_ptr_array_add (secrets, _secret_real_new_vpn_secret (pretty_name, - NM_SETTING (s_vpn), - groups[i], - nm_setting_vpn_get_service_type (s_vpn))); - } + AuthDialogData * data = user_data; + RequestData * request = data->request; + GPtrArray * secrets = data->secrets; + NMSettingVpn * s_vpn = nm_connection_get_setting_vpn(request->connection); + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + gs_strfreev char ** groups = NULL; + gs_free char * title = NULL; + gs_free char * message = NULL; + int i; + gs_free_error GError *error = NULL; + + data->child_watch_id = 0; + + nm_clear_g_cancellable_disconnect(data->cancellable, &data->cancellable_id); + + if (status != 0) { + g_set_error(&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Auth dialog failed with error code %d\n", + status); + goto out; + } + + keyfile = g_key_file_new(); + if (!g_key_file_load_from_data(keyfile, + data->auth_dialog_response->str, + data->auth_dialog_response->len, + G_KEY_FILE_NONE, + &error)) { + goto out; + } + + groups = g_key_file_get_groups(keyfile, NULL); + if (!nm_streq0(groups[0], "VPN Plugin UI")) { + g_set_error(&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Expected [VPN Plugin UI] in auth dialog response"); + goto out; + } + + title = g_key_file_get_string(keyfile, "VPN Plugin UI", "Title", &error); + if (!title) + goto out; + + message = g_key_file_get_string(keyfile, "VPN Plugin UI", "Description", &error); + if (!message) + goto out; + + for (i = 1; groups[i]; i++) { + gs_free char *pretty_name = NULL; + + if (!g_key_file_get_boolean(keyfile, groups[i], "IsSecret", NULL)) + continue; + if (!g_key_file_get_boolean(keyfile, groups[i], "ShouldAsk", NULL)) + continue; + + pretty_name = g_key_file_get_string(keyfile, groups[i], "Label", NULL); + g_ptr_array_add(secrets, + _secret_real_new_vpn_secret(pretty_name, + NM_SETTING(s_vpn), + groups[i], + nm_setting_vpn_get_service_type(s_vpn))); + } out: - /* Try to fall back to the hardwired VPN support if the auth dialog fails. - * We may eventually get rid of the whole hardwired secrets handling at some point, - * when the auth helpers are goode enough.. */ - if (error && add_vpn_secrets (request, secrets, &message)) { - g_clear_error (&error); - if (!message) { - message = g_strdup_printf (_("A password is required to connect to '%s'."), - nm_connection_get_id (request->connection)); - } - } - - if (error) - _request_data_complete (request, NULL, error, NULL); - else { - g_signal_emit (request->self, signals[REQUEST_SECRETS], 0, - request->request_id, title, message, secrets); - } - - _auth_dialog_data_free (data); + /* Try to fall back to the hardwired VPN support if the auth dialog fails. + * We may eventually get rid of the whole hardwired secrets handling at some point, + * when the auth helpers are goode enough.. */ + if (error && add_vpn_secrets(request, secrets, &message)) { + g_clear_error(&error); + if (!message) { + message = g_strdup_printf(_("A password is required to connect to '%s'."), + nm_connection_get_id(request->connection)); + } + } + + if (error) + _request_data_complete(request, NULL, error, NULL); + else { + g_signal_emit(request->self, + signals[REQUEST_SECRETS], + 0, + request->request_id, + title, + message, + secrets); + } + + _auth_dialog_data_free(data); } static void -_request_cancelled (GObject *object, gpointer user_data) +_request_cancelled(GObject *object, gpointer user_data) { - _auth_dialog_data_free (user_data); + _auth_dialog_data_free(user_data); } static void -_auth_dialog_read_done (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +_auth_dialog_read_done(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GInputStream *auth_dialog_out = G_INPUT_STREAM (source_object); - AuthDialogData *data = user_data; - gssize read_size; - gs_free_error GError *error = NULL; - - read_size = g_input_stream_read_finish (auth_dialog_out, res, &error); - switch (read_size) { - case -1: - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - _request_data_complete (data->request, NULL, error, NULL); - _auth_dialog_data_free (data); - break; - case 0: - /* Done reading. Let's wait for the auth dialog to exit so that we're able to collect the status. - * Remember we can be cancelled in between. */ - data->child_watch_id = g_child_watch_add (data->auth_dialog_pid, _auth_dialog_exited, data); - data->cancellable = g_object_ref (data->request->cancellable); - data->cancellable_id = g_cancellable_connect (data->cancellable, - G_CALLBACK (_request_cancelled), data, NULL); - break; - default: - g_string_append_len (data->auth_dialog_response, data->read_buf, read_size); - g_input_stream_read_async (auth_dialog_out, - data->read_buf, - sizeof (data->read_buf), - G_PRIORITY_DEFAULT, - NULL, - _auth_dialog_read_done, - data); - return; - } - - g_input_stream_close (auth_dialog_out, NULL, NULL); + GInputStream * auth_dialog_out = G_INPUT_STREAM(source_object); + AuthDialogData *data = user_data; + gssize read_size; + gs_free_error GError *error = NULL; + + read_size = g_input_stream_read_finish(auth_dialog_out, res, &error); + switch (read_size) { + case -1: + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _request_data_complete(data->request, NULL, error, NULL); + _auth_dialog_data_free(data); + break; + case 0: + /* Done reading. Let's wait for the auth dialog to exit so that we're able to collect the status. + * Remember we can be cancelled in between. */ + data->child_watch_id = g_child_watch_add(data->auth_dialog_pid, _auth_dialog_exited, data); + data->cancellable = g_object_ref(data->request->cancellable); + data->cancellable_id = + g_cancellable_connect(data->cancellable, G_CALLBACK(_request_cancelled), data, NULL); + break; + default: + g_string_append_len(data->auth_dialog_response, data->read_buf, read_size); + g_input_stream_read_async(auth_dialog_out, + data->read_buf, + sizeof(data->read_buf), + G_PRIORITY_DEFAULT, + NULL, + _auth_dialog_read_done, + data); + return; + } + + g_input_stream_close(auth_dialog_out, NULL, NULL); } static void -_auth_dialog_write_done (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +_auth_dialog_write_done(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GOutputStream *auth_dialog_out = G_OUTPUT_STREAM (source_object); - _nm_unused gs_free char *auth_dialog_request_free = user_data; + GOutputStream *auth_dialog_out = G_OUTPUT_STREAM(source_object); + _nm_unused gs_free char *auth_dialog_request_free = user_data; - /* We don't care about write errors. If there are any problems, the - * reader shall notice. */ - g_output_stream_write_finish (auth_dialog_out, res, NULL); - g_output_stream_close (auth_dialog_out, NULL, NULL); + /* We don't care about write errors. If there are any problems, the + * reader shall notice. */ + g_output_stream_write_finish(auth_dialog_out, res, NULL); + g_output_stream_close(auth_dialog_out, NULL, NULL); } static void -_add_to_string (GString *string, const char *key, const char *value) +_add_to_string(GString *string, const char *key, const char *value) { - gs_strfreev char **lines = NULL; - int i; + gs_strfreev char **lines = NULL; + int i; - lines = g_strsplit (value, "\n", -1); + lines = g_strsplit(value, "\n", -1); - g_string_append (string, key); - for (i = 0; lines[i]; i++) { - g_string_append_c (string, '='); - g_string_append (string, lines[i]); - g_string_append_c (string, '\n'); - } + g_string_append(string, key); + for (i = 0; lines[i]; i++) { + g_string_append_c(string, '='); + g_string_append(string, lines[i]); + g_string_append_c(string, '\n'); + } } static void -_add_data_item_to_string (const char *key, const char *value, gpointer user_data) +_add_data_item_to_string(const char *key, const char *value, gpointer user_data) { - GString *string = user_data; + GString *string = user_data; - _add_to_string (string, "DATA_KEY", key); - _add_to_string (string, "DATA_VAL", value); - g_string_append_c (string, '\n'); + _add_to_string(string, "DATA_KEY", key); + _add_to_string(string, "DATA_VAL", value); + g_string_append_c(string, '\n'); } static void -_add_secret_to_string (const char *key, const char *value, gpointer user_data) +_add_secret_to_string(const char *key, const char *value, gpointer user_data) { - GString *string = user_data; + GString *string = user_data; - _add_to_string (string, "SECRET_KEY", key); - _add_to_string (string, "SECRET_VAL", value); - g_string_append_c (string, '\n'); + _add_to_string(string, "SECRET_KEY", key); + _add_to_string(string, "SECRET_VAL", value); + g_string_append_c(string, '\n'); } static gboolean -try_spawn_vpn_auth_helper (RequestData *request, - GPtrArray *secrets) +try_spawn_vpn_auth_helper(RequestData *request, GPtrArray *secrets) { - NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (request->connection); - gs_unref_ptrarray GPtrArray *auth_dialog_argv = NULL; - NMVpnPluginInfo *plugin_info; - const char *s; - GPid auth_dialog_pid; - int auth_dialog_in_fd; - int auth_dialog_out_fd; - GOutputStream *auth_dialog_in; - GInputStream *auth_dialog_out; - GError *error = NULL; - GString *auth_dialog_request; - char *auth_dialog_request_str; - gsize auth_dialog_request_len; - AuthDialogData *data; - int i; - - plugin_info = nm_vpn_plugin_info_list_find_by_service (nm_vpn_get_plugin_infos (), - nm_setting_vpn_get_service_type (s_vpn)); - if (!plugin_info) - return FALSE; - - s = nm_vpn_plugin_info_lookup_property (plugin_info, "GNOME", "supports-external-ui-mode"); - if (!_nm_utils_ascii_str_to_bool (s, FALSE)) - return FALSE; - - auth_dialog_argv = g_ptr_array_new (); - - s = nm_vpn_plugin_info_lookup_property (plugin_info, "GNOME", "auth-dialog"); - g_return_val_if_fail (s, FALSE); - g_ptr_array_add (auth_dialog_argv, (gpointer) s); - - g_ptr_array_add (auth_dialog_argv, "-u"); - g_ptr_array_add (auth_dialog_argv, (gpointer) nm_connection_get_uuid (request->connection)); - g_ptr_array_add (auth_dialog_argv, "-n"); - g_ptr_array_add (auth_dialog_argv, (gpointer) nm_connection_get_id (request->connection)); - g_ptr_array_add (auth_dialog_argv, "-s"); - g_ptr_array_add (auth_dialog_argv, (gpointer) nm_setting_vpn_get_service_type (s_vpn)); - g_ptr_array_add (auth_dialog_argv, "--external-ui-mode"); - g_ptr_array_add (auth_dialog_argv, "-i"); - - if (request->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) - g_ptr_array_add (auth_dialog_argv, "-r"); - - s = nm_vpn_plugin_info_lookup_property (plugin_info, "GNOME", "supports-hints"); - if (_nm_utils_ascii_str_to_bool (s, FALSE)) { - for (i = 0; request->hints[i]; i++) { - g_ptr_array_add (auth_dialog_argv, "-t"); - g_ptr_array_add (auth_dialog_argv, request->hints[i]); - } - } - - g_ptr_array_add (auth_dialog_argv, NULL); - if (!g_spawn_async_with_pipes (NULL, (char **) auth_dialog_argv->pdata, NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, NULL, - &auth_dialog_pid, - &auth_dialog_in_fd, - &auth_dialog_out_fd, - NULL, - &error)) { - g_warning ("Failed to spawn the auth dialog%s\n", error->message); - return FALSE; - } - - auth_dialog_in = g_unix_output_stream_new (auth_dialog_in_fd, TRUE); - auth_dialog_out = g_unix_input_stream_new (auth_dialog_out_fd, TRUE); - - auth_dialog_request = g_string_new_len (NULL, 1024); - nm_setting_vpn_foreach_data_item (s_vpn, _add_data_item_to_string, auth_dialog_request); - nm_setting_vpn_foreach_secret (s_vpn, _add_secret_to_string, auth_dialog_request); - g_string_append (auth_dialog_request, "DONE\nQUIT\n"); - auth_dialog_request_len = auth_dialog_request->len; - auth_dialog_request_str = g_string_free (auth_dialog_request, FALSE); - - data = g_slice_new (AuthDialogData); - *data = (AuthDialogData) { - .auth_dialog_response = g_string_new_len (NULL, sizeof (data->read_buf)), - .auth_dialog_pid = auth_dialog_pid, - .request = request, - .secrets = g_ptr_array_ref (secrets), - .input_stream = auth_dialog_out, - .output_stream = auth_dialog_in, - }; - - g_output_stream_write_async (auth_dialog_in, - auth_dialog_request_str, - auth_dialog_request_len, - G_PRIORITY_DEFAULT, - request->cancellable, - _auth_dialog_write_done, - auth_dialog_request_str); - - g_input_stream_read_async (auth_dialog_out, - data->read_buf, - sizeof (data->read_buf), - G_PRIORITY_DEFAULT, - request->cancellable, - _auth_dialog_read_done, - data); - - return TRUE; + NMSettingVpn * s_vpn = nm_connection_get_setting_vpn(request->connection); + gs_unref_ptrarray GPtrArray *auth_dialog_argv = NULL; + NMVpnPluginInfo * plugin_info; + const char * s; + GPid auth_dialog_pid; + int auth_dialog_in_fd; + int auth_dialog_out_fd; + GOutputStream * auth_dialog_in; + GInputStream * auth_dialog_out; + GError * error = NULL; + GString * auth_dialog_request; + char * auth_dialog_request_str; + gsize auth_dialog_request_len; + AuthDialogData * data; + int i; + + plugin_info = nm_vpn_plugin_info_list_find_by_service(nm_vpn_get_plugin_infos(), + nm_setting_vpn_get_service_type(s_vpn)); + if (!plugin_info) + return FALSE; + + s = nm_vpn_plugin_info_lookup_property(plugin_info, "GNOME", "supports-external-ui-mode"); + if (!_nm_utils_ascii_str_to_bool(s, FALSE)) + return FALSE; + + auth_dialog_argv = g_ptr_array_new(); + + s = nm_vpn_plugin_info_lookup_property(plugin_info, "GNOME", "auth-dialog"); + g_return_val_if_fail(s, FALSE); + g_ptr_array_add(auth_dialog_argv, (gpointer) s); + + g_ptr_array_add(auth_dialog_argv, "-u"); + g_ptr_array_add(auth_dialog_argv, (gpointer) nm_connection_get_uuid(request->connection)); + g_ptr_array_add(auth_dialog_argv, "-n"); + g_ptr_array_add(auth_dialog_argv, (gpointer) nm_connection_get_id(request->connection)); + g_ptr_array_add(auth_dialog_argv, "-s"); + g_ptr_array_add(auth_dialog_argv, (gpointer) nm_setting_vpn_get_service_type(s_vpn)); + g_ptr_array_add(auth_dialog_argv, "--external-ui-mode"); + g_ptr_array_add(auth_dialog_argv, "-i"); + + if (request->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) + g_ptr_array_add(auth_dialog_argv, "-r"); + + s = nm_vpn_plugin_info_lookup_property(plugin_info, "GNOME", "supports-hints"); + if (_nm_utils_ascii_str_to_bool(s, FALSE)) { + for (i = 0; request->hints[i]; i++) { + g_ptr_array_add(auth_dialog_argv, "-t"); + g_ptr_array_add(auth_dialog_argv, request->hints[i]); + } + } + + g_ptr_array_add(auth_dialog_argv, NULL); + if (!g_spawn_async_with_pipes(NULL, + (char **) auth_dialog_argv->pdata, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &auth_dialog_pid, + &auth_dialog_in_fd, + &auth_dialog_out_fd, + NULL, + &error)) { + g_warning("Failed to spawn the auth dialog%s\n", error->message); + return FALSE; + } + + auth_dialog_in = g_unix_output_stream_new(auth_dialog_in_fd, TRUE); + auth_dialog_out = g_unix_input_stream_new(auth_dialog_out_fd, TRUE); + + auth_dialog_request = g_string_new_len(NULL, 1024); + nm_setting_vpn_foreach_data_item(s_vpn, _add_data_item_to_string, auth_dialog_request); + nm_setting_vpn_foreach_secret(s_vpn, _add_secret_to_string, auth_dialog_request); + g_string_append(auth_dialog_request, "DONE\nQUIT\n"); + auth_dialog_request_len = auth_dialog_request->len; + auth_dialog_request_str = g_string_free(auth_dialog_request, FALSE); + + data = g_slice_new(AuthDialogData); + *data = (AuthDialogData){ + .auth_dialog_response = g_string_new_len(NULL, sizeof(data->read_buf)), + .auth_dialog_pid = auth_dialog_pid, + .request = request, + .secrets = g_ptr_array_ref(secrets), + .input_stream = auth_dialog_out, + .output_stream = auth_dialog_in, + }; + + g_output_stream_write_async(auth_dialog_in, + auth_dialog_request_str, + auth_dialog_request_len, + G_PRIORITY_DEFAULT, + request->cancellable, + _auth_dialog_write_done, + auth_dialog_request_str); + + g_input_stream_read_async(auth_dialog_out, + data->read_buf, + sizeof(data->read_buf), + G_PRIORITY_DEFAULT, + request->cancellable, + _auth_dialog_read_done, + data); + + return TRUE; } static void -request_secrets_from_ui (RequestData *request) +request_secrets_from_ui(RequestData *request) { - gs_unref_ptrarray GPtrArray *secrets = NULL; - gs_free_error GError *error = NULL; - NMSecretAgentSimplePrivate *priv; - NMSecretAgentSimpleSecret *secret; - const char *title; - gs_free char *msg = NULL; - - priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (request->self); - g_return_if_fail (priv->enabled); - - /* We only handle requests for connection with @path if set. */ - if (priv->path && !g_str_has_prefix (request->request_id, priv->path)) { - g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Request for %s secrets doesn't match path %s", - request->request_id, priv->path); - goto out_fail_error; - } - - secrets = g_ptr_array_new_with_free_func ((GDestroyNotify) _secret_real_free); - - if (nm_connection_is_type (request->connection, NM_SETTING_WIRELESS_SETTING_NAME)) { - NMSettingWireless *s_wireless; - GBytes *ssid; - char *ssid_utf8; - - s_wireless = nm_connection_get_setting_wireless (request->connection); - ssid = nm_setting_wireless_get_ssid (s_wireless); - ssid_utf8 = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - - title = _("Authentication required by wireless network"); - msg = g_strdup_printf (_("Passwords or encryption keys are required to access the wireless network '%s'."), ssid_utf8); - - if (!add_wireless_secrets (request, secrets)) - goto out_fail; - } else if (nm_connection_is_type (request->connection, NM_SETTING_WIRED_SETTING_NAME)) { - title = _("Wired 802.1X authentication"); - msg = g_strdup_printf (_("Secrets are required to access the wired network '%s'"), - nm_connection_get_id (request->connection)); - - if (!add_8021x_secrets (request, secrets)) - goto out_fail; - } else if (nm_connection_is_type (request->connection, NM_SETTING_PPPOE_SETTING_NAME)) { - title = _("DSL authentication"); - msg = g_strdup_printf (_("Secrets are required for the DSL connection '%s'"), - nm_connection_get_id (request->connection)); - - if (!add_pppoe_secrets (request, secrets)) - goto out_fail; - } else if (nm_connection_is_type (request->connection, NM_SETTING_GSM_SETTING_NAME)) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (request->connection); - - if (g_strv_contains (NM_CAST_STRV_CC (request->hints), NM_SETTING_GSM_PIN)) { - title = _("PIN code required"); - msg = g_strdup (_("PIN code is needed for the mobile broadband device")); - - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("PIN"), - NM_SETTING (s_gsm), - NM_SETTING_GSM_PIN); - g_ptr_array_add (secrets, secret); - } else { - title = _("Mobile broadband network password"); - msg = g_strdup_printf (_("A password is required to connect to '%s'."), - nm_connection_get_id (request->connection)); - - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_gsm), - NM_SETTING_GSM_PASSWORD); - g_ptr_array_add (secrets, secret); - } - } else if (nm_connection_is_type (request->connection, NM_SETTING_MACSEC_SETTING_NAME)) { - NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec (request->connection); - - msg = g_strdup_printf (_("Secrets are required to access the MACsec network '%s'"), - nm_connection_get_id (request->connection)); - - if (nm_setting_macsec_get_mode (s_macsec) == NM_SETTING_MACSEC_MODE_PSK) { - title = _("MACsec PSK authentication"); - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("MKA CAK"), - NM_SETTING (s_macsec), - NM_SETTING_MACSEC_MKA_CAK); - g_ptr_array_add (secrets, secret); - } else { - title = _("MACsec EAP authentication"); - if (!add_8021x_secrets (request, secrets)) - goto out_fail; - } - } else if (nm_connection_is_type (request->connection, NM_SETTING_WIREGUARD_SETTING_NAME)) { - title = _("WireGuard VPN secret"); - if (!add_wireguard_secrets (request, secrets, &msg, &error)) - goto out_fail_error; - } else if (nm_connection_is_type (request->connection, NM_SETTING_CDMA_SETTING_NAME)) { - NMSettingCdma *s_cdma = nm_connection_get_setting_cdma (request->connection); - - title = _("Mobile broadband network password"); - msg = g_strdup_printf (_("A password is required to connect to '%s'."), - nm_connection_get_id (request->connection)); - - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_cdma), - NM_SETTING_CDMA_PASSWORD); - g_ptr_array_add (secrets, secret); - } else if (nm_connection_is_type (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { - NMSetting *setting = NULL; - - setting = nm_connection_get_setting_by_name (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME); - if ( setting - && !nm_streq0 (nm_setting_bluetooth_get_connection_type (NM_SETTING_BLUETOOTH (setting)), NM_SETTING_BLUETOOTH_TYPE_NAP)) { - setting = nm_connection_get_setting_by_name (request->connection, NM_SETTING_GSM_SETTING_NAME); - if (!setting) - setting = nm_connection_get_setting_by_name (request->connection, NM_SETTING_CDMA_SETTING_NAME); - } - - if (!setting) - goto out_fail; - - title = _("Mobile broadband network password"); - msg = g_strdup_printf (_("A password is required to connect to '%s'."), - nm_connection_get_id (request->connection)); - - secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - setting, - "password"); - g_ptr_array_add (secrets, secret); - } else if (nm_connection_is_type (request->connection, NM_SETTING_VPN_SETTING_NAME)) { - title = _("VPN password required"); - - if (try_spawn_vpn_auth_helper (request, secrets)) { - /* This will emit REQUEST_SECRETS when ready */ - return; - } - - if (!add_vpn_secrets (request, secrets, &msg)) - goto out_fail; - if (!msg) { - msg = g_strdup_printf (_("A password is required to connect to '%s'."), - nm_connection_get_id (request->connection)); - } - } else - goto out_fail; - - if (secrets->len == 0) - goto out_fail; - - g_signal_emit (request->self, signals[REQUEST_SECRETS], 0, - request->request_id, title, msg, secrets); - return; + gs_unref_ptrarray GPtrArray *secrets = NULL; + gs_free_error GError * error = NULL; + NMSecretAgentSimplePrivate *priv; + NMSecretAgentSimpleSecret * secret; + const char * title; + gs_free char * msg = NULL; + + priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(request->self); + g_return_if_fail(priv->enabled); + + /* We only handle requests for connection with @path if set. */ + if (priv->path && !g_str_has_prefix(request->request_id, priv->path)) { + g_set_error(&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Request for %s secrets doesn't match path %s", + request->request_id, + priv->path); + goto out_fail_error; + } + + secrets = g_ptr_array_new_with_free_func((GDestroyNotify) _secret_real_free); + + if (nm_connection_is_type(request->connection, NM_SETTING_WIRELESS_SETTING_NAME)) { + NMSettingWireless *s_wireless; + GBytes * ssid; + char * ssid_utf8; + + s_wireless = nm_connection_get_setting_wireless(request->connection); + ssid = nm_setting_wireless_get_ssid(s_wireless); + ssid_utf8 = nm_utils_ssid_to_utf8(g_bytes_get_data(ssid, NULL), g_bytes_get_size(ssid)); + + title = _("Authentication required by wireless network"); + msg = g_strdup_printf( + _("Passwords or encryption keys are required to access the wireless network '%s'."), + ssid_utf8); + + if (!add_wireless_secrets(request, secrets)) + goto out_fail; + } else if (nm_connection_is_type(request->connection, NM_SETTING_WIRED_SETTING_NAME)) { + title = _("Wired 802.1X authentication"); + msg = g_strdup_printf(_("Secrets are required to access the wired network '%s'"), + nm_connection_get_id(request->connection)); + + if (!add_8021x_secrets(request, secrets)) + goto out_fail; + } else if (nm_connection_is_type(request->connection, NM_SETTING_PPPOE_SETTING_NAME)) { + title = _("DSL authentication"); + msg = g_strdup_printf(_("Secrets are required for the DSL connection '%s'"), + nm_connection_get_id(request->connection)); + + if (!add_pppoe_secrets(request, secrets)) + goto out_fail; + } else if (nm_connection_is_type(request->connection, NM_SETTING_GSM_SETTING_NAME)) { + NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(request->connection); + + if (g_strv_contains(NM_CAST_STRV_CC(request->hints), NM_SETTING_GSM_PIN)) { + title = _("PIN code required"); + msg = g_strdup(_("PIN code is needed for the mobile broadband device")); + + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("PIN"), + NM_SETTING(s_gsm), + NM_SETTING_GSM_PIN); + g_ptr_array_add(secrets, secret); + } else { + title = _("Mobile broadband network password"); + msg = g_strdup_printf(_("A password is required to connect to '%s'."), + nm_connection_get_id(request->connection)); + + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_gsm), + NM_SETTING_GSM_PASSWORD); + g_ptr_array_add(secrets, secret); + } + } else if (nm_connection_is_type(request->connection, NM_SETTING_MACSEC_SETTING_NAME)) { + NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec(request->connection); + + msg = g_strdup_printf(_("Secrets are required to access the MACsec network '%s'"), + nm_connection_get_id(request->connection)); + + if (nm_setting_macsec_get_mode(s_macsec) == NM_SETTING_MACSEC_MODE_PSK) { + title = _("MACsec PSK authentication"); + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("MKA CAK"), + NM_SETTING(s_macsec), + NM_SETTING_MACSEC_MKA_CAK); + g_ptr_array_add(secrets, secret); + } else { + title = _("MACsec EAP authentication"); + if (!add_8021x_secrets(request, secrets)) + goto out_fail; + } + } else if (nm_connection_is_type(request->connection, NM_SETTING_WIREGUARD_SETTING_NAME)) { + title = _("WireGuard VPN secret"); + if (!add_wireguard_secrets(request, secrets, &msg, &error)) + goto out_fail_error; + } else if (nm_connection_is_type(request->connection, NM_SETTING_CDMA_SETTING_NAME)) { + NMSettingCdma *s_cdma = nm_connection_get_setting_cdma(request->connection); + + title = _("Mobile broadband network password"); + msg = g_strdup_printf(_("A password is required to connect to '%s'."), + nm_connection_get_id(request->connection)); + + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING(s_cdma), + NM_SETTING_CDMA_PASSWORD); + g_ptr_array_add(secrets, secret); + } else if (nm_connection_is_type(request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { + NMSetting *setting = NULL; + + setting = nm_connection_get_setting_by_name(request->connection, + NM_SETTING_BLUETOOTH_SETTING_NAME); + if (setting + && !nm_streq0(nm_setting_bluetooth_get_connection_type(NM_SETTING_BLUETOOTH(setting)), + NM_SETTING_BLUETOOTH_TYPE_NAP)) { + setting = + nm_connection_get_setting_by_name(request->connection, NM_SETTING_GSM_SETTING_NAME); + if (!setting) + setting = nm_connection_get_setting_by_name(request->connection, + NM_SETTING_CDMA_SETTING_NAME); + } + + if (!setting) + goto out_fail; + + title = _("Mobile broadband network password"); + msg = g_strdup_printf(_("A password is required to connect to '%s'."), + nm_connection_get_id(request->connection)); + + secret = _secret_real_new_plain(NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + setting, + "password"); + g_ptr_array_add(secrets, secret); + } else if (nm_connection_is_type(request->connection, NM_SETTING_VPN_SETTING_NAME)) { + title = _("VPN password required"); + + if (try_spawn_vpn_auth_helper(request, secrets)) { + /* This will emit REQUEST_SECRETS when ready */ + return; + } + + if (!add_vpn_secrets(request, secrets, &msg)) + goto out_fail; + if (!msg) { + msg = g_strdup_printf(_("A password is required to connect to '%s'."), + nm_connection_get_id(request->connection)); + } + } else + goto out_fail; + + if (secrets->len == 0) + goto out_fail; + + g_signal_emit(request->self, + signals[REQUEST_SECRETS], + 0, + request->request_id, + title, + msg, + secrets); + return; out_fail: - g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Cannot service a secrets request %s for a %s connection", - request->request_id, - nm_connection_get_connection_type (request->connection)); + g_set_error(&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Cannot service a secrets request %s for a %s connection", + request->request_id, + nm_connection_get_connection_type(request->connection)); out_fail_error: - _request_data_complete (request, NULL, error, NULL); - + _request_data_complete(request, NULL, error, NULL); } static void -get_secrets (NMSecretAgentOld *agent, - NMConnection *connection, - const char *connection_path, - const char *setting_name, - const char **hints, - NMSecretAgentGetSecretsFlags flags, - NMSecretAgentOldGetSecretsFunc callback, - gpointer callback_data) +get_secrets(NMSecretAgentOld * agent, + NMConnection * connection, + const char * connection_path, + const char * setting_name, + const char ** hints, + NMSecretAgentGetSecretsFlags flags, + NMSecretAgentOldGetSecretsFunc callback, + gpointer callback_data) { - NMSecretAgentSimple *self = NM_SECRET_AGENT_SIMPLE (agent); - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self); - RequestData *request; - gs_free_error GError *error = NULL; - gs_free char *request_id = NULL; - const char *request_id_setting_name; - - request_id = g_strdup_printf ("%s/%s", connection_path, setting_name); - - if (g_hash_table_contains (priv->requests, &request_id)) { - /* We already have a request pending for this (connection, setting) */ - error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Request for %s secrets already pending", request_id); - callback (agent, connection, NULL, error, callback_data); - return; - } - - if (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION)) { - /* We don't do stored passwords */ - error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_NO_SECRETS, - "Stored passwords not supported"); - callback (agent, connection, NULL, error, callback_data); - return; - } - - nm_assert (g_str_has_suffix (request_id, setting_name)); - request_id_setting_name = &request_id[strlen (request_id) - strlen (setting_name)]; - nm_assert (nm_streq (request_id_setting_name, setting_name)); - - request = g_slice_new (RequestData); - *request = (RequestData) { - .self = self, - .connection = g_object_ref (connection), - .setting_name = request_id_setting_name, - .hints = g_strdupv ((char **) hints), - .callback = callback, - .callback_data = callback_data, - .request_id = g_steal_pointer (&request_id), - .flags = flags, - .cancellable = g_cancellable_new (), - }; - g_hash_table_add (priv->requests, request); - - if (priv->enabled) - request_secrets_from_ui (request); + NMSecretAgentSimple * self = NM_SECRET_AGENT_SIMPLE(agent); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self); + RequestData * request; + gs_free_error GError *error = NULL; + gs_free char * request_id = NULL; + const char * request_id_setting_name; + + request_id = g_strdup_printf("%s/%s", connection_path, setting_name); + + if (g_hash_table_contains(priv->requests, &request_id)) { + /* We already have a request pending for this (connection, setting) */ + error = g_error_new(NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Request for %s secrets already pending", + request_id); + callback(agent, connection, NULL, error, callback_data); + return; + } + + if (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION)) { + /* We don't do stored passwords */ + error = g_error_new(NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NO_SECRETS, + "Stored passwords not supported"); + callback(agent, connection, NULL, error, callback_data); + return; + } + + nm_assert(g_str_has_suffix(request_id, setting_name)); + request_id_setting_name = &request_id[strlen(request_id) - strlen(setting_name)]; + nm_assert(nm_streq(request_id_setting_name, setting_name)); + + request = g_slice_new(RequestData); + *request = (RequestData){ + .self = self, + .connection = g_object_ref(connection), + .setting_name = request_id_setting_name, + .hints = g_strdupv((char **) hints), + .callback = callback, + .callback_data = callback_data, + .request_id = g_steal_pointer(&request_id), + .flags = flags, + .cancellable = g_cancellable_new(), + }; + g_hash_table_add(priv->requests, request); + + if (priv->enabled) + request_secrets_from_ui(request); } /** @@ -1068,150 +1093,158 @@ get_secrets (NMSecretAgentOld *agent, * cancelled the request, @secrets should be NULL. */ void -nm_secret_agent_simple_response (NMSecretAgentSimple *self, - const char *request_id, - GPtrArray *secrets) +nm_secret_agent_simple_response(NMSecretAgentSimple *self, + const char * request_id, + GPtrArray * secrets) { - NMSecretAgentSimplePrivate *priv; - RequestData *request; - gs_unref_variant GVariant *secrets_dict = NULL; - gs_free_error GError *error = NULL; - int i; - - g_return_if_fail (NM_IS_SECRET_AGENT_SIMPLE (self)); - - priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self); - request = g_hash_table_lookup (priv->requests, &request_id); - g_return_if_fail (request != NULL); - - if (secrets) { - GVariantBuilder conn_builder, *setting_builder; - GVariantBuilder vpn_secrets_builder; - GVariantBuilder wg_secrets_builder; - GVariantBuilder wg_peer_builder; - GHashTable *settings; - GHashTableIter iter; - const char *name; - gboolean has_vpn = FALSE; - gboolean has_wg = FALSE; - - settings = g_hash_table_new_full (nm_str_hash, - g_str_equal, - NULL, - (GDestroyNotify) g_variant_builder_unref); - for (i = 0; i < secrets->len; i++) { - SecretReal *secret = secrets->pdata[i]; - - setting_builder = g_hash_table_lookup (settings, nm_setting_get_name (secret->setting)); - if (!setting_builder) { - setting_builder = g_variant_builder_new (NM_VARIANT_TYPE_SETTING); - g_hash_table_insert (settings, (char *) nm_setting_get_name (secret->setting), - setting_builder); - } - - switch (secret->base.secret_type) { - case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY: - case NM_SECRET_AGENT_SECRET_TYPE_SECRET: - g_variant_builder_add (setting_builder, "{sv}", - secret->property, - g_variant_new_string (secret->base.value)); - break; - case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET: - if (!has_vpn) { - g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); - has_vpn = TRUE; - } - g_variant_builder_add (&vpn_secrets_builder, "{ss}", - secret->property, secret->base.value); - break; - case NM_SECRET_AGENT_SECRET_TYPE_WIREGUARD_PEER_PSK: - if (!has_wg) { - g_variant_builder_init (&wg_secrets_builder, G_VARIANT_TYPE ("aa{sv}")); - has_wg = TRUE; - } - g_variant_builder_init (&wg_peer_builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&wg_peer_builder, "{sv}", - NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY, g_variant_new_string (secret->property)); - g_variant_builder_add (&wg_peer_builder, "{sv}", - NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, g_variant_new_string (secret->base.value)); - g_variant_builder_add (&wg_secrets_builder, "a{sv}", - &wg_peer_builder); - break; - } - } - - if (has_vpn) { - g_variant_builder_add (setting_builder, "{sv}", - "secrets", - g_variant_builder_end (&vpn_secrets_builder)); - } - - if (has_wg) { - g_variant_builder_add (setting_builder, "{sv}", - NM_SETTING_WIREGUARD_PEERS, - g_variant_builder_end (&wg_secrets_builder)); - } - - g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION); - g_hash_table_iter_init (&iter, settings); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting_builder)) - g_variant_builder_add (&conn_builder, "{sa{sv}}", name, setting_builder); - secrets_dict = g_variant_ref_sink (g_variant_builder_end (&conn_builder)); - g_hash_table_destroy (settings); - } else { - error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED, - "User cancelled"); - } - - _request_data_complete (request, secrets_dict, error, NULL); + NMSecretAgentSimplePrivate *priv; + RequestData * request; + gs_unref_variant GVariant *secrets_dict = NULL; + gs_free_error GError *error = NULL; + int i; + + g_return_if_fail(NM_IS_SECRET_AGENT_SIMPLE(self)); + + priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self); + request = g_hash_table_lookup(priv->requests, &request_id); + g_return_if_fail(request != NULL); + + if (secrets) { + GVariantBuilder conn_builder, *setting_builder; + GVariantBuilder vpn_secrets_builder; + GVariantBuilder wg_secrets_builder; + GVariantBuilder wg_peer_builder; + GHashTable * settings; + GHashTableIter iter; + const char * name; + gboolean has_vpn = FALSE; + gboolean has_wg = FALSE; + + settings = g_hash_table_new_full(nm_str_hash, + g_str_equal, + NULL, + (GDestroyNotify) g_variant_builder_unref); + for (i = 0; i < secrets->len; i++) { + SecretReal *secret = secrets->pdata[i]; + + setting_builder = g_hash_table_lookup(settings, nm_setting_get_name(secret->setting)); + if (!setting_builder) { + setting_builder = g_variant_builder_new(NM_VARIANT_TYPE_SETTING); + g_hash_table_insert(settings, + (char *) nm_setting_get_name(secret->setting), + setting_builder); + } + + switch (secret->base.secret_type) { + case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY: + case NM_SECRET_AGENT_SECRET_TYPE_SECRET: + g_variant_builder_add(setting_builder, + "{sv}", + secret->property, + g_variant_new_string(secret->base.value)); + break; + case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET: + if (!has_vpn) { + g_variant_builder_init(&vpn_secrets_builder, G_VARIANT_TYPE("a{ss}")); + has_vpn = TRUE; + } + g_variant_builder_add(&vpn_secrets_builder, + "{ss}", + secret->property, + secret->base.value); + break; + case NM_SECRET_AGENT_SECRET_TYPE_WIREGUARD_PEER_PSK: + if (!has_wg) { + g_variant_builder_init(&wg_secrets_builder, G_VARIANT_TYPE("aa{sv}")); + has_wg = TRUE; + } + g_variant_builder_init(&wg_peer_builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&wg_peer_builder, + "{sv}", + NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY, + g_variant_new_string(secret->property)); + g_variant_builder_add(&wg_peer_builder, + "{sv}", + NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, + g_variant_new_string(secret->base.value)); + g_variant_builder_add(&wg_secrets_builder, "a{sv}", &wg_peer_builder); + break; + } + } + + if (has_vpn) { + g_variant_builder_add(setting_builder, + "{sv}", + "secrets", + g_variant_builder_end(&vpn_secrets_builder)); + } + + if (has_wg) { + g_variant_builder_add(setting_builder, + "{sv}", + NM_SETTING_WIREGUARD_PEERS, + g_variant_builder_end(&wg_secrets_builder)); + } + + g_variant_builder_init(&conn_builder, NM_VARIANT_TYPE_CONNECTION); + g_hash_table_iter_init(&iter, settings); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &setting_builder)) + g_variant_builder_add(&conn_builder, "{sa{sv}}", name, setting_builder); + secrets_dict = g_variant_ref_sink(g_variant_builder_end(&conn_builder)); + g_hash_table_destroy(settings); + } else { + error = g_error_new(NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + "User cancelled"); + } + + _request_data_complete(request, secrets_dict, error, NULL); } static void -cancel_get_secrets (NMSecretAgentOld *agent, - const char *connection_path, - const char *setting_name) +cancel_get_secrets(NMSecretAgentOld *agent, const char *connection_path, const char *setting_name) { - NMSecretAgentSimple *self = NM_SECRET_AGENT_SIMPLE (agent); - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - gs_free char *request_id = NULL; - RequestData *request; - - request_id = g_strdup_printf ("%s/%s", connection_path, setting_name); - request = g_hash_table_lookup (priv->requests, &request_id); - if (!request) { - /* this is really a bug of the caller (or us?). We cannot invoke a callback, - * hence the caller cannot cleanup the request. */ - g_return_if_reached (); - } - - g_set_error (&error, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_AGENT_CANCELED, - "The secret agent is going away"); - _request_data_complete (request, NULL, error, NULL); + NMSecretAgentSimple * self = NM_SECRET_AGENT_SIMPLE(agent); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self); + gs_free_error GError *error = NULL; + gs_free char * request_id = NULL; + RequestData * request; + + request_id = g_strdup_printf("%s/%s", connection_path, setting_name); + request = g_hash_table_lookup(priv->requests, &request_id); + if (!request) { + /* this is really a bug of the caller (or us?). We cannot invoke a callback, + * hence the caller cannot cleanup the request. */ + g_return_if_reached(); + } + + g_set_error(&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_AGENT_CANCELED, + "The secret agent is going away"); + _request_data_complete(request, NULL, error, NULL); } static void -save_secrets (NMSecretAgentOld *agent, - NMConnection *connection, - const char *connection_path, - NMSecretAgentOldSaveSecretsFunc callback, - gpointer callback_data) +save_secrets(NMSecretAgentOld * agent, + NMConnection * connection, + const char * connection_path, + NMSecretAgentOldSaveSecretsFunc callback, + gpointer callback_data) { - /* We don't support secret storage */ - callback (agent, connection, NULL, callback_data); + /* We don't support secret storage */ + callback(agent, connection, NULL, callback_data); } static void -delete_secrets (NMSecretAgentOld *agent, - NMConnection *connection, - const char *connection_path, - NMSecretAgentOldDeleteSecretsFunc callback, - gpointer callback_data) +delete_secrets(NMSecretAgentOld * agent, + NMConnection * connection, + const char * connection_path, + NMSecretAgentOldDeleteSecretsFunc callback, + gpointer callback_data) { - /* We don't support secret storage, so there's nothing to delete. */ - callback (agent, connection, NULL, callback_data); + /* We don't support secret storage, so there's nothing to delete. */ + callback(agent, connection, NULL, callback_data); } /** @@ -1225,44 +1258,43 @@ delete_secrets (NMSecretAgentOld *agent, * @path. */ void -nm_secret_agent_simple_enable (NMSecretAgentSimple *self, const char *path) +nm_secret_agent_simple_enable(NMSecretAgentSimple *self, const char *path) { - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self); - gs_free RequestData **requests = NULL; - gsize i; - gs_free char *path_full = NULL; - - /* The path is only used to match a request_id with the current - * connection. Since the request_id is "${CONNECTION_PATH}/${SETTING}", - * add a trailing '/' to the path to match the full connection path. - */ - path_full = path ? g_strdup_printf ("%s/", path) : NULL; - - if (!nm_streq0 (path_full, priv->path)) { - g_free (priv->path); - priv->path = g_steal_pointer (&path_full); - } - - if (priv->enabled) - return; - priv->enabled = TRUE; - - /* Service pending secret requests. */ - requests = (RequestData **) g_hash_table_get_keys_as_array (priv->requests, NULL); - for (i = 0; requests[i]; i++) - request_secrets_from_ui (requests[i]); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(self); + gs_free RequestData **requests = NULL; + gsize i; + gs_free char * path_full = NULL; + + /* The path is only used to match a request_id with the current + * connection. Since the request_id is "${CONNECTION_PATH}/${SETTING}", + * add a trailing '/' to the path to match the full connection path. + */ + path_full = path ? g_strdup_printf("%s/", path) : NULL; + + if (!nm_streq0(path_full, priv->path)) { + g_free(priv->path); + priv->path = g_steal_pointer(&path_full); + } + + if (priv->enabled) + return; + priv->enabled = TRUE; + + /* Service pending secret requests. */ + requests = (RequestData **) g_hash_table_get_keys_as_array(priv->requests, NULL); + for (i = 0; requests[i]; i++) + request_secrets_from_ui(requests[i]); } /*****************************************************************************/ static void -nm_secret_agent_simple_init (NMSecretAgentSimple *agent) +nm_secret_agent_simple_init(NMSecretAgentSimple *agent) { - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (agent); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(agent); - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (RequestData, request_id) == 0); - priv->requests = g_hash_table_new_full (nm_pstr_hash, nm_pstr_equal, - NULL, _request_data_free); + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(RequestData, request_id) == 0); + priv->requests = g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, NULL, _request_data_free); } /** @@ -1276,87 +1308,95 @@ nm_secret_agent_simple_init (NMSecretAgentSimple *agent) * or %NULL in case of a failure. */ NMSecretAgentSimple * -nm_secret_agent_simple_new (const char *name) +nm_secret_agent_simple_new(const char *name) { - return g_initable_new (NM_TYPE_SECRET_AGENT_SIMPLE, NULL, NULL, - NM_SECRET_AGENT_OLD_IDENTIFIER, name, - NM_SECRET_AGENT_OLD_CAPABILITIES, NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, - NULL); + return g_initable_new(NM_TYPE_SECRET_AGENT_SIMPLE, + NULL, + NULL, + NM_SECRET_AGENT_OLD_IDENTIFIER, + name, + NM_SECRET_AGENT_OLD_CAPABILITIES, + NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, + NULL); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (object); - gs_free_error GError *error = NULL; - GHashTableIter iter; - RequestData *request; - - g_hash_table_iter_init (&iter, priv->requests); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &request)) { - if (!error) - nm_utils_error_set_cancelled (&error, TRUE, "NMSecretAgentSimple"); - _request_data_complete (request, NULL, error, &iter); - } - - G_OBJECT_CLASS (nm_secret_agent_simple_parent_class)->dispose (object); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(object); + gs_free_error GError *error = NULL; + GHashTableIter iter; + RequestData * request; + + g_hash_table_iter_init(&iter, priv->requests); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &request)) { + if (!error) + nm_utils_error_set_cancelled(&error, TRUE, "NMSecretAgentSimple"); + _request_data_complete(request, NULL, error, &iter); + } + + G_OBJECT_CLASS(nm_secret_agent_simple_parent_class)->dispose(object); } static void -finalize (GObject *object) +finalize(GObject *object) { - NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (object); + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE(object); - g_hash_table_destroy (priv->requests); + g_hash_table_destroy(priv->requests); - g_free (priv->path); + g_free(priv->path); - G_OBJECT_CLASS (nm_secret_agent_simple_parent_class)->finalize (object); + G_OBJECT_CLASS(nm_secret_agent_simple_parent_class)->finalize(object); } void -nm_secret_agent_simple_class_init (NMSecretAgentSimpleClass *klass) +nm_secret_agent_simple_class_init(NMSecretAgentSimpleClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMSecretAgentOldClass *agent_class = NM_SECRET_AGENT_OLD_CLASS (klass); - - object_class->dispose = dispose; - object_class->finalize = finalize; - - agent_class->get_secrets = get_secrets; - agent_class->cancel_get_secrets = cancel_get_secrets; - agent_class->save_secrets = save_secrets; - agent_class->delete_secrets = delete_secrets; - - /** - * NMSecretAgentSimple::request-secrets: - * @agent: the #NMSecretAgentSimple - * @request_id: request ID, to eventually pass to - * nm_secret_agent_simple_response(). - * @title: a title for the password dialog - * @prompt: a prompt message for the password dialog - * @secrets: (element-type #NMSecretAgentSimpleSecret): array of secrets - * being requested. - * - * Emitted when the agent requires secrets from the user. - * - * The application should ask user for the secrets. For example, - * nmtui should create a password dialog (#NmtPasswordDialog) - * with the given title and prompt, and an entry for each - * element of @secrets. If any of the secrets already have a - * <literal>value</literal> filled in, the corresponding entry - * should be initialized to that value. - * - * When the dialog is complete, the app must call - * nm_secret_agent_simple_response() with the results. - */ - signals[REQUEST_SECRETS] = g_signal_new (NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, - G_TYPE_FROM_CLASS (klass), - 0, 0, NULL, NULL, NULL, - G_TYPE_NONE, - 4, - G_TYPE_STRING, /* request_id */ - G_TYPE_STRING, /* title */ - G_TYPE_STRING, /* prompt */ - G_TYPE_PTR_ARRAY); + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSecretAgentOldClass *agent_class = NM_SECRET_AGENT_OLD_CLASS(klass); + + object_class->dispose = dispose; + object_class->finalize = finalize; + + agent_class->get_secrets = get_secrets; + agent_class->cancel_get_secrets = cancel_get_secrets; + agent_class->save_secrets = save_secrets; + agent_class->delete_secrets = delete_secrets; + + /** + * NMSecretAgentSimple::request-secrets: + * @agent: the #NMSecretAgentSimple + * @request_id: request ID, to eventually pass to + * nm_secret_agent_simple_response(). + * @title: a title for the password dialog + * @prompt: a prompt message for the password dialog + * @secrets: (element-type #NMSecretAgentSimpleSecret): array of secrets + * being requested. + * + * Emitted when the agent requires secrets from the user. + * + * The application should ask user for the secrets. For example, + * nmtui should create a password dialog (#NmtPasswordDialog) + * with the given title and prompt, and an entry for each + * element of @secrets. If any of the secrets already have a + * <literal>value</literal> filled in, the corresponding entry + * should be initialized to that value. + * + * When the dialog is complete, the app must call + * nm_secret_agent_simple_response() with the results. + */ + signals[REQUEST_SECRETS] = g_signal_new(NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, + G_TYPE_FROM_CLASS(klass), + 0, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 4, + G_TYPE_STRING, /* request_id */ + G_TYPE_STRING, /* title */ + G_TYPE_STRING, /* prompt */ + G_TYPE_PTR_ARRAY); } |