summary refs log tree commit diff
path: root/clients/cli/connections.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-03-26 23:25:23 +0100
committerMichael Biebl <biebl@debian.org>2019-03-26 23:25:23 +0100
commit9a6dcbf895f9da01768e64b73cec88c16157d91e (patch)
treea359958930d731e9f1b59344642e10754419fe84 /clients/cli/connections.c
parent964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (diff)
New upstream version 1.16.0 upstream/1.16.0
Diffstat (limited to 'clients/cli/connections.c')
-rw-r--r--clients/cli/connections.c477
1 files changed, 318 insertions, 159 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 8a10691e..6db44f87 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -22,14 +22,13 @@
 #include "connections.h"
 
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <errno.h>
 #include <signal.h>
 #include <netinet/ether.h>
 #include <readline/readline.h>
 #include <readline/history.h>
+#include <fcntl.h>
 
 #include "nm-client-utils.h"
 #include "nm-vpn-helpers.h"
@@ -140,15 +139,68 @@ active_connection_get_state_ord (NMActiveConnection *active)
 	return -1;
 }
 
-static int
-active_connection_cmp (NMActiveConnection *ac_a, NMActiveConnection *ac_b)
+int
+nmc_active_connection_cmp (NMActiveConnection *ac_a, NMActiveConnection *ac_b)
 {
+	NMSettingIPConfig *s_ip;
+	NMRemoteConnection *conn;
+	NMIPConfig *da_ip;
+	NMIPConfig *db_ip;
+	int da_num_addrs;
+	int db_num_addrs;
+	int cmp = 0;
+
+	/* Non-active sort last. */
 	NM_CMP_SELF (ac_a, ac_b);
 	NM_CMP_DIRECT (active_connection_get_state_ord (ac_b),
 	               active_connection_get_state_ord (ac_a));
-	NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_id (ac_a), nm_active_connection_get_id (ac_b));
-	NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_connection_type (ac_a), nm_active_connection_get_connection_type (ac_b));
-	NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)), nm_object_get_path (NM_OBJECT (ac_b)));
+
+	/* Shared connections (likely hotspots) go on the top if possible */
+	conn = nm_active_connection_get_connection (ac_a);
+	s_ip = conn ? nm_connection_get_setting_ip6_config (NM_CONNECTION (conn)) : NULL;
+	if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0)
+		cmp++;
+	conn = nm_active_connection_get_connection (ac_b);
+	s_ip = conn ? nm_connection_get_setting_ip6_config (NM_CONNECTION (conn)) : NULL;
+	if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0)
+		cmp--;
+	NM_CMP_RETURN (cmp);
+
+	conn = nm_active_connection_get_connection (ac_a);
+	s_ip = conn ? nm_connection_get_setting_ip4_config (NM_CONNECTION (conn)) : NULL;
+	if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0)
+		cmp++;
+	conn = nm_active_connection_get_connection (ac_b);
+	s_ip = conn ? nm_connection_get_setting_ip4_config (NM_CONNECTION (conn)) : NULL;
+	if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0)
+		cmp--;
+	NM_CMP_RETURN (cmp);
+
+	/* VPNs go next */
+	NM_CMP_DIRECT (!!nm_active_connection_get_vpn (ac_a),
+	               !!nm_active_connection_get_vpn (ac_b));
+
+	/* Default devices are prioritized */
+	NM_CMP_DIRECT (nm_active_connection_get_default (ac_a),
+	               nm_active_connection_get_default (ac_b));
+
+	/* Default IPv6 devices are prioritized */
+	NM_CMP_DIRECT (nm_active_connection_get_default6 (ac_a),
+	               nm_active_connection_get_default6 (ac_b));
+
+	/* Sort by number of addresses. */
+	da_ip = nm_active_connection_get_ip4_config (ac_a);
+	da_num_addrs = da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0;
+	db_ip = nm_active_connection_get_ip4_config (ac_b);
+	db_num_addrs = db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0;
+
+	da_ip = nm_active_connection_get_ip6_config (ac_a);
+	da_num_addrs += da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0;
+	db_ip = nm_active_connection_get_ip6_config (ac_b);
+	db_num_addrs += db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0;
+
+	NM_CMP_DIRECT (da_num_addrs, db_num_addrs);
+
 	return 0;
 }
 
@@ -742,6 +794,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
                                          NM_SETTING_IP4_CONFIG_SETTING_NAME","\
                                          NM_SETTING_IP6_CONFIG_SETTING_NAME","\
                                          NM_SETTING_SERIAL_SETTING_NAME","\
+                                         NM_SETTING_WIFI_P2P_SETTING_NAME","\
                                          NM_SETTING_PPP_SETTING_NAME","\
                                          NM_SETTING_PPPOE_SETTING_NAME","\
                                          NM_SETTING_ADSL_SETTING_NAME","\
@@ -769,6 +822,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
                                          NM_SETTING_VXLAN_SETTING_NAME"," \
                                          NM_SETTING_WPAN_SETTING_NAME","\
                                          NM_SETTING_6LOWPAN_SETTING_NAME","\
+                                         NM_SETTING_WIREGUARD_SETTING_NAME","\
                                          NM_SETTING_PROXY_SETTING_NAME"," \
                                          NM_SETTING_TC_CONFIG_SETTING_NAME"," \
                                          NM_SETTING_SRIOV_SETTING_NAME"," \
