about summary refs log tree commit diff
path: root/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c')
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c1429
1 files changed, 809 insertions, 620 deletions
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 46bd2de1..164f6844 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -48,6 +48,7 @@
 #include "nm-setting-bridge.h"
 #include "nm-setting-bridge-port.h"
 #include "nm-setting-dcb.h"
+#include "nm-setting-user.h"
 #include "nm-setting-proxy.h"
 #include "nm-setting-generic.h"
 #include "nm-core-internal.h"
@@ -66,7 +67,7 @@
 #define _NMLOG_PREFIX_NAME "ifcfg-rh"
 #define _NMLOG(level, ...) \
     G_STMT_START { \
-        nm_log ((level), (_NMLOG_DOMAIN), \
+        nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \
                 "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
                 _NMLOG_PREFIX_NAME": " \
                 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
@@ -97,14 +98,13 @@ make_connection_name (shvarFile *ifcfg,
 	char *full_name = NULL, *name;
 
 	/* If the ifcfg file already has a NAME, always use that */
-	name = svGetValueString (ifcfg, "NAME");
-	if (name && strlen (name))
+	name = svGetValueStr_cp (ifcfg, "NAME");
+	if (name)
 		return name;
 
 	/* Otherwise construct a new NAME */
-	g_free (name);
 	if (!prefix)
-		prefix = _("System");
+		prefix = "System";
 
 	/* For cosmetic reasons, if the suggested name is the same as
 	 * the ifcfg files name, don't use it.  Mainly for wifi so that
@@ -142,22 +142,18 @@ make_connection_setting (const char *file,
 	g_free (new_id);
 
 	/* Try for a UUID key before falling back to hashing the file name */
-	uuid = svGetValueString (ifcfg, "UUID");
-	if (!uuid || !strlen (uuid)) {
-		g_free (uuid);
+	uuid = svGetValueStr_cp (ifcfg, "UUID");
+	if (!uuid)
 		uuid = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
-	}
-
-	stable_id = svGetValueString (ifcfg, "STABLE_ID");
 
 	g_object_set (s_con,
 	              NM_SETTING_CONNECTION_TYPE, type,
 	              NM_SETTING_CONNECTION_UUID, uuid,
-	              NM_SETTING_CONNECTION_STABLE_ID, stable_id,
+	              NM_SETTING_CONNECTION_STABLE_ID, svGetValue (ifcfg, "STABLE_ID", &stable_id),
 	              NULL);
 	g_free (uuid);
 
-	value = svGetValueString (ifcfg, "DEVICE");
+	value = svGetValueStr_cp (ifcfg, "DEVICE");
 	if (value) {
 		GError *error = NULL;
 
@@ -172,7 +168,7 @@ make_connection_setting (const char *file,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "LLDP");
+	value = svGetValueStr_cp (ifcfg, "LLDP");
 	if (!g_strcmp0 (value, "rx"))
 		lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX;
 	else
@@ -196,7 +192,7 @@ make_connection_setting (const char *file,
 	              NM_SETTING_CONNECTION_LLDP, lldp,
 	              NULL);
 
-	value = svGetValueString (ifcfg, "USERS");
+	value = svGetValueStr_cp (ifcfg, "USERS");
 	if (value) {
 		char **items, **iter;
 
@@ -212,15 +208,11 @@ make_connection_setting (const char *file,
 	}
 
 
-	zone = svGetValueString (ifcfg, "ZONE");
-	if (!zone || !strlen (zone)) {
-		g_free (zone);
-		zone = NULL;
-	}
+	zone = svGetValueStr_cp (ifcfg, "ZONE");
 	g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
 	g_free (zone);
 
-	value = svGetValueString (ifcfg, "SECONDARY_UUIDS");
+	value = svGetValueStr_cp (ifcfg, "SECONDARY_UUIDS");
 	if (value) {
 		char **items, **iter;
 
@@ -235,9 +227,9 @@ make_connection_setting (const char *file,
 		g_strfreev (items);
 	}
 
-	value = svGetValueString (ifcfg, "BRIDGE_UUID");
+	value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID");
 	if (!value)
-		value = svGetValueString (ifcfg, "BRIDGE");
+		value = svGetValueStr_cp (ifcfg, "BRIDGE");
 	if (value) {
 		const char *old_value;
 
@@ -252,7 +244,7 @@ make_connection_setting (const char *file,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "GATEWAY_PING_TIMEOUT");
+	value = svGetValueStr_cp (ifcfg, "GATEWAY_PING_TIMEOUT");
 	if (value) {
 		gint64 tmp;
 
@@ -280,75 +272,82 @@ make_connection_setting (const char *file,
 static gboolean
 read_ip4_address (shvarFile *ifcfg,
                   const char *tag,
-                  char **out_addr,
+                  gboolean *out_has_key,
+                  guint32 *out_addr,
                   GError **error)
 {
-	char *value = NULL;
-
-	g_return_val_if_fail (ifcfg != NULL, FALSE);
-	g_return_val_if_fail (tag != NULL, FALSE);
-	g_return_val_if_fail (out_addr != NULL, FALSE);
-	g_return_val_if_fail (!error || !*error, FALSE);
+	gs_free char *value_to_free = NULL;
+	const char *value;
+	guint32 a;
 
-	*out_addr = NULL;
+	nm_assert (ifcfg);
+	nm_assert (tag);
+	nm_assert (!error || !*error);
 
-	value = svGetValueString (ifcfg, tag);
-	if (!value)
+	value = svGetValueStr (ifcfg, tag, &value_to_free);
+	if (!value) {
+		NM_SET_OUT (out_has_key, FALSE);
+		NM_SET_OUT (out_addr, 0);
 		return TRUE;
+	}
 
-	if (nm_utils_ipaddr_valid (AF_INET, value)) {
-		*out_addr = value;
-		return TRUE;
-	} else {
+	if (inet_pton (AF_INET, value, &a) != 1) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Invalid %s IP4 address '%s'", tag, value);
-		g_free (value);
 		return FALSE;
 	}
+
+	NM_SET_OUT (out_has_key, TRUE);
+	NM_SET_OUT (out_addr, a);
+	return TRUE;
 }
 
-static char *
-get_numbered_tag (char *tag_name, int which)
+static void
+_numbered_tag (char *buf, gsize buf_len, const char *tag_name, int which)
 {
-	if (which == -1)
-		return g_strdup (tag_name);
-	return g_strdup_printf ("%s%u", tag_name, which);
+	gsize l;
+
+	l = g_strlcpy (buf, tag_name, buf_len);
+	nm_assert (l < buf_len);
+	if (which != -1) {
+		buf_len -= l;
+		l = g_snprintf (&buf[l], buf_len, "%d", which);
+		nm_assert (l < buf_len);
+	}
 }
+#define numbered_tag(buf, tag_name, which) \
+	({ \
+		_nm_unused char *const _buf = (buf); \
+		\
+		/* some static assert trying to ensure that the buffer is statically allocated.
+		 * It disallows a buffer size of sizeof(gpointer) to catch that. */ \
+		G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *) && sizeof (buf) < G_MAXINT); \
+		_numbered_tag (buf, sizeof (buf), ""tag_name"", (which)); \
+		buf; \
+	})
 
 static gboolean
 is_any_ip4_address_defined (shvarFile *ifcfg, int *idx)
 {
-	int i, ignore, *ret_idx;;
+	int i, ignore, *ret_idx;
 
 	ret_idx = idx ? idx : &ignore;
 
 	for (i = -1; i <= 2; i++) {
-		char *tag;
-		char *value;
+		gs_free char *value = NULL;
+		char tag[256];
 
-		tag = get_numbered_tag ("IPADDR", i);
-		value = svGetValueString (ifcfg, tag);
-		g_free (tag);
-		if (value) {
-			g_free (value);
+		if (svGetValueStr (ifcfg, numbered_tag (tag, "IPADDR", i), &value)) {
 			*ret_idx = i;
 			return TRUE;
 		}
 
-		tag = get_numbered_tag ("PREFIX", i);
-		value = svGetValueString (ifcfg, tag);
-		g_free(tag);
-		if (value) {
-			g_free (value);
+		if (svGetValueStr (ifcfg, numbered_tag (tag, "PREFIX", i), &value)) {
 			*ret_idx = i;
 			return TRUE;
 		}
 
-		tag = get_numbered_tag ("NETMASK", i);
-		value = svGetValueString (ifcfg, tag);
-		g_free(tag);
-		if (value) {
-			g_free (value);
+		if (svGetValueStr (ifcfg, numbered_tag (tag, "NETMASK", i), &value)) {
 			*ret_idx = i;
 			return TRUE;
 		}
@@ -365,12 +364,14 @@ read_full_ip4_address (shvarFile *ifcfg,
                        char **out_gateway,
                        GError **error)
 {
-	char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
-	char *ip = NULL;
+	char tag[256];
+	char prefix_tag[256];
+	guint32 ipaddr;
+	gs_free char *value = NULL;
 	int prefix = 0;
-	gboolean success = FALSE;
-	char *value;
-	guint32 tmp;
+	gboolean has_key;
+	guint32 a;
+	char inet_buf[NM_UTILS_INET_ADDRSTRLEN];
 
 	g_return_val_if_fail (which >= -1, FALSE);
 	g_return_val_if_fail (ifcfg != NULL, FALSE);
@@ -378,76 +379,186 @@ read_full_ip4_address (shvarFile *ifcfg,
 	g_return_val_if_fail (*out_address == NULL, FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
 
-	ip_tag = get_numbered_tag ("IPADDR", which);
-	prefix_tag = get_numbered_tag ("PREFIX", which);
-	netmask_tag = get_numbered_tag ("NETMASK", which);
-	gw_tag = get_numbered_tag ("GATEWAY", which);
-
 	/* IP address */
-	if (!read_ip4_address (ifcfg, ip_tag, &ip, error))
-		goto done;
-	if (!ip) {
-		if (base_addr)
-			ip = g_strdup (nm_ip_address_get_address (base_addr));
-		else {
-			success = TRUE;
-			goto done;
-		}
+	if (!read_ip4_address (ifcfg,
+	                       numbered_tag (tag, "IPADDR", which),
+	                       &has_key, &ipaddr, error))
+		return FALSE;
+	if (!has_key) {
+		if (!base_addr)
+			return TRUE;
+		nm_ip_address_get_address_binary (base_addr, &ipaddr);
 	}
 
 	/* Gateway */
 	if (out_gateway && !*out_gateway) {
-		if (!read_ip4_address (ifcfg, gw_tag, out_gateway, error))
-			goto done;
+		if (!read_ip4_address (ifcfg,
+		                       numbered_tag (tag, "GATEWAY", which),
+		                       &has_key, &a, error))
+			return FALSE;
+		if (has_key)
+			*out_gateway = g_strdup (nm_utils_inet4_ntop (a, inet_buf));
 	}
 
 	/* Prefix */
-	value = svGetValueString (ifcfg, prefix_tag);
+	numbered_tag (prefix_tag, "PREFIX", which);
+	value = svGetValueStr_cp (ifcfg, prefix_tag);
 	if (value) {
 		prefix = _nm_utils_ascii_str_to_int64 (value, 10, 0, 32, -1);
 		if (prefix < 0) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Invalid IP4 prefix '%s'", value);
-			g_free (value);
-			goto done;
+			return FALSE;
 		}
-		g_free (value);
 	} else {
 		/* Fall back to NETMASK if no PREFIX was specified */
-		if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
-			goto done;
-		if (value) {
-			inet_pton (AF_INET, value, &tmp);
-			prefix = nm_utils_ip4_netmask_to_prefix (tmp);
-			g_free (value);
-		} else {
+		if (!read_ip4_address (ifcfg,
+		                       numbered_tag (tag, "NETMASK", which),
+		                       &has_key, &a, error))
+			return FALSE;
+		if (has_key)
+			prefix = nm_utils_ip4_netmask_to_prefix (a);
+		else {
 			if (base_addr)
 				prefix = nm_ip_address_get_prefix (base_addr);
 			else {
 				/* Try to autodetermine the prefix for the address' class */
-				if (inet_pton (AF_INET, ip, &tmp) == 1) {
-					prefix = nm_utils_ip4_get_default_prefix (tmp);
-
-					PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, ip, prefix);
-				} else {
-					g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-					             "Missing IP4 prefix");
-					goto done;
-				}
+				prefix = nm_utils_ip4_get_default_prefix (ipaddr);
+				PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, nm_utils_inet4_ntop (ipaddr, inet_buf), prefix);
 			}
 		}
 	}
 
-	*out_address = nm_ip_address_new (AF_INET, ip, prefix, error);
+	*out_address = nm_ip_address_new_binary (AF_INET, &ipaddr, prefix, error);
 	if (*out_address)
-		success = TRUE;
+		return TRUE;
 
-done:
-	g_free (ip);
-	g_free (ip_tag);
-	g_free (prefix_tag);
-	g_free (netmask_tag);
-	g_free (gw_tag);
+	return FALSE;
+}
+
+/*
+ * Use looser syntax to comprise all the possibilities.
+ * The validity must be checked after the match.
+ */
+#define IPV4_ADDR_REGEX "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}"
+#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
+
+/*
+ * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
+ * namely destination IP without 'to' keyword is recognized just at line start.
+ */
+
+static gboolean
+parse_route_options (NMIPRoute *route, int family, const char *line, GError **error)
+{
+	GRegex *regex = NULL;
+	GMatchInfo *match_info = NULL;
+	gboolean success = FALSE;
+	static const char *metrics[] = { NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND,
+	                                 NM_IP_ROUTE_ATTRIBUTE_INITCWND, NM_IP_ROUTE_ATTRIBUTE_INITRWND,
+	                                 NM_IP_ROUTE_ATTRIBUTE_MTU, NULL };
+	char buffer[1024];
+	int i;
+
+	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+
+	for (i = 0; metrics[i]; i++) {
+		nm_sprintf_buf (buffer, "(?:\\s|^)%s\\s+(lock\\s+)?(\\d+)(?:$|\\s)", metrics[i]);
+		regex = g_regex_new (buffer, 0, 0, NULL);
+		g_regex_match (regex, line, 0, &match_info);
+		if (g_match_info_matches (match_info)) {
+			gs_free char *lock = g_match_info_fetch (match_info, 1);
+			gs_free char *str = g_match_info_fetch (match_info, 2);
+			gint64 num = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1);
+
+			if (num == -1) {
+				g_match_info_free (match_info);
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				             "Invalid route %s '%s'", metrics[i], str);
+				goto out;
+			}
+
+			nm_ip_route_set_attribute (route, metrics[i],
+			                           g_variant_new_uint32 (num));
+			if (lock && lock[0]) {
+				nm_sprintf_buf (buffer, "lock-%s", metrics[i]);
+				nm_ip_route_set_attribute (route, buffer,
+				                           g_variant_new_boolean (TRUE));
+			}
+		}
+		g_clear_pointer (&regex, g_regex_unref);
+		g_clear_pointer (&match_info, g_match_info_free);
+	}
+
+	/* tos */
+	regex = g_regex_new ("(?:\\s|^)tos\\s+(\\S+)(?:$|\\s)", 0, 0, NULL);
+	g_regex_match (regex, line, 0, &match_info);
+	if (g_match_info_matches (match_info)) {
+		gs_free char *str = g_match_info_fetch (match_info, 1);
+		gint64 num = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT8, -1);
+
+		if (num == -1) {
+			g_match_info_free (match_info);
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid route %s '%s'", "tos", str);
+			goto out;
+		}
+		nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TOS,
+		                           g_variant_new_byte ((guchar) num));
+	}
+	g_clear_pointer (&regex, g_regex_unref);
+	g_clear_pointer (&match_info, g_match_info_free);
+
+	/* from */
+	if (family == AF_INET6) {
+		regex = g_regex_new ("(?:\\s|^)from\\s+(" IPV6_ADDR_REGEX "(?:/\\d{1,3})?)(?:$|\\s)", 0, 0, NULL);
+		g_regex_match (regex, line, 0, &match_info);
+		if (g_match_info_matches (match_info)) {
+			gs_free char *str = g_match_info_fetch (match_info, 1);
+			gs_free_error GError *local_error = NULL;
+			GVariant *variant = g_variant_new_string (str);
+
+			if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_FROM, variant, family, NULL, &local_error)) {
+				g_match_info_free (match_info);
+				g_variant_unref (variant);
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				             "Invalid route from '%s': %s", str, local_error->message);
+				goto out;
+			}
+			nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_FROM, variant);
+		}
+		g_clear_pointer (&regex, g_regex_unref);
+		g_clear_pointer (&match_info, g_match_info_free);
+	}
+
+	if (family == AF_INET)
+		regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV4_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL);
+	else
+		regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV6_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL);
+	g_regex_match (regex, line, 0, &match_info);
+	if (g_match_info_matches (match_info)) {
+		gs_free char *str = g_match_info_fetch (match_info, 1);
+		gs_free_error GError *local_error = NULL;
+		GVariant *variant = g_variant_new_string (str);
+
+		if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_SRC, variant, family,
+		                                     NULL, &local_error)) {
+			g_match_info_free (match_info);
+			g_variant_unref (variant);
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid route src '%s': %s", str, local_error->message);
+			goto out;
+		}
+
+		nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_SRC, variant);
+	}
+	success = TRUE;
+
+out:
+	if (regex)
+		g_regex_unref (regex);
+	if (match_info)
+		g_match_info_free (match_info);
 
 	return success;
 }
