nms-ifcfg-rh-writer.c 106 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 34
#include "nm-glib-aux/nm-enum-utils.h"
#include "nm-glib-aux/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-libnm-core-intern/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
              GError **error)
213
{
214
	NMSetting8021xCKScheme scheme;
215
	const char *value = NULL;
216
	GBytes *blob = NULL;
217 218 219
	const char *password = NULL;
	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
	char *secret_name, *secret_flags;
220
	const char *extension;
221
	char *standard_file;
222

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

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

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

254 255 256 257 258 259
	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";
260

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

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

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

279 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);
	svUnsetValue (ifcfg, objtype->ifcfg_rh_key);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	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;
311 312
		}

313 314 315 316
		/* 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.
		 */
317 318 319 320 321
		if (!nm_utils_file_set_contents (filename,
		                                 (const char *) g_bytes_get_data (blob, NULL),
		                                 g_bytes_get_size (blob),
		                                 0600,
		                                 &write_error)) {
322
			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
323 324 325 326
			             "Could not write certificate to file \"%s\": %s",
			             filename,
			             write_error->message);
			return FALSE;
327 328 329
		}
	}

330
	return TRUE;
331 332
}

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

	/* CA certificate */
344
	if (!write_object (s_8021x, ifcfg, secrets, blobs,
345 346 347 348
	                   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],
	                   error))
349 350 351
		return FALSE;

	/* Private key */
352
	if (phase2)
353
		otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY];
354
	else
355
		otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY];
356

357
	/* Save the private key */
358
	if (!write_object (s_8021x, ifcfg, secrets, blobs, otype, error))
359
		return FALSE;
360

361 362 363 364 365 366 367
	/* Save the client certificate */
	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],
	                   error))
		return FALSE;
368

369
	return TRUE;
370 371
}

372
static gboolean
373 374
write_8021x_setting (NMConnection *connection,
                     shvarFile *ifcfg,
375
                     GHashTable *secrets,
376
                     GHashTable *blobs,
377 378
                     gboolean wired,
                     GError **error)
379 380
{
	NMSetting8021x *s_8021x;
381
	NMSetting8021xAuthFlags auth_flags;
382
	const char *value, *match;
383 384
	gconstpointer ptr;
	GBytes* bytes;
385
	char *tmp = NULL;
386
	GString *phase2_auth;
387 388
	GString *str;
	guint32 i, num;
389
	gsize size;
390
	int vint;
391

392
	s_8021x = nm_connection_get_setting_802_1x (connection);
393 394 395
	if (!s_8021x) {
		/* If wired, clear KEY_MGMT */
		if (wired)
396
			svUnsetValue (ifcfg, "KEY_MGMT");
397
		return TRUE;
398 399 400 401
	}

	/* If wired, write KEY_MGMT */
	if (wired)
402
		svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X");
403 404 405 406 407 408 409

	/* 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);
	}
410
	svSetValueStr (ifcfg, "IEEE_8021X_EAP_METHODS", tmp);
411 412
	g_free (tmp);

413 414
	svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY",
	               nm_setting_802_1x_get_identity (s_8021x));
415

416 417
	svSetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY",
	               nm_setting_802_1x_get_anonymous_identity (s_8021x));
418

419
	set_secret (ifcfg,
420
	            secrets,
421 422
	            "IEEE_8021X_PASSWORD",
	            nm_setting_802_1x_get_password (s_8021x),
423
	            "IEEE_8021X_PASSWORD_FLAGS",
424
	            nm_setting_802_1x_get_password_flags (s_8021x));
425

426 427 428 429 430 431 432 433 434 435 436 437 438 439
	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);

440 441
	/* PEAP version */
	value = nm_setting_802_1x_get_phase1_peapver (s_8021x);
442
	svUnsetValue (ifcfg, "IEEE_8021X_PEAP_VERSION");
443
	if (value && (!strcmp (value, "0") || !strcmp (value, "1")))
444
		svSetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", value);
445 446 447

	/* Force new PEAP label */
	value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x);
448
	svUnsetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL");
449
	if (value && !strcmp (value, "1"))
