nms-ifcfg-rh-writer.c 103 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service - keyfile plugin
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
18
 * Copyright 2009 - 2015 Red Hat, Inc.
19 20
 */

21
#include "nm-default.h"
22

Thomas Haller's avatar
Thomas Haller committed
23
#include "nms-ifcfg-rh-writer.h"
24

25 26 27
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
28 29 30 31
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
32

33
#include "nm-utils/nm-enum-utils.h"
34
#include "nm-utils/nm-io-utils.h"
35
#include "nm-manager.h"
36 37 38
#include "nm-setting-connection.h"
#include "nm-setting-wired.h"
#include "nm-setting-wireless.h"
39
#include "nm-setting-ethtool.h"
40
#include "nm-setting-8021x.h"
41
#include "nm-setting-proxy.h"
42 43 44 45
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-vlan.h"
46
#include "nm-setting-user.h"
47 48 49
#include "nm-setting-team.h"
#include "nm-setting-team-port.h"
#include "nm-utils.h"
50
#include "nm-core-internal.h"
51
#include "NetworkManagerUtils.h"
52
#include "nm-meta-setting.h"
53
#include "nm-ethtool-utils.h"
54

Thomas Haller's avatar
Thomas Haller committed
55 56 57
#include "nms-ifcfg-rh-common.h"
#include "nms-ifcfg-rh-reader.h"
#include "nms-ifcfg-rh-utils.h"
58
#include "shvar.h"
59

60 61 62 63 64 65
/*****************************************************************************/

#define _NMLOG_DOMAIN      LOGD_SETTINGS
#define _NMLOG_PREFIX_NAME "ifcfg-rh"
#define _NMLOG(level, ...) \
    G_STMT_START { \
66
        nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \
67 68 69 70 71 72
                "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
                _NMLOG_PREFIX_NAME": " \
                _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
    } G_STMT_END

/*****************************************************************************/
73

74 75 76 77 78 79 80 81 82 83 84
static void
save_secret_flags (shvarFile *ifcfg,
                   const char *key,
                   NMSettingSecretFlags flags)
{
	GString *str;

	g_return_if_fail (ifcfg != NULL);
	g_return_if_fail (key != NULL);

	if (flags == NM_SETTING_SECRET_FLAG_NONE) {
85
		svUnsetValue (ifcfg, key);
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		return;
	}

	/* Convert flags bitfield into string representation */
	str = g_string_sized_new (20);
	if (flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)
		g_string_append (str, SECRET_FLAG_AGENT);

	if (flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) {
		if (str->len)
			g_string_append_c (str, ' ');
		g_string_append (str, SECRET_FLAG_NOT_SAVED);
	}

	if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
		if (str->len)
			g_string_append_c (str, ' ');
		g_string_append (str, SECRET_FLAG_NOT_REQUIRED);
	}

106
	svSetValueStr (ifcfg, key, str->len ? str->str : NULL);
107 108 109
	g_string_free (str, TRUE);
}

110
static void
111
set_secret (shvarFile *ifcfg,
112
            GHashTable *secrets,
113 114
            const char *key,
            const char *value,
115
            const char *flags_key,
116
            NMSettingSecretFlags flags)
117
{
118
	/* Clear the secret from the ifcfg and the associated "keys" file */
119
	svUnsetValue (ifcfg, key);
120 121 122 123

	/* Save secret flags */
	save_secret_flags (ifcfg, flags_key, flags);

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	/* Only write the secret if it's system owned and supposed to be saved */
	if (flags != NM_SETTING_SECRET_FLAG_NONE)
		value = NULL;

	g_hash_table_replace (secrets, g_strdup (key), g_strdup (value));
}

static gboolean
write_secrets (shvarFile *ifcfg,
               GHashTable *secrets,
               GError **error)
{
	nm_auto_shvar_file_close shvarFile *keyfile = NULL;
	gs_free const char **secrets_keys = NULL;
	guint i, secrets_keys_n;
	GError *local = NULL;
	gboolean any_secrets = FALSE;

142
	keyfile = utils_get_keys_ifcfg (svFileGetName (ifcfg), TRUE);
143
	if (!keyfile) {
144 145 146
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
		             "Failure to create secrets file for '%s'", svFileGetName (ifcfg));
		return FALSE;
147 148
	}

149 150
	/* we purge all existing secrets. */
	svUnsetAll (keyfile, SV_KEY_TYPE_ANY);
151

152
	secrets_keys = nm_utils_strdict_get_keys (secrets, TRUE, &secrets_keys_n);
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	for (i = 0; i < secrets_keys_n; i++) {
		const char *k = secrets_keys[i];
		const char *v = g_hash_table_lookup (secrets, k);

		if (v) {
			svSetValueStr (keyfile, k, v);
			any_secrets = TRUE;
		}
	}

	if (!any_secrets)
		(void) unlink (svFileGetName (keyfile));
	else if (!svWriteFile (keyfile, 0600, &local)) {
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
		             "Failure to write secrets to '%s': %s", svFileGetName (keyfile), local->message);
		return FALSE;
	}

	return TRUE;
172 173
}

174 175
typedef struct {
	const NMSetting8021xSchemeVtable *vtable;
176
	const char *ifcfg_rh_key;
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
} Setting8021xSchemeVtable;