@@ -459,87 +570,85 @@ read_one_ip4_route (shvarFile *ifcfg,
                     NMIPRoute **out_route,
                     GError **error)
 {
-	char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
-	char *dest = NULL, *next_hop = NULL;
+	char tag[256];
+	char netmask_tag[256];
+	guint32 dest;
+	guint32 next_hop;
+	guint32 netmask;
+	gboolean has_key;
+	gs_free char *value = NULL;
 	gint64 prefix, metric;
-	gboolean success = FALSE;
+	char inet_buf[NM_UTILS_INET_ADDRSTRLEN];
 
 	g_return_val_if_fail (ifcfg != NULL, FALSE);
 	g_return_val_if_fail (out_route != NULL, FALSE);
 	g_return_val_if_fail (*out_route == NULL, FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
 
-	ip_tag = g_strdup_printf ("ADDRESS%u", which);
-	netmask_tag = g_strdup_printf ("NETMASK%u", which);
-	gw_tag = g_strdup_printf ("GATEWAY%u", which);
-	metric_tag = g_strdup_printf ("METRIC%u", which);
-
 	/* Destination */
-	if (!read_ip4_address (ifcfg, ip_tag, &dest, error))
-		goto out;
-	if (!dest) {
-		/* Check whether IP is missing or 0.0.0.0 */
-		char *val;
-		val = svGetValueString (ifcfg, ip_tag);
-		if (!val) {
-			*out_route = NULL;
-			success = TRUE;  /* missing route = success */
-			goto out;
-		}
-		g_free (val);
+	if (!read_ip4_address (ifcfg,
+	                       numbered_tag (tag, "ADDRESS", which),
+	                       &has_key, &dest, error))
+		return FALSE;
+	if (!has_key) {
+		/* missing route = success */
+		*out_route = NULL;
+		return TRUE;
 	}
 
 	/* Next hop */
-	if (!read_ip4_address (ifcfg, gw_tag, &next_hop, error))
-		goto out;
+	if (!read_ip4_address (ifcfg,
+	                       numbered_tag (tag, "GATEWAY", which),
+	                       NULL, &next_hop, error))
+		return FALSE;
 	/* We don't make distinction between missing GATEWAY IP and 0.0.0.0 */
 
 	/* Prefix */
-	if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
-		goto out;
-	if (value) {
-		guint32 netmask;
-
-		inet_pton (AF_INET, value, &netmask);
+	if (!read_ip4_address (ifcfg,
+	                       numbered_tag (netmask_tag, "NETMASK", which),
+	                       &has_key, &netmask, error))
+		return FALSE;
+	if (has_key) {
 		prefix = nm_utils_ip4_netmask_to_prefix (netmask);
-		g_free (value);
 		if (prefix == 0 || netmask != nm_utils_ip4_prefix_to_netmask (prefix)) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, NULL));
-			goto out;
+			             "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf));
+			return FALSE;
 		}
 	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IP4 route element '%s'", netmask_tag);
-		goto out;
+		return FALSE;
 	}
 
 	/* Metric */
-	value = svGetValueString (ifcfg, metric_tag);
+	nm_clear_g_free (&value);
+	value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "METRIC", which));
 	if (value) {
 		metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
 		if (metric < 0) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Invalid IP4 route metric '%s'", value);
-			g_free (value);
-			goto out;
+			return FALSE;
 		}
-		g_free (value);
 	} else
 		metric = -1;
 
-	*out_route = nm_ip_route_new (AF_INET, dest, prefix, next_hop, metric, error);
-	if (*out_route)
-		success = TRUE;
+	*out_route = nm_ip_route_new_binary (AF_INET, &dest, prefix, &next_hop, metric, error);
+	if (!*out_route)
+		return FALSE;
 
-out:
-	g_free (dest);
-	g_free (next_hop);
-	g_free (ip_tag);
-	g_free (netmask_tag);
-	g_free (gw_tag);
-	g_free (metric_tag);
-	return success;
+	/* Options */
+	nm_clear_g_free (&value);
+	value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "OPTIONS", which));
+	if (value) {
+		if (!parse_route_options (*out_route, AF_INET, value, error)) {
+			g_clear_pointer (out_route, nm_ip_route_unref);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
 }
 
 static gboolean
@@ -665,6 +774,12 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 		route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error);
 		if (!route)
 			goto error;
+
+		if (!parse_route_options (route, AF_INET, *iter, error)) {
+			nm_ip_route_unref (route);
+			goto error;
+		}
+
 		if (!nm_setting_ip_config_add_route (s_ip4, route))
 			PARSE_WARNING ("duplicate IP4 route");
 		nm_ip_route_unref (route);
@@ -758,13 +873,6 @@ error:
 	return success;
 }
 
-/* IPv6 address is very complex to describe completely by a regular expression,
- * so don't try to, rather use looser syntax to comprise all possibilities
- * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
- * namely destination IP without 'to' keyword is recognized just at line start.
- */
-#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
-
 static gboolean
 read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error)
 {
@@ -786,6 +894,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 	const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")";       /* IPv6 of gateway */
 	const char *pattern_metric = "metric\\s+(\\d+)";                /* metric */
 
+
 	g_return_val_if_fail (filename != NULL, FALSE);
 	g_return_val_if_fail (s_ip6 != NULL, FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
@@ -891,6 +1000,12 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 		g_free (next_hop);
 		if (!route)
 			goto error;
+
+		if (!parse_route_options (route, AF_INET6, *iter, error)) {
+			nm_ip_route_unref (route);
+			goto error;
+		}
+
 		if (!nm_setting_ip_config_add_route (s_ip6, route))
 			PARSE_WARNING ("duplicate IP6 route");
 		nm_ip_route_unref (route);
@@ -910,13 +1025,61 @@ error:
 }
 
 static NMSetting *
+make_user_setting (shvarFile *ifcfg, GError **error)
+{
+	gboolean has_user_data = FALSE;
+	gs_unref_object NMSettingUser *s_user = NULL;
+	gs_unref_hashtable GHashTable *keys = NULL;
+	GHashTableIter iter;
+	const char *key;
+	nm_auto_free_gstring GString *str = NULL;
+
+	keys = svGetKeys (ifcfg);
+	if (!keys)
+		return NULL;
+
+	g_hash_table_iter_init (&iter, keys);
+	while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
+		const char *value;
+		gs_free char *value_to_free = NULL;
+
+		if (!g_str_has_prefix (key, "NM_USER_"))
+			continue;
+
+		value = svGetValue (ifcfg, key, &value_to_free);
+
+		if (!value)
+			continue;
+
+		if (!str)
+			str = g_string_sized_new (100);
+		else
+			g_string_set_size (str, 0);
+
+		if (!nms_ifcfg_rh_utils_user_key_decode (key + NM_STRLEN ("NM_USER_"), str))
+			continue;
+
+		if (!s_user)
+			s_user = NM_SETTING_USER (nm_setting_user_new ());
+
+		if (nm_setting_user_set_data (s_user, str->str,
+		                              value, NULL))
+			has_user_data = TRUE;
+	}
+
+	return has_user_data
+	       ? g_steal_pointer (&s_user)
+	       : NULL;
+}
+
+static NMSetting *
 make_proxy_setting (shvarFile *ifcfg, GError **error)
 {
 	NMSettingProxy *s_proxy = NULL;
 	char *value = NULL;
 	NMSettingProxyMethod method;
 
-	value = svGetValueString (ifcfg, "PROXY_METHOD");
+	value = svGetValueStr_cp (ifcfg, "PROXY_METHOD");
 	if (!value)
 		return NULL;
 
@@ -934,14 +1097,14 @@ make_proxy_setting (shvarFile *ifcfg, GError **error)
 		              NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_AUTO,
 		              NULL);
 
