nm-setting.c 47.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
19 20
 * Copyright 2007 - 2011 Red Hat, Inc.
 * Copyright 2007 - 2008 Novell, Inc.
21
 */
22

23
#include "nm-default.h"
24

25 26
#include <string.h>

27
#include "nm-setting.h"
28
#include "nm-setting-private.h"
29
#include "nm-setting-connection.h"
30
#include "nm-utils.h"
31
#include "nm-utils-private.h"
32

Dan Williams's avatar
Dan Williams committed
33 34 35 36 37 38 39
/**
 * SECTION:nm-setting
 * @short_description: Describes related configuration information
 * @include: nm-setting.h
 *
 * Each #NMSetting contains properties that describe configuration that applies
 * to a specific network layer (like IPv4 or IPv6 configuration) or device type
40
 * (like Ethernet, or Wi-Fi).  A collection of individual settings together
Dan Williams's avatar
Dan Williams committed
41 42 43 44 45
 * make up an #NMConnection. Each property is strongly typed and usually has
 * a number of allowed values.  See each #NMSetting subclass for a description
 * of properties and allowed values.
 */

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/**
 * nm_setting_error_quark:
 *
 * Registers an error quark for #NMSetting if necessary.
 *
 * Returns: the error quark used for NMSetting errors.
 **/
GQuark
nm_setting_error_quark (void)
{
	static GQuark quark;

	if (G_UNLIKELY (!quark))
		quark = g_quark_from_static_string ("nm-setting-error-quark");
	return quark;
}

63
G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT)
64

65 66 67
#define NM_SETTING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING, NMSettingPrivate))

typedef struct {
68 69 70 71 72 73 74 75
	const char *name;
	GType type;
	guint32 priority;
	GQuark error_quark;
} SettingInfo;

typedef struct {
	const SettingInfo *info;
76 77
} NMSettingPrivate;

78 79 80
enum {
	PROP_0,
	PROP_NAME,
81

82 83
	PROP_LAST
};
84

85
/*****************************************************************************/
86 87

static GHashTable *registered_settings = NULL;
88 89 90 91 92 93 94 95 96 97 98 99
static GHashTable *registered_settings_by_type = NULL;

static gboolean
_nm_gtype_equal (gconstpointer v1, gconstpointer v2)
{
	return *((const GType *) v1) == *((const GType *) v2);
}
static guint
_nm_gtype_hash (gconstpointer v)
{
	return *((const GType *) v);
}
100

101
static void
102 103
_ensure_registered (void)
{
104 105
	if (G_UNLIKELY (registered_settings == NULL)) {
		_nm_value_transforms_register ();
106
		registered_settings = g_hash_table_new (g_str_hash, g_str_equal);
107 108
		registered_settings_by_type = g_hash_table_new (_nm_gtype_hash, _nm_gtype_equal);
	}
109 110
}

111 112 113 114 115 116
static void __attribute__((constructor))
_ensure_registered_constructor (void)
{
	_ensure_registered ();
}

117 118 119 120 121 122 123 124
#define _ensure_setting_info(self, priv) \
	G_STMT_START { \
		NMSettingPrivate *_priv_esi = (priv); \
		if (G_UNLIKELY (!_priv_esi->info)) { \
			_priv_esi->info = _nm_setting_lookup_setting_by_type (G_OBJECT_TYPE (self)); \
			g_assert (_priv_esi->info); \
		} \
	} G_STMT_END
125

126
/*****************************************************************************/
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

/*
 * _nm_register_setting:
 * @name: the name of the #NMSetting object to register
 * @type: the #GType of the #NMSetting
 * @priority: the sort priority of the setting, see below
 * @error_quark: the setting's error quark
 *
 * INTERNAL ONLY: registers a setting's internal properties, like its priority
 * and its error quark type, with libnm-util.
 *
 * A setting's priority should roughly follow the OSI layer model, but it also
 * controls which settings get asked for secrets first.  Thus settings which
 * relate to things that must be working first, like hardware, should get a
 * higher priority than things which layer on top of the hardware.  For example,
 * the GSM/CDMA settings should provide secrets before the PPP setting does,
 * because a PIN is required to unlock the device before PPP can even start.
 * Even settings without secrets should be assigned the right priority.
 *
 * 0: reserved for the Connection setting
 *
148
 * 1: hardware-related settings like Ethernet, Wi-Fi, InfiniBand, Bridge, etc.
149 150 151 152 153
 * These priority 1 settings are also "base types", which means that at least
 * one of them is required for the connection to be valid, and their name is
 * valid in the 'type' property of the Connection setting.
 *
 * 2: hardware-related auxiliary settings that require a base setting to be
154
 * successful first, like Wi-Fi security, 802.1x, etc.
155 156 157 158 159 160 161
 *
 * 3: hardware-independent settings that are required before IP connectivity
 * can be established, like PPP, PPPoE, etc.
 *
 * 4: IP-level stuff
 */
void
162 163 164 165
(_nm_register_setting) (const char *name,
                        const GType type,
                        const guint32 priority,
                        const GQuark error_quark)
166 167 168
{
	SettingInfo *info;

169
	g_return_if_fail (name != NULL && *name);
170 171 172 173 174 175 176
	g_return_if_fail (type != G_TYPE_INVALID);
	g_return_if_fail (type != G_TYPE_NONE);
	g_return_if_fail (error_quark != 0);
	g_return_if_fail (priority <= 4);

	_ensure_registered ();

177 178 179 180 181
	if (G_LIKELY ((info = g_hash_table_lookup (registered_settings, name)))) {
		g_return_if_fail (info->type == type);
		g_return_if_fail (info->error_quark == error_quark);
		g_return_if_fail (info->priority == priority);
		g_return_if_fail (g_strcmp0 (info->name, name) == 0);
182
		return;
183 184
	}
	g_return_if_fail (g_hash_table_lookup (registered_settings_by_type, &type) == NULL);
185 186 187 188 189 190 191 192

	if (priority == 0)
		g_assert_cmpstr (name, ==, NM_SETTING_CONNECTION_SETTING_NAME);

	info = g_slice_new0 (SettingInfo);
	info->type = type;
	info->priority = priority;
	info->error_quark = error_quark;
193 194 195 196 197 198 199 200 201 202
	info->name = name;
	g_hash_table_insert (registered_settings, (void *) info->name, info);
	g_hash_table_insert (registered_settings_by_type, &info->type, info);
}