static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = {
	[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT],
		.ifcfg_rh_key           = "IEEE_8021X_CA_CERT",
	},
	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT],
		.ifcfg_rh_key           = "IEEE_8021X_INNER_CA_CERT",
	},
	[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT],
		.ifcfg_rh_key           = "IEEE_8021X_CLIENT_CERT",
	},
	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT],
		.ifcfg_rh_key           = "IEEE_8021X_INNER_CLIENT_CERT",
	},
	[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY],
		.ifcfg_rh_key           = "IEEE_8021X_PRIVATE_KEY",
	},
	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = {
		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY],
		.ifcfg_rh_key           = "IEEE_8021X_INNER_PRIVATE_KEY",
	},
204 205
};

206
static gboolean
207 208
write_object (NMSetting8021x *s_8021x,
              shvarFile *ifcfg,
209
              GHashTable *secrets,
210
              GHashTable *blobs,
211
              const Setting8021xSchemeVtable *objtype,
212
              gboolean force_write,
213
              GError **error)
214
{
215
	NMSetting8021xCKScheme scheme;
216
	const char *value = NULL;
217
	GBytes *blob = NULL;
218 219 220
	const char *password = NULL;
	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
	char *secret_name, *secret_flags;
221
	const char *extension;
222
	char *standard_file;
223

224
	g_return_val_if_fail (ifcfg != NULL, FALSE);
225 226
	g_return_val_if_fail (objtype != NULL, FALSE);

227
	scheme = (*(objtype->vtable->scheme_func))(s_8021x);
228
	switch (scheme) {
229 230
	case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN:
		break;
231
	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
232
		blob = (*(objtype->vtable->blob_func))(s_8021x);
233 234
		break;
	case NM_SETTING_802_1X_CK_SCHEME_PATH:
235
		value = (*(objtype->vtable->path_func))(s_8021x);
236 237
		break;
	case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
238
		value = (*(objtype->vtable->uri_func))(s_8021x);
239 240
		break;
	default:
241 242 243
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
		             "Unhandled certificate object scheme");
		return FALSE;
244
	}
245

246
	/* Set the password for certificate/private key. */
247 248
	secret_name = g_strdup_printf ("%s_PASSWORD", objtype->ifcfg_rh_key);
	secret_flags = g_strdup_printf ("%s_PASSWORD_FLAGS", objtype->ifcfg_rh_key);
249 250
	password = (*(objtype->vtable->passwd_func))(s_8021x);
	flags = (*(objtype->vtable->pwflag_func))(s_8021x);
251
	set_secret (ifcfg, secrets, secret_name, password, secret_flags, flags);
252 253 254
	g_free (secret_name);
	g_free (secret_flags);

255 256 257 258 259 260
	if (!objtype->vtable->format_func)
		extension = "der";
	else if (objtype->vtable->format_func (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
		extension = "p12";
	else
		extension = "pem";
261

262 263 264
	/* If the object path was specified, prefer that over any raw cert data that
	 * may have been sent.
	 */
265
	if (value) {
266
		svSetValueStr (ifcfg, objtype->ifcfg_rh_key, value);
267
		return TRUE;
268 269
	}

270
	/* If it's raw certificate data, write the data out to the standard file */
271 272
	if (blob) {
		char *new_file;
273

274
		new_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension);
275 276 277 278 279
		g_hash_table_replace (blobs, new_file, g_bytes_ref (blob));
		svSetValueStr (ifcfg, objtype->ifcfg_rh_key, new_file);
		return TRUE;
	}

280 281 282 283 284 285 286 287 288 289 290
	/* If certificate/private key wasn't sent, the connection may no longer be
	 * 802.1x and thus we clear out the paths and certs.
	 *
	 * Since no cert/private key is now being used, delete any standard file
	 * that was created for this connection, but leave other files alone.
	 * Thus, for example,
	 * /etc/sysconfig/network-scripts/ca-cert-Test_Write_Wifi_WPA_EAP-TLS.der
	 * will be deleted, but /etc/pki/tls/cert.pem will not.
	 */
	standard_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension);
	g_hash_table_replace (blobs, standard_file, NULL);
291
	svSetValue (ifcfg, objtype->ifcfg_rh_key, force_write ? "" : NULL);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
	return TRUE;
}

static gboolean
write_blobs (GHashTable *blobs, GError **error)
{
	GHashTableIter iter;
	const char *filename;
	GBytes *blob;

	if (!blobs)
		return TRUE;

	g_hash_table_iter_init (&iter, blobs);
	while (g_hash_table_iter_next (&iter, (gpointer *) &filename, (gpointer *) &blob)) {
		GError *write_error = NULL;

		if (!blob) {
			(void) unlink (filename);
			continue;
312 313
		}

314 315 316 317
		/* Write the raw certificate data out to the standard file so that we
		 * can use paths from now on instead of pushing around the certificate
		 * data itself.
		 */
318 319 320 321 322
		if (!nm_utils_file_set_contents (filename,
		                                 (const char *) g_bytes_get_data (blob, NULL),
		                                 g_bytes_get_size (blob),
		                                 0600,
		                                 &write_error)) {
323
			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
324 325 326 327
			             "Could not write certificate to file \"%s\": %s",
			             filename,
			             write_error->message);
			return FALSE;
328 329 330
		}
	}