-		value = svGetValueString (ifcfg, "PAC_URL");
+		value = svGetValueStr_cp (ifcfg, "PAC_URL");
 		if (value) {
 			value = g_strstrip (value);
 			g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, value, NULL);
 			g_free (value);
 		}
 
-		value = svGetValueString (ifcfg, "PAC_SCRIPT");
+		value = svGetValueStr_cp (ifcfg, "PAC_SCRIPT");
 		if (value) {
 			value = g_strstrip (value);
 			g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, value, NULL);
@@ -956,7 +1119,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error)
 		break;
 	}
 
-	value = svGetValueString (ifcfg, "BROWSER_ONLY");
+	value = svGetValueStr_cp (ifcfg, "BROWSER_ONLY");
 	if (value) {
 		if (!g_ascii_strcasecmp (value, "yes"))
 			g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL);
@@ -969,21 +1132,27 @@ make_proxy_setting (shvarFile *ifcfg, GError **error)
 static NMSetting *
 make_ip4_setting (shvarFile *ifcfg,
                   const char *network_file,
+                  gboolean *out_has_defroute,
                   GError **error)
 {
-	NMSettingIPConfig *s_ip4 = NULL;
+	gs_unref_object NMSettingIPConfig *s_ip4 = NULL;
+	gs_free char *route_path = NULL;
 	char *value = NULL;
-	char *route_path = NULL;
 	char *method;
 	gs_free char *dns_options_free = NULL;
 	const char *dns_options = NULL;
 	gs_free char *gateway = NULL;
-	gint32 i;
+	int i;
+	guint32 a;
+	gboolean has_key;
 	shvarFile *network_ifcfg;
 	shvarFile *route_ifcfg;
-	gboolean never_default = FALSE;
+	gboolean never_default;
 	gint64 timeout;
 	gint priority;
+	char inet_buf[NM_UTILS_INET_ADDRSTRLEN];
+
+	nm_assert (out_has_defroute && !*out_has_defroute);
 
 	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
 
@@ -992,7 +1161,13 @@ make_ip4_setting (shvarFile *ifcfg,
 	 * specified is DEFROUTE=yes which means that this connection can be used
 	 * as a default route
 	 */
-	never_default = !svGetValueBoolean (ifcfg, "DEFROUTE", TRUE);
+	i = svGetValueBoolean (ifcfg, "DEFROUTE", -1);
+	if (i == -1)
+		never_default = FALSE;
+	else {
+		never_default = !i;
+		*out_has_defroute = TRUE;
+	}
 
 	/* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
 	network_ifcfg = svOpenFile (network_file, NULL);
@@ -1000,8 +1175,8 @@ make_ip4_setting (shvarFile *ifcfg,
 		char *gatewaydev;
 
 		/* Get the connection ifcfg device name and the global gateway device */
-		value = svGetValueString (ifcfg, "DEVICE");
-		gatewaydev = svGetValueString (network_ifcfg, "GATEWAYDEV");
+		value = svGetValueStr_cp (ifcfg, "DEVICE");
+		gatewaydev = svGetValueStr_cp (network_ifcfg, "GATEWAYDEV");
 		dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free);
 
 		/* If there was a global gateway device specified, then only connections
@@ -1015,7 +1190,7 @@ make_ip4_setting (shvarFile *ifcfg,
 		svCloseFile (network_ifcfg);
 	}
 
-	value = svGetValueString (ifcfg, "BOOTPROTO");
+	value = svGetValueStr_cp (ifcfg, "BOOTPROTO");
 
 	if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
 		if (is_any_ip4_address_defined (ifcfg, NULL))
@@ -1041,24 +1216,26 @@ make_ip4_setting (shvarFile *ifcfg,
 		              NULL);
 		/* 1 IP address is allowed for shared connections. Read it. */
 		if (is_any_ip4_address_defined (ifcfg, &idx)) {
+			guint32 gw;
 			NMIPAddress *addr = NULL;
 
 			if (!read_full_ip4_address (ifcfg, idx, NULL, &addr, NULL, error))
-				goto done;
-			if (!read_ip4_address (ifcfg, "GATEWAY", &gateway, error))
-				goto done;
+				return NULL;
+			if (!read_ip4_address (ifcfg, "GATEWAY", NULL, &gw, error))
+				return NULL;
 			(void) nm_setting_ip_config_add_address (s_ip4, addr);
 			nm_ip_address_unref (addr);
 			if (never_default)
 				PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
+			gateway = g_strdup (nm_utils_inet4_ntop (gw, inet_buf));
 			g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
 		}
-		return NM_SETTING (s_ip4);
+		return g_steal_pointer (&s_ip4);
 	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Unknown BOOTPROTO '%s'", value);
 		g_free (value);
-		goto done;
+		return NULL;
 	}
 	g_free (value);
 
@@ -1073,32 +1250,34 @@ make_ip4_setting (shvarFile *ifcfg,
 	              NULL);
 
 	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
-		return NM_SETTING (s_ip4);
+		return g_steal_pointer (&s_ip4);
 
 	/* Handle DHCP settings */
-	value = svGetValueString (ifcfg, "DHCP_HOSTNAME");
-	if (value && *value)
+	value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME");
+	if (value) {
 		g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL);
-	g_free (value);
+		g_free (value);
+	}
 
-	value = svGetValueString (ifcfg, "DHCP_FQDN");
-	if (value && *value) {
+	value = svGetValueStr_cp (ifcfg, "DHCP_FQDN");
+	if (value) {
 		g_object_set (s_ip4,
-			      NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL,
-			      NM_SETTING_IP4_CONFIG_DHCP_FQDN, value,
-			      NULL);
+		              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL,
+		              NM_SETTING_IP4_CONFIG_DHCP_FQDN, value,
+		              NULL);
+		g_free (value);
 	}
-	g_free (value);
 
 	g_object_set (s_ip4,
 		      NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE),
 		      NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0),
 		      NULL);
 
-	value = svGetValueString (ifcfg, "DHCP_CLIENT_ID");
-	if (value && strlen (value))
+	value = svGetValueStr_cp (ifcfg, "DHCP_CLIENT_ID");
+	if (value) {
 		g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
-	g_free (value);
+		g_free (value);
+	}
 
 	/* Read static IP addresses.
 	 * Read them even for AUTO method - in this case the addresses are
@@ -1111,7 +1290,7 @@ make_ip4_setting (shvarFile *ifcfg,
 		/* gateway will only be set if still unset. Hence, we don't leak gateway
 		 * here by calling read_full_ip4_address() repeatedly */
 		if (!read_full_ip4_address (ifcfg, i, NULL, &addr, &gateway, error))
-			goto done;
+			return NULL;
 
 		if (!addr) {
 			/* The first mandatory variable is 2-indexed (IPADDR2)
@@ -1132,16 +1311,17 @@ make_ip4_setting (shvarFile *ifcfg,
 		if (network_ifcfg) {
 			gboolean read_success;
 
-			read_success = read_ip4_address (network_ifcfg, "GATEWAY", &gateway, error);
+			read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error);
 			svCloseFile (network_ifcfg);
 			if (!read_success)
-				goto done;
-
-			if (gateway && nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
-				gs_free char *f = g_path_get_basename (svFileGetName (ifcfg));
-				PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s "
-				               "because the connection has no static addresses", f);
-				g_clear_pointer (&gateway, g_free);
+				return NULL;
+			if (has_key) {
+				if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
+					gs_free char *f = g_path_get_basename (svFileGetName (ifcfg));
+					PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s "
+					               "because the connection has no static addresses", f);
+				} else
+					gateway = g_strdup (nm_utils_inet4_ntop (a, inet_buf));
 			}
 		}
 	}
@@ -1154,10 +1334,10 @@ make_ip4_setting (shvarFile *ifcfg,
 	 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
 	 */
 	for (i = 1; i <= 10; i++) {
-		char *tag;
+		char tag[256];
 
-		tag = g_strdup_printf ("DNS%u", i);
-		value = svGetValueString (ifcfg, tag);
+		numbered_tag (tag, "DNS", i);
+		value = svGetValueStr_cp (ifcfg, tag);
 		if (value) {
 			if (nm_utils_ipaddr_valid (AF_INET, value)) {
 				if (!nm_setting_ip_config_add_dns (s_ip4, value))
@@ -1166,19 +1346,16 @@ make_ip4_setting (shvarFile *ifcfg,
 				/* Ignore IPv6 addresses */
 			} else {
 				PARSE_WARNING ("invalid DNS server address %s", value);
-				g_free (tag);
 				g_free (value);
-				goto done;
+				return NULL;
 			}
 
 			g_free (value);
 		}
-
-		g_free (tag);
 	}
 
 	/* DNS searches */
-	value = svGetValueString (ifcfg, "DOMAIN");
+	value = svGetValueStr_cp (ifcfg, "DOMAIN");
 	if (value) {
 		char **searches = NULL;
 
@@ -1222,7 +1399,7 @@ make_ip4_setting (shvarFile *ifcfg,
 
 				if (!read_one_ip4_route (route_ifcfg, i, &route, error)) {
 					svCloseFile (route_ifcfg);
-					goto done;
+					return NULL;
 				}
 
 				if (!route)
@@ -1236,13 +1413,12 @@ make_ip4_setting (shvarFile *ifcfg,
 		}
 	} else {
 		if (!read_route_file_legacy (route_path, s_ip4, error))
-			goto done;
+			return NULL;
 	}
-	g_free (route_path);
 
 	/* Legacy value NM used for a while but is incorrect (rh #459370) */
 	if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
-		value = svGetValueString (ifcfg, "SEARCH");
+		value = svGetValueStr_cp (ifcfg, "SEARCH");
 		if (value) {
 			char **searches = NULL;
 
@@ -1266,16 +1442,11 @@ make_ip4_setting (shvarFile *ifcfg,
 	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT,
 	              (gint) (timeout <= 0 ? timeout : timeout * 1000), NULL);
 
-	return NM_SETTING (s_ip4);
-
-done:
-	g_free (route_path);
-	g_object_unref (s_ip4);
-	return NULL;
+	return g_steal_pointer (&s_ip4);
 }
 
 static void
-read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
+read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *filename)
 {
 	GDir *dir;
 	char *dirname, *base;
@@ -1301,6 +1472,7 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
 		gboolean ok;
 
 		while ((item = g_dir_read_name (dir))) {
+			gs_free char *gateway = NULL;
 			char *full_path, *device;
 			const char *p;
 
@@ -1329,7 +1501,7 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
 				continue;
 			}
 
-			device = svGetValueString (parsed, "DEVICE");
+			device = svGetValueStr_cp (parsed, "DEVICE");
 			if (!device) {
 				PARSE_WARNING ("alias file '%s' has no DEVICE", full_path);
 				svCloseFile (parsed);
@@ -1347,12 +1519,30 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
 			}
 
 			addr = NULL;
-			ok = read_full_ip4_address (parsed, -1, base_addr, &addr, NULL, &err);
-			svCloseFile (parsed);
+			ok = read_full_ip4_address (parsed, -1, base_addr, &addr,
+			                            read_defroute ? &gateway : NULL,
+			                            &err);
 			if (ok) {
 				nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device));
 				if (!nm_setting_ip_config_add_address (s_ip4, addr))
 					PARSE_WARNING ("duplicate IP4 address in alias file %s", item);
+				if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
+					g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL);
+				if (read_defroute) {
+					int i;
+
+					if (gateway) {
+						g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
+						read_defroute = FALSE;
+					}
+					i = svGetValueBoolean (parsed, "DEFROUTE", -1);
+					if (i != -1) {
+						g_object_set (s_ip4,
+						              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, (gboolean) !i,
+						              NULL);
+						read_defroute = FALSE;
+					}
+				}
 			} else {
 				PARSE_WARNING ("error reading IP4 address from alias file '%s': %s",
 				               full_path, err ? err->message : "no address");
@@ -1360,6 +1550,8 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
 			}
 			nm_ip_address_unref (addr);
 
+			svCloseFile (parsed);
+
 			g_free (device);
 			g_free (full_path);
 		}