450
		svSetValueStr (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes");
451

452 453
	/* PAC file */
	value = nm_setting_802_1x_get_pac_file (s_8021x);
454
	svUnsetValue (ifcfg, "IEEE_8021X_PAC_FILE");
455
	if (value)
456
		svSetValueStr (ifcfg, "IEEE_8021X_PAC_FILE", value);
457 458 459

	/* FAST PAC provisioning */
	value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
460
	svUnsetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
461 462
	if (value) {
		if (strcmp (value, "1") == 0)
463
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth");
464
		else if (strcmp (value, "2") == 0)
465
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth");
466
		else if (strcmp (value, "3") == 0)
467
			svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth");
468 469
	}

470
	/* Phase2 auth methods */
471
	svUnsetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
	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);
	}

491 492 493 494
	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 {
495 496 497
		svSetValueEnum (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS",
		                nm_setting_802_1x_auth_flags_get_type(),
		                auth_flags);
498 499
	}

500 501
	svSetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS",
	               phase2_auth->len ? phase2_auth->str : NULL);
502

503
	g_string_free (phase2_auth, TRUE);
504

505 506
	svSetValueStr (ifcfg, "IEEE_8021X_SUBJECT_MATCH",
	               nm_setting_802_1x_get_subject_match (s_8021x));
507

508 509
	svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH",
	               nm_setting_802_1x_get_phase2_subject_match (s_8021x));
510

511
	svUnsetValue (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES");
512 513 514 515 516 517 518 519 520
	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)
521
		svSetValueStr (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", str->str);
522 523
	g_string_free (str, TRUE);

524
	svUnsetValue (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES");
525 526 527 528 529 530 531 532 533
	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)
534
		svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", str->str);
535 536
	g_string_free (str, TRUE);

537 538 539 540
	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));
541

542 543 544
	vint = nm_setting_802_1x_get_auth_timeout (s_8021x);
	svSetValueInt64_cond (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", vint > 0, vint);

545
	if (!write_8021x_certs (s_8021x, secrets, blobs, FALSE, ifcfg, error))
546
		return FALSE;
547

548
	/* phase2/inner certs */
549
	if (!write_8021x_certs (s_8021x, secrets, blobs, TRUE, ifcfg, error))
550 551 552
		return FALSE;

	return TRUE;
553 554 555 556 557
}

static gboolean
write_wireless_security_setting (NMConnection *connection,
                                 shvarFile *ifcfg,
558
                                 GHashTable *secrets,
559 560 561 562 563
                                 gboolean adhoc,
                                 gboolean *no_8021x,
                                 GError **error)
{
	NMSettingWirelessSecurity *s_wsec;
564 565
	const char *key_mgmt, *auth_alg, *key, *proto, *cipher;
	const char *psk = NULL;
566
	gboolean wep = FALSE, wpa = FALSE, dynamic_wep = FALSE;
567
	NMSettingWirelessSecurityWpsMethod wps_method;
568 569 570 571
	char *tmp;
	guint32 i, num;
	GString *str;

572
	s_wsec = nm_connection_get_setting_wireless_security (connection);
573
	if (!s_wsec) {
574
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
575 576 577 578 579 580 581 582 583
		             "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);

584
	svUnsetValue (ifcfg, "DEFAULTKEY");
585 586

	if (!strcmp (key_mgmt, "none")) {
587
		svUnsetValue (ifcfg, "KEY_MGMT");
588 589 590
		wep = TRUE;
		*no_8021x = TRUE;
	} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
591
		svSetValueStr (ifcfg, "KEY_MGMT", "WPA-PSK");
592 593
		wpa = TRUE;
		*no_8021x = TRUE;
594 595 596 597
	} else if (!strcmp (key_mgmt, "sae")) {
		svSetValueStr (ifcfg, "KEY_MGMT", "SAE");
		wpa = TRUE;
		*no_8021x = TRUE;
598
	} else if (!strcmp (key_mgmt, "ieee8021x")) {
599
		svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X");
600
		dynamic_wep = TRUE;
601
	} else if (!strcmp (key_mgmt, "wpa-eap")) {
602
		svSetValueStr (ifcfg, "KEY_MGMT", "WPA-EAP");
603 604 605
		wpa = TRUE;
	}

606
	svUnsetValue (ifcfg, "SECURITYMODE");
607 608
	if (auth_alg) {
		if (!strcmp (auth_alg, "shared"))
609
			svSetValueStr (ifcfg, "SECURITYMODE", "restricted");
610
		else if (!strcmp (auth_alg, "open"))
611
			svSetValueStr (ifcfg, "SECURITYMODE", "open");
612
		else if (!strcmp (auth_alg, "leap")) {
613 614 615
			svSetValueStr (ifcfg, "SECURITYMODE", "leap");
			svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY",
			               nm_setting_wireless_security_get_leap_username (s_wsec));
616
			set_secret (ifcfg,
617
			            secrets,
618
			            "IEEE_8021X_PASSWORD",
619
			            nm_setting_wireless_security_get_leap_password (s_wsec),
620
			            "IEEE_8021X_PASSWORD_FLAGS",
621
			            nm_setting_wireless_security_get_leap_password_flags (s_wsec));
622 623 624 625
			*no_8021x = TRUE;
		}
	}