331
	return TRUE;
332 333
}

334 335
static gboolean
write_8021x_certs (NMSetting8021x *s_8021x,
336
                   GHashTable *secrets,
337
                   GHashTable *blobs,
338 339 340 341
                   gboolean phase2,
                   shvarFile *ifcfg,
                   GError **error)
{
342 343
	const Setting8021xSchemeVtable *pk_otype = NULL;
	gs_free char *value_to_free = NULL;
344 345

	/* CA certificate */
346
	if (!write_object (s_8021x, ifcfg, secrets, blobs,
347 348 349
	                   phase2
	                       ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT]
	                       : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT],
350
	                   FALSE,
351
	                   error))
352 353 354
		return FALSE;

	/* Private key */
355
	if (phase2)
356
		pk_otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY];
357
	else
358
		pk_otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY];
359

360
	/* Save the private key */
361
	if (!write_object (s_8021x, ifcfg, secrets, blobs, pk_otype, FALSE, error))
362
		return FALSE;
363

364 365 366 367 368 369
	/* Save the client certificate.
	 * If there is a private key, always write a property for the
	 * client certificate even if it is empty, so that the reader
	 * doesn't have to read the private key file to determine if it
	 * is a PKCS #12 one which serves also as client certificate.
	 */
370 371 372 373
	if (!write_object (s_8021x, ifcfg, secrets, blobs,
	                   phase2
	                       ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT]
	                       : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT],
374
	                   !!svGetValue (ifcfg, pk_otype->ifcfg_rh_key, &value_to_free),
375 376
	                   error))
		return FALSE;
377

378
	return TRUE;
379 380
}

381
static gboolean
382 383
write_8021x_setting (NMConnection *connection,
                     shvarFile *ifcfg,
384
                     GHashTable *secrets,
385
                     GHashTable *blobs,
386 387
                     gboolean wired,
                     GError **error)
388 389
{
	NMSetting8021x *s_8021x;
390
	NMSetting8021xAuthFlags auth_flags;
391
	const char *value, *match;
392 393
	gconstpointer ptr;
	GBytes* bytes;
394
	char *tmp = NULL;
395
	GString *phase2_auth;
396 397
	GString *str;
	guint32 i, num;
398
	gsize size;
399
	int vint;
400

401
	s_8021x = nm_connection_get_setting_802_1x (connection);
402 403 404
	if (!s_8021x) {
		/* If wired, clear KEY_MGMT */
		if (wired)
405
			svUnsetValue (ifcfg, "KEY_MGMT");
406
		return TRUE;
407 408 409 410
	}

	/* If wired, write KEY_MGMT */
	if (wired)
411
		svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X");
412 413 414 415 416 417 418

	/* EAP method */
	if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) {
		value = nm_setting_802_1x_get_eap_method (s_8021x, 0);
		if (value)
			tmp = g_ascii_strup (value, -1);
	}
419
	svSetValueStr (ifcfg, "IEEE_8021X_EAP_METHODS", tmp);
420 421
	g_free (tmp);

422 423
	svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY",
	               nm_setting_802_1x_get_identity (s_8021x));
424

425 426
	svSetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY",
	               nm_setting_802_1x_get_anonymous_identity (s_8021x));
427

428
	set_secret (ifcfg,
429
	            secrets,
430 431
	            "IEEE_8021X_PASSWORD",
	            nm_setting_802_1x_get_password (s_8021x),
432
	            "IEEE_8021X_PASSWORD_FLAGS",
433
	            nm_setting_802_1x_get_password_flags (s_8021x));
434

435 436 437 438 439 440 441 442 443 444 445 446 447 448
	tmp = NULL;
	bytes = nm_setting_802_1x_get_password_raw (s_8021x);
	if (bytes) {
		ptr = g_bytes_get_data (bytes, &size);
		tmp = nm_utils_bin2hexstr (ptr, size, -1);
	}
	set_secret (ifcfg,
	            secrets,
	            "IEEE_8021X_PASSWORD_RAW",
	            tmp,
	            "IEEE_8021X_PASSWORD_RAW_FLAGS",
	            nm_setting_802_1x_get_password_raw_flags (s_8021x));
	g_free (tmp);

449 450
	/* PEAP version */
	value = nm_setting_802_1x_get_phase1_peapver (s_8021x);
451
	svUnsetValue (ifcfg, "IEEE_8021X_PEAP_VERSION");
452
	if (value && (!strcmp (value, "0") || !strcmp (value, "1")))
453
		svSetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", value);
454 455 456

	/* Force new PEAP label */
	value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x);
457
	svUnsetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL");
458
	if (value && !strcmp (value, "1"))