@@ -1416,9 +1608,9 @@ make_ip6_setting (shvarFile *ifcfg,
 		char *default_dev = NULL;
 
 		/* Get the connection ifcfg device name and the global default route device */
-		value = svGetValueString (ifcfg, "DEVICE");
-		ipv6_defaultgw = svGetValueString (network_ifcfg, "IPV6_DEFAULTGW");
-		ipv6_defaultdev = svGetValueString (network_ifcfg, "IPV6_DEFAULTDEV");
+		value = svGetValueStr_cp (ifcfg, "DEVICE");
+		ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW");
+		ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV");
 		dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free);
 
 		if (ipv6_defaultgw) {
@@ -1443,7 +1635,7 @@ make_ip6_setting (shvarFile *ifcfg,
 
 	/* Find out method property */
 	/* Is IPV6 enabled? Set method to "ignored", when not enabled */
-	str_value = svGetValueString (ifcfg, "IPV6INIT");
+	str_value = svGetValueStr_cp (ifcfg, "IPV6INIT");
 	ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE);
 	if (!str_value) {
 		network_ifcfg = svOpenFile (network_file, NULL);
@@ -1458,7 +1650,7 @@ make_ip6_setting (shvarFile *ifcfg,
 		method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE;  /* IPv6 is disabled */
 	else {
 		ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE);
-		str_value = svGetValueString (ifcfg, "IPV6_AUTOCONF");
+		str_value = svGetValueStr_cp (ifcfg, "IPV6_AUTOCONF");
 		dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE);
 
 		if (!g_strcmp0 (str_value, "shared"))
@@ -1470,9 +1662,9 @@ make_ip6_setting (shvarFile *ifcfg,
 		else {
 			/* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
 			g_free (str_value);
-			str_value = svGetValueString (ifcfg, "IPV6ADDR");
+			str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR");
 			if (!str_value)
-				str_value = svGetValueString (ifcfg, "IPV6ADDR_SECONDARIES");
+				str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES");
 
 			if (!str_value)
 				method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
@@ -1482,7 +1674,7 @@ make_ip6_setting (shvarFile *ifcfg,
 	/* TODO - handle other methods */
 
 	/* Read IPv6 Privacy Extensions configuration */
-	str_value = svGetValueString (ifcfg, "IPV6_PRIVACY");
+	str_value = svGetValueStr_cp (ifcfg, "IPV6_PRIVACY");
 	if (str_value) {
 		ip6_privacy = svParseBoolean (str_value, FALSE);
 		if (!ip6_privacy)
@@ -1512,13 +1704,13 @@ make_ip6_setting (shvarFile *ifcfg,
 	if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
 		return NM_SETTING (s_ip6);
 
-	value = svGetValueString (ifcfg, "DHCPV6_HOSTNAME");
+	value = svGetValueStr_cp (ifcfg, "DHCPV6_HOSTNAME");
 	/* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is
 	 * auto or dhcp: this is required to support old ifcfg files
 	 */
 	if (!value && (   !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
 		       || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP))) {
-		value = svGetValueString (ifcfg, "DHCP_HOSTNAME");
+		value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME");
 		if (value && !strchr (value, '.'))
 			g_clear_pointer (&value, g_free);
 	}
@@ -1534,8 +1726,8 @@ make_ip6_setting (shvarFile *ifcfg,
 	 * added to the automatic ones. Note that this is not currently supported by
 	 * the legacy 'network' service (ifup-eth).
 	 */
-	ipv6addr = svGetValueString (ifcfg, "IPV6ADDR");
-	ipv6addr_secondaries = svGetValueString (ifcfg, "IPV6ADDR_SECONDARIES");
+	ipv6addr = svGetValueStr_cp (ifcfg, "IPV6ADDR");
+	ipv6addr_secondaries = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES");
 
 	value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
 	                   ipv6addr ? ipv6addr : "",
@@ -1562,12 +1754,12 @@ make_ip6_setting (shvarFile *ifcfg,
 
 	/* Gateway */
 	if (nm_setting_ip_config_get_num_addresses (s_ip6)) {
-		value = svGetValueString (ifcfg, "IPV6_DEFAULTGW");
+		value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW");
 		if (!value) {
 			/* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */
 			network_ifcfg = svOpenFile (network_file, NULL);
 			if (network_ifcfg) {
-				value = svGetValueString (network_ifcfg, "IPV6_DEFAULTGW");
+				value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW");
 				svCloseFile (network_ifcfg);
 			}
 		}
@@ -1588,7 +1780,7 @@ make_ip6_setting (shvarFile *ifcfg,
 	}
 
 	/* IPv6 addressing mode configuration */
-	str_value = svGetValueString (ifcfg, "IPV6_ADDR_GEN_MODE");
+	str_value = svGetValueStr_cp (ifcfg, "IPV6_ADDR_GEN_MODE");
 	if (str_value) {
 		if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), str_value,
 		                            (int *) &addr_gen_mode, NULL))
@@ -1604,7 +1796,7 @@ make_ip6_setting (shvarFile *ifcfg,
 	}
 
 	/* IPv6 tokenized interface identifier */
-	str_value = svGetValueString (ifcfg, "IPV6_TOKEN");
+	str_value = svGetValueStr_cp (ifcfg, "IPV6_TOKEN");
 	if (str_value) {
 		g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, str_value, NULL);
 		g_free (str_value);
@@ -1614,13 +1806,13 @@ make_ip6_setting (shvarFile *ifcfg,
 	 * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
 	 */
 	for (i = 1; i <= 10; i++) {
-		char *tag;
+		char tag[256];
 
-		tag = g_strdup_printf ("DNS%u", i);
-		value = svGetValueString (ifcfg, tag);
+		numbered_tag (tag, "DNS", i);
+		value = svGetValueStr_cp (ifcfg, tag);
 		if (!value) {
-			g_free (tag);
-			break; /* all done */
+			/* all done */
+			break;
 		}
 
 		if (nm_utils_ipaddr_valid (AF_INET6, value)) {
@@ -1630,12 +1822,10 @@ make_ip6_setting (shvarFile *ifcfg,
 			/* Ignore IPv4 addresses */
 		} else {
 			PARSE_WARNING ("invalid DNS server address %s", value);
-			g_free (tag);
 			g_free (value);
 			goto error;
 		}
 
-		g_free (tag);
 		g_free (value);
 	}
 
@@ -1676,9 +1866,9 @@ check_if_bond_slave (shvarFile *ifcfg,
 {
 	char *value;
 
-	value = svGetValueString (ifcfg, "MASTER_UUID");
+	value = svGetValueStr_cp (ifcfg, "MASTER_UUID");
 	if (!value)
-		value = svGetValueString (ifcfg, "MASTER");
+		value = svGetValueStr_cp (ifcfg, "MASTER");
 
 	if (value) {
 		g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
@@ -1699,9 +1889,9 @@ check_if_team_slave (shvarFile *ifcfg,
 {
 	gs_free char *value = NULL;
 
-	value = svGetValueString (ifcfg, "TEAM_MASTER_UUID");
+	value = svGetValueStr_cp (ifcfg, "TEAM_MASTER_UUID");
 	if (!value)
-		value = svGetValueString (ifcfg, "TEAM_MASTER");
+		value = svGetValueStr_cp (ifcfg, "TEAM_MASTER");
 	if (!value)
 		return FALSE;
 
@@ -1777,7 +1967,7 @@ read_dcb_app (shvarFile *ifcfg,
 
 	/* Priority */
 	tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app);
-	val = svGetValueString (ifcfg, tmp);
+	val = svGetValueStr_cp (ifcfg, tmp);
 	if (val) {
 		priority = _nm_utils_ascii_str_to_int64 (val, 0, 0, 7, -1);
 		if (priority < 0) {
@@ -1814,26 +2004,23 @@ read_dcb_bool_array (shvarFile *ifcfg,
                      DcbSetBoolFunc set_func,
                      GError **error)
 {
-	char *val;
-	gboolean success = FALSE;
+	gs_free char *val = NULL;
 	guint i;
 
-	val = svGetValueString (ifcfg, prop);
+	val = svGetValueStr_cp (ifcfg, prop);
 	if (!val)
 		return TRUE;
 
 	if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
 		PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
-		success = TRUE;
-		goto out;
+		return TRUE;
 	}
 
-	val = g_strstrip (val);
 	if (strlen (val) != 8) {
 		PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "boolean array must be 8 characters");
-		goto out;
+		return FALSE;
 	}
 
 	/* All characters must be either 0 or 1 */
@@ -1842,15 +2029,11 @@ read_dcb_bool_array (shvarFile *ifcfg,
 			PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, val);
 			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			                     "invalid boolean digit");
-			goto out;
+			return FALSE;
 		}
 		set_func (s_dcb, i, (val[i] == '1'));
 	}
-	success = TRUE;
-
-out:
-	g_free (val);
-	return success;
+	return TRUE;
 }
 
 typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint);
@@ -1865,26 +2048,23 @@ read_dcb_uint_array (shvarFile *ifcfg,
                      DcbSetUintFunc set_func,
                      GError **error)
 {
-	char *val;
-	gboolean success = FALSE;
+	gs_free char *val = NULL;
 	guint i;
 
-	val = svGetValueString (ifcfg, prop);
+	val = svGetValueStr_cp (ifcfg, prop);
 	if (!val)
 		return TRUE;
 
 	if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
 		PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
-		success = TRUE;
-		goto out;
+		return TRUE;
 	}
 
-	val = g_strstrip (val);
 	if (strlen (val) != 8) {
 		PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "uint array must be 8 characters");
-		goto out;
+		return FALSE;
 	}
 
 	/* All characters must be either 0 - 7 or (optionally) f */
@@ -1898,14 +2078,11 @@ read_dcb_uint_array (shvarFile *ifcfg,
 			               prop, val, f_allowed ? " or 'f'" : "");
 			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			                     "invalid uint digit");
-			goto out;
+			return FALSE;
 		}
 	}
-	success = TRUE;
 
-out:
-	g_free (val);
-	return success;
+	return TRUE;
 }
 
 static gboolean
@@ -1918,28 +2095,26 @@ read_dcb_percent_array (shvarFile *ifcfg,
                         DcbSetUintFunc set_func,
                         GError **error)
 {
-	char *val;
-	gboolean success = FALSE;
-	char **split = NULL, **iter;
+	gs_free char *val = NULL;
+	gs_strfreev char **split = NULL;
+	char **iter;
 	guint i, sum = 0;
 
-	val = svGetValueString (ifcfg, prop);
+	val = svGetValueStr_cp (ifcfg, prop);
 	if (!val)
 		return TRUE;
 
 	if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
 		PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
-		success = TRUE;
-		goto out;
+		return TRUE;
 	}
 
-	val = g_strstrip (val);
 	split = g_strsplit_set (val, ",", 0);
 	if (!split || (g_strv_length (split) != 8)) {
 		PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val);
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "percent array must be 8 elements");
-		goto out;
+		return FALSE;
 	}
 
 	for (iter = split, i = 0; iter && *iter; iter++, i++) {
@@ -1950,7 +2125,7 @@ read_dcb_percent_array (shvarFile *ifcfg,
 			PARSE_WARNING ("invalid %s percentage value '%s'", prop, *iter);
 			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			                     "invalid percent element");
-			goto out;
+			return FALSE;
 		}
 		set_func (s_dcb, i, (guint) tmp);
 		sum += (guint) tmp;
@@ -1960,16 +2135,10 @@ read_dcb_percent_array (shvarFile *ifcfg,
 		PARSE_WARNING ("%s percentages do not equal 100%%", prop);
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "invalid percentage sum");
-		goto out;
+		return FALSE;
 	}
 
-	success = TRUE;
-
-out:
-	if (split)
-		g_strfreev (split);
-	g_free (val);
-	return success;
+	return TRUE;
 }
 
 static gboolean