static const SettingInfo *
_nm_setting_lookup_setting_by_type (GType type)
{
	_ensure_registered ();
	return g_hash_table_lookup (registered_settings_by_type, &type);
203 204 205
}

static guint32
206
_get_setting_type_priority (GType type)
207
{
208 209 210
	const SettingInfo *info;

	g_return_val_if_fail (g_type_is_a (type, NM_TYPE_SETTING), G_MAXUINT32);
211

212 213
	info = _nm_setting_lookup_setting_by_type (type);
	return info->priority;
214 215
}

216 217 218 219 220 221 222 223 224 225 226
guint32
_nm_setting_get_setting_priority (NMSetting *setting)
{
	NMSettingPrivate *priv;

	g_return_val_if_fail (NM_IS_SETTING (setting), G_MAXUINT32);
	priv = NM_SETTING_GET_PRIVATE (setting);
	_ensure_setting_info (setting, priv);
	return priv->info->priority;
}

227
gboolean
228
_nm_setting_type_is_base_type (GType type)
229 230 231
{
	/* Historical oddity: PPPoE is a base-type even though it's not
	 * priority 1.  It needs to be sorted *after* lower-level stuff like
232
	 * Wi-Fi security or 802.1x for secrets, but it's still allowed as a
233 234
	 * base type.
	 */
235 236 237 238 239 240 241
	return _get_setting_type_priority (type) == 1 || (type == NM_TYPE_SETTING_PPPOE);
}

gboolean
_nm_setting_is_base_type (NMSetting *setting)
{
	return _nm_setting_type_is_base_type (G_OBJECT_TYPE (setting));
242 243 244 245 246 247 248 249 250 251 252 253
}

GType
_nm_setting_lookup_setting_type (const char *name)
{
	SettingInfo *info;

	g_return_val_if_fail (name != NULL, G_TYPE_NONE);

	_ensure_registered ();

	info = g_hash_table_lookup (registered_settings, name);
254
	return info ? info->type : G_TYPE_INVALID;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
}

GType
_nm_setting_lookup_setting_type_by_quark (GQuark error_quark)
{
	SettingInfo *info;
	GHashTableIter iter;

	_ensure_registered ();

	g_hash_table_iter_init (&iter, registered_settings);
	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) {
		if (info->error_quark == error_quark)
			return info->type;
	}
	return G_TYPE_INVALID;
}

273
int
274 275 276 277
_nm_setting_compare_priority (gconstpointer a, gconstpointer b)
{
	guint32 prio_a, prio_b;

278 279
	prio_a = _nm_setting_get_setting_priority ((NMSetting *) a);
	prio_b = _nm_setting_get_setting_priority ((NMSetting *) b);
280 281 282 283 284 285 286 287

	if (prio_a < prio_b)
		return -1;
	else if (prio_a == prio_b)
		return 0;
	return 1;
}

288
/*****************************************************************************/
289

290
static void
291
destroy_gvalue (gpointer data)
292
{
293
	GValue *value = (GValue *) data;
294

295 296
	g_value_unset (value);
	g_slice_free (GValue, value);
297 298
}

Dan Williams's avatar
Dan Williams committed
299 300 301
/**
 * nm_setting_to_hash:
 * @setting: the #NMSetting
302
 * @flags: hash flags, e.g. %NM_SETTING_HASH_FLAG_ALL
Dan Williams's avatar
Dan Williams committed
303 304 305
 *
 * Converts the #NMSetting into a #GHashTable mapping each setting property
 * name to a GValue describing that property, suitable for marshalling over
306
 * D-Bus or serializing.  The mapping is string to GValue.
307
 *
308 309
 * Returns: (transfer full) (element-type utf8 GObject.Value): a new #GHashTable
 * describing the setting's properties
Dan Williams's avatar
Dan Williams committed
310
 **/
311
GHashTable *
312
nm_setting_to_hash (NMSetting *setting, NMSettingHashFlags flags)
313
{
314 315 316 317
	GHashTable *hash;
	GParamSpec **property_specs;
	guint n_property_specs;
	guint i;
318

319
	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
320

321
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
322

323
	hash = g_hash_table_new_full (g_str_hash, g_str_equal,
324
	                              g_free, destroy_gvalue);
325

326 327
	for (i = 0; i < n_property_specs; i++) {
		GParamSpec *prop_spec = property_specs[i];
328
		GValue *value;
329

330 331
		/* 'name' doesn't get serialized */
		if (strcmp (g_param_spec_get_name (prop_spec), NM_SETTING_NAME) == 0)
332
			continue;
333

334 335 336
		if (   (flags & NM_SETTING_HASH_FLAG_NO_SECRETS)
		    && (prop_spec->flags & NM_SETTING_PARAM_SECRET))
			continue;
337

338 339 340 341 342 343 344 345 346 347 348 349 350
		if (   (flags & NM_SETTING_HASH_FLAG_ONLY_SECRETS)
		    && !(prop_spec->flags & NM_SETTING_PARAM_SECRET))
			continue;

		value = g_slice_new0 (GValue);
		g_value_init (value, prop_spec->value_type);
		g_object_get_property (G_OBJECT (setting), prop_spec->name, value);

		/* Don't serialize values with default values */
		if (!g_param_value_defaults (prop_spec, value))
			g_hash_table_insert (hash, g_strdup (prop_spec->name), value);
		else
			destroy_gvalue (value);
351 352
	}
	g_free (property_specs);
353

354
	return hash;
355 356
}

Dan Williams's avatar
Dan Williams committed
357 358 359
/**
 * nm_setting_new_from_hash:
 * @setting_type: the #NMSetting type which the hash contains properties for
360 361
 * @hash: (element-type utf8 GObject.Value): the #GHashTable containing a
 * string to GValue mapping of properties that apply to the setting
Dan Williams's avatar
Dan Williams committed
362 363 364 365 366 367 368
 *
 * Creates a new #NMSetting object and populates that object with the properties
 * contained in the hash table, using each hash key as the property to set,
 * and each hash value as the value to set that property to.  Setting properties
 * are strongly typed, thus the GValue type of the hash value must be correct.
 * See the documentation on each #NMSetting object subclass for the correct
 * property names and value types.
369
 *
Dan Williams's avatar
Dan Williams committed
370
 * Returns: a new #NMSetting object populated with the properties from the
371
 * hash table, or %NULL on failure
Dan Williams's avatar
Dan Williams committed
372
 **/