459
		svSetValueStr (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes");
460

461 462
	/* PAC file */
	value = nm_setting_802_1x_get_pac_file (s_8021x);
463
	svUnsetValue (ifcfg, "IEEE_8021X_PAC_FILE");
464
	if (value)
465
		svSetValueStr (ifcfg, "IEEE_8021X_PAC_FILE", value);
466 467 468

	/* FAST PAC provisioning */
	value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
469
	svUnsetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
470 471
	if (value) {
		if (strcmp (value, "1") == 0)
472
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth");
473
		else if (strcmp (value, "2") == 0)
474
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth");
475
		else if (strcmp (value, "3") == 0)
476
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth");
477 478
	}

479
	/* Phase2 auth methods */
480
	svUnsetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	phase2_auth = g_string_new (NULL);

	value = nm_setting_802_1x_get_phase2_auth (s_8021x);
	if (value) {
		tmp = g_ascii_strup (value, -1);
		g_string_append (phase2_auth, tmp);
		g_free (tmp);
	}

	value = nm_setting_802_1x_get_phase2_autheap (s_8021x);
	if (value) {
		if (phase2_auth->len)
			g_string_append_c (phase2_auth, ' ');

		tmp = g_ascii_strup (value, -1);
		g_string_append_printf (phase2_auth, "EAP-%s", tmp);
		g_free (tmp);
	}

500 501 502 503
	auth_flags = nm_setting_802_1x_get_phase1_auth_flags (s_8021x);
	if (auth_flags == NM_SETTING_802_1X_AUTH_FLAGS_NONE) {
		svUnsetValue (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS");
	} else {
504 505 506
		svSetValueEnum (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS",
		                nm_setting_802_1x_auth_flags_get_type(),
		                auth_flags);
507 508
	}

509 510
	svSetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS",
	               phase2_auth->len ? phase2_auth->str : NULL);
511

512
	g_string_free (phase2_auth, TRUE);
513

514 515
	svSetValueStr (ifcfg, "IEEE_8021X_SUBJECT_MATCH",
	               nm_setting_802_1x_get_subject_match (s_8021x));
516

517 518
	svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH",
	               nm_setting_802_1x_get_phase2_subject_match (s_8021x));
519

520
	svUnsetValue (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES");
521 522 523 524 525 526 527 528 529
	str = g_string_new (NULL);
	num = nm_setting_802_1x_get_num_altsubject_matches (s_8021x);
	for (i = 0; i < num; i++) {
		if (i > 0)
			g_string_append_c (str, ' ');
		match = nm_setting_802_1x_get_altsubject_match (s_8021x, i);
		g_string_append (str, match);
	}
	if (str->len > 0)
530
		svSetValueStr (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", str->str);
531 532
	g_string_free (str, TRUE);

533
	svUnsetValue (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES");
534 535 536 537 538 539 540 541 542
	str = g_string_new (NULL);
	num = nm_setting_802_1x_get_num_phase2_altsubject_matches (s_8021x);
	for (i = 0; i < num; i++) {
		if (i > 0)
			g_string_append_c (str, ' ');
		match = nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, i);
		g_string_append (str, match);
	}
	if (str->len > 0)
543
		svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", str->str);
544 545
	g_string_free (str, TRUE);

546 547 548 549
	svSetValueStr (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH",
	               nm_setting_802_1x_get_domain_suffix_match (s_8021x));
	svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH",
	               nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x));
550

551 552 553
	vint = nm_setting_802_1x_get_auth_timeout (s_8021x);
	svSetValueInt64_cond (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", vint > 0, vint);

554
	if (!write_8021x_certs (s_8021x, secrets, blobs, FALSE, ifcfg, error))
555
		return FALSE;
556

557
	/* phase2/inner certs */
558
	if (!write_8021x_certs (s_8021x, secrets, blobs, TRUE, ifcfg, error))
559 560 561
		return FALSE;

	return TRUE;
562 563 564 565 566
}

static gboolean
write_wireless_security_setting (NMConnection *connection,
                                 shvarFile *ifcfg,
567
                                 GHashTable *secrets,
568 569 570 571 572
                                 gboolean adhoc,
                                 gboolean *no_8021x,
                                 GError **error)
{
	NMSettingWirelessSecurity *s_wsec;
573 574
	const char *key_mgmt, *auth_alg, *key, *proto, *cipher;
	const char *psk = NULL;
575
	gboolean wep = FALSE, wpa = FALSE, dynamic_wep = FALSE;
576
	NMSettingWirelessSecurityWpsMethod wps_method;
577 578 579 580
	char *tmp;
	guint32 i, num;
	GString *str;

581
	s_wsec = nm_connection_get_setting_wireless_security (connection);
582
	if (!s_wsec) {
583
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
584 585 586 587 588 589 590 591 592
		             "Missing '%s' setting", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
		return FALSE;
	}

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	g_assert (key_mgmt);

	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);

593
	svUnsetValue (ifcfg, "DEFAULTKEY");
594 595

	if (!strcmp (key_mgmt, "none")) {
596
		svUnsetValue (ifcfg, "KEY_MGMT");
597 598 599
		wep = TRUE;
		*no_8021x = TRUE;
	} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
600
		svSetValueStr (ifcfg, "KEY_MGMT", "WPA-PSK");
601 602
		wpa = TRUE;
		*no_8021x = TRUE;
603 604 605 606
	} else if (!strcmp (key_mgmt, "sae")) {
		svSetValueStr (ifcfg, "KEY_MGMT", "SAE");
		wpa = TRUE;
		*no_8021x = TRUE;
607
	} else if (!strcmp (key_mgmt, "ieee8021x")) {
608
		svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X");
609
		dynamic_wep = TRUE;
610
	} else if (!strcmp (key_mgmt, "wpa-eap")) {
611
		svSetValueStr (ifcfg, "KEY_MGMT", "WPA-EAP");
612 613 614
		wpa = TRUE;
	}