@@ -2001,7 +2170,7 @@ make_dcb_setting (shvarFile *ifcfg,
 		return FALSE;
 	}
 	if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) {
-		val = svGetValueString (ifcfg, KEY_DCB_APP_FCOE_MODE);
+		val = svGetValueStr_cp (ifcfg, KEY_DCB_APP_FCOE_MODE);
 		if (val) {
 			if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 ||
 			    strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0)
@@ -2138,11 +2307,9 @@ add_one_wep_key (shvarFile *ifcfg,
 	g_return_val_if_fail (key_idx <= 3, FALSE);
 	g_return_val_if_fail (s_wsec != NULL, FALSE);
 
-	value = svGetValueString (ifcfg, shvar_key);
-	if (!value || !strlen (value)) {
-		g_free (value);
+	value = svGetValueStr_cp (ifcfg, shvar_key);
+	if (!value)
 		return TRUE;
-	}
 
 	/* Validate keys */
 	if (passphrase) {
@@ -2195,9 +2362,10 @@ add_one_wep_key (shvarFile *ifcfg,
 		nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
 		g_free (key);
 		success = TRUE;
-	} else
+	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Invalid WEP key length.");
+	}
 
 out:
 	g_free (value);
@@ -2245,7 +2413,7 @@ read_secret_flags (shvarFile *ifcfg, const char *flags_key)
 	g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
 	g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
 
-	val = svGetValueString (ifcfg, flags_key);
+	val = svGetValueStr_cp (ifcfg, flags_key);
 	if (val) {
 		if (strstr (val, SECRET_FLAG_AGENT))
 			flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
@@ -2264,7 +2432,7 @@ make_wep_setting (shvarFile *ifcfg,
                   const char *file,
                   GError **error)
 {
-	NMSettingWirelessSecurity *s_wsec;
+	gs_unref_object NMSettingWirelessSecurity *s_wsec = NULL;
 	char *value;
 	shvarFile *keys_ifcfg = NULL;
 	int default_key_idx = 0;
@@ -2274,14 +2442,14 @@ make_wep_setting (shvarFile *ifcfg,
 	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
 	g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
 
-	value = svGetValueString (ifcfg, "DEFAULTKEY");
+	value = svGetValueStr_cp (ifcfg, "DEFAULTKEY");
 	if (value) {
 		default_key_idx = _nm_utils_ascii_str_to_int64 (value, 0, 1, 4, 0);
 		if (default_key_idx == 0) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Invalid default WEP key '%s'", value);
 			g_free (value);
-			goto error;
+			return NULL;
 		}
 		has_default_key = TRUE;
 		default_key_idx--;  /* convert to [0...3] */
@@ -2296,21 +2464,21 @@ make_wep_setting (shvarFile *ifcfg,
 	/* Read keys in the ifcfg file if they are system-owned */
 	if (key_flags == NM_SETTING_SECRET_FLAG_NONE) {
 		if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error))
-			goto error;
+			return NULL;
 
 		/* Try to get keys from the "shadow" key file */
 		keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
 		if (keys_ifcfg) {
 			if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) {
 				svCloseFile (keys_ifcfg);
-				goto error;
+				return NULL;
 			}
 			svCloseFile (keys_ifcfg);
 			g_assert (error == NULL || *error == NULL);
 		}
 	}
 
-	value = svGetValueString (ifcfg, "SECURITYMODE");
+	value = svGetValueStr_cp (ifcfg, "SECURITYMODE");
 	if (value) {
 		char *lcase;
 
@@ -2326,7 +2494,7 @@ make_wep_setting (shvarFile *ifcfg,
 			             "Invalid WEP authentication algorithm '%s'",
 			             lcase);
 			g_free (lcase);
-			goto error;
+			return NULL;
 		}
 		g_free (lcase);
 	}
@@ -2347,20 +2515,14 @@ make_wep_setting (shvarFile *ifcfg,
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "WEP Shared Key authentication is invalid for "
 			             "unencrypted connections.");
-			goto error;
+			return NULL;
 		}
 
 		/* Unencrypted */
-		g_object_unref (s_wsec);
-		s_wsec = NULL;
+		return NULL;
 	}
 
-	return (NMSetting *) s_wsec;
-
-error:
-	if (s_wsec)
-		g_object_unref (s_wsec);
-	return NULL;
+	return g_steal_pointer (&s_wsec);
 }
 
 static gboolean
@@ -2373,7 +2535,7 @@ fill_wpa_ciphers (shvarFile *ifcfg,
 	char **list = NULL, **iter;
 	int i = 0;
 
-	p = value = svGetValueString (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE");
+	p = value = svGetValueStr_cp (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE");
 	if (!value)
 		return TRUE;
 
@@ -2443,13 +2605,13 @@ parse_wpa_psk (shvarFile *ifcfg,
 	/* Try to get keys from the "shadow" key file */
 	keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
 	if (keys_ifcfg) {
-		psk = svGetValueString (keys_ifcfg, "WPA_PSK");
+		psk = svGetValueStr_cp (keys_ifcfg, "WPA_PSK");
 		svCloseFile (keys_ifcfg);
 	}
 
 	/* Fall back to the original ifcfg */
 	if (!psk)
-		psk = svGetValueString (ifcfg, "WPA_PSK");
+		psk = svGetValueStr_cp (ifcfg, "WPA_PSK");
 
 	if (!psk)
 		return NULL;
@@ -2486,7 +2648,7 @@ eap_simple_reader (const char *eap_method,
 	NMSettingSecretFlags flags;
 	char *value;
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY");
 	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
@@ -2501,10 +2663,10 @@ eap_simple_reader (const char *eap_method,
 
 	/* Only read the password if it's system-owned */
 	if (flags == NM_SETTING_SECRET_FLAG_NONE) {
-		value = svGetValueString (ifcfg, "IEEE_8021X_PASSWORD");
+		value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PASSWORD");
 		if (!value && keys) {
 			/* Try the lookaside keys file */
-			value = svGetValueString (keys, "IEEE_8021X_PASSWORD");
+			value = svGetValueStr_cp (keys, "IEEE_8021X_PASSWORD");
 		}
 
 		if (!value) {
@@ -2543,6 +2705,19 @@ get_full_file_path (const char *ifcfg_path, const char *file_path)
 	return ret;
 }
 
+static char *
+get_cert_value (const char *ifcfg_path, const char *value,
+                NMSetting8021xCKScheme *out_scheme)
+{
+	if (strncmp (value, "pkcs11:", 7) == 0) {
+		*out_scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11;
+		return g_strdup (value);
+	}
+
+	*out_scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
+	return get_full_file_path (ifcfg_path, value);
+}
+
 static gboolean
 eap_tls_reader (const char *eap_method,
                 shvarFile *ifcfg,
@@ -2551,48 +2726,58 @@ eap_tls_reader (const char *eap_method,
                 gboolean phase2,
                 GError **error)
 {
+	gs_free char *ca_cert = NULL;
+	gs_free char *privkey = NULL;
+	gs_free char *privkey_password = NULL;
 	char *value;
-	char *ca_cert = NULL;
-	char *real_path = NULL;
-	char *client_cert = NULL;
-	char *privkey = NULL;
-	char *privkey_password = NULL;
-	gboolean success = FALSE;
+	char *ca_cert_password = NULL;
+	char *client_cert_password = NULL;
 	NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
 	const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
-	const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
-	const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
+	const char *ca_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD";
+	const char *ca_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD;
+	const char *ca_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CA_CERT_PASSWORD_FLAGS";
+	const char *ca_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS;
 	const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
-	const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
+	const char *cli_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD";
+	const char *cli_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD;
+	const char *cli_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CLIENT_CERT_PASSWORD_FLAGS";
+	const char *cli_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS;
+	const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
+	const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
+	const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS" : "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
 	const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
 	NMSettingSecretFlags flags;
+	NMSetting8021xCKScheme scheme;
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY");
 	if (value) {
 		g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
 		g_free (value);
 	}
 
-	ca_cert = svGetValueString (ifcfg, ca_cert_key);
+	ca_cert = svGetValueStr_cp (ifcfg, ca_cert_key);
 	if (ca_cert) {
-		real_path = get_full_file_path (svFileGetName (ifcfg), ca_cert);
+		gs_free char *real_cert_value = NULL;
+
+		real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme);
 		if (phase2) {
-			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
-			                                           real_path,
-			                                           NM_SETTING_802_1X_CK_SCHEME_PATH,
-			                                           NULL,
-			                                           error))
-				goto done;
+			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
+				return FALSE;
 		} else {
-			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-			                                    real_path,
-			                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
-			                                    NULL,
-			                                    error))
-				goto done;
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
+				return FALSE;
+		}
+
+		if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
+			flags = read_secret_flags (ifcfg, ca_cert_pw_flags_key);
+			g_object_set (s_8021x, ca_cert_pw_flags_prop, flags, NULL);
+
+			if (flags == NM_SETTING_SECRET_FLAG_NONE) {
+				ca_cert_password = svGetValueStr_cp (ifcfg, ca_cert_pw_key);
+				g_object_set (s_8021x, ca_cert_pw_prop, ca_cert_password, NULL);
+			}
 		}
-		g_free (real_path);
-		real_path = NULL;
 	} else {
 		PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!",
 		               ca_cert_key, eap_method);
@@ -2605,10 +2790,10 @@ eap_tls_reader (const char *eap_method,
 	/* Read the private key password if it's system-owned */
 	if (flags == NM_SETTING_SECRET_FLAG_NONE) {
 		/* Private key password */
-		privkey_password = svGetValueString (ifcfg, pk_pw_key);
+		privkey_password = svGetValueStr_cp (ifcfg, pk_pw_key);
 		if (!privkey_password && keys) {
 			/* Try the lookaside keys file */
-			privkey_password = svGetValueString (keys, pk_pw_key);
+			privkey_password = svGetValueStr_cp (keys, pk_pw_key);
 		}
 
 		if (!privkey_password) {
@@ -2616,40 +2801,42 @@ eap_tls_reader (const char *eap_method,
 			             "Missing %s for EAP method '%s'.",
 			             pk_pw_key,
 			             eap_method);
-			goto done;
+			return FALSE;
 		}
 	}
 
 	/* The private key itself */
-	privkey = svGetValueString (ifcfg, pk_key);
+	privkey = svGetValueStr_cp (ifcfg, pk_key);
 	if (!privkey) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing %s for EAP method '%s'.",
 		             pk_key,
 		             eap_method);
-		goto done;
+		return FALSE;
 	}
 
-	real_path = get_full_file_path (svFileGetName (ifcfg), privkey);
-	if (phase2) {
-		if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
-		                                               real_path,
-		                                               privkey_password,
-		                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
-		                                               &privkey_format,
-		                                               error))
-			goto done;
-	} else {
-		if (!nm_setting_802_1x_set_private_key (s_8021x,
-		                                        real_path,
-		                                        privkey_password,
-		                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
-		                                        &privkey_format,
-		                                        error))
-			goto done;
+	{
+		gs_free char *real_cert_value = NULL;
+
+		real_cert_value = get_cert_value (svFileGetName (ifcfg), privkey, &scheme);
+		if (phase2) {
+			if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
+			                                               real_cert_value,
+			                                               privkey_password,
+			                                               scheme,
+			                                               &privkey_format,
+			                                               error))
+				return FALSE;
+		} else {
+			if (!nm_setting_802_1x_set_private_key (s_8021x,
+			                                        real_cert_value,
+			                                        privkey_password,
+			                                        scheme,
+			                                        &privkey_format,
+			                                        error))
+				return FALSE;
+		}
 	}
-	g_free (real_path);
-	real_path = NULL;
 
 	/* Only set the client certificate if the private key is not PKCS#12 format,
 	 * as NM (due to supplicant restrictions) requires.  If the key was PKCS#12,
@@ -2658,44 +2845,39 @@ eap_tls_reader (const char *eap_method,
 	 */
 	if (   privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
 	    || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
-		client_cert = svGetValueString (ifcfg, cli_cert_key);
+		gs_free char *real_cert_value = NULL;
+		gs_free char *client_cert = NULL;
+
+		client_cert = svGetValueStr_cp (ifcfg, cli_cert_key);
 		if (!client_cert) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Missing %s for EAP method '%s'.",
 			             cli_cert_key,
 			             eap_method);
-			goto done;
+			return FALSE;
 		}
 
-		real_path = get_full_file_path (svFileGetName (ifcfg), client_cert);
+		real_cert_value = get_cert_value (svFileGetName (ifcfg), client_cert, &scheme);
 		if (phase2) {
-			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
-			                                               real_path,
-			                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
-			                                               NULL,
-			                                               error))
-				goto done;
+			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, real_cert_value, scheme, NULL, error))
+				return FALSE;
 		} else {
-			if (!nm_setting_802_1x_set_client_cert (s_8021x,
-			                                        real_path,
-			                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
-			                                        NULL,
-			                                        error))
-				goto done;
+			if (!nm_setting_802_1x_set_client_cert (s_8021x, real_cert_value, scheme, NULL, error))
+				return FALSE;
 		}
-		g_free (real_path);
-		real_path = NULL;
-	}
 
-	success = TRUE;
+		if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
+			flags = read_secret_flags (ifcfg, cli_cert_pw_flags_key);
+			g_object_set (s_8021x, cli_cert_pw_flags_prop, flags, NULL);
 
-done:
-	g_free (real_path);
-	g_free (ca_cert);
-	g_free (client_cert);
-	g_free (privkey);
-	g_free (privkey_password);
-	return success;
+			if (flags == NM_SETTING_SECRET_FLAG_NONE) {
+				client_cert_password = svGetValueStr_cp (ifcfg, cli_cert_pw_key);
+				g_object_set (s_8021x, cli_cert_pw_prop, client_cert_password, NULL);
+			}
+		}
+	}
+
+	return TRUE;
 }
 
 static gboolean