373
NMSetting *
374
nm_setting_new_from_hash (GType setting_type, GHashTable *hash)
375
{
376
	GHashTableIter iter;
377
	NMSetting *setting;
378 379 380
	const char *prop_name;
	GValue *src_value;
	GObjectClass *class;
381

382 383
	g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
	g_return_val_if_fail (hash != NULL, NULL);
384

385 386 387 388
	/* g_type_class_ref() ensures the setting class is created if it hasn't
	 * already been used.
	 */
	class = g_type_class_ref (setting_type);
389 390

	setting = (NMSetting *) g_object_new (setting_type, NULL);
391 392 393 394 395 396

	g_hash_table_iter_init (&iter, hash);
	while (g_hash_table_iter_next (&iter, (gpointer) &prop_name, (gpointer) &src_value)) {
		GParamSpec *param_spec;

		param_spec = g_object_class_find_property (class, prop_name);
397
		if (!param_spec) {
398 399 400
			/* Assume that any unrecognized property either can be ignored, or
			 * else has a backward-compatibility equivalent.
			 */
401 402 403
			continue;
		}

404
		(void) nm_g_object_set_property ((GObject *) setting, prop_name, src_value, NULL);
405
	}
406

407
	g_type_class_unref (class);
408

409
	return setting;
410 411
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
gboolean
_nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value)
{
	GParamSpec *prop_spec;

	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
	g_return_val_if_fail (property_name, FALSE);
	g_return_val_if_fail (value, FALSE);

	prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name);

	if (!prop_spec) {
		g_value_unset (value);
		return FALSE;
	}

	g_value_init (value, prop_spec->value_type);
	g_object_get_property (G_OBJECT (setting), property_name, value);
	return TRUE;
}

433 434
static void
duplicate_setting (NMSetting *setting,
435 436 437 438
                   const char *name,
                   const GValue *value,
                   GParamFlags flags,
                   gpointer user_data)
439
{
440
	if ((flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE)
441
		g_object_set_property (G_OBJECT (user_data), name, value);
442 443
}

Dan Williams's avatar
Dan Williams committed
444 445 446 447 448 449
/**
 * nm_setting_duplicate:
 * @setting: the #NMSetting to duplicate
 *
 * Duplicates a #NMSetting.
 *
450
 * Returns: (transfer full): a new #NMSetting containing the same properties and values as the
Dan Williams's avatar
Dan Williams committed
451 452
 * source #NMSetting
 **/
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
NMSetting *
nm_setting_duplicate (NMSetting *setting)
{
	GObject *dup;

	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);

	dup = g_object_new (G_OBJECT_TYPE (setting), NULL);

	g_object_freeze_notify (dup);
	nm_setting_enumerate_values (setting, duplicate_setting, dup);
	g_object_thaw_notify (dup);

	return NM_SETTING (dup);
}

469
static int
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
find_setting_by_name (gconstpointer a, gconstpointer b)
{
	NMSetting *setting = NM_SETTING (a);
	const char *str = (const char *) b;

	return strcmp (nm_setting_get_name (setting), str);
}

NMSetting *
nm_setting_find_in_list (GSList     *settings_list,
                         const char *setting_name)
{
	GSList *found;

	found = g_slist_find_custom (settings_list, setting_name, find_setting_by_name);
	if (found)
		return found->data;
	else
		return NULL;
}

Dan Williams's avatar
Dan Williams committed
491 492 493 494 495 496 497 498 499
/**
 * nm_setting_get_name:
 * @setting: the #NMSetting
 *
 * Returns the type name of the #NMSetting object
 *
 * Returns: a string containing the type name of the #NMSetting object,
 * like 'ppp' or 'wireless' or 'wired'.
 **/
500 501
const char *
nm_setting_get_name (NMSetting *setting)
502
{
503
	NMSettingPrivate *priv;
504

505 506 507 508
	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
	priv = NM_SETTING_GET_PRIVATE (setting);
	_ensure_setting_info (setting, priv);
	return priv->info->name;
509 510
}

Dan Williams's avatar
Dan Williams committed
511 512 513
/**
 * nm_setting_verify:
 * @setting: the #NMSetting to verify
514 515
 * @all_settings: (element-type NMSetting): a #GSList of all settings
 *     in the connection from which @setting came
Dan Williams's avatar
Dan Williams committed
516 517 518 519 520 521 522
 * @error: location to store error, or %NULL
 *
 * Validates the setting.  Each setting's properties have allowed values, and
 * some are dependent on other values (hence the need for @all_settings).  The
 * returned #GError contains information about which property of the setting
 * failed validation, and in what way that property failed validation.
 *
Dan Williams's avatar
Dan Williams committed
523
 * Returns: %TRUE if the setting is valid, %FALSE if it is not
Dan Williams's avatar
Dan Williams committed
524
 **/
525
gboolean
526
nm_setting_verify (NMSetting *setting, GSList *all_settings, GError **error)
527
{
528 529 530 531 532 533 534 535 536 537 538 539 540
	NMSettingVerifyResult result = _nm_setting_verify (setting, all_settings, error);

	if (result == NM_SETTING_VERIFY_NORMALIZABLE)
		g_clear_error (error);

	return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE;
}

NMSettingVerifyResult
_nm_setting_verify (NMSetting *setting, GSList *all_settings, GError **error)
{
	g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_VERIFY_ERROR);
	g_return_val_if_fail (!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
541

542
	if (NM_SETTING_GET_CLASS (setting)->verify)
543
		return NM_SETTING_GET_CLASS (setting)->verify (setting, all_settings, error);
544

545
	return NM_SETTING_VERIFY_SUCCESS;
546 547
}

548 549
static gboolean
compare_property (NMSetting *setting,
550 551 552
                  NMSetting *other,
                  const GParamSpec *prop_spec,
                  NMSettingCompareFlags flags)
