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 273 274 275 276 277
}

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;
}

gint
_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
	                              (GDestroyNotify) 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
Martin Pitt's avatar
Martin Pitt committed
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 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
static gint
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
	gint 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 654 655 656 657 658 659 660 661 662
static inline gboolean
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 677 678 679 680 681 682
		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
			 * setting accidently uses a key "secrets". */
			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));