615
	svUnsetValue (ifcfg, "SECURITYMODE");
616 617
	if (auth_alg) {
		if (!strcmp (auth_alg, "shared"))
618
			svSetValueStr (ifcfg, "SECURITYMODE", "restricted");
619
		else if (!strcmp (auth_alg, "open"))
620
			svSetValueStr (ifcfg, "SECURITYMODE", "open");
621
		else if (!strcmp (auth_alg, "leap")) {
622 623 624
			svSetValueStr (ifcfg, "SECURITYMODE", "leap");
			svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY",
			               nm_setting_wireless_security_get_leap_username (s_wsec));
625
			set_secret (ifcfg,
626
			            secrets,
627
			            "IEEE_8021X_PASSWORD",
628
			            nm_setting_wireless_security_get_leap_password (s_wsec),
629
			            "IEEE_8021X_PASSWORD_FLAGS",
630
			            nm_setting_wireless_security_get_leap_password_flags (s_wsec));
631 632 633 634
			*no_8021x = TRUE;
		}
	}

635 636 637 638 639 640 641
	/* WPS */
	wps_method = nm_setting_wireless_security_get_wps_method (s_wsec);
	if (wps_method == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT)
		svUnsetValue (ifcfg, "WPS_METHOD");
	else
		svSetValueEnum (ifcfg, "WPS_METHOD", nm_setting_wireless_security_wps_method_get_type (), wps_method);

642 643
	/* WEP keys */

644
	/* Clear any default key */
645
	set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
646

647 648
	/* Clear existing keys */
	for (i = 0; i < 4; i++) {
649
		char tag[64];
650

651
		numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
652
		set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
653 654

		numbered_tag (tag, "KEY", i + 1);
655
		set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
656 657 658
	}

	/* And write the new ones out */
659
	if (wep) {
660 661 662
		NMWepKeyType key_type;
		const char *key_type_str = NULL;

663
		/* Default WEP TX key index */
664
		svSetValueInt64 (ifcfg, "DEFAULTKEY", nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) + 1);
665

666 667 668 669 670 671 672 673 674 675 676 677
		key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec);
		switch (key_type) {
		case NM_WEP_KEY_TYPE_KEY:
			key_type_str = "key";
			break;
		case NM_WEP_KEY_TYPE_PASSPHRASE:
			key_type_str = "passphrase";
			break;
		case NM_WEP_KEY_TYPE_UNKNOWN:
			break;
		}
		svSetValue (ifcfg, "KEY_TYPE", key_type_str);
678

679
		for (i = 0; i < 4; i++) {
680 681
			key = nm_setting_wireless_security_get_wep_key (s_wsec, i);
			if (key) {
682 683 684
				gs_free char *ascii_key = NULL;
				char tag[64];
				gboolean key_valid = TRUE;
685

686 687 688 689
				/* Passphrase needs a different ifcfg key since with WEP, there
				 * are some passphrases that are indistinguishable from WEP hex
				 * keys.
				 */
690 691 692 693 694 695
				if (key_type == NM_WEP_KEY_TYPE_UNKNOWN) {
					if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY))
						key_type = NM_WEP_KEY_TYPE_KEY;
					else if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_PASSPHRASE))
						key_type = NM_WEP_KEY_TYPE_PASSPHRASE;
				}
696

697
				if (key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
698
					numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
699
				else if (key_type == NM_WEP_KEY_TYPE_KEY) {
700
					numbered_tag (tag, "KEY", i + 1);
701

702 703 704 705 706
					/* Add 's:' prefix for ASCII keys */
					if (strlen (key) == 5 || strlen (key) == 13) {
						ascii_key = g_strdup_printf ("s:%s", key);
						key = ascii_key;
					}
707
				} else {
708
					g_warn_if_reached ();
709
					key_valid = FALSE;
710 711
				}

712
				if (key_valid) {
713
					set_secret (ifcfg,
714
					            secrets,
715
					            tag,
716 717
					            key,
					            "WEP_KEY_FLAGS",
718
					            nm_setting_wireless_security_get_wep_key_flags (s_wsec));
719
				}
720 721
			}
		}
722 723 724
	}

	/* WPA protos */
725 726
	svUnsetValue (ifcfg, "WPA_ALLOW_WPA");
	svUnsetValue (ifcfg, "WPA_ALLOW_WPA2");
727 728 729 730
	num = nm_setting_wireless_security_get_num_protos (s_wsec);
	for (i = 0; i < num; i++) {
		proto = nm_setting_wireless_security_get_proto (s_wsec, i);
		if (proto && !strcmp (proto, "wpa"))
731
			svSetValueStr (ifcfg, "WPA_ALLOW_WPA", "yes");
732
		else if (proto && !strcmp (proto, "rsn"))
733
			svSetValueStr (ifcfg, "WPA_ALLOW_WPA2", "yes");
734 735 736
	}

	/* WPA Pairwise ciphers */
737
	svUnsetValue (ifcfg, "CIPHER_PAIRWISE");
738 739
	str = g_string_new (NULL);
	num = nm_setting_wireless_security_get_num_pairwise (s_wsec);
740 741
	for (i = 0; i < num; i++) {
		if (i > 0)
742 743
			g_string_append_c (str, ' ');
		cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i);