626 627 628 629 630 631 632
	/* 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);

633 634
	/* WEP keys */

635
	/* Clear any default key */
636
	set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
637

638 639
	/* Clear existing keys */
	for (i = 0; i < 4; i++) {
640
		char tag[64];
641

642
		numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
643
		set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
644 645

		numbered_tag (tag, "KEY", i + 1);
646
		set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
647 648 649
	}

	/* And write the new ones out */
650
	if (wep) {
651 652 653
		NMWepKeyType key_type;
		const char *key_type_str = NULL;

654
		/* Default WEP TX key index */
655
		svSetValueInt64 (ifcfg, "DEFAULTKEY", nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) + 1);
656

657 658 659 660 661 662 663 664 665 666 667 668
		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);
669

670
		for (i = 0; i < 4; i++) {
671 672
			key = nm_setting_wireless_security_get_wep_key (s_wsec, i);
			if (key) {
673 674 675
				gs_free char *ascii_key = NULL;
				char tag[64];
				gboolean key_valid = TRUE;
676

677 678 679 680
				/* Passphrase needs a different ifcfg key since with WEP, there
				 * are some passphrases that are indistinguishable from WEP hex
				 * keys.
				 */
681 682 683 684 685 686
				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;
				}
687

688
				if (key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
689
					numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
690
				else if (key_type == NM_WEP_KEY_TYPE_KEY) {
691
					numbered_tag (tag, "KEY", i + 1);
692

693 694 695 696 697
					/* Add 's:' prefix for ASCII keys */
					if (strlen (key) == 5 || strlen (key) == 13) {
						ascii_key = g_strdup_printf ("s:%s", key);
						key = ascii_key;
					}
698
				} else {
699
					g_warn_if_reached ();
700
					key_valid = FALSE;
701 702
				}

703
				if (key_valid) {
704
					set_secret (ifcfg,
705
					            secrets,
706
					            tag,
707 708
					            key,
					            "WEP_KEY_FLAGS",
709
					            nm_setting_wireless_security_get_wep_key_flags (s_wsec));
710
				}
711 712
			}
		}
713 714 715
	}

	/* WPA protos */
716 717
	svUnsetValue (ifcfg, "WPA_ALLOW_WPA");
	svUnsetValue (ifcfg, "WPA_ALLOW_WPA2");
718 719 720 721
	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"))
722
			svSetValueStr (ifcfg, "WPA_ALLOW_WPA", "yes");
723
		else if (proto && !strcmp (proto, "rsn"))
724
			svSetValueStr (ifcfg, "WPA_ALLOW_WPA2", "yes");
725 726 727
	}

	/* WPA Pairwise ciphers */
728
	svUnsetValue (ifcfg, "CIPHER_PAIRWISE");
729 730
	str = g_string_new (NULL);
	num = nm_setting_wireless_security_get_num_pairwise (s_wsec);
731 732
	for (i = 0; i < num; i++) {
		if (i > 0)
733 734
			g_string_append_c (str, ' ');
		cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i);
735 736 737 738 739 740 741 742 743

		/* 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);
		}
744
	}
745
	if (strlen (str->str) && (dynamic_wep == FALSE))
746
		svSetValueStr (ifcfg, "CIPHER_PAIRWISE", str->str);
747 748 749
	g_string_free (str, TRUE);

	/* WPA Group ciphers */
750
	svUnsetValue (ifcfg, "CIPHER_GROUP");
751 752
	str = g_string_new (NULL);
	num = nm_setting_wireless_security_get_num_groups (s_wsec);
753 754
	for (i = 0; i < num; i++) {
		if (i > 0)
755 756 757 758 759 760
			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);
	}
761
	if (strlen (str->str) && (dynamic_wep == FALSE))
762
		svSetValueStr (ifcfg, "CIPHER_GROUP", str->str);
763 764
	g_string_free (str, TRUE);

765
	if (wpa)