553
{
554 555
	GValue value1 = G_VALUE_INIT;
	GValue value2 = G_VALUE_INIT;
556
	gboolean different;
557

558 559 560 561
	/* Handle compare flags */
	if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
		NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
		NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
562

563 564 565 566 567 568
		g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);

		if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL))
			g_return_val_if_reached (FALSE);
		if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL))
			g_return_val_if_reached (FALSE);
569

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
		/* If the secret flags aren't the same the settings aren't the same */
		if (a_secret_flags != b_secret_flags)
			return FALSE;

		/* Check for various secret flags that might cause us to ignore comparing
		 * this property.
		 */
		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
			return TRUE;

		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
			return TRUE;
	}

	g_value_init (&value1, prop_spec->value_type);
	g_object_get_property (G_OBJECT (setting), prop_spec->name, &value1);

	g_value_init (&value2, prop_spec->value_type);
	g_object_get_property (G_OBJECT (other), prop_spec->name, &value2);

	different = g_param_values_cmp ((GParamSpec *) prop_spec, &value1, &value2);

	g_value_unset (&value1);
	g_value_unset (&value2);

	return different == 0 ? TRUE : FALSE;
598 599
}

Dan Williams's avatar
Dan Williams committed
600 601 602 603 604 605 606 607 608 609
/**
 * nm_setting_compare:
 * @a: a #NMSetting
 * @b: a second #NMSetting to compare with the first
 * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
 *
 * Compares two #NMSetting objects for similarity, with comparison behavior
 * modified by a set of flags.  See the documentation for #NMSettingCompareFlags
 * for a description of each flag's behavior.
 *
Dan Williams's avatar
Dan Williams committed
610
 * Returns: %TRUE if the comparison succeeds, %FALSE if it does not
Dan Williams's avatar
Dan Williams committed
611
 **/
612
gboolean
Dan Williams's avatar
Dan Williams committed
613 614
nm_setting_compare (NMSetting *a,
                    NMSetting *b,
615
                    NMSettingCompareFlags flags)
616
{
617 618
	GParamSpec **property_specs;
	guint n_property_specs;
619
	int same = TRUE;
620
	guint i;
621

Dan Williams's avatar
Dan Williams committed
622 623
	g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
	g_return_val_if_fail (NM_IS_SETTING (b), FALSE);
624

625
	/* First check that both have the same type */
Dan Williams's avatar
Dan Williams committed
626
	if (G_OBJECT_TYPE (a) != G_OBJECT_TYPE (b))
627
		return FALSE;
628

629
	/* And now all properties */
Dan Williams's avatar
Dan Williams committed
630
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
631
	for (i = 0; i < n_property_specs && same; i++) {
632
		GParamSpec *prop_spec = property_specs[i];
633

634 635
		/* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
		if (   (flags & NM_SETTING_COMPARE_FLAG_FUZZY)
636
		    && (prop_spec->flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)))
637 638
			continue;

639 640 641
		if ((flags & NM_SETTING_COMPARE_FLAG_INFERRABLE) && !(prop_spec->flags & NM_SETTING_PARAM_INFERRABLE))
			continue;

642 643 644 645 646 647 648
		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
		    && (prop_spec->flags & NM_SETTING_PARAM_SECRET))
			continue;

		same = NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
	}
	g_free (property_specs);
649

650 651
	return same;
}
652

653
static gboolean
654 655 656 657 658 659 660 661 662
should_compare_prop (NMSetting *setting,
                     const char *prop_name,
                     NMSettingCompareFlags comp_flags,
                     GParamFlags prop_flags)
{
	/* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
	if (   (comp_flags & NM_SETTING_COMPARE_FLAG_FUZZY)
	    && (prop_flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)))
		return FALSE;
663

664 665 666
	if ((comp_flags & NM_SETTING_COMPARE_FLAG_INFERRABLE) && !(prop_flags & NM_SETTING_PARAM_INFERRABLE))
		return FALSE;

667 668 669 670 671 672
	if (prop_flags & NM_SETTING_PARAM_SECRET) {
		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;

		if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
			return FALSE;

673 674 675 676
		if (   NM_IS_SETTING_VPN (setting)
		    && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) {
			/* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET.
			 * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the
luz.paz's avatar
luz.paz committed
677
			 * setting accidentally uses a key "secrets". */
678 679 680 681 682
			return FALSE;
		}

		if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL))
			g_return_val_if_reached (FALSE);
683 684 685 686 687 688 689 690

		if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
		    && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
			return FALSE;

		if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
		    && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
			return FALSE;
691 692
	}

693 694 695 696
	if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID)
	    && NM_IS_SETTING_CONNECTION (setting)
	    && !strcmp (prop_name, NM_SETTING_CONNECTION_ID))
		return FALSE;
697

698
	return TRUE;
699 700
}

701 702 703 704 705 706 707
/**
 * nm_setting_diff:
 * @a: a #NMSetting
 * @b: a second #NMSetting to compare with the first
 * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
 * @invert_results: this parameter is used internally by libnm-util and should
 * be set to %FALSE.  If %TRUE inverts the meaning of the #NMSettingDiffResult.
708 709 710 711 712
 * @results: (inout) (transfer full) (element-type utf8 guint32): if the
 * settings differ, on return a hash table mapping the differing keys to one or
 * more %NMSettingDiffResult values OR-ed together.  If the settings do not
 * differ, any hash table passed in is unmodified.  If no hash table is passed
 * in and the settings differ, a new one is created and returned.
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
 *
 * Compares two #NMSetting objects for similarity, with comparison behavior
 * modified by a set of flags.  See the documentation for #NMSettingCompareFlags
 * for a description of each flag's behavior.  If the settings differ, the keys
 * of each setting that differ from the other are added to @results, mapped to
 * one or more #NMSettingDiffResult values.
 *
 * Returns: %TRUE if the settings contain the same values, %FALSE if they do not
 **/