744 745 746 747 748 749 750 751 752

		/* Don't write out WEP40 or WEP104 if for some reason they are set; they
		 * are not valid pairwise ciphers.
		 */
		if (strcmp (cipher, "wep40") && strcmp (cipher, "wep104")) {
			tmp = g_ascii_strup (cipher, -1);
			g_string_append (str, tmp);
			g_free (tmp);
		}
753
	}
754
	if (strlen (str->str) && (dynamic_wep == FALSE))
755
		svSetValueStr (ifcfg, "CIPHER_PAIRWISE", str->str);
756 757 758
	g_string_free (str, TRUE);

	/* WPA Group ciphers */
759
	svUnsetValue (ifcfg, "CIPHER_GROUP");
760 761
	str = g_string_new (NULL);
	num = nm_setting_wireless_security_get_num_groups (s_wsec);
762 763
	for (i = 0; i < num; i++) {
		if (i > 0)
764 765 766 767 768 769
			g_string_append_c (str, ' ');
		cipher = nm_setting_wireless_security_get_group (s_wsec, i);
		tmp = g_ascii_strup (cipher, -1);
		g_string_append (str, tmp);
		g_free (tmp);
	}
770
	if (strlen (str->str) && (dynamic_wep == FALSE))
771
		svSetValueStr (ifcfg, "CIPHER_GROUP", str->str);
772 773
	g_string_free (str, TRUE);

774
	if (wpa)
775
		psk = nm_setting_wireless_security_get_psk (s_wsec);
776 777

	set_secret (ifcfg,
778
	            secrets,
779 780 781
	            "WPA_PSK",
	            psk,
	            "WPA_PSK_FLAGS",
782
	            wpa ? nm_setting_wireless_security_get_psk_flags (s_wsec) : NM_SETTING_SECRET_FLAG_NONE);
783

784 785 786
	if (nm_setting_wireless_security_get_pmf (s_wsec) == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT)
		svUnsetValue (ifcfg, "PMF");
	else {
787 788
		svSetValueEnum (ifcfg, "PMF", nm_setting_wireless_security_pmf_get_type (),
		                nm_setting_wireless_security_get_pmf (s_wsec));
789 790
	}

791 792 793 794 795 796 797
	if (nm_setting_wireless_security_get_fils (s_wsec) == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT)
		svUnsetValue (ifcfg, "FILS");
	else {
		svSetValueEnum (ifcfg, "FILS", nm_setting_wireless_security_fils_get_type (),
		                nm_setting_wireless_security_get_fils (s_wsec));
	}

798 799 800 801 802 803
	return TRUE;
}

static gboolean
write_wireless_setting (NMConnection *connection,
                        shvarFile *ifcfg,
804
                        GHashTable *secrets,
805 806 807 808
                        gboolean *no_8021x,
                        GError **error)
{
	NMSettingWireless *s_wireless;
809 810 811
	GBytes *ssid;
	const guint8 *ssid_data;
	gsize ssid_len;
812 813
	const char *mode, *bssid;
	const char *device_mac, *cloned_mac;
814 815
	guint32 mtu, chan, i;
	gboolean adhoc = FALSE, hex_ssid = FALSE;
816
	const char *const*macaddr_blacklist;
817

818
	s_wireless = nm_connection_get_setting_wireless (connection);
819
	if (!s_wireless) {
820
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
821 822 823 824
		             "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}

825
	device_mac = nm_setting_wireless_get_mac_address (s_wireless);
826
	svSetValueStr (ifcfg, "HWADDR", device_mac);
827

828
	cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
829
	svSetValueStr (ifcfg, "MACADDR", cloned_mac);
830

831 832
	svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
	               nm_setting_wireless_get_generate_mac_address_mask (s_wireless));
833

834
	svUnsetValue (ifcfg, "HWADDR_BLACKLIST");
835
	macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
836 837
	if (macaddr_blacklist[0]) {
		char *blacklist_str;
838

839
		blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist);
840
		svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str);
841
		g_free (blacklist_str);
842 843
	}

844
	mtu = nm_setting_wireless_get_mtu (s_wireless);
845
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
846 847 848

	ssid = nm_setting_wireless_get_ssid (s_wireless);
	if (!ssid) {
849
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
850 851 852
		             "Missing SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}
853 854
	ssid_data = g_bytes_get_data (ssid, &ssid_len);
	if (!ssid_len || ssid_len > 32) {
855
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
856 857 858 859 860 861 862
		             "Invalid SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}

	/* If the SSID contains any non-printable characters, we need to use the
	 * hex notation of the SSID instead.
	 */
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
	if (   ssid_len > 2
	    && ssid_data[0] == '0'
	    && ssid_data[1] == 'x') {
		hex_ssid = TRUE;
		for (i = 2; i < ssid_len; i++) {
			if (!g_ascii_isxdigit (ssid_data[i])) {
				hex_ssid = FALSE;
				break;
			}
		}
	}
	if (!hex_ssid) {
		for (i = 0; i < ssid_len; i++) {
			if (!g_ascii_isprint (ssid_data[i])) {
				hex_ssid = TRUE;
				break;
			}
880 881 882 883 884 885 886
		}
	}

	if (hex_ssid) {
		GString *str;

		/* Hex SSIDs don't get quoted */
887
		str = g_string_sized_new (ssid_len * 2 + 3);
888
		g_string_append (str, "0x");
889 890
		for (i = 0; i < ssid_len; i++)
			g_string_append_printf (str, "%02X", ssid_data[i]);
891
		svSetValueStr (ifcfg, "ESSID", str->str);
892 893
		g_string_free (str, TRUE);
	} else {
894
		char buf[33];
895

896
		nm_assert (ssid_len <= 32);
897
		memcpy (buf, ssid_data, ssid_len);
898
		buf[ssid_len] = '\0';
899
		svSetValueStr (ifcfg, "ESSID", buf);
900 901 902
	}

	mode = nm_setting_wireless_get_mode (s_wireless);
903 904 905
	if (!mode)
		svUnsetValue(ifcfg, "MODE");
	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA))
