libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
[NetworkManager.git] / libnm-core / nm-setting.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3 /*
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301 USA.
18  *
19  * Copyright 2007 - 2011 Red Hat, Inc.
20  * Copyright 2007 - 2008 Novell, Inc.
21  */
22
23 #include "nm-default.h"
24
25 #include "nm-setting.h"
26
27 #include <string.h>
28
29 #include "nm-setting-private.h"
30 #include "nm-utils.h"
31 #include "nm-core-internal.h"
32 #include "nm-utils-private.h"
33 #include "nm-property-compare.h"
34
35 #include "nm-setting-connection.h"
36 #include "nm-setting-bond.h"
37 #include "nm-setting-bridge.h"
38 #include "nm-setting-bridge-port.h"
39 #include "nm-setting-pppoe.h"
40 #include "nm-setting-team.h"
41 #include "nm-setting-team-port.h"
42 #include "nm-setting-vpn.h"
43
44 /**
45  * SECTION:nm-setting
46  * @short_description: Describes related configuration information
47  *
48  * Each #NMSetting contains properties that describe configuration that applies
49  * to a specific network layer (like IPv4 or IPv6 configuration) or device type
50  * (like Ethernet, or Wi-Fi).  A collection of individual settings together
51  * make up an #NMConnection. Each property is strongly typed and usually has
52  * a number of allowed values.  See each #NMSetting subclass for a description
53  * of properties and allowed values.
54  */
55
56 G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT)
57
58 #define NM_SETTING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING, NMSettingPrivate))
59
60 typedef struct {
61         const char *name;
62         GType type;
63         guint32 priority;
64 } SettingInfo;
65
66 typedef struct {
67         const SettingInfo *info;
68 } NMSettingPrivate;
69
70 enum {
71         PROP_0,
72         PROP_NAME,
73
74         PROP_LAST
75 };
76
77 /*************************************************************/
78
79 static GHashTable *registered_settings = NULL;
80 static GHashTable *registered_settings_by_type = NULL;
81
82 static gboolean
83 _nm_gtype_equal (gconstpointer v1, gconstpointer v2)
84 {
85         return *((const GType *) v1) == *((const GType *) v2);
86 }
87 static guint
88 _nm_gtype_hash (gconstpointer v)
89 {
90         return *((const GType *) v);
91 }
92
93 static void
94 _ensure_registered (void)
95 {
96         if (G_UNLIKELY (registered_settings == NULL)) {
97                 nm_g_type_init ();
98                 registered_settings = g_hash_table_new (g_str_hash, g_str_equal);
99                 registered_settings_by_type = g_hash_table_new (_nm_gtype_hash, _nm_gtype_equal);
100         }
101 }
102
103 static void __attribute__((constructor))
104 _ensure_registered_constructor (void)
105 {
106         _ensure_registered ();
107 }
108
109 #define _ensure_setting_info(self, priv) \
110         G_STMT_START { \
111                 NMSettingPrivate *_priv_esi = (priv); \
112                 if (G_UNLIKELY (!_priv_esi->info)) { \
113                         _priv_esi->info = _nm_setting_lookup_setting_by_type (G_OBJECT_TYPE (self)); \
114                         g_assert (_priv_esi->info); \
115                 } \
116         } G_STMT_END
117
118 /*************************************************************/
119
120 /*
121  * _nm_register_setting:
122  * @name: the name of the #NMSetting object to register
123  * @type: the #GType of the #NMSetting
124  * @priority: the sort priority of the setting, see below
125  *
126  * INTERNAL ONLY: registers a setting's internal properties with libnm.
127  *
128  * A setting's priority should roughly follow the OSI layer model, but it also
129  * controls which settings get asked for secrets first.  Thus settings which
130  * relate to things that must be working first, like hardware, should get a
131  * higher priority than things which layer on top of the hardware.  For example,
132  * the GSM/CDMA settings should provide secrets before the PPP setting does,
133  * because a PIN is required to unlock the device before PPP can even start.
134  * Even settings without secrets should be assigned the right priority.
135  *
136  * 0: reserved for the Connection setting
137  *
138  * 1: hardware-related settings like Ethernet, Wi-Fi, InfiniBand, Bridge, etc.
139  * These priority 1 settings are also "base types", which means that at least
140  * one of them is required for the connection to be valid, and their name is
141  * valid in the 'type' property of the Connection setting.
142  *
143  * 2: hardware-related auxiliary settings that require a base setting to be
144  * successful first, like Wi-Fi security, 802.1x, etc.
145  *
146  * 3: hardware-independent settings that are required before IP connectivity
147  * can be established, like PPP, PPPoE, etc.
148  *
149  * 4: IP-level stuff
150  */
151 void
152 (_nm_register_setting) (const char *name,
153                         const GType type,
154                         const guint32 priority)
155 {
156         SettingInfo *info;
157
158         g_return_if_fail (name != NULL && *name);
159         g_return_if_fail (type != G_TYPE_INVALID);
160         g_return_if_fail (type != G_TYPE_NONE);
161         g_return_if_fail (priority <= 4);
162
163         _ensure_registered ();
164
165         if (G_LIKELY ((info = g_hash_table_lookup (registered_settings, name)))) {
166                 g_return_if_fail (info->type == type);
167                 g_return_if_fail (info->priority == priority);
168                 g_return_if_fail (g_strcmp0 (info->name, name) == 0);
169                 return;
170         }
171         g_return_if_fail (g_hash_table_lookup (registered_settings_by_type, &type) == NULL);
172
173         if (priority == 0)
174                 g_assert_cmpstr (name, ==, NM_SETTING_CONNECTION_SETTING_NAME);
175
176         info = g_slice_new0 (SettingInfo);
177         info->type = type;
178         info->priority = priority;
179         info->name = name;
180         g_hash_table_insert (registered_settings, (void *) info->name, info);
181         g_hash_table_insert (registered_settings_by_type, &info->type, info);
182 }
183
184 static const SettingInfo *
185 _nm_setting_lookup_setting_by_type (GType type)
186 {
187         _ensure_registered ();
188         return g_hash_table_lookup (registered_settings_by_type, &type);
189 }
190
191 static guint32
192 _get_setting_type_priority (GType type)
193 {
194         const SettingInfo *info;
195
196         g_return_val_if_fail (g_type_is_a (type, NM_TYPE_SETTING), G_MAXUINT32);
197
198         info = _nm_setting_lookup_setting_by_type (type);
199         return info->priority;
200 }
201
202 guint32
203 _nm_setting_get_setting_priority (NMSetting *setting)
204 {
205         NMSettingPrivate *priv;
206
207         g_return_val_if_fail (NM_IS_SETTING (setting), G_MAXUINT32);
208         priv = NM_SETTING_GET_PRIVATE (setting);
209         _ensure_setting_info (setting, priv);
210         return priv->info->priority;
211 }
212
213 gboolean
214 _nm_setting_type_is_base_type (GType type)
215 {
216         /* Historical oddity: PPPoE is a base-type even though it's not
217          * priority 1.  It needs to be sorted *after* lower-level stuff like
218          * Wi-Fi security or 802.1x for secrets, but it's still allowed as a
219          * base type.
220          */
221         return _get_setting_type_priority (type) == 1 || (type == NM_TYPE_SETTING_PPPOE);
222 }
223
224 gboolean
225 _nm_setting_is_base_type (NMSetting *setting)
226 {
227         return _nm_setting_type_is_base_type (G_OBJECT_TYPE (setting));
228 }
229
230 /**
231  * nm_setting_lookup_type:
232  * @name: a setting name
233  *
234  * Returns the #GType of the setting's class for a given setting name.
235  *
236  * Returns: the #GType of the setting's class, or %G_TYPE_INVALID if
237  *   @name is not recognized.
238  **/
239 GType
240 nm_setting_lookup_type (const char *name)
241 {
242         SettingInfo *info;
243
244         g_return_val_if_fail (name != NULL, G_TYPE_INVALID);
245
246         _ensure_registered ();
247
248         info = g_hash_table_lookup (registered_settings, name);
249         return info ? info->type : G_TYPE_INVALID;
250 }
251
252 gint
253 _nm_setting_compare_priority (gconstpointer a, gconstpointer b)
254 {
255         guint32 prio_a, prio_b;
256
257         prio_a = _nm_setting_get_setting_priority ((NMSetting *) a);
258         prio_b = _nm_setting_get_setting_priority ((NMSetting *) b);
259
260         if (prio_a < prio_b)
261                 return -1;
262         else if (prio_a == prio_b)
263                 return 0;
264         return 1;
265 }
266
267 /*************************************************************/
268
269 gboolean
270 _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_type)
271 {
272         const char *port_type = NULL;
273         gboolean found = TRUE;
274
275         if (!slave_type)
276                 found = FALSE;
277         else if (!strcmp (slave_type, NM_SETTING_BOND_SETTING_NAME))
278                 ;
279         else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME))
280                 port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME;
281         else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME))
282                 port_type = NM_SETTING_TEAM_PORT_SETTING_NAME;
283         else
284                 found = FALSE;
285
286         if (out_port_type)
287                 *out_port_type = port_type;
288         return found;
289 }
290
291 /*************************************************************/
292
293 typedef struct {
294         const char *name;
295         GParamSpec *param_spec;
296         const GVariantType *dbus_type;
297
298         NMSettingPropertyGetFunc get_func;
299         NMSettingPropertySynthFunc synth_func;
300         NMSettingPropertySetFunc set_func;
301         NMSettingPropertyNotSetFunc not_set_func;
302
303         NMSettingPropertyTransformToFunc to_dbus;
304         NMSettingPropertyTransformFromFunc from_dbus;
305 } NMSettingProperty;
306
307 static GQuark setting_property_overrides_quark;
308 static GQuark setting_properties_quark;
309
310 static NMSettingProperty *
311 find_property (GArray *properties, const char *name)
312 {
313         NMSettingProperty *property;
314         int i;
315
316         if (!properties)
317                 return NULL;
318
319         for (i = 0; i < properties->len; i++) {
320                 property = &g_array_index (properties, NMSettingProperty, i);
321                 if (strcmp (name, property->name) == 0)
322                         return property;
323         }
324
325         return NULL;
326 }
327
328 static void
329 add_property_override (NMSettingClass *setting_class,
330                        const char *property_name,
331                        GParamSpec *param_spec,
332                        const GVariantType *dbus_type,
333                        NMSettingPropertyGetFunc get_func,
334                        NMSettingPropertySynthFunc synth_func,
335                        NMSettingPropertySetFunc set_func,
336                        NMSettingPropertyNotSetFunc not_set_func,
337                        NMSettingPropertyTransformToFunc to_dbus,
338                        NMSettingPropertyTransformFromFunc from_dbus)
339 {
340         GType setting_type = G_TYPE_FROM_CLASS (setting_class);
341         GArray *overrides;
342         NMSettingProperty override;
343
344         g_return_if_fail (g_type_get_qdata (setting_type, setting_properties_quark) == NULL);
345
346         memset (&override, 0, sizeof (override));
347         override.name = property_name;
348         override.param_spec = param_spec;
349         override.dbus_type = dbus_type;
350         override.get_func = get_func;
351         override.synth_func = synth_func;
352         override.set_func = set_func;
353         override.not_set_func = not_set_func;
354         override.to_dbus = to_dbus;
355         override.from_dbus = from_dbus;
356
357         overrides = g_type_get_qdata (setting_type, setting_property_overrides_quark);
358         if (!overrides) {
359                 overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
360                 g_type_set_qdata (setting_type, setting_property_overrides_quark, overrides);
361         }
362         g_return_if_fail (find_property (overrides, property_name) == NULL);
363
364         g_array_append_val (overrides, override);
365 }
366
367 /**
368  * _nm_setting_class_add_dbus_only_property:
369  * @setting_class: the setting class
370  * @property_name: the name of the property to override
371  * @dbus_type: the type of the property (in its D-Bus representation)
372  * @synth_func: (allow-none): function to call to synthesize a value for the property
373  * @set_func: (allow-none): function to call to set the value of the property
374  *
375  * Registers a property named @property_name, which will be used in the D-Bus
376  * serialization of objects of @setting_class, but which does not correspond to
377  * a #GObject property.
378  *
379  * When serializing a setting to D-Bus, @synth_func will be called to synthesize
380  * a value for the property. (If it returns %NULL, no value will be added to the
381  * serialization. If @synth_func is %NULL, the property will always be omitted
382  * in the serialization.)
383  *
384  * When deserializing a D-Bus representation into a setting, if @property_name
385  * is present, then @set_func will be called to set it. (If @set_func is %NULL
386  * then the property will be ignored when deserializing.)
387  */
388 void
389 _nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class,
390                                           const char *property_name,
391                                           const GVariantType *dbus_type,
392                                           NMSettingPropertySynthFunc synth_func,
393                                           NMSettingPropertySetFunc set_func)
394 {
395         g_return_if_fail (NM_IS_SETTING_CLASS (setting_class));
396         g_return_if_fail (property_name != NULL);
397
398         /* Must not match any GObject property. */
399         g_return_if_fail (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), property_name));
400
401         add_property_override (setting_class,
402                                property_name, NULL, dbus_type,
403                                NULL, synth_func, set_func, NULL,
404                                NULL, NULL);
405 }
406
407 /**
408  * _nm_setting_class_override_property:
409  * @setting_class: the setting class
410  * @property_name: the name of the property to override
411  * @dbus_type: the type of the property (in its D-Bus representation)
412  * @get_func: (allow-none): function to call to get the value of the property
413  * @set_func: (allow-none): function to call to set the value of the property
414  * @not_set_func: (allow-none): function to call to indicate the property was not set
415  *
416  * Overrides the D-Bus representation of the #GObject property named
417  * @property_name on @setting_class.
418  *
419  * When serializing a setting to D-Bus, if @get_func is non-%NULL, then it will
420  * be called to get the property's value. If it returns a #GVariant, the
421  * property will be added to the hash, and if it returns %NULL, the property
422  * will be omitted. (If @get_func is %NULL, the property will be read normally
423  * with g_object_get_property(), and added to the hash if it is not the default
424  * value.)
425  *
426  * When deserializing a D-Bus representation into a setting, if @property_name
427  * is present, then @set_func will be called to set it. (If @set_func is %NULL
428  * then the property will be set normally with g_object_set_property().)
429  *
430  * If @not_set_func is non-%NULL, then it will be called when deserializing a
431  * representation that does NOT contain @property_name. This can be used, eg, if
432  * a new property needs to be initialized from some older deprecated property
433  * when it is not present.
434  */
435 void
436 _nm_setting_class_override_property (NMSettingClass *setting_class,
437                                      const char *property_name,
438                                      const GVariantType *dbus_type,
439                                      NMSettingPropertyGetFunc get_func,
440                                      NMSettingPropertySetFunc set_func,
441                                      NMSettingPropertyNotSetFunc not_set_func)
442 {
443         GParamSpec *param_spec;
444
445         param_spec = g_object_class_find_property (G_OBJECT_CLASS (setting_class), property_name);
446         g_return_if_fail (param_spec != NULL);
447
448         add_property_override (setting_class,
449                                property_name, param_spec, dbus_type,
450                                get_func, NULL, set_func, not_set_func,
451                                NULL, NULL);
452 }
453
454 /**
455  * _nm_setting_class_transform_property:
456  * @setting_class: the setting class
457  * @property: the name of the property to transform
458  * @dbus_type: the type of the property (in its D-Bus representation)
459  * @to_dbus: function to convert from object to D-Bus format
460  * @from_dbus: function to convert from D-Bus to object format
461  *
462  * Indicates that @property on @setting_class does not have the same format as
463  * its corresponding D-Bus representation, and so must be transformed when
464  * serializing/deserializing.
465  *
466  * The transformation will also be used by nm_setting_compare(), meaning that
467  * the underlying object property does not need to be of a type that
468  * nm_property_compare() recognizes, as long as it recognizes @dbus_type.
469  */
470 void
471 _nm_setting_class_transform_property (NMSettingClass *setting_class,
472                                       const char *property,
473                                       const GVariantType *dbus_type,
474                                       NMSettingPropertyTransformToFunc to_dbus,
475                                       NMSettingPropertyTransformFromFunc from_dbus)
476 {
477         GParamSpec *param_spec;
478
479         param_spec = g_object_class_find_property (G_OBJECT_CLASS (setting_class), property);
480         g_return_if_fail (param_spec != NULL);
481
482         add_property_override (setting_class,
483                                property, param_spec, dbus_type,
484                                NULL, NULL, NULL, NULL,
485                                to_dbus, from_dbus);
486 }
487
488 gboolean
489 _nm_setting_use_legacy_property (NMSetting *setting,
490                                  GVariant *connection_dict,
491                                  const char *legacy_property,
492                                  const char *new_property)
493 {
494         GVariant *setting_dict, *value;
495
496         setting_dict = g_variant_lookup_value (connection_dict, nm_setting_get_name (NM_SETTING (setting)), NM_VARIANT_TYPE_SETTING);
497         g_return_val_if_fail (setting_dict != NULL, FALSE);
498
499         /* If the new property isn't set, we have to use the legacy property. */
500         value = g_variant_lookup_value (setting_dict, new_property, NULL);
501         if (!value) {
502                 g_variant_unref (setting_dict);
503                 return TRUE;
504         }
505         g_variant_unref (value);
506
507         /* Otherwise, clients always prefer new properties sent from the daemon. */
508         if (!_nm_utils_is_manager_process) {
509                 g_variant_unref (setting_dict);
510                 return FALSE;
511         }
512
513         /* The daemon prefers the legacy property if it exists. */
514         value = g_variant_lookup_value (setting_dict, legacy_property, NULL);
515         g_variant_unref (setting_dict);
516
517         if (value) {
518                 g_variant_unref (value);
519                 return TRUE;
520         } else
521                 return FALSE;
522 }
523
524 static GArray *
525 nm_setting_class_ensure_properties (NMSettingClass *setting_class)
526 {
527         GType type = G_TYPE_FROM_CLASS (setting_class), otype;
528         NMSettingProperty property, *override;
529         GArray *overrides, *type_overrides, *properties;
530         GParamSpec **property_specs;
531         guint n_property_specs, i;
532
533         properties = g_type_get_qdata (type, setting_properties_quark);
534         if (properties)
535                 return properties;
536
537         /* Build overrides array from @setting_class and its superclasses */
538         overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
539         for (otype = type; otype != G_TYPE_OBJECT; otype = g_type_parent (otype)) {
540                 type_overrides = g_type_get_qdata (otype, setting_property_overrides_quark);
541                 if (type_overrides)
542                         g_array_append_vals (overrides, (NMSettingProperty *)type_overrides->data, type_overrides->len);
543         }
544
545         /* Build the properties array from the GParamSpecs, obeying overrides */
546         properties = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
547
548         property_specs = g_object_class_list_properties (G_OBJECT_CLASS (setting_class),
549                                                          &n_property_specs);
550         for (i = 0; i < n_property_specs; i++) {
551                 override = find_property (overrides, property_specs[i]->name);
552                 if (override)
553                         property = *override;
554                 else {
555                         memset (&property, 0, sizeof (property));
556                         property.name = property_specs[i]->name;
557                         property.param_spec = property_specs[i];
558                 }
559                 g_array_append_val (properties, property);
560         }
561         g_free (property_specs);
562
563         /* Add any remaining overrides not corresponding to GObject properties */
564         for (i = 0; i < overrides->len; i++) {
565                 override = &g_array_index (overrides, NMSettingProperty, i);
566                 if (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), override->name))
567                         g_array_append_val (properties, *override);
568         }
569         g_array_unref (overrides);
570
571         g_type_set_qdata (type, setting_properties_quark, properties);
572         return properties;
573 }
574
575 static const NMSettingProperty *
576 nm_setting_class_get_properties (NMSettingClass *setting_class, guint *n_properties)
577 {
578         GArray *properties;
579
580         properties = nm_setting_class_ensure_properties (setting_class);
581
582         *n_properties = properties->len;
583         return (NMSettingProperty *) properties->data;
584 }
585
586 static const NMSettingProperty *
587 nm_setting_class_find_property (NMSettingClass *setting_class, const char *property_name)
588 {
589         GArray *properties;
590
591         properties = nm_setting_class_ensure_properties (setting_class);
592         return find_property (properties, property_name);
593 }
594
595 /*************************************************************/
596
597 static const GVariantType *
598 variant_type_for_gtype (GType type)
599 {
600         if (type == G_TYPE_BOOLEAN)
601                 return G_VARIANT_TYPE_BOOLEAN;
602         else if (type == G_TYPE_UCHAR)
603                 return G_VARIANT_TYPE_BYTE;
604         else if (type == G_TYPE_INT)
605                 return G_VARIANT_TYPE_INT32;
606         else if (type == G_TYPE_UINT)
607                 return G_VARIANT_TYPE_UINT32;
608         else if (type == G_TYPE_INT64)
609                 return G_VARIANT_TYPE_INT64;
610         else if (type == G_TYPE_UINT64)
611                 return G_VARIANT_TYPE_UINT64;
612         else if (type == G_TYPE_STRING)
613                 return G_VARIANT_TYPE_STRING;
614         else if (type == G_TYPE_DOUBLE)
615                 return G_VARIANT_TYPE_DOUBLE;
616         else if (type == G_TYPE_STRV)
617                 return G_VARIANT_TYPE_STRING_ARRAY;
618         else if (type == G_TYPE_BYTES)
619                 return G_VARIANT_TYPE_BYTESTRING;
620         else if (g_type_is_a (type, G_TYPE_ENUM))
621                 return G_VARIANT_TYPE_INT32;
622         else if (g_type_is_a (type, G_TYPE_FLAGS))
623                 return G_VARIANT_TYPE_UINT32;
624         else
625                 g_assert_not_reached ();
626 }
627
628 static GVariant *
629 get_property_for_dbus (NMSetting *setting,
630                        const NMSettingProperty *property,
631                        gboolean ignore_default)
632 {
633         GValue prop_value = { 0, };
634         GVariant *dbus_value;
635
636         if (property->get_func)
637                 return property->get_func (setting, property->name);
638         else
639                 g_return_val_if_fail (property->param_spec != NULL, NULL);
640
641         g_value_init (&prop_value, property->param_spec->value_type);
642         g_object_get_property (G_OBJECT (setting), property->param_spec->name, &prop_value);
643
644         if (ignore_default && g_param_value_defaults (property->param_spec, &prop_value)) {
645                 g_value_unset (&prop_value);
646                 return NULL;
647         }
648
649         if (property->to_dbus)
650                 dbus_value = property->to_dbus (&prop_value);
651         else if (property->dbus_type)
652                 dbus_value = g_dbus_gvalue_to_gvariant (&prop_value, property->dbus_type);
653         else if (g_type_is_a (prop_value.g_type, G_TYPE_ENUM))
654                 dbus_value = g_variant_new_int32 (g_value_get_enum (&prop_value));
655         else if (g_type_is_a (prop_value.g_type, G_TYPE_FLAGS))
656                 dbus_value = g_variant_new_uint32 (g_value_get_flags (&prop_value));
657         else if (prop_value.g_type == G_TYPE_BYTES)
658                 dbus_value = _nm_utils_bytes_to_dbus (&prop_value);
659         else
660                 dbus_value = g_dbus_gvalue_to_gvariant (&prop_value, variant_type_for_gtype (prop_value.g_type));
661         g_value_unset (&prop_value);
662
663         return dbus_value;
664 }
665
666 static gboolean
667 set_property_from_dbus (const NMSettingProperty *property,
668                         GVariant *src_value,
669                         GValue *dst_value)
670 {
671         g_return_val_if_fail (property->param_spec != NULL, FALSE);
672
673         if (property->from_dbus) {
674                 if (!g_variant_type_equal (g_variant_get_type (src_value), property->dbus_type))
675                         return FALSE;
676
677                 property->from_dbus (src_value, dst_value);
678         } else if (dst_value->g_type == G_TYPE_BYTES) {
679                 if (!g_variant_is_of_type (src_value, G_VARIANT_TYPE_BYTESTRING))
680                         return FALSE;
681
682                 _nm_utils_bytes_from_dbus (src_value, dst_value);
683         } else {
684                 GValue tmp = G_VALUE_INIT;
685
686                 g_dbus_gvariant_to_gvalue (src_value, &tmp);
687                 if (G_VALUE_TYPE (&tmp) == G_VALUE_TYPE (dst_value))
688                         *dst_value = tmp;
689                 else {
690                         gboolean success;
691
692                         success = g_value_transform (&tmp, dst_value);
693                         g_value_unset (&tmp);
694                         if (!success)
695                                 return FALSE;
696                 }
697         }
698
699         return TRUE;
700 }
701
702
703 /**
704  * _nm_setting_to_dbus:
705  * @setting: the #NMSetting
706  * @connection: the #NMConnection containing @setting
707  * @flags: hash flags, e.g. %NM_CONNECTION_SERIALIZE_ALL
708  *
709  * Converts the #NMSetting into a #GVariant of type #NM_VARIANT_TYPE_SETTING
710  * mapping each setting property name to a value describing that property,
711  * suitable for marshalling over D-Bus or serializing.
712  *
713  * Returns: (transfer none): a new floating #GVariant describing the setting's
714  * properties
715  **/
716 GVariant *
717 _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionSerializationFlags flags)
718 {
719         GVariantBuilder builder;
720         GVariant *dbus_value;
721         const NMSettingProperty *properties;
722         guint n_properties, i;
723
724         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
725
726         properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties);
727
728         g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
729
730         for (i = 0; i < n_properties; i++) {
731                 const NMSettingProperty *property = &properties[i];
732                 GParamSpec *prop_spec = property->param_spec;
733
734                 if (!prop_spec && !property->synth_func) {
735                         /* D-Bus-only property with no synth_func, so we skip it. */
736                         continue;
737                 }
738
739                 if (prop_spec && !(prop_spec->flags & G_PARAM_WRITABLE))
740                         continue;
741
742                 if (   prop_spec && (prop_spec->flags & NM_SETTING_PARAM_LEGACY)
743                     && !_nm_utils_is_manager_process)
744                         continue;
745
746                 if (   (flags & NM_CONNECTION_SERIALIZE_NO_SECRETS)
747                     && (prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET)))
748                         continue;
749
750                 if (   (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
751                     && !(prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET)))
752                         continue;
753
754                 if (property->synth_func)
755                         dbus_value = property->synth_func (setting, connection, property->name);
756                 else
757                         dbus_value = get_property_for_dbus (setting, property, TRUE);
758                 if (dbus_value) {
759                         /* Allow dbus_value to be either floating or not. */
760                         g_variant_take_ref (dbus_value);
761
762                         g_variant_builder_add (&builder, "{sv}", property->name, dbus_value);
763                         g_variant_unref (dbus_value);
764                 }
765         }
766
767         return g_variant_builder_end (&builder);
768 }
769
770 /**
771  * _nm_setting_new_from_dbus:
772  * @setting_type: the #NMSetting type which the hash contains properties for
773  * @setting_dict: the #GVariant containing an %NM_VARIANT_TYPE_SETTING dictionary
774  *   mapping property names to values
775  * @connection_dict: the #GVariant containing an %NM_VARIANT_TYPE_CONNECTION
776  *   dictionary mapping setting names to dictionaries.
777  * @parse_flags: flags to determine behavior during parsing.
778  * @error: location to store error, or %NULL
779  *
780  * Creates a new #NMSetting object and populates that object with the properties
781  * contained in @setting_dict, using each key as the property to set, and each
782  * value as the value to set that property to.  Setting properties are strongly
783  * typed, thus the #GVariantType of the dict value must be correct.  See the
784  * documentation on each #NMSetting object subclass for the correct property
785  * names and value types.
786  *
787  * Returns: a new #NMSetting object populated with the properties from the
788  * hash table, or %NULL if @setting_hash could not be deserialized.
789  **/
790 NMSetting *
791 _nm_setting_new_from_dbus (GType setting_type,
792                            GVariant *setting_dict,
793                            GVariant *connection_dict,
794                            NMSettingParseFlags parse_flags,
795                            GError **error)
796 {
797         gs_unref_object NMSetting *setting = NULL;
798         gs_unref_hashtable GHashTable *keys = NULL;
799         const NMSettingProperty *properties;
800         guint i, n_properties;
801
802         g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
803         g_return_val_if_fail (g_variant_is_of_type (setting_dict, NM_VARIANT_TYPE_SETTING), NULL);
804
805         nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
806         nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
807
808         /* connection_dict is not technically optional, but some tests in test-general
809          * don't bother with it in cases where they know it's not needed.
810          */
811         if (connection_dict)
812                 g_return_val_if_fail (g_variant_is_of_type (connection_dict, NM_VARIANT_TYPE_CONNECTION), NULL);
813
814         /* Build the setting object from the properties we know about; we assume
815          * that any propreties in @setting_dict that we don't know about can
816          * either be ignored or else has a backward-compatibility equivalent
817          * that we do know about.
818          */
819         setting = (NMSetting *) g_object_new (setting_type, NULL);
820
821         if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
822                 GVariantIter iter;
823                 GVariant *entry, *entry_key;
824                 char *key;
825
826                 keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
827
828                 g_variant_iter_init (&iter, setting_dict);
829                 while ((entry = g_variant_iter_next_value (&iter))) {
830                         entry_key = g_variant_get_child_value (entry, 0);
831                         key = g_strdup (g_variant_get_string (entry_key, NULL));
832                         g_variant_unref (entry_key);
833                         g_variant_unref (entry);
834
835                         if (!nm_g_hash_table_add (keys, key)) {
836                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
837                                              _("duplicate property"));
838                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
839                                 return NULL;
840                         }
841                 }
842         }
843
844         properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties);
845         for (i = 0; i < n_properties; i++) {
846                 const NMSettingProperty *property = &properties[i];
847                 gs_unref_variant GVariant *value = NULL;
848                 gs_free_error GError *local = NULL;
849
850                 if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE))
851                         continue;
852
853                 value = g_variant_lookup_value (setting_dict, property->name, NULL);
854
855                 if (value && keys)
856                         g_hash_table_remove (keys, property->name);
857
858                 if (value && property->set_func) {
859
860                         if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) {
861                                 /* for backward behavior, fail unless best-effort is chosen. */
862                                 if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
863                                         continue;
864                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
865                                              _("can't set property of type '%s' from value of type '%s'"),
866                                              property->dbus_type ?
867                                                  g_variant_type_peek_string (property->dbus_type) :
868                                                  property->param_spec ?
869                                                      g_type_name (property->param_spec->value_type) : "(unknown)",
870                                              g_variant_get_type_string (value));
871                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
872                                 return NULL;
873                         }
874
875                         if (!property->set_func (setting,
876                                                  connection_dict,
877                                                  property->name,
878                                                  value,
879                                                  parse_flags,
880                                                  &local)) {
881                                 if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
882                                         continue;
883                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
884                                              _("failed to set property: %s"),
885                                              local->message);
886                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
887                                 return NULL;
888                         }
889                 } else if (!value && property->not_set_func) {
890                         if (!property->not_set_func (setting,
891                                                      connection_dict,
892                                                      property->name,
893                                                      parse_flags,
894                                                      &local)) {
895                                 if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
896                                         continue;
897                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
898                                              _("failed to set property: %s"),
899                                              local->message);
900                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
901                                 return NULL;
902                         }
903                 } else if (value && property->param_spec) {
904                         nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
905
906                         g_value_init (&object_value, property->param_spec->value_type);
907                         if (!set_property_from_dbus (property, value, &object_value)) {
908                                 /* for backward behavior, fail unless best-effort is chosen. */
909                                 if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
910                                         continue;
911                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
912                                              _("can't set property of type '%s' from value of type '%s'"),
913                                              property->dbus_type ?
914                                                  g_variant_type_peek_string (property->dbus_type) :
915                                                  property->param_spec ?
916                                                      g_type_name (property->param_spec->value_type) : "(unknown)",
917                                              g_variant_get_type_string (value));
918                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
919                                 return NULL;
920                         }
921
922                         if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) {
923                                 if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
924                                         continue;
925                                 g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
926                                              _("can not set property: %s"),
927                                              local->message);
928                                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
929                                 return NULL;
930                         }
931                 }
932         }
933
934         if (   NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
935             && g_hash_table_size (keys) > 0) {
936                 GHashTableIter iter;
937                 const char *key;
938
939                 g_hash_table_iter_init (&iter, keys);
940                 if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
941                         g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
942                                      _("unknown property"));
943                         g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
944                         return NULL;
945                 }
946         }
947
948         return nm_unauto (&setting);
949 }
950
951 /**
952  * nm_setting_get_dbus_property_type:
953  * @setting: an #NMSetting
954  * @property_name: the property of @setting to get the type of
955  *
956  * Gets the D-Bus marshalling type of a property. @property_name is a D-Bus
957  * property name, which may not necessarily be a #GObject property.
958  *
959  * Returns: the D-Bus marshalling type of @property on @setting.
960  */
961 const GVariantType *
962 nm_setting_get_dbus_property_type (NMSetting *setting,
963                                    const char *property_name)
964 {
965         const NMSettingProperty *property;
966
967         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
968         g_return_val_if_fail (property_name != NULL, NULL);
969
970         property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), property_name);
971         g_return_val_if_fail (property != NULL, NULL);
972
973         if (property->dbus_type)
974                 return property->dbus_type;
975         else
976                 return variant_type_for_gtype (property->param_spec->value_type);
977 }
978
979 gboolean
980 _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value)
981 {
982         GParamSpec *prop_spec;
983
984         g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
985         g_return_val_if_fail (property_name, FALSE);
986         g_return_val_if_fail (value, FALSE);
987
988         prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name);
989
990         if (!prop_spec) {
991                 g_value_unset (value);
992                 return FALSE;
993         }
994
995         g_value_init (value, prop_spec->value_type);
996         g_object_get_property (G_OBJECT (setting), property_name, value);
997         return TRUE;
998 }
999
1000 static void
1001 duplicate_setting (NMSetting *setting,
1002                    const char *name,
1003                    const GValue *value,
1004                    GParamFlags flags,
1005                    gpointer user_data)
1006 {
1007         if ((flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE)
1008                 g_object_set_property (G_OBJECT (user_data), name, value);
1009 }
1010
1011 /**
1012  * nm_setting_duplicate:
1013  * @setting: the #NMSetting to duplicate
1014  *
1015  * Duplicates a #NMSetting.
1016  *
1017  * Returns: (transfer full): a new #NMSetting containing the same properties and values as the
1018  * source #NMSetting
1019  **/
1020 NMSetting *
1021 nm_setting_duplicate (NMSetting *setting)
1022 {
1023         GObject *dup;
1024
1025         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1026
1027         dup = g_object_new (G_OBJECT_TYPE (setting), NULL);
1028
1029         g_object_freeze_notify (dup);
1030         nm_setting_enumerate_values (setting, duplicate_setting, dup);
1031         g_object_thaw_notify (dup);
1032
1033         return NM_SETTING (dup);
1034 }
1035
1036 /**
1037  * nm_setting_get_name:
1038  * @setting: the #NMSetting
1039  *
1040  * Returns the type name of the #NMSetting object
1041  *
1042  * Returns: a string containing the type name of the #NMSetting object,
1043  * like 'ppp' or 'wireless' or 'wired'.
1044  **/
1045 const char *
1046 nm_setting_get_name (NMSetting *setting)
1047 {
1048         NMSettingPrivate *priv;
1049
1050         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1051         priv = NM_SETTING_GET_PRIVATE (setting);
1052         _ensure_setting_info (setting, priv);
1053         return priv->info->name;
1054 }
1055
1056 /**
1057  * nm_setting_verify:
1058  * @setting: the #NMSetting to verify
1059  * @connection: (allow-none): the #NMConnection that @setting came from, or
1060  *   %NULL if @setting is being verified in isolation.
1061  * @error: location to store error, or %NULL
1062  *
1063  * Validates the setting.  Each setting's properties have allowed values, and
1064  * some are dependent on other values (hence the need for @connection).  The
1065  * returned #GError contains information about which property of the setting
1066  * failed validation, and in what way that property failed validation.
1067  *
1068  * Returns: %TRUE if the setting is valid, %FALSE if it is not
1069  **/
1070 gboolean
1071 nm_setting_verify (NMSetting *setting, NMConnection *connection, GError **error)
1072 {
1073         NMSettingVerifyResult result = _nm_setting_verify (setting, connection, error);
1074
1075         if (result == NM_SETTING_VERIFY_NORMALIZABLE)
1076                 g_clear_error (error);
1077
1078         return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE;
1079 }
1080
1081 NMSettingVerifyResult
1082 _nm_setting_verify (NMSetting *setting, NMConnection *connection, GError **error)
1083 {
1084         g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_VERIFY_ERROR);
1085         g_return_val_if_fail (!connection || NM_IS_CONNECTION (connection), NM_SETTING_VERIFY_ERROR);
1086         g_return_val_if_fail (!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
1087
1088         if (NM_SETTING_GET_CLASS (setting)->verify)
1089                 return NM_SETTING_GET_CLASS (setting)->verify (setting, connection, error);
1090
1091         return NM_SETTING_VERIFY_SUCCESS;
1092 }
1093
1094 /**
1095  * nm_setting_verify_secrets:
1096  * @setting: the #NMSetting to verify secrets in
1097  * @connection: (allow-none): the #NMConnection that @setting came from, or
1098  *   %NULL if @setting is being verified in isolation.
1099  * @error: location to store error, or %NULL
1100  *
1101  * Verifies the secrets in the setting.
1102  * The returned #GError contains information about which secret of the setting
1103  * failed validation, and in what way that secret failed validation.
1104  * The secret validation is done separately from main setting validation, because
1105  * in some cases connection failure is not desired just for the secrets.
1106  *
1107  * Returns: %TRUE if the setting secrets are valid, %FALSE if they are not
1108  *
1109  * Since: 1.2
1110  **/
1111 gboolean
1112 nm_setting_verify_secrets (NMSetting *setting, NMConnection *connection, GError **error)
1113 {
1114         g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_VERIFY_ERROR);
1115         g_return_val_if_fail (!connection || NM_IS_CONNECTION (connection), NM_SETTING_VERIFY_ERROR);
1116         g_return_val_if_fail (!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
1117
1118         if (NM_SETTING_GET_CLASS (setting)->verify_secrets)
1119                 return NM_SETTING_GET_CLASS (setting)->verify_secrets (setting, connection, error);
1120
1121         return NM_SETTING_VERIFY_SUCCESS;
1122 }
1123
1124 gboolean
1125 _nm_setting_verify_secret_string (const char *str,
1126                                   const char *setting_name,
1127                                   const char *property,
1128                                   GError **error)
1129 {
1130         if (str && !*str) {
1131                 g_set_error_literal (error,
1132                                      NM_CONNECTION_ERROR,
1133                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
1134                                      _("property is empty"));
1135                 g_prefix_error (error, "%s.%s: ", setting_name, property);
1136                 return FALSE;
1137         }
1138         return TRUE;
1139 }
1140
1141 static gboolean
1142 compare_property (NMSetting *setting,
1143                   NMSetting *other,
1144                   const GParamSpec *prop_spec,
1145                   NMSettingCompareFlags flags)
1146 {
1147         const NMSettingProperty *property;
1148         GVariant *value1, *value2;
1149         int cmp;
1150
1151         /* Handle compare flags */
1152         if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
1153                 NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
1154                 NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
1155
1156                 g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
1157
1158                 if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL))
1159                         g_return_val_if_reached (FALSE);
1160                 if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL))
1161                         g_return_val_if_reached (FALSE);
1162
1163                 /* If the secret flags aren't the same the settings aren't the same */
1164                 if (a_secret_flags != b_secret_flags)
1165                         return FALSE;
1166
1167                 /* Check for various secret flags that might cause us to ignore comparing
1168                  * this property.
1169                  */
1170                 if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
1171                     && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
1172                         return TRUE;
1173
1174                 if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
1175                     && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
1176                         return TRUE;
1177         }
1178
1179         property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), prop_spec->name);
1180         g_return_val_if_fail (property != NULL, FALSE);
1181
1182         value1 = get_property_for_dbus (setting, property, TRUE);
1183         value2 = get_property_for_dbus (other, property, TRUE);
1184
1185         cmp = nm_property_compare (value1, value2);
1186
1187         if (value1)
1188                 g_variant_unref (value1);
1189         if (value2)
1190                 g_variant_unref (value2);
1191
1192         return cmp == 0;
1193 }
1194
1195 /**
1196  * nm_setting_compare:
1197  * @a: a #NMSetting
1198  * @b: a second #NMSetting to compare with the first
1199  * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
1200  *
1201  * Compares two #NMSetting objects for similarity, with comparison behavior
1202  * modified by a set of flags.  See the documentation for #NMSettingCompareFlags
1203  * for a description of each flag's behavior.
1204  *
1205  * Returns: %TRUE if the comparison succeeds, %FALSE if it does not
1206  **/
1207 gboolean
1208 nm_setting_compare (NMSetting *a,
1209                     NMSetting *b,
1210                     NMSettingCompareFlags flags)
1211 {
1212         GParamSpec **property_specs;
1213         guint n_property_specs;
1214         gint same = TRUE;
1215         guint i;
1216
1217         g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
1218         g_return_val_if_fail (NM_IS_SETTING (b), FALSE);
1219
1220         /* First check that both have the same type */
1221         if (G_OBJECT_TYPE (a) != G_OBJECT_TYPE (b))
1222                 return FALSE;
1223
1224         /* And now all properties */
1225         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
1226         for (i = 0; i < n_property_specs && same; i++) {
1227                 GParamSpec *prop_spec = property_specs[i];
1228
1229                 /* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
1230                 if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY)
1231                     && !NM_FLAGS_ANY (prop_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
1232                         continue;
1233
1234                 if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
1235                     && !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_INFERRABLE))
1236                         continue;
1237
1238                 if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
1239                     && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
1240                         continue;
1241
1242                 if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
1243                     && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
1244                         continue;
1245
1246                 same = NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
1247         }
1248         g_free (property_specs);
1249
1250         return same;
1251 }
1252
1253 static inline gboolean
1254 should_compare_prop (NMSetting *setting,
1255                      const char *prop_name,
1256                      NMSettingCompareFlags comp_flags,
1257                      GParamFlags prop_flags)
1258 {
1259         /* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
1260         if (   (comp_flags & NM_SETTING_COMPARE_FLAG_FUZZY)
1261             && (prop_flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)))
1262                 return FALSE;
1263
1264         if ((comp_flags & NM_SETTING_COMPARE_FLAG_INFERRABLE) && !(prop_flags & NM_SETTING_PARAM_INFERRABLE))
1265                 return FALSE;
1266
1267         if ((comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY) && !(prop_flags & NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
1268                 return FALSE;
1269
1270         if (prop_flags & NM_SETTING_PARAM_SECRET) {
1271                 NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
1272
1273                 if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
1274                         return FALSE;
1275
1276                 if (   NM_IS_SETTING_VPN (setting)
1277                     && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) {
1278                         /* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET.
1279                          * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the
1280                          * setting accidently uses a key "secrets". */
1281                         return TRUE;
1282                 }
1283
1284                 if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL))
1285                         g_return_val_if_reached (FALSE);
1286
1287                 if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
1288                     && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
1289                         return FALSE;
1290
1291                 if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
1292                     && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
1293                         return FALSE;
1294         }
1295
1296         if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID)
1297             && NM_IS_SETTING_CONNECTION (setting)
1298             && !strcmp (prop_name, NM_SETTING_CONNECTION_ID))
1299                 return FALSE;
1300
1301         if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
1302             && NM_IS_SETTING_CONNECTION (setting)
1303             && !strcmp (prop_name, NM_SETTING_CONNECTION_TIMESTAMP))
1304                 return FALSE;
1305
1306         return TRUE;
1307 }
1308
1309 /**
1310  * nm_setting_diff:
1311  * @a: a #NMSetting
1312  * @b: a second #NMSetting to compare with the first
1313  * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
1314  * @invert_results: this parameter is used internally by libnm and should
1315  * be set to %FALSE.  If %TRUE inverts the meaning of the #NMSettingDiffResult.
1316  * @results: (inout) (transfer full) (element-type utf8 guint32): if the
1317  * settings differ, on return a hash table mapping the differing keys to one or
1318  * more %NMSettingDiffResult values OR-ed together.  If the settings do not
1319  * differ, any hash table passed in is unmodified.  If no hash table is passed
1320  * in and the settings differ, a new one is created and returned.
1321  *
1322  * Compares two #NMSetting objects for similarity, with comparison behavior
1323  * modified by a set of flags.  See the documentation for #NMSettingCompareFlags
1324  * for a description of each flag's behavior.  If the settings differ, the keys
1325  * of each setting that differ from the other are added to @results, mapped to
1326  * one or more #NMSettingDiffResult values.
1327  *
1328  * Returns: %TRUE if the settings contain the same values, %FALSE if they do not
1329  **/
1330 gboolean
1331 nm_setting_diff (NMSetting *a,
1332                  NMSetting *b,
1333                  NMSettingCompareFlags flags,
1334                  gboolean invert_results,
1335                  GHashTable **results)
1336 {
1337         GParamSpec **property_specs;
1338         guint n_property_specs;
1339         guint i;
1340         NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A;
1341         NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B;
1342         NMSettingDiffResult a_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
1343         NMSettingDiffResult b_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
1344         gboolean results_created = FALSE;
1345
1346         g_return_val_if_fail (results != NULL, FALSE);
1347         g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
1348         if (b) {
1349                 g_return_val_if_fail (NM_IS_SETTING (b), FALSE);
1350                 g_return_val_if_fail (G_OBJECT_TYPE (a) == G_OBJECT_TYPE (b), FALSE);
1351         }
1352
1353         if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) ==
1354                      (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) {
1355                 /* conflicting flags: default to WITH_DEFAULT (clearing NO_DEFAULT). */
1356                 flags &= ~NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT;
1357         }
1358
1359         /* If the caller is calling this function in a pattern like this to get
1360          * complete diffs:
1361          *
1362          * nm_setting_diff (A, B, FALSE, &results);
1363          * nm_setting_diff (B, A, TRUE, &results);
1364          *
1365          * and wants us to invert the results so that the second invocation comes
1366          * out correctly, do that here.
1367          */
1368         if (invert_results) {
1369                 a_result = NM_SETTING_DIFF_RESULT_IN_B;
1370                 b_result = NM_SETTING_DIFF_RESULT_IN_A;
1371                 a_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
1372                 b_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
1373         }
1374
1375         if (*results == NULL) {
1376                 *results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1377                 results_created = TRUE;
1378         }
1379
1380         /* And now all properties */
1381         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
1382
1383         for (i = 0; i < n_property_specs; i++) {
1384                 GParamSpec *prop_spec = property_specs[i];
1385                 NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
1386
1387                 /* Handle compare flags */
1388                 if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags))
1389                         continue;
1390                 if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
1391                         continue;
1392
1393                 if (b) {
1394                         gboolean different;
1395
1396                         different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
1397                         if (different) {
1398                                 gboolean a_is_default, b_is_default;
1399                                 GValue value = G_VALUE_INIT;
1400
1401                                 g_value_init (&value, prop_spec->value_type);
1402                                 g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
1403                                 a_is_default = g_param_value_defaults (prop_spec, &value);
1404
1405                                 g_value_reset (&value);
1406                                 g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
1407                                 b_is_default = g_param_value_defaults (prop_spec, &value);
1408
1409                                 g_value_unset (&value);
1410                                 if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) {
1411                                         if (!a_is_default)
1412                                                 r |= a_result;
1413                                         if (!b_is_default)
1414                                                 r |= b_result;
1415                                 } else {
1416                                         r |= a_result | b_result;
1417                                         if (a_is_default)
1418                                                 r |= a_result_default;
1419                                         if (b_is_default)
1420                                                 r |= b_result_default;
1421                                 }
1422                         }
1423                 } else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0)
1424                         r = a_result;  /* only in A */
1425                 else {
1426                         GValue value = G_VALUE_INIT;
1427
1428                         g_value_init (&value, prop_spec->value_type);
1429                         g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
1430                         if (!g_param_value_defaults (prop_spec, &value))
1431                                 r |= a_result;
1432                         else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
1433                                 r |= a_result | a_result_default;
1434
1435                         g_value_unset (&value);
1436                 }
1437
1438                 if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
1439                         void *p;
1440
1441                         if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) {
1442                                 if ((r & GPOINTER_TO_UINT (p)) != r)
1443                                         g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p)));
1444                         } else
1445                                 g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r));
1446                 }
1447         }
1448         g_free (property_specs);
1449
1450         /* Don't return an empty hash table */
1451         if (results_created && !g_hash_table_size (*results)) {
1452                 g_hash_table_destroy (*results);
1453                 *results = NULL;
1454         }
1455
1456         return !(*results);
1457 }
1458
1459 #define CMP_AND_RETURN(n_a, n_b, name) \
1460         G_STMT_START { \
1461                 gboolean _is = (strcmp (n_a, ""name) == 0); \
1462                 \
1463                 if (_is || (strcmp (n_b, ""name) == 0)) \
1464                         return _is ? -1 : 1; \
1465         } G_STMT_END
1466
1467 static int
1468 _enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type)
1469 {
1470         const char *n_a = (*p_a)->name;
1471         const char *n_b = (*p_b)->name;
1472         int c = strcmp (n_a, n_b);
1473
1474         if (c) {
1475                 if (*p_type == NM_TYPE_SETTING_CONNECTION) {
1476                         /* for [connection], report first id, uuid, type in that order. */
1477                         CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID);
1478                         CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID);
1479                         CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE);
1480                 }
1481         }
1482         return c;
1483 }
1484 #undef CMP_AND_RETURN
1485
1486 /**
1487  * nm_setting_enumerate_values:
1488  * @setting: the #NMSetting
1489  * @func: (scope call): user-supplied function called for each property of the setting
1490  * @user_data: user data passed to @func at each invocation
1491  *
1492  * Iterates over each property of the #NMSetting object, calling the supplied
1493  * user function for each property.
1494  **/
1495 void
1496 nm_setting_enumerate_values (NMSetting *setting,
1497                              NMSettingValueIterFn func,
1498                              gpointer user_data)
1499 {
1500         GParamSpec **property_specs;
1501         guint n_property_specs;
1502         int i;
1503         GType type;
1504
1505         g_return_if_fail (NM_IS_SETTING (setting));
1506         g_return_if_fail (func != NULL);
1507
1508         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
1509
1510         /* sort the properties. This has an effect on the order in which keyfile
1511          * prints them. */
1512         type = G_OBJECT_TYPE (setting);
1513         g_qsort_with_data (property_specs, n_property_specs, sizeof (gpointer),
1514                            (GCompareDataFunc) _enumerate_values_sort, &type);
1515
1516         for (i = 0; i < n_property_specs; i++) {
1517                 GParamSpec *prop_spec = property_specs[i];
1518                 GValue value = G_VALUE_INIT;
1519
1520                 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
1521                 g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
1522                 func (setting, prop_spec->name, &value, prop_spec->flags, user_data);
1523                 g_value_unset (&value);
1524         }
1525
1526         g_free (property_specs);
1527 }
1528
1529 /**
1530  * _nm_setting_clear_secrets:
1531  * @setting: the #NMSetting
1532  *
1533  * Resets and clears any secrets in the setting.  Secrets should be added to the
1534  * setting only when needed, and cleared immediately after use to prevent
1535  * leakage of information.
1536  *
1537  * Returns: %TRUE if the setting changed at all
1538  **/
1539 gboolean
1540 _nm_setting_clear_secrets (NMSetting *setting)
1541 {
1542         GParamSpec **property_specs;
1543         guint n_property_specs;
1544         guint i;
1545         gboolean changed = FALSE;
1546
1547         g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
1548
1549         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
1550
1551         for (i = 0; i < n_property_specs; i++) {
1552                 GParamSpec *prop_spec = property_specs[i];
1553
1554                 if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
1555                         GValue value = G_VALUE_INIT;
1556
1557                         g_value_init (&value, prop_spec->value_type);
1558                         g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
1559                         if (!g_param_value_defaults (prop_spec, &value)) {
1560                                 g_param_value_set_default (prop_spec, &value);
1561                                 g_object_set_property (G_OBJECT (setting), prop_spec->name, &value);
1562                                 changed = TRUE;
1563                         }
1564                         g_value_unset (&value);
1565                 }
1566         }
1567
1568         g_free (property_specs);
1569
1570         return changed;
1571 }
1572
1573 static gboolean
1574 clear_secrets_with_flags (NMSetting *setting,
1575                           GParamSpec *pspec,
1576                           NMSettingClearSecretsWithFlagsFn func,
1577                           gpointer user_data)
1578 {
1579         NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
1580         gboolean changed = FALSE;
1581
1582         g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
1583
1584         /* Clear the secret if the user function says to do so */
1585         if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL))
1586                 g_return_val_if_reached (FALSE);
1587
1588         if (func (setting, pspec->name, flags, user_data) == TRUE) {
1589                 GValue value = G_VALUE_INIT;
1590
1591                 g_value_init (&value, pspec->value_type);
1592                 g_object_get_property (G_OBJECT (setting), pspec->name, &value);
1593                 if (!g_param_value_defaults (pspec, &value)) {
1594                         g_param_value_set_default (pspec, &value);
1595                         g_object_set_property (G_OBJECT (setting), pspec->name, &value);
1596                         changed = TRUE;
1597                 }
1598                 g_value_unset (&value);
1599         }
1600
1601         return changed;
1602 }
1603
1604 /**
1605  * _nm_setting_clear_secrets_with_flags:
1606  * @setting: the #NMSetting
1607  * @func: (scope call): function to be called to determine whether a
1608  *     specific secret should be cleared or not
1609  * @user_data: caller-supplied data passed to @func
1610  *
1611  * Clears and frees secrets determined by @func.
1612  *
1613  * Returns: %TRUE if the setting changed at all
1614  **/
1615 gboolean
1616 _nm_setting_clear_secrets_with_flags (NMSetting *setting,
1617                                       NMSettingClearSecretsWithFlagsFn func,
1618                                       gpointer user_data)
1619 {
1620         GParamSpec **property_specs;
1621         guint n_property_specs;
1622         guint i;
1623         gboolean changed = FALSE;
1624
1625         g_return_val_if_fail (setting, FALSE);
1626         g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
1627         g_return_val_if_fail (func != NULL, FALSE);
1628
1629         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
1630         for (i = 0; i < n_property_specs; i++) {
1631                 if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) {
1632                         changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
1633                                                                                              property_specs[i],
1634                                                                                              func,
1635                                                                                              user_data);
1636                 }
1637         }
1638
1639         g_free (property_specs);
1640         return changed;
1641 }
1642
1643 /**
1644  * _nm_setting_need_secrets:
1645  * @setting: the #NMSetting
1646  *
1647  * Returns an array of property names for each secret which may be required
1648  * to make a successful connection.  The returned hints are only intended as a
1649  * guide to what secrets may be required, because in some circumstances, there
1650  * is no way to conclusively determine exactly which secrets are needed.
1651  *
1652  * Returns: (transfer container) (element-type utf8): a #GPtrArray containing
1653  * the property names of secrets of the #NMSetting which may be required; the
1654  * caller owns the array and must free it with g_ptr_array_free(), but must not
1655  * free the elements.
1656  **/
1657 GPtrArray *
1658 _nm_setting_need_secrets (NMSetting *setting)
1659 {
1660         GPtrArray *secrets = NULL;
1661
1662         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1663
1664         if (NM_SETTING_GET_CLASS (setting)->need_secrets)
1665                 secrets = NM_SETTING_GET_CLASS (setting)->need_secrets (setting);
1666
1667         return secrets;
1668 }
1669
1670 static int
1671 update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError **error)
1672 {
1673         const NMSettingProperty *property;
1674         GParamSpec *prop_spec;
1675         GValue prop_value = { 0, };
1676
1677         property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), key);
1678         if (!property) {
1679                 g_set_error_literal (error,
1680                                      NM_CONNECTION_ERROR,
1681                                      NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
1682                                      _("secret not found"));
1683                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
1684                 return NM_SETTING_UPDATE_SECRET_ERROR;
1685         }
1686
1687         /* Silently ignore non-secrets */
1688         prop_spec = property->param_spec;
1689         if (!prop_spec || !(prop_spec->flags & NM_SETTING_PARAM_SECRET))
1690                 return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
1691
1692         if (   g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)
1693             && G_IS_PARAM_SPEC_STRING (prop_spec)) {
1694                 /* String is expected to be a common case. Handle it specially and check
1695                  * whether the value is already set. Otherwise, we just reset the
1696                  * property and assume the value got modified.
1697                  */
1698                 char *v;
1699
1700                 g_object_get (G_OBJECT (setting), prop_spec->name, &v, NULL);
1701                 if (g_strcmp0 (v, g_variant_get_string (value, NULL)) == 0) {
1702                         g_free (v);
1703                         return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
1704                 }
1705                 g_free (v);
1706         }
1707
1708         g_value_init (&prop_value, prop_spec->value_type);
1709         set_property_from_dbus (property, value, &prop_value);
1710         g_object_set_property (G_OBJECT (setting), prop_spec->name, &prop_value);
1711         g_value_unset (&prop_value);
1712
1713         return NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
1714 }
1715
1716 /**
1717  * _nm_setting_update_secrets:
1718  * @setting: the #NMSetting
1719  * @secrets: a #GVariant of type #NM_VARIANT_TYPE_SETTING, mapping property
1720  *   names to secrets.
1721  * @error: location to store error, or %NULL
1722  *
1723  * Update the setting's secrets, given a dictionary of secrets intended for that
1724  * setting (deserialized from D-Bus for example).
1725  *
1726  * Returns: an #NMSettingUpdateSecretResult
1727  **/
1728 NMSettingUpdateSecretResult
1729 _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **error)
1730 {
1731         GVariantIter iter;
1732         const char *secret_key;
1733         GVariant *secret_value;
1734         GError *tmp_error = NULL;
1735         NMSettingUpdateSecretResult result = NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
1736
1737         g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_UPDATE_SECRET_ERROR);
1738         g_return_val_if_fail (g_variant_is_of_type (secrets, NM_VARIANT_TYPE_SETTING), NM_SETTING_UPDATE_SECRET_ERROR);
1739         if (error)
1740                 g_return_val_if_fail (*error == NULL, NM_SETTING_UPDATE_SECRET_ERROR);
1741
1742         g_variant_iter_init (&iter, secrets);
1743         while (g_variant_iter_next (&iter, "{&sv}", &secret_key, &secret_value)) {
1744                 int success;
1745
1746                 success = NM_SETTING_GET_CLASS (setting)->update_one_secret (setting, secret_key, secret_value, &tmp_error);
1747                 g_assert (!((success == NM_SETTING_UPDATE_SECRET_ERROR) ^ (!!tmp_error)));
1748
1749                 g_variant_unref (secret_value);
1750
1751                 if (success == NM_SETTING_UPDATE_SECRET_ERROR) {
1752                         g_propagate_error (error, tmp_error);
1753                         return NM_SETTING_UPDATE_SECRET_ERROR;
1754                 }
1755
1756                 if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
1757                         result = NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
1758         }
1759
1760         return result;
1761 }
1762
1763 static gboolean
1764 is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
1765 {
1766         const NMSettingProperty *property;
1767         GParamSpec *pspec;
1768
1769         property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), secret_name);
1770         if (!property) {
1771                 g_set_error_literal (error,
1772                                      NM_CONNECTION_ERROR,
1773                                      NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
1774                                      _("secret is not set"));
1775                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
1776                 return FALSE;
1777         }
1778
1779         pspec = property->param_spec;
1780         if (!pspec || !(pspec->flags & NM_SETTING_PARAM_SECRET)) {
1781                 g_set_error_literal (error,
1782                                      NM_CONNECTION_ERROR,
1783                                      NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
1784                                      _("not a secret property"));
1785                 g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
1786                 return FALSE;
1787         }
1788
1789         return TRUE;
1790 }
1791
1792 static gboolean
1793 get_secret_flags (NMSetting *setting,
1794                   const char *secret_name,
1795                   gboolean verify_secret,
1796                   NMSettingSecretFlags *out_flags,
1797                   GError **error)
1798 {
1799         char *flags_prop;
1800         NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
1801
1802         if (verify_secret && !is_secret_prop (setting, secret_name, error)) {
1803                 if (out_flags)
1804                         *out_flags = NM_SETTING_SECRET_FLAG_NONE;
1805                 return FALSE;
1806         }
1807
1808         flags_prop = g_strdup_printf ("%s-flags", secret_name);
1809         g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL);
1810         g_free (flags_prop);
1811
1812         if (out_flags)
1813                 *out_flags = flags;
1814         return TRUE;
1815 }
1816
1817 /**
1818  * nm_setting_get_secret_flags:
1819  * @setting: the #NMSetting
1820  * @secret_name: the secret key name to get flags for
1821  * @out_flags: on success, the #NMSettingSecretFlags for the secret
1822  * @error: location to store error, or %NULL
1823  *
1824  * For a given secret, retrieves the #NMSettingSecretFlags describing how to
1825  * handle that secret.
1826  *
1827  * Returns: %TRUE on success (if the given secret name was a valid property of
1828  * this setting, and if that property is secret), %FALSE if not
1829  **/
1830 gboolean
1831 nm_setting_get_secret_flags (NMSetting *setting,
1832                              const char *secret_name,
1833                              NMSettingSecretFlags *out_flags,
1834                              GError **error)
1835 {
1836         g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
1837         g_return_val_if_fail (secret_name != NULL, FALSE);
1838
1839         return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error);
1840 }
1841
1842 static gboolean
1843 set_secret_flags (NMSetting *setting,
1844                   const char *secret_name,
1845                   gboolean verify_secret,
1846                   NMSettingSecretFlags flags,
1847                   GError **error)
1848 {
1849         char *flags_prop;
1850
1851         if (verify_secret)
1852                 g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE);
1853
1854         flags_prop = g_strdup_printf ("%s-flags", secret_name);
1855         g_object_set (G_OBJECT (setting), flags_prop, flags, NULL);
1856         g_free (flags_prop);
1857         return TRUE;
1858 }
1859
1860 /**
1861  * nm_setting_set_secret_flags:
1862  * @setting: the #NMSetting
1863  * @secret_name: the secret key name to set flags for
1864  * @flags: the #NMSettingSecretFlags for the secret
1865  * @error: location to store error, or %NULL
1866  *
1867  * For a given secret, stores the #NMSettingSecretFlags describing how to
1868  * handle that secret.
1869  *
1870  * Returns: %TRUE on success (if the given secret name was a valid property of
1871  * this setting, and if that property is secret), %FALSE if not
1872  **/
1873 gboolean
1874 nm_setting_set_secret_flags (NMSetting *setting,
1875                              const char *secret_name,
1876                              NMSettingSecretFlags flags,
1877                              GError **error)
1878 {
1879         g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
1880         g_return_val_if_fail (secret_name != NULL, FALSE);
1881         g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE);
1882
1883         return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error);
1884 }
1885
1886 /**
1887  * nm_setting_to_string:
1888  * @setting: the #NMSetting
1889  *
1890  * Convert the setting into a string.  For debugging purposes ONLY, should NOT
1891  * be used for serialization of the setting, or machine-parsed in any way. The
1892  * output format is not guaranteed to be stable and may change at any time.
1893  *
1894  * Returns: an allocated string containing a textual representation of the
1895  * setting's properties and values (including secrets!), which the caller should
1896  * free with g_free()
1897  **/
1898 char *
1899 nm_setting_to_string (NMSetting *setting)
1900 {
1901         GString *string;
1902         GParamSpec **property_specs;
1903         guint n_property_specs;
1904         guint i;
1905
1906         g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
1907
1908         property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
1909
1910         string = g_string_new (nm_setting_get_name (setting));
1911         g_string_append_c (string, '\n');
1912
1913         for (i = 0; i < n_property_specs; i++) {
1914                 GParamSpec *prop_spec = property_specs[i];
1915                 GValue value = G_VALUE_INIT;
1916                 char *value_str;
1917                 gboolean is_default;
1918
1919                 if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
1920                         continue;
1921
1922                 g_value_init (&value, prop_spec->value_type);
1923                 g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
1924
1925                 value_str = g_strdup_value_contents (&value);
1926                 g_string_append_printf (string, "\t%s : %s", prop_spec->name, value_str);
1927                 g_free (value_str);
1928
1929                 is_default = g_param_value_defaults (prop_spec, &value);
1930                 g_value_unset (&value);
1931
1932                 g_string_append (string, " (");
1933                 g_string_append_c (string, 's');
1934                 if (is_default)
1935                         g_string_append_c (string, 'd');
1936                 g_string_append_c (string, ')');
1937                 g_string_append_c (string, '\n');
1938         }
1939
1940         g_free (property_specs);
1941         g_string_append_c (string, '\n');
1942
1943         return g_string_free (string, FALSE);
1944 }
1945
1946 GVariant *
1947 _nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
1948                                                    NMConnection *connection,
1949                                                    const char *property)
1950 {
1951         NMSettingConnection *s_con;
1952
1953         s_con = nm_connection_get_setting_connection (connection);
1954         g_return_val_if_fail (s_con != NULL, NULL);
1955
1956         if (nm_setting_connection_get_interface_name (s_con))
1957                 return g_variant_new_string (nm_setting_connection_get_interface_name (s_con));
1958         else
1959                 return NULL;
1960 }
1961
1962 /*****************************************************************************/
1963
1964 static void
1965 nm_setting_init (NMSetting *setting)
1966 {
1967 }
1968
1969 static void
1970 constructed (GObject *object)
1971 {
1972         _ensure_setting_info (object, NM_SETTING_GET_PRIVATE (object));
1973
1974         G_OBJECT_CLASS (nm_setting_parent_class)->constructed (object);
1975 }
1976
1977 static void
1978 get_property (GObject *object, guint prop_id,
1979               GValue *value, GParamSpec *pspec)
1980 {
1981         NMSetting *setting = NM_SETTING (object);
1982
1983         switch (prop_id) {
1984         case PROP_NAME:
1985                 g_value_set_string (value, nm_setting_get_name (setting));
1986                 break;
1987         default:
1988                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1989                 break;
1990         }
1991 }
1992
1993 static void
1994 nm_setting_class_init (NMSettingClass *setting_class)
1995 {
1996         GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
1997
1998         if (!setting_property_overrides_quark)
1999                 setting_property_overrides_quark = g_quark_from_static_string ("nm-setting-property-overrides");
2000         if (!setting_properties_quark)
2001                 setting_properties_quark = g_quark_from_static_string ("nm-setting-properties");
2002
2003         g_type_class_add_private (setting_class, sizeof (NMSettingPrivate));
2004
2005         /* virtual methods */
2006         object_class->constructed  = constructed;
2007         object_class->get_property = get_property;
2008
2009         setting_class->update_one_secret = update_one_secret;
2010         setting_class->get_secret_flags = get_secret_flags;
2011         setting_class->set_secret_flags = set_secret_flags;
2012         setting_class->compare_property = compare_property;
2013         setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
2014
2015         /* Properties */
2016
2017         /**
2018          * NMSetting:name:
2019          *
2020          * The setting's name, which uniquely identifies the setting within the
2021          * connection.  Each setting type has a name unique to that type, for
2022          * example "ppp" or "wireless" or "wired".
2023          **/
2024         g_object_class_install_property
2025                 (object_class, PROP_NAME,
2026                  g_param_spec_string (NM_SETTING_NAME, "", "",
2027                                       NULL,
2028                                       G_PARAM_READABLE |
2029                                       G_PARAM_STATIC_STRINGS));
2030 }