gboolean
nm_setting_diff (NMSetting *a,
                 NMSetting *b,
                 NMSettingCompareFlags flags,
                 gboolean invert_results,
                 GHashTable **results)
{
	GParamSpec **property_specs;
	guint n_property_specs;
	guint i;
	NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A;
	NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B;
734 735
	NMSettingDiffResult a_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
	NMSettingDiffResult b_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
736 737 738 739 740 741 742 743 744
	gboolean results_created = FALSE;

	g_return_val_if_fail (results != NULL, FALSE);
	g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
	if (b) {
		g_return_val_if_fail (NM_IS_SETTING (b), FALSE);
		g_return_val_if_fail (G_OBJECT_TYPE (a) == G_OBJECT_TYPE (b), FALSE);
	}

745 746 747 748 749 750
	if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) ==
	             (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) {
		/* conflicting flags: default to WITH_DEFAULT (clearing NO_DEFAULT). */
		flags &= ~NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT;
	}

751 752 753 754 755 756 757 758 759 760 761 762
	/* If the caller is calling this function in a pattern like this to get
	 * complete diffs:
	 *
	 * nm_setting_diff (A, B, FALSE, &results);
	 * nm_setting_diff (B, A, TRUE, &results);
	 *
	 * and wants us to invert the results so that the second invocation comes
	 * out correctly, do that here.
	 */
	if (invert_results) {
		a_result = NM_SETTING_DIFF_RESULT_IN_B;
		b_result = NM_SETTING_DIFF_RESULT_IN_A;
763 764
		a_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
		b_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
765 766 767 768 769 770 771 772 773 774 775 776
	}

	if (*results == NULL) {
		*results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
		results_created = TRUE;
	}

	/* And now all properties */
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);

	for (i = 0; i < n_property_specs; i++) {
		GParamSpec *prop_spec = property_specs[i];
777
		NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
778 779 780 781 782 783 784 785

		/* Handle compare flags */
		if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags))
			continue;
		if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
			continue;

		if (b) {
786 787
			gboolean different;

788
			different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
789
			if (different) {
790
				gboolean a_is_default, b_is_default;
791
				GValue value = G_VALUE_INIT;
792

793 794
				g_value_init (&value, prop_spec->value_type);
				g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
795
				a_is_default = g_param_value_defaults (prop_spec, &value);
796 797 798

				g_value_reset (&value);
				g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
799
				b_is_default = g_param_value_defaults (prop_spec, &value);
800

801
				g_value_unset (&value);
802 803 804 805 806 807 808 809 810 811 812 813
				if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) {
					if (!a_is_default)
						r |= a_result;
					if (!b_is_default)
						r |= b_result;
				} else {
					r |= a_result | b_result;
					if (a_is_default)
						r |= a_result_default;
					if (b_is_default)
						r |= b_result_default;
				}
814
			}
815
		} else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0)
816
			r = a_result;  /* only in A */
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
		else {
			GValue value = G_VALUE_INIT;

			g_value_init (&value, prop_spec->value_type);
			g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
			if (!g_param_value_defaults (prop_spec, &value))
				r |= a_result;
			else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
				r |= a_result | a_result_default;

			g_value_unset (&value);
		}

		if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
			void *p;
832

833 834 835 836 837
			if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) {
				if ((r & GPOINTER_TO_UINT (p)) != r)
					g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p)));
			} else
				g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r));
838 839 840 841 842 843 844 845 846 847 848 849 850
		}
	}
	g_free (property_specs);

	/* Don't return an empty hash table */
	if (results_created && !g_hash_table_size (*results)) {
		g_hash_table_destroy (*results);
		*results = NULL;
	}

	return !(*results);
}

Dan Williams's avatar
Dan Williams committed
851 852 853
/**
 * nm_setting_enumerate_values:
 * @setting: the #NMSetting
854
 * @func: (scope call): user-supplied function called for each property of the setting
Dan Williams's avatar
Dan Williams committed
855 856 857 858 859
 * @user_data: user data passed to @func at each invocation
 *
 * Iterates over each property of the #NMSetting object, calling the supplied
 * user function for each property.
 **/
860 861
void
nm_setting_enumerate_values (NMSetting *setting,
862 863
                             NMSettingValueIterFn func,
                             gpointer user_data)
864
{
865 866
	GParamSpec **property_specs;
	guint n_property_specs;
867 868
	int i;

869 870
	g_return_if_fail (NM_IS_SETTING (setting));
	g_return_if_fail (func != NULL);
871

872 873 874
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
	for (i = 0; i < n_property_specs; i++) {
		GParamSpec *prop_spec = property_specs[i];
875
		GValue value = G_VALUE_INIT;
876

877 878
		g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
		g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
879
		func (setting, prop_spec->name, &value, prop_spec->flags, user_data);
880
		g_value_unset (&value);
881 882
	}

883
	g_free (property_specs);
884 885
}

Dan Williams's avatar
Dan Williams committed
886 887 888 889 890 891 892 893
/**
 * nm_setting_clear_secrets:
 * @setting: the #NMSetting
 *
 * Resets and clears any secrets in the setting.  Secrets should be added to the
 * setting only when needed, and cleared immediately after use to prevent
 * leakage of information.
 **/
894 895
void
nm_setting_clear_secrets (NMSetting *setting)
896 897 898 899 900 901
{
	_nm_setting_clear_secrets (setting);
}

gboolean
_nm_setting_clear_secrets (NMSetting *setting)
902
{
903 904 905
	GParamSpec **property_specs;
	guint n_property_specs;
	guint i;
906
	gboolean changed = FALSE;
907

908
	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
909

910
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
911

912 913
	for (i = 0; i < n_property_specs; i++) {
		GParamSpec *prop_spec = property_specs[i];
914

915
		if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
916 917
			GValue value = G_VALUE_INIT;

918
			g_value_init (&value, prop_spec->value_type);
919 920 921 922 923 924
			g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
			if (!g_param_value_defaults (prop_spec, &value)) {
				g_param_value_set_default (prop_spec, &value);
				g_object_set_property (G_OBJECT (setting), prop_spec->name, &value);
				changed = TRUE;
			}
925 926
			g_value_unset (&value);
		}
927 928
	}

929
	g_free (property_specs);
930 931

	return changed;
932 933
}

934
static gboolean
935
clear_secrets_with_flags (NMSetting *setting,
936 937 938
                          GParamSpec *pspec,
                          NMSettingClearSecretsWithFlagsFn func,
                          gpointer user_data)