@@ -991,8 +1045,10 @@ usage_connection_add (void)
 	              "                  [source-port-min <0-65535>]\n"
 	              "                  [source-port-max <0-65535>]\n"
 	              "                  [destination-port <0-65535>]\n\n"
-	              "    wpan:         [short-addr <0x0000-0xffff>]\n\n"
-	              "                  [pan-id <0x0000-0xffff>]\n\n"
+	              "    wpan:         [short-addr <0x0000-0xffff>]\n"
+	              "                  [pan-id <0x0000-0xffff>]\n"
+	              "                  [page <default|0-31>]\n"
+	              "                  [channel <default|0-26>]\n"
 	              "                  [mac <MAC address>]\n\n"
 	              "    6lowpan:      dev <parent device (connection UUID, ifname, or MAC)>\n"
 	              "    dummy:\n\n"
@@ -1141,12 +1197,20 @@ construct_header_name (const char *base, const char *spec)
 }
 
 static int
-get_ac_for_connection_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data)
+get_ac_for_connection_cmp (gconstpointer pa, gconstpointer pb)
 {
 	NMActiveConnection *ac_a = *((NMActiveConnection *const*) pa);
 	NMActiveConnection *ac_b = *((NMActiveConnection *const*) pb);
 
-	return active_connection_cmp (ac_a, ac_b);
+	NM_CMP_RETURN (nmc_active_connection_cmp (ac_a, ac_b));
+	NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_id (ac_a),
+	                       nm_active_connection_get_id (ac_b));
+	NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_connection_type (ac_a),
+	                       nm_active_connection_get_connection_type (ac_b));
+	NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)),
+	                       nm_object_get_path (NM_OBJECT (ac_b)));
+
+	g_return_val_if_reached (0);
 }
 
 static NMActiveConnection *
@@ -1172,7 +1236,7 @@ get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection, G
 	}
 
 	if (result) {
-		g_ptr_array_sort_with_data (result, get_ac_for_connection_cmp, NULL);
+		g_ptr_array_sort (result, get_ac_for_connection_cmp);
 		best_candidate = result->pdata[0];
 	}
 
@@ -1629,12 +1693,10 @@ con_show_get_items_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data)
 			switch (item) {
 
 			case NMC_SORT_ACTIVE:
-				NM_CMP_DIRECT (active_connection_get_state_ord (ac_b),
-				               active_connection_get_state_ord (ac_a));
+				NM_CMP_RETURN (nmc_active_connection_cmp (ac_b, ac_a));
 				break;
 			case NMC_SORT_ACTIVE_INV:
-				NM_CMP_DIRECT (active_connection_get_state_ord (ac_a),
-				               active_connection_get_state_ord (ac_b));
+				NM_CMP_RETURN (nmc_active_connection_cmp (ac_a, ac_b));
 				break;
 
 			case NMC_SORT_TYPE:
@@ -1673,13 +1735,12 @@ con_show_get_items_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data)
 		                       nm_connection_get_uuid (c_b));
 		NM_CMP_DIRECT_STRCMP0 (nm_connection_get_path (c_a),
 		                       nm_connection_get_path (c_b));
-
-		/* This line is not expected to be reached, because there shouldn't be two
-		 * different connections with the same path. Anyway, fall-through and compare by
-		 * active connections... */
 	}
 
-	return active_connection_cmp (ac_a, ac_b);
+	NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)),
+	                       nm_object_get_path (NM_OBJECT (ac_b)));
+
+	g_return_val_if_reached (0);
 }
 
 static GPtrArray *
@@ -1755,7 +1816,7 @@ con_show_get_items (NmCli *nmc, gboolean active_only, gboolean show_active_field
 		 * color (activated or not) based on primary_active. */
 		if (!row_data) {
 			/* this is unexpected. The active connection references a connection that
-			 * seemingly no longer exists. It's a bug in libnm. Add a row nontheless. */
+			 * seemingly no longer exists. It's a bug in libnm. Add a row nonetheless. */
 			row_data = _metagen_con_show_row_data_new_for_connection (c, show_active_fields);
 			g_hash_table_insert (row_hash, c, row_data);
 		}
@@ -1985,8 +2046,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
 			}
 		}
 
-		/* Optionally start paging the output. */
-		nmc_terminal_spawn_pager (&nmc->nmc_config);
+		nm_cli_spawn_pager (nmc);
 
 		items = con_show_get_items (nmc, active_only, show_active_fields, order);
 		g_ptr_array_add (items, NULL);
