device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / nm-setting-vpn.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301 USA.
17  *
18  * Copyright 2007 - 2013 Red Hat, Inc.
19  * Copyright 2007 - 2008 Novell, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include <string.h>
25 #include <errno.h>
26 #include <stdlib.h>
27
28 #include "nm-setting-vpn.h"
29 #include "nm-utils.h"
30 #include "nm-utils-private.h"
31 #include "nm-setting-private.h"
32
33 /**
34  * SECTION:nm-setting-vpn
35  * @short_description: Describes connection properties for Virtual Private Networks
36  *
37  * The #NMSettingVpn object is a #NMSetting subclass that describes properties
38  * necessary for connection to Virtual Private Networks.  NetworkManager uses
39  * a plugin architecture to allow easier use of new VPN types, and this
40  * setting abstracts the configuration for those plugins.  Since the configuration
41  * options are only known to the VPN plugins themselves, the VPN configuration
42  * options are stored as key/value pairs of strings rather than GObject
43  * properties.
44  **/
45
46 G_DEFINE_TYPE_WITH_CODE (NMSettingVpn, nm_setting_vpn, NM_TYPE_SETTING,
47                          _nm_register_setting (VPN, 1))
48 NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_VPN)
49
50 #define NM_SETTING_VPN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VPN, NMSettingVpnPrivate))
51
52 typedef struct {
53         char *service_type;
54
55         /* username of the user requesting this connection, thus
56          * it's really only valid for user connections, and it also
57          * should never be saved out to persistent config.
58          */
59         char *user_name;
60
61         /* Whether the VPN stays up across link changes, until the user
62          * explicitly disconnects it.
63          */
64         gboolean persistent;
65
66         /* The hash table is created at setting object
67          * init time and should not be replaced.  It is
68          * a char * -> char * mapping, and both the key
69          * and value are owned by the hash table, and should
70          * be allocated with functions whose value can be
71          * freed with g_free().  Should not contain secrets.
72          */
73         GHashTable *data;
74
75         /* The hash table is created at setting object
76          * init time and should not be replaced.  It is
77          * a char * -> char * mapping, and both the key
78          * and value are owned by the hash table, and should
79          * be allocated with functions whose value can be
80          * freed with g_free().  Should contain secrets only.
81          */
82         GHashTable *secrets;
83
84         /* Timeout for the VPN service to establish the connection */
85         guint32 timeout;
86 } NMSettingVpnPrivate;
87
88 enum {
89         PROP_0,
90         PROP_SERVICE_TYPE,
91         PROP_USER_NAME,
92         PROP_PERSISTENT,
93         PROP_DATA,
94         PROP_SECRETS,
95         PROP_TIMEOUT,
96
97         LAST_PROP
98 };
99
100 /**
101  * nm_setting_vpn_new:
102  *
103  * Creates a new #NMSettingVpn object with default values.
104  *
105  * Returns: (transfer full): the new empty #NMSettingVpn object
106  **/
107 NMSetting *
108 nm_setting_vpn_new (void)
109 {
110         return (NMSetting *) g_object_new (NM_TYPE_SETTING_VPN, NULL);
111 }
112
113 /**
114  * nm_setting_vpn_get_service_type:
115  * @setting: the #NMSettingVpn
116  *
117  * Returns the service name of the VPN, which identifies the specific VPN
118  * plugin that should be used to connect to this VPN.
119  *
120  * Returns: the VPN plugin's service name
121  **/
122 const char *
123 nm_setting_vpn_get_service_type (NMSettingVpn *setting)
124 {
125         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL);
126
127         return NM_SETTING_VPN_GET_PRIVATE (setting)->service_type;
128 }
129
130 /**
131  * nm_setting_vpn_get_user_name:
132  * @setting: the #NMSettingVpn
133  *
134  * Returns: the #NMSettingVpn:user-name property of the setting
135  **/
136 const char *
137 nm_setting_vpn_get_user_name (NMSettingVpn *setting)
138 {
139         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL);
140
141         return NM_SETTING_VPN_GET_PRIVATE (setting)->user_name;
142 }
143
144 /**
145  * nm_setting_vpn_get_persistent:
146  * @setting: the #NMSettingVpn
147  *
148  * Returns: the #NMSettingVpn:persistent property of the setting
149  **/
150 gboolean
151 nm_setting_vpn_get_persistent (NMSettingVpn *setting)
152 {
153         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
154
155         return NM_SETTING_VPN_GET_PRIVATE (setting)->persistent;
156 }
157
158 /**
159  * nm_setting_vpn_get_num_data_items:
160  * @setting: the #NMSettingVpn
161  *
162  * Gets number of key/value pairs of VPN configuration data.
163  *
164  * Returns: the number of VPN plugin specific configuration data items
165  **/
166 guint32
167 nm_setting_vpn_get_num_data_items (NMSettingVpn *setting)
168 {
169         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), 0);
170
171         return g_hash_table_size (NM_SETTING_VPN_GET_PRIVATE (setting)->data);
172 }
173
174 /**
175  * nm_setting_vpn_add_data_item:
176  * @setting: the #NMSettingVpn
177  * @key: a name that uniquely identifies the given value @item
178  * @item: the value to be referenced by @key
179  *
180  * Establishes a relationship between @key and @item internally in the
181  * setting which may be retrieved later.  Should not be used to store passwords
182  * or other secrets, which is what nm_setting_vpn_add_secret() is for.
183  **/
184 void
185 nm_setting_vpn_add_data_item (NMSettingVpn *setting,
186                               const char *key,
187                               const char *item)
188 {
189         g_return_if_fail (NM_IS_SETTING_VPN (setting));
190         g_return_if_fail (key != NULL);
191         g_return_if_fail (strlen (key) > 0);
192         g_return_if_fail (item != NULL);
193         g_return_if_fail (strlen (item) > 0);
194
195         g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
196                              g_strdup (key), g_strdup (item));
197         g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_DATA);
198 }
199
200 /**
201  * nm_setting_vpn_get_data_item:
202  * @setting: the #NMSettingVpn
203  * @key: the name of the data item to retrieve
204  *
205  * Retrieves the data item of a key/value relationship previously established
206  * by nm_setting_vpn_add_data_item().
207  *
208  * Returns: the data item, if any
209  **/
210 const char *
211 nm_setting_vpn_get_data_item (NMSettingVpn *setting, const char *key)
212 {
213         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL);
214
215         return (const char *) g_hash_table_lookup (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
216 }
217
218 /**
219  * nm_setting_vpn_remove_data_item:
220  * @setting: the #NMSettingVpn
221  * @key: the name of the data item to remove
222  *
223  * Deletes a key/value relationship previously established by
224  * nm_setting_vpn_add_data_item().
225  *
226  * Returns: %TRUE if the data item was found and removed from the internal list,
227  * %FALSE if it was not.
228  **/
229 gboolean
230 nm_setting_vpn_remove_data_item (NMSettingVpn *setting, const char *key)
231 {
232         gboolean found;
233
234         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
235
236         found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
237         if (found)
238                 g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_DATA);
239         return found;
240 }
241
242 static void
243 foreach_item_helper (GHashTable *hash,
244                      NMVpnIterFunc func,
245                      gpointer user_data)
246 {
247         GList *keys, *liter;
248         GSList *copied = NULL, *siter;
249
250         g_return_if_fail (hash != NULL);
251
252         /* Grab keys and copy them so that the callback func can modify
253          * the hash table items if it wants to.
254          */
255         keys = g_hash_table_get_keys (hash);
256         for (liter = keys; liter; liter = g_list_next (liter))
257                 copied = g_slist_prepend (copied, g_strdup (liter->data));
258         copied = g_slist_reverse (copied);
259         g_list_free (keys);
260
261         for (siter = copied; siter; siter = g_slist_next (siter)) {
262                 gpointer value;
263
264                 value = g_hash_table_lookup (hash, siter->data);
265                 func (siter->data, value, user_data);
266         }
267
268         g_slist_free_full (copied, g_free);
269 }
270
271 /**
272  * nm_setting_vpn_foreach_data_item:
273  * @setting: a #NMSettingVpn
274  * @func: (scope call): an user provided function
275  * @user_data: data to be passed to @func
276  *
277  * Iterates all data items stored in this setting.  It is safe to add, remove,
278  * and modify data items inside @func, though any additions or removals made
279  * during iteration will not be part of the iteration.
280  */
281 void
282 nm_setting_vpn_foreach_data_item (NMSettingVpn *setting,
283                                   NMVpnIterFunc func,
284                                   gpointer user_data)
285 {
286         g_return_if_fail (NM_IS_SETTING_VPN (setting));
287
288         foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->data, func, user_data);
289 }
290
291 /**
292  * nm_setting_vpn_get_num_secrets:
293  * @setting: the #NMSettingVpn
294  *
295  * Gets number of VPN plugin specific secrets in the setting.
296  *
297  * Returns: the number of VPN plugin specific secrets
298  **/
299 guint32
300 nm_setting_vpn_get_num_secrets (NMSettingVpn *setting)
301 {
302         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), 0);
303
304         return g_hash_table_size (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets);
305 }
306
307 /**
308  * nm_setting_vpn_add_secret:
309  * @setting: the #NMSettingVpn
310  * @key: a name that uniquely identifies the given secret @secret
311  * @secret: the secret to be referenced by @key
312  *
313  * Establishes a relationship between @key and @secret internally in the
314  * setting which may be retrieved later.
315  **/
316 void
317 nm_setting_vpn_add_secret (NMSettingVpn *setting,
318                            const char *key,
319                            const char *secret)
320 {
321         g_return_if_fail (NM_IS_SETTING_VPN (setting));
322         g_return_if_fail (key != NULL);
323         g_return_if_fail (strlen (key) > 0);
324         g_return_if_fail (secret != NULL);
325         g_return_if_fail (strlen (secret) > 0);
326
327         g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets,
328                              g_strdup (key), g_strdup (secret));
329         g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
330 }
331
332 /**
333  * nm_setting_vpn_get_secret:
334  * @setting: the #NMSettingVpn
335  * @key: the name of the secret to retrieve
336  *
337  * Retrieves the secret of a key/value relationship previously established
338  * by nm_setting_vpn_add_secret().
339  *
340  * Returns: the secret, if any
341  **/
342 const char *
343 nm_setting_vpn_get_secret (NMSettingVpn *setting, const char *key)
344 {
345         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL);
346
347         return (const char *) g_hash_table_lookup (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key);
348 }
349
350 /**
351  * nm_setting_vpn_remove_secret:
352  * @setting: the #NMSettingVpn
353  * @key: the name of the secret to remove
354  *
355  * Deletes a key/value relationship previously established by
356  * nm_setting_vpn_add_secret().
357  *
358  * Returns: %TRUE if the secret was found and removed from the internal list,
359  * %FALSE if it was not.
360  **/
361 gboolean
362 nm_setting_vpn_remove_secret (NMSettingVpn *setting, const char *key)
363 {
364         gboolean found;
365
366         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
367
368         found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key);
369         if (found)
370                 g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
371         return found;
372 }
373
374 /**
375  * nm_setting_vpn_foreach_secret:
376  * @setting: a #NMSettingVpn
377  * @func: (scope call): an user provided function
378  * @user_data: data to be passed to @func
379  *
380  * Iterates all secrets stored in this setting.  It is safe to add, remove,
381  * and modify secrets inside @func, though any additions or removals made during
382  * iteration will not be part of the iteration.
383  */
384 void
385 nm_setting_vpn_foreach_secret (NMSettingVpn *setting,
386                                NMVpnIterFunc func,
387                                gpointer user_data)
388 {
389         g_return_if_fail (NM_IS_SETTING_VPN (setting));
390
391         foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, func, user_data);
392 }
393
394 /**
395  * nm_setting_vpn_get_timeout:
396  * @setting: the #NMSettingVpn
397  *
398  * Returns: the #NMSettingVpn:timeout property of the setting
399  *
400  * Since: 1.2
401  **/
402 guint32
403 nm_setting_vpn_get_timeout (NMSettingVpn *setting)
404 {
405         g_return_val_if_fail (NM_IS_SETTING_VPN (setting), 0);
406
407         return NM_SETTING_VPN_GET_PRIVATE (setting)->timeout;
408 }
409
410 static gboolean
411 verify (NMSetting *setting, NMConnection *connection, GError **error)
412 {
413         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
414
415         if (!priv->service_type) {
416                 g_set_error_literal (error,
417                                      NM_CONNECTION_ERROR,
418                                      NM_CONNECTION_ERROR_MISSING_PROPERTY,
419                                      _("property is missing"));
420                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_SERVICE_TYPE);
421                 return FALSE;
422         }
423
424         if (!strlen (priv->service_type)) {
425                 g_set_error_literal (error,
426                                      NM_CONNECTION_ERROR,
427                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
428                                      _("property is empty"));
429                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_SERVICE_TYPE);
430                 return FALSE;
431         }
432
433         /* default username can be NULL, but can't be zero-length */
434         if (priv->user_name && !strlen (priv->user_name)) {
435                 g_set_error_literal (error,
436                                      NM_CONNECTION_ERROR,
437                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
438                                      _("property is empty"));
439                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_USER_NAME);
440                 return FALSE;
441         }
442
443         return TRUE;
444 }
445
446 static NMSettingUpdateSecretResult
447 update_secret_string (NMSetting *setting,
448                       const char *key,
449                       const char *value,
450                       GError **error)
451 {
452         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
453
454         g_return_val_if_fail (key != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
455         g_return_val_if_fail (value != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
456
457         if (!value || !strlen (value)) {
458                 g_set_error (error, NM_CONNECTION_ERROR,
459                              NM_CONNECTION_ERROR_INVALID_PROPERTY,
460                              _("secret was empty"));
461                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, key);
462                 return NM_SETTING_UPDATE_SECRET_ERROR;
463         }
464
465         if (g_strcmp0 (g_hash_table_lookup (priv->secrets, key), value) == 0)
466                 return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
467
468         g_hash_table_insert (priv->secrets, g_strdup (key), g_strdup (value));
469         return NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
470 }
471
472 static NMSettingUpdateSecretResult
473 update_secret_dict (NMSetting *setting,
474                     GVariant *secrets,
475                     GError **error)
476 {
477         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
478         GVariantIter iter;
479         const char *name, *value;
480         NMSettingUpdateSecretResult result = NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
481
482         g_return_val_if_fail (secrets != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
483
484         /* Make sure the items are valid */
485         g_variant_iter_init (&iter, secrets);
486         while (g_variant_iter_next (&iter, "{&s&s}", &name, &value)) {
487                 if (!name || !strlen (name)) {
488                         g_set_error_literal (error, NM_CONNECTION_ERROR,
489                                              NM_CONNECTION_ERROR_INVALID_SETTING,
490                                              _("setting contained a secret with an empty name"));
491                         g_prefix_error (error, "%s: ", NM_SETTING_VPN_SETTING_NAME);
492                         return NM_SETTING_UPDATE_SECRET_ERROR;
493                 }
494
495                 if (!value || !strlen (value)) {
496                         g_set_error (error, NM_CONNECTION_ERROR,
497                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
498                                      _("secret value was empty"));
499                         g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, name);
500                         return NM_SETTING_UPDATE_SECRET_ERROR;
501                 }
502         }
503
504         /* Now add the items to the settings' secrets list */
505         g_variant_iter_init (&iter, secrets);
506         while (g_variant_iter_next (&iter, "{&s&s}", &name, &value)) {
507                 if (value == NULL) {
508                         g_warn_if_fail (value != NULL);
509                         continue;
510                 }
511                 if (strlen (value) == 0) {
512                         g_warn_if_fail (strlen (value) > 0);
513                         continue;
514                 }
515
516                 if (g_strcmp0 (g_hash_table_lookup (priv->secrets, name), value) == 0)
517                         continue;
518
519                 g_hash_table_insert (priv->secrets, g_strdup (name), g_strdup (value));
520                 result = NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
521         }
522
523         return result;
524 }
525
526 static int
527 update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError **error)
528 {
529         NMSettingUpdateSecretResult success = NM_SETTING_UPDATE_SECRET_ERROR;
530
531         g_return_val_if_fail (key != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
532         g_return_val_if_fail (value != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
533
534         if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) {
535                 /* Passing the string properties individually isn't correct, and won't
536                  * produce the correct result, but for some reason that's how it used
537                  * to be done.  So even though it's not correct, keep the code around
538                  * for compatibility's sake.
539                  */
540                 success = update_secret_string (setting, key, g_variant_get_string (value, NULL), error);
541         } else if (g_variant_is_of_type (value, G_VARIANT_TYPE ("a{ss}"))) {
542                 if (strcmp (key, NM_SETTING_VPN_SECRETS) != 0) {
543                         g_set_error_literal (error, NM_CONNECTION_ERROR,
544                                              NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
545                                              _("not a secret property"));
546                         g_prefix_error (error, "%s.%s ", NM_SETTING_VPN_SETTING_NAME, key);
547                 } else
548                         success = update_secret_dict (setting, value, error);
549         } else {
550                 g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
551                                      _("secret is not of correct type"));
552                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, key);
553         }
554
555         if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
556                 g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
557
558         return success;
559 }
560
561 static gboolean
562 get_secret_flags (NMSetting *setting,
563                   const char *secret_name,
564                   gboolean verify_secret,
565                   NMSettingSecretFlags *out_flags,
566                   GError **error)
567 {
568         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
569         gboolean success = FALSE;
570         char *flags_key;
571         gpointer val;
572         unsigned long tmp;
573         NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
574
575         flags_key = g_strdup_printf ("%s-flags", secret_name);
576         if (g_hash_table_lookup_extended (priv->data, flags_key, NULL, &val)) {
577                 errno = 0;
578                 tmp = strtoul ((const char *) val, NULL, 10);
579                 if ((errno == 0) && (tmp <= NM_SETTING_SECRET_FLAGS_ALL)) {
580                         flags = (NMSettingSecretFlags) tmp;
581                         success = TRUE;
582                 } else {
583                         g_set_error (error,
584                                      NM_CONNECTION_ERROR,
585                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
586                                      _("failed to convert value '%s' to uint"),
587                                      (const char *) val);
588                         g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, flags_key);
589                 }
590         } else {
591                 g_set_error_literal (error,
592                                      NM_CONNECTION_ERROR,
593                                      NM_CONNECTION_ERROR_MISSING_PROPERTY,
594                                      _("secret flags property not found"));
595                 g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, flags_key);
596         }
597         g_free (flags_key);
598         if (out_flags)
599                 *out_flags = flags;
600         return success;
601 }
602
603 static gboolean
604 set_secret_flags (NMSetting *setting,
605                   const char *secret_name,
606                   gboolean verify_secret,
607                   NMSettingSecretFlags flags,
608                   GError **error)
609 {
610         g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
611                              g_strdup_printf ("%s-flags", secret_name),
612                              g_strdup_printf ("%u", flags));
613         g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
614         return TRUE;
615 }
616
617 static GPtrArray *
618 need_secrets (NMSetting *setting)
619 {
620         /* Assume that VPN connections need secrets since they almost always will */
621         return g_ptr_array_sized_new (1);
622 }
623
624 static gboolean
625 compare_one_secret (NMSettingVpn *a,
626                     NMSettingVpn *b,
627                     NMSettingCompareFlags flags)
628 {
629         GHashTable *a_secrets, *b_secrets;
630         GHashTableIter iter;
631         const char *key, *val;
632
633         a_secrets = NM_SETTING_VPN_GET_PRIVATE (a)->secrets;
634         b_secrets = NM_SETTING_VPN_GET_PRIVATE (b)->secrets;
635
636         g_hash_table_iter_init (&iter, a_secrets);
637         while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
638                 NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
639                 NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
640
641                 nm_setting_get_secret_flags (NM_SETTING (a), key, &a_secret_flags, NULL);
642                 nm_setting_get_secret_flags (NM_SETTING (b), key, &b_secret_flags, NULL);
643
644                 /* If the secret flags aren't the same, the settings aren't the same */
645                 if (a_secret_flags != b_secret_flags)
646                         return FALSE;
647
648                 if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
649                     && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
650                         continue;
651
652                 if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
653                     && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
654                         continue;
655
656                 /* Now compare the values themselves */
657                 if (g_strcmp0 (val, nm_setting_vpn_get_secret (b, key)) != 0)
658                         return FALSE;
659         }
660
661         return TRUE;
662 }
663
664 static gboolean
665 compare_property (NMSetting *setting,
666                   NMSetting *other,
667                   const GParamSpec *prop_spec,
668                   NMSettingCompareFlags flags)
669 {
670         gboolean same;
671
672         /* We only need to treat the 'secrets' property specially */
673         if (g_strcmp0 (prop_spec->name, NM_SETTING_VPN_SECRETS) != 0)
674                 return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (setting, other, prop_spec, flags);
675
676         /* Compare A to B to ensure everything in A is found in B */
677         same = compare_one_secret (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
678         if (same) {
679                 /* And then B to A to ensure everything in B is also found in A */
680                 same = compare_one_secret (NM_SETTING_VPN (other), NM_SETTING_VPN (setting), flags);
681         }
682
683         return same;
684 }
685
686 static gboolean
687 clear_secrets_with_flags (NMSetting *setting,
688                           GParamSpec *pspec,
689                           NMSettingClearSecretsWithFlagsFn func,
690                           gpointer user_data)
691 {
692         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
693         GHashTableIter iter;
694         const char *secret;
695         gboolean changed = TRUE;
696
697         if (priv->secrets == NULL)
698                 return FALSE;
699
700         /* Iterate through secrets hash and check each entry */
701         g_hash_table_iter_init (&iter, priv->secrets);
702         while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) {
703                 NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
704
705                 nm_setting_get_secret_flags (setting, secret, &flags, NULL);
706                 if (func (setting, pspec->name, flags, user_data) == TRUE) {
707                         g_hash_table_iter_remove (&iter);
708                         changed = TRUE;
709                 }
710         }
711
712         if (changed)
713                 g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
714
715         return changed;
716 }
717
718 static void
719 destroy_one_secret (gpointer data)
720 {
721         char *secret = (char *) data;
722
723         /* Don't leave the secret lying around in memory */
724         memset (secret, 0, strlen (secret));
725         g_free (secret);
726 }
727
728 static void
729 nm_setting_vpn_init (NMSettingVpn *setting)
730 {
731         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
732
733         priv->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
734         priv->secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_one_secret);
735 }
736
737 static void
738 finalize (GObject *object)
739 {
740         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
741
742         g_free (priv->service_type);
743         g_free (priv->user_name);
744         g_hash_table_destroy (priv->data);
745         g_hash_table_destroy (priv->secrets);
746
747         G_OBJECT_CLASS (nm_setting_vpn_parent_class)->finalize (object);
748 }
749
750 static void
751 set_property (GObject *object, guint prop_id,
752               const GValue *value, GParamSpec *pspec)
753 {
754         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
755
756         switch (prop_id) {
757         case PROP_SERVICE_TYPE:
758                 g_free (priv->service_type);
759                 priv->service_type = g_value_dup_string (value);
760                 break;
761         case PROP_USER_NAME:
762                 g_free (priv->user_name);
763                 priv->user_name = g_value_dup_string (value);
764                 break;
765         case PROP_PERSISTENT:
766                 priv->persistent = g_value_get_boolean (value);
767                 break;
768         case PROP_DATA:
769                 g_hash_table_unref (priv->data);
770                 priv->data = _nm_utils_copy_strdict (g_value_get_boxed (value));
771                 break;
772         case PROP_SECRETS:
773                 g_hash_table_unref (priv->secrets);
774                 priv->secrets = _nm_utils_copy_strdict (g_value_get_boxed (value));
775                 break;
776         case PROP_TIMEOUT:
777                 priv->timeout = g_value_get_uint (value);
778                 break;
779         default:
780                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
781                 break;
782         }
783 }
784
785 static void
786 get_property (GObject *object, guint prop_id,
787               GValue *value, GParamSpec *pspec)
788 {
789         NMSettingVpn *setting = NM_SETTING_VPN (object);
790         NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
791
792         switch (prop_id) {
793         case PROP_SERVICE_TYPE:
794                 g_value_set_string (value, nm_setting_vpn_get_service_type (setting));
795                 break;
796         case PROP_USER_NAME:
797                 g_value_set_string (value, nm_setting_vpn_get_user_name (setting));
798                 break;
799         case PROP_PERSISTENT:
800                 g_value_set_boolean (value, priv->persistent);
801                 break;
802         case PROP_DATA:
803                 g_value_take_boxed (value, _nm_utils_copy_strdict (priv->data));
804                 break;
805         case PROP_SECRETS:
806                 g_value_take_boxed (value, _nm_utils_copy_strdict (priv->secrets));
807                 break;
808         case PROP_TIMEOUT:
809                 g_value_set_uint (value, nm_setting_vpn_get_timeout (setting));
810                 break;
811         default:
812                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
813                 break;
814         }
815 }
816
817 static void
818 nm_setting_vpn_class_init (NMSettingVpnClass *setting_class)
819 {
820         GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
821         NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
822
823         g_type_class_add_private (setting_class, sizeof (NMSettingVpnPrivate));
824
825         /* virtual methods */
826         object_class->set_property = set_property;
827         object_class->get_property = get_property;
828         object_class->finalize     = finalize;
829
830         parent_class->verify            = verify;
831         parent_class->update_one_secret = update_one_secret;
832         parent_class->get_secret_flags  = get_secret_flags;
833         parent_class->set_secret_flags  = set_secret_flags;
834         parent_class->need_secrets      = need_secrets;
835         parent_class->compare_property  = compare_property;
836         parent_class->clear_secrets_with_flags = clear_secrets_with_flags;
837
838         /* Properties */
839         /**
840          * NMSettingVpn:service-type:
841          *
842          * D-Bus service name of the VPN plugin that this setting uses to connect to
843          * its network.  i.e. org.freedesktop.NetworkManager.vpnc for the vpnc
844          * plugin.
845          **/
846         g_object_class_install_property
847                 (object_class, PROP_SERVICE_TYPE,
848                  g_param_spec_string (NM_SETTING_VPN_SERVICE_TYPE, "", "",
849                                       NULL,
850                                       G_PARAM_READWRITE |
851                                       G_PARAM_STATIC_STRINGS));
852
853         /**
854          * NMSettingVpn:user-name:
855          *
856          * If the VPN connection requires a user name for authentication, that name
857          * should be provided here.  If the connection is available to more than one
858          * user, and the VPN requires each user to supply a different name, then
859          * leave this property empty.  If this property is empty, NetworkManager
860          * will automatically supply the username of the user which requested the
861          * VPN connection.
862          **/
863         g_object_class_install_property
864                 (object_class, PROP_USER_NAME,
865                  g_param_spec_string (NM_SETTING_VPN_USER_NAME, "", "",
866                                       NULL,
867                                       G_PARAM_READWRITE |
868                                       G_PARAM_STATIC_STRINGS));
869
870         /**
871          * NMSettingVpn:persistent:
872          *
873          * If the VPN service supports persistence, and this property is %TRUE,
874          * the VPN will attempt to stay connected across link changes and outages,
875          * until explicitly disconnected.
876          **/
877         g_object_class_install_property
878                 (object_class, PROP_PERSISTENT,
879                  g_param_spec_boolean (NM_SETTING_VPN_PERSISTENT, "", "",
880                                        FALSE,
881                                        G_PARAM_READWRITE |
882                                        G_PARAM_STATIC_STRINGS));
883
884         /**
885          * NMSettingVpn:data:
886          *
887          * Dictionary of key/value pairs of VPN plugin specific data.  Both keys and
888          * values must be strings.
889          *
890          * Type: GHashTable(utf8,utf8)
891          **/
892         /* ---keyfile---
893          * property: data
894          * variable: separate variables named after keys of the dictionary
895          * description: The keys of the data dictionary are used as variable names directly
896          *   under [vpn] section.
897          * example: remote=ovpn.corp.com cipher=AES-256-CBC username=joe
898          * ---end---
899          */
900         g_object_class_install_property
901                 (object_class, PROP_DATA,
902                  g_param_spec_boxed (NM_SETTING_VPN_DATA, "", "",
903                                      G_TYPE_HASH_TABLE,
904                                      G_PARAM_READWRITE |
905                                      G_PARAM_STATIC_STRINGS));
906         _nm_setting_class_transform_property (parent_class, NM_SETTING_VPN_DATA,
907                                               G_VARIANT_TYPE ("a{ss}"),
908                                               _nm_utils_strdict_to_dbus,
909                                               _nm_utils_strdict_from_dbus);
910
911         /**
912          * NMSettingVpn:secrets:
913          *
914          * Dictionary of key/value pairs of VPN plugin specific secrets like
915          * passwords or private keys.  Both keys and values must be strings.
916          *
917          * Type: GHashTable(utf8,utf8)
918          **/
919         /* ---keyfile---
920          * property: secrets
921          * variable: separate variables named after keys of the dictionary
922          * description: The keys of the secrets dictionary are used as variable names directly
923          *   under [vpn-secrets] section.
924          * example: password=Popocatepetl
925          * ---end---
926          */
927         g_object_class_install_property
928                 (object_class, PROP_SECRETS,
929                  g_param_spec_boxed (NM_SETTING_VPN_SECRETS, "", "",
930                                      G_TYPE_HASH_TABLE,
931                                      G_PARAM_READWRITE |
932                                      NM_SETTING_PARAM_SECRET |
933                                      G_PARAM_STATIC_STRINGS));
934         _nm_setting_class_transform_property (parent_class, NM_SETTING_VPN_SECRETS,
935                                               G_VARIANT_TYPE ("a{ss}"),
936                                               _nm_utils_strdict_to_dbus,
937                                               _nm_utils_strdict_from_dbus);
938
939         /**
940          * NMSettingVpn:timeout:
941          *
942          * Timeout for the VPN service to establish the connection. Some services
943          * may take quite a long time to connect.
944          * Value of 0 means a default timeout, which is 60 seconds (unless overriden
945          * by vpn.timeout in configuration file). Values greater than zero mean
946          * timeout in seconds.
947          *
948          * Since: 1.2
949          **/
950         g_object_class_install_property
951                 (object_class, PROP_TIMEOUT,
952                  g_param_spec_uint (NM_SETTING_VPN_TIMEOUT, "", "",
953                                     0, G_MAXUINT32, 0,
954                                     G_PARAM_READWRITE |
955                                     G_PARAM_STATIC_STRINGS));
956 }