766
		psk = nm_setting_wireless_security_get_psk (s_wsec);
767 768

	set_secret (ifcfg,
769
	            secrets,
770 771 772
	            "WPA_PSK",
	            psk,
	            "WPA_PSK_FLAGS",
773
	            wpa ? nm_setting_wireless_security_get_psk_flags (s_wsec) : NM_SETTING_SECRET_FLAG_NONE);
774

775 776 777
	if (nm_setting_wireless_security_get_pmf (s_wsec) == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT)
		svUnsetValue (ifcfg, "PMF");
	else {
778 779
		svSetValueEnum (ifcfg, "PMF", nm_setting_wireless_security_pmf_get_type (),
		                nm_setting_wireless_security_get_pmf (s_wsec));
780 781
	}

782 783 784 785 786 787 788
	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));
	}

789 790 791 792 793 794
	return TRUE;
}

static gboolean
write_wireless_setting (NMConnection *connection,
                        shvarFile *ifcfg,
795
                        GHashTable *secrets,
796 797 798 799
                        gboolean *no_8021x,
                        GError **error)
{
	NMSettingWireless *s_wireless;
800 801 802
	GBytes *ssid;
	const guint8 *ssid_data;
	gsize ssid_len;
803 804
	const char *mode, *bssid;
	const char *device_mac, *cloned_mac;
805 806
	guint32 mtu, chan, i;
	gboolean adhoc = FALSE, hex_ssid = FALSE;
807
	const char *const*macaddr_blacklist;
808

809
	s_wireless = nm_connection_get_setting_wireless (connection);
810
	if (!s_wireless) {
811
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
812 813 814 815
		             "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}

816
	device_mac = nm_setting_wireless_get_mac_address (s_wireless);
817
	svSetValueStr (ifcfg, "HWADDR", device_mac);
818

819
	cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
820
	svSetValueStr (ifcfg, "MACADDR", cloned_mac);
821

822 823
	svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
	               nm_setting_wireless_get_generate_mac_address_mask (s_wireless));
824

825
	svUnsetValue (ifcfg, "HWADDR_BLACKLIST");
826
	macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
827 828
	if (macaddr_blacklist[0]) {
		char *blacklist_str;
829

830
		blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist);
831
		svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str);
832
		g_free (blacklist_str);
833 834
	}

835
	mtu = nm_setting_wireless_get_mtu (s_wireless);
836
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
837 838 839

	ssid = nm_setting_wireless_get_ssid (s_wireless);
	if (!ssid) {
840
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
841 842 843
		             "Missing SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}
844 845
	ssid_data = g_bytes_get_data (ssid, &ssid_len);
	if (!ssid_len || ssid_len > 32) {
846
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
847 848 849 850 851 852 853
		             "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.
	 */
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
	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;
			}
871 872 873 874 875 876 877
		}
	}

	if (hex_ssid) {
		GString *str;

		/* Hex SSIDs don't get quoted */
878
		str = g_string_sized_new (ssid_len * 2 + 3);
879
		g_string_append (str, "0x");
880 881
		for (i = 0; i < ssid_len; i++)
			g_string_append_printf (str, "%02X", ssid_data[i]);
882
		svSetValueStr (ifcfg, "ESSID", str->str);
883 884
		g_string_free (str, TRUE);
	} else {
885
		char buf[33];
886

887
		nm_assert (ssid_len <= 32);
888
		memcpy (buf, ssid_data, ssid_len);
889
		buf[ssid_len] = '\0';
890
		svSetValueStr (ifcfg, "ESSID", buf);
891 892 893
	}

	mode = nm_setting_wireless_get_mode (s_wireless);
894 895 896
	if (!mode)
		svUnsetValue(ifcfg, "MODE");
	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA))
897
		svSetValueStr (ifcfg, "MODE", "Managed");
898
	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
899
		svSetValueStr (ifcfg, "MODE", "Ad-Hoc");
900
		adhoc = TRUE;
901
	} else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_AP))
902
		svSetValueStr (ifcfg, "MODE", "Ap");
903
	else {
904
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
905 906 907 908 909
		             "Invalid mode '%s' in '%s' setting",
		             mode, NM_SETTING_WIRELESS_SETTING_NAME);
		return FALSE;
	}

910 911
	svUnsetValue (ifcfg, "CHANNEL");
	svUnsetValue (ifcfg, "BAND");