@@ -2708,28 +2890,25 @@ eap_peap_reader (const char *eap_method,
 {
 	char *anon_ident = NULL;
 	char *ca_cert = NULL;
-	char *real_cert_path = NULL;
+	char *real_cert_value = NULL;
 	char *inner_auth = NULL;
 	char *peapver = NULL;
 	char *lower;
 	char **list = NULL, **iter;
 	gboolean success = FALSE;
+	NMSetting8021xCKScheme scheme;
 
-	ca_cert = svGetValueString (ifcfg, "IEEE_8021X_CA_CERT");
+	ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT");
 	if (ca_cert) {
-		real_cert_path = get_full_file_path (svFileGetName (ifcfg), ca_cert);
-		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-		                                    real_cert_path,
-		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
-		                                    NULL,
-		                                    error))
+		real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme);
+		if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
 			goto done;
 	} else {
 		PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
 		               eap_method);
 	}
 
-	peapver = svGetValueString (ifcfg, "IEEE_8021X_PEAP_VERSION");
+	peapver = svGetValueStr_cp (ifcfg, "IEEE_8021X_PEAP_VERSION");
 	if (peapver) {
 		if (!strcmp (peapver, "0"))
 			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
@@ -2746,11 +2925,11 @@ eap_peap_reader (const char *eap_method,
 	if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE))
 		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
 
-	anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY");
-	if (anon_ident && strlen (anon_ident))
+	anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY");
+	if (anon_ident)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
 
-	inner_auth = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
+	inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
 	if (!inner_auth) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
@@ -2797,7 +2976,7 @@ done:
 		g_strfreev (list);
 	g_free (inner_auth);
 	g_free (peapver);
-	g_free (real_cert_path);
+	g_free (real_cert_value);
 	g_free (ca_cert);
 	g_free (anon_ident);
 	return success;
@@ -2814,30 +2993,27 @@ eap_ttls_reader (const char *eap_method,
 	gboolean success = FALSE;
 	char *anon_ident = NULL;
 	char *ca_cert = NULL;
-	char *real_cert_path = NULL;
+	char *real_cert_value = NULL;
 	char *inner_auth = NULL;
 	char *tmp;
 	char **list = NULL, **iter;
+	NMSetting8021xCKScheme scheme;
 
-	ca_cert = svGetValueString (ifcfg, "IEEE_8021X_CA_CERT");
+	ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT");
 	if (ca_cert) {
-		real_cert_path = get_full_file_path (svFileGetName (ifcfg), ca_cert);
-		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-		                                    real_cert_path,
-		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
-		                                    NULL,
-		                                    error))
+		real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme);
+		if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
 			goto done;
 	} else {
 		PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
 		               eap_method);
 	}
 
-	anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY");
-	if (anon_ident && strlen (anon_ident))
+	anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY");
+	if (anon_ident)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
 
-	tmp = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
+	tmp = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
 	if (!tmp) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
@@ -2885,7 +3061,7 @@ done:
 	if (list)
 		g_strfreev (list);
 	g_free (inner_auth);
-	g_free (real_cert_path);
+	g_free (real_cert_value);
 	g_free (ca_cert);
 	g_free (anon_ident);
 	return success;
@@ -2906,17 +3082,17 @@ eap_fast_reader (const char *eap_method,
 	char *fast_provisioning = NULL;
 	char *lower;
 	char **list = NULL, **iter;
-	const char* pac_prov_str;
+	const char *pac_prov_str;
 	gboolean allow_unauth = FALSE, allow_auth = FALSE;
 	gboolean success = FALSE;
 
-	pac_file = svGetValueString (ifcfg, "IEEE_8021X_PAC_FILE");
+	pac_file = svGetValueStr_cp (ifcfg, "IEEE_8021X_PAC_FILE");
 	if (pac_file) {
 		real_pac_path = get_full_file_path (svFileGetName (ifcfg), pac_file);
 		g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
 	}
 
-	fast_provisioning = svGetValueString (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
+	fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
 	if (fast_provisioning) {
 		list = g_strsplit_set (fast_provisioning, " \t", 0);
 		for (iter = list; iter && *iter; iter++) {
@@ -2944,11 +3120,11 @@ eap_fast_reader (const char *eap_method,
 		goto done;
 	}
 
-	anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY");
-	if (anon_ident && strlen (anon_ident))
+	anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY");
+	if (anon_ident)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
 
-	inner_auth = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
+	inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
 	if (!inner_auth) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
@@ -2998,12 +3174,12 @@ done:
 
 typedef struct {
 	const char *method;
-	gboolean (*reader)(const char *eap_method,
-	                   shvarFile *ifcfg,
-	                   shvarFile *keys,
-	                   NMSetting8021x *s_8021x,
-	                   gboolean phase2,
-	                   GError **error);
+	gboolean (*reader) (const char *eap_method,
+	                    shvarFile *ifcfg,
+	                    shvarFile *keys,
+	                    NMSetting8021x *s_8021x,
+	                    gboolean phase2,
+	                    GError **error);
 	gboolean wifi_phase2_only;
 } EAPReader;
 
@@ -3035,7 +3211,7 @@ read_8021x_list_value (shvarFile *ifcfg,
 	g_return_if_fail (ifcfg_var_name != NULL);
 	g_return_if_fail (prop_name != NULL);
 
-	value = svGetValueString (ifcfg, ifcfg_var_name);
+	value = svGetValueStr_cp (ifcfg, ifcfg_var_name);
 	if (!value)
 		return;
 
@@ -3053,12 +3229,13 @@ fill_8021x (shvarFile *ifcfg,
             gboolean wifi,
             GError **error)
 {
+	nm_auto_shvar_file_close shvarFile *keys = NULL;
 	NMSetting8021x *s_8021x;
-	shvarFile *keys = NULL;
 	char *value;
 	char **list = NULL, **iter;
+	gint64 timeout;
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_EAP_METHODS");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_EAP_METHODS");
 	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
@@ -3104,7 +3281,7 @@ fill_8021x (shvarFile *ifcfg,
 			found = TRUE;
 			break;
 
-		next:
+next:
 			eap++;
 		}
 
@@ -3119,37 +3296,54 @@ fill_8021x (shvarFile *ifcfg,
 		goto error;
 	}
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_SUBJECT_MATCH");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_SUBJECT_MATCH");
 	g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, value, NULL);
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH");
 	g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, value, NULL);
 	g_free (value);
 
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS");
+	if (value) {
+		NMSetting8021xAuthFlags flags;
+		char *token;
+
+		if (nm_utils_enum_from_str (nm_setting_802_1x_auth_flags_get_type (), value,
+		                            (int *) &flags, &token)) {
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, flags, NULL);
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid IEEE_8021X_PHASE1_AUTH_FLAGS flag '%s'", token);
+			g_free (token);
+			g_free (value);
+			goto error;
+		}
+		g_free (value);
+	}
+
 	read_8021x_list_value (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES",
 	                       s_8021x, NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
 	read_8021x_list_value (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES",
 	                       s_8021x, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH");
 	g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, value, NULL);
 	g_free (value);
-	value = svGetValueString (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH");
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH");
 	g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, value, NULL);
 	g_free (value);
 
+	timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0);
+	g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (gint32) timeout, NULL);
+
 	if (list)
 		g_strfreev (list);
-	if (keys)
-		svCloseFile (keys);
 	return s_8021x;
 
 error:
 	if (list)
 		g_strfreev (list);
-	if (keys)
-		svCloseFile (keys);
 	g_object_unref (s_8021x);
 	return NULL;
 }
