summary refs log tree commit diff
path: root/system-settings/plugins/keyfile/io/reader.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2010-11-29 19:00:22 +0100
committerMichael Biebl <biebl@debian.org>2010-11-29 19:00:22 +0100
commita6b89d35fabd9f5934b84d7cde22e9268f92c3d3 (patch)
tree9e44755880d5933fcc90c6008d4585a76298a1bd /system-settings/plugins/keyfile/io/reader.c
parent9fae01fa351805b2903e535736e06971bc0b925e (diff)
Imported Upstream version 0.8.2 upstream/0.8.2
Diffstat (limited to 'system-settings/plugins/keyfile/io/reader.c')
-rw-r--r--system-settings/plugins/keyfile/io/reader.c1085
1 files changed, 0 insertions, 1085 deletions
diff --git a/system-settings/plugins/keyfile/io/reader.c b/system-settings/plugins/keyfile/io/reader.c
deleted file mode 100644
index 5582733f..00000000
--- a/system-settings/plugins/keyfile/io/reader.c
+++ /dev/null
@@ -1,1085 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2008 - 2010 Red Hat, Inc.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <dbus/dbus-glib.h>
-#include <nm-setting.h>
-#include <nm-setting-ip4-config.h>
-#include <nm-setting-ip6-config.h>
-#include <nm-setting-vpn.h>
-#include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-bluetooth.h>
-#include <nm-setting-serial.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-cdma.h>
-#include <nm-setting-ppp.h>
-#include <arpa/inet.h>
-#include <netinet/ether.h>
-#include <string.h>
-
-#include "nm-dbus-glib-types.h"
-#include "reader.h"
-
-static gboolean
-read_array_of_uint (GKeyFile *file,
-                    NMSetting *setting,
-                    const char *key)
-{
-	GArray *array = NULL;
-	gsize length;
-	int i;
-	gint *tmp;
-
-	tmp = g_key_file_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
-	array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
-	for (i = 0; i < length; i++)
-		g_array_append_val (array, tmp[i]);
-
-	if (array) {
-		g_object_set (setting, key, array, NULL);
-		g_array_free (array, TRUE);
-	}
-
-	return TRUE;
-}
-
-static gboolean
-get_one_int (const char *str, guint32 max_val, const char *key_name, guint32 *out)
-{
-	long tmp;
-
-	errno = 0;
-	tmp = strtol (str, NULL, 10);
-	if (errno || (tmp < 0) || (tmp > max_val)) {
-		g_warning ("%s: ignoring invalid IP %s item '%s'", __func__, key_name, str);
-		return FALSE;
-	}
-
-	*out = (guint32) tmp;
-	return TRUE;
-}
-
-static void
-free_one_ip4_address (gpointer data, gpointer user_data)
-{
-	g_array_free ((GArray *) data, TRUE);
-}
-
-static GPtrArray *
-read_ip4_addresses (GKeyFile *file,
-			    const char *setting_name,
-			    const char *key)
-{
-	GPtrArray *addresses;
-	int i = 0;
-
-	addresses = g_ptr_array_sized_new (3);
-
-	/* Look for individual addresses */
-	while (i++ < 1000) {
-		gchar **tmp, **iter;
-		char *key_name;
-		gsize length = 0;
-		int ret;
-		GArray *address;
-		guint32 empty = 0;
-		int j;
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
-		g_free (key_name);
-
-		if (!tmp || !length)
-			break; /* all done */
-
-		if ((length < 2) || (length > 3)) {
-			g_warning ("%s: ignoring invalid IPv4 address item '%s'", __func__, key_name);
-			goto next;
-		}
-
-		/* convert the string array into IP addresses */
-		address = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
-		for (iter = tmp, j = 0; *iter; iter++, j++) {
-			struct in_addr addr;
-
-			if (j == 1) {
-				guint32 prefix = 0;
-
-				/* prefix */
-				if (!get_one_int (*iter, 32, key_name, &prefix)) {
-					g_array_free (address, TRUE);
-					goto next;
-				}
-
-				g_array_append_val (address, prefix);
-			} else {
-				/* address and gateway */
-				ret = inet_pton (AF_INET, *iter, &addr);
-				if (ret <= 0) {
-					g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter);
-					g_array_free (address, TRUE);
-					goto next;
-				}
-				g_array_append_val (address, addr.s_addr);
-			}
-		}
-
-		/* fill in blank gateway if not specified */
-		if (address->len == 2)
-			g_array_append_val (address, empty);
-
-		g_ptr_array_add (addresses, address);
-
-next:
-		g_strfreev (tmp);
-	}
-
-	if (addresses->len < 1) {
-		g_ptr_array_free (addresses, TRUE);
-		addresses = NULL;
-	}
-
-	return addresses;
-}
-
-static void
-ip4_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	GPtrArray *addresses;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	addresses = read_ip4_addresses (keyfile, setting_name, key);
-
-	/* Work around for previous syntax */
-	if (!addresses && !strcmp (key, NM_SETTING_IP4_CONFIG_ADDRESSES))
-		addresses = read_ip4_addresses (keyfile, setting_name, "address");
-
-	if (addresses) {
-		g_object_set (setting, key, addresses, NULL);
-		g_ptr_array_foreach (addresses, free_one_ip4_address, NULL);
-		g_ptr_array_free (addresses, TRUE);
-	}
-}
-
-static void
-free_one_ip4_route (gpointer data, gpointer user_data)
-{
-	g_array_free ((GArray *) data, TRUE);
-}
-
-static GPtrArray *
-read_ip4_routes (GKeyFile *file,
-			 const char *setting_name,
-			 const char *key)
-{
-	GPtrArray *routes;
-	int i = 0;
-
-	routes = g_ptr_array_sized_new (3);
-
-	/* Look for individual routes */
-	while (i++ < 1000) {
-		gchar **tmp, **iter;
-		char *key_name;
-		gsize length = 0;
-		int ret;
-		GArray *route;
-		int j;
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
-		g_free (key_name);
-
-		if (!tmp || !length)
-			break; /* all done */
-
-		if (length != 4) {
-			g_warning ("%s: ignoring invalid IPv4 route item '%s'", __func__, key_name);
-			goto next;
-		}
-
-		/* convert the string array into IP addresses */
-		route = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4);
-		for (iter = tmp, j = 0; *iter; iter++, j++) {
-			struct in_addr addr;
-
-			if (j == 1) {
-				guint32 prefix = 0;
-
-				/* prefix */
-				if (!get_one_int (*iter, 32, key_name, &prefix)) {
-					g_array_free (route, TRUE);
-					goto next;
-				}
-
-				g_array_append_val (route, prefix);
-			} else if (j == 3) {
-				guint32 metric = 0;
-
-				/* metric */
-				if (!get_one_int (*iter, G_MAXUINT32, key_name, &metric)) {
-					g_array_free (route, TRUE);
-					goto next;
-				}
-
-				g_array_append_val (route, metric);
-			} else {
-				/* address and next hop */
-				ret = inet_pton (AF_INET, *iter, &addr);
-				if (ret <= 0) {
-					g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter);
-					g_array_free (route, TRUE);
-					goto next;
-				}
-				g_array_append_val (route, addr.s_addr);
-			}
-		}
-		g_ptr_array_add (routes, route);
-
-next:
-		g_strfreev (tmp);
-	}
-
-	if (routes->len < 1) {
-		g_ptr_array_free (routes, TRUE);
-		routes = NULL;
-	}
-
-	return routes;
-}
-
-static void
-ip4_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	GPtrArray *routes;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	routes = read_ip4_routes (keyfile, setting_name, key);
-	if (routes) {
-		g_object_set (setting, key, routes, NULL);
-		g_ptr_array_foreach (routes, free_one_ip4_route, NULL);
-		g_ptr_array_free (routes, TRUE);
-	}
-}
-
-static void
-ip4_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	const char *setting_name = nm_setting_get_name (setting);
-	GArray *array = NULL;
-	gsize length;
-	char **list, **iter;
-	int ret;
-
-	list = g_key_file_get_string_list (keyfile, setting_name, key, &length, NULL);
-	if (!list || !g_strv_length (list))
-		return;
-
-	array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
-	for (iter = list; *iter; iter++) {
-		struct in_addr addr;
-
-		ret = inet_pton (AF_INET, *iter, &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid DNS server address '%s'", __func__, *iter);
-			continue;
-		}
-
-		g_array_append_val (array, addr.s_addr);
-	}
-	g_strfreev (list);
-
-	if (array) {
-		g_object_set (setting, key, array, NULL);
-		g_array_free (array, TRUE);
-	}
-}
-
-static void
-free_one_ip6_address (gpointer data, gpointer user_data)
-{
-	g_value_array_free ((GValueArray *) data);
-}
-
-static char *
-split_prefix (char *addr)
-{
-	char *slash;
-
-	g_return_val_if_fail (addr != NULL, NULL);
-
-	/* Find the prefix and split the string */
-	slash = strchr (addr, '/');
-	if (slash && slash > addr) {
-		slash++;
-		*(slash - 1) = '\0';
-	}
-
-	return slash;
-}
-
-static char *
-split_gw (char *str)
-{
-	char *comma;
-
-	g_return_val_if_fail (str != NULL, NULL);
-
-	/* Find the prefix and split the string */
-	comma = strchr (str, ',');
-	if (comma && comma > str) {
-		comma++;
-		*(comma - 1) = '\0';
-		return comma;
-	}
-	return NULL;
-}
-
-static GPtrArray *
-read_ip6_addresses (GKeyFile *file,
-                    const char *setting_name,
-                    const char *key)
-{
-	GPtrArray *addresses;
-	struct in6_addr addr, gw;
-	guint32 prefix;
-	int i = 0;
-
-	addresses = g_ptr_array_sized_new (3);
-
-	/* Look for individual addresses */
-	while (i++ < 1000) {
-		char *tmp, *key_name, *str_prefix, *str_gw;
-		int ret;
-		GValueArray *values;
-		GByteArray *address;
-		GByteArray *gateway;
-		GValue value = { 0 };
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string (file, setting_name, key_name, NULL);
-		g_free (key_name);
-
-		if (!tmp)
-			break; /* all done */
-
-		/* convert the string array into IPv6 addresses */
-		values = g_value_array_new (2); /* NMIP6Address has 2 items */
-
-		/* Split the address and prefix */
-		str_prefix = split_prefix (tmp);
-
-		/* address */
-		ret = inet_pton (AF_INET6, tmp, &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp);
-			g_value_array_free (values);
-			goto next;
-		}
-
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* prefix */
-		prefix = 0;
-		if (str_prefix) {
-			if (!get_one_int (str_prefix, 128, key_name, &prefix)) {
-				g_value_array_free (values);
-				goto next;
-			}
-		} else {
-			/* Missing prefix defaults to /64 */
-			prefix = 64;
-		}
-
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, prefix);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* Gateway (optional) */
-		str_gw = split_gw (str_prefix);
-		if (str_gw) {
-			ret = inet_pton (AF_INET6, str_gw, &gw);
-			if (ret <= 0) {
-				g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp);
-				g_value_array_free (values);
-				goto next;
-			}
-
-			if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) {
-				gateway = g_byte_array_new ();
-				g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16);
-				g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-				g_value_take_boxed (&value, gateway);
-				g_value_array_append (values, &value);
-				g_value_unset (&value);
-			}
-		}
-
-		g_ptr_array_add (addresses, values);
-
-next:
-		g_free (tmp);
-	}
-
-	if (addresses->len < 1) {
-		g_ptr_array_free (addresses, TRUE);
-		addresses = NULL;
-	}
-
-	return addresses;
-}
-
-static void
-ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	GPtrArray *addresses;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	addresses = read_ip6_addresses (keyfile, setting_name, key);
-	if (addresses) {
-		g_object_set (setting, key, addresses, NULL);
-		g_ptr_array_foreach (addresses, free_one_ip6_address, NULL);
-		g_ptr_array_free (addresses, TRUE);
-	}
-}
-
-static void
-free_one_ip6_route (gpointer data, gpointer user_data)
-{
-	g_value_array_free ((GValueArray *) data);
-}
-
-static GPtrArray *
-read_ip6_routes (GKeyFile *file,
-                 const char *setting_name,
-                 const char *key)
-{
-	GPtrArray *routes;
-	struct in6_addr addr;
-	guint32 prefix, metric;
-	int i = 0;
-
-	routes = g_ptr_array_sized_new (3);
-
-	/* Look for individual routes */
-	while (i++ < 1000) {
-		gchar **tmp;
-		char *key_name, *str_prefix;
-		gsize length = 0;
-		int ret;
-		GValueArray *values;
-		GByteArray *address;
-		GValue value = { 0 };
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
-		g_free (key_name);
-
-		if (!tmp || !length)
-			break; /* all done */
-
-		if (length != 3) {
-			g_warning ("%s: ignoring invalid IPv6 address item '%s'", __func__, key_name);
-			goto next;
-		}
-
-		/* convert the string array into IPv6 routes */
-		values = g_value_array_new (4); /* NMIP6Route has 4 items */
-
-		/* Split the route and prefix */
-		str_prefix = split_prefix (tmp[0]);
-
-		/* destination address */
-		ret = inet_pton (AF_INET6, tmp[0], &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[0]);
-			g_value_array_free (values);
-			goto next;
-		}
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* prefix */
-		prefix = 0;
-		if (str_prefix) {
-			if (!get_one_int (str_prefix, 128, key_name, &prefix)) {
-				g_value_array_free (values);
-				goto next;
-			}
-		} else {
-			/* default to 64 if unspecified */
-			prefix = 64;
-		}
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, prefix);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* next hop address */
-		ret = inet_pton (AF_INET6, tmp[1], &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[1]);
-			g_value_array_free (values);
-			goto next;
-		}
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* metric */
-		metric = 0;
-		if (!get_one_int (tmp[2], G_MAXUINT32, key_name, &metric)) {
-			g_value_array_free (values);
-			goto next;
-		}
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, metric);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		g_ptr_array_add (routes, values);
-
-next:
-		g_strfreev (tmp);
-	}
-
-	if (routes->len < 1) {
-		g_ptr_array_free (routes, TRUE);
-		routes = NULL;
-	}
-
-	return routes;
-}
-
-static void
-ip6_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	GPtrArray *routes;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	routes = read_ip6_routes (keyfile, setting_name, key);
-
-	if (routes) {
-		g_object_set (setting, key, routes, NULL);
-		g_ptr_array_foreach (routes, free_one_ip6_route, NULL);
-		g_ptr_array_free (routes, TRUE);
-	}
-}
-
-static void
-free_one_ip6_dns (gpointer data, gpointer user_data)
-{
-	g_byte_array_free ((GByteArray *) data, TRUE);
-}
-
-static void
-ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	const char *setting_name = nm_setting_get_name (setting);
-	GPtrArray *array = NULL;
-	gsize length;
-	char **list, **iter;
-	int ret;
-
-	list = g_key_file_get_string_list (keyfile, setting_name, key, &length, NULL);
-	if (!list || !g_strv_length (list))
-		return;
-
-	array = g_ptr_array_sized_new (length);
-	for (iter = list; *iter; iter++) {
-		GByteArray *byte_array;
-		struct in6_addr addr;
-
-		ret = inet_pton (AF_INET6, *iter, &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid DNS server IPv6 address '%s'", __func__, *iter);
-			continue;
-		}
-		byte_array = g_byte_array_new ();
-		g_byte_array_append (byte_array, (guint8 *) addr.s6_addr, 16);
-
-		g_ptr_array_add (array, byte_array);
-	}
-	g_strfreev (list);
-
-	if (array) {
-		g_object_set (setting, key, array, NULL);
-		g_ptr_array_foreach (array, free_one_ip6_dns, NULL);
-		g_ptr_array_free (array, TRUE);
-	}
-}
-
-static void
-mac_address_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
-{
-	const char *setting_name = nm_setting_get_name (setting);
-	struct ether_addr *eth;
-	char *tmp_string = NULL, *p;
-	gint *tmp_list;
-	GByteArray *array = NULL;
-	gsize length;
-	int i;
-
-	p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL);
-	if (tmp_string) {
-		/* Look for enough ':' characters to signify a MAC address */
-		i = 0;
-		while (*p) {
-			if (*p == ':')
-				i++;
-			p++;
-		}
-		if (i == 5) {
-			/* parse as a MAC address */
-			eth = ether_aton (tmp_string);
-			if (eth) {
-				g_free (tmp_string);
-				array = g_byte_array_sized_new (ETH_ALEN);
-				g_byte_array_append (array, eth->ether_addr_octet, ETH_ALEN);
-				goto done;
-			}
-		}
-	}
-	g_free (tmp_string);
-
-	/* Old format; list of ints */
-	tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL);
-	array = g_byte_array_sized_new (length);
-	for (i = 0; i < length; i++) {
-		int val = tmp_list[i];
-		unsigned char v = (unsigned char) (val & 0xFF);
-
-		if (val < 0 || val > 255) {
-			g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not "
-			           " between 0 and 255 inclusive)", __func__, setting_name,
-			           key, val);
-		} else
-			g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
-	}
-	g_free (tmp_list);
-
-done:
-	if (array->len == ETH_ALEN) {
-		g_object_set (setting, key, array, NULL);
-	} else {
-		g_warning ("%s: ignoring invalid MAC address for %s / %s",
-		           __func__, setting_name, key);
-	}
-	g_byte_array_free (array, TRUE);
-}
-
-static void
-read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
-{
-	char **keys, **iter;
-	char *value;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	keys = g_key_file_get_keys (file, setting_name, NULL, NULL);
-	if (!keys || !*keys)
-		return;
-
-	for (iter = keys; *iter; iter++) {
-		value = g_key_file_get_string (file, setting_name, *iter, NULL);
-		if (!value)
-			continue;
-
-		if (NM_IS_SETTING_VPN (setting)) {
-			if (strcmp (*iter, NM_SETTING_VPN_SERVICE_TYPE))
-				nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), *iter, value);
-		}
-		g_free (value);
-	}
-	g_strfreev (keys);
-}
-
-
-typedef struct {
-	const char *setting_name;
-	const char *key;
-	gboolean check_for_key;
-	void (*parser) (NMSetting *setting, const char *key, GKeyFile *keyfile);
-} KeyParser;
-
-/* A table of keys that require further parsing/conversion becuase they are
- * stored in a format that can't be automatically read using the key's type.
- * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are
- * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored 
- * in struct in6_addr internally, but as string in keyfiles.
- */
-static KeyParser key_parsers[] = {
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP4_CONFIG_ADDRESSES,
-	  FALSE,
-	  ip4_addr_parser },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP6_CONFIG_ADDRESSES,
-	  FALSE,
-	  ip6_addr_parser },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP4_CONFIG_ROUTES,
-	  FALSE,
-	  ip4_route_parser },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP6_CONFIG_ROUTES,
-	  FALSE,
-	  ip6_route_parser },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP4_CONFIG_DNS,
-	  FALSE,
-	  ip4_dns_parser },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	  NM_SETTING_IP6_CONFIG_DNS,
-	  FALSE,
-	  ip6_dns_parser },
-	{ NM_SETTING_WIRED_SETTING_NAME,
-	  NM_SETTING_WIRED_MAC_ADDRESS,
-	  TRUE,
-	  mac_address_parser },
-	{ NM_SETTING_WIRELESS_SETTING_NAME,
-	  NM_SETTING_WIRELESS_MAC_ADDRESS,
-	  TRUE,
-	  mac_address_parser },
-	{ NM_SETTING_WIRELESS_SETTING_NAME,
-	  NM_SETTING_WIRELESS_BSSID,
-	  TRUE,
-	  mac_address_parser },
-	{ NM_SETTING_BLUETOOTH_SETTING_NAME,
-	  NM_SETTING_BLUETOOTH_BDADDR,
-	  TRUE,
-	  mac_address_parser },
-	{ NULL, NULL, FALSE }
-};
-
-static void
-read_one_setting_value (NMSetting *setting,
-                        const char *key,
-                        const GValue *value,
-                        GParamFlags flags,
-                        gpointer user_data)
-{
-	GKeyFile *file = user_data;
-	const char *setting_name;
-	GType type;
-	GError *err = NULL;
-	gboolean check_for_key = TRUE;
-	KeyParser *parser = &key_parsers[0];
-
-	/* Property is not writable */
-	if (!(flags & G_PARAM_WRITABLE))
-		return;
-
-	/* Setting name gets picked up from the keyfile's section name instead */
-	if (!strcmp (key, NM_SETTING_NAME))
-		return;
-
-	/* Don't read the NMSettingConnection object's 'read-only' property */
-	if (   NM_IS_SETTING_CONNECTION (setting)
-	    && !strcmp (key, NM_SETTING_CONNECTION_READ_ONLY))
-		return;
-
-	setting_name = nm_setting_get_name (setting);
-
-	/* Look through the list of handlers for non-standard format key values */
-	while (parser->setting_name) {
-		if (!strcmp (parser->setting_name, setting_name) && !strcmp (parser->key, key)) {
-			check_for_key = parser->check_for_key;
-			break;
-		}
-		parser++;
-	}
-
-	/* VPN properties don't have the exact key name */
-	if (NM_IS_SETTING_VPN (setting))
-		check_for_key = FALSE;
-
-	/* Check for the exact key in the GKeyFile if required.  Most setting
-	 * properties map 1:1 to a key in the GKeyFile, but for those properties
-	 * like IP addresses and routes where more than one value is actually
-	 * encoded by the setting property, this won't be true.
-	 */
-	if (check_for_key && !g_key_file_has_key (file, setting_name, key, &err)) {
-		/* Key doesn't exist or an error ocurred, thus nothing to do. */
-		if (err) {
-			g_warning ("Error loading setting '%s' value: %s", setting_name, err->message);
-			g_error_free (err);
-		}
-		return;
-	}
-
-	/* If there's a custom parser for this key, handle that before the generic
-	 * parsers below.
-	 */
-	if (parser && parser->setting_name) {
-		(*parser->parser) (setting, key, file);
-		return;
-	}
-
-	type = G_VALUE_TYPE (value);
-
-	if (type == G_TYPE_STRING) {
-		char *str_val;
-
-		str_val = g_key_file_get_string (file, setting_name, key, NULL);
-		g_object_set (setting, key, str_val, NULL);
-		g_free (str_val);
-	} else if (type == G_TYPE_UINT) {
-		int int_val;
-
-		int_val = g_key_file_get_integer (file, setting_name, key, NULL);
-		if (int_val < 0)
-			g_warning ("Casting negative value (%i) to uint", int_val);
-		g_object_set (setting, key, int_val, NULL);
-	} else if (type == G_TYPE_INT) {
-		int int_val;
-
-		int_val = g_key_file_get_integer (file, setting_name, key, NULL);
-		g_object_set (setting, key, int_val, NULL);
-	} else if (type == G_TYPE_BOOLEAN) {
-		gboolean bool_val;
-
-		bool_val = g_key_file_get_boolean (file, setting_name, key, NULL);
-		g_object_set (setting, key, bool_val, NULL);
-	} else if (type == G_TYPE_CHAR) {
-		int int_val;
-
-		int_val = g_key_file_get_integer (file, setting_name, key, NULL);
-		if (int_val < G_MININT8 || int_val > G_MAXINT8)
-			g_warning ("Casting value (%i) to char", int_val);
-
-		g_object_set (setting, key, int_val, NULL);
-	} else if (type == G_TYPE_UINT64) {
-		char *tmp_str;
-		guint64 uint_val;
-
-		tmp_str = g_key_file_get_value (file, setting_name, key, NULL);
-		uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
-		g_free (tmp_str);
-		g_object_set (setting, key, uint_val, NULL);
- 	} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
-		gint *tmp;
-		GByteArray *array;
-		gsize length;
-		int i;
-
-		tmp = g_key_file_get_integer_list (file, setting_name, key, &length, NULL);
-
-		array = g_byte_array_sized_new (length);
-		for (i = 0; i < length; i++) {
-			int val = tmp[i];
-			unsigned char v = (unsigned char) (val & 0xFF);
-
-			if (val < 0 || val > 255) {
-				g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not "
-				           " between 0 and 255 inclusive)", __func__, setting_name,
-				           key, val);
-			} else
-				g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
-		}
-
-		g_object_set (setting, key, array, NULL);
-		g_byte_array_free (array, TRUE);
-		g_free (tmp);
- 	} else if (type == DBUS_TYPE_G_LIST_OF_STRING) {
-		gchar **sa;
-		gsize length;
-		int i;
-		GSList *list = NULL;
-
-		sa = g_key_file_get_string_list (file, setting_name, key, &length, NULL);
-		for (i = 0; i < length; i++)
-			list = g_slist_prepend (list, sa[i]);
-
-		list = g_slist_reverse (list);
-		g_object_set (setting, key, list, NULL);
-
-		g_slist_free (list);
-		g_strfreev (sa);
-	} else if (type == DBUS_TYPE_G_MAP_OF_STRING) {
-		read_hash_of_string (file, setting, key);
-	} else if (type == DBUS_TYPE_G_UINT_ARRAY) {
-		if (!read_array_of_uint (file, setting, key)) {
-			g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'",
-					 setting_name, key, G_VALUE_TYPE_NAME (value));
-		}
-	} else {
-		g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'",
-				 setting_name, key, G_VALUE_TYPE_NAME (value));
-	}
-}
-
-static NMSetting *
-read_setting (GKeyFile *file, const char *name)
-{
-	NMSetting *setting;
-
-	setting = nm_connection_create_setting (name);
-	if (setting)
-		nm_setting_enumerate_values (setting, read_one_setting_value, (gpointer) file);
-	else
-		g_warning ("Invalid setting name '%s'", name);
-
-	return setting;
-}
-
-static void
-read_vpn_secrets (GKeyFile *file, NMSettingVPN *s_vpn)
-{
-	char **keys, **iter;
-
-	keys = g_key_file_get_keys (file, VPN_SECRETS_GROUP, NULL, NULL);
-	for (iter = keys; *iter; iter++) {
-		char *secret;
-
-		secret = g_key_file_get_string (file, VPN_SECRETS_GROUP, *iter, NULL);
-		if (secret) {
-			nm_setting_vpn_add_secret (s_vpn, *iter, secret);
-			g_free (secret);
-		}
-	}
-	g_strfreev (keys);
-}
-
-NMConnection *
-connection_from_file (const char *filename)
-{
-	GKeyFile *key_file;
-	struct stat statbuf;
-	gboolean bad_owner, bad_permissions;
-	NMConnection *connection = NULL;
-	GError *err = NULL;
-
-	if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode))
-		return NULL;
-
-	bad_owner = getuid () != statbuf.st_uid;
-	bad_permissions = statbuf.st_mode & 0077;
-
-	if (bad_owner || bad_permissions) {
-		g_warning ("Ignoring insecure configuration file '%s'", filename);
-		return NULL;
-	}
-
-	key_file = g_key_file_new ();
-	if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &err)) {
-		NMSettingConnection *s_con;
-		NMSettingBluetooth *s_bt;
-		NMSetting *setting;
-		gchar **groups;
-		gsize length;
-		int i;
-		gboolean vpn_secrets = FALSE;
-		const char *ctype, *tmp;
-
-		connection = nm_connection_new ();
-
-		groups = g_key_file_get_groups (key_file, &length);
-		for (i = 0; i < length; i++) {
-			/* Only read out secrets when needed */
-			if (!strcmp (groups[i], VPN_SECRETS_GROUP)) {
-				vpn_secrets = TRUE;
-				continue;
-			}
-
-			setting = read_setting (key_file, groups[i]);
-			if (setting)
-				nm_connection_add_setting (connection, setting);
-		}
-
-		/* Make sure that we have the base device type setting even if
-		 * the keyfile didn't include it, which can happen when the base
-		 * device type setting is all default values (like ethernet).
-		 */
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
-		if (s_con) {
-			ctype = nm_setting_connection_get_connection_type (s_con);
-			setting = nm_connection_get_setting_by_name (connection, ctype);
-			if (ctype) {
-				gboolean add_serial = FALSE;
-				NMSetting *new_setting = NULL;
-
-				if (!setting && !strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME))
-					new_setting = nm_setting_wired_new ();
-				else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
-					s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
-					if (s_bt) {
-						tmp = nm_setting_bluetooth_get_connection_type (s_bt);
-						if (tmp && !strcmp (tmp, NM_SETTING_BLUETOOTH_TYPE_DUN))
-							add_serial = TRUE;
-					}
-				} else if (!strcmp (ctype, NM_SETTING_GSM_SETTING_NAME))
-					add_serial = TRUE;
-				else if (!strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME))
-					add_serial = TRUE;
-
-				/* Bluetooth DUN, GSM, and CDMA connections require a serial setting */
-				if (add_serial && !nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL))
-					new_setting = nm_setting_serial_new ();
-
-				if (new_setting)
-					nm_connection_add_setting (connection, new_setting);
-			}
-		}
-
-		/* Serial connections require a PPP setting too */
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL)) {
-			if (!nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP))
-				nm_connection_add_setting (connection, nm_setting_ppp_new ());
-		}
-
-		/* Handle vpn secrets after the 'vpn' setting was read */
-		if (vpn_secrets) {
-			NMSettingVPN *s_vpn;
-
-			s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
-			if (s_vpn)
-				read_vpn_secrets (key_file, s_vpn);
-		}
-
-		g_strfreev (groups);
-	} else {
-		g_warning ("Error parsing file '%s': %s", filename, err->message);
-		g_error_free (err);
-	}
-
-	g_key_file_free (key_file);
-
-	return connection;
-}