diff options
author | Thomas Haller <thaller@redhat.com> | 2017-11-23 14:51:16 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-11-23 14:51:21 +0100 |
commit | ca26d1ae07a4e8a7036051301d0103ab0822fd44 (patch) | |
tree | 77b91d60dc25cb9cd83d0fea0905d307535b3c41 | |
parent | 8649fcf02ad0646ebbf2daea2ededd0ee4a5745a (diff) | |
parent | 272439cb2077a889485dd195bb6b99ca91d3e3bf (diff) | |
download | NetworkManager-ca26d1ae07a4e8a7036051301d0103ab0822fd44.tar.gz |
all: merge branch 'th/vpn-secrets-bgo790655'
https://bugzilla.gnome.org/show_bug.cgi?id=790655
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | clients/cli/agent.c | 2 | ||||
-rw-r--r-- | clients/cli/common.c | 58 | ||||
-rw-r--r-- | clients/common/nm-secret-agent-simple.c | 220 | ||||
-rw-r--r-- | clients/common/nm-secret-agent-simple.h | 20 | ||||
-rw-r--r-- | clients/tui/nmt-password-dialog.c | 4 | ||||
-rw-r--r-- | clients/tui/nmtui-connect.c | 43 | ||||
-rw-r--r-- | libnm-core/nm-setting-vpn.c | 149 | ||||
-rw-r--r-- | libnm-core/nm-setting-vpn.h | 8 | ||||
-rw-r--r-- | libnm-core/nm-setting.c | 25 | ||||
-rw-r--r-- | libnm/libnm.ver | 2 | ||||
-rw-r--r-- | libnm/nm-vpn-plugin-old.c | 123 | ||||
-rw-r--r-- | libnm/nm-vpn-service-plugin.c | 74 | ||||
-rw-r--r-- | shared/nm-utils/nm-compat.c | 88 | ||||
-rw-r--r-- | shared/nm-utils/nm-compat.h | 53 | ||||
-rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 22 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 8 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 8 | ||||
-rw-r--r-- | src/settings/nm-agent-manager.c | 2 | ||||
-rw-r--r-- | src/settings/nm-agent-manager.h | 2 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 2 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.h | 2 | ||||
-rw-r--r-- | src/vpn/nm-vpn-connection.c | 32 |
23 files changed, 544 insertions, 406 deletions
diff --git a/Makefile.am b/Makefile.am index ceba78422c..3f60ea5b3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1066,6 +1066,7 @@ libnm_tests_test_remote_settings_client_CPPFLAGS = $(libnm_tests_cppflags) libnm_tests_test_secret_agent_CPPFLAGS = $(libnm_tests_cppflags) libnm_tests_test_general_SOURCES = \ + shared/nm-utils/nm-compat.c \ libnm/tests/test-general.c libnm_tests_test_nm_client_SOURCES = \ @@ -4565,6 +4566,8 @@ EXTRA_DIST += \ shared/nm-utils/c-list-util.c \ shared/nm-utils/c-list-util.h \ shared/nm-utils/gsystem-local-alloc.h \ + shared/nm-utils/nm-compat.c \ + shared/nm-utils/nm-compat.h \ shared/nm-utils/nm-glib.h \ shared/nm-utils/nm-jansson.h \ shared/nm-utils/nm-obj.h \ diff --git a/clients/cli/agent.c b/clients/cli/agent.c index 656a58511d..2088648aa0 100644 --- a/clients/cli/agent.c +++ b/clients/cli/agent.c @@ -104,7 +104,7 @@ get_secrets_from_user (const char *request_id, rl_startup_hook = set_deftext; pre_input_deftext = g_strdup (secret->value); } - pwd = nmc_readline ("%s (%s): ", secret->name, secret->prop_name); + pwd = nmc_readline ("%s (%s): ", secret->pretty_name, secret->entry_id); /* No password provided, cancel the secrets. */ if (!pwd) diff --git a/clients/cli/common.c b/clients/cli/common.c index 4f369f458b..f785e2c568 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -531,10 +531,10 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets) { GError *error = NULL; NMSettingVpn *s_vpn; - const char *vpn_type, *gw, *port; - char *cookie = NULL; - char *gateway = NULL; - char *gwcert = NULL; + const char *gw, *port; + gs_free char *cookie = NULL; + gs_free char *gateway = NULL; + gs_free char *gwcert = NULL; int status = 0; int i; gboolean ret; @@ -546,8 +546,7 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets) return FALSE; s_vpn = nm_connection_get_setting_vpn (connection); - vpn_type = nm_setting_vpn_get_service_type (s_vpn); - if (g_strcmp0 (vpn_type, NM_DBUS_INTERFACE ".openconnect")) + if (!nm_streq0 (nm_setting_vpn_get_service_type (s_vpn), NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT)) return FALSE; /* Get gateway and port */ @@ -570,34 +569,31 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets) /* Append port to the host value */ if (gateway && port) { - char *tmp = gateway; - gateway = g_strdup_printf ("%s%s", gateway, port); - g_free (tmp); + gs_free char *tmp = gateway; + + gateway = g_strdup_printf ("%s%s", tmp, port); } /* Fill secrets to the array */ for (i = 0; i < secrets->len; i++) { NMSecretAgentSimpleSecret *secret = secrets->pdata[i]; - if (!g_strcmp0 (secret->vpn_type, vpn_type)) { - if (!g_strcmp0 (secret->vpn_property, "cookie")) { - g_free (secret->value); - secret->value = cookie; - cookie = NULL; - } else if (!g_strcmp0 (secret->vpn_property, "gateway")) { - g_free (secret->value); - secret->value = gateway; - gateway = NULL; - } else if (!g_strcmp0 (secret->vpn_property, "gwcert")) { - g_free (secret->value); - secret->value = gwcert; - gwcert = NULL; - } + if (secret->secret_type != NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET) + continue; + if (!nm_streq0 (secret->vpn_type, NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT)) + continue; + + if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "cookie")) { + g_free (secret->value); + secret->value = g_steal_pointer (&cookie); + } else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gateway")) { + g_free (secret->value); + secret->value = g_steal_pointer (&gateway); + } else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gwcert")) { + g_free (secret->value); + secret->value = g_steal_pointer (&gwcert); } } - g_free (cookie); - g_free (gateway); - g_free (gwcert); return TRUE; } @@ -624,7 +620,7 @@ get_secrets_from_user (const char *request_id, /* First try to find the password in provided passwords file, * then ask user. */ - if (pwds_hash && (pwd = g_hash_table_lookup (pwds_hash, secret->prop_name))) { + if (pwds_hash && (pwd = g_hash_table_lookup (pwds_hash, secret->entry_id))) { pwd = g_strdup (pwd); } else { if (ask) { @@ -640,8 +636,10 @@ get_secrets_from_user (const char *request_id, } if (msg) g_print ("%s\n", msg); - pwd = nmc_readline_echo (secret->password ? echo_on : TRUE, - "%s (%s): ", secret->name, secret->prop_name); + pwd = nmc_readline_echo (secret->is_secret + ? echo_on + : TRUE, + "%s (%s): ", secret->pretty_name, secret->entry_id); if (!pwd) pwd = g_strdup (""); } else { @@ -649,7 +647,7 @@ get_secrets_from_user (const char *request_id, g_print ("%s\n", msg); g_printerr (_("Warning: password for '%s' not given in 'passwd-file' " "and nmcli cannot ask without '--ask' option.\n"), - secret->prop_name); + secret->entry_id); } } /* No password provided, cancel the secrets. */ diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 21aaf99540..f3b377c12c 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -147,7 +147,6 @@ strv_has (gchar **haystack, typedef struct { NMSecretAgentSimpleSecret base; - NMSetting *setting; char *property; } NMSecretAgentSimpleSecretReal; @@ -157,11 +156,10 @@ nm_secret_agent_simple_secret_free (NMSecretAgentSimpleSecret *secret) { NMSecretAgentSimpleSecretReal *real = (NMSecretAgentSimpleSecretReal *)secret; - g_free (secret->name); - g_free (secret->prop_name); + g_free ((char *) secret->pretty_name); + g_free ((char *) secret->entry_id); g_free (secret->value); - g_free (secret->vpn_property); - g_free (secret->vpn_type); + g_free ((char *) secret->vpn_type); g_free (real->property); g_clear_object (&real->setting); @@ -169,33 +167,45 @@ nm_secret_agent_simple_secret_free (NMSecretAgentSimpleSecret *secret) } static NMSecretAgentSimpleSecret * -nm_secret_agent_simple_secret_new (const char *name, +nm_secret_agent_simple_secret_new (NMSecretAgentSecretType secret_type, + const char *pretty_name, NMSetting *setting, const char *property, - const char *vpn_property, - const char *vpn_type, - gboolean password) + const char *vpn_type) { NMSecretAgentSimpleSecretReal *real; + const char *vpn_prefix; + const char *value; + + nm_assert (property); + nm_assert (NM_IS_SETTING (setting)); real = g_slice_new0 (NMSecretAgentSimpleSecretReal); - real->base.name = g_strdup (name); - real->base.prop_name = vpn_property ? - g_strdup_printf ("%s.%s.%s", nm_setting_get_name (setting), property, vpn_property) : - g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property); - real->base.vpn_property = g_strdup (vpn_property); - real->base.vpn_type = g_strdup (vpn_type); - real->base.password = password; - - if (setting) { - real->setting = g_object_ref (setting); - real->property = g_strdup (property); - - if (vpn_property) - real->base.value = g_strdup (nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), vpn_property)); - else - g_object_get (setting, property, &real->base.value, NULL); + *((NMSecretAgentSecretType *) &real->base.secret_type) = secret_type; + real->setting = g_object_ref (setting); + real->base.pretty_name = g_strdup (pretty_name); + real->property = g_strdup (property); + switch (secret_type) { + case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY: + case NM_SECRET_AGENT_SECRET_TYPE_SECRET: + nm_assert (!vpn_type); + 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)); + real->base.entry_id = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property); + g_object_get (setting, property, &real->base.value, NULL); + real->base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY); + break; + case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET: + vpn_prefix = NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET; + value = nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), property); + real->base.entry_id = g_strdup_printf ("%s%s", vpn_prefix, property); + nm_assert (vpn_type); + real->base.vpn_type = g_strdup (vpn_type); + real->base.value = g_strdup (value); + real->base.is_secret = TRUE; + break; } + nm_assert (real->base.entry_id); return &real->base; } @@ -220,37 +230,33 @@ add_8021x_secrets (NMSecretAgentSimpleRequest *request, * is not visible here since we only care about phase2 authentication * (and don't even care of which one) */ - secret = nm_secret_agent_simple_secret_new (_("Username"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), NM_SETTING (s_8021x), NM_SETTING_802_1X_IDENTITY, - NULL, - NULL, - FALSE); + NULL); g_ptr_array_add (secrets, secret); - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_8021x), NM_SETTING_802_1X_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); return TRUE; } if (!strcmp (eap_method, "tls")) { - secret = nm_secret_agent_simple_secret_new (_("Identity"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Identity"), NM_SETTING (s_8021x), NM_SETTING_802_1X_IDENTITY, - NULL, - NULL, - FALSE); + NULL); g_ptr_array_add (secrets, secret); - secret = nm_secret_agent_simple_secret_new (_("Private key password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Private key password"), NM_SETTING (s_8021x), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); return TRUE; } @@ -270,12 +276,11 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, return FALSE; if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) { - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_wsec), NM_SETTING_WIRELESS_SECURITY_PSK, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); return TRUE; } @@ -286,12 +291,11 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, index = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec); key = g_strdup_printf ("wep-key%d", index); - secret = nm_secret_agent_simple_secret_new (_("Key"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Key"), NM_SETTING (s_wsec), key, - NULL, - NULL, - TRUE); + NULL); g_free (key); g_ptr_array_add (secrets, secret); @@ -300,12 +304,11 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, if (!strcmp (key_mgmt, "iee8021x")) { if (!g_strcmp0 (nm_setting_wireless_security_get_auth_alg (s_wsec), "leap")) { - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_wsec), NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); return TRUE; } else @@ -325,26 +328,23 @@ add_pppoe_secrets (NMSecretAgentSimpleRequest *request, NMSettingPppoe *s_pppoe = nm_connection_get_setting_pppoe (request->connection); NMSecretAgentSimpleSecret *secret; - secret = nm_secret_agent_simple_secret_new (_("Username"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_USERNAME, - NULL, - NULL, - FALSE); + NULL); g_ptr_array_add (secrets, secret); - secret = nm_secret_agent_simple_secret_new (_("Service"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Service"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_SERVICE, - NULL, - NULL, - FALSE); + NULL); g_ptr_array_add (secrets, secret); - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); return TRUE; } @@ -369,23 +369,27 @@ add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name NMSettingSecretFlags flags; int i; - /* Check for duplicates */ - for (i = 0; i < secrets->len; i++) { - secret = secrets->pdata[i]; - - if (g_strcmp0 (secret->vpn_property, name) == 0) - return; - } - flags = get_vpn_secret_flags (s_vpn, name); if ( flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) { - secret = nm_secret_agent_simple_secret_new (ui_name, + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, + ui_name, NM_SETTING (s_vpn), - NM_SETTING_VPN_SECRETS, name, - nm_setting_vpn_get_service_type (s_vpn), - TRUE); + 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)) { + nm_secret_agent_simple_secret_free (secret); + return; + } + } + g_ptr_array_add (secrets, secret); } } @@ -489,24 +493,22 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) title = _("PIN code required"); msg = g_strdup (_("PIN code is needed for the mobile broadband device")); - secret = nm_secret_agent_simple_secret_new (_("PIN"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("PIN"), NM_SETTING (s_gsm), NM_SETTING_GSM_PIN, - NULL, - NULL, - FALSE); + NULL); 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 = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_gsm), NM_SETTING_GSM_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); } } else if (nm_connection_is_type (request->connection, NM_SETTING_MACSEC_SETTING_NAME)) { @@ -517,12 +519,11 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) if (nm_setting_macsec_get_mode (s_macsec) == NM_SETTING_MACSEC_MODE_PSK) { title = _("MACsec PSK authentication"); - secret = nm_secret_agent_simple_secret_new (_("MKA CAK"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("MKA CAK"), NM_SETTING (s_macsec), NM_SETTING_MACSEC_MKA_CAK, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); } else { title = _("MACsec EAP authentication"); @@ -535,12 +536,11 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) msg = g_strdup_printf (_("A password is required to connect to '%s'."), nm_connection_get_id (request->connection)); - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), NM_SETTING (s_cdma), NM_SETTING_CDMA_PASSWORD, - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); } else if (nm_connection_is_type (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { NMSetting *setting = NULL; @@ -558,12 +558,11 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) msg = g_strdup_printf (_("A password is required to connect to '%s'."), nm_connection_get_id (request->connection)); - secret = nm_secret_agent_simple_secret_new (_("Password"), + secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), setting, "password", - NULL, - NULL, - TRUE); + NULL); g_ptr_array_add (secrets, secret); } else ok = FALSE; @@ -690,9 +689,7 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self, GHashTable *settings; GHashTableIter iter; const char *name; - const char *vpn_secrets_base_name = NULL; - - g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); + gboolean has_vpn = FALSE; settings = g_hash_table_new (nm_str_hash, g_str_equal); for (i = 0; i < secrets->len; i++) { @@ -705,22 +702,27 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self, setting_builder); } - if (secret->base.vpn_property) { - /* VPN secrets need slightly different treatment. - * "secrets" property is actually a hash table of secrets. */ - vpn_secrets_base_name = secret->property; - g_variant_builder_add (&vpn_secrets_builder, "{ss}", - secret->base.vpn_property, secret->base.value); - } else { + 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; } } - if (vpn_secrets_base_name) { + if (has_vpn) { g_variant_builder_add (setting_builder, "{sv}", - vpn_secrets_base_name, + "secrets", g_variant_builder_end (&vpn_secrets_builder)); } diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h index 2989723dbf..c0f6befcb4 100644 --- a/clients/common/nm-secret-agent-simple.h +++ b/clients/common/nm-secret-agent-simple.h @@ -42,13 +42,25 @@ typedef struct { } NMSecretAgentSimpleClass; +typedef enum { + NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + NM_SECRET_AGENT_SECRET_TYPE_SECRET, + NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, +} NMSecretAgentSecretType; + typedef struct { - char *name, *prop_name, *value; - char *vpn_property; - char *vpn_type; - gboolean password; + const NMSecretAgentSecretType secret_type; + const char *pretty_name; + const char *entry_id; + char *value; + const char *vpn_type; + gboolean is_secret; } NMSecretAgentSimpleSecret; +#define NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "vpn.secret." + +#define NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT NM_DBUS_INTERFACE".openconnect" + GType nm_secret_agent_simple_get_type (void); NMSecretAgentOld *nm_secret_agent_simple_new (const char *name); diff --git a/clients/tui/nmt-password-dialog.c b/clients/tui/nmt-password-dialog.c index fb9567e691..16920fcf39 100644 --- a/clients/tui/nmt-password-dialog.c +++ b/clients/tui/nmt-password-dialog.c @@ -144,12 +144,12 @@ nmt_password_dialog_constructed (GObject *object) NMSecretAgentSimpleSecret *secret = priv->secrets->pdata[i]; NmtNewtEntryFlags flags; - widget = nmt_newt_label_new (secret->name); + widget = nmt_newt_label_new (secret->pretty_name); nmt_newt_grid_add (secret_grid, widget, 0, i); nmt_newt_widget_set_padding (widget, 4, 0, 1, 0); flags = NMT_NEWT_ENTRY_NONEMPTY; - if (secret->password) + if (secret->is_secret) flags |= NMT_NEWT_ENTRY_PASSWORD; widget = nmt_newt_entry_new (30, flags); if (secret->value) diff --git a/clients/tui/nmtui-connect.c b/clients/tui/nmtui-connect.c index 086e4bd3fb..2a954fb8cb 100644 --- a/clients/tui/nmtui-connect.c +++ b/clients/tui/nmtui-connect.c @@ -100,41 +100,38 @@ secrets_requested (NMSecretAgentSimple *agent, { NmtNewtForm *form; NMConnection *connection = NM_CONNECTION (user_data); - char *cookie = NULL; - char *gateway = NULL; - char *gwcert = NULL; int i; /* Get secrets for OpenConnect VPN */ - if (connection && nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { + if ( connection + && nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (connection); - const char *vpn_type = nm_setting_vpn_get_service_type (s_vpn); - if (!g_strcmp0 (vpn_type, NM_DBUS_INTERFACE ".openconnect")) { + if (nm_streq0 (nm_setting_vpn_get_service_type (s_vpn), NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT)) { + gs_free char *cookie = NULL; + gs_free char *gateway = NULL; + gs_free char *gwcert = NULL; + openconnect_authenticate (connection, &cookie, &gateway, &gwcert); for (i = 0; i < secrets->len; i++) { NMSecretAgentSimpleSecret *secret = secrets->pdata[i]; - if (!g_strcmp0 (secret->vpn_type, NM_DBUS_INTERFACE ".openconnect")) { - if (!g_strcmp0 (secret->vpn_property, "cookie")) { - g_free (secret->value); - secret->value = cookie; - cookie = NULL; - } else if (!g_strcmp0 (secret->vpn_property, "gateway")) { - g_free (secret->value); - secret->value = gateway; - gateway = NULL; - } else if (!g_strcmp0 (secret->vpn_property, "gwcert")) { - g_free (secret->value); - secret->value = gwcert; - gwcert = NULL; - } + if (secret->secret_type != NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET) + continue; + if (!nm_streq0 (secret->vpn_type, NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT)) + continue; + if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "cookie")) { + g_free (secret->value); + secret->value = g_steal_pointer (&cookie); + } else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gateway")) { + g_free (secret->value); + secret->value = g_steal_pointer (&gateway); + } else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gwcert")) { + g_free (secret->value); + secret->value = g_steal_pointer (&gwcert); } } - g_free (cookie); - g_free (gateway); - g_free (gwcert); } } diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index 343bd9aa30..79a7350bdb 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -155,6 +155,39 @@ nm_setting_vpn_get_persistent (NMSettingVpn *setting) return NM_SETTING_VPN_GET_PRIVATE (setting)->persistent; } +static const char ** +_get_keys (NMSettingVpn *setting, + gboolean is_secrets, + guint *out_length) +{ + NMSettingVpnPrivate *priv; + GHashTable *hash; + const char **keys; + guint len; + + nm_assert (NM_IS_SETTING_VPN (setting)); + + priv = NM_SETTING_VPN_GET_PRIVATE (setting); + + hash = is_secrets ? priv->secrets : priv->data; + + if (!g_hash_table_size (hash)) { + NM_SET_OUT (out_length, 0); + return NULL; + } + + keys = (const char **) g_hash_table_get_keys_as_array (hash, &len); + if (len > 1) { + g_qsort_with_data (keys, + len, + sizeof (const char *), + nm_strcmp_p_with_data, + NULL); + } + NM_SET_OUT (out_length, len); + return keys; +} + /** * nm_setting_vpn_get_num_data_items: * @setting: the #NMSettingVpn @@ -216,6 +249,28 @@ nm_setting_vpn_get_data_item (NMSettingVpn *setting, const char *key) } /** + * nm_setting_vpn_get_data_keys: + * @setting: the #NMSettingVpn + * @out_length: (allow-none): (out): the length of the returned array + * + * Retrieves every data key inside @setting, as an array. + * + * Returns: (array length=out_length) (transfer container): a + * %NULL-terminated array containing each data key or %NULL if + * there are no data items. + * + * Since: 1.12 + */ +const char ** +nm_setting_vpn_get_data_keys (NMSettingVpn *setting, + guint *out_length) +{ + g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + + return _get_keys (setting, FALSE, out_length); +} + +/** * nm_setting_vpn_remove_data_item: * @setting: the #NMSettingVpn * @key: the name of the data item to remove @@ -240,32 +295,52 @@ nm_setting_vpn_remove_data_item (NMSettingVpn *setting, const char *key) } static void -foreach_item_helper (GHashTable *hash, +foreach_item_helper (NMSettingVpn *self, + gboolean is_secrets, NMVpnIterFunc func, gpointer user_data) { - GList *keys, *liter; - GSList *copied = NULL, *siter; + NMSettingVpnPrivate *priv; + guint len, i; + gs_strfreev char **keys = NULL; + GHashTable *hash; - g_return_if_fail (hash != NULL); + nm_assert (NM_IS_SETTING_VPN (self)); + nm_assert (func); - /* Grab keys and copy them so that the callback func can modify - * the hash table items if it wants to. - */ - keys = g_hash_table_get_keys (hash); - for (liter = keys; liter; liter = g_list_next (liter)) - copied = g_slist_prepend (copied, g_strdup (liter->data)); - copied = g_slist_reverse (copied); - g_list_free (keys); + priv = NM_SETTING_VPN_GET_PRIVATE (self); - for (siter = copied; siter; siter = g_slist_next (siter)) { - gpointer value; + if (is_secrets) { + keys = (char **) nm_setting_vpn_get_secret_keys (self, &len); + hash = priv->secrets; + } else { + keys = (char **) nm_setting_vpn_get_data_keys (self, &len); + hash = priv->data; + } - value = g_hash_table_lookup (hash, siter->data); - func (siter->data, value, user_data); + if (!len) { + nm_assert (!keys); + return; } - g_slist_free_full (copied, g_free); + for (i = 0; i < len; i++) { + nm_assert (keys[i]); + keys[i] = g_strdup (keys[i]); + } + nm_assert (!keys[i]); + + for (i = 0; i < len; i++) { + const char *value; + + value = g_hash_table_lookup (hash, keys[i]); + /* XXX: note that we call the function with a clone of @key, + * not with the actual key from the dictionary. + * + * The @value on the other hand, is actually inside our dictionary, + * it's not a clone. However, it might be %NULL, in case the key was + * deleted while iterating. */ + func (keys[i], value, user_data); + } } /** @@ -284,8 +359,9 @@ nm_setting_vpn_foreach_data_item (NMSettingVpn *setting, gpointer user_data) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); + g_return_if_fail (func); - foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->data, func, user_data); + foreach_item_helper (setting, FALSE, func, user_data); } /** @@ -348,6 +424,28 @@ nm_setting_vpn_get_secret (NMSettingVpn *setting, const char *key) } /** + * nm_setting_vpn_get_secret_keys: + * @setting: the #NMSettingVpn + * @out_length: (allow-none): (out): the length of the returned array + * + * Retrieves every secret key inside @setting, as an array. + * + * Returns: (array length=out_length) (transfer container): a + * %NULL-terminated array containing each secret key or %NULL if + * there are no secrets. + * + * Since: 1.12 + */ +const char ** +nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, + guint *out_length) +{ + g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + + return _get_keys (setting, TRUE, out_length); +} + +/** * nm_setting_vpn_remove_secret: * @setting: the #NMSettingVpn * @key: the name of the secret to remove @@ -387,8 +485,9 @@ nm_setting_vpn_foreach_secret (NMSettingVpn *setting, gpointer user_data) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); + g_return_if_fail (func); - foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, func, user_data); + foreach_item_helper (setting, TRUE, func, user_data); } /** @@ -708,22 +807,12 @@ clear_secrets_with_flags (NMSetting *setting, } static void -destroy_one_secret (gpointer data) -{ - char *secret = (char *) data; - - /* Don't leave the secret lying around in memory */ - memset (secret, 0, strlen (secret)); - g_free (secret); -} - -static void nm_setting_vpn_init (NMSettingVpn *setting) { NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); priv->data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - priv->secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, destroy_one_secret); + priv->secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) nm_free_secret); } static void diff --git a/libnm-core/nm-setting-vpn.h b/libnm-core/nm-setting-vpn.h index 115aa8676e..1f1576fdfe 100644 --- a/libnm-core/nm-setting-vpn.h +++ b/libnm-core/nm-setting-vpn.h @@ -90,6 +90,9 @@ gboolean nm_setting_vpn_remove_data_item (NMSettingVpn *setting, void nm_setting_vpn_foreach_data_item (NMSettingVpn *setting, NMVpnIterFunc func, gpointer user_data); +NM_AVAILABLE_IN_1_12 +const char ** nm_setting_vpn_get_data_keys (NMSettingVpn *setting, + guint *out_length); guint32 nm_setting_vpn_get_num_secrets (NMSettingVpn *setting); void nm_setting_vpn_add_secret (NMSettingVpn *setting, @@ -102,6 +105,11 @@ gboolean nm_setting_vpn_remove_secret (NMSettingVpn *setting, void nm_setting_vpn_foreach_secret (NMSettingVpn *setting, NMVpnIterFunc func, gpointer user_data); +NM_AVAILABLE_IN_1_12 +const char ** nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, + guint *out_length); + + NM_AVAILABLE_IN_1_2 guint32 nm_setting_vpn_get_timeout (NMSettingVpn *setting); diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 297887411d..5a06fd062b 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -1800,21 +1800,19 @@ get_secret_flags (NMSetting *setting, NMSettingSecretFlags *out_flags, GError **error) { - char *flags_prop; + gs_free char *name_to_free = NULL; NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; if (verify_secret && !is_secret_prop (setting, secret_name, error)) { - if (out_flags) - *out_flags = NM_SETTING_SECRET_FLAG_NONE; + NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE); return FALSE; } - flags_prop = g_strdup_printf ("%s-flags", secret_name); - g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL); - g_free (flags_prop); - - if (out_flags) - *out_flags = flags; + g_object_get (G_OBJECT (setting), + nm_construct_name_a ("%s-flags", secret_name, &name_to_free), + &flags, + NULL); + NM_SET_OUT (out_flags, flags); return TRUE; } @@ -1850,14 +1848,15 @@ set_secret_flags (NMSetting *setting, NMSettingSecretFlags flags, GError **error) { - char *flags_prop; + gs_free char *name_to_free = NULL; if (verify_secret) g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); - flags_prop = g_strdup_printf ("%s-flags", secret_name); - g_object_set (G_OBJECT (setting), flags_prop, flags, NULL); - g_free (flags_prop); + g_object_set (G_OBJECT (setting), + nm_construct_name_a ("%s-flags", secret_name, &name_to_free), + flags, + NULL); return TRUE; } diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 5e9feaffc8..aad581698b 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1258,4 +1258,6 @@ global: nm_setting_team_port_get_lacp_key; nm_setting_team_remove_runner_tx_hash; nm_setting_team_remove_runner_tx_hash_by_value; + nm_setting_vpn_get_data_keys; + nm_setting_vpn_get_secret_keys; } libnm_1_10_0; diff --git a/libnm/nm-vpn-plugin-old.c b/libnm/nm-vpn-plugin-old.c index 1892c394b7..73d2b2abc0 100644 --- a/libnm/nm-vpn-plugin-old.c +++ b/libnm/nm-vpn-plugin-old.c @@ -33,6 +33,7 @@ #include "nm-dbus-helpers.h" #include "nm-core-internal.h" #include "nm-simple-connection.h" +#include "nm-vpn-service-plugin.h" #include "introspection/org.freedesktop.NetworkManager.VPN.Plugin.h" @@ -683,20 +684,6 @@ nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, /*****************************************************************************/ -#define DATA_KEY_TAG "DATA_KEY=" -#define DATA_VAL_TAG "DATA_VAL=" -#define SECRET_KEY_TAG "SECRET_KEY=" -#define SECRET_VAL_TAG "SECRET_VAL=" - -static void -free_secret (gpointer data) -{ - char *secret = data; - - memset (secret, 0, strlen (secret)); - g_free (secret); -} - /** * nm_vpn_plugin_old_read_vpn_details: * @fd: file descriptor to read from, usually stdin (0) @@ -717,87 +704,7 @@ nm_vpn_plugin_old_read_vpn_details (int fd, GHashTable **out_data, GHashTable **out_secrets) { - GHashTable *data, *secrets; - gboolean success = FALSE; - char *key = NULL, *val = NULL; - GString *line; - gchar c; - - if (out_data) - g_return_val_if_fail (*out_data == NULL, FALSE); - if (out_secrets) - g_return_val_if_fail (*out_secrets == NULL, FALSE); - - data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, free_secret); - - line = g_string_new (NULL); - - /* Read stdin for data and secret items until we get a DONE */ - while (1) { - ssize_t nr; - GHashTable *hash = NULL; - - errno = 0; - nr = read (fd, &c, 1); - if (nr == -1) { - if (errno == EAGAIN) { - g_usleep (100); - continue; - } - break; - } - - if (c != '\n') { - g_string_append_c (line, c); - continue; - } - - /* Check for the finish marker */ - if (strcmp (line->str, "DONE") == 0) - break; - - /* Otherwise it's a data/secret item */ - if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) { - hash = data; - key = g_strdup (line->str + strlen (DATA_KEY_TAG)); - } else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) { - hash = data; - val = g_strdup (line->str + strlen (DATA_VAL_TAG)); - } else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) { - hash = secrets; - key = g_strdup (line->str + strlen (SECRET_KEY_TAG)); - } else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) { - hash = secrets; - val = g_strdup (line->str + strlen (SECRET_VAL_TAG)); - } - g_string_truncate (line, 0); - - if (key && val && hash) { - g_hash_table_insert (hash, key, val); - key = NULL; - val = NULL; - success = TRUE; /* Got at least one value */ - } - } - - if (success) { - if (out_data) - *out_data = data; - else - g_hash_table_destroy (data); - - if (out_secrets) - *out_secrets = secrets; - else - g_hash_table_destroy (secrets); - } else { - g_hash_table_destroy (data); - g_hash_table_destroy (secrets); - } - - g_string_free (line, TRUE); - return success; + return nm_vpn_service_plugin_read_vpn_details (fd, out_data, out_secrets); } /** @@ -820,31 +727,7 @@ nm_vpn_plugin_old_get_secret_flags (GHashTable *data, const char *secret_name, NMSettingSecretFlags *out_flags) { - char *flag_name; - const char *val; - unsigned long tmp; - gboolean success = FALSE; - - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (secret_name != NULL, FALSE); - g_return_val_if_fail (out_flags != NULL, FALSE); - g_return_val_if_fail (*out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE); - - flag_name = g_strdup_printf ("%s-flags", secret_name); - - /* Try new flags value first */ - val = g_hash_table_lookup (data, flag_name); - if (val) { - errno = 0; - tmp = strtoul (val, NULL, 10); - if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) { - *out_flags = (NMSettingSecretFlags) tmp; - success = TRUE; - } - } - - g_free (flag_name); - return success; + return nm_vpn_service_plugin_get_secret_flags (data, secret_name, out_flags); } /*****************************************************************************/ diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 79bd0f8193..b9e3992631 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -710,15 +710,6 @@ nm_vpn_service_plugin_secrets_required (NMVpnServicePlugin *plugin, #define SECRET_KEY_TAG "SECRET_KEY=" #define SECRET_VAL_TAG "SECRET_VAL=" -static void -free_secret (gpointer data) -{ - char *secret = data; - - memset (secret, 0, strlen (secret)); - g_free (secret); -} - /** * nm_vpn_service_plugin_read_vpn_details: * @fd: file descriptor to read from, usually stdin (0) @@ -739,10 +730,11 @@ nm_vpn_service_plugin_read_vpn_details (int fd, GHashTable **out_data, GHashTable **out_secrets) { - GHashTable *data, *secrets; + gs_unref_hashtable GHashTable *data = NULL; + gs_unref_hashtable GHashTable *secrets = NULL; gboolean success = FALSE; char *key = NULL, *val = NULL; - GString *line; + nm_auto_free_gstring GString *line = NULL; gchar c; if (out_data) @@ -751,7 +743,7 @@ nm_vpn_service_plugin_read_vpn_details (int fd, g_return_val_if_fail (*out_secrets == NULL, FALSE); data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, free_secret); + secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) nm_free_secret); line = g_string_new (NULL); @@ -804,21 +796,9 @@ nm_vpn_service_plugin_read_vpn_details (int fd, } if (success) { - if (out_data) - *out_data = data; - else - g_hash_table_destroy (data); - - if (out_secrets) - *out_secrets = secrets; - else - g_hash_table_destroy (secrets); - } else { - g_hash_table_destroy (data); - g_hash_table_destroy (secrets); + NM_SET_OUT (out_data, g_steal_pointer (&data)); + NM_SET_OUT (out_secrets, g_steal_pointer (&secrets)); } - - g_string_free (line, TRUE); return success; } @@ -842,31 +822,29 @@ nm_vpn_service_plugin_get_secret_flags (GHashTable *data, const char *secret_name, NMSettingSecretFlags *out_flags) { - char *flag_name; - const char *val; - unsigned long tmp; - gboolean success = FALSE; - - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (secret_name != NULL, FALSE); - g_return_val_if_fail (out_flags != NULL, FALSE); - g_return_val_if_fail (*out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE); + gs_free char *flag_name_free = NULL; + const char *s; + gint64 t1; + NMSettingSecretFlags t0; - flag_name = g_strdup_printf ("%s-flags", secret_name); + g_return_val_if_fail (data, FALSE); + g_return_val_if_fail (out_flags && *out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE); + if (!secret_name || !*secret_name) + g_return_val_if_reached (FALSE); - /* Try new flags value first */ - val = g_hash_table_lookup (data, flag_name); - if (val) { - errno = 0; - tmp = strtoul (val, NULL, 10); - if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) { - *out_flags = (NMSettingSecretFlags) tmp; - success = TRUE; - } - } - g_free (flag_name); - return success; + s = g_hash_table_lookup (data, + nm_construct_name_a ("%s-flags", secret_name, &flag_name_free)); + if (!s) + return FALSE; + t1 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXINT64, -1); + if (t1 == -1) + return FALSE; + t0 = (NMSettingSecretFlags) t1; + if ((gint64) t0 != t1) + return FALSE; + NM_SET_OUT (out_flags, t0); + return TRUE; } /*****************************************************************************/ diff --git a/shared/nm-utils/nm-compat.c b/shared/nm-utils/nm-compat.c new file mode 100644 index 0000000000..22ab675de8 --- /dev/null +++ b/shared/nm-utils/nm-compat.c @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-compat.h" + +/*****************************************************************************/ + +static void +_get_keys_cb (const char *key, const char *val, gpointer user_data) +{ + GPtrArray *a = user_data; + + g_ptr_array_add (a, g_strdup (key)); +} + +static const char ** +_get_keys (NMSettingVpn *setting, + gboolean is_secrets, + guint *out_length) +{ + guint len; + const char **keys = NULL; + gs_unref_ptrarray GPtrArray *a = NULL; + + nm_assert (NM_IS_SETTING_VPN (setting)); + + a = g_ptr_array_new (); + if (is_secrets) + nm_setting_vpn_foreach_secret (setting, _get_keys_cb, a); + else + nm_setting_vpn_foreach_data_item (setting, _get_keys_cb, a); + len = a->len; + + if (a->len) { + g_ptr_array_sort (a, nm_strcmp_p); + g_ptr_array_add (a, NULL); + keys = (const char **) g_ptr_array_free (g_steal_pointer (&a), FALSE); + + /* we need to cache the keys *somewhere*. */ + g_object_set_qdata_full (G_OBJECT (setting), + is_secrets + ? NM_CACHED_QUARK ("libnm._nm_setting_vpn_get_secret_keys") + : NM_CACHED_QUARK ("libnm._nm_setting_vpn_get_data_keys"), + keys, + (GDestroyNotify) g_strfreev); + } + + NM_SET_OUT (out_length, len); + return keys; +} + +const char ** +_nm_setting_vpn_get_data_keys (NMSettingVpn *setting, + guint *out_length) +{ + g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + + return _get_keys (setting, FALSE, out_length); +} + +const char ** +_nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, + guint *out_length) +{ + g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + + return _get_keys (setting, TRUE, out_length); +} diff --git a/shared/nm-utils/nm-compat.h b/shared/nm-utils/nm-compat.h new file mode 100644 index 0000000000..5234169033 --- /dev/null +++ b/shared/nm-utils/nm-compat.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_COMPAT_H__ +#define __NM_COMPAT_H__ + +#include "nm-setting-vpn.h" + +const char **_nm_setting_vpn_get_data_keys (NMSettingVpn *setting, + guint *out_length); + +const char **_nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, + guint *out_length); + +#if NM_CHECK_VERSION (1, 11, 0) +#define nm_setting_vpn_get_data_keys(setting, out_length) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + nm_setting_vpn_get_data_keys (setting, out_length); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) +#define nm_setting_vpn_get_secret_keys(setting, out_length) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + nm_setting_vpn_get_secret_keys (setting, out_length); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) +#else +#define nm_setting_vpn_get_data_keys(setting, out_length) \ + _nm_setting_vpn_get_data_keys (setting, out_length) +#define nm_setting_vpn_get_secret_keys(setting, out_length) \ + _nm_setting_vpn_get_secret_keys (setting, out_length) +#endif + +#endif /* __NM_COMPAT_H__ */ diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index ce13d3a6fa..cf9142fe99 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -1172,6 +1172,28 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) _buf; \ }) +/* aims to alloca() a buffer and fill it with printf(format, name). + * Note that format must not contain any format specifier except + * "%s". + * If the resulting string would be too large for stack allocation, + * it allocates a buffer with g_malloc() and assigns it to *p_val_to_free. */ +#define nm_construct_name_a(format, name, p_val_to_free) \ + ({ \ + const char *const _name = (name); \ + char **const _p_val_to_free = (p_val_to_free); \ + const gsize _name_len = strlen (_name); \ + char *_buf2; \ + \ + nm_assert (_p_val_to_free && !*_p_val_to_free); \ + if (NM_STRLEN (format) + _name_len < 200) \ + _buf2 = nm_sprintf_bufa (NM_STRLEN (format) + _name_len, format, _name); \ + else { \ + _buf2 = g_strdup_printf (format, _name); \ + *_p_val_to_free = _buf2; \ + } \ + (const char *) _buf2; \ + }) + /*****************************************************************************/ /** diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 0c951dd4fc..ee4014ac3c 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -861,12 +861,6 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) return c; } -gboolean -nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) -{ - return nmp_object_cmp (obj1, obj2) == 0; -} - /* @src is a const object, which is not entirely correct for link types, where * we increase the ref count for src->_link.udev.device. * Hence, nmp_object_copy() can violate the const promise of @src. @@ -1076,7 +1070,7 @@ nmp_object_id_hash (const NMPObject *obj) NMHashState h; if (!obj) - return 0; + return nm_hash_static (914932607u); nm_hash_init (&h, 914932607u); nmp_object_id_hash_update (obj, &h); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 6db7573a99..d8fe60a60e 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -471,7 +471,13 @@ const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifinde const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2); -gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2); + +static inline gboolean +nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) +{ + return nmp_object_cmp (obj1, obj2) == 0; +} + void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only); NMPObject *nmp_object_clone (const NMPObject *obj, gboolean id_only); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index bcd178435f..29abd71bd5 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -1213,7 +1213,7 @@ nm_agent_manager_get_secrets (NMAgentManager *self, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data) { diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 7f8126935f..c2a2ec1d8f 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -60,7 +60,7 @@ NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index ed69115c8b..1185aef905 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -1228,7 +1228,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, NMAuthSubject *subject, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMSettingsConnectionSecretsFunc callback, gpointer callback_data) { diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index faacd94909..7a9e383259 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -167,7 +167,7 @@ NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnect NMAuthSubject *subject, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMSettingsConnectionSecretsFunc callback, gpointer callback_data); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 7122243d35..e441bbd051 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -185,13 +185,13 @@ static NMSettingsConnection *_get_settings_connection (NMVpnConnection *self, static void get_secrets (NMVpnConnection *self, SecretsReq secrets_idx, - const char **hints); + const char *const*hints); static guint32 get_route_table (NMVpnConnection *self, int addr_family, gboolean fallback_main); static void plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets); + const char *const*secrets); static void _set_vpn_state (NMVpnConnection *self, VpnState vpn_state, @@ -2047,7 +2047,7 @@ state_changed_cb (GDBusProxy *proxy, static void secrets_required_cb (GDBusProxy *proxy, const char *message, - const char **secrets, + const char *const*secrets, gpointer user_data) { NMVpnConnection *self = NM_VPN_CONNECTION (user_data); @@ -2638,7 +2638,7 @@ get_secrets_cb (NMSettingsConnection *connection, static void get_secrets (NMVpnConnection *self, SecretsReq secrets_idx, - const char **hints) + const char *const*hints) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; @@ -2683,12 +2683,13 @@ get_secrets (NMVpnConnection *self, static void plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets) + const char *const*secrets) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - guint32 secrets_len = secrets ? g_strv_length ((char **) secrets) : 0; - char **hints; - guint32 i; + const gsize secrets_len = NM_PTRARRAY_LEN (secrets); + gsize i; + gs_free const char **hints = NULL; + gs_free char *message_hint = NULL; _LOGI ("VPN plugin: requested secrets; state %s (%d)", vpn_state_to_string (priv->vpn_state), priv->vpn_state); @@ -2700,14 +2701,17 @@ plugin_interactive_secrets_required (NMVpnConnection *self, _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); /* Copy hints and add message to the end */ - hints = g_malloc0 (sizeof (char *) * (secrets_len + 2)); + hints = g_new (const char *, secrets_len + 2); for (i = 0; i < secrets_len; i++) - hints[i] = g_strdup (secrets[i]); - if (message) - hints[i] = g_strdup_printf ("x-vpn-message:%s", message); + hints[i] = secrets[i]; + if (message) { + message_hint = g_strdup_printf ("x-vpn-message:%s", message); + hints[i++] = message_hint; + } + hints[i] = NULL; + nm_assert (i < secrets_len + 2); - get_secrets (self, SECRETS_REQ_INTERACTIVE, (const char **) hints); - g_strfreev (hints); + get_secrets (self, SECRETS_REQ_INTERACTIVE, hints); } /*****************************************************************************/ |