@@ -2287,7 +2347,7 @@ find_device_for_connection (NmCli *nmc,
 					continue;
 
 				if (!nm_device_connection_compatible (dev, connection, error)) {
-					g_prefix_error (error, _("device '%s' not compatible with connection '%s':"),
+					g_prefix_error (error, _("device '%s' not compatible with connection '%s': "),
 					                iface, nm_setting_connection_get_id (s_con));
 					return FALSE;
 				}
@@ -2340,6 +2400,43 @@ typedef struct {
 	NMActiveConnection *active;
 } ActivateConnectionInfo;
 
+static void
+active_connection_hint (GString *return_text,
+                        NMActiveConnection *active,
+                        NMDevice *device)
+{
+	NMRemoteConnection *connection;
+	nm_auto_free_gstring GString *hint = NULL;
+	const GPtrArray *devices;
+	guint i;
+
+	if (!active)
+		return;
+
+	if (!nm_streq (NM_CONFIG_DEFAULT_LOGGING_BACKEND, "journal"))
+		return;
+
+	connection = nm_active_connection_get_connection (active);
+	g_return_if_fail (connection);
+
+	hint = g_string_new ("journalctl -xe ");
+	g_string_append_printf (hint, "NM_CONNECTION=%s",
+	                        nm_connection_get_uuid (NM_CONNECTION (connection)));
+
+	if (device)
+		g_string_append_printf (hint, " + NM_DEVICE=%s", nm_device_get_iface (device));
+	else {
+		devices = nm_active_connection_get_devices (active);
+		for (i = 0; i < devices->len; i++) {
+			g_string_append_printf (hint, " + NM_DEVICE=%s",
+			                        nm_device_get_iface (NM_DEVICE (g_ptr_array_index (devices, i))));
+		}
+	}
+
+	g_string_append (return_text, "\n");
+	g_string_append_printf (return_text, _("Hint: use '%s' to get more details."), hint->str);
+}
+
 static void activate_connection_info_finish (ActivateConnectionInfo *info);
 
 static void
@@ -2368,6 +2465,7 @@ check_activated (ActivateConnectionInfo *info)
 		nm_assert (reason);
 		g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"),
 		                 reason);
+		active_connection_hint (nmc->return_text, info->active, info->device);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 		activate_connection_info_finish (info);
 		break;
@@ -2375,7 +2473,7 @@ check_activated (ActivateConnectionInfo *info)
 		if (nmc->secret_agent) {
 			NMRemoteConnection *connection = nm_active_connection_get_connection (info->active);
 
-			nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent),
+			nm_secret_agent_simple_enable (nmc->secret_agent,
 			                               nm_connection_get_path (NM_CONNECTION (connection)));
 		}
 		break;
@@ -2490,6 +2588,7 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat
 		g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"),
 		                 error->message);
 		g_error_free (error);
+		active_connection_hint (nmc->return_text, info->active, info->device);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 		activate_connection_info_finish (info);
 	} else {
@@ -2676,7 +2775,6 @@ nmc_activate_connection (NmCli *nmc,
 		g_hash_table_destroy (nmc->pwds_hash);
 	nmc->pwds_hash = pwds_hash;
 
-	/* Create secret agent */
 	nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect");
 	if (nmc->secret_agent) {
 		g_signal_connect (nmc->secret_agent,
@@ -2726,14 +2824,14 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	argc_ptr = &argc;
 
 	if (argc == 0 && nmc->ask) {
-		char *line;
+		gs_free char *line = NULL;
 
 		/* nmc_do_cmd() should not call this with argc=0. */
 		g_assert (!nmc->complete);
 
-		line = nmc_readline (PROMPT_CONNECTION);
+		line = nmc_readline (&nmc->nmc_config,
+		                     PROMPT_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		g_free (line);
 		argv_ptr = &arg_arr;
 		argc_ptr = &arg_num;
 	}
@@ -2906,6 +3004,7 @@ connection_cb_info_finish (ConnectionCbInfo *info, gpointer obj)
 
 	nm_clear_g_source (&info->timeout_id);
 	nm_clear_g_cancellable (&info->cancellable);
+	g_ptr_array_free (info->obj_list, TRUE);
 
 	g_signal_handlers_disconnect_by_func (info->nmc->client, connection_removed_cb, info);
 
@@ -2980,9 +3079,11 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 		g_assert (!nmc->complete);
 
 		if (nmc->ask) {
-			char *line = nmc_readline (PROMPT_ACTIVE_CONNECTIONS);
+			gs_free char *line = NULL;
+
+			line = nmc_readline (&nmc->nmc_config,
+			                     PROMPT_ACTIVE_CONNECTIONS);
 			nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-			g_free (line);
 			arg_ptr = arg_arr;
 		}
 		if (arg_num == 0) {
@@ -3204,7 +3305,7 @@ get_valid_properties_string (const NMMetaSettingValidPartItem *const*array,
 	str = g_string_sized_new (1024);
 
 	for (i = 0; i < 2; i++, iter = array_slv) {
-		for(; !full_match && iter && *iter; iter++) {
+		for (; !full_match && iter && *iter; iter++) {
 			const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info;
 
 			if (   !(g_str_has_prefix (setting_info->general->setting_name, prefix))
@@ -3850,9 +3951,13 @@ reset_options (void)
 }
 
 static gboolean
-set_property (NMConnection *connection,
-              const char *setting_name, const char *property, const char *value,
-              char modifier, GError **error)
+set_property (NMClient *client,
+              NMConnection *connection,
+              const char *setting_name,
+              const char *property,
+              const char *value,
+              char modifier,
+              GError **error)
 {
 	gs_free char *property_name = NULL, *value_free = NULL;
 	NMSetting *setting;
@@ -3885,7 +3990,7 @@ set_property (NMConnection *connection,
 			value = value_free = g_strdup (value);
 			nmc_setting_reset_property (setting, property_name, NULL);
 		}
-		if (!nmc_setting_set_property (setting, property_name, value, &local)) {
+		if (!nmc_setting_set_property (client, setting, property_name, value, &local)) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			             _("Error: failed to modify %s.%s: %s."),
 			             setting_name, property, local->message);
@@ -3937,7 +4042,7 @@ set_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abst
 	if (option && option->check_and_set) {
 		return option->check_and_set (nmc, connection, option, value, error);
 	} else if (value) {
-		return set_property (connection, setting_name, property_name,
+		return set_property (nmc->client, connection, setting_name, property_name,
 		                     value, inf_flags & NM_META_PROPERTY_INF_FLAG_MULTI ? '+' : '\0', error);
 	} else if (inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) {
 		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -3985,7 +4090,7 @@ con_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const*
 
 /*
  * Make sure all required settings are in place (should be called when
- * it's possible that a type is aready set).
+ * it's possible that a type is already set).
  */
 static void
 ensure_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const*item)
@@ -4059,7 +4164,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co
 	}
 
 	if (slave_type) {
-		if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME,
+		if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME,
 		                   NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
 		                   '\0', error)) {
 			return FALSE;
@@ -4076,7 +4181,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co
 		                 NM_SETTING_CONNECTION_INTERFACE_NAME);
 	}
 
-	if (!set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error))
+	if (!set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error))
 		return FALSE;
 
 	if (!con_settings (con, &type_settings, &slv_settings, error))
@@ -4105,7 +4210,7 @@ set_connection_iface (NmCli *nmc, NMConnection *con, const OptionInfo *option, c
 		}
 	}
 
-	return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
 }
 
 static gboolean
@@ -4128,13 +4233,13 @@ set_connection_master (NmCli *nmc, NMConnection *con, const OptionInfo *option,
 	connections = nm_client_get_connections (nmc->client);
 	value = normalized_master_for_slave (connections, value, slave_type, &slave_type);
 
-	if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME,
+	if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME,
 	                   NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
 	                   '\0', error)) {
 		return FALSE;
 	}
 
-	return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
 }
 
 static gboolean
@@ -4248,7 +4353,7 @@ set_bluetooth_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, con
 		return FALSE;
 	}
 
-	return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
 }
 
 static gboolean
@@ -4267,7 +4372,7 @@ set_ip4_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const
 		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
 		              NULL);
 	}
