1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* NetworkManager system settings service
3    	 *
4    	 * This program is free software; you can redistribute it and/or modify
5    	 * it under the terms of the GNU General Public License as published by
6    	 * the Free Software Foundation; either version 2 of the License, or
7    	 * (at your option) any later version.
8    	 *
9    	 * This program is distributed in the hope that it will be useful,
10   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   	 * GNU General Public License for more details.
13   	 *
14   	 * You should have received a copy of the GNU General Public License along
15   	 * with this program; if not, write to the Free Software Foundation, Inc.,
16   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17   	 *
18   	 * Copyright (C) 2008 - 2012 Red Hat, Inc.
19   	 */
20   	
21   	#include <config.h>
22   	#include <stdlib.h>
23   	#include <string.h>
24   	#include <sys/types.h>
25   	#include <sys/socket.h>
26   	#include <arpa/inet.h>
27   	#include <sys/wait.h>
28   	#include <sys/inotify.h>
29   	#include <errno.h>
30   	#include <sys/ioctl.h>
31   	#include <unistd.h>
32   	#include <netinet/ether.h>
33   	#include <linux/if.h>
34   	
35   	#include <glib.h>
36   	#include <glib/gi18n.h>
37   	#include <nm-connection.h>
38   	#include <NetworkManager.h>
39   	#include <nm-setting-connection.h>
40   	#include <nm-setting-ip4-config.h>
41   	#include <nm-setting-vlan.h>
42   	#include <nm-setting-ip6-config.h>
43   	#include <nm-setting-wired.h>
44   	#include <nm-setting-wireless.h>
45   	#include <nm-setting-8021x.h>
46   	#include <nm-setting-bond.h>
47   	#include <nm-setting-team.h>
48   	#include <nm-setting-team-port.h>
49   	#include <nm-setting-bridge.h>
50   	#include <nm-setting-bridge-port.h>
51   	#include <nm-utils.h>
52   	
53   	#include "wifi-utils.h"
54   	#include "nm-posix-signals.h"
55   	#include "NetworkManagerUtils.h"
56   	
57   	#include "common.h"
58   	#include "shvar.h"
59   	#include "utils.h"
60   	
61   	#include "reader.h"
62   	
63   	#define PLUGIN_PRINT(pname, fmt, args...) \
64   		{ g_message ("   " pname ": " fmt, ##args); }
65   	
66   	#define PLUGIN_WARN(pname, fmt, args...) \
67   		{ g_warning ("   " pname ": " fmt, ##args); }
68   	
69   	static gboolean
70   	get_int (const char *str, int *value)
71   	{
72   		char *e;
73   		long int tmp;
74   	
75   		errno = 0;
76   		tmp = strtol (str, &e, 0);
77   		if (errno || *e != '\0')
78   			return FALSE;
79   		*value = (int) tmp;
80   		return TRUE;
81   	}
82   	
83   	static gboolean
84   	get_uint (const char *str, guint32 *value)
85   	{
86   		char *e;
87   		long unsigned int tmp;
88   	
89   		errno = 0;
90   		tmp = strtoul (str, &e, 0);
91   		if (errno || *e != '\0')
92   			return FALSE;
93   		*value = (guint32) tmp;
94   		return TRUE;
95   	}
96   	
97   	static char *
98   	make_connection_name (shvarFile *ifcfg,
99   	                      const char *ifcfg_name,
100  	                      const char *suggested,
101  	                      const char *prefix)
102  	{
103  		char *full_name = NULL, *name;
104  	
105  		/* If the ifcfg file already has a NAME, always use that */
106  		name = svGetValue (ifcfg, "NAME", FALSE);
107  		if (name && strlen (name))
108  			return name;
109  	
110  		/* Otherwise construct a new NAME */
111  		g_free (name);
112  		if (!prefix)
113  			prefix = _("System");
114  	
115  		/* For cosmetic reasons, if the suggested name is the same as
116  		 * the ifcfg files name, don't use it.  Mainly for wifi so that
117  		 * the SSID is shown in the connection ID instead of just "wlan0".
118  		 */
119  		if (suggested && strcmp (ifcfg_name, suggested))
120  			full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
121  		else
122  			full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
123  	
124  		return full_name;
125  	}
126  	
127  	static NMSetting *
128  	make_connection_setting (const char *file,
129  	                         shvarFile *ifcfg,
130  	                         const char *type,
131  	                         const char *suggested,
132  	                         const char *prefix)
133  	{
134  		NMSettingConnection *s_con;
135  		const char *ifcfg_name = NULL;
136  		char *new_id, *uuid = NULL, *zone = NULL, *value;
137  	
138  		ifcfg_name = utils_get_ifcfg_name (file, TRUE);
139  		if (!ifcfg_name)
140  			return NULL;
141  	
142  		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
143  	
144  		new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
145  		g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
146  		g_free (new_id);
147  	
148  		/* Try for a UUID key before falling back to hashing the file name */
149  		uuid = svGetValue (ifcfg, "UUID", FALSE);
150  		if (!uuid || !strlen (uuid)) {
151  			g_free (uuid);
152  			uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
153  		}
154  	
155  		g_object_set (s_con,
156  		              NM_SETTING_CONNECTION_TYPE, type,
157  		              NM_SETTING_CONNECTION_UUID, uuid,
158  		              NULL);
159  		g_free (uuid);
160  	
161  		value = svGetValue (ifcfg, "DEVICE", FALSE);
162  		if (value) {
163  			if (nm_utils_iface_valid_name (value)) {
164  				g_object_set (s_con,
165  				              NM_SETTING_CONNECTION_INTERFACE_NAME, value,
166  				              NULL);
167  			} else
168  				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid DEVICE name '%s'", value);
169  			g_free (value);
170  		}
171  	
172  		/* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
173  		g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT,
174  		              svTrueValue (ifcfg, "ONBOOT", TRUE),
175  		              NULL);
176  	
177  		value = svGetValue (ifcfg, "USERS", FALSE);
178  		if (value) {
179  			char **items, **iter;
180  	
181  			items = g_strsplit_set (value, " ", -1);
182  			for (iter = items; iter && *iter; iter++) {
183  				if (strlen (*iter)) {
184  					if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL))
185  						PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid USERS item '%s'", *iter);
186  				}
187  			}
188  			g_free (value);
189  			g_strfreev (items);
190  		}
191  	
192  	
193  		zone = svGetValue(ifcfg, "ZONE", FALSE);
194  		if (!zone || !strlen (zone)) {
195  			g_free (zone);
196  			zone = NULL;
197  		}
198  		g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
199  		g_free (zone);
200  	
201  		value = svGetValue (ifcfg, "SECONDARY_UUIDS", FALSE);
202  		if (value) {
203  			char **items, **iter;
204  	
205  			items = g_strsplit_set (value, " \t", -1);
206  			for (iter = items; iter && *iter; iter++) {
207  				if (strlen (*iter)) {
208  					if (!nm_setting_connection_add_secondary (s_con, *iter))
209  						PLUGIN_WARN (IFCFG_PLUGIN_NAME,
210  						             "    warning: secondary connection UUID '%s' already added", *iter);
211  				}
212  			}
213  			g_free (value);
214  			g_strfreev (items);
215  		}
216  	
217  		value = svGetValue (ifcfg, "BRIDGE", FALSE);
218  		if (value) {
219  			const char *bridge;
220  	
221  			if ((bridge = nm_setting_connection_get_master (s_con))) {
222  				PLUGIN_WARN (IFCFG_PLUGIN_NAME,
223  				             "     warning: Already configured as slave of %s. "
224  				             "Ignoring BRIDGE=\"%s\"", bridge, value);
225  				g_free (value);
226  			}
227  	
228  			g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
229  			g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE,
230  			              NM_SETTING_BRIDGE_SETTING_NAME, NULL);
231  			g_free (value);
232  		}
233  	
234  		value = svGetValue (ifcfg, "GATEWAY_PING_TIMEOUT", FALSE);
235  		if (value) {
236  			long int tmp;
237  			guint32 timeout;
238  	
239  			errno = 0;
240  			tmp = strtol (value, NULL, 10);
241  			if (errno == 0 && tmp >= 0 && tmp < G_MAXINT32) {
242  				timeout = (guint32) tmp;
243  				g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, timeout, NULL);
244  			} else
245  				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid GATEWAY_PING_TIMEOUT time");
246  			g_free (value);
247  		}
248  	
249  		return NM_SETTING (s_con);
250  	}
251  	
252  	static gboolean
253  	read_mac_address (shvarFile *ifcfg, const char *key, int type,
254  	                  GByteArray **array, GError **error)
255  	{
256  		char *value = NULL;
257  	
258  		g_return_val_if_fail (ifcfg != NULL, FALSE);
259  		g_return_val_if_fail (array != NULL, FALSE);
260  		g_return_val_if_fail (*array == NULL, FALSE);
261  		if (error)
262  			g_return_val_if_fail (*error == NULL, FALSE);
263  	
264  		value = svGetValue (ifcfg, key, FALSE);
265  		if (!value || !strlen (value)) {
266  			g_free (value);
267  			return TRUE;
268  		}
269  	
270  		*array = nm_utils_hwaddr_atoba (value, type);
271  		if (!*array) {
272  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
273  			             "%s: the MAC address '%s' was invalid.", key, value);
274  			g_free (value);
275  			return FALSE;
276  		}
277  	
278  		g_free (value);
279  		return TRUE;
280  	}
281  	
282  	static void
283  	iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED)
284  	{
285  		/* We are in the child process here; set a different process group to
286  		 * ensure signal isolation between child and parent.
287  		 */
288  		pid_t pid = getpid ();
289  		setpgid (pid, pid);
290  	
291  		/*
292  		 * We blocked signals in main(). We need to restore original signal
293  		 * mask for iscsiadm here so that it can receive signals.
294  		 */
295  		nm_unblock_posix_signals (NULL);
296  	}
297  	
298  	static char *
299  	match_iscsiadm_tag (const char *line, const char *tag, gboolean *skip)
300  	{
301  		char *p;
302  	
303  		if (g_ascii_strncasecmp (line, tag, strlen (tag)))
304  			return NULL;
305  	
306  		p = strchr (line, '=');
307  		if (!p) {
308  			g_warning ("%s: malformed iscsiadm record: no = in '%s'.",
309  			           __func__, line);
310  			*skip = TRUE;
311  			return NULL;
312  		}
313  	
314  		p++; /* advance past = */
315  		return g_strstrip (p);
316  	}
317  	
318  	#define ISCSI_HWADDR_TAG    "iface.hwaddress"
319  	#define ISCSI_BOOTPROTO_TAG "iface.bootproto"
320  	#define ISCSI_IPADDR_TAG    "iface.ipaddress"
321  	#define ISCSI_SUBNET_TAG    "iface.subnet_mask"
322  	#define ISCSI_GATEWAY_TAG   "iface.gateway"
323  	#define ISCSI_DNS1_TAG      "iface.primary_dns"
324  	#define ISCSI_DNS2_TAG      "iface.secondary_dns"
325  	
326  	static gboolean
327  	fill_ip4_setting_from_ibft (shvarFile *ifcfg,
328  	                            NMSettingIP4Config *s_ip4,
329  	                            const char *iscsiadm_path,
330  	                            GError **error)
331  	{
332  		const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL };
333  		const char *envp[1] = { NULL };
334  		gboolean success = FALSE, in_record = FALSE, hwaddr_matched = FALSE, skip = FALSE;
335  		char *out = NULL, *err = NULL;
336  		gint status = 0;
337  		GByteArray *ifcfg_mac = NULL;
338  		char **lines = NULL, **iter;
339  		const char *method = NULL;
340  		guint32 ipaddr;
341  		guint32 gateway;
342  		guint32 dns1;
343  		guint32 dns2;
344  		guint32 prefix = 0;
345  	
346  		g_return_val_if_fail (s_ip4 != NULL, FALSE);
347  		g_return_val_if_fail (iscsiadm_path != NULL, FALSE);
348  	
349  		if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0,
350  		                   iscsiadm_child_setup, NULL, &out, &err, &status, error))
351  			return FALSE;
352  	
353  		if (!WIFEXITED (status)) {
354  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
355  			             "%s exited abnormally.", iscsiadm_path);
356  			goto done;
357  		}
358  	
359  		if (WEXITSTATUS (status) != 0) {
360  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
361  			             "%s exited with error %d.  Message: '%s'",
362  			             iscsiadm_path, WEXITSTATUS (status), err ? err : "(none)");
363  			goto done;
364  		}
365  	
366  		if (!read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &ifcfg_mac, error))
367  			goto done;
368  		/* Ensure we got a MAC */
369  		if (!ifcfg_mac) {
370  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
371  			             "Missing device MAC address (no HWADDR tag present).");
372  			goto done;
373  		}
374  	
375  		memset (&ipaddr, 0, sizeof (ipaddr));
376  		memset (&gateway, 0, sizeof (gateway));
377  		memset (&dns1, 0, sizeof (dns1));
378  		memset (&dns2, 0, sizeof (dns2));
379  	
380  		/* Success, lets parse the output */
381  		lines = g_strsplit_set (out, "\n\r", -1);
382  		for (iter = lines; iter && *iter; iter++) {
383  			char *p;
384  	
385  			if (!g_ascii_strcasecmp (*iter, "# BEGIN RECORD")) {
386  				if (in_record) {
387  					g_warning ("%s: malformed iscsiadm record: already parsing record.", __func__);
388  					skip = TRUE;
389  				}
390  			} else if (!g_ascii_strcasecmp (*iter, "# END RECORD")) {
391  				if (!skip && hwaddr_matched) {
392  					/* Record is good; fill IP4 config with its info */
393  					if (!method) {
394  						g_warning ("%s: malformed iscsiadm record: missing BOOTPROTO.", __func__);
395  						goto done;
396  					}
397  	
398  					g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
399  	
400  					if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
401  						NMIP4Address *addr;
402  	
403  					    if (!ipaddr || !prefix) {
404  							g_warning ("%s: malformed iscsiadm record: BOOTPROTO=static "
405  							           "but missing IP address or prefix.", __func__);
406  							goto done;
407  						}
408  	
409  						addr = nm_ip4_address_new ();
410  						nm_ip4_address_set_address (addr, ipaddr);
411  						nm_ip4_address_set_prefix (addr, prefix);
412  						nm_ip4_address_set_gateway (addr, gateway);
413  						nm_setting_ip4_config_add_address (s_ip4, addr);
414  						nm_ip4_address_unref (addr);
415  	
416  						if (dns1)
417  							nm_setting_ip4_config_add_dns (s_ip4, dns1);
418  						if (dns2)
419  							nm_setting_ip4_config_add_dns (s_ip4, dns2);
420  	
421  						// FIXME: DNS search domains?
422  					}
423  					success = TRUE;
424  					goto done;
425  				}
426  				skip = FALSE;
427  				hwaddr_matched = FALSE;
428  				memset (&ipaddr, 0, sizeof (ipaddr));
429  				memset (&gateway, 0, sizeof (gateway));
430  				memset (&dns1, 0, sizeof (dns1));
431  				memset (&dns2, 0, sizeof (dns2));
432  				prefix = 0;
433  				method = NULL;
434  			}
435  	
436  			if (skip)
437  				continue;
438  	
439  			/* HWADDR */
440  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_HWADDR_TAG, &skip))) {
441  				struct ether_addr *ibft_mac;
442  	
443  				ibft_mac = ether_aton (p);
444  				if (!ibft_mac) {
445  					g_warning ("%s: malformed iscsiadm record: invalid hwaddress.", __func__);
446  					skip = TRUE;
447  					continue;
448  				}
449  	
450  				if (memcmp (ifcfg_mac->data, (guint8 *) ibft_mac->ether_addr_octet, ETH_ALEN)) {
451  					/* This record isn't for the current device, ignore it */
452  					skip = TRUE;
453  					continue;
454  				}
455  	
456  				/* Success, this record is for this device */
457  				hwaddr_matched = TRUE;
458  			}
459  	
460  			/* BOOTPROTO */
461  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_BOOTPROTO_TAG, &skip))) {
462  				if (!g_ascii_strcasecmp (p, "dhcp"))
463  					method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
464  				else if (!g_ascii_strcasecmp (p, "static"))
465  					method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
466  				else {
467  					g_warning ("%s: malformed iscsiadm record: unknown BOOTPROTO '%s'.",
468  					           __func__, p);
469  					skip = TRUE;
470  					continue;
471  				}
472  			}
473  	
474  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_IPADDR_TAG, &skip))) {
475  				if (inet_pton (AF_INET, p, &ipaddr) < 1) {
476  					g_warning ("%s: malformed iscsiadm record: invalid IP address '%s'.",
477  					           __func__, p);
478  					skip = TRUE;
479  					continue;
480  				}
481  			}
482  	
483  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_SUBNET_TAG, &skip))) {
484  				guint32 mask;
485  	
486  				if (inet_pton (AF_INET, p, &mask) < 1) {
487  					g_warning ("%s: malformed iscsiadm record: invalid subnet mask '%s'.",
488  					           __func__, p);
489  					skip = TRUE;
490  					continue;
491  				}
492  	
493  				prefix = nm_utils_ip4_netmask_to_prefix (mask);
494  			}
495  	
496  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_GATEWAY_TAG, &skip))) {
497  				if (inet_pton (AF_INET, p, &gateway) < 1) {
498  					g_warning ("%s: malformed iscsiadm record: invalid IP gateway '%s'.",
499  					           __func__, p);
500  					skip = TRUE;
501  					continue;
502  				}
503  			}
504  	
505  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS1_TAG, &skip))) {
506  				if (inet_pton (AF_INET, p, &dns1) < 1) {
507  					g_warning ("%s: malformed iscsiadm record: invalid DNS1 address '%s'.",
508  					           __func__, p);
509  					skip = TRUE;
510  					continue;
511  				}
512  			}
513  	
514  			if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS2_TAG, &skip))) {
515  				if (inet_pton (AF_INET, p, &dns2) < 1) {
516  					g_warning ("%s: malformed iscsiadm record: invalid DNS2 address '%s'.",
517  					           __func__, p);
518  					skip = TRUE;
519  					continue;
520  				}
521  			}
522  		}
523  	
524  		success = TRUE;
525  	
526  	done:
527  		if (ifcfg_mac)
528  			g_byte_array_free (ifcfg_mac, TRUE);
529  		g_strfreev (lines);
530  		g_free (out);
531  		g_free (err);
532  		return success;
533  	}
534  	
535  	/* Returns TRUE on missing address or valid address */
536  	static gboolean
537  	read_ip4_address (shvarFile *ifcfg,
538  	                  const char *tag,
539  	                  guint32 *out_addr,
540  	                  GError **error)
541  	{
542  		char *value = NULL;
543  		guint32 ip4_addr;
544  		gboolean success = FALSE;
545  	
546  		g_return_val_if_fail (ifcfg != NULL, FALSE);
547  		g_return_val_if_fail (tag != NULL, FALSE);
548  		g_return_val_if_fail (out_addr != NULL, FALSE);
549  		if (error)
550  			g_return_val_if_fail (*error == NULL, FALSE);
551  	
552  		*out_addr = 0;
553  	
554  		value = svGetValue (ifcfg, tag, FALSE);
555  		if (!value)
556  			return TRUE;
557  	
558  		if (inet_pton (AF_INET, value, &ip4_addr) > 0) {
559  			*out_addr = ip4_addr;
560  			success = TRUE;
561  		} else {
562  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
563  			             "Invalid %s IP4 address '%s'", tag, value);
564  		}
565  		g_free (value);
566  		return success;
567  	}
568  	
569  	/* Returns TRUE on valid address, including unspecified (::) */
570  	static gboolean
571  	parse_ip6_address (const char *value,
572  	                   struct in6_addr *out_addr,
573  	                   GError **error)
574  	{
575  		struct in6_addr ip6_addr;
576  	
577  		g_return_val_if_fail (value != NULL, FALSE);
578  		g_return_val_if_fail (out_addr != NULL, FALSE);
579  		if (error)
580  			g_return_val_if_fail (*error == NULL, FALSE);
581  	
582  		*out_addr = in6addr_any;
583  		if (inet_pton (AF_INET6, value, &ip6_addr) <= 0) {
584  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
585  			             "Invalid IP6 address '%s'", value);
586  			return FALSE;
587  		}
588  	
589  		*out_addr = ip6_addr;
590  		return TRUE;
591  	}
592  	
593  	static char *
594  	get_numbered_tag (char *tag_name, int which)
595  	{
596  		if (which == -1)
597  			return g_strdup (tag_name);
598  		return g_strdup_printf ("%s%u", tag_name, which);
599  	}
600  	
601  	static gboolean
602  	is_any_ip4_address_defined (shvarFile *ifcfg)
603  	{
604  		int i;
605  	
606  		for (i = -1; i <= 2; i++) {
607  			char *tag;
608  			char *value;
609  	
610  			tag = get_numbered_tag ("IPADDR", i);
611  			value = svGetValue (ifcfg, tag, FALSE);
612  			g_free (tag);
613  			if (value) {
614  				g_free (value);
615  				return TRUE;
616  			}
617  	
618  			tag = get_numbered_tag ("PREFIX", i);
619  			value = svGetValue (ifcfg, tag, FALSE);
620  			g_free(tag);
621  			if (value) {
622  				g_free (value);
623  				return TRUE;
624  			}
625  	
626  			tag = get_numbered_tag ("NETMASK", i);
627  			value = svGetValue (ifcfg, tag, FALSE);
628  			g_free(tag);
629  			if (value) {
630  				g_free (value);
631  				return TRUE;
632  			}
633  		}
634  		return FALSE;
635  	}
636  	
637  	/* Returns TRUE on missing address or valid address */
638  	static gboolean
639  	read_full_ip4_address (shvarFile *ifcfg,
640  	                       const char *network_file,
641  	                       gint32 which,
642  	                       NMIP4Address **out_address,
643  	                       GError **error)
644  	{
645  		NMIP4Address *addr;
646  		char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
647  		guint32 tmp;
648  		gboolean success = FALSE;
649  		shvarFile *network_ifcfg;
650  		char *value;
651  	
652  		g_return_val_if_fail (which >= -1, FALSE);
653  		g_return_val_if_fail (ifcfg != NULL, FALSE);
654  		g_return_val_if_fail (network_file != NULL, FALSE);
655  		g_return_val_if_fail (out_address != NULL, FALSE);
656  		g_return_val_if_fail (*out_address == NULL, FALSE);
657  		if (error)
658  			g_return_val_if_fail (*error == NULL, FALSE);
659  	
660  		addr = nm_ip4_address_new ();
661  		ip_tag = get_numbered_tag ("IPADDR", which);
662  		prefix_tag = get_numbered_tag ("PREFIX", which);
663  		netmask_tag = get_numbered_tag ("NETMASK", which);
664  		gw_tag = get_numbered_tag ("GATEWAY", which);
665  	
666  		/* IP address */
667  		if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
668  			goto done;
669  		if (!tmp) {
670  			nm_ip4_address_unref (addr);
671  			addr = NULL;
672  			success = TRUE;  /* done */
673  			goto done;
674  		}
675  		nm_ip4_address_set_address (addr, tmp);
676  	
677  		/* Gateway */
678  		if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
679  			goto done;
680  		if (tmp)
681  			nm_ip4_address_set_gateway (addr, tmp);
682  		else {
683  			gboolean read_success;
684  	
685  			/* If no gateway in the ifcfg, try /etc/sysconfig/network instead */
686  			network_ifcfg = svNewFile (network_file);
687  			if (network_ifcfg) {
688  				read_success = read_ip4_address (network_ifcfg, "GATEWAY", &tmp, error);
689  				svCloseFile (network_ifcfg);
690  				if (!read_success)
691  					goto done;
692  				nm_ip4_address_set_gateway (addr, tmp);
693  			}
694  		}
695  	
696  		/* Prefix */
697  		value = svGetValue (ifcfg, prefix_tag, FALSE);
698  		if (value) {
699  			long int prefix;
700  	
701  			errno = 0;
702  			prefix = strtol (value, NULL, 10);
703  			if (errno || prefix <= 0 || prefix > 32) {
704  				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
705  				             "Invalid IP4 prefix '%s'", value);
706  				g_free (value);
707  				goto done;
708  			}
709  			nm_ip4_address_set_prefix (addr, (guint32) prefix);
710  			g_free (value);
711  		}
712  	
713  		/* Fall back to NETMASK if no PREFIX was specified */
714  		if (!nm_ip4_address_get_prefix (addr)) {
715  			if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
716  				goto done;
717  			if (tmp)
718  				nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (tmp));
719  		}
720  	
721  		/* Try to autodetermine the prefix for the address' class */
722  		if (!nm_ip4_address_get_prefix (addr)) {
723  			guint32 prefix = 0;
724  	
725  			prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
726  			nm_ip4_address_set_prefix (addr, prefix);
727  	
728  			value = svGetValue (ifcfg, ip_tag, FALSE);
729  			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing %s, assuming %s/%u",
730  			             prefix_tag, value, prefix);
731  			g_free (value);
732  		}
733  	
734  		/* Validate the prefix */
735  		if (nm_ip4_address_get_prefix (addr) > 32) {
736  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
737  			             "Missing or invalid IP4 prefix '%d'",
738  			             nm_ip4_address_get_prefix (addr));
739  			goto done;
740  		}
741  	
742  		*out_address = addr;
743  		success = TRUE;
744  	
745  	done:
746  		if (!success && addr)
747  			nm_ip4_address_unref (addr);
748  	
749  		g_free (ip_tag);
750  		g_free (prefix_tag);
751  		g_free (netmask_tag);
752  		g_free (gw_tag);
753  	
754  		return success;
755  	}
756  	
757  	/* Returns TRUE on missing route or valid route */
758  	static gboolean
759  	read_one_ip4_route (shvarFile *ifcfg,
760  	                    const char *network_file,
761  	                    guint32 which,
762  	                    NMIP4Route **out_route,
763  	                    GError **error)
764  	{
765  		NMIP4Route *route;
766  		char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
767  		guint32 tmp;
768  		gboolean success = FALSE;
769  	
770  		g_return_val_if_fail (ifcfg != NULL, FALSE);
771  		g_return_val_if_fail (network_file != NULL, FALSE);
772  		g_return_val_if_fail (out_route != NULL, FALSE);
773  		g_return_val_if_fail (*out_route == NULL, FALSE);
774  		if (error)
775  			g_return_val_if_fail (*error == NULL, FALSE);
776  	
777  		route = nm_ip4_route_new ();
778  	
779  		ip_tag = g_strdup_printf ("ADDRESS%u", which);
780  		netmask_tag = g_strdup_printf ("NETMASK%u", which);
781  		gw_tag = g_strdup_printf ("GATEWAY%u", which);
782  		metric_tag = g_strdup_printf ("METRIC%u", which);
783  	
784  		/* Destination */
785  		if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
786  			goto out;
787  		if (!tmp) {
788  			/* Check whether IP is missing or 0.0.0.0 */
789  			char *val;
790  			val = svGetValue (ifcfg, ip_tag, FALSE);
791  			if (!val) {
792  				nm_ip4_route_unref (route);
793  				route = NULL;
794  				success = TRUE;  /* missing route = success */
795  				goto out;
796  			}
797  			g_free (val);
798  		}
799  		nm_ip4_route_set_dest (route, tmp);
800  	
801  		/* Next hop */
802  		if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
803  			goto out;
804  		/* No need to check tmp, because we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
805  		nm_ip4_route_set_next_hop (route, tmp);
806  	
807  		/* Prefix */
808  		if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
809  			goto out;
810  		if (tmp)
811  			nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (tmp));
812  	
813  		/* Validate the prefix */
814  		if (  !nm_ip4_route_get_prefix (route)
815  		    || nm_ip4_route_get_prefix (route) > 32) {
816  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
817  			             "Missing or invalid IP4 prefix '%d'",
818  			             nm_ip4_route_get_prefix (route));
819  			goto out;
820  		}
821  	
822  		/* Metric */
823  		value = svGetValue (ifcfg, metric_tag, FALSE);
824  		if (value) {
825  			long int metric;
826  	
827  			errno = 0;
828  			metric = strtol (value, NULL, 10);
829  			if (errno || metric < 0) {
830  				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
831  				             "Invalid IP4 route metric '%s'", value);
832  				g_free (value);
833  				goto out;
834  			}
835  			nm_ip4_route_set_metric (route, (guint32) metric);
836  			g_free (value);
837  		}
838  	
839  		*out_route = route;
840  		success = TRUE;
841  	
842  	out:
843  		if (!success && route)
844  			nm_ip4_route_unref (route);
845  	
846  		g_free (ip_tag);
847  		g_free (netmask_tag);
848  		g_free (gw_tag);
849  		g_free (metric_tag);
850  		return success;
851  	}
852  	
853  	static gboolean
854  	read_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError **error)
855  	{
856  		char *contents = NULL;
857  		gsize len = 0;
858  		char **lines = NULL, **iter;
859  		GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
860  		GMatchInfo *match_info;
861  		NMIP4Route *route;
862  		guint32 ip4_addr;
863  		char *dest = NULL, *prefix = NULL, *metric = NULL;
864  		long int prefix_int, metric_int;
865  		gboolean success = FALSE;
866  	
867  		const char *pattern_empty = "^\\s*(\\#.*)?$";
868  		const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)"  /* IP or 'default' keyword */
869  		                          "(?:/(\\d{1,2}))?";                                         /* optional prefix */
870  		const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
871  		                          "(?:/(\\d{1,2}))?";                                         /* optional prefix */
872  		const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})";       /* IP of gateway */
873  		const char *pattern_metric = "metric\\s+(\\d+)";                                      /* metric */
874  	
875  		g_return_val_if_fail (filename != NULL, FALSE);
876  		g_return_val_if_fail (s_ip4 != NULL, FALSE);
877  		if (error)
878  			g_return_val_if_fail (*error == NULL, FALSE);
879  	
880  		/* Read the route file */
881  		if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
882  			g_free (contents);
883  			return TRUE;  /* missing/empty = success */
884  		}
885  	
886  		/* Create regexes for pieces to be matched */
887  		regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
888  		regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
889  		regex_via = g_regex_new (pattern_via, 0, 0, NULL);
890  		regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
891  	
892  		/* New NMIP4Route structure */
893  		route = nm_ip4_route_new ();
894  	
895  		/* Iterate through file lines */
896  		lines = g_strsplit_set (contents, "\n\r", -1);
897  		for (iter = lines; iter && *iter; iter++) {
898  	
899  			/* Skip empty lines */
900  			if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
901  				continue;
902  	
903  			/* Destination */
904  			g_regex_match (regex_to1, *iter, 0, &match_info);
905  			if (!g_match_info_matches (match_info)) {
906  				g_match_info_free (match_info);
907  				g_regex_match (regex_to2, *iter, 0, &match_info);
908  				if (!g_match_info_matches (match_info)) {
909  					g_match_info_free (match_info);
910  					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
911  						     "Missing IP4 route destination address in record: '%s'", *iter);
912  					goto error;
913  				}
914  			}
915  			dest = g_match_info_fetch (match_info, 1);
916  			if (!strcmp (dest, "default"))
917  				strcpy (dest, "0.0.0.0");
918  			if (inet_pton (AF_INET, dest, &ip4_addr) != 1) {
919  				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
920  					     "Invalid IP4 route destination address '%s'", dest);
921  				g_free (dest);
922  				goto error;
923  			}
924  			nm_ip4_route_set_dest (route, ip4_addr);
925  			g_free (dest);
926  	
927  			/* Prefix - is optional; 32 if missing */
928  			prefix = g_match_info_fetch (match_info, 2);
929  			g_match_info_free (match_info);
930  			prefix_int = 32;
931  			if (prefix) {
932  				errno = 0;
933  				prefix_int = strtol (prefix, NULL, 10);
934  				if (errno || prefix_int <= 0 || prefix_int > 32) {
935  					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
936  						     "Invalid IP4 route destination prefix '%s'", prefix);
937  					g_free (prefix);
938  					goto error;
939  				}
940  			}
941  			nm_ip4_route_set_prefix (route, (guint32) prefix_int);
942  			g_free (prefix);
943  	
944  			/* Next hop */
945  			g_regex_match (regex_via, *iter, 0, &match_info);
946  			if (g_match_info_matches (match_info)) {
947  				char *next_hop = g_match_info_fetch (match_info, 1);
948  				if (inet_pton (AF_INET, next_hop, &ip4_addr) != 1) {
949  					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
950  					             "Invalid IP4 route gateway address '%s'",
951  					             next_hop);
952  					g_match_info_free (match_info);
953  					g_free (next_hop);
954  					goto error;
955  				}
956  				g_free (next_hop);
957  			} else {
958  				/* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
959  				ip4_addr = 0;
960  			}
961  			nm_ip4_route_set_next_hop (route, ip4_addr);
962  			g_match_info_free (match_info);
963  	
964  			/* Metric */
965  			g_regex_match (regex_metric, *iter, 0, &match_info);
966  			metric_int = 0;
967  			if (g_match_info_matches (match_info)) {
968  				metric = g_match_info_fetch (match_info, 1);
969  				errno = 0;
970  				metric_int = strtol (metric, NULL, 10);
971  				if (errno || metric_int < 0) {
972  					g_match_info_free (match_info);
973  					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
974  					             "Invalid IP4 route metric '%s'", metric);
975  					g_free (metric);
976  					goto error;
977  				}
978  				g_free (metric);
979  			}
980  	
981  			nm_ip4_route_set_metric (route, (guint32) metric_int);
982  			g_match_info_free (match_info);
983  	
984  			if (!nm_setting_ip4_config_add_route (s_ip4, route))
985  				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 route");
986  	
987  		}
988  	
989  		success = TRUE;
990  	
991  	error:
992  		g_free (contents);
993  		g_strfreev (lines);
994  		nm_ip4_route_unref (route);
995  		g_regex_unref (regex_to1);
996  		g_regex_unref (regex_to2);
997  		g_regex_unref (regex_via);
998  		g_regex_unref (regex_metric);
999  	
1000 		return success;
1001 	}
1002 	
1003 	static gboolean
1004 	parse_full_ip6_address (shvarFile *ifcfg,
1005 	                        const char *network_file,
1006 	                        const char *addr_str,
1007 	                        int i,
1008 	                        NMIP6Address **out_address,
1009 	                        GError **error)
1010 	{
1011 		NMIP6Address *addr = NULL;
1012 		char **list;
1013 		char *ip_val, *prefix_val;
1014 		shvarFile *network_ifcfg;
1015 		char *value = NULL;
1016 		struct in6_addr tmp = IN6ADDR_ANY_INIT;
1017 		gboolean success = FALSE;
1018 	
1019 		g_return_val_if_fail (addr_str != NULL, FALSE);
1020 		g_return_val_if_fail (out_address != NULL, FALSE);
1021 		g_return_val_if_fail (*out_address == NULL, FALSE);
1022 		if (error)
1023 			g_return_val_if_fail (*error == NULL, FALSE);
1024 	
1025 		/* Split the address and prefix */
1026 		list = g_strsplit_set (addr_str, "/", 2);
1027 		if (g_strv_length (list) < 1) {
1028 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1029 			             "Invalid IP6 address '%s'", addr_str);
1030 			goto error;
1031 		}
1032 	
1033 		ip_val = list[0];
1034 		prefix_val = list[1];
1035 	
1036 		addr = nm_ip6_address_new ();
1037 		/* IP address */
1038 		if (!parse_ip6_address (ip_val, &tmp, error))
1039 			goto error;
1040 		if (IN6_IS_ADDR_UNSPECIFIED (&tmp)) {
1041 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1042 			             "Invalid IP6 address '%s'", ip_val);
1043 			goto error;
1044 		}
1045 		nm_ip6_address_set_address (addr, &tmp);
1046 	
1047 		/* Prefix */
1048 		if (prefix_val) {
1049 			long int prefix;
1050 	
1051 			errno = 0;
1052 			prefix = strtol (prefix_val, NULL, 10);
1053 			if (errno || prefix <= 0 || prefix > 128) {
1054 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1055 				             "Invalid IP6 prefix '%s'", prefix_val);
1056 				goto error;
1057 			}
1058 			nm_ip6_address_set_prefix (addr, (guint32) prefix);
1059 		} else {
1060 			/* Missing prefix is treated as prefix of 64 */
1061 			nm_ip6_address_set_prefix (addr, 64);
1062 		}
1063 	
1064 		/* Gateway */
1065 		tmp = in6addr_any;
1066 		value = svGetValue (ifcfg, "IPV6_DEFAULTGW", FALSE);
1067 		if (i != 0) {
1068 			/* We don't support gateways for IPV6ADDR_SECONDARIES yet */
1069 			g_free (value);
1070 			value = NULL;
1071 		}
1072 		if (!value) {
1073 			/* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */
1074 			network_ifcfg = svNewFile (network_file);
1075 			if (network_ifcfg) {
1076 				value = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1077 				svCloseFile (network_ifcfg);
1078 			}
1079 		}
1080 		if (value) {
1081 			char *ptr;
1082 	
1083 			if ((ptr = strchr (value, '%')) != NULL)
1084 				*ptr = '\0';  /* remove %interface prefix if present */
1085 			if (!parse_ip6_address (value, &tmp, error))
1086 				goto error;
1087 			nm_ip6_address_set_gateway (addr, &tmp);
1088 		}
1089 	
1090 		*out_address = addr;
1091 		success = TRUE;
1092 	
1093 	error:
1094 		if (!success && addr)
1095 			nm_ip6_address_unref (addr);
1096 	
1097 		g_strfreev (list);
1098 		g_free (value);
1099 		return success;
1100 	}
1101 	
1102 	/* IPv6 address is very complex to describe completely by a regular expression,
1103 	 * so don't try to, rather use looser syntax to comprise all possibilities
1104 	 * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
1105 	 * namely destination IP without 'to' keyword is recognized just at line start.
1106 	 */
1107 	#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
1108 	
1109 	static gboolean
1110 	read_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **error)
1111 	{
1112 		char *contents = NULL;
1113 		gsize len = 0;
1114 		char **lines = NULL, **iter;
1115 		GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
1116 		GMatchInfo *match_info;
1117 		NMIP6Route *route;
1118 		struct in6_addr ip6_addr;
1119 		char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
1120 		long int prefix_int, metric_int;
1121 		gboolean success = FALSE;
1122 	
1123 		const char *pattern_empty = "^\\s*(\\#.*)?$";
1124 		const char *pattern_to1 = "^\\s*(default|" IPV6_ADDR_REGEX ")"  /* IPv6 or 'default' keyword */
1125 		                          "(?:/(\\d{1,3}))?";                   /* optional prefix */
1126 		const char *pattern_to2 = "to\\s+(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
1127 		                          "(?:/(\\d{1,3}))?";                   /* optional prefix */
1128 		const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")";       /* IPv6 of gateway */
1129 		const char *pattern_metric = "metric\\s+(\\d+)";                /* metric */
1130 	
1131 		g_return_val_if_fail (filename != NULL, FALSE);
1132 		g_return_val_if_fail (s_ip6 != NULL, FALSE);
1133 		if (error)
1134 			g_return_val_if_fail (*error == NULL, FALSE);
1135 	
1136 		/* Read the route file */
1137 		if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
1138 			g_free (contents);
1139 			return TRUE;  /* missing/empty = success */
1140 		}
1141 	
1142 		/* Create regexes for pieces to be matched */
1143 		regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
1144 		regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
1145 		regex_via = g_regex_new (pattern_via, 0, 0, NULL);
1146 		regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
1147 	
1148 		/* New NMIP6Route structure */
1149 		route = nm_ip6_route_new ();
1150 	
1151 		/* Iterate through file lines */
1152 		lines = g_strsplit_set (contents, "\n\r", -1);
1153 		for (iter = lines; iter && *iter; iter++) {
1154 	
1155 			/* Skip empty lines */
1156 			if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
1157 				continue;
1158 	
1159 			/* Destination */
1160 			g_regex_match (regex_to1, *iter, 0, &match_info);
1161 			if (!g_match_info_matches (match_info)) {
1162 				g_match_info_free (match_info);
1163 				g_regex_match (regex_to2, *iter, 0, &match_info);
1164 				if (!g_match_info_matches (match_info)) {
1165 					g_match_info_free (match_info);
1166 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1167 						     "Missing IP6 route destination address in record: '%s'", *iter);
1168 					goto error;
1169 				}
1170 			}
1171 			dest = g_match_info_fetch (match_info, 1);
1172 			if (!g_strcmp0 (dest, "default")) {
1173 				/* Ignore default route - NM handles it internally */
1174 				g_free (dest);
1175 				g_match_info_free (match_info);
1176 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring manual default route: '%s' (%s)",
1177 				             *iter, filename);
1178 				continue;
1179 			}
1180 			if (inet_pton (AF_INET6, dest, &ip6_addr) != 1) {
1181 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1182 					     "Invalid IP6 route destination address '%s'", dest);
1183 				g_free (dest);
1184 				goto error;
1185 			}
1186 			nm_ip6_route_set_dest (route, &ip6_addr);
1187 			g_free (dest);
1188 	
1189 			/* Prefix - is optional; 128 if missing */
1190 			prefix = g_match_info_fetch (match_info, 2);
1191 			g_match_info_free (match_info);
1192 			prefix_int = 128;
1193 			if (prefix) {
1194 				errno = 0;
1195 				prefix_int = strtol (prefix, NULL, 10);
1196 				if (errno || prefix_int <= 0 || prefix_int > 128) {
1197 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1198 						     "Invalid IP6 route destination prefix '%s'", prefix);
1199 					g_free (prefix);
1200 					goto error;
1201 				}
1202 			}
1203 			nm_ip6_route_set_prefix (route, (guint32) prefix_int);
1204 			g_free (prefix);
1205 	
1206 			/* Next hop */
1207 			g_regex_match (regex_via, *iter, 0, &match_info);
1208 			if (!g_match_info_matches (match_info)) {
1209 				g_match_info_free (match_info);
1210 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1211 				             "Missing IP6 route gateway address in record: '%s'", *iter);
1212 				goto error;
1213 			}
1214 			next_hop = g_match_info_fetch (match_info, 1);
1215 			g_match_info_free (match_info);
1216 			if (inet_pton (AF_INET6, next_hop, &ip6_addr) != 1) {
1217 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1218 				             "Invalid IP6 route gateway address '%s'", next_hop);
1219 				g_free (next_hop);
1220 				goto error;
1221 			}
1222 			nm_ip6_route_set_next_hop (route, &ip6_addr);
1223 			g_free (next_hop);
1224 	
1225 			/* Metric */
1226 			g_regex_match (regex_metric, *iter, 0, &match_info);
1227 			metric_int = 0;
1228 			if (g_match_info_matches (match_info)) {
1229 				metric = g_match_info_fetch (match_info, 1);
1230 				errno = 0;
1231 				metric_int = strtol (metric, NULL, 10);
1232 				if (errno || metric_int < 0 || metric_int > G_MAXUINT32) {
1233 					g_match_info_free (match_info);
1234 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1235 					             "Invalid IP6 route metric '%s'", metric);
1236 					g_free (metric);
1237 					goto error;
1238 				}
1239 				g_free (metric);
1240 			}
1241 	
1242 			nm_ip6_route_set_metric (route, (guint32) metric_int);
1243 			g_match_info_free (match_info);
1244 	
1245 			if (!nm_setting_ip6_config_add_route (s_ip6, route))
1246 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP6 route");
1247 		}
1248 	
1249 		success = TRUE;
1250 	
1251 	error:
1252 		g_free (contents);
1253 		g_strfreev (lines);
1254 		nm_ip6_route_unref (route);
1255 		g_regex_unref (regex_to1);
1256 		g_regex_unref (regex_to2);
1257 		g_regex_unref (regex_via);
1258 		g_regex_unref (regex_metric);
1259 	
1260 		return success;
1261 	}
1262 	
1263 	
1264 	static NMSetting *
1265 	make_ip4_setting (shvarFile *ifcfg,
1266 	                  const char *network_file,
1267 	                  const char *iscsiadm_path,
1268 	                  GError **error)
1269 	{
1270 		NMSettingIP4Config *s_ip4 = NULL;
1271 		char *value = NULL;
1272 		char *route_path = NULL;
1273 		char *method;
1274 		gint32 i;
1275 		shvarFile *network_ifcfg;
1276 		shvarFile *route_ifcfg;
1277 		gboolean never_default = FALSE;
1278 	
1279 		s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
1280 	
1281 		/* First check if DEFROUTE is set for this device; DEFROUTE has the
1282 		 * opposite meaning from never-default. The default if DEFROUTE is not
1283 		 * specified is DEFROUTE=yes which means that this connection can be used
1284 		 * as a default route
1285 		 */
1286 		never_default = !svTrueValue (ifcfg, "DEFROUTE", TRUE);
1287 	
1288 		/* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
1289 		network_ifcfg = svNewFile (network_file);
1290 		if (network_ifcfg) {
1291 			char *gatewaydev;
1292 	
1293 			/* Get the connection ifcfg device name and the global gateway device */
1294 			value = svGetValue (ifcfg, "DEVICE", FALSE);
1295 			gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
1296 	
1297 			/* If there was a global gateway device specified, then only connections
1298 			 * for that device can be the default connection.
1299 			 */
1300 			if (gatewaydev && value)
1301 				never_default = !!strcmp (value, gatewaydev);
1302 	
1303 			g_free (gatewaydev);
1304 			g_free (value);
1305 			svCloseFile (network_ifcfg);
1306 		}
1307 	
1308 		value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
1309 	
1310 		if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
1311 			if (is_any_ip4_address_defined (ifcfg))
1312 				method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
1313 			else
1314 				method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
1315 		} else if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
1316 			method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
1317 		} else if (!g_ascii_strcasecmp (value, "static")) {
1318 			method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
1319 		} else if (!g_ascii_strcasecmp (value, "ibft")) {
1320 			g_free (value);
1321 			g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default, NULL);
1322 			/* iSCSI Boot Firmware Table: need to read values from the iSCSI
1323 			 * firmware for this device and create the IP4 setting using those.
1324 			 */
1325 			if (fill_ip4_setting_from_ibft (ifcfg, s_ip4, iscsiadm_path, error))
1326 				return NM_SETTING (s_ip4);
1327 			g_object_unref (s_ip4);
1328 			return NULL;
1329 		} else if (!g_ascii_strcasecmp (value, "autoip")) {
1330 			g_free (value);
1331 			g_object_set (s_ip4,
1332 			              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
1333 			              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1334 			              NULL);
1335 			return NM_SETTING (s_ip4);
1336 		} else if (!g_ascii_strcasecmp (value, "shared")) {
1337 			g_free (value);
1338 			g_object_set (s_ip4,
1339 			              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
1340 			              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1341 			              NULL);
1342 			return NM_SETTING (s_ip4);
1343 		} else {
1344 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1345 			             "Unknown BOOTPROTO '%s'", value);
1346 			g_free (value);
1347 			goto done;
1348 		}
1349 		g_free (value);
1350 	
1351 		g_object_set (s_ip4,
1352 		              NM_SETTING_IP4_CONFIG_METHOD, method,
1353 		              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
1354 		              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
1355 		              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1356 		              NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
1357 		              NULL);
1358 	
1359 		if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
1360 			return NM_SETTING (s_ip4);
1361 	
1362 		/* Handle DHCP settings */
1363 		if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
1364 			value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
1365 			if (value && strlen (value))
1366 				g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, value, NULL);
1367 			g_free (value);
1368 	
1369 			value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE);
1370 			if (value && strlen (value))
1371 				g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
1372 			g_free (value);
1373 		}
1374 	
1375 		/* Read static IP addresses.
1376 		 * Read them even for AUTO method - in this case the addresses are
1377 		 * added to the automatic ones. Note that this is not currently supported by
1378 		 * the legacy 'network' service (ifup-eth).
1379 		 */
1380 		for (i = -1; i < 256; i++) {
1381 			NMIP4Address *addr = NULL;
1382 	
1383 			if (!read_full_ip4_address (ifcfg, network_file, i, &addr, error))
1384 				goto done;
1385 			if (!addr) {
1386 				/* The first mandatory variable is 2-indexed (IPADDR2)
1387 				 * Variables IPADDR, IPADDR0 and IPADDR1 are optional */
1388 				if (i > 1)
1389 					break;
1390 				continue;
1391 			}
1392 	
1393 			if (!nm_setting_ip4_config_add_address (s_ip4, addr))
1394 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 address");
1395 			nm_ip4_address_unref (addr);
1396 		}
1397 	
1398 		/* DNS servers
1399 		 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
1400 		 */
1401 		for (i = 1; i <= 10; i++) {
1402 			char *tag;
1403 			guint32 dns;
1404 			struct in6_addr ip6_dns;
1405 	
1406 			tag = g_strdup_printf ("DNS%u", i);
1407 			if (!read_ip4_address (ifcfg, tag, &dns, error)) {
1408 				gboolean valid = TRUE;
1409 	
1410 				/* Ignore IPv6 addresses */
1411 				dns = 0;
1412 				value = svGetValue (ifcfg, tag, FALSE);
1413 				if (value)
1414 					valid = parse_ip6_address (value, &ip6_dns, NULL);
1415 				g_free (value);
1416 	
1417 				if (!valid) {
1418 					g_free (tag);
1419 					goto done;
1420 				}
1421 				g_clear_error (error);
1422 			}
1423 	
1424 			if (dns && !nm_setting_ip4_config_add_dns (s_ip4, dns))
1425 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS server %s", tag);
1426 			g_free (tag);
1427 		}
1428 	
1429 		/* DNS searches */
1430 		value = svGetValue (ifcfg, "DOMAIN", FALSE);
1431 		if (value) {
1432 			char **searches = NULL;
1433 	
1434 			searches = g_strsplit (value, " ", 0);
1435 			if (searches) {
1436 				char **item;
1437 				for (item = searches; *item; item++) {
1438 					if (strlen (*item)) {
1439 						if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
1440 							PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS domain '%s'", *item);
1441 					}
1442 				}
1443 				g_strfreev (searches);
1444 			}
1445 			g_free (value);
1446 		}
1447 	
1448 		/* Static routes  - route-<name> file */
1449 		route_path = utils_get_route_path (ifcfg->fileName);
1450 		if (!route_path) {
1451 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1452 			             "Could not get route file path for '%s'", ifcfg->fileName);
1453 			goto done;
1454 		}
1455 	
1456 		/* First test new/legacy syntax */
1457 		if (utils_has_route_file_new_syntax (route_path)) {
1458 			/* Parse route file in new syntax */
1459 			route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
1460 			if (route_ifcfg) {
1461 				for (i = 0; i < 256; i++) {
1462 					NMIP4Route *route = NULL;
1463 	
1464 					if (!read_one_ip4_route (route_ifcfg, network_file, i, &route, error)) {
1465 						svCloseFile (route_ifcfg);
1466 						goto done;
1467 					}
1468 	
1469 					if (!route)
1470 						break;
1471 	
1472 					if (!nm_setting_ip4_config_add_route (s_ip4, route))
1473 						PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 route");
1474 					nm_ip4_route_unref (route);
1475 				}
1476 				svCloseFile (route_ifcfg);
1477 			}
1478 		} else {
1479 			if (!read_route_file_legacy (route_path, s_ip4, error))
1480 				goto done;
1481 		}
1482 	
1483 		/* Legacy value NM used for a while but is incorrect (rh #459370) */
1484 		if (!nm_setting_ip4_config_get_num_dns_searches (s_ip4)) {
1485 			value = svGetValue (ifcfg, "SEARCH", FALSE);
1486 			if (value) {
1487 				char **searches = NULL;
1488 	
1489 				searches = g_strsplit (value, " ", 0);
1490 				if (searches) {
1491 					char **item;
1492 					for (item = searches; *item; item++) {
1493 						if (strlen (*item)) {
1494 							if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
1495 								PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS search '%s'", *item);
1496 						}
1497 					}
1498 					g_strfreev (searches);
1499 				}
1500 				g_free (value);
1501 			}
1502 		}
1503 	
1504 		return NM_SETTING (s_ip4);
1505 	
1506 	done:
1507 		g_free (route_path);
1508 		g_object_unref (s_ip4);
1509 		return NULL;
1510 	}
1511 	
1512 	static NMSetting *
1513 	make_ip6_setting (shvarFile *ifcfg,
1514 	                  const char *network_file,
1515 	                  const char *iscsiadm_path,
1516 	                  GError **error)
1517 	{
1518 		NMSettingIP6Config *s_ip6 = NULL;
1519 		char *value = NULL;
1520 		char *str_value;
1521 		char *route6_path = NULL;
1522 		gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
1523 		char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
1524 		char *ipv6addr, *ipv6addr_secondaries;
1525 		char **list = NULL, **iter;
1526 		guint32 i;
1527 		shvarFile *network_ifcfg;
1528 		gboolean never_default = FALSE;
1529 		gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip;
1530 		char *ip6_privacy_str;
1531 		NMSettingIP6ConfigPrivacy ip6_privacy_val;
1532 	
1533 		s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
1534 	
1535 		/* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the
1536 		 * opposite meaning from never-default. The default if IPV6_DEFROUTE is not
1537 		 * specified is IPV6_DEFROUTE=yes which means that this connection can be used
1538 		 * as a default route
1539 		 */
1540 		never_default = !svTrueValue (ifcfg, "IPV6_DEFROUTE", TRUE);
1541 	
1542 		/* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified;
1543 		 * they are global and override IPV6_DEFROUTE
1544 		 * When both are set, the device specified in IPV6_DEFAULTGW takes preference.
1545 		 */
1546 		network_ifcfg = svNewFile (network_file);
1547 		if (network_ifcfg) {
1548 			char *ipv6_defaultgw, *ipv6_defaultdev;
1549 			char *default_dev = NULL;
1550 	
1551 			/* Get the connection ifcfg device name and the global default route device */
1552 			value = svGetValue (ifcfg, "DEVICE", FALSE);
1553 			ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1554 			ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
1555 	
1556 			if (ipv6_defaultgw) {
1557 				default_dev = strchr (ipv6_defaultgw, '%');
1558 				if (default_dev)
1559 					default_dev++;
1560 			}
1561 			if (!default_dev)
1562 				default_dev = ipv6_defaultdev;
1563 	
1564 			/* If there was a global default route device specified, then only connections
1565 			 * for that device can be the default connection.
1566 			 */
1567 			if (default_dev && value)
1568 				never_default = !!strcmp (value, default_dev);
1569 	
1570 			g_free (ipv6_defaultgw);
1571 			g_free (ipv6_defaultdev);
1572 			g_free (value);
1573 			svCloseFile (network_ifcfg);
1574 		}
1575 	
1576 		/* Find out method property */
1577 		/* Is IPV6 enabled? Set method to "ignored", when not enabled */
1578 		str_value = svGetValue (ifcfg, "IPV6INIT", FALSE);
1579 		ipv6init = svTrueValue (ifcfg, "IPV6INIT", FALSE);
1580 		if (!str_value) {
1581 			network_ifcfg = svNewFile (network_file);
1582 			if (network_ifcfg) {
1583 				ipv6init = svTrueValue (network_ifcfg, "IPV6INIT", FALSE);
1584 				svCloseFile (network_ifcfg);
1585 			}
1586 		}
1587 		g_free (str_value);
1588 	
1589 		if (!ipv6init)
1590 			method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE;  /* IPv6 is disabled */
1591 		else {
1592 			ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE);
1593 			ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding);
1594 			dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE);
1595 	
1596 			if (ipv6_autoconf)
1597 				method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
1598 			else if (dhcp6)
1599 				method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
1600 			else {
1601 				/* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
1602 				str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1603 				if (!str_value)
1604 					str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1605 	
1606 				if (!str_value)
1607 					method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
1608 				g_free (str_value);
1609 			}
1610 		}
1611 		/* TODO - handle other methods */
1612 	
1613 		/* Read IPv6 Privacy Extensions configuration */
1614 		ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
1615 		if (ip6_privacy_str) {
1616 			ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE);
1617 			if (!ip6_privacy)
1618 				ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 ||
1619 				              g_strcmp0 (ip6_privacy_str, "rfc3041") == 0;
1620 		}
1621 		ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
1622 		ip6_privacy_val = ip6_privacy_str ?
1623 		                      (ip6_privacy ?
1624 		                          (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
1625 		                          NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
1626 		                      NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
1627 		g_free (ip6_privacy_str);
1628 	
1629 		g_object_set (s_ip6,
1630 		              NM_SETTING_IP6_CONFIG_METHOD, method,
1631 		              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE),
1632 		              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
1633 		              NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default,
1634 		              NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
1635 		              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
1636 		              NULL);
1637 	
1638 		/* Don't bother to read IP, DNS and routes when IPv6 is disabled */
1639 		if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
1640 			return NM_SETTING (s_ip6);
1641 	
1642 		if (   !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
1643 		    || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
1644 			/* METHOD_AUTO may trigger DHCPv6, so save the hostname to send to DHCP */
1645 			value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
1646 			if (value && value[0])
1647 				g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME, value, NULL);
1648 			g_free (value);
1649 		}
1650 	
1651 		/* Read static IP addresses.
1652 		 * Read them even for AUTO and DHCP methods - in this case the addresses are
1653 		 * added to the automatic ones. Note that this is not currently supported by
1654 		 * the legacy 'network' service (ifup-eth).
1655 		 */
1656 		ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1657 		ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1658 	
1659 		value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
1660 		                   ipv6addr ? ipv6addr : "",
1661 		                   ipv6addr_secondaries ? ipv6addr_secondaries : "",
1662 		                   NULL);
1663 		g_free (ipv6addr);
1664 		g_free (ipv6addr_secondaries);
1665 	
1666 		list = g_strsplit_set (value, " ", 0);
1667 		g_free (value);
1668 		for (iter = list, i = 0; iter && *iter; iter++, i++) {
1669 			NMIP6Address *addr = NULL;
1670 	
1671 			if (!parse_full_ip6_address (ifcfg, network_file, *iter, i, &addr, error)) {
1672 				g_strfreev (list);
1673 				goto error;
1674 			}
1675 	
1676 			if (!nm_setting_ip6_config_add_address (s_ip6, addr))
1677 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP6 address");
1678 			nm_ip6_address_unref (addr);
1679 		}
1680 		g_strfreev (list);
1681 	
1682 		/* DNS servers
1683 		 * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
1684 		 */
1685 		for (i = 1; i <= 10; i++) {
1686 			char *tag;
1687 			struct in6_addr ip6_dns;
1688 			guint32 ip4_addr;
1689 	
1690 			tag = g_strdup_printf ("DNS%u", i);
1691 			value = svGetValue (ifcfg, tag, FALSE);
1692 			if (!value) {
1693 				g_free (tag);
1694 				break; /* all done */
1695 			}
1696 	
1697 			ip6_dns = in6addr_any;
1698 			if (parse_ip6_address (value, &ip6_dns, NULL)) {
1699 				if (!IN6_IS_ADDR_UNSPECIFIED (&ip6_dns) && !nm_setting_ip6_config_add_dns (s_ip6, &ip6_dns))
1700 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS server %s", tag);
1701 			} else {
1702 				/* Maybe an IPv4 address? If so ignore it */
1703 				if (inet_pton (AF_INET, value, &ip4_addr) != 1) {
1704 					g_free (tag);
1705 					g_free (value);
1706 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP6 address");
1707 					goto error;
1708 				}
1709 			}
1710 	
1711 			g_free (tag);
1712 			g_free (value);
1713 		}
1714 	
1715 		/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIP4Config */
1716 	
1717 		/* Read static routes from route6-<interface> file */
1718 		route6_path = utils_get_route6_path (ifcfg->fileName);
1719 		if (!route6_path) {
1720 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1721 			             "Could not get route6 file path for '%s'", ifcfg->fileName);
1722 			goto error;
1723 		}
1724 	
1725 		if (!read_route6_file (route6_path, s_ip6, error))
1726 			goto error;
1727 	
1728 		g_free (route6_path);
1729 		return NM_SETTING (s_ip6);
1730 	
1731 	error:
1732 		g_free (route6_path);
1733 		g_object_unref (s_ip6);
1734 		return NULL;
1735 	}
1736 	
1737 	static void
1738 	check_if_bond_slave (shvarFile *ifcfg,
1739 	                     NMSettingConnection *s_con)
1740 	{
1741 		char *value;
1742 	
1743 		value = svGetValue (ifcfg, "MASTER", FALSE);
1744 		if (value) {
1745 			g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1746 			g_object_set (s_con,
1747 			              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
1748 			              NULL);
1749 			g_free (value);
1750 		}
1751 	}
1752 	
1753 	static void
1754 	check_if_team_slave (shvarFile *ifcfg,
1755 	                     NMSettingConnection *s_con)
1756 	{
1757 		char *value;
1758 	
1759 		value = svGetValue (ifcfg, "DEVICETYPE", FALSE);
1760 		if (!value)
1761 			return;
1762 		if (strcasecmp (value, TYPE_TEAM_PORT)) {
1763 			g_free (value);
1764 			return;
1765 		}
1766 		g_free (value);
1767 		value = svGetValue (ifcfg, "TEAM_MASTER", FALSE);
1768 		if (!value)
1769 			return;
1770 		g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1771 		g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL);
1772 		g_free (value);
1773 	}
1774 	
1775 	static gboolean
1776 	add_one_wep_key (shvarFile *ifcfg,
1777 	                 const char *shvar_key,
1778 	                 guint8 key_idx,
1779 	                 gboolean passphrase,
1780 	                 NMSettingWirelessSecurity *s_wsec,
1781 	                 GError **error)
1782 	{
1783 		char *key = NULL;
1784 		char *value = NULL;
1785 		gboolean success = FALSE;
1786 	
1787 		g_return_val_if_fail (ifcfg != NULL, FALSE);
1788 		g_return_val_if_fail (shvar_key != NULL, FALSE);
1789 		g_return_val_if_fail (key_idx <= 3, FALSE);
1790 		g_return_val_if_fail (s_wsec != NULL, FALSE);
1791 	
1792 		value = svGetValue (ifcfg, shvar_key, FALSE);
1793 		if (!value || !strlen (value)) {
1794 			g_free (value);
1795 			return TRUE;
1796 		}
1797 	
1798 		/* Validate keys */
1799 		if (passphrase) {
1800 			if (strlen (value) && strlen (value) < 64) {
1801 				key = g_strdup (value);
1802 				g_object_set (G_OBJECT (s_wsec),
1803 				              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
1804 				              NM_WEP_KEY_TYPE_PASSPHRASE,
1805 				              NULL);
1806 			}
1807 		} else {
1808 			if (strlen (value) == 10 || strlen (value) == 26) {
1809 				/* Hexadecimal WEP key */
1810 				char *p = value;
1811 	
1812 				while (*p) {
1813 					if (!g_ascii_isxdigit (*p)) {
1814 						g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1815 						             "Invalid hexadecimal WEP key.");
1816 						goto out;
1817 					}
1818 					p++;
1819 				}
1820 				key = g_strdup (value);
1821 			} else if (   !strncmp (value, "s:", 2)
1822 			           && (strlen (value) == 7 || strlen (value) == 15)) {
1823 				/* ASCII key */
1824 				char *p = value + 2;
1825 	
1826 				while (*p) {
1827 					if (!g_ascii_isprint ((int) (*p))) {
1828 						g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1829 						             "Invalid ASCII WEP key.");
1830 						goto out;
1831 					}
1832 					p++;
1833 				}
1834 	
1835 				/* Remove 's:' prefix.
1836 				 * Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array
1837 				 * and converts it to hex string itself. Even though we convert hex string keys into a bin string
1838 				 * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly,
1839 				 * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users.
1840 				 */
1841 				key = g_strdup (value + 2);
1842 			}
1843 		}
1844 	
1845 		if (key) {
1846 			nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
1847 			g_free (key);
1848 			success = TRUE;
1849 		} else
1850 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid WEP key length.");
1851 	
1852 	out:
1853 		g_free (value);
1854 		return success;
1855 	}
1856 	
1857 	static gboolean
1858 	read_wep_keys (shvarFile *ifcfg,
1859 	               guint8 def_idx,
1860 	               NMSettingWirelessSecurity *s_wsec,
1861 	               GError **error)
1862 	{
1863 		/* Try hex/ascii keys first */
1864 		if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error))
1865 			return FALSE;
1866 		if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error))
1867 			return FALSE;
1868 		if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error))
1869 			return FALSE;
1870 		if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error))
1871 			return FALSE;
1872 		if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error))
1873 			return FALSE;
1874 	
1875 		/* And then passphrases */
1876 		if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error))
1877 			return FALSE;
1878 		if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error))
1879 			return FALSE;
1880 		if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error))
1881 			return FALSE;
1882 		if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error))
1883 			return FALSE;
1884 	
1885 		return TRUE;
1886 	}
1887 	
1888 	static NMSettingSecretFlags
1889 	read_secret_flags (shvarFile *ifcfg, const char *flags_key)
1890 	{
1891 		NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
1892 		char *val;
1893 	
1894 		g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE);
1895 		g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
1896 		g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
1897 	
1898 		val = svGetValue (ifcfg, flags_key, FALSE);
1899 		if (val) {
1900 			if (strstr (val, SECRET_FLAG_AGENT))
1901 				flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
1902 			if (strstr (val, SECRET_FLAG_NOT_SAVED))
1903 				flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
1904 			if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
1905 				flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
1906 	
1907 			g_free (val);
1908 		}
1909 		return flags;
1910 	}
1911 	
1912 	static NMSetting *
1913 	make_wep_setting (shvarFile *ifcfg,
1914 	                  const char *file,
1915 	                  GError **error)
1916 	{
1917 		NMSettingWirelessSecurity *s_wsec;
1918 		char *value;
1919 		shvarFile *keys_ifcfg = NULL;
1920 		int default_key_idx = 0;
1921 		gboolean has_default_key = FALSE, success;
1922 		NMSettingSecretFlags key_flags;
1923 	
1924 		s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
1925 		g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
1926 	
1927 		value = svGetValue (ifcfg, "DEFAULTKEY", FALSE);
1928 		if (value) {
1929 			success = get_int (value, &default_key_idx);
1930 			if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
1931 				has_default_key = TRUE;
1932 				default_key_idx--;  /* convert to [0...3] */
1933 				g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
1934 			} else {
1935 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1936 				             "Invalid default WEP key '%s'", value);
1937 		 		g_free (value);
1938 				goto error;
1939 			}
1940 	 		g_free (value);
1941 		}
1942 	
1943 		/* Read WEP key flags */
1944 		key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS");
1945 		g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL);
1946 	
1947 		/* Read keys in the ifcfg file if they are system-owned */
1948 		if (key_flags == NM_SETTING_SECRET_FLAG_NONE) {
1949 			if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error))
1950 				goto error;
1951 	
1952 			/* Try to get keys from the "shadow" key file */
1953 			keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
1954 			if (keys_ifcfg) {
1955 				if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) {
1956 					svCloseFile (keys_ifcfg);
1957 					goto error;
1958 				}
1959 				svCloseFile (keys_ifcfg);
1960 				g_assert (error == NULL || *error == NULL);
1961 			}
1962 		}
1963 	
1964 		value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
1965 		if (value) {
1966 			char *lcase;
1967 	
1968 			lcase = g_ascii_strdown (value, -1);
1969 			g_free (value);
1970 	
1971 			if (!strcmp (lcase, "open")) {
1972 				g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
1973 			} else if (!strcmp (lcase, "restricted")) {
1974 				g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
1975 			} else {
1976 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1977 				             "Invalid WEP authentication algorithm '%s'",
1978 				             lcase);
1979 				g_free (lcase);
1980 				goto error;
1981 			}
1982 			g_free (lcase);
1983 		}
1984 	
1985 		/* If no WEP keys were given, and the keys are not agent-owned, and no
1986 		 * default WEP key index was given, then the connection is unencrypted.
1987 		 */
1988 		if (   !nm_setting_wireless_security_get_wep_key (s_wsec, 0)
1989 		    && !nm_setting_wireless_security_get_wep_key (s_wsec, 1)
1990 		    && !nm_setting_wireless_security_get_wep_key (s_wsec, 2)
1991 		    && !nm_setting_wireless_security_get_wep_key (s_wsec, 3)
1992 		    && (has_default_key == FALSE)
1993 		    && (key_flags == NM_SETTING_SECRET_FLAG_NONE)) {
1994 			const char *auth_alg;
1995 	
1996 			auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
1997 			if (auth_alg && !strcmp (auth_alg, "shared")) {
1998 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1999 				             "WEP Shared Key authentication is invalid for "
2000 				             "unencrypted connections.");
2001 				goto error;
2002 			}
2003 	
2004 			/* Unencrypted */
2005 			g_object_unref (s_wsec);
2006 			s_wsec = NULL;
2007 		}
2008 	
2009 		return (NMSetting *) s_wsec;
2010 	
2011 	error:
2012 		if (s_wsec)
2013 			g_object_unref (s_wsec);
2014 		return NULL;
2015 	}
2016 	
2017 	static gboolean
2018 	fill_wpa_ciphers (shvarFile *ifcfg,
2019 	                  NMSettingWirelessSecurity *wsec,
2020 	                  gboolean group,
2021 	                  gboolean adhoc)
2022 	{
2023 		char *value = NULL, *p;
2024 		char **list = NULL, **iter;
2025 		int i = 0;
2026 	
2027 		p = value = svGetValue (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", TRUE);
2028 		if (!value)
2029 			return TRUE;
2030 	
2031 		/* Strip quotes */
2032 		if (p[0] == '"')
2033 			p++;
2034 		if (p[strlen (p) - 1] == '"')
2035 			p[strlen (p) - 1] = '\0';
2036 	
2037 		list = g_strsplit_set (p, " ", 0);
2038 		for (iter = list; iter && *iter; iter++, i++) {
2039 			/* Ad-Hoc configurations cannot have pairwise ciphers, and can only
2040 			 * have one group cipher.  Ignore any additional group ciphers and
2041 			 * any pairwise ciphers specified.
2042 			 */
2043 			if (adhoc) {
2044 				if (group && (i > 0)) {
2045 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)",
2046 					             *iter);
2047 					continue;
2048 				} else if (!group) {
2049 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)",
2050 					             *iter);
2051 					continue;
2052 				}
2053 			}
2054 	
2055 			if (!strcmp (*iter, "CCMP")) {
2056 				if (group)
2057 					nm_setting_wireless_security_add_group (wsec, "ccmp");
2058 				else
2059 					nm_setting_wireless_security_add_pairwise (wsec, "ccmp");
2060 			} else if (!strcmp (*iter, "TKIP")) {
2061 				if (group)
2062 					nm_setting_wireless_security_add_group (wsec, "tkip");
2063 				else
2064 					nm_setting_wireless_security_add_pairwise (wsec, "tkip");
2065 			} else if (group && !strcmp (*iter, "WEP104"))
2066 				nm_setting_wireless_security_add_group (wsec, "wep104");
2067 			else if (group && !strcmp (*iter, "WEP40"))
2068 				nm_setting_wireless_security_add_group (wsec, "wep40");
2069 			else {
2070 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring invalid %s cipher '%s'",
2071 				             group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
2072 				             *iter);
2073 			}
2074 		}
2075 	
2076 		if (list)
2077 			g_strfreev (list);
2078 		g_free (value);
2079 		return TRUE;
2080 	}
2081 	
2082 	#define WPA_PMK_LEN 32
2083 	
2084 	static char *
2085 	parse_wpa_psk (shvarFile *ifcfg,
2086 	               const char *file,
2087 	               const GByteArray *ssid,
2088 	               GError **error)
2089 	{
2090 		shvarFile *keys_ifcfg;
2091 		char *psk = NULL, *p, *hashed = NULL;
2092 		size_t plen;
2093 		gboolean quoted = FALSE;
2094 	
2095 		/* Passphrase must be between 10 and 66 characters in length because WPA
2096 		 * hex keys are exactly 64 characters (no quoting), and WPA passphrases
2097 		 * are between 8 and 63 characters (inclusive), plus optional quoting if
2098 		 * the passphrase contains spaces.
2099 		 */
2100 	
2101 		/* Try to get keys from the "shadow" key file */
2102 		keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2103 		if (keys_ifcfg) {
2104 			psk = svGetValue (keys_ifcfg, "WPA_PSK", TRUE);
2105 			svCloseFile (keys_ifcfg);
2106 		}
2107 	
2108 		/* Fall back to the original ifcfg */
2109 		if (!psk)
2110 			psk = svGetValue (ifcfg, "WPA_PSK", TRUE);
2111 	
2112 		if (!psk)
2113 			return NULL;
2114 	
2115 		p = psk;
2116 		plen = strlen (p);
2117 	
2118 		if (   (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
2119 		    || (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
2120 			quoted = TRUE;
2121 	
2122 		if (!quoted && (strlen (psk) == 64)) {
2123 			/* Verify the hex PSK; 64 digits */
2124 			while (*p) {
2125 				if (!g_ascii_isxdigit (*p++)) {
2126 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2127 					             "Invalid WPA_PSK (contains non-hexadecimal characters)");
2128 					goto out;
2129 				}
2130 			}
2131 			hashed = g_strdup (psk);
2132 		} else {
2133 			/* Prior to 4f6eef9e77265484555663cf666cde4fa8323469 and
2134 			 * 28e2e446868b94b92edc4a82aa0bf1e3eda8ec54 the writer may not have
2135 			 * properly quoted passphrases, so just handle anything that's unquoted
2136 			 * and between 8 and 63 characters as a passphrase.
2137 			 */
2138 	
2139 			/* Get rid of the quotes */
2140 			hashed = utils_single_unquote_string (p);
2141 	
2142 			/* Length check */
2143 			if (strlen (hashed) < 8 || strlen (hashed) > 63) {
2144 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2145 				             "Invalid WPA_PSK (passphrases must be between "
2146 				             "8 and 63 characters long (inclusive))");
2147 				g_free (hashed);
2148 				hashed = NULL;
2149 				goto out;
2150 			}
2151 		}
2152 	
2153 		if (!hashed) {
2154 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2155 			             "Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
2156 			goto out;
2157 		}
2158 	
2159 	out:
2160 		g_free (psk);
2161 		return hashed;
2162 	}
2163 	
2164 	static gboolean
2165 	eap_simple_reader (const char *eap_method,
2166 	                   shvarFile *ifcfg,
2167 	                   shvarFile *keys,
2168 	                   NMSetting8021x *s_8021x,
2169 	                   gboolean phase2,
2170 	                   GError **error)
2171 	{
2172 		NMSettingSecretFlags flags;
2173 		char *value;
2174 	
2175 		value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2176 		if (!value) {
2177 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2178 			             "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2179 			             eap_method);
2180 			return FALSE;
2181 		}
2182 		g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2183 		g_free (value);
2184 	
2185 		flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
2186 		g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL);
2187 	
2188 		/* Only read the password if it's system-owned */
2189 		if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2190 			value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2191 			if (!value && keys) {
2192 				/* Try the lookaside keys file */
2193 				value = svGetValue (keys, "IEEE_8021X_PASSWORD", FALSE);
2194 			}
2195 	
2196 			if (!value) {
2197 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2198 				             "Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
2199 				             eap_method);
2200 				return FALSE;
2201 			}
2202 	
2203 			g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
2204 			g_free (value);
2205 		}
2206 	
2207 		return TRUE;
2208 	}
2209 	
2210 	static char *
2211 	get_full_file_path (const char *ifcfg_path, const char *file_path)
2212 	{
2213 		const char *base = file_path;
2214 		char *p, *ret, *dirname;
2215 	
2216 		g_return_val_if_fail (ifcfg_path != NULL, NULL);
2217 		g_return_val_if_fail (file_path != NULL, NULL);
2218 	
2219 		if (file_path[0] == '/')
2220 			return g_strdup (file_path);
2221 	
2222 		p = strrchr (file_path, '/');
2223 		if (p)
2224 			base = p + 1;
2225 	
2226 		dirname = g_path_get_dirname (ifcfg_path);
2227 		ret = g_build_path ("/", dirname, base, NULL);
2228 		g_free (dirname);
2229 		return ret;
2230 	}
2231 	
2232 	static gboolean
2233 	eap_tls_reader (const char *eap_method,
2234 	                shvarFile *ifcfg,
2235 	                shvarFile *keys,
2236 	                NMSetting8021x *s_8021x,
2237 	                gboolean phase2,
2238 	                GError **error)
2239 	{
2240 		char *value;
2241 		char *ca_cert = NULL;
2242 		char *real_path = NULL;
2243 		char *client_cert = NULL;
2244 		char *privkey = NULL;
2245 		char *privkey_password = NULL;
2246 		gboolean success = FALSE;
2247 		NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
2248 		const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
2249 		const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
2250 		const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
2251 		const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
2252 		const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
2253 		const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
2254 		NMSettingSecretFlags flags;
2255 	
2256 		value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2257 		if (!value) {
2258 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2259 			             "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2260 			             eap_method);
2261 			return FALSE;
2262 		}
2263 		g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2264 		g_free (value);
2265 	
2266 		ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
2267 		if (ca_cert) {
2268 			real_path = get_full_file_path (ifcfg->fileName, ca_cert);
2269 			if (phase2) {
2270 				if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
2271 				                                           real_path,
2272 				                                           NM_SETTING_802_1X_CK_SCHEME_PATH,
2273 				                                           NULL,
2274 				                                           error))
2275 					goto done;
2276 			} else {
2277 				if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2278 				                                    real_path,
2279 				                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
2280 				                                    NULL,
2281 				                                    error))
2282 					goto done;
2283 			}
2284 			g_free (real_path);
2285 			real_path = NULL;
2286 		} else {
2287 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing %s for EAP"
2288 			             " method '%s'; this is insecure!",
2289 			             ca_cert_key,
2290 			             eap_method);
2291 		}
2292 	
2293 		/* Read and set private key password flags */
2294 		flags = read_secret_flags (ifcfg, pk_pw_flags_key);
2295 		g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL);
2296 	
2297 		/* Read the private key password if it's system-owned */
2298 		if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2299 			/* Private key password */
2300 			privkey_password = svGetValue (ifcfg, pk_pw_key, FALSE);
2301 			if (!privkey_password && keys) {
2302 				/* Try the lookaside keys file */
2303 				privkey_password = svGetValue (keys, pk_pw_key, FALSE);
2304 			}
2305 	
2306 			if (!privkey_password) {
2307 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2308 				             "Missing %s for EAP method '%s'.",
2309 				             pk_pw_key,
2310 				             eap_method);
2311 				goto done;
2312 			}
2313 		}
2314 	
2315 		/* The private key itself */
2316 		privkey = svGetValue (ifcfg, pk_key, FALSE);
2317 		if (!privkey) {
2318 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2319 			             "Missing %s for EAP method '%s'.",
2320 			             pk_key,
2321 			             eap_method);
2322 			goto done;
2323 		}
2324 	
2325 		real_path = get_full_file_path (ifcfg->fileName, privkey);
2326 		if (phase2) {
2327 			if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
2328 			                                               real_path,
2329 			                                               privkey_password,
2330 			                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
2331 			                                               &privkey_format,
2332 			                                               error))
2333 				goto done;
2334 		} else {
2335 			if (!nm_setting_802_1x_set_private_key (s_8021x,
2336 			                                        real_path,
2337 			                                        privkey_password,
2338 			                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
2339 			                                        &privkey_format,
2340 			                                        error))
2341 				goto done;
2342 		}
2343 		g_free (real_path);
2344 		real_path = NULL;
2345 	
2346 		/* Only set the client certificate if the private key is not PKCS#12 format,
2347 		 * as NM (due to supplicant restrictions) requires.  If the key was PKCS#12,
2348 		 * then nm_setting_802_1x_set_private_key() already set the client certificate
2349 		 * to the same value as the private key.
2350 		 */
2351 		if (   privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
2352 		    || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
2353 			client_cert = svGetValue (ifcfg, cli_cert_key, FALSE);
2354 			if (!client_cert) {
2355 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2356 				             "Missing %s for EAP method '%s'.",
2357 				             cli_cert_key,
2358 				             eap_method);
2359 				goto done;
2360 			}
2361 	
2362 			real_path = get_full_file_path (ifcfg->fileName, client_cert);
2363 			if (phase2) {
2364 				if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
2365 				                                               real_path,
2366 				                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
2367 				                                               NULL,
2368 				                                               error))
2369 					goto done;
2370 			} else {
2371 				if (!nm_setting_802_1x_set_client_cert (s_8021x,
2372 				                                        real_path,
2373 				                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
2374 				                                        NULL,
2375 				                                        error))
2376 					goto done;
2377 			}
2378 			g_free (real_path);
2379 			real_path = NULL;
2380 		}
2381 	
2382 		success = TRUE;
2383 	
2384 	done:
2385 		g_free (real_path);
2386 		g_free (ca_cert);
2387 		g_free (client_cert);
2388 		g_free (privkey);
2389 		g_free (privkey_password);
2390 		return success;
2391 	}
2392 	
2393 	static gboolean
2394 	eap_peap_reader (const char *eap_method,
2395 	                 shvarFile *ifcfg,
2396 	                 shvarFile *keys,
2397 	                 NMSetting8021x *s_8021x,
2398 	                 gboolean phase2,
2399 	                 GError **error)
2400 	{
2401 		char *anon_ident = NULL;
2402 		char *ca_cert = NULL;
2403 		char *real_cert_path = NULL;
2404 		char *inner_auth = NULL;
2405 		char *peapver = NULL;
2406 		char *lower;
2407 		char **list = NULL, **iter;
2408 		gboolean success = FALSE;
2409 	
2410 		ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2411 		if (ca_cert) {
2412 			real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2413 			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2414 			                                    real_cert_path,
2415 			                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
2416 			                                    NULL,
2417 			                                    error))
2418 				goto done;
2419 		} else {
2420 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing "
2421 			             "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
2422 			             " insecure!",
2423 			             eap_method);
2424 		}
2425 	
2426 		peapver = svGetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", FALSE);
2427 		if (peapver) {
2428 			if (!strcmp (peapver, "0"))
2429 				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
2430 			else if (!strcmp (peapver, "1"))
2431 				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
2432 			else {
2433 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2434 				             "Unknown IEEE_8021X_PEAP_VERSION value '%s'",
2435 				             peapver);
2436 				goto done;
2437 			}
2438 		}
2439 	
2440 		if (svTrueValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE))
2441 			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
2442 	
2443 		anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2444 		if (anon_ident && strlen (anon_ident))
2445 			g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2446 	
2447 		inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2448 		if (!inner_auth) {
2449 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2450 			             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2451 			goto done;
2452 		}
2453 	
2454 		/* Handle options for the inner auth method */
2455 		list = g_strsplit (inner_auth, " ", 0);
2456 		for (iter = list; iter && *iter; iter++) {
2457 			if (!strlen (*iter))
2458 				continue;
2459 	
2460 			if (   !strcmp (*iter, "MSCHAPV2")
2461 			    || !strcmp (*iter, "MD5")
2462 			    || !strcmp (*iter, "GTC")) {
2463 				if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2464 					goto done;
2465 			} else if (!strcmp (*iter, "TLS")) {
2466 				if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2467 					goto done;
2468 			} else {
2469 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2470 				             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2471 				             *iter);
2472 				goto done;
2473 			}
2474 	
2475 			lower = g_ascii_strdown (*iter, -1);
2476 			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2477 			g_free (lower);
2478 			break;
2479 		}
2480 	
2481 		if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2482 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2483 			             "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2484 			goto done;
2485 		}
2486 	
2487 		success = TRUE;
2488 	
2489 	done:
2490 		if (list)
2491 			g_strfreev (list);
2492 		g_free (inner_auth);
2493 		g_free (peapver);
2494 		g_free (real_cert_path);
2495 		g_free (ca_cert);
2496 		g_free (anon_ident);
2497 		return success;
2498 	}
2499 	
2500 	static gboolean
2501 	eap_ttls_reader (const char *eap_method,
2502 	                 shvarFile *ifcfg,
2503 	                 shvarFile *keys,
2504 	                 NMSetting8021x *s_8021x,
2505 	                 gboolean phase2,
2506 	                 GError **error)
2507 	{
2508 		gboolean success = FALSE;
2509 		char *anon_ident = NULL;
2510 		char *ca_cert = NULL;
2511 		char *real_cert_path = NULL;
2512 		char *inner_auth = NULL;
2513 		char *tmp;
2514 		char **list = NULL, **iter;
2515 	
2516 		ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2517 		if (ca_cert) {
2518 			real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2519 			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2520 			                                    real_cert_path,
2521 			                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
2522 			                                    NULL,
2523 			                                    error))
2524 				goto done;
2525 		} else {
2526 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing "
2527 			             "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
2528 			             " insecure!",
2529 			             eap_method);
2530 		}
2531 	
2532 		anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2533 		if (anon_ident && strlen (anon_ident))
2534 			g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2535 	
2536 		tmp = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2537 		if (!tmp) {
2538 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2539 			             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2540 			goto done;
2541 		}
2542 	
2543 		inner_auth = g_ascii_strdown (tmp, -1);
2544 		g_free (tmp);
2545 	
2546 		/* Handle options for the inner auth method */
2547 		list = g_strsplit (inner_auth, " ", 0);
2548 		for (iter = list; iter && *iter; iter++) {
2549 			if (!strlen (*iter))
2550 				continue;
2551 	
2552 			if (   !strcmp (*iter, "mschapv2")
2553 			    || !strcmp (*iter, "mschap")
2554 			    || !strcmp (*iter, "pap")
2555 			    || !strcmp (*iter, "chap")) {
2556 				if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2557 					goto done;
2558 				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
2559 			} else if (!strcmp (*iter, "eap-tls")) {
2560 				if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2561 					goto done;
2562 				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
2563 			} else if (!strcmp (*iter, "eap-mschapv2") || !strcmp (*iter, "eap-md5")) {
2564 				if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2565 					goto done;
2566 				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + strlen ("eap-")), NULL);
2567 			} else {
2568 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2569 				             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2570 				             *iter);
2571 				goto done;
2572 			}
2573 			break;
2574 		}
2575 	
2576 		success = TRUE;
2577 	
2578 	done:
2579 		if (list)
2580 			g_strfreev (list);
2581 		g_free (inner_auth);
2582 		g_free (real_cert_path);
2583 		g_free (ca_cert);
2584 		g_free (anon_ident);
2585 		return success;
2586 	}
2587 	
2588 	static gboolean
2589 	eap_fast_reader (const char *eap_method,
2590 	                 shvarFile *ifcfg,
2591 	                 shvarFile *keys,
2592 	                 NMSetting8021x *s_8021x,
2593 	                 gboolean phase2,
2594 	                 GError **error)
2595 	{
2596 		char *anon_ident = NULL;
2597 		char *pac_file = NULL;
2598 		char *real_pac_path = NULL;
2599 		char *inner_auth = NULL;
2600 		char *fast_provisioning = NULL;
2601 		char *lower;
2602 		char **list = NULL, **iter;
2603 		const char* pac_prov_str;
2604 		gboolean allow_unauth = FALSE, allow_auth = FALSE;
2605 		gboolean success = FALSE;
2606 	
2607 		pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
2608 		if (pac_file) {
2609 			real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
2610 			g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
2611 		}
2612 	
2613 		fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
2614 		if (fast_provisioning) {
2615 			list = g_strsplit_set (fast_provisioning, " \t", 0);
2616 			for (iter = list; iter && *iter; iter++) {
2617 				if (**iter == '\0')
2618 					continue;
2619 				if (strcmp (*iter, "allow-unauth") == 0)
2620 					allow_unauth = TRUE;
2621 				else if (strcmp (*iter, "allow-auth") == 0)
2622 					allow_auth = TRUE;
2623 				else {
2624 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid IEEE_8021X_FAST_PROVISIONING '%s' "
2625 					             "(space-separated list of these values [allow-auth, allow-unauth] expected)",
2626 					             *iter);
2627 				}
2628 			}
2629 			g_strfreev (list);
2630 			list = NULL;
2631 		}
2632 		pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
2633 		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
2634 	
2635 		if (!pac_file && !(allow_unauth || allow_auth)) {
2636 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2637 			             "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
2638 			goto done;
2639 		}
2640 	
2641 		anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2642 		if (anon_ident && strlen (anon_ident))
2643 			g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2644 	
2645 		inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2646 		if (!inner_auth) {
2647 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2648 			             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2649 			goto done;
2650 		}
2651 	
2652 		/* Handle options for the inner auth method */
2653 		list = g_strsplit (inner_auth, " ", 0);
2654 		for (iter = list; iter && *iter; iter++) {
2655 			if (!strlen (*iter))
2656 				continue;
2657 	
2658 			if (   !strcmp (*iter, "MSCHAPV2")
2659 			    || !strcmp (*iter, "GTC")) {
2660 				if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2661 					goto done;
2662 			} else {
2663 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2664 				             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2665 				             *iter);
2666 				goto done;
2667 			}
2668 	
2669 			lower = g_ascii_strdown (*iter, -1);
2670 			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2671 			g_free (lower);
2672 			break;
2673 		}
2674 	
2675 		if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2676 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2677 			             "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2678 			goto done;
2679 		}
2680 	
2681 		success = TRUE;
2682 	
2683 	done:
2684 		g_strfreev (list);
2685 		g_free (inner_auth);
2686 		g_free (fast_provisioning);
2687 		g_free (real_pac_path);
2688 		g_free (pac_file);
2689 		g_free (anon_ident);
2690 		return success;
2691 	}
2692 	
2693 	typedef struct {
2694 		const char *method;
2695 		gboolean (*reader)(const char *eap_method,
2696 		                   shvarFile *ifcfg,
2697 		                   shvarFile *keys,
2698 		                   NMSetting8021x *s_8021x,
2699 		                   gboolean phase2,
2700 		                   GError **error);
2701 		gboolean wifi_phase2_only;
2702 	} EAPReader;
2703 	
2704 	static EAPReader eap_readers[] = {
2705 		{ "md5", eap_simple_reader, TRUE },
2706 		{ "pap", eap_simple_reader, TRUE },
2707 		{ "chap", eap_simple_reader, TRUE },
2708 		{ "mschap", eap_simple_reader, TRUE },
2709 		{ "mschapv2", eap_simple_reader, TRUE },
2710 		{ "leap", eap_simple_reader, FALSE },
2711 		{ "pwd", eap_simple_reader, FALSE },
2712 		{ "tls", eap_tls_reader, FALSE },
2713 		{ "peap", eap_peap_reader, FALSE },
2714 		{ "ttls", eap_ttls_reader, FALSE },
2715 		{ "fast", eap_fast_reader, FALSE },
2716 		{ NULL, NULL }
2717 	};
2718 	
2719 	static NMSetting8021x *
2720 	fill_8021x (shvarFile *ifcfg,
2721 	            const char *file,
2722 	            const char *key_mgmt,
2723 	            gboolean wifi,
2724 	            GError **error)
2725 	{
2726 		NMSetting8021x *s_8021x;
2727 		shvarFile *keys = NULL;
2728 		char *value;
2729 		char **list = NULL, **iter;
2730 	
2731 		value = svGetValue (ifcfg, "IEEE_8021X_EAP_METHODS", FALSE);
2732 		if (!value) {
2733 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2734 			             "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
2735 			             key_mgmt);
2736 			return NULL;
2737 		}
2738 	
2739 		list = g_strsplit (value, " ", 0);
2740 		g_free (value);
2741 	
2742 		s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
2743 	
2744 		/* Read in the lookaside keys file, if present */
2745 		keys = utils_get_keys_ifcfg (file, FALSE);
2746 	
2747 		/* Validate and handle each EAP method */
2748 		for (iter = list; iter && *iter; iter++) {
2749 			EAPReader *eap = &eap_readers[0];
2750 			gboolean found = FALSE;
2751 			char *lower = NULL;
2752 	
2753 			lower = g_ascii_strdown (*iter, -1);
2754 			while (eap->method && !found) {
2755 				if (strcmp (eap->method, lower))
2756 					goto next;
2757 	
2758 				/* Some EAP methods don't provide keying material, thus they
2759 				 * cannot be used with WiFi unless they are an inner method
2760 				 * used with TTLS or PEAP or whatever.
2761 				 */
2762 				if (wifi && eap->wifi_phase2_only) {
2763 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignored invalid "
2764 					             "IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
2765 					             lower);
2766 					goto next;
2767 				}
2768 	
2769 				/* Parse EAP method specific options */
2770 				if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) {
2771 					g_free (lower);
2772 					goto error;
2773 				}
2774 				nm_setting_802_1x_add_eap_method (s_8021x, lower);
2775 				found = TRUE;
2776 	
2777 			next:
2778 				eap++;
2779 			}
2780 	
2781 			if (!found) {
2782 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignored unknown"
2783 				             "IEEE_8021X_EAP_METHOD '%s'.",
2784 				             lower);
2785 			}
2786 			g_free (lower);
2787 		}
2788 	
2789 		if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
2790 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2791 			             "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
2792 			goto error;
2793 		}
2794 	
2795 		if (list)
2796 			g_strfreev (list);
2797 		if (keys)
2798 			svCloseFile (keys);
2799 		return s_8021x;
2800 	
2801 	error:
2802 		if (list)
2803 			g_strfreev (list);
2804 		if (keys)
2805 			svCloseFile (keys);
2806 		g_object_unref (s_8021x);
2807 		return NULL;
2808 	}
2809 	
2810 	static NMSetting *
2811 	make_wpa_setting (shvarFile *ifcfg,
2812 	                  const char *file,
2813 	                  const GByteArray *ssid,
2814 	                  gboolean adhoc,
2815 	                  NMSetting8021x **s_8021x,
2816 	                  GError **error)
2817 	{
2818 		NMSettingWirelessSecurity *wsec;
2819 		char *value, *psk, *lower;
2820 		gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE;
2821 	
2822 		wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
2823 	
2824 		value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
2825 		wpa_psk = !g_strcmp0 (value, "WPA-PSK");
2826 		wpa_eap = !g_strcmp0 (value, "WPA-EAP");
2827 		ieee8021x = !g_strcmp0 (value, "IEEE8021X");
2828 		if (!wpa_psk && !wpa_eap && !ieee8021x)
2829 			goto error; /* Not WPA or Dynamic WEP */
2830 	
2831 		/* Pairwise and Group ciphers (only relevant for WPA/RSN) */
2832 		if (wpa_psk || wpa_eap) {
2833 			fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc);
2834 			fill_wpa_ciphers (ifcfg, wsec, TRUE, adhoc);
2835 		}
2836 	
2837 		/* WPA and/or RSN */
2838 		if (adhoc) {
2839 			/* Ad-Hoc mode only supports WPA proto for now */
2840 			nm_setting_wireless_security_add_proto (wsec, "wpa");
2841 		} else {
2842 			char *allow_wpa, *allow_rsn;
2843 	
2844 			allow_wpa = svGetValue (ifcfg, "WPA_ALLOW_WPA", FALSE);
2845 			allow_rsn = svGetValue (ifcfg, "WPA_ALLOW_WPA2", FALSE);
2846 	
2847 			if (allow_wpa && svTrueValue (ifcfg, "WPA_ALLOW_WPA", TRUE))
2848 				nm_setting_wireless_security_add_proto (wsec, "wpa");
2849 			if (allow_rsn && svTrueValue (ifcfg, "WPA_ALLOW_WPA2", TRUE))
2850 				nm_setting_wireless_security_add_proto (wsec, "rsn");
2851 	
2852 			/* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default
2853 			 * to both WPA and RSN allowed.
2854 			 */
2855 			if (!allow_wpa && !allow_rsn && !ieee8021x) {
2856 				nm_setting_wireless_security_add_proto (wsec, "wpa");
2857 				nm_setting_wireless_security_add_proto (wsec, "rsn");
2858 			}
2859 	
2860 			g_free (allow_wpa);
2861 			g_free (allow_rsn);
2862 		}
2863 	
2864 		if (!strcmp (value, "WPA-PSK")) {
2865 			NMSettingSecretFlags psk_flags;
2866 	
2867 			psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS");
2868 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL);
2869 	
2870 			/* Read PSK if it's system-owned */
2871 			if (psk_flags == NM_SETTING_SECRET_FLAG_NONE) {
2872 				psk = parse_wpa_psk (ifcfg, file, ssid, error);
2873 				if (psk) {
2874 					g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
2875 					g_free (psk);
2876 				}
2877 			}
2878 	
2879 			if (adhoc)
2880 				g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
2881 			else
2882 				g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
2883 		} else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) {
2884 			/* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
2885 			if (adhoc) {
2886 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2887 				             "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value);
2888 				goto error;
2889 			}
2890 	
2891 			*s_8021x = fill_8021x (ifcfg, file, value, TRUE, error);
2892 			if (!*s_8021x)
2893 				goto error;
2894 	
2895 			lower = g_ascii_strdown (value, -1);
2896 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL);
2897 			g_free (lower);
2898 		} else {
2899 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2900 			             "Unknown wireless KEY_MGMT type '%s'", value);
2901 			goto error;
2902 		}
2903 	
2904 		g_free (value);
2905 		return (NMSetting *) wsec;
2906 	
2907 	error:
2908 		g_free (value);
2909 		if (wsec)
2910 			g_object_unref (wsec);
2911 		return NULL;
2912 	}
2913 	
2914 	static NMSetting *
2915 	make_leap_setting (shvarFile *ifcfg,
2916 	                   const char *file,
2917 	                   GError **error)
2918 	{
2919 		NMSettingWirelessSecurity *wsec;
2920 		shvarFile *keys_ifcfg;
2921 		char *value;
2922 		NMSettingSecretFlags flags;
2923 	
2924 		wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
2925 	
2926 		value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
2927 		if (!value || strcmp (value, "IEEE8021X"))
2928 			goto error; /* Not LEAP */
2929 	
2930 		g_free (value);
2931 		value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
2932 		if (!value || strcasecmp (value, "leap"))
2933 			goto error; /* Not LEAP */
2934 	
2935 		g_free (value);
2936 	
2937 		flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
2938 		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL);
2939 	
2940 		/* Read LEAP password if it's system-owned */
2941 		if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2942 			value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2943 			if (!value) {
2944 				/* Try to get keys from the "shadow" key file */
2945 				keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2946 				if (keys_ifcfg) {
2947 					value = svGetValue (keys_ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2948 					svCloseFile (keys_ifcfg);
2949 				}
2950 			}
2951 			if (value && strlen (value))
2952 				g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL);
2953 			g_free (value);
2954 		}
2955 	
2956 		value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2957 		if (!value || !strlen (value)) {
2958 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2959 			             "Missing LEAP identity");
2960 			goto error;
2961 		}
2962 		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL);
2963 		g_free (value);
2964 	
2965 		g_object_set (wsec,
2966 		              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
2967 		              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
2968 		              NULL);
2969 	
2970 		return (NMSetting *) wsec;
2971 	
2972 	error:
2973 		g_free (value);
2974 		if (wsec)
2975 			g_object_unref (wsec);
2976 		return NULL;
2977 	}
2978 	
2979 	static NMSetting *
2980 	make_wireless_security_setting (shvarFile *ifcfg,
2981 	                                const char *file,
2982 	                                const GByteArray *ssid,
2983 	                                gboolean adhoc,
2984 	                                NMSetting8021x **s_8021x,
2985 	                                GError **error)
2986 	{
2987 		NMSetting *wsec;
2988 	
2989 		if (!adhoc) {
2990 			wsec = make_leap_setting (ifcfg, file, error);
2991 			if (wsec)
2992 				return wsec;
2993 			else if (*error)
2994 				return NULL;
2995 		}
2996 	
2997 		wsec = make_wpa_setting (ifcfg, file, ssid, adhoc, s_8021x, error);
2998 		if (wsec)
2999 			return wsec;
3000 		else if (*error)
3001 			return NULL;
3002 	
3003 		wsec = make_wep_setting (ifcfg, file, error);
3004 		if (wsec)
3005 			return wsec;
3006 		else if (*error)
3007 			return NULL;
3008 	
3009 		return NULL; /* unencrypted */
3010 	}
3011 	
3012 	static NMSetting *
3013 	make_wireless_setting (shvarFile *ifcfg,
3014 	                       gboolean nm_controlled,
3015 	                       char **unmanaged,
3016 	                       GError **error)
3017 	{
3018 		NMSettingWireless *s_wireless;
3019 		GByteArray *array = NULL;
3020 		GSList *macaddr_blacklist = NULL;
3021 		char *value;
3022 	
3023 		s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
3024 	
3025 		if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &array, error)) {
3026 			if (array) {
3027 				g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL);
3028 	
3029 				if (!nm_controlled) {
3030 					*unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
3031 					                              array->data[0], array->data[1], array->data[2],
3032 					                              array->data[3], array->data[4], array->data[5]);
3033 				}
3034 	
3035 				g_byte_array_free (array, TRUE);
3036 			}
3037 		} else {
3038 			g_object_unref (s_wireless);
3039 			return NULL;
3040 		}
3041 	
3042 		array = NULL;
3043 		if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &array, error)) {
3044 			if (array) {
3045 				g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL);
3046 				g_byte_array_free (array, TRUE);
3047 			}
3048 		} else {
3049 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: %s", (*error)->message);
3050 			g_clear_error (error);
3051 		}
3052 	
3053 		value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3054 		if (value) {
3055 			char **list = NULL, **iter;
3056 			struct ether_addr addr;
3057 	
3058 			list = g_strsplit_set (value, " \t", 0);
3059 			for (iter = list; iter && *iter; iter++) {
3060 				if (**iter == '\0')
3061 					continue;
3062 				if (!ether_aton_r (*iter, &addr)) {
3063 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter);
3064 					continue;
3065 				}
3066 				macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter);
3067 			}
3068 			if (macaddr_blacklist) {
3069 				macaddr_blacklist = g_slist_reverse (macaddr_blacklist);
3070 				g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL);
3071 				g_slist_free (macaddr_blacklist);
3072 			}
3073 			g_free (value);
3074 			g_strfreev (list);
3075 		}
3076 	
3077 		value = svGetValue (ifcfg, "ESSID", TRUE);
3078 		if (value) {
3079 			gsize ssid_len = 0, value_len = strlen (value);
3080 			char *p = value, *tmp;
3081 			char buf[33];
3082 	
3083 			ssid_len = value_len;
3084 			if (   (value_len >= 2)
3085 			    && (value[0] == '"')
3086 			    && (value[value_len - 1] == '"')) {
3087 				/* Strip the quotes and unescape */
3088 				p = value + 1;
3089 				value[value_len - 1] = '\0';
3090 				svUnescape (p);
3091 				ssid_len = strlen (p);
3092 			} else if ((value_len > 2) && (strncmp (value, "0x", 2) == 0)) {
3093 				/* Hex representation */
3094 				if (value_len % 2) {
3095 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3096 					             "Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
3097 					             value);
3098 					g_free (value);
3099 					goto error;
3100 				}
3101 	
3102 				p = value + 2;
3103 				while (*p) {
3104 					if (!g_ascii_isxdigit (*p)) {
3105 						g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3106 						             "Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)",
3107 						             value, *p);
3108 						g_free (value);
3109 						goto error;
3110 					}
3111 					p++;
3112 				}
3113 	
3114 				tmp = nm_utils_hexstr2bin (value + 2, value_len - 2);
3115 				ssid_len  = (value_len - 2) / 2;
3116 				memcpy (buf, tmp, ssid_len);
3117 				p = &buf[0];
3118 				g_free (tmp);
3119 			}
3120 	
3121 			if (ssid_len > 32 || ssid_len == 0) {
3122 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3123 				             "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
3124 				             value, ssid_len);
3125 				g_free (value);
3126 				goto error;
3127 			}
3128 	
3129 			array = g_byte_array_sized_new (ssid_len);
3130 			g_byte_array_append (array, (const guint8 *) p, ssid_len);
3131 			g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, array, NULL);
3132 			g_byte_array_free (array, TRUE);
3133 			g_free (value);
3134 		} else {
3135 			/* Only fail on lack of SSID if device is managed */
3136 			if (nm_controlled) {
3137 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing SSID");
3138 				goto error;
3139 			}
3140 		}
3141 	
3142 		if (!nm_controlled)
3143 			goto done;
3144 	
3145 		value = svGetValue (ifcfg, "MODE", FALSE);
3146 		if (value) {
3147 			char *lcase;
3148 			const char *mode = NULL;
3149 	
3150 			lcase = g_ascii_strdown (value, -1);
3151 			g_free (value);
3152 	
3153 			if (!strcmp (lcase, "ad-hoc")) {
3154 				mode = "adhoc";
3155 			} else if (!strcmp (lcase, "managed") || !strcmp (lcase, "auto")) {
3156 				mode = "infrastructure";
3157 			} else {
3158 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3159 				             "Invalid mode '%s' (not 'Ad-Hoc', 'Managed', or 'Auto')",
3160 				             lcase);
3161 				g_free (lcase);
3162 				goto error;
3163 			}
3164 			g_free (lcase);
3165 	
3166 			g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
3167 		}
3168 	
3169 		value = svGetValue (ifcfg, "BSSID", FALSE);
3170 		if (value) {
3171 			GByteArray *bssid;
3172 	
3173 			bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
3174 			if (!bssid) {
3175 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3176 				             "Invalid BSSID '%s'", value);
3177 				g_free (value);
3178 				goto error;
3179 			}
3180 	
3181 			g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, bssid, NULL);
3182 			g_byte_array_free (bssid, TRUE);
3183 			g_free (value);
3184 		}
3185 	
3186 		value = svGetValue (ifcfg, "CHANNEL", FALSE);
3187 		if (value) {
3188 			long int chan;
3189 	
3190 			errno = 0;
3191 			chan = strtol (value, NULL, 10);
3192 			if (errno || chan <= 0 || chan > 196) {
3193 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3194 				             "Invalid wireless channel '%s'", value);
3195 				g_free (value);
3196 				goto error;
3197 			}
3198 			g_object_set (s_wireless, NM_SETTING_WIRELESS_CHANNEL, (guint32) chan, NULL);
3199 			if (chan > 14)
3200 				g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
3201 			else
3202 				g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
3203 			g_free (value);
3204 		}
3205 	
3206 		value = svGetValue (ifcfg, "MTU", FALSE);
3207 		if (value) {
3208 			long int mtu;
3209 	
3210 			errno = 0;
3211 			mtu = strtol (value, NULL, 10);
3212 			if (errno || mtu < 0 || mtu > 50000) {
3213 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3214 				             "Invalid wireless MTU '%s'", value);
3215 				g_free (value);
3216 				goto error;
3217 			}
3218 			g_object_set (s_wireless, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL);
3219 			g_free (value);
3220 		}
3221 	
3222 	done:
3223 		return NM_SETTING (s_wireless);
3224 	
3225 	error:
3226 		if (s_wireless)
3227 			g_object_unref (s_wireless);
3228 		return NULL;
3229 	}
3230 	
3231 	static NMConnection *
3232 	wireless_connection_from_ifcfg (const char *file,
3233 	                                shvarFile *ifcfg,
3234 	                                gboolean nm_controlled,
3235 	                                char **unmanaged,
3236 	                                GError **error)
3237 	{
3238 		NMConnection *connection = NULL;
3239 		NMSetting *con_setting = NULL;
3240 		NMSetting *wireless_setting = NULL;
3241 		NMSetting8021x *s_8021x = NULL;
3242 		const GByteArray *ssid;
3243 		NMSetting *security_setting = NULL;
3244 		char *printable_ssid = NULL;
3245 		const char *mode;
3246 		gboolean adhoc = FALSE;
3247 	
3248 		g_return_val_if_fail (file != NULL, NULL);
3249 		g_return_val_if_fail (ifcfg != NULL, NULL);
3250 		g_return_val_if_fail (error != NULL, NULL);
3251 		g_return_val_if_fail (*error == NULL, NULL);
3252 	
3253 		connection = nm_connection_new ();
3254 	
3255 		/* Wireless */
3256 		wireless_setting = make_wireless_setting (ifcfg, nm_controlled, unmanaged, error);
3257 		if (!wireless_setting) {
3258 			g_object_unref (connection);
3259 			return NULL;
3260 		}
3261 		nm_connection_add_setting (connection, wireless_setting);
3262 	
3263 		ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
3264 		if (ssid)
3265 			printable_ssid = nm_utils_ssid_to_utf8 (ssid);
3266 		else
3267 			printable_ssid = g_strdup_printf ("unmanaged");
3268 	
3269 		if (nm_controlled) {
3270 			mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
3271 			if (mode && !strcmp (mode, "adhoc"))
3272 				adhoc = TRUE;
3273 	
3274 			/* Wireless security */
3275 			security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, error);
3276 			if (*error) {
3277 				g_free (printable_ssid);
3278 				g_object_unref (connection);
3279 				return NULL;
3280 			}
3281 			if (security_setting) {
3282 				nm_connection_add_setting (connection, security_setting);
3283 				if (s_8021x)
3284 					nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3285 			}
3286 		}
3287 	
3288 		/* Connection */
3289 		con_setting = make_connection_setting (file, ifcfg,
3290 		                                       NM_SETTING_WIRELESS_SETTING_NAME,
3291 		                                       printable_ssid, NULL);
3292 		g_free (printable_ssid);
3293 		if (!con_setting) {
3294 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3295 			             "Failed to create connection setting.");
3296 			g_object_unref (connection);
3297 			return NULL;
3298 		}
3299 		nm_connection_add_setting (connection, con_setting);
3300 	
3301 		/* Don't verify if unmanaged since we may not have an SSID or whatever */
3302 		if (nm_controlled) {
(19) Event example_checked: Example5: "nm_connection_verify(connection, error)" has its value checked in "nm_connection_verify(connection, error)".
Also see events: [check_return][example_checked][example_assign][example_checked][example_checked][example_checked][unchecked_value]
3303 			if (!nm_connection_verify (connection, error)) {
3304 				g_object_unref (connection);
3305 				return NULL;
3306 			}
3307 		}
3308 	
3309 		return connection;
3310 	}
3311 	
3312 	static NMSetting *
3313 	make_wired_setting (shvarFile *ifcfg,
3314 	                    const char *file,
3315 	                    gboolean nm_controlled,
3316 	                    char **unmanaged,
3317 	                    NMSetting8021x **s_8021x,
3318 	                    GError **error)
3319 	{
3320 		NMSettingWired *s_wired;
3321 		char *value = NULL;
3322 		int mtu;
3323 		GByteArray *mac = NULL;
3324 		GSList *macaddr_blacklist = NULL;
3325 		char *nettype;
3326 	
3327 		s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
3328 	
3329 		value = svGetValue (ifcfg, "MTU", FALSE);
3330 		if (value) {
3331 			if (get_int (value, &mtu)) {
3332 				if (mtu >= 0 && mtu < 65536)
3333 					g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
3334 			} else {
3335 				/* Shouldn't be fatal... */
3336 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MTU '%s'", value);
3337 			}
3338 			g_free (value);
3339 		}
3340 	
3341 		if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &mac, error)) {
3342 			if (mac) {
3343 				g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
3344 	
3345 				if (!nm_controlled) {
3346 					*unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
3347 					                              mac->data[0], mac->data[1], mac->data[2],
3348 					                              mac->data[3], mac->data[4], mac->data[5]);
3349 				}
3350 	
3351 				g_byte_array_free (mac, TRUE);
3352 			}
3353 		} else {
3354 			g_object_unref (s_wired);
3355 			return NULL;
3356 		}
3357 	
3358 		value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
3359 		if (value) {
3360 			const char *p = value;
3361 			gboolean success = TRUE;
3362 			char **chans = NULL;
3363 	
3364 			/* basic sanity checks */
3365 			while (*p) {
3366 				if (!g_ascii_isxdigit (*p) && (*p != ',') && (*p != '.')) {
3367 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid SUBCHANNELS '%s'", value);
3368 					success = FALSE;
3369 					break;
3370 				}
3371 				p++;
3372 			}
3373 	
3374 			if (success) {
3375 				guint32 num_chans;
3376 	
3377 				chans = g_strsplit_set (value, ",", 0);
3378 				num_chans = g_strv_length (chans);
3379 				if (num_chans < 2 || num_chans > 3) {
3380 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid SUBCHANNELS '%s' (%d channels, 2 or 3 expected)",
3381 					             value, g_strv_length (chans));
3382 				} else {
3383 					GPtrArray *array = g_ptr_array_sized_new (num_chans);
3384 	
3385 					g_ptr_array_add (array, chans[0]);
3386 					g_ptr_array_add (array, chans[1]);
3387 					if (num_chans == 3)
3388 						g_ptr_array_add (array, chans[2]);
3389 	
3390 					g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, array, NULL);
3391 					g_ptr_array_free (array, TRUE);
3392 	
3393 					/* set the unmanaged spec too */
3394 					if (!nm_controlled && !*unmanaged)
3395 						*unmanaged = g_strdup_printf ("s390-subchannels:%s", value);
3396 				}
3397 				g_strfreev (chans);
3398 			}
3399 			g_free (value);
3400 		}
3401 	
3402 		value = svGetValue (ifcfg, "PORTNAME", FALSE);
3403 		if (value && strlen (value)) {
3404 			nm_setting_wired_add_s390_option (s_wired, "portname", value);
3405 		}
3406 		g_free (value);
3407 	
3408 		value = svGetValue (ifcfg, "CTCPROT", FALSE);
3409 		if (value && strlen (value))
3410 			nm_setting_wired_add_s390_option (s_wired, "ctcprot", value);
3411 		g_free (value);
3412 	
3413 		nettype = svGetValue (ifcfg, "NETTYPE", FALSE);
3414 		if (nettype && strlen (nettype)) {
3415 			if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc"))
3416 				g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL);
3417 			else
3418 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: unknown s390 NETTYPE '%s'", nettype);
3419 		}
3420 		g_free (nettype);
3421 	
3422 		value = svGetValue (ifcfg, "OPTIONS", FALSE);
3423 		if (value && strlen (value)) {
3424 			char **options, **iter;
3425 	
3426 			iter = options = g_strsplit_set (value, " ", 0);
3427 			while (iter && *iter) {
3428 				char *equals = strchr (*iter, '=');
3429 				gboolean valid = FALSE;
3430 	
3431 				if (equals) {
3432 					*equals = '\0';
3433 					valid = nm_setting_wired_add_s390_option (s_wired, *iter, equals + 1);
3434 				}
3435 				if (!valid)
3436 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid s390 OPTION '%s'", *iter);
3437 				iter++;
3438 			}
3439 			g_strfreev (options);
3440 		}
3441 		g_free (value);
3442 	
3443 		mac = NULL;
3444 		if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &mac, error)) {
3445 			if (mac) {
3446 				g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL);
3447 				g_byte_array_free (mac, TRUE);
3448 			}
3449 		} else {
3450 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: %s", (*error)->message);
3451 			g_clear_error (error);
3452 		}
3453 	
3454 		value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3455 		if (value) {
3456 			char **list = NULL, **iter;
3457 			struct ether_addr addr;
3458 	
3459 			list = g_strsplit_set (value, " \t", 0);
3460 			for (iter = list; iter && *iter; iter++) {
3461 				if (**iter == '\0')
3462 					continue;
3463 				if (!ether_aton_r (*iter, &addr)) {
3464 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter);
3465 					continue;
3466 				}
3467 				macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter);
3468 			}
3469 			if (macaddr_blacklist) {
3470 				macaddr_blacklist = g_slist_reverse (macaddr_blacklist);
3471 				g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL);
3472 				g_slist_free (macaddr_blacklist);
3473 			}
3474 			g_free (value);
3475 			g_strfreev (list);
3476 		}
3477 	
3478 		value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
3479 		if (value) {
3480 			if (!strcmp (value, "IEEE8021X")) {
3481 				*s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
3482 				if (!*s_8021x)
3483 					goto error;
3484 			} else {
3485 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3486 				             "Unknown wired KEY_MGMT type '%s'", value);
3487 				goto error;
3488 			}
3489 			g_free (value);
3490 		}
3491 	
3492 		return (NMSetting *) s_wired;
3493 	
3494 	error:
3495 		g_free (value);
3496 		g_object_unref (s_wired);
3497 		return NULL;
3498 	}
3499 	
3500 	static NMConnection *
3501 	wired_connection_from_ifcfg (const char *file,
3502 	                             shvarFile *ifcfg,
3503 	                             gboolean nm_controlled,
3504 	                             char **unmanaged,
3505 	                             GError **error)
3506 	{
3507 		NMConnection *connection = NULL;
3508 		NMSetting *con_setting = NULL;
3509 		NMSetting *wired_setting = NULL;
3510 		NMSetting8021x *s_8021x = NULL;
3511 	
3512 		g_return_val_if_fail (file != NULL, NULL);
3513 		g_return_val_if_fail (ifcfg != NULL, NULL);
3514 	
3515 		connection = nm_connection_new ();
3516 	
3517 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
3518 		if (!con_setting) {
3519 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3520 			             "Failed to create connection setting.");
3521 			g_object_unref (connection);
3522 			return NULL;
3523 		}
3524 		check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3525 		check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3526 		nm_connection_add_setting (connection, con_setting);
3527 	
3528 		wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3529 		if (!wired_setting) {
3530 			g_object_unref (connection);
3531 			return NULL;
3532 		}
3533 		nm_connection_add_setting (connection, wired_setting);
3534 	
3535 		if (s_8021x)
3536 			nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3537 	
(18) Event example_checked: Example4: "nm_connection_verify(connection, error)" has its value checked in "nm_connection_verify(connection, error)".
Also see events: [check_return][example_checked][example_assign][example_checked][example_checked][example_checked][unchecked_value]
3538 		if (!nm_connection_verify (connection, error)) {
3539 			g_object_unref (connection);
3540 			return NULL;
3541 		}
3542 	
3543 		return connection;
3544 	}
3545 	
3546 	static gboolean
3547 	parse_infiniband_p_key (shvarFile *ifcfg,
3548 	                        int *out_p_key,
3549 	                        char **out_parent,
3550 	                        GError **error)
3551 	{
3552 		char *device = NULL, *physdev = NULL, *pkey_id = NULL, *end;
3553 		char *ifname = NULL;
3554 		guint32 id;
3555 		gboolean ret = FALSE;
3556 	
3557 		device = svGetValue (ifcfg, "DEVICE", FALSE);
3558 		if (!device) {
3559 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    InfiniBand connection specified PKEY but not DEVICE");
3560 			goto done;
3561 		}
3562 	
3563 		physdev = svGetValue (ifcfg, "PHYSDEV", FALSE);
3564 		if (!physdev) {
3565 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    InfiniBand connection specified PKEY but not PHYSDEV");
3566 			goto done;
3567 		}
3568 	
3569 		pkey_id = svGetValue (ifcfg, "PKEY_ID", FALSE);
3570 		if (!pkey_id) {
3571 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    InfiniBand connection specified PKEY but not PKEY_ID");
3572 			goto done;
3573 		}
3574 	
3575 		if (g_str_has_prefix (pkey_id, "0x"))
3576 			id = strtoul (pkey_id, &end, 16);
3577 		else if (!g_str_has_prefix (pkey_id, "0"))
3578 			id = strtoul (pkey_id, &end, 10);
3579 		else
3580 			end = pkey_id;
3581 		if (end == pkey_id || *end || id > 0xFFFF) {
3582 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    invalid InfiniBand PKEY_ID '%s'", pkey_id);
3583 			goto done;
3584 		}
3585 		id = (id | 0x8000);
3586 	
3587 		ifname = g_strdup_printf ("%s.%04x", physdev, id);
3588 		if (strcmp (device, ifname) != 0) {
3589 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    InfiniBand DEVICE (%s) does not match PHYSDEV+PKEY_ID (%s)",
3590 			             device, ifname);
3591 			goto done;
3592 		}
3593 	
3594 		*out_p_key = id;
3595 		*out_parent = g_strdup (physdev);
3596 		ret = TRUE;
3597 	
3598 	 done:
3599 		g_free (device);
3600 		g_free (physdev);
3601 		g_free (pkey_id);
3602 		g_free (ifname);
3603 	
3604 		if (!ret) {
3605 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3606 			             "Failed to create InfiniBand setting.");
3607 		}
3608 		return ret;
3609 	}
3610 	
3611 	
3612 	static NMSetting *
3613 	make_infiniband_setting (shvarFile *ifcfg,
3614 	                         const char *file,
3615 	                         gboolean nm_controlled,
3616 	                         char **unmanaged,
3617 	                         GError **error)
3618 	{
3619 		NMSettingInfiniband *s_infiniband;
3620 		char *value = NULL;
3621 		GByteArray *mac = NULL;
3622 		int mtu;
3623 	
3624 		s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
3625 	
3626 		value = svGetValue (ifcfg, "MTU", FALSE);
3627 		if (value) {
3628 			if (get_int (value, &mtu)) {
3629 				if (mtu >= 0 && mtu < 65536)
3630 					g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu, NULL);
3631 			} else {
3632 				/* Shouldn't be fatal... */
3633 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MTU '%s'", value);
3634 			}
3635 			g_free (value);
3636 		}
3637 	
3638 		if (read_mac_address (ifcfg, "HWADDR", ARPHRD_INFINIBAND, &mac, error)) {
3639 			if (mac) {
3640 				g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
3641 	
3642 				if (!nm_controlled) {
3643 					char *mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
3644 					*unmanaged = g_strdup_printf ("mac:%s", mac_str);
3645 					g_free (mac_str);
3646 				}
3647 	
3648 				g_byte_array_free (mac, TRUE);
3649 			}
3650 		} else {
3651 			g_object_unref (s_infiniband);
3652 			return NULL;
3653 		}
3654 	
3655 		if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE))
3656 			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
3657 		else
3658 			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
3659 	
3660 		if (svTrueValue (ifcfg, "PKEY", FALSE)) {
3661 			int p_key;
3662 			char *parent;
3663 	
3664 			if (!parse_infiniband_p_key (ifcfg, &p_key, &parent, error)) {
3665 				g_object_unref (s_infiniband);
3666 				return NULL;
3667 			}
3668 	
3669 			g_object_set (s_infiniband,
3670 			              NM_SETTING_INFINIBAND_P_KEY, p_key,
3671 			              NM_SETTING_INFINIBAND_PARENT, parent,
3672 			              NULL);
3673 		}
3674 	
3675 		return (NMSetting *) s_infiniband;
3676 	}
3677 	
3678 	static NMConnection *
3679 	infiniband_connection_from_ifcfg (const char *file,
3680 	                                  shvarFile *ifcfg,
3681 	                                  gboolean nm_controlled,
3682 	                                  char **unmanaged,
3683 	                                  GError **error)
3684 	{
3685 		NMConnection *connection = NULL;
3686 		NMSetting *con_setting = NULL;
3687 		NMSetting *infiniband_setting = NULL;
3688 	
3689 		g_return_val_if_fail (file != NULL, NULL);
3690 		g_return_val_if_fail (ifcfg != NULL, NULL);
3691 	
3692 		connection = nm_connection_new ();
3693 	
3694 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
3695 		if (!con_setting) {
3696 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3697 			             "Failed to create connection setting.");
3698 			g_object_unref (connection);
3699 			return NULL;
3700 		}
3701 		check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3702 		check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3703 		nm_connection_add_setting (connection, con_setting);
3704 	
3705 		infiniband_setting = make_infiniband_setting (ifcfg, file, nm_controlled, unmanaged, error);
3706 		if (!infiniband_setting) {
3707 			g_object_unref (connection);
3708 			return NULL;
3709 		}
3710 		nm_connection_add_setting (connection, infiniband_setting);
3711 	
3712 		if (!nm_connection_verify (connection, error)) {
3713 			g_object_unref (connection);
3714 			return NULL;
3715 		}
3716 	
3717 		return connection;
3718 	}
3719 	
3720 	static void
3721 	handle_bond_option (NMSettingBond *s_bond,
3722 	                    const char *key,
3723 	                    const char *value)
3724 	{
3725 		char *sanitized = NULL, *j;
3726 		const char *p = value;
3727 	
3728 		/* Remove any quotes or +/- from arp_ip_target */
3729 		if (!g_strcmp0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) && value && value[0]) {
3730 			if (*p == '\'' || *p == '"')
3731 				p++;
3732 			j = sanitized = g_malloc0 (strlen (p) + 1);
3733 			while (*p) {
3734 				if (*p != '+' && *p != '-' && *p != '\'' && *p != '"')
3735 					*j++ = *p;
3736 				p++;
3737 			}
3738 		}
3739 	
3740 		if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value))
3741 			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid bonding option '%s'", key);
3742 		g_free (sanitized);
3743 	}
3744 	
3745 	static NMSetting *
3746 	make_bond_setting (shvarFile *ifcfg,
3747 	                   const char *file,
3748 	                   gboolean nm_controlled,
3749 	                   char **unmanaged,
3750 	                   GError **error)
3751 	{
3752 		NMSettingBond *s_bond;
3753 		char *value;
3754 	
3755 		s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
3756 	
3757 		value = svGetValue (ifcfg, "DEVICE", FALSE);
3758 		if (!value || !strlen (value)) {
3759 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
3760 			goto error;
3761 		}
3762 	
3763 		g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, value, NULL);
3764 		g_free (value);
3765 	
3766 		value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
3767 		if (value) {
3768 			char **items, **iter;
3769 	
3770 			items = g_strsplit_set (value, " ", -1);
3771 			for (iter = items; iter && *iter; iter++) {
3772 				if (strlen (*iter)) {
3773 					char **keys, *key, *val;
3774 	
3775 					keys = g_strsplit_set (*iter, "=", 2);
3776 					if (keys && *keys) {
3777 						key = *keys;
3778 						val = *(keys + 1);
3779 						if (val && strlen(key) && strlen(val))
3780 							handle_bond_option (s_bond, key, val);
3781 					}
3782 	
3783 					g_strfreev (keys);
3784 				}
3785 			}
3786 			g_free (value);
3787 			g_strfreev (items);
3788 		}
3789 	
3790 		return (NMSetting *) s_bond;
3791 	
3792 	error:
3793 		g_object_unref (s_bond);
3794 		return NULL;
3795 	}
3796 	
3797 	static NMConnection *
3798 	bond_connection_from_ifcfg (const char *file,
3799 	                            shvarFile *ifcfg,
3800 	                            gboolean nm_controlled,
3801 	                            char **unmanaged,
3802 	                            GError **error)
3803 	{
3804 		NMConnection *connection = NULL;
3805 		NMSetting *con_setting = NULL;
3806 		NMSetting *bond_setting = NULL;
3807 		NMSetting *wired_setting = NULL;
3808 		NMSetting8021x *s_8021x = NULL;
3809 	
3810 		g_return_val_if_fail (file != NULL, NULL);
3811 		g_return_val_if_fail (ifcfg != NULL, NULL);
3812 	
3813 		connection = nm_connection_new ();
3814 	
3815 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
3816 		if (!con_setting) {
3817 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3818 			             "Failed to create connection setting.");
3819 			g_object_unref (connection);
3820 			return NULL;
3821 		}
3822 		nm_connection_add_setting (connection, con_setting);
3823 	
3824 		bond_setting = make_bond_setting (ifcfg, file, nm_controlled, unmanaged, error);
3825 		if (!bond_setting) {
3826 			g_object_unref (connection);
3827 			return NULL;
3828 		}
3829 		nm_connection_add_setting (connection, bond_setting);
3830 	
3831 		wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3832 		if (!wired_setting) {
3833 			g_object_unref (connection);
3834 			return NULL;
3835 		}
3836 		nm_connection_add_setting (connection, wired_setting);
3837 	
3838 		if (s_8021x)
3839 			nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3840 	
3841 		if (!nm_connection_verify (connection, error)) {
3842 			g_object_unref (connection);
3843 			return NULL;
3844 		}
3845 	
3846 		return connection;
3847 	}
3848 	
3849 	static NMSetting *
3850 	make_team_setting (shvarFile *ifcfg,
3851 	                   const char *file,
3852 	                   gboolean nm_controlled,
3853 	                   char **unmanaged,
3854 	                   GError **error)
3855 	{
3856 		NMSettingTeam *s_team;
3857 		char *value;
3858 	
3859 		s_team = NM_SETTING_TEAM (nm_setting_team_new ());
3860 	
3861 		value = svGetValue (ifcfg, "DEVICE", FALSE);
3862 		if (!value || !strlen (value)) {
3863 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
3864 			goto error;
3865 		}
3866 	
3867 		g_object_set (s_team, NM_SETTING_TEAM_INTERFACE_NAME, value, NULL);
3868 		g_free (value);
3869 	
3870 		value = svGetValue (ifcfg, "TEAM_CONFIG", FALSE);
3871 		if (value) {
3872 			g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
3873 			g_free (value);
3874 		}
3875 	
3876 		return (NMSetting *) s_team;
3877 	
3878 	error:
3879 		g_object_unref (s_team);
3880 		return NULL;
3881 	}
3882 	
3883 	static NMConnection *
3884 	team_connection_from_ifcfg (const char *file,
3885 	                            shvarFile *ifcfg,
3886 	                            gboolean nm_controlled,
3887 	                            char **unmanaged,
3888 	                            GError **error)
3889 	{
3890 		NMConnection *connection = NULL;
3891 		NMSetting *con_setting = NULL;
3892 		NMSetting *team_setting = NULL;
3893 		NMSetting *wired_setting = NULL;
3894 		NMSetting8021x *s_8021x = NULL;
3895 	
3896 		g_return_val_if_fail (file != NULL, NULL);
3897 		g_return_val_if_fail (ifcfg != NULL, NULL);
3898 	
3899 		connection = nm_connection_new ();
3900 	
3901 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
3902 		if (!con_setting) {
3903 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3904 			             "Failed to create connection setting.");
3905 			g_object_unref (connection);
3906 			return NULL;
3907 		}
3908 		nm_connection_add_setting (connection, con_setting);
3909 	
3910 		team_setting = make_team_setting (ifcfg, file, nm_controlled, unmanaged, error);
3911 		if (!team_setting) {
3912 			g_object_unref (connection);
3913 			return NULL;
3914 		}
3915 		nm_connection_add_setting (connection, team_setting);
3916 	
3917 		wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3918 		if (!wired_setting) {
3919 			g_object_unref (connection);
3920 			return NULL;
3921 		}
3922 		nm_connection_add_setting (connection, wired_setting);
3923 	
3924 		if (s_8021x)
3925 			nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3926 	
3927 		if (!nm_connection_verify (connection, error)) {
3928 			g_object_unref (connection);
3929 			return NULL;
3930 		}
3931 	
3932 		return connection;
3933 	}
3934 	
3935 	typedef void (*BridgeOptFunc) (NMSetting *setting,
3936 	                               gboolean stp,
3937 	                               const char *key,
3938 	                               const char *value);
3939 	
3940 	static void
3941 	handle_bridge_option (NMSetting *setting,
3942 	                      gboolean stp,
3943 	                      const char *key,
3944 	                      const char *value)
3945 	{
3946 		guint32 u = 0;
3947 	
3948 		if (!strcmp (key, "priority")) {
3949 			if (stp == FALSE) {
3950 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: 'priority' invalid when STP is disabled");
3951 			} else if (get_uint (value, &u))
3952 				g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL);
3953 			else
3954 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid priority value '%s'", value);
3955 		} else if (!strcmp (key, "hello_time")) {
3956 			if (stp == FALSE) {
3957 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: 'hello_time' invalid when STP is disabled");
3958 			} else if (get_uint (value, &u))
3959 				g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL);
3960 			else
3961 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid hello_time value '%s'", value);
3962 		} else if (!strcmp (key, "max_age")) {
3963 			if (stp == FALSE) {
3964 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: 'max_age' invalid when STP is disabled");
3965 			} else if (get_uint (value, &u))
3966 				g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL);
3967 			else
3968 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid max_age value '%s'", value);
3969 		} else if (!strcmp (key, "ageing_time")) {
3970 			if (get_uint (value, &u))
3971 				g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL);
3972 			else
3973 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid ageing_time value '%s'", value);
3974 		} else
3975 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: unhandled bridge option '%s'", key);
3976 	}
3977 	
3978 	static void
3979 	handle_bridging_opts (NMSetting *setting,
3980 	                      gboolean stp,
3981 	                      const char *value,
3982 	                      BridgeOptFunc func)
3983 	{
3984 		char **items, **iter;
3985 	
3986 		items = g_strsplit_set (value, " ", -1);
3987 		for (iter = items; iter && *iter; iter++) {
3988 			if (strlen (*iter)) {
3989 				char **keys, *key, *val;
3990 	
3991 				keys = g_strsplit_set (*iter, "=", 2);
3992 				if (keys && *keys) {
3993 					key = *keys;
3994 					val = *(keys + 1);
3995 					if (val && strlen(key) && strlen(val))
3996 						func (setting, stp, key, val);
3997 				}
3998 	
3999 				g_strfreev (keys);
4000 			}
4001 		}
4002 		g_strfreev (items);
4003 	}
4004 	
4005 	static NMSetting *
4006 	make_bridge_setting (shvarFile *ifcfg,
4007 	                     const char *file,
4008 	                     gboolean nm_controlled,
4009 	                     char **unmanaged,
4010 	                     GError **error)
4011 	{
4012 		NMSettingBridge *s_bridge;
4013 		char *value;
4014 		guint32 u;
4015 		gboolean stp = FALSE;
4016 		gboolean stp_set = FALSE;
4017 	
4018 		s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
4019 	
4020 		value = svGetValue (ifcfg, "DEVICE", FALSE);
4021 		if (!value || !strlen (value)) {
4022 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
4023 			goto error;
4024 		}
4025 	
4026 		g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, value, NULL);
4027 		g_free (value);
4028 	
4029 		value = svGetValue (ifcfg, "STP", FALSE);
4030 		if (value) {
4031 			if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {
4032 				g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL);
4033 				stp = TRUE;
4034 				stp_set = TRUE;
4035 			} else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) {
4036 				g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4037 				stp_set = TRUE;
4038 			} else
4039 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid STP value '%s'", value);
4040 			g_free (value);
4041 		}
4042 	
4043 		if (!stp_set) {
4044 			/* Missing or invalid STP property means "no" */
4045 			g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4046 		}
4047 	
4048 		value = svGetValue (ifcfg, "DELAY", FALSE);
4049 		if (value) {
4050 			if (stp) {
4051 				if (get_uint (value, &u))
4052 					g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL);
4053 				else
4054 					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid forward delay value '%s'", value);
4055 			} else
4056 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: DELAY invalid when STP is disabled");
4057 			g_free (value);
4058 		}
4059 	
4060 		value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4061 		if (value) {
4062 			handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option);
4063 			g_free (value);
4064 		}
4065 	
4066 		return (NMSetting *) s_bridge;
4067 	
4068 	error:
4069 		g_object_unref (s_bridge);
4070 		return NULL;
4071 	}
4072 	
4073 	static NMConnection *
4074 	bridge_connection_from_ifcfg (const char *file,
4075 	                              shvarFile *ifcfg,
4076 	                              gboolean nm_controlled,
4077 	                              char **unmanaged,
4078 	                              GError **error)
4079 	{
4080 		NMConnection *connection = NULL;
4081 		NMSetting *con_setting = NULL;
4082 		NMSetting *bridge_setting = NULL;
4083 	
4084 		g_return_val_if_fail (file != NULL, NULL);
4085 		g_return_val_if_fail (ifcfg != NULL, NULL);
4086 	
4087 		connection = nm_connection_new ();
4088 	
4089 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
4090 		if (!con_setting) {
4091 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4092 			             "Failed to create connection setting.");
4093 			g_object_unref (connection);
4094 			return NULL;
4095 		}
4096 		nm_connection_add_setting (connection, con_setting);
4097 	
4098 		bridge_setting = make_bridge_setting (ifcfg, file, nm_controlled, unmanaged, error);
4099 		if (!bridge_setting) {
4100 			g_object_unref (connection);
4101 			return NULL;
4102 		}
4103 		nm_connection_add_setting (connection, bridge_setting);	
4104 	
4105 		if (!nm_connection_verify (connection, error)) {
4106 			g_object_unref (connection);
4107 			return NULL;
4108 		}
4109 	
4110 		return connection;
4111 	}
4112 	
4113 	static void
4114 	handle_bridge_port_option (NMSetting *setting,
4115 	                           gboolean stp,
4116 	                           const char *key,
4117 	                           const char *value)
4118 	{
4119 		guint32 u = 0;
4120 	
4121 		if (!strcmp (key, "priority")) {
4122 			if (get_uint (value, &u))
4123 				g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL);
4124 			else
4125 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid priority value '%s'", value);
4126 		} else if (!strcmp (key, "path_cost")) {
4127 			if (get_uint (value, &u))
4128 				g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL);
4129 			else
4130 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid path_cost value '%s'", value);
4131 		} else if (!strcmp (key, "hairpin_mode")) {
4132 			if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1"))
4133 				g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL);
4134 			else if (!strcasecmp (value, "off") || !strcasecmp (value, "no"))
4135 				g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL);
4136 			else
4137 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid hairpin_mode value '%s'", value);
4138 		} else
4139 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: unhandled bridge port option '%s'", key);
4140 	}
4141 	
4142 	static NMSetting *
4143 	make_bridge_port_setting (shvarFile *ifcfg)
4144 	{
4145 		NMSetting *s_port = NULL;
4146 		char *value;
4147 	
4148 		g_return_val_if_fail (ifcfg != NULL, FALSE);
4149 	
4150 		value = svGetValue (ifcfg, "BRIDGE", FALSE);
4151 		if (value) {
4152 			g_free (value);
4153 	
4154 			s_port = nm_setting_bridge_port_new ();
4155 			value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4156 			if (value)
4157 				handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option);
4158 			g_free (value);
4159 		}
4160 	
4161 		return s_port;
4162 	}
4163 	
4164 	static NMSetting *
4165 	make_team_port_setting (shvarFile *ifcfg)
4166 	{
4167 		NMSetting *s_port = NULL;
4168 		char *value;
4169 	
4170 		value = svGetValue (ifcfg, "TEAM_PORT_CONFIG", FALSE);
4171 		if (value) {
4172 			s_port = nm_setting_team_port_new ();
4173 			g_object_set (s_port, NM_SETTING_TEAM_PORT_CONFIG, value, NULL);
4174 			g_free (value);
4175 		}
4176 	
4177 		return s_port;
4178 	}
4179 	
4180 	static gboolean
4181 	is_bond_device (const char *name, shvarFile *parsed)
4182 	{
4183 		g_return_val_if_fail (name != NULL, FALSE);
4184 		g_return_val_if_fail (parsed != NULL, FALSE);
4185 	
4186 		if (svTrueValue (parsed, "BONDING_MASTER", FALSE))
4187 			return TRUE;
4188 		
4189 		/* XXX: Check for "bond[\d]+"? */
4190 	
4191 		return FALSE;
4192 	}
4193 	
4194 	static gboolean
4195 	is_vlan_device (const char *name, shvarFile *parsed)
4196 	{
4197 		g_return_val_if_fail (name != NULL, FALSE);
4198 		g_return_val_if_fail (parsed != NULL, FALSE);
4199 	
4200 		if (svTrueValue (parsed, "VLAN", FALSE))
4201 			return TRUE;
4202 	
4203 		return FALSE;
4204 	}
4205 	
4206 	static void
4207 	parse_prio_map_list (NMSettingVlan *s_vlan,
4208 	                     shvarFile *ifcfg,
4209 	                     const char *key,
4210 	                     NMVlanPriorityMap map)
4211 	{
4212 		char *value;
4213 		gchar **list = NULL, **iter;
4214 	
4215 		value = svGetValue (ifcfg, key, FALSE);
4216 		if (!value)
4217 			return;
4218 	
4219 		list = g_strsplit_set (value, ",", -1);
4220 		g_free (value);
4221 	
4222 		for (iter = list; iter && *iter; iter++) {
4223 			if (!*iter || !strchr (*iter, ':'))
4224 				continue;
4225 	
4226 			if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter)) {
4227 				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid %s priority map item '%s'",
4228 				             key, *iter);
4229 			}
4230 		}
4231 		g_strfreev (list);
4232 	}
4233 	
4234 	static NMSetting *
4235 	make_vlan_setting (shvarFile *ifcfg,
4236 	                   const char *file,
4237 	                   gboolean nm_controlled,
4238 	                   char **out_master,
4239 	                   char **unmanaged,
4240 	                   NMSetting8021x **s_8021x,
4241 	                   GError **error)
4242 	{
4243 		NMSettingVlan *s_vlan = NULL;
4244 		char *value = NULL;
4245 		char *iface_name = NULL;
4246 		char *parent = NULL;
4247 		const char *p = NULL;
4248 		char *end = NULL;
4249 		gint vlan_id = -1;
4250 		guint32 vlan_flags = 0;
4251 	
4252 		value = svGetValue (ifcfg, "VLAN_ID", FALSE);
4253 		if (value) {
4254 			errno = 0;
4255 			vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
4256 			if (vlan_id < 0 || vlan_id > 4096 || errno) {
4257 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid VLAN_ID '%s'", value);
4258 				g_free (value);
4259 				return NULL;
4260 			}
4261 			g_free (value);
4262 		}
4263 	
4264 		/* Need DEVICE if we don't have a separate VLAN_ID property */
4265 		iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
4266 		if (!iface_name && vlan_id < 0) {
4267 			g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4268 			                     "Missing DEVICE property; cannot determine VLAN ID.");
4269 			return NULL;
4270 		}
4271 	
4272 		s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
4273 	
4274 		/* Parent interface from PHYSDEV takes precedence if it exists */
4275 		parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
4276 	
4277 		if (iface_name) {
4278 			g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, iface_name, NULL);
4279 	
4280 			p = strchr (iface_name, '.');
4281 			if (p) {
4282 				/* eth0.43; PHYSDEV is assumed from it if unknown */
4283 				if (!parent) {
4284 					parent = g_strndup (iface_name, p - iface_name);
4285 					if (g_str_has_prefix (parent, "vlan")) {
4286 						/* Like initscripts, if no PHYSDEV and we get an obviously
4287 						 * invalid parent interface from DEVICE, fail.
4288 						 */
4289 						g_free (parent);
4290 						parent = NULL;
4291 					}
4292 				}
4293 				p++;
4294 			} else {
4295 				/* format like vlan43; PHYSDEV or MASTER must be set */
4296 				if (g_str_has_prefix (iface_name, "vlan"))
4297 					p = iface_name + 4;
4298 			}
4299 	
4300 			if (p) {
4301 				/* Grab VLAN ID from interface name; this takes precedence over the
4302 				 * separate VLAN_ID property for backwards compat.
4303 				 */
4304 				vlan_id = (gint) g_ascii_strtoll (p, &end, 10);
4305 				if (vlan_id < 0 || vlan_id > 4095 || end == p || *end) {
4306 					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4307 					             "Failed to determine VLAN ID from DEVICE '%s'",
4308 					             iface_name);
4309 					goto error;
4310 				}
4311 			}
4312 		}
4313 	
4314 		if (vlan_id < 0) {
4315 			g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4316 			                     "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
4317 			goto error;
4318 		}
4319 		g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
4320 	
4321 		if (parent == NULL) {
4322 			g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4323 			                     "Failed to determine VLAN parent from DEVICE or PHYSDEV");
4324 			goto error;
4325 		}
4326 		g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
4327 	
4328 		if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
4329 			vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
4330 	
4331 		value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
4332 		if (value) {
4333 			if (g_strstr_len (value, -1, "GVRP"))
4334 				vlan_flags |= NM_VLAN_FLAG_GVRP;
4335 			if (g_strstr_len (value, -1, "LOOSE_BINDING"))
4336 				vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
4337 		}
4338 	
4339 		g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
4340 		g_free (value);
4341 	
4342 		parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
4343 		parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
4344 	
4345 		if (out_master)
4346 			*out_master = svGetValue (ifcfg, "MASTER", FALSE);
4347 		return (NMSetting *) s_vlan;
4348 	
4349 	error:
4350 		g_free (parent);
4351 		g_free (iface_name);
4352 		g_object_unref (s_vlan);
4353 		return NULL;
4354 	}
4355 	
4356 	static NMConnection *
4357 	vlan_connection_from_ifcfg (const char *file,
4358 	                            shvarFile *ifcfg,
4359 	                            gboolean nm_controlled,
4360 	                            char **unmanaged,
4361 	                            GError **error)
4362 	{
4363 		NMConnection *connection = NULL;
4364 		NMSetting *con_setting = NULL;
4365 		NMSetting *wired_setting = NULL;
4366 		NMSetting *vlan_setting = NULL;
4367 		NMSetting8021x *s_8021x = NULL;
4368 		char *master = NULL;
4369 	
4370 		g_return_val_if_fail (file != NULL, NULL);
4371 		g_return_val_if_fail (ifcfg != NULL, NULL);
4372 	
4373 		connection = nm_connection_new ();
4374 	
4375 		con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
4376 		if (!con_setting) {
4377 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4378 				     "Failed to create connection setting.");
4379 			g_object_unref (connection);
4380 			return NULL;
4381 		}
4382 		nm_connection_add_setting (connection, con_setting);
4383 	
4384 		vlan_setting = make_vlan_setting (ifcfg, file, nm_controlled, &master, unmanaged, &s_8021x, error);
4385 		if (!vlan_setting) {
4386 			g_object_unref (connection);
4387 			return NULL;
4388 		}
4389 		nm_connection_add_setting (connection, vlan_setting);
4390 	
4391 		/* Handle master interface or connection */
4392 		if (master) {
4393 			g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, master, NULL);
4394 			g_object_set (con_setting,
4395 			              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
4396 			              NULL);
4397 			g_free (master);
4398 		}
4399 	
4400 		wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
4401 		if (!wired_setting) {
4402 			g_object_unref (connection);
4403 			return NULL;
4404 		}
4405 		nm_connection_add_setting (connection, wired_setting);
4406 	
4407 		if (s_8021x)
4408 			nm_connection_add_setting (connection, NM_SETTING (s_8021x));
(17) Event example_checked: Example3: "nm_connection_verify(connection, error)" has its value checked in "nm_connection_verify(connection, error)".
Also see events: [check_return][example_checked][example_assign][example_checked][example_checked][example_checked][unchecked_value]
4409 		if (!nm_connection_verify (connection, error)) {
4410 			g_object_unref (connection);
4411 			return NULL;
4412 		}
4413 	
4414 		return connection;
4415 	}
4416 	
4417 	static void
4418 	ensure_unmanaged (shvarFile *ifcfg,
4419 	                  char **unmanaged)
4420 	{
4421 		char *value;
4422 	
4423 		if (*unmanaged)
4424 			return;
4425 	
4426 		value = svGetValue (ifcfg, "DEVICE", FALSE);
4427 		if (value) {
4428 			*unmanaged = g_strdup_printf ("interface-name:%s", value);
4429 			g_free (value);
4430 			return;
4431 		}
4432 	
4433 		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
4434 	}
4435 	
4436 	char *
4437 	uuid_from_file (const char *filename)
4438 	{
4439 		const char *ifcfg_name = NULL;
4440 		shvarFile *ifcfg;
4441 		char *uuid;
4442 	
4443 		g_return_val_if_fail (filename != NULL, NULL);
4444 	
4445 		ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4446 		if (!ifcfg_name)
4447 			return NULL;
4448 	
4449 		ifcfg = svNewFile (filename);
4450 		if (!ifcfg)
4451 			return NULL;
4452 	
4453 		/* Try for a UUID key before falling back to hashing the file name */
4454 		uuid = svGetValue (ifcfg, "UUID", FALSE);
4455 		if (!uuid || !strlen (uuid)) {
4456 			g_free (uuid);
4457 			uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
4458 		}
4459 	
4460 		svCloseFile (ifcfg);
4461 		return uuid;
4462 	}
4463 	
4464 	static void
4465 	check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
4466 	{
4467 		if (!s_ip6)
4468 			return;
4469 	
4470 		/* If there is no IPv4 config or it doesn't contain DNS searches,
4471 		 * read DOMAIN and put the domains into IPv6.
4472 		 */
4473 		if (!s_ip4 || nm_setting_ip4_config_get_num_dns_searches (NM_SETTING_IP4_CONFIG (s_ip4)) == 0) {
4474 			/* DNS searches */
4475 			char *value = svGetValue (ifcfg, "DOMAIN", FALSE);
4476 			if (value) {
4477 				char **searches = g_strsplit (value, " ", 0);
4478 				if (searches) {
4479 					char **item;
4480 					for (item = searches; *item; item++) {
4481 						if (strlen (*item)) {
4482 							if (!nm_setting_ip6_config_add_dns_search (NM_SETTING_IP6_CONFIG (s_ip6), *item))
4483 								PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS domain '%s'", *item);
4484 						}
4485 					}
4486 					g_strfreev (searches);
4487 				}
4488 				g_free (value);
4489 			}
4490 		}
4491 	}
4492 	
4493 	NMConnection *
4494 	connection_from_file (const char *filename,
4495 	                      const char *network_file,  /* for unit tests only */
4496 	                      const char *test_type,     /* for unit tests only */
4497 	                      const char *iscsiadm_path, /* for unit tests only */
4498 	                      char **out_unmanaged,
4499 	                      char **out_keyfile,
4500 	                      char **out_routefile,
4501 	                      char **out_route6file,
4502 	                      GError **error,
4503 	                      gboolean *out_ignore_error)
4504 	{
4505 		NMConnection *connection = NULL;
4506 		shvarFile *parsed;
4507 		char *type, *devtype, *nmc = NULL, *bootproto;
4508 		NMSetting *s_ip4, *s_ip6, *s_port;
4509 		const char *ifcfg_name = NULL;
4510 		gboolean nm_controlled = TRUE;
4511 		char *unmanaged = NULL;
4512 	
4513 		g_return_val_if_fail (filename != NULL, NULL);
4514 		if (out_unmanaged)
4515 			g_return_val_if_fail (*out_unmanaged == NULL, NULL);
4516 		if (out_keyfile)
4517 			g_return_val_if_fail (*out_keyfile == NULL, NULL);
4518 		if (out_routefile)
4519 			g_return_val_if_fail (*out_routefile == NULL, NULL);
4520 		if (out_route6file)
4521 			g_return_val_if_fail (*out_route6file == NULL, NULL);
4522 	
4523 		/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
4524 		if (!network_file)
4525 			network_file = SYSCONFDIR "/sysconfig/network";
4526 	
4527 		if (!iscsiadm_path)
4528 			iscsiadm_path = "/sbin/iscsiadm";
4529 	
4530 		ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4531 		if (!ifcfg_name) {
4532 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4533 			             "Ignoring connection '%s' because it's not an ifcfg file.", filename);
4534 			return NULL;
4535 		}
4536 	
4537 		parsed = svNewFile (filename);
4538 		if (!parsed) {
4539 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4540 			             "Couldn't parse file '%s'", filename);
4541 			return NULL;
4542 		}
4543 	
4544 		type = NULL;
4545 	
4546 		devtype = svGetValue (parsed, "DEVICETYPE", FALSE);
4547 		if (devtype) {
4548 			if (!strcasecmp (devtype, TYPE_TEAM))
4549 				type = g_strdup (TYPE_TEAM);
4550 			g_free (devtype);
4551 		}
4552 	
4553 		if (!type)
4554 			type = svGetValue (parsed, "TYPE", FALSE);
4555 	
4556 		if (!type) {
4557 			char *device;
4558 	
4559 			device = svGetValue (parsed, "DEVICE", FALSE);
4560 			if (!device) {
4561 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4562 				             "File '%s' had neither TYPE nor DEVICE keys.", filename);
4563 				goto done;
4564 			}
4565 	
4566 			if (!strcmp (device, "lo")) {
4567 				if (out_ignore_error)
4568 					*out_ignore_error = TRUE;
4569 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4570 				             "Ignoring loopback device config.");
4571 				g_free (device);
4572 				goto done;
4573 			}
4574 	
4575 			if (!test_type) {
4576 				if (is_bond_device (device, parsed))
4577 					type = g_strdup (TYPE_BOND);
4578 				else if (is_vlan_device (device, parsed))
4579 					type = g_strdup (TYPE_VLAN);
4580 				/* Test wireless extensions */
4581 				else if (wifi_utils_is_wifi (device, NULL))
4582 					type = g_strdup (TYPE_WIRELESS);
4583 				else
4584 					type = g_strdup (TYPE_ETHERNET);
4585 			} else {
4586 				/* For the unit tests, there won't necessarily be any
4587 				 * adapters of the connection's type in the system so the
4588 				 * type can't be tested with ioctls.
4589 				 */
4590 				type = g_strdup (test_type);
4591 			}
4592 	
4593 			g_free (device);
4594 		} else {
4595 			/* Check for IBM s390 CTC devices and call them Ethernet */
4596 			if (g_strcmp0 (type, "CTC") == 0) {
4597 				g_free (type);
4598 				type = g_strdup (TYPE_ETHERNET);
4599 			}
4600 		}
4601 	
4602 		nmc = svGetValue (parsed, "NM_CONTROLLED", FALSE);
4603 		if (nmc) {
4604 			char *lower;
4605 	
4606 			lower = g_ascii_strdown (nmc, -1);
4607 			g_free (nmc);
4608 	
4609 			if (!strcmp (lower, "no") || !strcmp (lower, "n") || !strcmp (lower, "false"))
4610 				nm_controlled = FALSE;
4611 			g_free (lower);
4612 		}
4613 	
4614 		if (svTrueValue (parsed, "BONDING_MASTER", FALSE) &&
4615 		    strcasecmp (type, TYPE_BOND)) {
4616 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4617 			             "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
4618 			goto done;
4619 		}
4620 	
4621 		/* Construct the connection */
4622 		if (!strcasecmp (type, TYPE_ETHERNET))
4623 			connection = wired_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4624 		else if (!strcasecmp (type, TYPE_WIRELESS))
4625 			connection = wireless_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4626 		else if (!strcasecmp (type, TYPE_INFINIBAND))
4627 			connection = infiniband_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4628 		else if (!strcasecmp (type, TYPE_BOND))
4629 			connection = bond_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4630 		else if (!strcasecmp (type, TYPE_TEAM))
4631 			connection = team_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4632 		else if (!strcasecmp (type, TYPE_VLAN))
4633 			connection = vlan_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4634 		else if (!strcasecmp (type, TYPE_BRIDGE))
4635 			connection = bridge_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4636 		else {
4637 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Unknown connection type '%s'", type);
4638 		}
4639 	
4640 		if (!nm_controlled)
4641 			ensure_unmanaged (parsed, &unmanaged);
4642 	
4643 		g_free (type);
4644 	
4645 		/* Don't bother reading the connection fully if it's unmanaged or ignored */
4646 		if (!connection || unmanaged)
4647 			goto done;
4648 	
4649 		s_ip6 = make_ip6_setting (parsed, network_file, iscsiadm_path, error);
4650 		if (!s_ip6) {
4651 			g_object_unref (connection);
4652 			connection = NULL;
4653 			goto done;
4654 		} else
4655 			nm_connection_add_setting (connection, s_ip6);
4656 	
4657 		s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, error);
4658 		if (!s_ip4) {
4659 			g_object_unref (connection);
4660 			connection = NULL;
4661 			goto done;
4662 		} else
4663 			nm_connection_add_setting (connection, s_ip4);
4664 	
4665 		/* There is only one DOMAIN variable and it is read and put to IPv4 config
4666 		 * But if IPv4 is disabled or the config fails for some reason, we read
4667 		 * DOMAIN and put the values into IPv6 config instead.
4668 		 */
4669 		check_dns_search_domains (parsed, s_ip4, s_ip6);
4670 	
4671 		/* Bridge port? */
4672 		s_port = make_bridge_port_setting (parsed);
4673 		if (s_port)
4674 			nm_connection_add_setting (connection, s_port);
4675 	
4676 		/* Team port? */
4677 		s_port = make_team_port_setting (parsed);
4678 		if (s_port)
4679 			nm_connection_add_setting (connection, s_port);
4680 	
4681 		/* iSCSI / ibft connections are read-only since their settings are
4682 		 * stored in NVRAM and can only be changed in BIOS.
4683 		 */
4684 		bootproto = svGetValue (parsed, "BOOTPROTO", FALSE);
4685 		if (   bootproto
4686 		    && connection
4687 		    && !g_ascii_strcasecmp (bootproto, "ibft")) {
4688 			NMSettingConnection *s_con;
4689 	
4690 			s_con = nm_connection_get_setting_connection (connection);
4691 			g_assert (s_con);
4692 	
4693 			g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL);
4694 		}
4695 		g_free (bootproto);
4696 	
4697 		nm_utils_normalize_connection (connection, TRUE);
4698 	
4699 		if (!nm_connection_verify (connection, error)) {
4700 			g_object_unref (connection);
4701 			connection = NULL;
4702 		}
4703 	
4704 		if (out_keyfile)
4705 			*out_keyfile = utils_get_keys_path (filename);
4706 		if (out_routefile)
4707 			*out_routefile = utils_get_route_path (filename);
4708 		if (out_route6file)
4709 			*out_route6file = utils_get_route6_path (filename);
4710 	
4711 	done:
4712 		if (out_unmanaged)
4713 			*out_unmanaged = unmanaged;
4714 		else
4715 			g_free (unmanaged);
4716 	
4717 		svCloseFile (parsed);
4718 		return connection;
4719 	}
4720 	
4721