939 940
{
	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
941
	gboolean changed = FALSE;
942

943 944
	g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);

945
	/* Clear the secret if the user function says to do so */
946 947 948
	if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL))
		g_return_val_if_reached (FALSE);

949
	if (func (setting, pspec->name, flags, user_data) == TRUE) {
950 951
		GValue value = G_VALUE_INIT;

952
		g_value_init (&value, pspec->value_type);
953 954 955 956 957 958
		g_object_get_property (G_OBJECT (setting), pspec->name, &value);
		if (!g_param_value_defaults (pspec, &value)) {
			g_param_value_set_default (pspec, &value);
			g_object_set_property (G_OBJECT (setting), pspec->name, &value);
			changed = TRUE;
		}
959 960
		g_value_unset (&value);
	}
961 962

	return changed;
963 964 965 966 967
}

/**
 * nm_setting_clear_secrets_with_flags:
 * @setting: the #NMSetting
968 969
 * @func: (scope call): function to be called to determine whether a
 *     specific secret should be cleared or not
970 971 972 973 974 975 976 977
 * @user_data: caller-supplied data passed to @func
 *
 * Clears and frees secrets determined by @func.
 **/
void
nm_setting_clear_secrets_with_flags (NMSetting *setting,
                                     NMSettingClearSecretsWithFlagsFn func,
                                     gpointer user_data)
978 979 980 981 982 983 984 985
{
	_nm_setting_clear_secrets_with_flags (setting, func, user_data);
}

gboolean
_nm_setting_clear_secrets_with_flags (NMSetting *setting,
                                      NMSettingClearSecretsWithFlagsFn func,
                                      gpointer user_data)
986 987 988 989
{
	GParamSpec **property_specs;
	guint n_property_specs;
	guint i;
990
	gboolean changed = FALSE;
991

992 993 994
	g_return_val_if_fail (setting, FALSE);
	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
	g_return_val_if_fail (func != NULL, FALSE);
995 996 997 998

	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
	for (i = 0; i < n_property_specs; i++) {
		if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) {
999 1000 1001 1002
			changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
			                                                                     property_specs[i],
			                                                                     func,
			                                                                     user_data);
1003 1004 1005 1006
		}
	}

	g_free (property_specs);
1007
	return changed;
1008 1009
}

Dan Williams's avatar
Dan Williams committed
1010 1011 1012 1013 1014 1015 1016 1017 1018
/**
 * nm_setting_need_secrets:
 * @setting: the #NMSetting
 *
 * Returns an array of property names for each secret which may be required
 * to make a successful connection.  The returned hints are only intended as a
 * guide to what secrets may be required, because in some circumstances, there
 * is no way to conclusively determine exactly which secrets are needed.
 *
1019 1020 1021 1022
 * Returns: (transfer container) (element-type utf8): a #GPtrArray containing
 * the property names of secrets of the #NMSetting which may be required; the
 * caller owns the array and must free it with g_ptr_array_free(), but must not
 * free the elements.
Dan Williams's avatar
Dan Williams committed
1023
 **/
1024 1025
GPtrArray *
nm_setting_need_secrets (NMSetting *setting)
1026
{
1027
	GPtrArray *secrets = NULL;
1028

1029
	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1030

1031 1032
	if (NM_SETTING_GET_CLASS (setting)->need_secrets)
		secrets = NM_SETTING_GET_CLASS (setting)->need_secrets (setting);
1033

1034
	return secrets;
1035 1036
}

1037
static int
1038
update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error)
1039
{
1040
	GParamSpec *prop_spec;
1041

1042
	prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key);
1043
	if (!prop_spec) {
1044 1045 1046 1047
		g_set_error (error,
		             NM_SETTING_ERROR,
		             NM_SETTING_ERROR_PROPERTY_NOT_FOUND,
		             "%s", key);
1048
		return NM_SETTING_UPDATE_SECRET_ERROR;
1049 1050
	}

1051 1052
	/* Silently ignore non-secrets */
	if (!(prop_spec->flags & NM_SETTING_PARAM_SECRET))
1053
		return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
Dan Williams's avatar
Dan Williams committed
1054

1055
	if (g_value_type_compatible (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (prop_spec))) {
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
		if (G_VALUE_HOLDS_STRING (value) && G_IS_PARAM_SPEC_STRING (prop_spec)) {
			/* String is expected to be a common case. Handle it specially and check whether
			 * the value is already set. Otherwise, we just reset the property and
			 * assume the value got modified. */
			char *v;

			g_object_get (G_OBJECT (setting), prop_spec->name, &v, NULL);
			if (g_strcmp0 (v, g_value_get_string (value)) == 0) {
				g_free (v);
				return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
			}
			g_free (v);
		}
1069
		g_object_set_property (G_OBJECT (setting), prop_spec->name, value);
1070 1071 1072 1073 1074 1075 1076
		return NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
	}
	g_set_error (error,
	             NM_SETTING_ERROR,
	             NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH,
	             "%s", key);
	return NM_SETTING_UPDATE_SECRET_ERROR;
1077 1078
}

1079 1080 1081
/**
 * nm_setting_update_secrets:
 * @setting: the #NMSetting
1082 1083
 * @secrets: (element-type utf8 GObject.Value): a #GHashTable mapping
 * string to #GValue of setting property names and secrets
1084 1085 1086 1087
 * @error: location to store error, or %NULL
 *
 * Update the setting's secrets, given a hash table of secrets intended for that
 * setting (deserialized from D-Bus for example).
1088
 *
1089 1090
 * Returns: %TRUE if the secrets were successfully updated, %FALSE on failure to
 * update one or more of the secrets.
1091 1092 1093
 **/
gboolean
nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **error)
1094 1095 1096 1097 1098 1099
{
	return _nm_setting_update_secrets (setting, secrets, error) != NM_SETTING_UPDATE_SECRET_ERROR;
}