912 913
	chan = nm_setting_wireless_get_channel (s_wireless);
	if (chan) {
914
		svSetValueInt64 (ifcfg, "CHANNEL", chan);
915 916
	} else {
		/* Band only set if channel is not, since channel implies band */
917
		svSetValueStr (ifcfg, "BAND", nm_setting_wireless_get_band (s_wireless));
918 919 920
	}

	bssid = nm_setting_wireless_get_bssid (s_wireless);
921
	svSetValueStr (ifcfg, "BSSID", bssid);
922

923 924 925 926
	/* 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.
	 */
927 928
	svUnsetValue (ifcfg, "DEFAULTKEY");
	svUnsetValue (ifcfg, "SECURITYMODE");
929

930
	if (nm_connection_get_setting_wireless_security (connection)) {
931
		if (!write_wireless_security_setting (connection, ifcfg, secrets, adhoc, no_8021x, error))
932
			return FALSE;
933 934
	} else {
		/* Clear out wifi security keys */
935 936
		svUnsetValue (ifcfg, "KEY_MGMT");
		svUnsetValue (ifcfg, "IEEE_8021X_IDENTITY");
937
		set_secret (ifcfg, secrets, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
938
		svUnsetValue (ifcfg, "SECURITYMODE");
939 940

		/* Clear existing keys */
941
		set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
942
		for (i = 0; i < 4; i++) {
943
			char tag[64];
944

945
			numbered_tag (tag, "KEY_PASSPHRASE", i + 1);
946
			set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
947 948

			numbered_tag (tag, "KEY", i + 1);
949
			set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
950 951
		}

952 953 954 955 956
		svUnsetValue (ifcfg, "DEFAULTKEY");
		svUnsetValue (ifcfg, "WPA_ALLOW_WPA");
		svUnsetValue (ifcfg, "WPA_ALLOW_WPA2");
		svUnsetValue (ifcfg, "CIPHER_PAIRWISE");
		svUnsetValue (ifcfg, "CIPHER_GROUP");
957
		set_secret (ifcfg, secrets, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE);
958 959
	}

960
	svSetValueStr (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL);
961 962 963

	switch (nm_setting_wireless_get_powersave (s_wireless)) {
	case NM_SETTING_WIRELESS_POWERSAVE_IGNORE:
964
		svSetValueStr (ifcfg, "POWERSAVE", "ignore");
965 966
		break;
	case NM_SETTING_WIRELESS_POWERSAVE_DISABLE:
967
		svSetValueStr (ifcfg, "POWERSAVE", "disable");
968 969
		break;
	case NM_SETTING_WIRELESS_POWERSAVE_ENABLE:
970
		svSetValueStr (ifcfg, "POWERSAVE", "enable");
971 972 973
		break;
	default:
	case NM_SETTING_WIRELESS_POWERSAVE_DEFAULT:
974
		svUnsetValue (ifcfg, "POWERSAVE");
975 976
		break;
	}
977

978
	switch (nm_setting_wireless_get_mac_address_randomization (s_wireless)) {
979
	case NM_SETTING_MAC_RANDOMIZATION_NEVER:
980
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "never");
981 982
		break;
	case NM_SETTING_MAC_RANDOMIZATION_ALWAYS:
983
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "always");
984
		break;
985
	case NM_SETTING_MAC_RANDOMIZATION_DEFAULT:
986
	default:
987
		svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "default");
988 989 990
		break;
	}

991
	svSetValueStr (ifcfg, "TYPE", TYPE_WIRELESS);
992 993 994 995

	return TRUE;
}

996 997 998 999
static gboolean
write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingInfiniband *s_infiniband;
1000
	const char *mac, *transport_mode, *parent;
1001
	guint32 mtu;
1002
	int p_key;
1003 1004 1005

	s_infiniband = nm_connection_get_setting_infiniband (connection);
	if (!s_infiniband) {
1006
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
1007 1008 1009 1010 1011
		             "Missing '%s' setting", NM_SETTING_INFINIBAND_SETTING_NAME);
		return FALSE;
	}

	mac = nm_setting_infiniband_get_mac_address (s_infiniband);
1012
	svSetValueStr (ifcfg, "HWADDR", mac);
1013 1014

	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
1015
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
1016 1017

	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
1018
	svSetValueBoolean (ifcfg, "CONNECTED_MODE", nm_streq (transport_mode, "connected"));
1019