-	return set_property (con, option->setting_info->general->setting_name, option->property, value,
+	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value,
 	                     '+', error);
 }
 
@@ -4287,7 +4392,7 @@ set_ip6_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const
 		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
 		              NULL);
 	}
-	return set_property (con, option->setting_info->general->setting_name, option->property, value,
+	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value,
 	                     '+', error);
 }
 
@@ -4573,7 +4678,7 @@ nmc_read_connection_properties (NmCli *nmc,
 			if (!*argc && nmc->complete)
 				complete_property (setting, strv[1], value ?: "", connection);
 
-			if (!set_property (connection, setting_name, strv[1], value, modifier, error))
+			if (!set_property (nmc->client, connection, setting_name, strv[1], value, modifier, error))
 				return FALSE;
 		} else {
 			NMMetaSettingType s;
@@ -4853,7 +4958,9 @@ ask_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abst
 		g_print (_("You can specify this option more than once. Press <Enter> when you're done.\n"));
 
 again:
-	value = nmc_readline ("%s", prompt);
+	value = nmc_readline (&nmc->nmc_config,
+	                      "%s",
+	                      prompt);
 	if (multi && !value)
 		return;
 
@@ -4943,23 +5050,25 @@ questionnaire_mandatory (NmCli *nmc, NMConnection *connection)
 }
 
 static gboolean
-want_provide_opt_args (const char *type, int num)
+want_provide_opt_args (const NmcConfig *nmc_config,
+                       const char *type,
+                       guint num)
 {
-	char *answer;
-	gboolean ret = TRUE;
+	gs_free char *answer = NULL;
 
 	/* Ask for optional arguments. */
 	g_print (ngettext ("There is %d optional setting for %s.\n",
-	                   "There are %d optional settings for %s.\n", num),
-	         num, type);
-	answer = nmc_readline (ngettext ("Do you want to provide it? %s",
-	                                 "Do you want to provide them? %s", num),
+	                   "There are %d optional settings for %s.\n",
+	                   num),
+	         (int) num,
+	         type);
+	answer = nmc_readline (nmc_config,
+	                       ngettext ("Do you want to provide it? %s",
+	                                 "Do you want to provide them? %s",
+	                                 num),
 	                       prompt_yes_no (TRUE, NULL));
-	answer = answer ? g_strstrip (answer) : NULL;
-	if (answer && !matches (answer, WORD_YES))
-		ret = FALSE;
-	g_free (answer);
-	return ret;
+	nm_strstrip (answer);
+	return !answer || matches (answer, WORD_YES);
 }
 
 static gboolean
@@ -5029,7 +5138,9 @@ again:
 
 		/* Now ask for the settings. */
 		if (   already_confirmed
-			|| want_provide_opt_args (_(setting_info->pretty_name), infos->len)) {
+		    || want_provide_opt_args (&nmc->nmc_config,
+		                              _(setting_info->pretty_name),
+		                              infos->len)) {
 			ask_option (nmc, connection, infos->pdata[0]);
 			already_confirmed = TRUE;
 			/* asking for an option may enable other options. Create the list again. */
@@ -5059,7 +5170,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
 
 	next_arg (nmc, &argc, &argv, NULL);
 
-	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_add_tab_completion;
+	rl_attempted_completion_function = nmcli_con_add_tab_completion;
 
 	nmc->return_value = NMC_RESULT_SUCCESS;
 
@@ -6615,7 +6726,7 @@ progress_activation_editor_cb (gpointer user_data)
 		NMRemoteConnection *connection;
 
 		connection = nm_active_connection_get_connection (ac);
-		nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (info->nmc->secret_agent),
+		nm_secret_agent_simple_enable (info->nmc->secret_agent,
 		                               nm_object_get_path (NM_OBJECT (connection)));
 	}
 