906
		svSetValueStr (ifcfg, "MODE", "Managed");
907
	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
908
		svSetValueStr (ifcfg, "MODE", "Ad-Hoc");
909
		adhoc = TRUE;
910
	} else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_AP))
911
		svSetValueStr (ifcfg, "MODE", "Ap");
912
	else {
913
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
914 915 916 917 918
		             "Invalid mode '%s' in '%s' setting",
		             mode, NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}

919 920
	svUnsetValue (ifcfg, "CHANNEL");
	svUnsetValue (ifcfg, "BAND");
921 922
	chan = nm_setting_wireless_get_channel (s_wireless);
	if (chan) {
923
		svSetValueInt64 (ifcfg, "CHANNEL", chan);
924 925
	} else {
		/* Band only set if channel is not, since channel implies band */
926
		svSetValueStr (ifcfg, "BAND", nm_setting_wireless_get_band (s_wireless));
927 928 929
	}

	bssid = nm_setting_wireless_get_bssid (s_wireless);
930
	svSetValueStr (ifcfg, "BSSID", bssid);
931

932 933 934 935
	/* Ensure DEFAULTKEY and SECURITYMODE are cleared unless there's security;
	 * otherwise there's no way to detect WEP vs. open when WEP keys aren't
	 * saved.
	 */
936 937
	svUnsetValue (ifcfg, "DEFAULTKEY");
	svUnsetValue (ifcfg, "SECURITYMODE");
938

939
	if (nm_connection_get_setting_wireless_security (connection)) {
940
		if (!write_wireless_security_setting (connection, ifcfg, secrets, adhoc, no_8021x, error))
941
			return FALSE;
942 943
	} else {
		/* Clear out wifi security keys */
944 945
		svUnsetValue (ifcfg, "KEY_MGMT");
		svUnsetValue (ifcfg, "IEEE_8021X_IDENTITY");
946
		set_secret (ifcfg, secrets, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
947
		svUnsetValue (ifcfg, "SECURITYMODE");
948 949

		/* Clear existing keys */
950
		set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
951
		for (i = 0; i < 4; i++) {
952
			char tag[64];
953

954
			numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
955
			set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
956 957

			numbered_tag (tag, "KEY", i + 1);
958
			set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
959 960
		}

961 962 963 964 965
		svUnsetValue (ifcfg, "DEFAULTKEY");
		svUnsetValue (ifcfg, "WPA_ALLOW_WPA");
		svUnsetValue (ifcfg, "WPA_ALLOW_WPA2");
		svUnsetValue (ifcfg, "CIPHER_PAIRWISE");
		svUnsetValue (ifcfg, "CIPHER_GROUP");
966
		set_secret (ifcfg, secrets, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
967 968
	}

969
	svSetValueStr (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL);
970 971 972

	switch (nm_setting_wireless_get_powersave (s_wireless)) {
	case NM_SETTING_WIRELESS_POWERSAVE_IGNORE:
973
		svSetValueStr (ifcfg, "POWERSAVE", "ignore");
974 975
		break;
	case NM_SETTING_WIRELESS_POWERSAVE_DISABLE:
976
		svSetValueStr (ifcfg, "POWERSAVE", "disable");
977 978
		break;
	case NM_SETTING_WIRELESS_POWERSAVE_ENABLE:
979
		svSetValueStr (ifcfg, "POWERSAVE", "enable");
980 981 982
		break;
	default:
	case NM_SETTING_WIRELESS_POWERSAVE_DEFAULT:
983
		svUnsetValue (ifcfg, "POWERSAVE");
984 985
		break;
	}
986

987
	switch (nm_setting_wireless_get_mac_address_randomization (s_wireless)) {
988
	case NM_SETTING_MAC_RANDOMIZATION_NEVER:
989
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "never");
990 991
		break;
	case NM_SETTING_MAC_RANDOMIZATION_ALWAYS:
992
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "always");
993
		break;
994
	case NM_SETTING_MAC_RANDOMIZATION_DEFAULT:
995
	default:
996
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "default");
997 998 999
		break;
	}

1000
	svSetValueStr (ifcfg, "TYPE", TYPE_WIRELESS);
1001 1002 1003 1004

	return TRUE;
}

1005 1006 1007 1008
static gboolean
write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingInfiniband *s_infiniband;
1009
	const char *mac, *transport_mode, *parent;
1010
	guint32 mtu;
1011
	int p_key;
