1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* NetworkManager system settings service - keyfile plugin
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) 2009 - 2012 Red Hat, Inc.
19   	 */
20   	
21   	#include <string.h>
22   	#include <sys/types.h>
23   	#include <sys/socket.h>
24   	#include <arpa/inet.h>
25   	#include <errno.h>
26   	#include <stdlib.h>
27   	#include <sys/stat.h>
28   	#include <unistd.h>
29   	#include <stdio.h>
30   	#include <netinet/ether.h>
31   	
32   	#include <nm-setting-connection.h>
33   	#include <nm-setting-wired.h>
34   	#include <nm-setting-wireless.h>
35   	#include <nm-setting-8021x.h>
36   	#include <nm-setting-ip4-config.h>
37   	#include <nm-setting-ip6-config.h>
38   	#include <nm-setting-pppoe.h>
39   	#include <nm-setting-vlan.h>
40   	#include <nm-setting-team.h>
41   	#include <nm-setting-team-port.h>
42   	#include <nm-utils.h>
43   	
44   	#include "common.h"
45   	#include "shvar.h"
46   	#include "reader.h"
47   	#include "writer.h"
48   	#include "utils.h"
49   	#include "crypto.h"
50   	
51   	#define PLUGIN_WARN(pname, fmt, args...) \
52   		{ g_warning ("   " pname ": " fmt, ##args); }
53   	
54   	static void
55   	save_secret_flags (shvarFile *ifcfg,
56   	                   const char *key,
57   	                   NMSettingSecretFlags flags)
58   	{
59   		GString *str;
60   	
61   		g_return_if_fail (ifcfg != NULL);
62   		g_return_if_fail (key != NULL);
63   	
64   		if (flags == NM_SETTING_SECRET_FLAG_NONE) {
65   			svSetValue (ifcfg, key, NULL, FALSE);
66   			return;
67   		}
68   	
69   		/* Convert flags bitfield into string representation */
70   		str = g_string_sized_new (20);
71   		if (flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)
72   			g_string_append (str, SECRET_FLAG_AGENT);
73   	
74   		if (flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) {
75   			if (str->len)
76   				g_string_append_c (str, ' ');
77   			g_string_append (str, SECRET_FLAG_NOT_SAVED);
78   		}
79   	
80   		if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
81   			if (str->len)
82   				g_string_append_c (str, ' ');
83   			g_string_append (str, SECRET_FLAG_NOT_REQUIRED);
84   		}
85   	
86   		svSetValue (ifcfg, key, str->len ? str->str : NULL, FALSE);
87   		g_string_free (str, TRUE);
88   	}
89   	
90   	static void
91   	set_secret (shvarFile *ifcfg,
92   	            const char *key,
93   	            const char *value,
94   	            const char *flags_key,
95   	            NMSettingSecretFlags flags,
96   	            gboolean verbatim)
97   	{
98   		shvarFile *keyfile;
99   		
100  		/* Clear the secret from the ifcfg and the associated "keys" file */
101  		svSetValue (ifcfg, key, NULL, FALSE);
102  	
103  		/* Save secret flags */
104  		save_secret_flags (ifcfg, flags_key, flags);
105  	
106  		keyfile = utils_get_keys_ifcfg (ifcfg->fileName, TRUE);
107  		if (!keyfile) {
108  			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: could not create key file for '%s'",
109  			             ifcfg->fileName);
110  			goto error;
111  		}
112  	
113  		/* Clear the secret from the associated "keys" file */
114  		svSetValue (keyfile, key, NULL, FALSE);
115  	
116  		/* Only write the secret if it's system owned and supposed to be saved */
117  		if (flags == NM_SETTING_SECRET_FLAG_NONE)
118  			svSetValue (keyfile, key, value, verbatim);
119  	
120  		if (svWriteFile (keyfile, 0600)) {
121  			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: could not update key file '%s'",
122  			             keyfile->fileName);
123  			svCloseFile (keyfile);
124  			goto error;
125  		}
126  		svCloseFile (keyfile);
127  		return;
128  	
129  	error:
130  		/* Try setting the secret in the actual ifcfg */
131  		svSetValue (ifcfg, key, value, FALSE);
132  	}
133  	
134  	static gboolean
135  	write_secret_file (const char *path,
136  	                   const char *data,
137  	                   gsize len,
138  	                   GError **error)
139  	{
140  		char *tmppath;
141  		int fd = -1, written;
142  		gboolean success = FALSE;
143  	
144  		tmppath = g_malloc0 (strlen (path) + 10);
145  		memcpy (tmppath, path, strlen (path));
146  		strcat (tmppath, ".XXXXXX");
147  	
148  		errno = 0;
149  		fd = mkstemp (tmppath);
150  		if (fd < 0) {
151  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
152  			             "Could not create temporary file for '%s': %d",
153  			             path, errno);
154  			goto out;
155  		}
156  	
157  		/* Only readable by root */
158  		errno = 0;
159  		if (fchmod (fd, S_IRUSR | S_IWUSR)) {
160  			close (fd);
161  			unlink (tmppath);
162  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
163  			             "Could not set permissions for temporary file '%s': %d",
164  			             path, errno);
165  			goto out;
166  		}
167  	
168  		errno = 0;
169  		written = write (fd, data, len);
170  		if (written != len) {
171  			close (fd);
172  			unlink (tmppath);
173  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
174  			             "Could not write temporary file for '%s': %d",
175  			             path, errno);
176  			goto out;
177  		}
178  		close (fd);
179  	
180  		/* Try to rename */
181  		errno = 0;
182  		if (rename (tmppath, path)) {
183  			unlink (tmppath);
184  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
185  			             "Could not rename temporary file to '%s': %d",
186  			             path, errno);
187  			goto out;
188  		}
189  		success = TRUE;
190  	
191  	out:
192  		g_free (tmppath);
193  		return success;
194  	}
195  	
196  	typedef struct ObjectType {
197  		const char *setting_key;
198  		NMSetting8021xCKScheme (*scheme_func)(NMSetting8021x *setting);
199  		const char *           (*path_func)  (NMSetting8021x *setting);
200  		const GByteArray *     (*blob_func)  (NMSetting8021x *setting);
201  		const char *ifcfg_key;
202  		const char *suffix;
203  	} ObjectType;
204  	
205  	static const ObjectType ca_type = {
206  		NM_SETTING_802_1X_CA_CERT,
207  		nm_setting_802_1x_get_ca_cert_scheme,
208  		nm_setting_802_1x_get_ca_cert_path,
209  		nm_setting_802_1x_get_ca_cert_blob,
210  		"IEEE_8021X_CA_CERT",
211  		"ca-cert.der"
212  	};
213  	
214  	static const ObjectType phase2_ca_type = {
215  		NM_SETTING_802_1X_PHASE2_CA_CERT,
216  		nm_setting_802_1x_get_phase2_ca_cert_scheme,
217  		nm_setting_802_1x_get_phase2_ca_cert_path,
218  		nm_setting_802_1x_get_phase2_ca_cert_blob,
219  		"IEEE_8021X_INNER_CA_CERT",
220  		"inner-ca-cert.der"
221  	};
222  	
223  	static const ObjectType client_type = {
224  		NM_SETTING_802_1X_CLIENT_CERT,
225  		nm_setting_802_1x_get_client_cert_scheme,
226  		nm_setting_802_1x_get_client_cert_path,
227  		nm_setting_802_1x_get_client_cert_blob,
228  		"IEEE_8021X_CLIENT_CERT",
229  		"client-cert.der"
230  	};
231  	
232  	static const ObjectType phase2_client_type = {
233  		NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
234  		nm_setting_802_1x_get_phase2_client_cert_scheme,
235  		nm_setting_802_1x_get_phase2_client_cert_path,
236  		nm_setting_802_1x_get_phase2_client_cert_blob,
237  		"IEEE_8021X_INNER_CLIENT_CERT",
238  		"inner-client-cert.der"
239  	};
240  	
241  	static const ObjectType pk_type = {
242  		NM_SETTING_802_1X_PRIVATE_KEY,
243  		nm_setting_802_1x_get_private_key_scheme,
244  		nm_setting_802_1x_get_private_key_path,
245  		nm_setting_802_1x_get_private_key_blob,
246  		"IEEE_8021X_PRIVATE_KEY",
247  		"private-key.pem"
248  	};
249  	
250  	static const ObjectType phase2_pk_type = {
251  		NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
252  		nm_setting_802_1x_get_phase2_private_key_scheme,
253  		nm_setting_802_1x_get_phase2_private_key_path,
254  		nm_setting_802_1x_get_phase2_private_key_blob,
255  		"IEEE_8021X_INNER_PRIVATE_KEY",
256  		"inner-private-key.pem"
257  	};
258  	
259  	static const ObjectType p12_type = {
260  		NM_SETTING_802_1X_PRIVATE_KEY,
261  		nm_setting_802_1x_get_private_key_scheme,
262  		nm_setting_802_1x_get_private_key_path,
263  		nm_setting_802_1x_get_private_key_blob,
264  		"IEEE_8021X_PRIVATE_KEY",
265  		"private-key.p12"
266  	};
267  	
268  	static const ObjectType phase2_p12_type = {
269  		NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
270  		nm_setting_802_1x_get_phase2_private_key_scheme,
271  		nm_setting_802_1x_get_phase2_private_key_path,
272  		nm_setting_802_1x_get_phase2_private_key_blob,
273  		"IEEE_8021X_INNER_PRIVATE_KEY",
274  		"inner-private-key.p12"
275  	};
276  	
277  	static gboolean
278  	write_object (NMSetting8021x *s_8021x,
279  	              shvarFile *ifcfg,
280  	              const ObjectType *objtype,
281  	              GError **error)
282  	{
283  		NMSetting8021xCKScheme scheme;
284  		const char *path = NULL;
285  		const GByteArray *blob = NULL;
286  	
287  		g_return_val_if_fail (ifcfg != NULL, FALSE);
288  		g_return_val_if_fail (objtype != NULL, FALSE);
289  	
290  		scheme = (*(objtype->scheme_func))(s_8021x);
291  		switch (scheme) {
292  		case NM_SETTING_802_1X_CK_SCHEME_BLOB:
293  			blob = (*(objtype->blob_func))(s_8021x);
294  			break;
295  		case NM_SETTING_802_1X_CK_SCHEME_PATH:
296  			path = (*(objtype->path_func))(s_8021x);
297  			break;
298  		default:
299  			break;
300  		}
301  	
302  		/* If certificate/private key wasn't sent, the connection may no longer be
303  		 * 802.1x and thus we clear out the paths and certs.
304  		 */
305  		if (!path && !blob) {
306  			char *standard_file;
307  			int ignored;
308  	
309  			/* Since no cert/private key is now being used, delete any standard file
310  			 * that was created for this connection, but leave other files alone.
311  			 * Thus, for example,
312  			 * /etc/sysconfig/network-scripts/ca-cert-Test_Write_Wifi_WPA_EAP-TLS.der
313  			 * will be deleted, but /etc/pki/tls/cert.pem will not.
314  			 */
315  			standard_file = utils_cert_path (ifcfg->fileName, objtype->suffix);
316  			if (g_file_test (standard_file, G_FILE_TEST_EXISTS))
317  				ignored = unlink (standard_file);
318  			g_free (standard_file);
319  	
320  			svSetValue (ifcfg, objtype->ifcfg_key, NULL, FALSE);
321  			return TRUE;
322  		}
323  	
324  		/* If the object path was specified, prefer that over any raw cert data that
325  		 * may have been sent.
326  		 */
327  		if (path) {
328  			svSetValue (ifcfg, objtype->ifcfg_key, path, FALSE);
329  			return TRUE;
330  		}
331  	
332  		/* If it's raw certificate data, write the data out to the standard file */
333  		if (blob) {
334  			gboolean success;
335  			char *new_file;
336  			GError *write_error = NULL;
337  	
338  			new_file = utils_cert_path (ifcfg->fileName, objtype->suffix);
339  			if (!new_file) {
340  				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
341  				             "Could not create file path for %s / %s",
342  				             NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key);
343  				return FALSE;
344  			}
345  	
346  			/* Write the raw certificate data out to the standard file so that we
347  			 * can use paths from now on instead of pushing around the certificate
348  			 * data itself.
349  			 */
350  			success = write_secret_file (new_file, (const char *) blob->data, blob->len, &write_error);
351  			if (success) {
352  				svSetValue (ifcfg, objtype->ifcfg_key, new_file, FALSE);
353  				g_free (new_file);
354  				return TRUE;
355  			} else {
356  				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
357  				             "Could not write certificate/key for %s / %s: %s",
358  				             NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key,
359  				             (write_error && write_error->message) ? write_error->message : "(unknown)");
360  				g_clear_error (&write_error);
361  			}
362  			g_free (new_file);
363  		}
364  	
365  		return FALSE;
366  	}
367  	
368  	static gboolean
369  	write_8021x_certs (NMSetting8021x *s_8021x,
370  	                   gboolean phase2,
371  	                   shvarFile *ifcfg,
372  	                   GError **error)
373  	{
374  		const char *password = NULL;
375  		gboolean success = FALSE, is_pkcs12 = FALSE;
376  		const ObjectType *otype = NULL;
377  		NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
378  	
379  		/* CA certificate */
380  		if (!write_object (s_8021x, ifcfg, phase2 ? &phase2_ca_type : &ca_type, error))
381  			return FALSE;
382  	
383  		/* Private key */
384  		if (phase2) {
385  			otype = &phase2_pk_type;
386  			if (nm_setting_802_1x_get_phase2_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
387  				otype = &phase2_p12_type;
388  				is_pkcs12 = TRUE;
389  			}
390  			password = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
391  			flags = nm_setting_802_1x_get_phase2_private_key_password_flags (s_8021x);
392  		} else {
393  			otype = &pk_type;
394  			if (nm_setting_802_1x_get_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
395  				otype = &p12_type;
396  				is_pkcs12 = TRUE;
397  			}
398  			password = nm_setting_802_1x_get_private_key_password (s_8021x);
399  			flags = nm_setting_802_1x_get_private_key_password_flags (s_8021x);
400  		}
401  	
402  		/* Save the private key */
403  		if (!write_object (s_8021x, ifcfg, otype, error))
404  			goto out;
405  	
406  		/* Private key password */
407  		if (phase2) {
408  			set_secret (ifcfg,
409  			            "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD",
410  			            password,
411  			            "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS",
412  			            flags,
413  			            FALSE);
414  		} else {
415  			set_secret (ifcfg,
416  			            "IEEE_8021X_PRIVATE_KEY_PASSWORD",
417  			            password,
418  			            "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS",
419  			            flags,
420  			            FALSE);
421  		}
422  	
423  		/* Client certificate */
424  		if (is_pkcs12) {
425  			/* Don't need a client certificate with PKCS#12 since the file is both
426  			 * the client certificate and the private key in one file.
427  			 */
428  			svSetValue (ifcfg,
429  			            phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT",
430  			            NULL, FALSE);
431  		} else {
432  			/* Save the client certificate */
433  			if (!write_object (s_8021x, ifcfg, phase2 ? &phase2_client_type : &client_type, error))
434  				goto out;
435  		}
436  	
437  		success = TRUE;
438  	
439  	out:
440  		return success;
441  	}
442  	
443  	static gboolean
444  	write_8021x_setting (NMConnection *connection,
445  	                     shvarFile *ifcfg,
446  	                     gboolean wired,
447  	                     GError **error)
448  	{
449  		NMSetting8021x *s_8021x;
450  		const char *value;
451  		char *tmp = NULL;
452  		gboolean success = FALSE;
453  		GString *phase2_auth;
454  	
455  		s_8021x = nm_connection_get_setting_802_1x (connection);
456  		if (!s_8021x) {
457  			/* If wired, clear KEY_MGMT */
458  			if (wired)
459  				svSetValue (ifcfg, "KEY_MGMT", NULL, FALSE);
460  			return TRUE;
461  		}
462  	
463  		/* If wired, write KEY_MGMT */
464  		if (wired)
465  			svSetValue (ifcfg, "KEY_MGMT", "IEEE8021X", FALSE);
466  	
467  		/* EAP method */
468  		if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) {
469  			value = nm_setting_802_1x_get_eap_method (s_8021x, 0);
470  			if (value)
471  				tmp = g_ascii_strup (value, -1);
472  		}
473  		svSetValue (ifcfg, "IEEE_8021X_EAP_METHODS", tmp ? tmp : NULL, FALSE);
474  		g_free (tmp);
475  	
476  		svSetValue (ifcfg, "IEEE_8021X_IDENTITY",
477  		            nm_setting_802_1x_get_identity (s_8021x),
478  		            FALSE);
479  	
480  		svSetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY",
481  		            nm_setting_802_1x_get_anonymous_identity (s_8021x),
482  		            FALSE);
483  	
484  		set_secret (ifcfg,
485  		            "IEEE_8021X_PASSWORD",
486  		            nm_setting_802_1x_get_password (s_8021x),
487  		            "IEEE_8021X_PASSWORD_FLAGS",
488  		            nm_setting_802_1x_get_password_flags (s_8021x),
489  		            FALSE);
490  	
491  		/* PEAP version */
492  		value = nm_setting_802_1x_get_phase1_peapver (s_8021x);
493  		svSetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", NULL, FALSE);
494  		if (value && (!strcmp (value, "0") || !strcmp (value, "1")))
495  			svSetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", value, FALSE);
496  	
497  		/* Force new PEAP label */
498  		value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x);
499  		svSetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", NULL, FALSE);
500  		if (value && !strcmp (value, "1"))
501  			svSetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes", FALSE);
502  	
503  		/* PAC file */
504  		value = nm_setting_802_1x_get_pac_file (s_8021x);
505  		svSetValue (ifcfg, "IEEE_8021X_PAC_FILE", NULL, FALSE);
506  		if (value)
507  			svSetValue (ifcfg, "IEEE_8021X_PAC_FILE", value, FALSE);
508  	
509  		/* FAST PAC provisioning */
510  		value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
511  		svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", NULL, FALSE);
512  		if (value) {
513  			if (strcmp (value, "1") == 0)
514  				svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth", FALSE);
515  			else if (strcmp (value, "2") == 0)
516  				svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth", FALSE);
517  			else if (strcmp (value, "3") == 0)
518  				svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth", FALSE);
519  		}
520  	
521  		/* Phase2 auth methods */
522  		svSetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", NULL, FALSE);
523  		phase2_auth = g_string_new (NULL);
524  	
525  		value = nm_setting_802_1x_get_phase2_auth (s_8021x);
526  		if (value) {
527  			tmp = g_ascii_strup (value, -1);
528  			g_string_append (phase2_auth, tmp);
529  			g_free (tmp);
530  		}
531  	
532  		value = nm_setting_802_1x_get_phase2_autheap (s_8021x);
533  		if (value) {
534  			if (phase2_auth->len)
535  				g_string_append_c (phase2_auth, ' ');
536  	
537  			tmp = g_ascii_strup (value, -1);
538  			g_string_append_printf (phase2_auth, "EAP-%s", tmp);
539  			g_free (tmp);
540  		}
541  	
542  		svSetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS",
543  		            phase2_auth->len ? phase2_auth->str : NULL,
544  		            FALSE);
545  	
546  		g_string_free (phase2_auth, TRUE);
547  	
548  		success = write_8021x_certs (s_8021x, FALSE, ifcfg, error);
549  		if (success) {
550  			/* phase2/inner certs */
551  			success = write_8021x_certs (s_8021x, TRUE, ifcfg, error);
552  		}
553  	
554  		return success;
555  	}
556  	
557  	static gboolean
558  	write_wireless_security_setting (NMConnection *connection,
559  	                                 shvarFile *ifcfg,
560  	                                 gboolean adhoc,
561  	                                 gboolean *no_8021x,
562  	                                 GError **error)
563  	{
564  		NMSettingWirelessSecurity *s_wsec;
565  		const char *key_mgmt, *auth_alg, *key, *proto, *cipher, *psk;
566  		gboolean wep = FALSE, wpa = FALSE, dynamic_wep = FALSE;
567  		char *tmp;
568  		guint32 i, num;
569  		GString *str;
570  	
571  		s_wsec = nm_connection_get_setting_wireless_security (connection);
572  		if (!s_wsec) {
573  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
574  			             "Missing '%s' setting", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
575  			return FALSE;
576  		}
577  	
578  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
579  		g_assert (key_mgmt);
580  	
581  		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
582  	
583  		svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE);
584  	
585  		if (!strcmp (key_mgmt, "none")) {
586  			svSetValue (ifcfg, "KEY_MGMT", NULL, FALSE);
587  			wep = TRUE;
588  			*no_8021x = TRUE;
589  		} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
590  			svSetValue (ifcfg, "KEY_MGMT", "WPA-PSK", FALSE);
591  			wpa = TRUE;
592  			*no_8021x = TRUE;
593  		} else if (!strcmp (key_mgmt, "ieee8021x")) {
594  			svSetValue (ifcfg, "KEY_MGMT", "IEEE8021X", FALSE);
595  			dynamic_wep = TRUE;
596  		} else if (!strcmp (key_mgmt, "wpa-eap")) {
597  			svSetValue (ifcfg, "KEY_MGMT", "WPA-EAP", FALSE);
598  			wpa = TRUE;
599  		}
600  	
601  		svSetValue (ifcfg, "SECURITYMODE", NULL, FALSE);
602  		if (auth_alg) {
603  			if (!strcmp (auth_alg, "shared"))
604  				svSetValue (ifcfg, "SECURITYMODE", "restricted", FALSE);
605  			else if (!strcmp (auth_alg, "open"))
606  				svSetValue (ifcfg, "SECURITYMODE", "open", FALSE);
607  			else if (!strcmp (auth_alg, "leap")) {
608  				svSetValue (ifcfg, "SECURITYMODE", "leap", FALSE);
609  				svSetValue (ifcfg, "IEEE_8021X_IDENTITY",
610  				            nm_setting_wireless_security_get_leap_username (s_wsec),
611  				            FALSE);
612  				set_secret (ifcfg,
613  				            "IEEE_8021X_PASSWORD",
614  				            nm_setting_wireless_security_get_leap_password (s_wsec),
615  				            "IEEE_8021X_PASSWORD_FLAGS",
616  				            nm_setting_wireless_security_get_leap_password_flags (s_wsec),
617  				            FALSE);
618  				*no_8021x = TRUE;
619  			}
620  		}
621  	
622  		/* WEP keys */
623  	
624  		/* Clear any default key */
625  		set_secret (ifcfg, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
626  	
627  		/* Clear existing keys */
628  		for (i = 0; i < 4; i++) {
629  			tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1);
630  			set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
631  			g_free (tmp);
632  	
633  			tmp = g_strdup_printf ("KEY%d", i + 1);
634  			set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
635  			g_free (tmp);
636  		}
637  	
638  		/* And write the new ones out */
639  		if (wep) {
640  			/* Default WEP TX key index */
641  			tmp = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec) + 1);
642  			svSetValue (ifcfg, "DEFAULTKEY", tmp, FALSE);
643  			g_free (tmp);
644  	
645  			for (i = 0; i < 4; i++) {
646  				NMWepKeyType key_type;
647  	
648  				key = nm_setting_wireless_security_get_wep_key (s_wsec, i);
649  				if (key) {
650  					char *ascii_key = NULL;
651  	
652  					/* Passphrase needs a different ifcfg key since with WEP, there
653  					 * are some passphrases that are indistinguishable from WEP hex
654  					 * keys.
655  					 */
656  					key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec);
657  					if (key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
658  						tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1);
659  					else {
660  						tmp = g_strdup_printf ("KEY%d", i + 1);
661  	
662  						/* Add 's:' prefix for ASCII keys */
663  						if (strlen (key) == 5 || strlen (key) == 13) {
664  							ascii_key = g_strdup_printf ("s:%s", key);
665  							key = ascii_key;
666  						}
667  					}
668  	
669  					set_secret (ifcfg,
670  					            tmp,
671  					            key,
672  					            "WEP_KEY_FLAGS",
673  					            nm_setting_wireless_security_get_wep_key_flags (s_wsec),
674  					            FALSE);
675  					g_free (tmp);
676  					g_free (ascii_key);
677  				}
678  			}
679  		}
680  	
681  		/* WPA protos */
682  		svSetValue (ifcfg, "WPA_ALLOW_WPA", NULL, FALSE);
683  		svSetValue (ifcfg, "WPA_ALLOW_WPA2", NULL, FALSE);
684  		num = nm_setting_wireless_security_get_num_protos (s_wsec);
685  		for (i = 0; i < num; i++) {
686  			proto = nm_setting_wireless_security_get_proto (s_wsec, i);
687  			if (proto && !strcmp (proto, "wpa"))
688  				svSetValue (ifcfg, "WPA_ALLOW_WPA", "yes", FALSE);
689  			else if (proto && !strcmp (proto, "rsn"))
690  				svSetValue (ifcfg, "WPA_ALLOW_WPA2", "yes", FALSE);
691  		}
692  	
693  		/* WPA Pairwise ciphers */
694  		svSetValue (ifcfg, "CIPHER_PAIRWISE", NULL, FALSE);
695  		str = g_string_new (NULL);
696  		num = nm_setting_wireless_security_get_num_pairwise (s_wsec);
697  		for (i = 0; i < num; i++) {
698  			if (i > 0)
699  				g_string_append_c (str, ' ');
700  			cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i);
701  	
702  			/* Don't write out WEP40 or WEP104 if for some reason they are set; they
703  			 * are not valid pairwise ciphers.
704  			 */
705  			if (strcmp (cipher, "wep40") && strcmp (cipher, "wep104")) {
706  				tmp = g_ascii_strup (cipher, -1);
707  				g_string_append (str, tmp);
708  				g_free (tmp);
709  			}
710  		}
711  		if (strlen (str->str) && (dynamic_wep == FALSE))
712  			svSetValue (ifcfg, "CIPHER_PAIRWISE", str->str, FALSE);
713  		g_string_free (str, TRUE);
714  	
715  		/* WPA Group ciphers */
716  		svSetValue (ifcfg, "CIPHER_GROUP", NULL, FALSE);
717  		str = g_string_new (NULL);
718  		num = nm_setting_wireless_security_get_num_groups (s_wsec);
719  		for (i = 0; i < num; i++) {
720  			if (i > 0)
721  				g_string_append_c (str, ' ');
722  			cipher = nm_setting_wireless_security_get_group (s_wsec, i);
723  			tmp = g_ascii_strup (cipher, -1);
724  			g_string_append (str, tmp);
725  			g_free (tmp);
726  		}
727  		if (strlen (str->str) && (dynamic_wep == FALSE))
728  			svSetValue (ifcfg, "CIPHER_GROUP", str->str, FALSE);
729  		g_string_free (str, TRUE);
730  	
731  		/* WPA Passphrase */
732  		if (wpa) {
733  			char *quoted = NULL;
734  	
735  			psk = nm_setting_wireless_security_get_psk (s_wsec);
736  			if (psk && (strlen (psk) != 64)) {
737  				/* Quote the PSK since it's a passphrase */
738  				quoted = utils_single_quote_string (psk);
739  			}
740  			set_secret (ifcfg,
741  			            "WPA_PSK",
742  			            quoted ? quoted : psk,
743  			            "WPA_PSK_FLAGS",
744  			            nm_setting_wireless_security_get_psk_flags (s_wsec),
745  			            TRUE);
746  			g_free (quoted);
747  		} else {
748  			set_secret (ifcfg,
749  			            "WPA_PSK",
750  			            NULL,
751  			            "WPA_PSK_FLAGS",
752  			            NM_SETTING_SECRET_FLAG_NONE,
753  			            FALSE);
754  		}
755  	
756  		return TRUE;
757  	}
758  	
759  	static gboolean
760  	write_wireless_setting (NMConnection *connection,
761  	                        shvarFile *ifcfg,
762  	                        gboolean *no_8021x,
763  	                        GError **error)
764  	{
765  		NMSettingWireless *s_wireless;
766  		char *tmp, *tmp2;
767  		const GByteArray *ssid, *device_mac, *cloned_mac, *bssid;
768  		const char *mode;
769  		char buf[33];
770  		guint32 mtu, chan, i;
771  		gboolean adhoc = FALSE, hex_ssid = FALSE;
772  		const GSList *macaddr_blacklist;
773  	
774  		s_wireless = nm_connection_get_setting_wireless (connection);
775  		if (!s_wireless) {
776  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
777  			             "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
778  			return FALSE;
779  		}
780  	
781  		svSetValue (ifcfg, "HWADDR", NULL, FALSE);
782  		device_mac = nm_setting_wireless_get_mac_address (s_wireless);
783  		if (device_mac) {
784  			tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
785  			                       device_mac->data[0], device_mac->data[1], device_mac->data[2],
786  			                       device_mac->data[3], device_mac->data[4], device_mac->data[5]);
787  			svSetValue (ifcfg, "HWADDR", tmp, FALSE);
788  			g_free (tmp);
789  		}
790  	
791  		svSetValue (ifcfg, "MACADDR", NULL, FALSE);
792  		cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
793  		if (cloned_mac) {
794  			tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
795  			                       cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2],
796  			                       cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]);
797  			svSetValue (ifcfg, "MACADDR", tmp, FALSE);
798  			g_free (tmp);
799  		}
800  	
801  		svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
802  		macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
803  		if (macaddr_blacklist) {
804  			const GSList *iter;
805  			GString *blacklist_str = g_string_new (NULL);
806  	
807  			for (iter = macaddr_blacklist; iter; iter = g_slist_next (iter)) {
808  				g_string_append (blacklist_str, iter->data);
809  				g_string_append_c (blacklist_str, ' ');
810  	
811  			}
812  			if (blacklist_str->len > 0)
813  				g_string_truncate (blacklist_str, blacklist_str->len - 1);
814  			svSetValue (ifcfg, "HWADDR_BLACKLIST", blacklist_str->str, FALSE);
815  			g_string_free (blacklist_str, TRUE);
816  		}
817  	
818  		svSetValue (ifcfg, "MTU", NULL, FALSE);
819  		mtu = nm_setting_wireless_get_mtu (s_wireless);
820  		if (mtu) {
821  			tmp = g_strdup_printf ("%u", mtu);
822  			svSetValue (ifcfg, "MTU", tmp, FALSE);
823  			g_free (tmp);
824  		}
825  	
826  		ssid = nm_setting_wireless_get_ssid (s_wireless);
827  		if (!ssid) {
828  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
829  			             "Missing SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
830  			return FALSE;
831  		}
832  		if (!ssid->len || ssid->len > 32) {
833  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
834  			             "Invalid SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
835  			return FALSE;
836  		}
837  	
838  		/* If the SSID contains any non-printable characters, we need to use the
839  		 * hex notation of the SSID instead.
840  		 */
841  		for (i = 0; i < ssid->len; i++) {
842  			if (!g_ascii_isprint (ssid->data[i])) {
843  				hex_ssid = TRUE;
844  				break;
845  			}
846  		}
847  	
848  		if (hex_ssid) {
849  			GString *str;
850  	
851  			/* Hex SSIDs don't get quoted */
852  			str = g_string_sized_new (ssid->len * 2 + 3);
853  			g_string_append (str, "0x");
854  			for (i = 0; i < ssid->len; i++)
855  				g_string_append_printf (str, "%02X", ssid->data[i]);
856  			svSetValue (ifcfg, "ESSID", str->str, TRUE);
857  			g_string_free (str, TRUE);
858  		} else {
859  			/* Printable SSIDs always get quoted */
860  			memset (buf, 0, sizeof (buf));
861  			memcpy (buf, ssid->data, ssid->len);
862  			tmp = svEscape (buf);
863  	
864  			/* svEscape will usually quote the string, but just for consistency,
865  			 * if svEscape doesn't quote the ESSID, we quote it ourselves.
866  			 */
867  			if (tmp[0] != '"' && tmp[strlen (tmp) - 1] != '"') {
868  				tmp2 = g_strdup_printf ("\"%s\"", tmp);
869  				svSetValue (ifcfg, "ESSID", tmp2, TRUE);
870  				g_free (tmp2);
871  			} else
872  				svSetValue (ifcfg, "ESSID", tmp, TRUE);
873  			g_free (tmp);
874  		}
875  	
876  		mode = nm_setting_wireless_get_mode (s_wireless);
877  		if (!mode || !strcmp (mode, "infrastructure")) {
878  			svSetValue (ifcfg, "MODE", "Managed", FALSE);
879  		} else if (!strcmp (mode, "adhoc")) {
880  			svSetValue (ifcfg, "MODE", "Ad-Hoc", FALSE);
881  			adhoc = TRUE;
882  		} else {
883  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
884  			             "Invalid mode '%s' in '%s' setting",
885  			             mode, NM_SETTING_WIRELESS_SETTING_NAME);
886  			return FALSE;
887  		}
888  	
889  		svSetValue (ifcfg, "CHANNEL", NULL, FALSE);
890  		chan = nm_setting_wireless_get_channel (s_wireless);
891  		if (chan) {
892  			tmp = g_strdup_printf ("%u", chan);
893  			svSetValue (ifcfg, "CHANNEL", tmp, FALSE);
894  			g_free (tmp);
895  		}
896  	
897  		svSetValue (ifcfg, "BSSID", NULL, FALSE);
898  		bssid = nm_setting_wireless_get_bssid (s_wireless);
899  		if (bssid) {
900  			tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
901  			                       bssid->data[0], bssid->data[1], bssid->data[2],
902  			                       bssid->data[3], bssid->data[4], bssid->data[5]);
903  			svSetValue (ifcfg, "BSSID", tmp, FALSE);
904  			g_free (tmp);
905  		}
906  	
907  		/* Ensure DEFAULTKEY and SECURITYMODE are cleared unless there's security;
908  		 * otherwise there's no way to detect WEP vs. open when WEP keys aren't
909  		 * saved.
910  		 */
911  		svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE);
912  		svSetValue (ifcfg, "SECURITYMODE", NULL, FALSE);
913  	
914  		if (nm_connection_get_setting_wireless_security (connection)) {
915  			if (!write_wireless_security_setting (connection, ifcfg, adhoc, no_8021x, error))
916  				return FALSE;
917  		} else {
918  			char *keys_path;
919  	
920  			/* Clear out wifi security keys */
921  			svSetValue (ifcfg, "KEY_MGMT", NULL, FALSE);
922  			svSetValue (ifcfg, "IEEE_8021X_IDENTITY", NULL, FALSE);
923  			set_secret (ifcfg, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
924  			svSetValue (ifcfg, "SECURITYMODE", NULL, FALSE);
925  	
926  			/* Clear existing keys */
927  			set_secret (ifcfg, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
928  			for (i = 0; i < 4; i++) {
929  				tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1);
930  				set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
931  				g_free (tmp);
932  		
933  				tmp = g_strdup_printf ("KEY%d", i + 1);
934  				set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
935  				g_free (tmp);
936  			}
937  	
938  			svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE);
939  			svSetValue (ifcfg, "WPA_ALLOW_WPA", NULL, FALSE);
940  			svSetValue (ifcfg, "WPA_ALLOW_WPA2", NULL, FALSE);
941  			svSetValue (ifcfg, "CIPHER_PAIRWISE", NULL, FALSE);
942  			svSetValue (ifcfg, "CIPHER_GROUP", NULL, FALSE);
943  			set_secret (ifcfg, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE);
944  	
945  			/* Kill any old keys file */
946  			keys_path = utils_get_keys_path (ifcfg->fileName);
947  			(void) unlink (keys_path);
948  			g_free (keys_path);
949  		}
950  	
951  		svSetValue (ifcfg, "TYPE", TYPE_WIRELESS, FALSE);
952  	
953  		return TRUE;
954  	}
955  	
956  	static gboolean
957  	write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
958  	{
959  		NMSettingInfiniband *s_infiniband;
960  		const GByteArray *mac;
961  		char *tmp;
962  		const char *transport_mode, *parent;
963  		guint32 mtu;
964  		int p_key;
965  	
966  		s_infiniband = nm_connection_get_setting_infiniband (connection);
967  		if (!s_infiniband) {
968  			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
969  			             "Missing '%s' setting", NM_SETTING_INFINIBAND_SETTING_NAME);
970  			return FALSE;
971  		}
972  	
973  		svSetValue (ifcfg, "HWADDR", NULL, FALSE);
974  		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
975  		if (mac) {
976  			tmp = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
977  			svSetValue (ifcfg, "HWADDR", tmp, FALSE);
978  			g_free (tmp);
979  		}
980  	
981  		svSetValue (ifcfg, "MTU", NULL, FALSE);
982  		mtu = nm_setting_infiniband_get_mtu (s_infiniband);
983  		if (mtu) {
984  			tmp = g_strdup_printf ("%u", mtu);
985  			svSetValue (ifcfg, "MTU", tmp, FALSE);
986  			g_free (tmp);
987  		}
988  	
989  		transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
990  		svSetValue (ifcfg, "CONNECTED_MODE",
991  		            strcmp (transport_mode, "connected") == 0 ? "yes" : "no",
992  		            FALSE);
993  	
994  		p_key = nm_setting_infiniband_get_p_key (s_infiniband);
995  		if (p_key != -1) {
996  			svSetValue (ifcfg, "PKEY", "yes", FALSE);
997  			tmp = g_strdup_printf ("%u", p_key);
998  			svSetValue (ifcfg, "PKEY_ID", tmp, FALSE);
999  			g_free (tmp);
1000 	
1001 			parent = nm_setting_infiniband_get_parent (s_infiniband);
1002 			if (parent)
1003 				svSetValue (ifcfg, "PHYSDEV", parent, FALSE);
1004 		}
1005 	
1006 		svSetValue (ifcfg, "TYPE", TYPE_INFINIBAND, FALSE);
1007 	
1008 		return TRUE;
1009 	}
1010 	
1011 	static gboolean
1012 	write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1013 	{
1014 		NMSettingWired *s_wired;
1015 		const GByteArray *device_mac, *cloned_mac;
1016 		char *tmp;
1017 		const char *nettype, *portname, *ctcprot, *s390_key, *s390_val;
1018 		guint32 mtu, num_opts, i;
1019 		const GPtrArray *s390_subchannels;
1020 		GString *str;
1021 		const GSList *macaddr_blacklist;
1022 	
1023 		s_wired = nm_connection_get_setting_wired (connection);
1024 		if (!s_wired) {
1025 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1026 			             "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME);
1027 			return FALSE;
1028 		}
1029 	
1030 		svSetValue (ifcfg, "HWADDR", NULL, FALSE);
1031 		device_mac = nm_setting_wired_get_mac_address (s_wired);
1032 		if (device_mac) {
1033 			tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
1034 			                       device_mac->data[0], device_mac->data[1], device_mac->data[2],
1035 			                       device_mac->data[3], device_mac->data[4], device_mac->data[5]);
1036 			svSetValue (ifcfg, "HWADDR", tmp, FALSE);
1037 			g_free (tmp);
1038 		}
1039 	
1040 		svSetValue (ifcfg, "MACADDR", NULL, FALSE);
1041 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
1042 		if (cloned_mac) {
1043 			tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
1044 			                       cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2],
1045 			                       cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]);
1046 			svSetValue (ifcfg, "MACADDR", tmp, FALSE);
1047 			g_free (tmp);
1048 		}
1049 	
1050 		svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
1051 		macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
1052 		if (macaddr_blacklist) {
1053 			const GSList *iter;
1054 			GString *blacklist_str = g_string_new (NULL);
1055 	
1056 			for (iter = macaddr_blacklist; iter; iter = g_slist_next (iter)) {
1057 				g_string_append (blacklist_str, iter->data);
1058 				g_string_append_c (blacklist_str, ' ');
1059 	
1060 			}
1061 			if (blacklist_str->len > 0)
1062 				g_string_truncate (blacklist_str, blacklist_str->len - 1);
1063 			svSetValue (ifcfg, "HWADDR_BLACKLIST", blacklist_str->str, FALSE);
1064 			g_string_free (blacklist_str, TRUE);
1065 		}
1066 	
1067 		svSetValue (ifcfg, "MTU", NULL, FALSE);
1068 		mtu = nm_setting_wired_get_mtu (s_wired);
1069 		if (mtu) {
1070 			tmp = g_strdup_printf ("%u", mtu);
1071 			svSetValue (ifcfg, "MTU", tmp, FALSE);
1072 			g_free (tmp);
1073 		}
1074 	
1075 		svSetValue (ifcfg, "SUBCHANNELS", NULL, FALSE);
1076 		s390_subchannels = nm_setting_wired_get_s390_subchannels (s_wired);
1077 		if (s390_subchannels) {
1078 			tmp = NULL;
1079 		    if (s390_subchannels->len == 2) {
1080 				tmp = g_strdup_printf ("%s,%s",
1081 					                   (const char *) g_ptr_array_index (s390_subchannels, 0),
1082 					                   (const char *) g_ptr_array_index (s390_subchannels, 1));
1083 		    } else if (s390_subchannels->len == 3) {
1084 				tmp = g_strdup_printf ("%s,%s,%s",
1085 					                   (const char *) g_ptr_array_index (s390_subchannels, 0),
1086 					                   (const char *) g_ptr_array_index (s390_subchannels, 1),
1087 					                   (const char *) g_ptr_array_index (s390_subchannels, 2));
1088 			}
1089 			svSetValue (ifcfg, "SUBCHANNELS", tmp, FALSE);
1090 			g_free (tmp);
1091 		}
1092 	
1093 		svSetValue (ifcfg, "NETTYPE", NULL, FALSE);
1094 		nettype = nm_setting_wired_get_s390_nettype (s_wired);
1095 		if (nettype)
1096 			svSetValue (ifcfg, "NETTYPE", nettype, FALSE);
1097 	
1098 		svSetValue (ifcfg, "PORTNAME", NULL, FALSE);
1099 		portname = nm_setting_wired_get_s390_option_by_key (s_wired, "portname");
1100 		if (portname)
1101 			svSetValue (ifcfg, "PORTNAME", portname, FALSE);
1102 	
1103 		svSetValue (ifcfg, "CTCPROT", NULL, FALSE);
1104 		ctcprot = nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot");
1105 		if (ctcprot)
1106 			svSetValue (ifcfg, "CTCPROT", ctcprot, FALSE);
1107 	
1108 		svSetValue (ifcfg, "OPTIONS", NULL, FALSE);
1109 		num_opts = nm_setting_wired_get_num_s390_options (s_wired);
1110 		if (s390_subchannels && num_opts) {
1111 			str = g_string_sized_new (30);
1112 			for (i = 0; i < num_opts; i++) {
1113 				nm_setting_wired_get_s390_option (s_wired, i, &s390_key, &s390_val);
1114 	
1115 				/* portname is handled separately */
1116 				if (!strcmp (s390_key, "portname") || !strcmp (s390_key, "ctcprot"))
1117 					continue;
1118 	
1119 				if (str->len)
1120 					g_string_append_c (str, ' ');
1121 				g_string_append_printf (str, "%s=%s", s390_key, s390_val);
1122 			}
1123 			if (str->len)
1124 				svSetValue (ifcfg, "OPTIONS", str->str, FALSE);
1125 			g_string_free (str, TRUE);
1126 		}
1127 	
1128 		svSetValue (ifcfg, "TYPE", TYPE_ETHERNET, FALSE);
1129 	
1130 		return TRUE;
1131 	}
1132 	
1133 	static GString *
1134 	vlan_priority_maplist_to_stringlist (NMSettingVlan *s_vlan, NMVlanPriorityMap map)
1135 	{
1136 		GSList *strlist = NULL, *iter;
1137 		GString *value = NULL;
1138 	
1139 		if (map == NM_VLAN_INGRESS_MAP)
1140 			g_object_get (G_OBJECT (s_vlan), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, &strlist, NULL);
1141 		else if (map == NM_VLAN_EGRESS_MAP)
1142 			g_object_get (G_OBJECT (s_vlan), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, &strlist, NULL);
1143 		else
1144 			return NULL;
1145 	
1146 		value = g_string_new ("");
1147 		for (iter = strlist; iter; iter = g_slist_next (iter))
1148 			g_string_append_printf (value, "%s%s", value->len ? "," : "", (const char *) iter->data);
1149 	
1150 		g_slist_free_full (strlist, g_free);
1151 	
1152 		return value;
1153 	}
1154 	
1155 	static gboolean
1156 	write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, GError **error)
1157 	{
1158 		NMSettingVlan *s_vlan;
1159 		NMSettingConnection *s_con;
1160 		NMSettingWired *s_wired;
1161 		char *tmp;
1162 		guint32 vlan_flags = 0;
1163 		GString *text = NULL;
1164 	
1165 		s_con = nm_connection_get_setting_connection (connection);
1166 		if (!s_con) {
1167 			g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "Missing connection setting");
1168 			return FALSE;
1169 		}
1170 	
1171 		s_vlan = nm_connection_get_setting_vlan (connection);
1172 		if (!s_vlan) {
1173 			g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "Missing VLAN setting");
1174 			return FALSE;
1175 		}
1176 	
1177 		svSetValue (ifcfg, "VLAN", "yes", FALSE);
1178 		svSetValue (ifcfg, "TYPE", TYPE_VLAN, FALSE);
1179 		svSetValue (ifcfg, "DEVICE", nm_setting_vlan_get_interface_name (s_vlan), FALSE);
1180 		svSetValue (ifcfg, "PHYSDEV", nm_setting_vlan_get_parent (s_vlan), FALSE);
1181 		svSetValue (ifcfg, "MASTER", nm_setting_connection_get_master (s_con), FALSE);
1182 	
1183 		tmp = g_strdup_printf ("%d", nm_setting_vlan_get_id (s_vlan));
1184 		svSetValue (ifcfg, "VLAN_ID", tmp, FALSE);
1185 		g_free (tmp);
1186 	
1187 		vlan_flags = nm_setting_vlan_get_flags (s_vlan);
1188 		if (vlan_flags & NM_VLAN_FLAG_REORDER_HEADERS)
1189 			svSetValue (ifcfg, "REORDER_HDR", "1", FALSE);
1190 		else
1191 			svSetValue (ifcfg, "REORDER_HDR", "0", FALSE);
1192 	
1193 		svSetValue (ifcfg, "VLAN_FLAGS", NULL, FALSE);
1194 		if (vlan_flags & NM_VLAN_FLAG_GVRP) {
1195 			if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING)
1196 				svSetValue (ifcfg, "VLAN_FLAGS", "GVRP,LOOSE_BINDING", FALSE);
1197 			else
1198 				svSetValue (ifcfg, "VLAN_FLAGS", "GVRP", FALSE);
1199 		} else if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING)
1200 			svSetValue (ifcfg, "VLAN_FLAGS", "LOOSE_BINDING", FALSE);
1201 	
1202 		text = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_INGRESS_MAP);
1203 		svSetValue (ifcfg, "VLAN_INGRESS_PRIORITY_MAP", text ? text->str : NULL, FALSE);
1204 		if (text)
1205 			g_string_free (text, TRUE);
1206 	
1207 		text = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_EGRESS_MAP);
1208 		svSetValue (ifcfg, "VLAN_EGRESS_PRIORITY_MAP", text ? text->str : NULL, FALSE);
1209 		if (text)
1210 			g_string_free (text, TRUE);
1211 	
1212 		svSetValue (ifcfg, "HWADDR", NULL, FALSE);
1213 		svSetValue (ifcfg, "MACADDR", NULL, FALSE);
1214 		svSetValue (ifcfg, "MTU", NULL, FALSE);
1215 	
1216 		s_wired = nm_connection_get_setting_wired (connection);
1217 		if (s_wired) {
1218 			const GByteArray *device_mac, *cloned_mac;
1219 			guint32 mtu;
1220 	
1221 			*wired = TRUE;
1222 	
1223 			device_mac = nm_setting_wired_get_mac_address (s_wired);
1224 			if (device_mac) {
1225 				tmp = nm_utils_hwaddr_ntoa (device_mac->data, ARPHRD_ETHER);
1226 				svSetValue (ifcfg, "HWADDR", tmp, FALSE);
1227 				g_free (tmp);
1228 			}
1229 	
1230 			cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
1231 			if (cloned_mac) {
1232 				tmp = nm_utils_hwaddr_ntoa (cloned_mac->data, ARPHRD_ETHER);
1233 				svSetValue (ifcfg, "MACADDR", tmp, FALSE);
1234 				g_free (tmp);
1235 			}
1236 	
1237 			mtu = nm_setting_wired_get_mtu (s_wired);
1238 			if (mtu) {
1239 				tmp = g_strdup_printf ("%u", mtu);
1240 				svSetValue (ifcfg, "MTU", tmp, FALSE);
1241 				g_free (tmp);
1242 			}
1243 		}
1244 	
1245 		return TRUE;
1246 	}
1247 	
1248 	static gboolean
1249 	write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1250 	{
1251 		NMSettingBond *s_bond;
1252 		const char *iface;
1253 		guint32 i, num_opts;
1254 	
1255 		s_bond = nm_connection_get_setting_bond (connection);
1256 		if (!s_bond) {
1257 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1258 			             "Missing '%s' setting", NM_SETTING_BOND_SETTING_NAME);
1259 			return FALSE;
1260 		}
1261 	
1262 		iface = nm_setting_bond_get_interface_name (s_bond);
1263 		if (!iface) {
1264 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing interface name");
1265 			return FALSE;
1266 		}
1267 	
1268 		svSetValue (ifcfg, "DEVICE", iface, FALSE);
1269 		svSetValue (ifcfg, "BONDING_OPTS", NULL, FALSE);
1270 	
1271 		num_opts = nm_setting_bond_get_num_options (s_bond);
1272 		if (num_opts > 0) {
1273 			GString *str = g_string_sized_new (64);
1274 	
1275 			for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
1276 				const char *key, *value;
1277 	
1278 				if (!nm_setting_bond_get_option (s_bond, i, &key, &value))
1279 					continue;
1280 	
1281 				if (str->len)
1282 					g_string_append_c (str, ' ');
1283 	
1284 				g_string_append_printf (str, "%s=%s", key, value);
1285 			}
1286 	
1287 			if (str->len)
1288 				svSetValue (ifcfg, "BONDING_OPTS", str->str, FALSE);
1289 	
1290 			g_string_free (str, TRUE);
1291 		}
1292 	
1293 		svSetValue (ifcfg, "TYPE", TYPE_BOND, FALSE);
1294 		svSetValue (ifcfg, "BONDING_MASTER", "yes", FALSE);
1295 	
1296 		return TRUE;
1297 	}
1298 	
1299 	static gboolean
1300 	write_team_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1301 	{
1302 		NMSettingTeam *s_team;
1303 		const char *iface;
1304 		const char *config;
1305 	
1306 		s_team = nm_connection_get_setting_team (connection);
1307 		if (!s_team) {
1308 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1309 			             "Missing '%s' setting", NM_SETTING_TEAM_SETTING_NAME);
1310 			return FALSE;
1311 		}
1312 	
1313 		iface = nm_setting_team_get_interface_name (s_team);
1314 		if (!iface) {
1315 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing interface name");
1316 			return FALSE;
1317 		}
1318 	
1319 		svSetValue (ifcfg, "DEVICE", iface, FALSE);
1320 		config = nm_setting_team_get_config (s_team);
1321 		svSetValue (ifcfg, "TEAM_CONFIG", config, FALSE);
1322 		svSetValue (ifcfg, "DEVICETYPE", TYPE_TEAM, FALSE);
1323 	
1324 		return TRUE;
1325 	}
1326 	
1327 	static guint32
1328 	get_setting_default (NMSetting *setting, const char *prop)
1329 	{
1330 		GParamSpec *pspec;
1331 		GValue val = G_VALUE_INIT;
1332 		guint32 ret = 0;
1333 	
1334 		pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop);
1335 		g_assert (pspec);
1336 		g_value_init (&val, pspec->value_type);
1337 		g_param_value_set_default (pspec, &val);
1338 		g_assert (G_VALUE_HOLDS_UINT (&val));
1339 		ret = g_value_get_uint (&val);
1340 		g_value_unset (&val);
1341 		return ret;
1342 	}
1343 	
1344 	static gboolean
1345 	write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1346 	{
1347 		NMSettingBridge *s_bridge;
1348 		const char *iface;
1349 		guint32 i;
1350 		GString *opts;
1351 		char *s;
1352 	
1353 		s_bridge = nm_connection_get_setting_bridge (connection);
1354 		if (!s_bridge) {
1355 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1356 			             "Missing '%s' setting", NM_SETTING_BRIDGE_SETTING_NAME);
1357 			return FALSE;
1358 		}
1359 	
1360 		iface = nm_setting_bridge_get_interface_name (s_bridge);
1361 		if (!iface) {
1362 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing interface name");
1363 			return FALSE;
1364 		}
1365 	
1366 		svSetValue (ifcfg, "DEVICE", iface, FALSE);
1367 		svSetValue (ifcfg, "BRIDGING_OPTS", NULL, FALSE);
1368 		svSetValue (ifcfg, "STP", "no", FALSE);
1369 		svSetValue (ifcfg, "DELAY", NULL, FALSE);
1370 	
1371 		/* Bridge options */
1372 		opts = g_string_sized_new (32);
1373 	
1374 		if (nm_setting_bridge_get_stp (s_bridge)) {
1375 			svSetValue (ifcfg, "STP", "yes", FALSE);
1376 	
1377 			i = nm_setting_bridge_get_forward_delay (s_bridge);
1378 			if (i && i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY)) {
1379 				s = g_strdup_printf ("%u", i);
1380 				svSetValue (ifcfg, "DELAY", s, FALSE);
1381 				g_free (s);
1382 			}
1383 	
1384 			g_string_append_printf (opts, "priority=%u", nm_setting_bridge_get_priority (s_bridge));
1385 	
1386 			i = nm_setting_bridge_get_hello_time (s_bridge);
1387 			if (i && i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME)) {
1388 				if (opts->len)
1389 					g_string_append_c (opts, ' ');
1390 				g_string_append_printf (opts, "hello_time=%u", i);
1391 			}
1392 	
1393 			i = nm_setting_bridge_get_max_age (s_bridge);
1394 			if (i && i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MAX_AGE)) {
1395 				if (opts->len)
1396 					g_string_append_c (opts, ' ');
1397 				g_string_append_printf (opts, "max_age=%u", i);
1398 			}
1399 		}
1400 	
1401 		i = nm_setting_bridge_get_ageing_time (s_bridge);
1402 		if (i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME)) {
1403 			if (opts->len)
1404 				g_string_append_c (opts, ' ');
1405 			g_string_append_printf (opts, "ageing_time=%u", i);
1406 		}
1407 	
1408 		if (opts->len)
1409 			svSetValue (ifcfg, "BRIDGING_OPTS", opts->str, FALSE);
1410 		g_string_free (opts, TRUE);
1411 	
1412 		svSetValue (ifcfg, "TYPE", TYPE_BRIDGE, FALSE);
1413 	
1414 		return TRUE;
1415 	}
1416 	
1417 	static gboolean
1418 	write_bridge_port_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1419 	{
1420 		NMSettingBridgePort *s_port;
1421 		guint32 i;
1422 		GString *opts;
1423 	
1424 		s_port = nm_connection_get_setting_bridge_port (connection);
1425 		if (!s_port)
1426 			return TRUE;
1427 	
1428 		svSetValue (ifcfg, "BRIDGING_OPTS", NULL, FALSE);
1429 	
1430 		/* Bridge options */
1431 		opts = g_string_sized_new (32);
1432 	
1433 		i = nm_setting_bridge_port_get_priority (s_port);
1434 		if (i && i != get_setting_default (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY))
1435 			g_string_append_printf (opts, "priority=%u", i);
1436 	
1437 		i = nm_setting_bridge_port_get_path_cost (s_port);
1438 		if (i && i != get_setting_default (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST)) {
1439 			if (opts->len)
1440 				g_string_append_c (opts, ' ');
1441 			g_string_append_printf (opts, "path_cost=%u", i);
1442 		}
1443 	
1444 		if (nm_setting_bridge_port_get_hairpin_mode (s_port)) {
1445 			if (opts->len)
1446 				g_string_append_c (opts, ' ');
1447 			g_string_append_printf (opts, "hairpin_mode=1");
1448 		}
1449 	
1450 		if (opts->len)
1451 			svSetValue (ifcfg, "BRIDGING_OPTS", opts->str, FALSE);
1452 		g_string_free (opts, TRUE);
1453 	
1454 		return TRUE;
1455 	}
1456 	
1457 	static gboolean
1458 	write_team_port_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1459 	{
1460 		NMSettingTeamPort *s_port;
1461 		const char *config;
1462 	
1463 		s_port = nm_connection_get_setting_team_port (connection);
1464 		if (!s_port)
1465 			return TRUE;
1466 	
1467 		config = nm_setting_team_port_get_config (s_port);
1468 		svSetValue (ifcfg, "TEAM_PORT_CONFIG", config, FALSE);
1469 	
1470 		return TRUE;
1471 	}
1472 	
1473 	static void
1474 	write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
1475 	{
1476 		guint32 n, i;
1477 		GString *str;
1478 		const char *master;
1479 		char *tmp;
1480 	
1481 		svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE);
1482 		svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE);
1483 		svSetValue (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con), FALSE);
1484 		svSetValue (ifcfg, "ONBOOT",
1485 		            nm_setting_connection_get_autoconnect (s_con) ? "yes" : "no",
1486 		            FALSE);
1487 	
1488 		/* Permissions */
1489 		svSetValue (ifcfg, "USERS", NULL, FALSE);
1490 		n = nm_setting_connection_get_num_permissions (s_con);
1491 		if (n > 0) {
1492 			str = g_string_sized_new (n * 20);
1493 	
1494 			for (i = 0; i < n; i++) {
1495 				const char *puser = NULL;
1496 	
1497 				/* Items separated by space for consistency with eg
1498 				 * IPV6ADDR_SECONDARIES and DOMAIN.
1499 				 */
1500 				if (str->len)
1501 					g_string_append_c (str, ' ');
1502 	
(10) Event example_checked: Example5: "nm_setting_connection_get_permission(s_con, i, NULL, &puser, NULL)" has its value checked in "nm_setting_connection_get_permission(s_con, i, NULL, &puser, NULL)".
Also see events: [check_return][example_assign][example_checked][example_checked][example_assign][example_checked][example_assign][example_checked][unchecked_value]
1503 				if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL))
1504 					g_string_append (str, puser);
1505 			}
1506 			svSetValue (ifcfg, "USERS", str->str, FALSE);
1507 			g_string_free (str, TRUE);
1508 		}
1509 	
1510 		svSetValue (ifcfg, "ZONE", nm_setting_connection_get_zone(s_con), FALSE);
1511 	
1512 		master = nm_setting_connection_get_master (s_con);
1513 		if (master) {
1514 			if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME))
1515 				svSetValue (ifcfg, "MASTER", master, FALSE);
1516 			else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME))
1517 				svSetValue (ifcfg, "BRIDGE", master, FALSE);
1518 			else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) {
1519 				svSetValue (ifcfg, "TEAM_MASTER", master, FALSE);
1520 				svSetValue (ifcfg, "DEVICETYPE", TYPE_TEAM_PORT, FALSE);
1521 			}
1522 		}
1523 	
1524 		/* secondary connection UUIDs */
1525 		svSetValue (ifcfg, "SECONDARY_UUIDS", NULL, FALSE);
1526 		n = nm_setting_connection_get_num_secondaries (s_con);
1527 		if (n > 0) {
1528 			str = g_string_sized_new (n * 37);
1529 	
1530 			for (i = 0; i < n; i++) {
1531 				const char *uuid;
1532 	
1533 				/* Items separated by space for consistency with eg
1534 				 * IPV6ADDR_SECONDARIES and DOMAIN.
1535 				 */
1536 				if (str->len)
1537 					g_string_append_c (str, ' ');
1538 	
1539 				if ((uuid = nm_setting_connection_get_secondary (s_con, i)) != NULL)
1540 					g_string_append (str, uuid);
1541 			}
1542 			svSetValue (ifcfg, "SECONDARY_UUIDS", str->str, FALSE);
1543 			g_string_free (str, TRUE);
1544 		}
1545 	
1546 		svSetValue (ifcfg, "GATEWAY_PING_TIMEOUT", NULL, FALSE);
1547 		if (nm_setting_connection_get_gateway_ping_timeout (s_con)) {
1548 			tmp = g_strdup_printf ("%" G_GUINT32_FORMAT, nm_setting_connection_get_gateway_ping_timeout (s_con));
1549 			svSetValue (ifcfg, "GATEWAY_PING_TIMEOUT", tmp, FALSE);
1550 			g_free (tmp);
1551 		}
1552 	}
1553 	
1554 	static gboolean
1555 	write_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError **error)
1556 	{
1557 		char dest[INET_ADDRSTRLEN];
1558 		char next_hop[INET_ADDRSTRLEN];
1559 		char **route_items;
1560 		char *route_contents;
1561 		NMIP4Route *route;
1562 		guint32 ip, prefix, metric;
1563 		guint32 i, num;
1564 		gboolean success = FALSE;
1565 	
1566 		g_return_val_if_fail (filename != NULL, FALSE);
1567 		g_return_val_if_fail (s_ip4 != NULL, FALSE);
1568 		g_return_val_if_fail (error != NULL, FALSE);
1569 		g_return_val_if_fail (*error == NULL, FALSE);
1570 	
1571 		num = nm_setting_ip4_config_get_num_routes (s_ip4);
1572 		if (num == 0) {
1573 			unlink (filename);
1574 			return TRUE;
1575 		}
1576 	
1577 		route_items = g_malloc0 (sizeof (char*) * (num + 1));
1578 		for (i = 0; i < num; i++) {
1579 			route = nm_setting_ip4_config_get_route (s_ip4, i);
1580 	
1581 			memset (dest, 0, sizeof (dest));
1582 			ip = nm_ip4_route_get_dest (route);
1583 			inet_ntop (AF_INET, (const void *) &ip, &dest[0], sizeof (dest));
1584 	
1585 			prefix = nm_ip4_route_get_prefix (route);
1586 	
1587 			memset (next_hop, 0, sizeof (next_hop));
1588 			ip = nm_ip4_route_get_next_hop (route);
1589 			inet_ntop (AF_INET, (const void *) &ip, &next_hop[0], sizeof (next_hop));
1590 	
1591 			metric = nm_ip4_route_get_metric (route);
1592 	
1593 			route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, metric);
1594 		}
1595 		route_items[num] = NULL;
1596 		route_contents = g_strjoinv (NULL, route_items);
1597 		g_strfreev (route_items);
1598 	
1599 		if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
1600 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1601 			             "Writing route file '%s' failed", filename);
1602 			goto error;
1603 		}
1604 	
1605 		success = TRUE;
1606 	
1607 	error:
1608 		g_free (route_contents);
1609 	
1610 		return success;
1611 	}
1612 	
1613 	static gboolean
1614 	write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1615 	{
1616 		NMSettingIP4Config *s_ip4;
1617 		const char *value;
1618 		char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *tmp;
1619 		char *route_path = NULL;
1620 		gint32 j;
1621 		guint32 i, num;
1622 		GString *searches;
1623 		gboolean success = FALSE;
1624 		gboolean fake_ip4 = FALSE;
1625 		const char *method = NULL;
1626 	
1627 		s_ip4 = nm_connection_get_setting_ip4_config (connection);
1628 		if (s_ip4)
1629 			method = nm_setting_ip4_config_get_method (s_ip4);
1630 	
1631 		/* Missing IP4 setting is assumed to be DHCP */
1632 		if (!method)
1633 			method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
1634 	
1635 		if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
1636 			int result;
1637 	
1638 			/* IPv4 disabled, clear IPv4 related parameters */
1639 			svSetValue (ifcfg, "BOOTPROTO", NULL, FALSE);
1640 			for (j = -1; j < 256; j++) {
1641 				if (j == -1) {
1642 					addr_key = g_strdup ("IPADDR");
1643 					prefix_key = g_strdup ("PREFIX");
1644 					netmask_key = g_strdup ("NETMASK");
1645 					gw_key = g_strdup ("GATEWAY");
1646 				} else {
1647 					addr_key = g_strdup_printf ("IPADDR%d", j);
1648 					prefix_key = g_strdup_printf ("PREFIX%d", j);
1649 					netmask_key = g_strdup_printf ("NETMASK%d", j);
1650 					gw_key = g_strdup_printf ("GATEWAY%d", j);
1651 				}
1652 	
1653 				svSetValue (ifcfg, addr_key, NULL, FALSE);
1654 				svSetValue (ifcfg, prefix_key, NULL, FALSE);
1655 				svSetValue (ifcfg, netmask_key, NULL, FALSE);
1656 				svSetValue (ifcfg, gw_key, NULL, FALSE);
1657 	
1658 				g_free (addr_key);
1659 				g_free (prefix_key);
1660 				g_free (netmask_key);
1661 				g_free (gw_key);
1662 			}
1663 	
1664 			route_path = utils_get_route_path (ifcfg->fileName);
1665 			result = unlink (route_path);
1666 			g_free (route_path);
1667 			return TRUE;
1668 		}
1669 	
1670 		/* Temporarily create fake IP4 setting if missing; method set to DHCP above */
1671 		if (!s_ip4) {
1672 			s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
1673 			fake_ip4 = TRUE;
1674 		}
1675 	
1676 		if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
1677 			svSetValue (ifcfg, "BOOTPROTO", "dhcp", FALSE);
1678 		else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
1679 			svSetValue (ifcfg, "BOOTPROTO", "none", FALSE);
1680 		else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
1681 			svSetValue (ifcfg, "BOOTPROTO", "autoip", FALSE);
1682 		else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
1683 			svSetValue (ifcfg, "BOOTPROTO", "shared", FALSE);
1684 	
1685 		/* Write out IPADDR0 .. IPADDR255, PREFIX0 .. PREFIX255, GATEWAY0 .. GATEWAY255
1686 		 * Possible NETMASK<n> is removed only (it's obsolete) */
1687 		num = nm_setting_ip4_config_get_num_addresses (s_ip4);
1688 		svSetValue (ifcfg, "IPADDR", NULL, FALSE);
1689 		svSetValue (ifcfg, "PREFIX", NULL, FALSE);
1690 		svSetValue (ifcfg, "NETMASK", NULL, FALSE);
1691 		svSetValue (ifcfg, "GATEWAY", NULL, FALSE);
1692 		for (i = 0; i < 256; i++) {
1693 			char buf[INET_ADDRSTRLEN];
1694 			NMIP4Address *addr;
1695 			guint32 ip;
1696 	
1697 			addr_key = g_strdup_printf ("IPADDR%d", i);
1698 			prefix_key = g_strdup_printf ("PREFIX%d", i);
1699 			netmask_key = g_strdup_printf ("NETMASK%d", i);
1700 			gw_key = g_strdup_printf ("GATEWAY%d", i);
1701 	
1702 			if (i >= num) {
1703 				svSetValue (ifcfg, addr_key, NULL, FALSE);
1704 				svSetValue (ifcfg, prefix_key, NULL, FALSE);
1705 				svSetValue (ifcfg, netmask_key, NULL, FALSE);
1706 				svSetValue (ifcfg, gw_key, NULL, FALSE);
1707 			} else {
1708 				addr = nm_setting_ip4_config_get_address (s_ip4, i);
1709 	
1710 				memset (buf, 0, sizeof (buf));
1711 				ip = nm_ip4_address_get_address (addr);
1712 				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1713 				svSetValue (ifcfg, addr_key, &buf[0], FALSE);
1714 	
1715 				tmp = g_strdup_printf ("%u", nm_ip4_address_get_prefix (addr));
1716 				svSetValue (ifcfg, prefix_key, tmp, FALSE);
1717 				g_free (tmp);
1718 	
1719 				if (nm_ip4_address_get_gateway (addr)) {
1720 					memset (buf, 0, sizeof (buf));
1721 					ip = nm_ip4_address_get_gateway (addr);
1722 					inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1723 					svSetValue (ifcfg, gw_key, &buf[0], FALSE);
1724 				} else
1725 					svSetValue (ifcfg, gw_key, NULL, FALSE);
1726 			}
1727 	
1728 			g_free (addr_key);
1729 			g_free (prefix_key);
1730 			g_free (netmask_key);
1731 			g_free (gw_key);
1732 		}
1733 	
1734 		num = nm_setting_ip4_config_get_num_dns (s_ip4);
1735 		for (i = 0; i < 254; i++) {
1736 			char buf[INET_ADDRSTRLEN + 1];
1737 			guint32 ip;
1738 	
1739 			addr_key = g_strdup_printf ("DNS%d", i + 1);
1740 	
1741 			if (i >= num)
1742 				svSetValue (ifcfg, addr_key, NULL, FALSE);
1743 			else {
1744 				ip = nm_setting_ip4_config_get_dns (s_ip4, i);
1745 	
1746 				memset (buf, 0, sizeof (buf));
1747 				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1748 				svSetValue (ifcfg, addr_key, &buf[0], FALSE);
1749 			}
1750 			g_free (addr_key);
1751 		}
1752 	
1753 		num = nm_setting_ip4_config_get_num_dns_searches (s_ip4);
1754 		if (num > 0) {
1755 			searches = g_string_new (NULL);
1756 			for (i = 0; i < num; i++) {
1757 				if (i > 0)
1758 					g_string_append_c (searches, ' ');
1759 				g_string_append (searches, nm_setting_ip4_config_get_dns_search (s_ip4, i));
1760 			}
1761 			svSetValue (ifcfg, "DOMAIN", searches->str, FALSE);
1762 			g_string_free (searches, TRUE);
1763 		} else
1764 			svSetValue (ifcfg, "DOMAIN", NULL, FALSE);
1765 	
1766 		/* DEFROUTE; remember that it has the opposite meaning from never-default */
1767 		svSetValue (ifcfg, "DEFROUTE",
1768 		            nm_setting_ip4_config_get_never_default (s_ip4) ? "no" : "yes",
1769 		            FALSE);
1770 	
1771 		svSetValue (ifcfg, "PEERDNS", NULL, FALSE);
1772 		svSetValue (ifcfg, "PEERROUTES", NULL, FALSE);
1773 		svSetValue (ifcfg, "DHCP_CLIENT_ID", NULL, FALSE);
1774 		if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
1775 			svSetValue (ifcfg, "PEERDNS",
1776 			            nm_setting_ip4_config_get_ignore_auto_dns (s_ip4) ? "no" : "yes",
1777 			            FALSE);
1778 	
1779 			svSetValue (ifcfg, "PEERROUTES",
1780 			            nm_setting_ip4_config_get_ignore_auto_routes (s_ip4) ? "no" : "yes",
1781 			            FALSE);
1782 	
1783 			value = nm_setting_ip4_config_get_dhcp_hostname (s_ip4);
1784 			if (value)
1785 				svSetValue (ifcfg, "DHCP_HOSTNAME", value, FALSE);
1786 	
1787 			value = nm_setting_ip4_config_get_dhcp_client_id (s_ip4);
1788 			if (value)
1789 				svSetValue (ifcfg, "DHCP_CLIENT_ID", value, FALSE);
1790 		}
1791 	
1792 		svSetValue (ifcfg, "IPV4_FAILURE_FATAL",
1793 		            nm_setting_ip4_config_get_may_fail (s_ip4) ? "no" : "yes",
1794 		            FALSE);
1795 	
1796 		/* Static routes - route-<name> file */
1797 		route_path = utils_get_route_path (ifcfg->fileName);
1798 		if (!route_path) {
1799 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1800 			             "Could not get route file path for '%s'", ifcfg->fileName);
1801 			goto out;
1802 		}
1803 	
1804 		if (utils_has_route_file_new_syntax (route_path)) {
1805 			shvarFile *routefile;
1806 	
1807 			routefile = utils_get_route_ifcfg (ifcfg->fileName, TRUE);
1808 			if (!routefile) {
1809 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1810 				             "Could not create route file '%s'", route_path);
1811 				g_free (route_path);
1812 				goto out;
1813 			}
1814 			g_free (route_path);
1815 	
1816 			num = nm_setting_ip4_config_get_num_routes (s_ip4);
1817 			for (i = 0; i < 256; i++) {
1818 				char buf[INET_ADDRSTRLEN];
1819 				NMIP4Route *route;
1820 				guint32 ip, metric;
1821 	
1822 				addr_key = g_strdup_printf ("ADDRESS%d", i);
1823 				netmask_key = g_strdup_printf ("NETMASK%d", i);
1824 				gw_key = g_strdup_printf ("GATEWAY%d", i);
1825 				metric_key = g_strdup_printf ("METRIC%d", i);
1826 	
1827 				if (i >= num) {
1828 					svSetValue (routefile, addr_key, NULL, FALSE);
1829 					svSetValue (routefile, netmask_key, NULL, FALSE);
1830 					svSetValue (routefile, gw_key, NULL, FALSE);
1831 					svSetValue (routefile, metric_key, NULL, FALSE);
1832 				} else {
1833 					route = nm_setting_ip4_config_get_route (s_ip4, i);
1834 	
1835 					memset (buf, 0, sizeof (buf));
1836 					ip = nm_ip4_route_get_dest (route);
1837 					inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1838 					svSetValue (routefile, addr_key, &buf[0], FALSE);
1839 	
1840 					memset (buf, 0, sizeof (buf));
1841 					ip = nm_utils_ip4_prefix_to_netmask (nm_ip4_route_get_prefix (route));
1842 					inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1843 					svSetValue (routefile, netmask_key, &buf[0], FALSE);
1844 	
1845 					memset (buf, 0, sizeof (buf));
1846 					ip = nm_ip4_route_get_next_hop (route);
1847 					inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
1848 					svSetValue (routefile, gw_key, &buf[0], FALSE);
1849 	
1850 					memset (buf, 0, sizeof (buf));
1851 					metric = nm_ip4_route_get_metric (route);
1852 					if (metric == 0)
1853 						svSetValue (routefile, metric_key, NULL, FALSE);
1854 					else {
1855 						tmp = g_strdup_printf ("%u", metric);
1856 						svSetValue (routefile, metric_key, tmp, FALSE);
1857 						g_free (tmp);
1858 					}
1859 				}
1860 	
1861 				g_free (addr_key);
1862 				g_free (netmask_key);
1863 				g_free (gw_key);
1864 				g_free (metric_key);
1865 			}
1866 			if (svWriteFile (routefile, 0644)) {
1867 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1868 				             "Could not update route file '%s'", routefile->fileName);
1869 				svCloseFile (routefile);
1870 				goto out;
1871 			}
1872 			svCloseFile (routefile);
1873 		} else {
1874 			write_route_file_legacy (route_path, s_ip4, error);
1875 			g_free (route_path);
1876 			if (error && *error)
1877 				goto out;
1878 		}
1879 	
1880 		success = TRUE;
1881 	
1882 	out:
1883 		if (fake_ip4)
1884 			g_object_unref (s_ip4);
1885 	
1886 		return success;
1887 	}
1888 	
1889 	static gboolean
1890 	write_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **error)
1891 	{
1892 		char dest[INET6_ADDRSTRLEN];
1893 		char next_hop[INET6_ADDRSTRLEN];
1894 		char **route_items;
1895 		char *route_contents;
1896 		NMIP6Route *route;
1897 		const struct in6_addr *ip;
1898 		guint32 prefix, metric;
1899 		guint32 i, num;
1900 		gboolean success = FALSE;
1901 	
1902 		g_return_val_if_fail (filename != NULL, FALSE);
1903 		g_return_val_if_fail (s_ip6 != NULL, FALSE);
1904 		g_return_val_if_fail (error != NULL, FALSE);
1905 		g_return_val_if_fail (*error == NULL, FALSE);
1906 	
1907 		num = nm_setting_ip6_config_get_num_routes (s_ip6);
1908 		if (num == 0) {
1909 			unlink (filename);
1910 			return TRUE;
1911 		}
1912 	
1913 		route_items = g_malloc0 (sizeof (char*) * (num + 1));
1914 		for (i = 0; i < num; i++) {
1915 			route = nm_setting_ip6_config_get_route (s_ip6, i);
1916 	
1917 			memset (dest, 0, sizeof (dest));
1918 			ip = nm_ip6_route_get_dest (route);
1919 			inet_ntop (AF_INET6, (const void *) ip, &dest[0], sizeof (dest));
1920 	
1921 			prefix = nm_ip6_route_get_prefix (route);
1922 	
1923 			memset (next_hop, 0, sizeof (next_hop));
1924 			ip = nm_ip6_route_get_next_hop (route);
1925 			inet_ntop (AF_INET6, (const void *) ip, &next_hop[0], sizeof (next_hop));
1926 	
1927 			metric = nm_ip6_route_get_metric (route);
1928 	
1929 			route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, metric);
1930 		}
1931 		route_items[num] = NULL;
1932 		route_contents = g_strjoinv (NULL, route_items);
1933 		g_strfreev (route_items);
1934 	
1935 		if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
1936 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1937 			             "Writing route6 file '%s' failed", filename);
1938 			goto error;
1939 		}
1940 	
1941 		success = TRUE;
1942 	
1943 	error:
1944 		g_free (route_contents);
1945 		return success;
1946 	}
1947 	
1948 	static gboolean
1949 	write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
1950 	{
1951 		NMSettingIP6Config *s_ip6;
1952 		NMSettingIP4Config *s_ip4;
1953 		const char *value;
1954 		char *addr_key, *prefix;
1955 		guint32 i, num, num4;
1956 		GString *searches;
1957 		char buf[INET6_ADDRSTRLEN];
1958 		char ipv6_defaultgw[INET6_ADDRSTRLEN];
1959 		NMIP6Address *addr;
1960 		const struct in6_addr *ip;
1961 		GString *ip_str1, *ip_str2, *ip_ptr;
1962 		char *route6_path;
1963 	
1964 		s_ip6 = nm_connection_get_setting_ip6_config (connection);
1965 		if (!s_ip6) {
1966 			/* Treat missing IPv6 setting as a setting with method "auto" */
1967 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
1968 			svSetValue (ifcfg, "IPV6_AUTOCONF", "yes", FALSE);
1969 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
1970 			svSetValue (ifcfg, "IPV6_DEFROUTE", "yes", FALSE);
1971 			svSetValue (ifcfg, "IPV6_PEERDNS", "yes", FALSE);
1972 			svSetValue (ifcfg, "IPV6_PEERROUTES", "yes", FALSE);
1973 			svSetValue (ifcfg, "IPV6_FAILURE_FATAL", "no", FALSE);
1974 			return TRUE;
1975 		}
1976 	
1977 		value = nm_setting_ip6_config_get_method (s_ip6);
1978 		g_assert (value);
1979 		if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
1980 			svSetValue (ifcfg, "IPV6INIT", "no", FALSE);
1981 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
1982 			return TRUE;
1983 		} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
1984 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
1985 			svSetValue (ifcfg, "IPV6_AUTOCONF", "yes", FALSE);
1986 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
1987 		} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
1988 			const char *hostname;
1989 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
1990 			svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
1991 			svSetValue (ifcfg, "DHCPV6C", "yes", FALSE);
1992 			hostname = nm_setting_ip6_config_get_dhcp_hostname (s_ip6);
1993 			if (hostname)
1994 				svSetValue (ifcfg, "DHCP_HOSTNAME", hostname, FALSE);
1995 		} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
1996 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
1997 			svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
1998 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
1999 		} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
2000 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
2001 			svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
2002 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
2003 		} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) {
2004 			svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
2005 			svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
2006 			/* TODO */
2007 		}
2008 	
2009 		/* Write out IP addresses */
2010 		num = nm_setting_ip6_config_get_num_addresses (s_ip6);
2011 		ip_str1 = g_string_new (NULL);
2012 		ip_str2 = g_string_new (NULL);
2013 		ipv6_defaultgw[0] = 0;
2014 		for (i = 0; i < num; i++) {
2015 			if (i == 0)
2016 				ip_ptr = ip_str1;
2017 			else
2018 				ip_ptr = ip_str2;
2019 	
2020 			addr = nm_setting_ip6_config_get_address (s_ip6, i);
2021 			ip = nm_ip6_address_get_address (addr);
2022 			prefix = g_strdup_printf ("%u", nm_ip6_address_get_prefix (addr));
2023 			memset (buf, 0, sizeof (buf));
2024 			inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
2025 			if (i > 1)
2026 				g_string_append_c (ip_ptr, ' ');  /* separate addresses in IPV6ADDR_SECONDARIES */
2027 			g_string_append (ip_ptr, buf);
2028 			g_string_append_c (ip_ptr, '/');
2029 			g_string_append (ip_ptr, prefix);
2030 			g_free (prefix);
2031 	
2032 			/* We only support gateway for the first IP address for now */
2033 			if (i == 0) {
2034 				ip = nm_ip6_address_get_gateway (addr);
2035 				if (!IN6_IS_ADDR_UNSPECIFIED (ip))
2036 					inet_ntop (AF_INET6, ip, ipv6_defaultgw, sizeof (ipv6_defaultgw));
2037 			}
2038 		}
2039 		svSetValue (ifcfg, "IPV6ADDR", ip_str1->str, FALSE);
2040 		svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str, FALSE);
2041 		svSetValue (ifcfg, "IPV6_DEFAULTGW", ipv6_defaultgw, FALSE);
2042 		g_string_free (ip_str1, TRUE);
2043 		g_string_free (ip_str2, TRUE);
2044 	
2045 		/* Write out DNS - 'DNS' key is used both for IPv4 and IPv6 */
2046 		s_ip4 = nm_connection_get_setting_ip4_config (connection);
2047 		num4 = s_ip4 ? nm_setting_ip4_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */
2048 		num = nm_setting_ip6_config_get_num_dns (s_ip6);
2049 		for (i = 0; i < 254; i++) {
2050 			addr_key = g_strdup_printf ("DNS%d", i + num4 + 1);
2051 	
2052 			if (i >= num)
2053 				svSetValue (ifcfg, addr_key, NULL, FALSE);
2054 			else {
2055 				ip = nm_setting_ip6_config_get_dns (s_ip6, i);
2056 	
2057 				memset (buf, 0, sizeof (buf));
2058 				inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
2059 				svSetValue (ifcfg, addr_key, buf, FALSE);
2060 			}
2061 			g_free (addr_key);
2062 		}
2063 	
2064 		/* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */
2065 		num = nm_setting_ip6_config_get_num_dns_searches (s_ip6);
2066 		if (num > 0) {
2067 			char *ip4_domains;
2068 			ip4_domains = svGetValue (ifcfg, "DOMAIN", FALSE);
2069 			searches = g_string_new (ip4_domains);
2070 			for (i = 0; i < num; i++) {
2071 				if (searches->len > 0)
2072 					g_string_append_c (searches, ' ');
2073 				g_string_append (searches, nm_setting_ip6_config_get_dns_search (s_ip6, i));
2074 			}
2075 			svSetValue (ifcfg, "DOMAIN", searches->str, FALSE);
2076 			g_string_free (searches, TRUE);
2077 			g_free (ip4_domains);
2078 		}
2079 	
2080 		/* handle IPV6_DEFROUTE */
2081 		/* IPV6_DEFROUTE has the opposite meaning from 'never-default' */
2082 		if (nm_setting_ip6_config_get_never_default(s_ip6))
2083 			svSetValue (ifcfg, "IPV6_DEFROUTE", "no", FALSE);
2084 		else
2085 			svSetValue (ifcfg, "IPV6_DEFROUTE", "yes", FALSE);
2086 	
2087 		svSetValue (ifcfg, "IPV6_PEERDNS", NULL, FALSE);
2088 		svSetValue (ifcfg, "IPV6_PEERROUTES", NULL, FALSE);
2089 		if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
2090 			svSetValue (ifcfg, "IPV6_PEERDNS",
2091 			            nm_setting_ip6_config_get_ignore_auto_dns (s_ip6) ? "no" : "yes",
2092 			            FALSE);
2093 	
2094 			svSetValue (ifcfg, "IPV6_PEERROUTES",
2095 			            nm_setting_ip6_config_get_ignore_auto_routes (s_ip6) ? "no" : "yes",
2096 			            FALSE);
2097 		}
2098 	
2099 		svSetValue (ifcfg, "IPV6_FAILURE_FATAL",
2100 		            nm_setting_ip6_config_get_may_fail (s_ip6) ? "no" : "yes",
2101 		            FALSE);
2102 	
2103 		/* IPv6 Privacy Extensions */
2104 		svSetValue (ifcfg, "IPV6_PRIVACY", NULL, FALSE);
2105 		svSetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", NULL, FALSE);
2106 		switch (nm_setting_ip6_config_get_ip6_privacy (s_ip6)){
2107 		case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
2108 			svSetValue (ifcfg, "IPV6_PRIVACY", "no", FALSE);
2109 		break;
2110 		case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
2111 			svSetValue (ifcfg, "IPV6_PRIVACY", "rfc3041", FALSE);
2112 			svSetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", "yes", FALSE);
2113 		break;
2114 		case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
2115 			svSetValue (ifcfg, "IPV6_PRIVACY", "rfc3041", FALSE);
2116 		break;
2117 		default:
2118 		break;
2119 		}
2120 	
2121 		/* Static routes go to route6-<dev> file */
2122 		route6_path = utils_get_route6_path (ifcfg->fileName);
2123 		if (!route6_path) {
2124 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2125 			             "Could not get route6 file path for '%s'", ifcfg->fileName);
2126 			goto error;
2127 		}
2128 		write_route6_file (route6_path, s_ip6, error);
2129 		g_free (route6_path);
2130 		if (error && *error)
2131 			goto error;
2132 	
2133 		return TRUE;
2134 	
2135 	error:
2136 		return FALSE;
2137 	}
2138 	
2139 	static char *
2140 	escape_id (const char *id)
2141 	{
2142 		static const char const as_dash[] = "\\][|/=()!";
2143 		char *escaped = g_strdup (id);
2144 		char *p = escaped;
2145 	
2146 		/* Escape random stuff */
2147 		while (*p) {
2148 			if (*p == ' ')
2149 				*p = '_';
2150 			else if (strchr (as_dash, *p))
2151 				*p = '-';
2152 			p++;
2153 		}
2154 	
2155 		return escaped;
2156 	}
2157 	
2158 	static gboolean
2159 	write_connection (NMConnection *connection,
2160 	                  const char *ifcfg_dir,
2161 	                  const char *filename,
2162 	                  const char *keyfile,
2163 	                  char **out_filename,
2164 	                  GError **error)
2165 	{
2166 		NMSettingConnection *s_con;
2167 		gboolean success = FALSE;
2168 		shvarFile *ifcfg = NULL;
2169 		char *ifcfg_name = NULL;
2170 		const char *type;
2171 		gboolean no_8021x = FALSE;
2172 		gboolean wired = FALSE;
2173 	
2174 		if (!writer_can_write_connection (connection, error))
2175 			return FALSE;
2176 	
2177 		s_con = nm_connection_get_setting_connection (connection);
2178 		g_assert (s_con);
2179 	
2180 		if (filename) {
2181 			/* For existing connections, 'filename' should be full path to ifcfg file */
2182 			ifcfg = svNewFile (filename);
2183 			ifcfg_name = g_strdup (filename);
2184 		} else {
2185 			char *escaped;
2186 	
2187 			escaped = escape_id (nm_setting_connection_get_id (s_con));
2188 			ifcfg_name = g_strdup_printf ("%s/ifcfg-%s", ifcfg_dir, escaped);
2189 	
2190 			/* If a file with this path already exists then we need another name.
2191 			 * Multiple connections can have the same ID (ie if two connections with
2192 			 * the same ID are visible to different users) but of course can't have
2193 			 * the same path.
2194 			 */
2195 			if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS)) {
2196 				guint32 idx = 0;
2197 	
2198 				g_free (ifcfg_name);
2199 				while (idx++ < 500) {
2200 					ifcfg_name = g_strdup_printf ("%s/ifcfg-%s-%u", ifcfg_dir, escaped, idx);
2201 					if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE)
2202 						break;
2203 					g_free (ifcfg_name);
2204 					ifcfg_name = NULL;
2205 				}
2206 			}
2207 			g_free (escaped);
2208 	
2209 			if (ifcfg_name == NULL) {
2210 				g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
2211 				                     "Failed to find usable ifcfg file name");
2212 				return FALSE;
2213 			}
2214 	
2215 			ifcfg = svCreateFile (ifcfg_name);
2216 		}
2217 	
2218 		if (!ifcfg) {
2219 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2220 			             "Failed to open/create ifcfg file '%s'", ifcfg_name);
2221 			goto out;
2222 		}
2223 	
2224 		type = nm_setting_connection_get_connection_type (s_con);
2225 		if (!type) {
2226 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2227 			             "Missing connection type!");
2228 			goto out;
2229 		}
2230 	
2231 		if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) {
2232 			// FIXME: can't write PPPoE at this time
2233 			if (nm_connection_get_setting_pppoe (connection)) {
2234 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2235 				             "Can't write connection type '%s'",
2236 				             NM_SETTING_PPPOE_SETTING_NAME);
2237 				goto out;
2238 			}
2239 	
2240 			if (!write_wired_setting (connection, ifcfg, error))
2241 				goto out;
2242 			wired = TRUE;
2243 		} else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) {
2244 			if (!write_vlan_setting (connection, ifcfg, &wired, error))
2245 				goto out;
2246 		} else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
2247 			if (!write_wireless_setting (connection, ifcfg, &no_8021x, error))
2248 				goto out;
2249 		} else if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
2250 			if (!write_infiniband_setting (connection, ifcfg, error))
2251 				goto out;
2252 		} else if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME)) {
2253 			if (!write_bonding_setting (connection, ifcfg, error))
2254 				goto out;
2255 		} else if (!strcmp (type, NM_SETTING_TEAM_SETTING_NAME)) {
2256 			if (!write_team_setting (connection, ifcfg, error))
2257 				goto out;
2258 		} else if (!strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)) {
2259 			if (!write_bridge_setting (connection, ifcfg, error))
2260 				goto out;
2261 		} else {
2262 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2263 			             "Can't write connection type '%s'", type);
2264 			goto out;
2265 		}
2266 	
2267 		if (!no_8021x) {
2268 			if (!write_8021x_setting (connection, ifcfg, wired, error))
2269 				goto out;
2270 		}
2271 	
2272 		if (!write_bridge_port_setting (connection, ifcfg, error))
2273 			goto out;
2274 	
2275 		if (!write_team_port_setting (connection, ifcfg, error))
2276 			goto out;
2277 	
2278 		if (!utils_ignore_ip_config (connection)) {
2279 			svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE);
2280 	
2281 			if (!write_ip4_setting (connection, ifcfg, error))
2282 				goto out;
2283 	
2284 			if (!write_ip6_setting (connection, ifcfg, error))
2285 				goto out;
2286 		}
2287 	
2288 		write_connection_setting (s_con, ifcfg);
2289 	
2290 		if (svWriteFile (ifcfg, 0644)) {
2291 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2292 			             "Can't write connection '%s'", ifcfg->fileName);
2293 			goto out;
2294 		}
2295 	
2296 		/* Only return the filename if this was a newly written ifcfg */
2297 		if (out_filename && !filename)
2298 			*out_filename = g_strdup (ifcfg_name);
2299 	
2300 		success = TRUE;
2301 	
2302 	out:
2303 		if (ifcfg)
2304 			svCloseFile (ifcfg);
2305 		g_free (ifcfg_name);
2306 		return success;
2307 	}
2308 	
2309 	gboolean
2310 	writer_can_write_connection (NMConnection *connection, GError **error)
2311 	{
2312 		NMSettingConnection *s_con;
2313 	
2314 		if (   (   nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)
2315 		        && !nm_connection_get_setting_pppoe (connection))
2316 		    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)
2317 		    || nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME)
2318 		    || nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)
2319 		    || nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
2320 		    || nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)
2321 		    || nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
2322 			return TRUE;
2323 	
2324 		s_con = nm_connection_get_setting_connection (connection);
2325 		g_assert (s_con);
2326 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2327 		             "The ifcfg-rh plugin cannot write the connection '%s' (type '%s' pppoe %d)",
2328 		             nm_connection_get_id (connection),
2329 		             nm_setting_connection_get_connection_type (s_con),
2330 		             !!nm_connection_get_setting_pppoe (connection));
2331 		return FALSE;
2332 	}
2333 	
2334 	gboolean
2335 	writer_new_connection (NMConnection *connection,
2336 	                       const char *ifcfg_dir,
2337 	                       char **out_filename,
2338 	                       GError **error)
2339 	{
2340 		return write_connection (connection, ifcfg_dir, NULL, NULL, out_filename, error);
2341 	}
2342 	
2343 	gboolean
2344 	writer_update_connection (NMConnection *connection,
2345 	                          const char *ifcfg_dir,
2346 	                          const char *filename,
2347 	                          const char *keyfile,
2348 	                          GError **error)
2349 	{
2350 		return write_connection (connection, ifcfg_dir, filename, keyfile, NULL, error);
2351 	}
2352 	
2353