@@ -6656,6 +6767,10 @@ activate_connection_editor_cb (GObject *client,
 		} else
 			g_object_unref (active);
 	}
+
+	nm_g_object_unref (info->device);
+	g_free (info);
+
 	set_info_and_signal_editor_thread (error, monitor_ac_info);
 	g_clear_error (&error);
 }
@@ -6749,20 +6864,16 @@ is_connection_dirty (NMConnection *connection, NMRemoteConnection *remote)
 }
 
 static gboolean
-confirm_quit (void)
+confirm_quit (const NmcConfig *nmc_config)
 {
-	char *answer;
-	gboolean want_quit = FALSE;
+	gs_free char *answer = NULL;
 
-	answer = nmc_readline (_("The connection is not saved. "
+	answer = nmc_readline (nmc_config,
+	                       _("The connection is not saved. "
 	                         "Do you really want to quit? %s"),
 	                       prompt_yes_no (FALSE, NULL));
-	answer = answer ? g_strstrip (answer) : NULL;
-	if (answer && matches (answer, WORD_YES))
-		want_quit = TRUE;
-
-	g_free (answer);
-	return want_quit;
+	nm_strstrip (answer);
+	return (answer && matches (answer, WORD_YES));
 }
 
 /*
@@ -6797,7 +6908,7 @@ property_edit_submenu (NmCli *nmc,
 		gboolean removed;
 		gboolean dirty;
 
-		/* Get the remote connection again, it may have disapeared */
+		/* Get the remote connection again, it may have disappeared */
 		removed = refresh_remote_connection (rem_con_weak, rem_con);
 		if (removed) {
 			g_print (_("The connection profile has been removed from another client. "
@@ -6810,10 +6921,13 @@ property_edit_submenu (NmCli *nmc,
 		if (nmc->editor_status_line)
 			editor_show_status_line (connection, dirty, temp_changes);
 
-		cmd_property_user = nmc_readline ("%s", prompt);
+		cmd_property_user = nmc_readline (&nmc->nmc_config,
+		                                  "%s",
+		                                  prompt);
 		if (!cmd_property_user || !*cmd_property_user)
 			continue;
-		cmdsub = parse_editor_sub_cmd (g_strstrip (cmd_property_user), &cmd_property_arg);
+		g_strstrip (cmd_property_user);
+		cmdsub = parse_editor_sub_cmd (cmd_property_user, &cmd_property_arg);
 
 		switch (cmdsub) {
 		case NMC_EDITOR_SUB_CMD_SET:
@@ -6834,7 +6948,9 @@ property_edit_submenu (NmCli *nmc,
 					g_print (_("Allowed values for '%s' property: %s\n"),
 					         prop_name, avals_str);
 				}
-				prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name);
+				prop_val_user = nmc_readline (&nmc->nmc_config,
+				                              _("Enter '%s' value: "),
+				                              prop_name);
 			} else
 				prop_val_user = g_strdup (cmd_property_arg);
 
@@ -6846,7 +6962,7 @@ property_edit_submenu (NmCli *nmc,
 				nmc_property_set_default_value (curr_setting, prop_name);
 			}
 
-			set_result = nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err);
+			set_result = nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err);
 			if (!set_result) {
 				g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
 				g_clear_error (&tmp_err);
@@ -6862,12 +6978,14 @@ property_edit_submenu (NmCli *nmc,
 		case NMC_EDITOR_SUB_CMD_CHANGE:
 			rl_startup_hook = nmc_rl_set_deftext;
 			nmc_rl_pre_input_deftext = nmc_setting_get_property_parsable (curr_setting, prop_name, NULL);
-			prop_val_user = nmc_readline (_("Edit '%s' value: "), prop_name);
+			prop_val_user = nmc_readline (&nmc->nmc_config,
+			                              _("Edit '%s' value: "),
+			                              prop_name);
 
 			nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value);
 			nmc_property_set_default_value (curr_setting, prop_name);
 
-			if (!nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err)) {
+			if (!nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err)) {
 				g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
 				g_clear_error (&tmp_err);
 				g_signal_handlers_block_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL);
@@ -6879,19 +6997,20 @@ property_edit_submenu (NmCli *nmc,
 		case NMC_EDITOR_SUB_CMD_REMOVE:
 			if (cmd_property_arg) {
 				unsigned long val_int = G_MAXUINT32;
-				char *option = NULL;
+				gs_free char *option = NULL;
 
-				if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int))
+				if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int)) {
 					option = g_strdup (cmd_property_arg);
+					g_strstrip (option);
+				}
 
 				if (!nmc_setting_remove_property_option (curr_setting, prop_name,
-				                                         option ? g_strstrip (option) : NULL,
+				                                         option,
 				                                         (guint32) val_int,
 				                                         &tmp_err)) {
 					g_print (_("Error: %s\n"), tmp_err->message);
 					g_clear_error (&tmp_err);
 				}
-				g_free (option);
 			} else {
 				if (!nmc_setting_reset_property (curr_setting, prop_name, &tmp_err)) {
 					g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name,
@@ -6934,7 +7053,7 @@ property_edit_submenu (NmCli *nmc,
 
 		case NMC_EDITOR_SUB_CMD_QUIT:
 			if (is_connection_dirty (connection, *rem_con)) {
-				if (confirm_quit ())
+				if (confirm_quit (&nmc->nmc_config))
 					return FALSE;
 			} else
 				return FALSE;
@@ -6995,7 +7114,8 @@ create_setting_by_name (const char *name, const NMMetaSettingValidPartItem *cons
 }
 
 static const char *
-ask_check_setting (const char *arg,
+ask_check_setting (const NmcConfig *nmc_config,
+                   const char *arg,
                    const NMMetaSettingValidPartItem *const*valid_settings_main,
                    const NMMetaSettingValidPartItem *const*valid_settings_slave,
                    const char *valid_settings_str)
@@ -7006,12 +7126,12 @@ ask_check_setting (const char *arg,
 
 	if (!arg) {
 		g_print (_("Available settings: %s\n"), valid_settings_str);
-		setting_name_user = nmc_readline (EDITOR_PROMPT_SETTING);
+		setting_name_user = nmc_readline (nmc_config,
+		                                  EDITOR_PROMPT_SETTING);
 	} else
 		setting_name_user = g_strdup (arg);
 
-	if (setting_name_user)
-		g_strstrip (setting_name_user);
+	nm_strstrip (setting_name_user);
 
 	if (!(setting_name = check_valid_name (setting_name_user,
 	                                       valid_settings_main,
@@ -7025,7 +7145,8 @@ ask_check_setting (const char *arg,
 }
 
 static const char *
-ask_check_property (const char *arg,
+ask_check_property (const NmcConfig *nmc_config,
+                    const char *arg,
                     const char **valid_props,
                     const char *valid_props_str)
 {
@@ -7035,9 +7156,9 @@ ask_check_property (const char *arg,
 
 	if (!arg) {
 		g_print (_("Available properties: %s\n"), valid_props_str);
-		prop_name_user = nmc_readline (EDITOR_PROMPT_PROPERTY);
-		if (prop_name_user)
-			g_strstrip (prop_name_user);
+		prop_name_user = nmc_readline (nmc_config,
+		                               EDITOR_PROMPT_PROPERTY);
+		nm_strstrip (prop_name_user);
 	} else
 		prop_name_user = g_strdup (arg);
 
@@ -7064,7 +7185,9 @@ update_connection_timestamp (NMConnection *src, NMConnection *dst)
 }
 
 static gboolean
-confirm_connection_saving (NMConnection *local, NMConnection *remote)
+confirm_connection_saving (const NmcConfig *nmc_config,
+                           NMConnection *local,
+                           NMConnection *remote)
 {
 	NMSettingConnection *s_con_loc, *s_con_rem;
 	gboolean ac_local, ac_remote;
@@ -7082,16 +7205,15 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote)
 		ac_remote = FALSE;
 
 	if (ac_local && !ac_remote) {
-		char *answer;
-		answer = nmc_readline (_("Saving the connection with 'autoconnect=yes'. "
+		gs_free char *answer = NULL;
+
+		answer = nmc_readline (nmc_config,
+		                       _("Saving the connection with 'autoconnect=yes'. "
 		                         "That might result in an immediate activation of the connection.\n"
-		                         "Do you still want to save? %s"), prompt_yes_no (TRUE, NULL));
-		answer = answer ? g_strstrip (answer) : NULL;
-		if (!answer || matches (answer, WORD_YES))
-			confirmed = TRUE;
-		else
-			confirmed = FALSE;
-		g_free (answer);
+		                         "Do you still want to save? %s"),
+		                       prompt_yes_no (TRUE, NULL));
+		nm_strstrip (answer);
+		confirmed = (!answer || matches (answer, WORD_YES));
 	}
 	return confirmed;
 }
@@ -7196,9 +7318,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 		if (nmc->editor_status_line)
 			editor_show_status_line (connection, dirty, temp_changes);
 
-		cmd_user = nmc_readline ("%s", menu_ctx.main_prompt);
+		cmd_user = nmc_readline (&nmc->nmc_config,
+		                         "%s",
+		                         menu_ctx.main_prompt);
 
-		/* Get the remote connection again, it may have disapeared */
+		/* Get the remote connection again, it may have disappeared */
 		removed = refresh_remote_connection (&weak, &rem_con);
 		if (removed) {
 			g_print (_("The connection profile has been removed from another client. "
@@ -7208,7 +7332,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 		if (!cmd_user || !*cmd_user)
 			continue;
 
-		cmd = parse_editor_main_cmd (g_strstrip (cmd_user), &cmd_arg);
+		g_strstrip (cmd_user);
+
+		cmd = parse_editor_main_cmd (cmd_user, &cmd_arg);
 
 		split_editor_main_cmd_args (cmd_arg, &cmd_arg_s, &cmd_arg_p, &cmd_arg_v);
 		switch (cmd) {
@@ -7222,7 +7348,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					const char *const*avals;
 					GError *tmp_err = NULL;
 
-					prop_name = ask_check_property (cmd_arg,
+					prop_name = ask_check_property (&nmc->nmc_config,
+					                                cmd_arg,
 					                                (const char **) menu_ctx.valid_props,
 					                                menu_ctx.valid_props_str);
 					if (!prop_name)
@@ -7236,10 +7363,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 						g_print (_("Allowed values for '%s' property: %s\n"),
 						         prop_name, avals_str);
 					}
-					prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name);
+					prop_val_user = nmc_readline (&nmc->nmc_config,
+					                              _("Enter '%s' value: "),
+					                              prop_name);
 
 					/* Set property value */
-					if (!nmc_setting_set_property (menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) {
+					if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) {
 						g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
 						g_clear_error (&tmp_err);
 					}
@@ -7294,11 +7423,13 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 						g_print (_("Allowed values for '%s' property: %s\n"),
 						         prop_name, avals_str);
 					}
-					cmd_arg_v = nmc_readline (_("Enter '%s' value: "), prop_name);
+					cmd_arg_v = nmc_readline (&nmc->nmc_config,
+					                          _("Enter '%s' value: "),
+					                          prop_name);
 				}
 
 				/* Set property value */
-				if (!nmc_setting_set_property (ss, prop_name, cmd_arg_v, &tmp_err)) {
+				if (!nmc_setting_set_property (nmc->client, ss, prop_name, cmd_arg_v, &tmp_err)) {
 					g_print (_("Error: failed to set '%s' property: %s\n"),
 					         prop_name, tmp_err->message);
 					g_clear_error (&tmp_err);
@@ -7317,7 +7448,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				NMSetting *setting;
 				const char *user_arg = cmd_arg_s ?: cmd_arg_p;
 
-				setting_name = ask_check_setting (user_arg,
+				setting_name = ask_check_setting (&nmc->nmc_config,
+				                                  user_arg,
 				                                  valid_settings_main,
 				                                  valid_settings_slave,
 				                                  valid_settings_str);
@@ -7363,7 +7495,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				/* level 1 - setting selected */
 				const char *prop_name;
 
-				prop_name = ask_check_property (cmd_arg_p,
+				prop_name = ask_check_property (&nmc->nmc_config,
+				                                cmd_arg_p,
 				                                (const char **) menu_ctx.valid_props,
 				                                menu_ctx.valid_props_str);
 				if (!prop_name)
@@ -7386,7 +7519,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					GError *tmp_err = NULL;
 					const char *prop_name;
 
-					prop_name = ask_check_property (cmd_arg,
+					prop_name = ask_check_property (&nmc->nmc_config,
+					                                cmd_arg,
 					                                (const char **) menu_ctx.valid_props,
 					                                menu_ctx.valid_props_str);
 					if (!prop_name)
@@ -7480,7 +7614,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				if (menu_ctx.level == 1) {
 					const char *prop_name;
 
-					prop_name = ask_check_property (cmd_arg,
+					prop_name = ask_check_property (&nmc->nmc_config,
+					                                cmd_arg,
 					                                (const char **) menu_ctx.valid_props,
 					                                menu_ctx.valid_props_str);
 					if (!prop_name)
@@ -7682,9 +7817,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				}
 
 				/* Ask for save confirmation if the connection changes to autoconnect=yes */
-				if (nmc->editor_save_confirmation)
-					if (!confirm_connection_saving (connection, NM_CONNECTION (rem_con)))
+				if (nmc->editor_save_confirmation) {
+					if (!confirm_connection_saving (&nmc->nmc_config,
+					                                connection,
+					                                NM_CONNECTION (rem_con)))
 						break;
+				}
 
 				if (!rem_con) {
 					/* Tell the settings service to add the new connection */
@@ -7823,7 +7961,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				         nmc_editor_error->message);
 				g_error_free (nmc_editor_error);
 			} else {
-				nmc_readline (_("Monitoring connection activation (press any key to continue)\n"));
+				nmc_readline (&nmc->nmc_config,
+				              _("Monitoring connection activation (press any key to continue)\n"));
 			}
 
 			if (nmc_editor_monitor_ac) {
@@ -7897,7 +8036,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 
 		case NMC_EDITOR_MAIN_CMD_QUIT:
 			if (is_connection_dirty (connection, rem_con)) {
-				if (confirm_quit ())
+				if (confirm_quit (&nmc->nmc_config))
 					cmd_loop = FALSE;  /* quit command loop */
 			} else
 				cmd_loop = FALSE;  /* quit command loop */
@@ -8085,7 +8224,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 
 	/* Setup some readline completion stuff */
 	/* Set a pointer to an alternative function to create matches */
-	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_editor_tab_completion;
+	rl_attempted_completion_function = nmcli_editor_tab_completion;
 	/* Use ' ' and '.' as word break characters */
 	rl_completer_word_break_characters = ". ";
 
@@ -8173,8 +8312,9 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 				g_print (_("Error: invalid connection type; %s\n"), err1->message);
 			g_clear_error (&err1);
 
-			type_ask = nmc_readline (EDITOR_PROMPT_CON_TYPE);
-			type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
+			type_ask = nmc_readline (&nmc->nmc_config,
+			                         EDITOR_PROMPT_CON_TYPE);
+			type = type_ask = nm_strstrip (type_ask);
 			connection_type = check_valid_name_toplevel (type_ask, &slave_type, &err1);
 		}
 		nm_clear_g_free (&tmp_str);
@@ -8367,14 +8507,14 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 	argc_ptr = &argc;
 
 	if (argc == 0 && nmc->ask) {
-		char *line;
+		gs_free char *line = NULL;
 
 		/* nmc_do_cmd() should not call this with argc=0. */
 		g_assert (!nmc->complete);
 
-		line = nmc_readline (PROMPT_CONNECTION);
+		line = nmc_readline (&nmc->nmc_config,
+		                     PROMPT_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		g_free (line);
 		argv_ptr = &arg_arr;
 		argc_ptr = &arg_num;
 	}
@@ -8390,9 +8530,10 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 
 	if (argv[0])
 		new_name = *argv;
-	else if (nmc->ask)
-		new_name = new_name_ask = nmc_readline (_("New connection name: "));
-	else {
+	else if (nmc->ask) {
+		new_name = new_name_ask = nmc_readline (&nmc->nmc_config,
+		                                        _("New connection name: "));
+	} else {
 		g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
 		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
 	}
@@ -8477,14 +8618,14 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 
 	if (argc == 0) {
 		if (nmc->ask) {
-			char *line;
+			gs_free char *line = NULL;
 
 			/* nmc_do_cmd() should not call this with argc=0. */
 			g_assert (!nmc->complete);
 
-			line = nmc_readline (PROMPT_CONNECTIONS);
+			line = nmc_readline (&nmc->nmc_config,
+			                     PROMPT_CONNECTIONS);
 			nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-			g_free (line);
 			arg_ptr = arg_arr;
 		}
 		if (arg_num == 0) {
@@ -8733,10 +8874,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		g_assert (!nmc->complete);
 
 		if (nmc->ask) {
-			type_ask = nmc_readline ("%s: ", gettext (NM_META_TEXT_PROMPT_VPN_TYPE));
-			filename_ask = nmc_readline (gettext (PROMPT_IMPORT_FILE));
-			type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
-			filename = filename_ask = filename_ask ? g_strstrip (filename_ask) : NULL;
+			type_ask = nmc_readline (&nmc->nmc_config,
+			                         "%s: ",
+			                         gettext (NM_META_TEXT_PROMPT_VPN_TYPE));
+			type = nm_strstrip (type_ask);
+			filename_ask = nmc_readline (&nmc->nmc_config,
+			                             gettext (PROMPT_IMPORT_FILE));
+			filename = nm_strstrip (filename_ask);
 		} else {
 			g_string_printf (nmc->return_text, _("Error: No arguments provided."));
 			NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
@@ -8744,8 +8888,11 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 	}
 
 	while (argc > 0) {
-		if (argc == 1 && nmc->complete)
-			nmc_complete_strings (*argv, "type", "file", NULL);
+		if (argc == 1 && nmc->complete) {
+			nmc_complete_strings (*argv,
+			                      type ? NULL : "type",
+			                      filename ? NULL : "file");
+		}
 
 		if (strcmp (*argv, "type") == 0) {
 			argc--;
@@ -8755,8 +8902,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 				NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
 			}
 
-			if (argc == 1 && nmc->complete)
-				complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, *argv, NULL);
+			if (   argc == 1
+			    && nmc->complete) {
+				nmc_complete_strings (*argv, "wireguard");
+				complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type,
+				                 *argv,
+				                 NULL);
+			}
 
 			if (!type)
 				type = *argv;
@@ -8796,21 +8948,26 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
 	}
 
-	service_type = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), type);
-	if (!service_type) {
-		g_string_printf (nmc->return_text, _("Error: failed to find VPN plugin for %s."), type);
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
-	}
+	if (nm_streq (type, "wireguard"))
+		connection = nm_vpn_wireguard_import (filename, &error);
+	else {
+		service_type = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), type);
+		if (!service_type) {
+			g_string_printf (nmc->return_text, _("Error: failed to find VPN plugin for %s."), type);
+			NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+		}
 
-	/* Import VPN configuration */
-	plugin = nm_vpn_get_editor_plugin (service_type, &error);
-	if (!plugin) {
-		g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."),
-		                 error->message);
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+		/* Import VPN configuration */
+		plugin = nm_vpn_get_editor_plugin (service_type, &error);
+		if (!plugin) {
+			g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."),
+			                 error->message);
+			NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+		}
+
+		connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
 	}
 
-	connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."),
 		                 filename, error->message);
@@ -8853,14 +9010,14 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 	argc_ptr = &argc;
 
 	if (argc == 0 && nmc->ask) {
-		char *line;
+		gs_free char *line = NULL;
 
 		/* nmc_do_cmd() should not call this with argc=0. */
 		g_assert (!nmc->complete);
 
-		line = nmc_readline (PROMPT_VPN_CONNECTION);
+		line = nmc_readline (&nmc->nmc_config,
+		                     PROMPT_VPN_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		g_free (line);
 		argv_ptr = &arg_arr;
 		argc_ptr = &arg_num;
 	}
@@ -8883,8 +9040,10 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 		goto finish;
 	}
 
-	if (out_name == NULL && nmc->ask)
-		out_name = out_name_ask = nmc_readline (_("Output file name: "));
+	if (!out_name && nmc->ask) {
+		out_name = out_name_ask = nmc_readline (&nmc->nmc_config,
+		                                        _("Output file name: "));
+	}
 
 	type = nm_connection_get_connection_type (connection);
 	if (g_strcmp0 (type, NM_SETTING_VPN_SETTING_NAME) != 0) {
@@ -8908,7 +9067,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 	else {
 		nm_auto_close int fd = -1;
 
-		fd = g_mkstemp (tmpfile);
+		fd = g_mkstemp_full (tmpfile, O_RDWR | O_CLOEXEC, 0600);
 		if (fd == -1) {
 			g_string_printf (nmc->return_text, _("Error: failed to create temporary file %s."), tmpfile);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
@@ -9060,7 +9219,7 @@ do_connections (NmCli *nmc, int argc, char **argv)
 	nmc_start_polkit_agent_start_try (nmc);
 
 	/* Set completion function for 'nmcli con' */
-	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_tab_completion;
+	rl_attempted_completion_function = nmcli_con_tab_completion;
 
 	nmc_do_cmd (nmc, connection_cmds, *argv, argc, argv);