1020 1021
	p_key = nm_setting_infiniband_get_p_key (s_infiniband);
	if (p_key != -1) {
1022
		svSetValueStr (ifcfg, "PKEY", "yes");
1023
		svSetValueInt64 (ifcfg, "PKEY_ID", p_key);
1024 1025 1026

		parent = nm_setting_infiniband_get_parent (s_infiniband);
		if (parent)
1027
			svSetValueStr (ifcfg, "PHYSDEV", parent);
1028 1029
	}

1030
	svSetValueStr (ifcfg, "TYPE", TYPE_INFINIBAND);
1031 1032 1033 1034

	return TRUE;
}

1035 1036 1037 1038
static gboolean
write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingWired *s_wired;
1039
	const char *const*s390_subchannels;
1040
	guint32 mtu, num_opts, i;
1041
	const char *const*macaddr_blacklist;
1042

1043
	s_wired = nm_connection_get_setting_wired (connection);
1044
	if (!s_wired) {
1045
		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
1046 1047 1048 1049
		             "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME);
		return FALSE;
	}

1050 1051
	svSetValueStr (ifcfg, "HWADDR",
	               nm_setting_wired_get_mac_address (s_wired));
1052

1053 1054
	svSetValueStr (ifcfg, "MACADDR",
	               nm_setting_wired_get_cloned_mac_address (s_wired));
1055

1056 1057
	svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
	               nm_setting_wired_get_generate_mac_address_mask (s_wired));
1058

1059
	macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
1060
	if (macaddr_blacklist[0]) {
1061
		gs_free char *blacklist_str = NULL;
1062

1063
		blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist);
1064
		svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str);
1065 1066
	} else
		svUnsetValue (ifcfg, "HWADDR_BLACKLIST");
1067

1068
	mtu = nm_setting_wired_get_mtu (s_wired);
1069
	svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu);
1070

1071
	s390_subchannels = nm_setting_wired_get_s390_subchannels (s_wired);
1072

1073 1074 1075 1076
	{
		gs_free char *tmp = NULL;
		gsize len = NM_PTRARRAY_LEN (s390_subchannels);

1077
		if (len == 2) {
1078 1079 1080
			tmp = g_strdup_printf ("%s,%s",
			                       s390_subchannels[0],
			                       s390_subchannels[1]);
1081
		} else if (len == 3) {
1082 1083 1084
			tmp = g_strdup_printf ("%s,%s,%s",
			                       s390_subchannels[0],
			                       s390_subchannels[1],
1085
			                       s390_subchannels[2]);
1086
		}
1087

1088
		svSetValueStr (ifcfg, "SUBCHANNELS", tmp);
1089 1090
	}

1091 1092
	svSetValueStr (ifcfg, "NETTYPE",
	               nm_setting_wired_get_s390_nettype (s_wired));
1093

1094 1095
	svSetValueStr (ifcfg, "PORTNAME",
	               nm_setting_wired_get_s390_option_by_key (s_wired, "portname"));
1096

1097 1098
	svSetValueStr (ifcfg, "CTCPROT",
	               nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot"));
1099

1100
	svUnsetValue (ifcfg, "OPTIONS");
1101 1102
	num_opts = nm_setting_wired_get_num_s390_options (s_wired);
	if (s390_subchannels && num_opts) {
1103 1104
		nm_auto_free_gstring GString *tmp = NULL;

1105
		for (i = 0; i < num_opts; i++) {
1106 1107
			const char *s390_key, *s390_val;

1108 1109 1110
			nm_setting_wired_get_s390_option (s_wired, i, &s390_key, &s390_val);

			/* portname is handled separately */
1111
			if (!strcmp (s390_key, "portname") || !strcmp (s390_key, "ctcprot"))
1112 1113
				continue;

1114 1115 1116 1117 1118
			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);
1119
		}
1120 1121
		if (tmp)
			svSetValueStr (ifcfg, "OPTIONS", tmp->str);
1122 1123
	}

1124 1125 1126 1127 1128 1129 1130 1131 1132
	svSetValueStr (ifcfg, "TYPE", TYPE_ETHERNET);

	return TRUE;
}

static gboolean
write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
	NMSettingWired *s_wired;
1133
	NMSettingEthtool *s_ethtool;
1134 1135 1136 1137 1138 1139 1140 1141
	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);
1142
	s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL));
1143

1144 1145 1146
	if (!s_wired && !s_ethtool) {
		svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN");
		svUnsetValue (ifcfg, "ETHTOOL_OPTS");
1147
		return TRUE;
1148
	}
1149

1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221