@@ -3168,7 +3362,7 @@ make_wpa_setting (shvarFile *ifcfg,
 
 	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
 
-	value = svGetValueString (ifcfg, "KEY_MGMT");
+	value = svGetValueStr_cp (ifcfg, "KEY_MGMT");
 	wpa_psk = !g_strcmp0 (value, "WPA-PSK");
 	wpa_eap = !g_strcmp0 (value, "WPA-EAP");
 	ieee8021x = !g_strcmp0 (value, "IEEE8021X");
@@ -3188,8 +3382,8 @@ make_wpa_setting (shvarFile *ifcfg,
 	} else {
 		char *allow_wpa, *allow_rsn;
 
-		allow_wpa = svGetValueString (ifcfg, "WPA_ALLOW_WPA");
-		allow_rsn = svGetValueString (ifcfg, "WPA_ALLOW_WPA2");
+		allow_wpa = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA");
+		allow_rsn = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA2");
 
 		if (allow_wpa && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA", TRUE))
 			nm_setting_wireless_security_add_proto (wsec, "wpa");
@@ -3243,7 +3437,7 @@ make_wpa_setting (shvarFile *ifcfg,
 
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "SECURITYMODE");
+	value = svGetValueStr_cp (ifcfg, "SECURITYMODE");
 	if (NM_IN_STRSET (value, NULL, "open"))
 		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, value, NULL);
 
@@ -3269,12 +3463,12 @@ make_leap_setting (shvarFile *ifcfg,
 
 	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
 
-	value = svGetValueString (ifcfg, "KEY_MGMT");
+	value = svGetValueStr_cp (ifcfg, "KEY_MGMT");
 	if (!value || strcmp (value, "IEEE8021X"))
 		goto error; /* Not LEAP */
 
 	g_free (value);
-	value = svGetValueString (ifcfg, "SECURITYMODE");
+	value = svGetValueStr_cp (ifcfg, "SECURITYMODE");
 	if (!value || strcasecmp (value, "leap"))
 		goto error; /* Not LEAP */
 
@@ -3285,12 +3479,12 @@ make_leap_setting (shvarFile *ifcfg,
 
 	/* Read LEAP password if it's system-owned */
 	if (flags == NM_SETTING_SECRET_FLAG_NONE) {
-		value = svGetValueString (ifcfg, "IEEE_8021X_PASSWORD");
+		value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PASSWORD");
 		if (!value) {
 			/* Try to get keys from the "shadow" key file */
 			keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
 			if (keys_ifcfg) {
-				value = svGetValueString (keys_ifcfg, "IEEE_8021X_PASSWORD");
+				value = svGetValueStr_cp (keys_ifcfg, "IEEE_8021X_PASSWORD");
 				svCloseFile (keys_ifcfg);
 			}
 		}
@@ -3299,8 +3493,8 @@ make_leap_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY");
-	if (!value || !strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY");
+	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Missing LEAP identity");
 		goto error;
@@ -3392,25 +3586,25 @@ make_wireless_setting (shvarFile *ifcfg,
 
 	s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
 
-	value = svGetValueString (ifcfg, "HWADDR");
+	value = svGetValueStr_cp (ifcfg, "HWADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "MACADDR");
+	value = svGetValueStr_cp (ifcfg, "MACADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK");
+	value = svGetValueStr_cp (ifcfg, "GENERATE_MAC_ADDRESS_MASK");
 	g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL);
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "HWADDR_BLACKLIST");
+	value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST");
 	if (value) {
 		char **strv;
 
@@ -3420,7 +3614,7 @@ make_wireless_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "ESSID");
+	value = svGetValueStr_cp (ifcfg, "ESSID");
 	if (value) {
 		gs_unref_bytes GBytes *bytes = NULL;
 		gsize ssid_len = 0;
@@ -3449,7 +3643,7 @@ make_wireless_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "MODE");
+	value = svGetValueStr_cp (ifcfg, "MODE");
 	if (value) {
 		char *lcase;
 		const char *mode = NULL;
@@ -3475,14 +3669,14 @@ make_wireless_setting (shvarFile *ifcfg,
 		g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
 	}
 
-	value = svGetValueString (ifcfg, "BSSID");
+	value = svGetValueStr_cp (ifcfg, "BSSID");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "CHANNEL");
+	value = svGetValueStr_cp (ifcfg, "CHANNEL");
 	if (value) {
 		errno = 0;
 		chan = _nm_utils_ascii_str_to_int64 (value, 10, 1, 196, 0);
@@ -3496,7 +3690,7 @@ make_wireless_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "BAND");
+	value = svGetValueStr_cp (ifcfg, "BAND");
 	if (value) {
 		if (!strcmp (value, "a")) {
 			if (chan && chan <= 14) {
@@ -3527,7 +3721,7 @@ make_wireless_setting (shvarFile *ifcfg,
 			g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
 	}
 
-	value = svGetValueString (ifcfg, "MTU");
+	value = svGetValueStr_cp (ifcfg, "MTU");
 	if (value) {
 		int mtu;
 
@@ -3637,7 +3831,7 @@ wireless_connection_from_ifcfg (const char *file,
 		printable_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL),
 		                                        g_bytes_get_size (ssid));
 	} else
-		printable_ssid = g_strdup_printf ("unmanaged");
+		printable_ssid = g_strdup ("unmanaged");
 
 	mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
 	if (mode && !strcmp (mode, "adhoc"))
@@ -3856,7 +4050,7 @@ parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *va
 	}
 
 	/* ETHTOOL_WAKE_ON_LAN = ignore overrides WoL settings in ETHTOOL_OPTS */
-	wol_value = svGetValueString (ifcfg, "ETHTOOL_WAKE_ON_LAN");
+	wol_value = svGetValueStr_cp (ifcfg, "ETHTOOL_WAKE_ON_LAN");
 	if (wol_value) {
 		if (strcmp (wol_value, "ignore") == 0)
 			wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
@@ -3891,7 +4085,7 @@ make_wired_setting (shvarFile *ifcfg,
 
 	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
 
-	value = svGetValueString (ifcfg, "MTU");
+	value = svGetValueStr_cp (ifcfg, "MTU");
 	if (value) {
 		int mtu;
 
@@ -3903,14 +4097,14 @@ make_wired_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "HWADDR");
+	value = svGetValueStr_cp (ifcfg, "HWADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "SUBCHANNELS");
+	value = svGetValueStr_cp (ifcfg, "SUBCHANNELS");
 	if (value) {
 		const char *p = value;
 		gboolean success = TRUE;
@@ -3941,28 +4135,29 @@ make_wired_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "PORTNAME");
-	if (value && strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "PORTNAME");
+	if (value) {
 		nm_setting_wired_add_s390_option (s_wired, "portname", value);
+		g_free (value);
 	}
-	g_free (value);
 
-	value = svGetValueString (ifcfg, "CTCPROT");
-	if (value && strlen (value))
+	value = svGetValueStr_cp (ifcfg, "CTCPROT");
+	if (value) {
 		nm_setting_wired_add_s390_option (s_wired, "ctcprot", value);
-	g_free (value);
+		g_free (value);
+	}
 
-	nettype = svGetValueString (ifcfg, "NETTYPE");
-	if (nettype && strlen (nettype)) {
+	nettype = svGetValueStr_cp (ifcfg, "NETTYPE");
+	if (nettype) {
 		if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc"))
 			g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL);
 		else
 			PARSE_WARNING ("unknown s390 NETTYPE '%s'", nettype);
+		g_free (nettype);
 	}
-	g_free (nettype);
 
-	value = svGetValueString (ifcfg, "OPTIONS");
-	if (value && strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "OPTIONS");
+	if (value) {
 		char **options, **iter;
 
 		iter = options = g_strsplit_set (value, " ", 0);
@@ -3979,21 +4174,21 @@ make_wired_setting (shvarFile *ifcfg,
 			iter++;
 		}
 		g_strfreev (options);
+		g_free (value);
 	}
-	g_free (value);
 
-	value = svGetValueString (ifcfg, "MACADDR");
+	value = svGetValueStr_cp (ifcfg, "MACADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK");
+	value = svGetValueStr_cp (ifcfg, "GENERATE_MAC_ADDRESS_MASK");
 	g_object_set (s_wired, NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, value, NULL);
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "HWADDR_BLACKLIST");
+	value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST");
 	if (value) {
 		char **strv;
 
@@ -4003,7 +4198,7 @@ make_wired_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "KEY_MGMT");
+	value = svGetValueStr_cp (ifcfg, "KEY_MGMT");
 	if (value) {
 		if (!strcmp (value, "IEEE8021X")) {
 			*s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
@@ -4078,19 +4273,19 @@ parse_infiniband_p_key (shvarFile *ifcfg,
 	int id;
 	gboolean ret = FALSE;
 
-	device = svGetValueString (ifcfg, "DEVICE");
+	device = svGetValueStr_cp (ifcfg, "DEVICE");
 	if (!device) {
 		PARSE_WARNING ("InfiniBand connection specified PKEY but not DEVICE");
 		goto done;
 	}
 
-	physdev = svGetValueString (ifcfg, "PHYSDEV");
+	physdev = svGetValueStr_cp (ifcfg, "PHYSDEV");
 	if (!physdev) {
 		PARSE_WARNING ("InfiniBand connection specified PKEY but not PHYSDEV");
 		goto done;
 	}
 
-	pkey_id = svGetValueString (ifcfg, "PKEY_ID");
+	pkey_id = svGetValueStr_cp (ifcfg, "PKEY_ID");
 	if (!pkey_id) {
 		PARSE_WARNING ("InfiniBand connection specified PKEY but not PKEY_ID");
 		goto done;
@@ -4138,7 +4333,7 @@ make_infiniband_setting (shvarFile *ifcfg,
 
 	s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
 
-	value = svGetValueString (ifcfg, "MTU");
+	value = svGetValueStr_cp (ifcfg, "MTU");
 	if (value) {
 		int mtu;
 
@@ -4150,7 +4345,7 @@ make_infiniband_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "HWADDR");
+	value = svGetValueStr_cp (ifcfg, "HWADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, value, NULL);
@@ -4248,17 +4443,17 @@ make_bond_setting (shvarFile *ifcfg,
 	NMSettingBond *s_bond;
 	char *value;
 
-	s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
-
-	value = svGetValueString (ifcfg, "DEVICE");
-	if (!value || !strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "DEVICE");
+	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "mandatory DEVICE keyword missing");
-		goto error;
+		return NULL;
 	}
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "BONDING_OPTS");
+	s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
+
+	value = svGetValueStr_cp (ifcfg, "BONDING_OPTS");
 	if (value) {
 		char **items, **iter;
 
@@ -4271,7 +4466,7 @@ make_bond_setting (shvarFile *ifcfg,
 				if (keys && *keys) {
 					key = *keys;
 					val = *(keys + 1);
-					if (val && strlen(key) && strlen(val))
+					if (val && key[0] && val[0])
 						handle_bond_option (s_bond, key, val);
 				}
 
@@ -4283,10 +4478,6 @@ make_bond_setting (shvarFile *ifcfg,
 	}
 
 	return (NMSetting *) s_bond;
-
-error:
-	g_object_unref (s_bond);
-	return NULL;
 }
 
 static NMConnection *
@@ -4342,7 +4533,7 @@ read_team_config (shvarFile *ifcfg, const char *key, GError **error)
 	gs_free char *value = NULL;
 	size_t l;
 
-	value = svGetValueString (ifcfg, key);
+	value = svGetValueStr_cp (ifcfg, key);
 	if (!value)
 		return NULL;
 
@@ -4370,29 +4561,26 @@ make_team_setting (shvarFile *ifcfg,
 	char *value;
 	GError *local_err = NULL;
 
-	s_team = NM_SETTING_TEAM (nm_setting_team_new ());
-
-	value = svGetValueString (ifcfg, "DEVICE");
-	if (!value || !strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "DEVICE");
+	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "mandatory DEVICE keyword missing");
-		goto error;
+		return NULL;
 	}
 	g_free (value);
 
 	value = read_team_config (ifcfg, "TEAM_CONFIG", &local_err);
 	if (local_err) {
 		g_propagate_error (error, local_err);
-		goto error;
+		return NULL;
 	}
+
+	s_team = NM_SETTING_TEAM (nm_setting_team_new ());
+
 	g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
 	g_free (value);
 
 	return (NMSetting *) s_team;
-
-error:
-	g_object_unref (s_team);
-	return NULL;
 }
 
 static NMConnection *
@@ -4454,23 +4642,23 @@ handle_bridge_option (NMSetting *setting,
 	guint32 u = 0;
 
 	if (!strcmp (key, "priority")) {
-		if (stp == FALSE) {
+		if (stp == FALSE)
 			PARSE_WARNING ("'priority' invalid when STP is disabled");
-		} else if (get_uint (value, &u))
+		else if (get_uint (value, &u))
 			g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL);
 		else
 			PARSE_WARNING ("invalid priority value '%s'", value);
 	} else if (!strcmp (key, "hello_time")) {
-		if (stp == FALSE) {
+		if (stp == FALSE)
 			PARSE_WARNING ("'hello_time' invalid when STP is disabled");
-		} else if (get_uint (value, &u))
+		else if (get_uint (value, &u))
 			g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL);
 		else
 			PARSE_WARNING ("invalid hello_time value '%s'", value);
 	} else if (!strcmp (key, "max_age")) {
-		if (stp == FALSE) {
+		if (stp == FALSE)
 			PARSE_WARNING ("'max_age' invalid when STP is disabled");
-		} else if (get_uint (value, &u))
+		else if (get_uint (value, &u))
 			g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL);
 		else
 			PARSE_WARNING ("invalid max_age value '%s'", value);
@@ -4506,7 +4694,7 @@ handle_bridging_opts (NMSetting *setting,
 			if (keys && *keys) {
 				key = *keys;
 				val = *(keys + 1);
-				if (val && strlen(key) && strlen(val))
+				if (val && strlen (key) && strlen (val))
 					func (setting, stp, key, val);
 			}
 
@@ -4527,24 +4715,24 @@ make_bridge_setting (shvarFile *ifcfg,
 	gboolean stp = FALSE;
 	gboolean stp_set = FALSE;
 
-	s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
-
-	value = svGetValueString (ifcfg, "DEVICE");
-	if (!value || !strlen (value)) {
+	value = svGetValueStr_cp (ifcfg, "DEVICE");
+	if (!value) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "mandatory DEVICE keyword missing");
-		goto error;
+		return NULL;
 	}
 	g_free (value);
 
-	value = svGetValueString (ifcfg, "MACADDR");
+	s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
+
+	value = svGetValueStr_cp (ifcfg, "MACADDR");
 	if (value) {
 		value = g_strstrip (value);
 		g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL);
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "STP");
+	value = svGetValueStr_cp (ifcfg, "STP");
 	if (value) {
 		if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {
 			g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL);
@@ -4563,7 +4751,7 @@ make_bridge_setting (shvarFile *ifcfg,
 		g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
 	}
 
-	value = svGetValueString (ifcfg, "DELAY");
+	value = svGetValueStr_cp (ifcfg, "DELAY");
 	if (value) {
 		if (stp) {
 			if (get_uint (value, &u))
@@ -4575,17 +4763,13 @@ make_bridge_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	value = svGetValueString (ifcfg, "BRIDGING_OPTS");
+	value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS");
 	if (value) {
 		handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option);
 		g_free (value);
 	}
 
 	return (NMSetting *) s_bridge;
-
-error:
-	g_object_unref (s_bridge);
-	return NULL;
 }
 
 static NMConnection *
@@ -4616,7 +4800,7 @@ bridge_connection_from_ifcfg (const char *file,
 		g_object_unref (connection);
 		return NULL;
 	}
-	nm_connection_add_setting (connection, bridge_setting);	
+	nm_connection_add_setting (connection, bridge_setting);
 
 	return connection;
 }
@@ -4658,14 +4842,14 @@ make_bridge_port_setting (shvarFile *ifcfg)
 
 	g_return_val_if_fail (ifcfg != NULL, FALSE);
 
-	value = svGetValueString (ifcfg, "BRIDGE_UUID");
+	value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID");
 	if (!value)
-		value = svGetValueString (ifcfg, "BRIDGE");
+		value = svGetValueStr_cp (ifcfg, "BRIDGE");
 	if (value) {
 		g_free (value);
 
 		s_port = nm_setting_bridge_port_new ();
-		value = svGetValueString (ifcfg, "BRIDGING_OPTS");
+		value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS");
 		if (value)
 			handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option);
 		g_free (value);
@@ -4742,7 +4926,7 @@ parse_prio_map_list (NMSettingVlan *s_vlan,
 	char *value;
 	gchar **list = NULL, **iter;
 
-	value = svGetValueString (ifcfg, key);
+	value = svGetValueStr_cp (ifcfg, key);
 	if (!value)
 		return;
 
@@ -4764,16 +4948,16 @@ make_vlan_setting (shvarFile *ifcfg,
                    const char *file,
                    GError **error)
 {
-	NMSettingVlan *s_vlan = NULL;
+	gs_unref_object NMSettingVlan *s_vlan = NULL;
+	gs_free char *parent = NULL;
+	gs_free char *iface_name = NULL;
 	char *value = NULL;
-	char *iface_name = NULL;
-	char *parent = NULL;
 	const char *p = NULL;
 	int vlan_id = -1;
 	guint32 vlan_flags = 0;
 	gint gvrp, reorder_hdr;
 
-	value = svGetValueString (ifcfg, "VLAN_ID");
+	value = svGetValueStr_cp (ifcfg, "VLAN_ID");
 	if (value) {
 		vlan_id = _nm_utils_ascii_str_to_int64 (value, 10, 0, 4095, -1);
 		if (vlan_id == -1) {
@@ -4786,7 +4970,7 @@ make_vlan_setting (shvarFile *ifcfg,
 	}
 
 	/* Need DEVICE if we don't have a separate VLAN_ID property */
-	iface_name = svGetValueString (ifcfg, "DEVICE");
+	iface_name = svGetValueStr_cp (ifcfg, "DEVICE");
 	if (!iface_name && vlan_id < 0) {
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "Missing DEVICE property; cannot determine VLAN ID.");
@@ -4796,7 +4980,7 @@ make_vlan_setting (shvarFile *ifcfg,
 	s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
 
 	/* Parent interface from PHYSDEV takes precedence if it exists */
-	parent = svGetValueString (ifcfg, "PHYSDEV");
+	parent = svGetValueStr_cp (ifcfg, "PHYSDEV");
 
 	if (iface_name) {
 		p = strchr (iface_name, '.');
@@ -4808,8 +4992,7 @@ make_vlan_setting (shvarFile *ifcfg,
 					/* Like initscripts, if no PHYSDEV and we get an obviously
 					 * invalid parent interface from DEVICE, fail.
 					 */
-					g_free (parent);
-					parent = NULL;
+					nm_clear_g_free (&parent);
 				}
 			}
 			p++;
@@ -4834,17 +5017,16 @@ make_vlan_setting (shvarFile *ifcfg,
 	if (vlan_id < 0) {
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
-		goto error;
+		return NULL;
 	}
 	g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
 
 	if (parent == NULL) {
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "Failed to determine VLAN parent from DEVICE or PHYSDEV");
-		goto error;
+		return NULL;
 	}
 	g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
-	g_clear_pointer (&parent, g_free);
 
 	vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
 
@@ -4852,7 +5034,7 @@ make_vlan_setting (shvarFile *ifcfg,
 	if (gvrp > 0)
 		vlan_flags |= NM_VLAN_FLAG_GVRP;
 
-	value = svGetValueString (ifcfg, "VLAN_FLAGS");
+	value = svGetValueStr_cp (ifcfg, "VLAN_FLAGS");
 	if (value) {
 		gs_strfreev char **strv = NULL;
 		char **ptr;
@@ -4883,15 +5065,7 @@ make_vlan_setting (shvarFile *ifcfg,
 	parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
 	parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
 
-	g_free (iface_name);
-
-	return (NMSetting *) s_vlan;
-
-error:
-	g_free (parent);
-	g_free (iface_name);
-	g_object_unref (s_vlan);
-	return NULL;
+	return g_steal_pointer (&s_vlan);
 }
 
 static NMConnection *
@@ -4963,7 +5137,7 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg,
 	nm_connection_add_setting (connection, nm_setting_generic_new ());
 
 	/* Get a spec */
-	value = svGetValueString (ifcfg, "HWADDR");
+	value = svGetValueStr_cp (ifcfg, "HWADDR");
 	if (value) {
 		char *lower = g_ascii_strdown (value, -1);
 		*out_spec = g_strdup_printf ("%s:mac:%s", type, lower);
@@ -4972,14 +5146,14 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg,
 		return connection;
 	}
 
-	value = svGetValueString (ifcfg, "SUBCHANNELS");
+	value = svGetValueStr_cp (ifcfg, "SUBCHANNELS");
 	if (value) {
 		*out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value);
 		g_free (value);
 		return connection;
 	}
 
-	value = svGetValueString (ifcfg, "DEVICE");
+	value = svGetValueStr_cp (ifcfg, "DEVICE");
 	if (value) {
 		*out_spec = g_strdup_printf ("%s:interface-name:%s", type, value);
 		g_free (value);
@@ -5008,11 +5182,9 @@ uuid_from_file (const char *filename)
 		return NULL;
 
 	/* Try for a UUID key before falling back to hashing the file name */
-	uuid = svGetValueString (ifcfg, "UUID");
-	if (!uuid || !strlen (uuid)) {
-		g_free (uuid);
+	uuid = svGetValueStr_cp (ifcfg, "UUID");
+	if (!uuid)
 		uuid = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
-	}
 
 	svCloseFile (ifcfg);
 	return uuid;
@@ -5029,7 +5201,8 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
 	 */
 	if (!s_ip4 || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) {
 		/* DNS searches */
-		char *value = svGetValueString (ifcfg, "DOMAIN");
+		char *value = svGetValueStr_cp (ifcfg, "DOMAIN");
+
 		if (value) {
 			char **searches = g_strsplit (value, " ", 0);
 			if (searches) {
@@ -5055,12 +5228,13 @@ connection_from_file_full (const char *filename,
                            GError **error,
                            gboolean *out_ignore_error)
 {
-	NMConnection *connection = NULL;
-	shvarFile *parsed;
+	nm_auto_shvar_file_close shvarFile *parsed = NULL;
+	gs_unref_object NMConnection *connection = NULL;
 	gs_free char *type = NULL;
 	char *devtype, *bootproto;
-	NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL;
+	NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user;
 	const char *ifcfg_name = NULL;
+	gboolean has_ip4_defroute = FALSE;
 
 	g_return_val_if_fail (filename != NULL, NULL);
 	g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL);
@@ -5082,30 +5256,38 @@ connection_from_file_full (const char *filename,
 
 	if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) {
 		connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
-		if (!connection)
+		if (!connection) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 			             "NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
-		goto done;
+		}
+		return g_steal_pointer (&connection);
 	}
 
 	/* iBFT is handled by the iBFT settings plugin */
-	bootproto = svGetValueString (parsed, "BOOTPROTO");
+	bootproto = svGetValueStr_cp (parsed, "BOOTPROTO");
 	if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) {
 		if (out_ignore_error)
 			*out_ignore_error = TRUE;
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Ignoring iBFT configuration");
 		g_free (bootproto);
-		goto done;
+		return NULL;
 	}
 	g_free (bootproto);
 
-	devtype = svGetValueString (parsed, "DEVICETYPE");
+	devtype = svGetValueStr_cp (parsed, "DEVICETYPE");
 	if (devtype) {
 		if (!strcasecmp (devtype, TYPE_TEAM))
 			type = g_strdup (TYPE_TEAM);
-		else if (!strcasecmp (devtype, TYPE_TEAM_PORT))
-			type = g_strdup (TYPE_ETHERNET);
+		else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) {
+			gs_free char *device = NULL;
+
+			device = svGetValueStr_cp (parsed, "DEVICE");
+			if (device && is_vlan_device (device, parsed))
+				type = g_strdup (TYPE_VLAN);
+			else
+				type = g_strdup (TYPE_ETHERNET);
+		}
 		g_free (devtype);
 	}
 	if (!type) {
@@ -5114,33 +5296,32 @@ connection_from_file_full (const char *filename,
 		/* Team and TeamPort types are also accepted by the mere
 		 * presense of TEAM_CONFIG/TEAM_MASTER. They don't require
 		 * DEVICETYPE. */
-		t = svGetValueString (parsed, "TEAM_CONFIG");
+		t = svGetValueStr_cp (parsed, "TEAM_CONFIG");
 		if (t)
 			type = g_strdup (TYPE_TEAM);
 	}
 
 	if (!type)
-		type = svGetValueString (parsed, "TYPE");
+		type = svGetValueStr_cp (parsed, "TYPE");
 
 	if (!type) {
 		gs_free char *tmp = NULL;
 		char *device;
 
-		if ((tmp = svGetValueString (parsed, "IPV6TUNNELIPV4"))) {
+		if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) {
 			if (out_ignore_error)
 				*out_ignore_error = TRUE;
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Ignoring unsupported connection due to IPV6TUNNELIPV4");
-			goto done;
+			return NULL;
 		}
 
-		device = svGetValueString (parsed, "DEVICE");
+		device = svGetValueStr_cp (parsed, "DEVICE");
 		if (!device) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "File '%s' had neither TYPE nor DEVICE keys.", filename);
-			goto done;
+			return NULL;
 		}
-		g_assert (device[0]);
 
 		if (!strcmp (device, "lo")) {
 			if (out_ignore_error)
@@ -5148,7 +5329,7 @@ connection_from_file_full (const char *filename,
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Ignoring loopback device config.");
 			g_free (device);
-			goto done;
+			return NULL;
 		}
 
 		if (!test_type) {
@@ -5196,7 +5377,7 @@ connection_from_file_full (const char *filename,
 						g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 						             "Ignore script for unknown device type which has a matching %s script",
 						             p_path);
-						goto done;
+						return NULL;
 					}
 				}
 
@@ -5220,11 +5401,21 @@ connection_from_file_full (const char *filename,
 		}
 	}
 
+	if (nm_streq0 (type, TYPE_ETHERNET)) {
+		gs_free char *bond_options = NULL;
+
+		if (svGetValueStr (parsed, "BONDING_OPTS", &bond_options)) {
+			/* initscripts consider these as bond masters */
+			g_free (type);
+			type = g_strdup (TYPE_BOND);
+		}
+	}
+
 	if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) &&
 	    strcasecmp (type, TYPE_BOND)) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
-		goto done;
+		return NULL;
 	}
 
 	/* Construct the connection */
@@ -5244,29 +5435,30 @@ connection_from_file_full (const char *filename,
 		connection = bridge_connection_from_ifcfg (filename, parsed, error);
 	else {
 		connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
-		if (!connection)
+		if (!connection) {
 			PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
-		goto done;
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Failed to read unrecognized connection");
+		}
+		return g_steal_pointer (&connection);
 	}
 
 	if (!connection)
-		goto done;
+		return NULL;
 
 	s_ip6 = make_ip6_setting (parsed, network_file, error);
-	if (!s_ip6) {
-		g_object_unref (connection);
-		connection = NULL;
-		goto done;
-	} else
+	if (!s_ip6)
+		return NULL;
+	else
 		nm_connection_add_setting (connection, s_ip6);
 
-	s_ip4 = make_ip4_setting (parsed, network_file, error);
-	if (!s_ip4) {
-		g_object_unref (connection);
-		connection = NULL;
-		goto done;
-	} else {
-		read_aliases (NM_SETTING_IP_CONFIG (s_ip4), filename);
+	s_ip4 = make_ip4_setting (parsed, network_file, &has_ip4_defroute, error);
+	if (!s_ip4)
+		return NULL;
+	else {
+		read_aliases (NM_SETTING_IP_CONFIG (s_ip4),
+		              !has_ip4_defroute && !nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (s_ip4)),
+		              filename);
 		nm_connection_add_setting (connection, s_ip4);
 	}
 
@@ -5280,6 +5472,10 @@ connection_from_file_full (const char *filename,
 	if (s_proxy)
 		nm_connection_add_setting (connection, s_proxy);
 
+	s_user = make_user_setting (parsed, error);
+	if (s_user)
+		nm_connection_add_setting (connection, s_user);
+
 	/* Bridge port? */
 	s_port = make_bridge_port_setting (parsed);
 	if (s_port)
@@ -5290,22 +5486,15 @@ connection_from_file_full (const char *filename,
 	if (s_port)
 		nm_connection_add_setting (connection, s_port);
 
-	if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) {
-		g_object_unref (connection);
-		connection = NULL;
-		goto done;
-	}
+	if (!make_dcb_setting (parsed, network_file, &s_dcb, error))
+		return NULL;
 	if (s_dcb)
 		nm_connection_add_setting (connection, s_dcb);
 
-	if (!nm_connection_normalize (connection, NULL, NULL, error)) {
-		g_object_unref (connection);
-		connection = NULL;
-	}
+	if (!nm_connection_normalize (connection, NULL, NULL, error))
+		return NULL;
 
-done:
-	svCloseFile (parsed);
-	return connection;
+	return g_steal_pointer (&connection);
 }
 
 NMConnection *
@@ -5348,7 +5537,7 @@ devtimeout_from_file (const char *filename)
 	if (!ifcfg)
 		return 0;
 
-	devtimeout_str = svGetValueString (ifcfg, "DEVTIMEOUT");
+	devtimeout_str = svGetValueStr_cp (ifcfg, "DEVTIMEOUT");
 	if (devtimeout_str) {
 		devtimeout = _nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0);
 		g_free (devtimeout_str);