NMSettingUpdateSecretResult
_nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **error)
1100
{
1101 1102 1103
	GHashTableIter iter;
	gpointer key, data;
	GError *tmp_error = NULL;
1104
	NMSettingUpdateSecretResult result = NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
1105

1106 1107
	g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_UPDATE_SECRET_ERROR);
	g_return_val_if_fail (secrets != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
1108
	if (error)
1109
		g_return_val_if_fail (*error == NULL, NM_SETTING_UPDATE_SECRET_ERROR);
1110

1111
	g_hash_table_iter_init (&iter, secrets);
1112
	while (g_hash_table_iter_next (&iter, &key, &data)) {
1113
		int success;
1114 1115
		const char *secret_key = (const char *) key;
		GValue *secret_value = (GValue *) data;
1116

1117 1118 1119 1120
		success = NM_SETTING_GET_CLASS (setting)->update_one_secret (setting, secret_key, secret_value, &tmp_error);
		g_assert (!((success == NM_SETTING_UPDATE_SECRET_ERROR) ^ (!!tmp_error)));

		if (success == NM_SETTING_UPDATE_SECRET_ERROR) {
1121
			g_propagate_error (error, tmp_error);
1122
			return NM_SETTING_UPDATE_SECRET_ERROR;
1123
		}
1124 1125 1126

		if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
			result = NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
1127 1128
	}

1129
	return result;
1130 1131
}

1132 1133 1134 1135 1136
static gboolean
is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
{
	GParamSpec *pspec;

1137
	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), secret_name);
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
	if (!pspec) {
		g_set_error (error,
		             NM_SETTING_ERROR,
		             NM_SETTING_ERROR_PROPERTY_NOT_FOUND,
		             "Secret %s not provided by this setting", secret_name);
		return FALSE;
	}

	if (!(pspec->flags & NM_SETTING_PARAM_SECRET)) {
		g_set_error (error,
		             NM_SETTING_ERROR,
		             NM_SETTING_ERROR_PROPERTY_NOT_SECRET,
		             "Property %s is not a secret", secret_name);
		return FALSE;
	}

	return TRUE;
}

static gboolean
get_secret_flags (NMSetting *setting,
                  const char *secret_name,
1160
                  gboolean verify_secret,
1161 1162 1163 1164
                  NMSettingSecretFlags *out_flags,
                  GError **error)
{
	char *flags_prop;
1165
	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
1166

1167 1168 1169 1170 1171
	if (verify_secret && !is_secret_prop (setting, secret_name, error)) {
		if (out_flags)
			*out_flags = NM_SETTING_SECRET_FLAG_NONE;
		return FALSE;
	}
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191

	flags_prop = g_strdup_printf ("%s-flags", secret_name);
	g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL);
	g_free (flags_prop);

	if (out_flags)
		*out_flags = flags;
	return TRUE;
}

/**
 * nm_setting_get_secret_flags:
 * @setting: the #NMSetting
 * @secret_name: the secret key name to get flags for
 * @out_flags: on success, the #NMSettingSecretFlags for the secret
 * @error: location to store error, or %NULL
 *
 * For a given secret, retrieves the #NMSettingSecretFlags describing how to
 * handle that secret.
 *
1192 1193
 * Returns: %TRUE on success (if the given secret name was a valid property of
 * this setting, and if that property is secret), %FALSE if not
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
 **/
gboolean
nm_setting_get_secret_flags (NMSetting *setting,
                             const char *secret_name,
                             NMSettingSecretFlags *out_flags,
                             GError **error)
{
	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
	g_return_val_if_fail (secret_name != NULL, FALSE);

1204
	return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error);
1205 1206 1207 1208 1209
}

static gboolean
set_secret_flags (NMSetting *setting,
                  const char *secret_name,
1210
                  gboolean verify_secret,
1211 1212 1213 1214 1215
                  NMSettingSecretFlags flags,
                  GError **error)
{
	char *flags_prop;

1216 1217
	if (verify_secret)
		g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE);
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231

	flags_prop = g_strdup_printf ("%s-flags", secret_name);
	g_object_set (G_OBJECT (setting), flags_prop, flags, NULL);
	g_free (flags_prop);
	return TRUE;
}

/**
 * nm_setting_set_secret_flags:
 * @setting: the #NMSetting
 * @secret_name: the secret key name to set flags for
 * @flags: the #NMSettingSecretFlags for the secret
 * @error: location to store error, or %NULL
 *
1232
 * For a given secret, stores the #NMSettingSecretFlags describing how to
1233 1234
 * handle that secret.
 *
1235 1236
 * Returns: %TRUE on success (if the given secret name was a valid property of
 * this setting, and if that property is secret), %FALSE if not
1237 1238 1239 1240 1241 1242 1243 1244 1245
 **/
gboolean
nm_setting_set_secret_flags (NMSetting *setting,
                             const char *secret_name,
                             NMSettingSecretFlags flags,
                             GError **error)
{
	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
	g_return_val_if_fail (secret_name != NULL, FALSE);
1246
	g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE);
1247

1248
	return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error);
1249 1250
}

Dan Williams's avatar
Dan Williams committed
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
/**
 * nm_setting_to_string:
 * @setting: the #NMSetting
 *
 * Convert the setting into a string.  For debugging purposes ONLY, should NOT
 * be used for serialization of the setting, or machine-parsed in any way. The
 * output format is not guaranteed to be stable and may change at any time.
 *
 * Returns: an allocated string containing a textual representation of the
 * setting's properties and values (including secrets!), which the caller should
 * free with g_free()
 **/
1263 1264
char *
nm_setting_to_string (NMSetting *setting)
1265
{
1266 1267 1268 1269
	GString *string;
	GParamSpec **property_specs;
	guint n_property_specs;
	guint i;
1270

1271
	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1272

1273
	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
1274

1275
	string = g_string_new (nm_setting_get_name (setting));
1276
	g_string_append_c (string, '\n');
1277

1278 1279
	for (i = 0; i < n_property_specs; i++) {
		GParamSpec *prop_spec = property_specs[i];
1280
		GValue value = G_VALUE_INIT;
1281 1282
		char *value_str;
		gboolean is_default;
1283

1284 1285 1286
		if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
			continue;

1287 1288
		g_value_init (&value, prop_spec->value_type);
		g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
1289

1290 1291 1292
		value_str = g_strdup_value_contents (&value);
		g_string_append_printf (string, "\t%s : %s", prop_spec->name, value_str);
		g_free (value_str);
1293

1294
		is_default = g_param_value_defaults (prop_spec, &value);
1295 1296
		g_value_unset (&value);

1297 1298 1299 1300 1301
		g_string_append (string, " (");
		g_string_append_c (string, 's');
		if (is_default)
			g_string_append_c (string, 'd');
		g_string_append_c (string, ')');
1302
		g_string_append_c (string, '\n');
1303 1304
	}

1305 1306
	g_free (property_specs);
	g_string_append_c (string, '\n');
1307

1308
	return g_string_free (string, FALSE);
1309 1310
}