1012 1013 1014

	s_infiniband = nm_connection_get_setting_infiniband (connection);
	if (!s_infiniband) {
1015
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
1016 1017 1018 1019 1020
		             "Missing '%s' setting", NM_SETTING_INFINIBAND_SETTING_NAME);
		return FALSE;
	}

	mac = nm_setting_infiniband_get_mac_address (s_infiniband);
1021
	svSetValueStr (ifcfg, "HWADDR", mac);
1022 1023

	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
1024
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
1025 1026

	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
1027
	svSetValueBoolean (ifcfg, "CONNECTED_MODE", nm_streq (transport_mode, "connected"));
1028

1029 1030
	p_key = nm_setting_infiniband_get_p_key (s_infiniband);
	if (p_key != -1) {
1031
		svSetValueStr (ifcfg, "PKEY", "yes");
1032
		svSetValueInt64 (ifcfg, "PKEY_ID", p_key);
1033 1034 1035

		parent = nm_setting_infiniband_get_parent (s_infiniband);
		if (parent)
1036
			svSetValueStr (ifcfg, "PHYSDEV", parent);
1037 1038
	}

1039
	svSetValueStr (ifcfg, "TYPE", TYPE_INFINIBAND);
1040 1041 1042 1043

	return TRUE;
}

1044 1045 1046 1047
static gboolean
write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingWired *s_wired;
1048
	const char *const*s390_subchannels;
1049
	guint32 mtu, num_opts, i;
1050
	const char *const*macaddr_blacklist;
1051

1052
	s_wired = nm_connection_get_setting_wired (connection);
1053
	if (!s_wired) {
1054
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
1055 1056 1057 1058
		             "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME);
		return FALSE;
	}

1059 1060
	svSetValueStr (ifcfg, "HWADDR",
	               nm_setting_wired_get_mac_address (s_wired));
1061

1062 1063
	svSetValueStr (ifcfg, "MACADDR",
	               nm_setting_wired_get_cloned_mac_address (s_wired));
1064

1065 1066
	svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
	               nm_setting_wired_get_generate_mac_address_mask (s_wired));
1067

1068
	macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
1069
	if (macaddr_blacklist[0]) {
1070
		gs_free char *blacklist_str = NULL;
1071

1072
		blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist);
1073
		svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str);
1074 1075
	} else
		svUnsetValue (ifcfg, "HWADDR_BLACKLIST");
1076

1077
	mtu = nm_setting_wired_get_mtu (s_wired);
1078
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
1079

1080
	s390_subchannels = nm_setting_wired_get_s390_subchannels (s_wired);
1081

1082 1083 1084 1085
	{
		gs_free char *tmp = NULL;
		gsize len = NM_PTRARRAY_LEN (s390_subchannels);

1086
		if (len == 2) {
1087 1088 1089
			tmp = g_strdup_printf ("%s,%s",
			                       s390_subchannels[0],
			                       s390_subchannels[1]);
1090
		} else if (len == 3) {
1091 1092 1093
			tmp = g_strdup_printf ("%s,%s,%s",
			                       s390_subchannels[0],
			                       s390_subchannels[1],
1094
			                       s390_subchannels[2]);
1095
		}
1096

1097
		svSetValueStr (ifcfg, "SUBCHANNELS", tmp);
1098 1099
	}

1100 1101
	svSetValueStr (ifcfg, "NETTYPE",
	               nm_setting_wired_get_s390_nettype (s_wired));
1102

1103 1104
	svSetValueStr (ifcfg, "PORTNAME",
	               nm_setting_wired_get_s390_option_by_key (s_wired, "portname"));
1105

1106 1107
	svSetValueStr (ifcfg, "CTCPROT",
	               nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot"));
1108

1109
	svUnsetValue (ifcfg, "OPTIONS");
1110 1111
	num_opts = nm_setting_wired_get_num_s390_options (s_wired);
	if (s390_subchannels && num_opts) {
1112 1113
		nm_auto_free_gstring GString *tmp = NULL;

1114
		for (i = 0; i < num_opts; i++) {
1115 1116
			const char *s390_key, *s390_val;

1117 1118 1119
			nm_setting_wired_get_s390_option (s_wired, i, &s390_key, &s390_val);

			/* portname is handled separately */
1120
			if (!strcmp (s390_key, "portname") || !strcmp (s390_key, "ctcprot"))
1121 1122
				continue;

1123 1124 1125 1126 1127
			if (!tmp)
				tmp = g_string_sized_new (30);
			else
				g_string_append_c (tmp, ' ');
			g_string_append_printf (tmp, "%s=%s", s390_key, s390_val);
1128
		}
1129 1130
		if (tmp)
			svSetValueStr (ifcfg, "OPTIONS", tmp->str);
1131 1132
	}

1133 1134 1135 1136 1137 1138 1139 1140 1141
	svSetValueStr (ifcfg, "TYPE", TYPE_ETHERNET);

	return TRUE;
}

static gboolean
write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingWired *s_wired;
1142
	NMSettingEthtool *s_ethtool;
1143 1144 1145 1146 1147 1148 1149 1150
	const char *duplex;
	guint32 speed;
	GString *str = NULL;
	gboolean auto_negotiate;
	NMSettingWiredWakeOnLan wol;
	const char *wol_password;

	s_wired = nm_connection_get_setting_wired (connection);
1151
	s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL));
1152