1311 1312 1313 1314 1315 1316 1317
/**
 * nm_setting_get_virtual_iface_name:
 * @setting: the #NMSetting
 *
 * Returns the name of the virtual kernel interface which the connection
 * needs to use if specified in the settings.
 *
1318 1319
 * Returns: Name of the virtual interface or %NULL if the setting does not
 * support this feature
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
 **/
const char *
nm_setting_get_virtual_iface_name (NMSetting *setting)
{
	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);

	if (NM_SETTING_GET_CLASS (setting)->get_virtual_iface_name)
		return NM_SETTING_GET_CLASS (setting)->get_virtual_iface_name (setting);

	return NULL;
}

1332 1333 1334 1335 1336 1337
NMSettingVerifyResult
_nm_setting_verify_deprecated_virtual_iface_name (const char *interface_name,
                                                  gboolean allow_missing,
                                                  const char *setting_name,
                                                  const char *setting_property,
                                                  GQuark error_quark,
1338 1339
                                                  int e_invalid_property,
                                                  int e_missing_property,
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
                                                  GSList *all_settings,
                                                  GError **error)
{
	NMSettingConnection *s_con;
	const char *con_name;

	s_con = NM_SETTING_CONNECTION (nm_setting_find_in_list (all_settings, NM_SETTING_CONNECTION_SETTING_NAME));
	con_name = s_con ? nm_setting_connection_get_interface_name (s_con) : NULL;
	if (!interface_name && !con_name) {
		if (allow_missing)
			return NM_SETTING_VERIFY_SUCCESS;

		g_set_error_literal (error,
		                     NM_SETTING_CONNECTION_ERROR,
		                     NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY,
		                     _("property is missing"));
		g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME);
		return NM_SETTING_VERIFY_ERROR;
	}
	if (!con_name && !nm_utils_iface_valid_name (interface_name)) {
		/* the interface_name is invalid, we cannot normalize it. Only do this if !con_name,
		 * because if con_name is set, it can overwrite interface_name. */
		g_set_error_literal (error,
		                     error_quark,
		                     e_invalid_property,
		                     _("property is invalid"));
		g_prefix_error (error, "%s.%s: ", setting_name, setting_property);
		return NM_SETTING_VERIFY_ERROR;
	}
	if (!con_name) {
		/* NMSettingConnection has interface not set, it should be normalized to interface_name */
		g_set_error_literal (error,
		                     NM_SETTING_CONNECTION_ERROR,
		                     NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY,
		                     _("property is missing"));
		g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME);
		return NM_SETTING_VERIFY_NORMALIZABLE;
	}
	if (!nm_utils_iface_valid_name (con_name)) {
		/* NMSettingConnection:interface_name is invalid, we cannot normalize it. */
		g_set_error_literal (error,
		                     NM_SETTING_CONNECTION_ERROR,
		                     NM_SETTING_CONNECTION_ERROR_INVALID_PROPERTY,
		                     _("property is invalid"));
		g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME);
		return NM_SETTING_VERIFY_ERROR;
	}
	if (!interface_name) {
		/* Normalize by setting NMSettingConnection:interface_name. */
		g_set_error_literal (error,
		                     error_quark,
		                     e_missing_property,
		                     _("property is missing"));
		g_prefix_error (error, "%s.%s: ", setting_name, setting_property);
		return NM_SETTING_VERIFY_NORMALIZABLE;
	}
	if (strcmp (con_name, interface_name) != 0) {
		/* con_name and interface_name are different. It can be normalized by setting interface_name
		 * to con_name. */
		g_set_error_literal (error,
		                     error_quark,
1401
		                     e_invalid_property,
1402 1403
		                     _("property is invalid"));
		g_prefix_error (error, "%s.%s: ", setting_name, setting_property);
1404
		/* we would like to make this a NORMALIZABLE_ERROR, but that might
1405 1406 1407 1408 1409 1410 1411
		 * break older connections. */
		return NM_SETTING_VERIFY_NORMALIZABLE;
	}

	return NM_SETTING_VERIFY_SUCCESS;
}

1412
/*****************************************************************************/
1413

1414 1415
static void
nm_setting_init (NMSetting *setting)
1416
{
1417 1418
}

1419 1420
static GObject*
constructor (GType type,
1421 1422
             guint n_construct_params,
             GObjectConstructParam *construct_params)
1423 1424 1425 1426
{
	GObject *object;

	object = G_OBJECT_CLASS (nm_setting_parent_class)->constructor (type,
1427 1428
	                                                                n_construct_params,
	                                                                construct_params);
1429

1430
	_ensure_setting_info (object, NM_SETTING_GET_PRIVATE (object));
1431 1432 1433
	return object;
}

1434 1435
static void
set_property (GObject *object, guint prop_id,
1436
              const GValue *value, GParamSpec *pspec)
1437
{
1438
	NMSettingPrivate *priv = NM_SETTING_GET_PRIVATE (object);
1439

1440 1441
	switch (prop_id) {
	case PROP_NAME:
1442 1443 1444 1445 1446 1447 1448
		/* The setter for NAME is deprecated and should not be used anymore.
		 * Keep the setter for NAME to remain backward compatible.
		 * Only assert that the caller does not try to set the name to a different value
		 * then the registered name, which would be extra wrong.
		 **/
		_ensure_setting_info (object, priv);
		g_return_if_fail (!g_strcmp0 (priv->info->name, g_value_get_string (value)));
1449 1450 1451 1452 1453
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
1454 1455
}

1456 1457
static void
get_property (GObject *object, guint prop_id,
1458
              GValue *value, GParamSpec *pspec)
1459
{
1460
	NMSetting *setting = NM_SETTING (object);
1461