~dylanmccall/ubuntu/oneiric/network-manager-applet/lp852961-disable-autostart-for-gnome-shell

« back to all changes in this revision

Viewing changes to src/gconf-helpers/nma-gconf-connection.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2011-05-30 13:25:18 UTC
  • mto: This revision was merged to the branch mainline in revision 68.
  • Revision ID: james.westby@ubuntu.com-20110530132518-ya5i5mcrl8szsmoj
Tags: upstream-0.8.9997+git.20110529t170033.9ec4c5d
ImportĀ upstreamĀ versionĀ 0.8.9997+git.20110529t170033.9ec4c5d

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
 
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or modify
5
 
 * it under the terms of the GNU General Public License as published by
6
 
 * the Free Software Foundation; either version 2 of the License, or
7
 
 * (at your option) any later version.
8
 
 *
9
 
 * This program 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
12
 
 * GNU General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU General Public License along
15
 
 * with this program; if not, write to the Free Software Foundation, Inc.,
16
 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 
 *
18
 
 * (C) Copyright 2008 Novell, Inc.
19
 
 * (C) Copyright 2008 - 2009 Red Hat, Inc.
20
 
 */
21
 
 
22
 
#include <string.h>
23
 
#include <unistd.h>
24
 
 
25
 
#include <dbus/dbus.h>
26
 
#include <dbus/dbus-glib.h>
27
 
#include <dbus/dbus-glib-lowlevel.h>
28
 
#include <gnome-keyring.h>
29
 
 
30
 
#include <nm-setting-connection.h>
31
 
#include <nm-setting-vpn.h>
32
 
#include <nm-setting-8021x.h>
33
 
 
34
 
#include "nma-gconf-connection.h"
35
 
#include "gconf-helpers.h"
36
 
#include "nm-utils.h"
37
 
#include "utils.h"
38
 
#include "nma-marshal.h"
39
 
#include "nm-settings-interface.h"
40
 
 
41
 
static NMSettingsConnectionInterface *parent_settings_connection_iface;
42
 
 
43
 
static void settings_connection_interface_init (NMSettingsConnectionInterface *class);
44
 
 
45
 
G_DEFINE_TYPE_EXTENDED (NMAGConfConnection, nma_gconf_connection, NM_TYPE_EXPORTED_CONNECTION, 0,
46
 
                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE,
47
 
                                               settings_connection_interface_init))
48
 
 
49
 
#define NMA_GCONF_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMA_TYPE_GCONF_CONNECTION, NMAGConfConnectionPrivate))
50
 
 
51
 
typedef struct {
52
 
        GConfClient *client;
53
 
        char *dir;
54
 
 
55
 
        gboolean disposed;
56
 
} NMAGConfConnectionPrivate;
57
 
 
58
 
enum {
59
 
        PROP_0,
60
 
        PROP_CLIENT,
61
 
        PROP_DIR,
62
 
 
63
 
        LAST_PROP
64
 
};
65
 
 
66
 
enum {
67
 
        NEW_SECRETS_REQUESTED,
68
 
 
69
 
        LAST_SIGNAL
70
 
};
71
 
 
72
 
static guint signals[LAST_SIGNAL] = { 0 };
73
 
 
74
 
NMAGConfConnection *
75
 
nma_gconf_connection_new (GConfClient *client, const char *conf_dir)
76
 
{
77
 
        NMConnection *connection;
78
 
        NMAGConfConnection *gconf_connection;
79
 
 
80
 
        g_return_val_if_fail (GCONF_IS_CLIENT (client), NULL);
81
 
        g_return_val_if_fail (conf_dir != NULL, NULL);
82
 
 
83
 
        /* retrieve GConf data */
84
 
        connection = nm_gconf_read_connection (client, conf_dir);
85
 
        if (connection) {
86
 
                gconf_connection = nma_gconf_connection_new_from_connection (client, conf_dir, connection);
87
 
                g_object_unref (connection);
88
 
        } else {
89
 
                nm_warning ("No connection read from GConf at %s.", conf_dir);
90
 
                gconf_connection = NULL;
91
 
        }
92
 
        
93
 
        return gconf_connection;
94
 
}
95
 
 
96
 
NMAGConfConnection *
97
 
nma_gconf_connection_new_from_connection (GConfClient *client,
98
 
                                          const char *conf_dir,
99
 
                                          NMConnection *connection)
100
 
{
101
 
        GObject *object;
102
 
        NMAGConfConnection *self;
103
 
        GError *error = NULL;
104
 
        gboolean success;
105
 
        GHashTable *settings;
106
 
 
107
 
        g_return_val_if_fail (GCONF_IS_CLIENT (client), NULL);
108
 
        g_return_val_if_fail (conf_dir != NULL, NULL);
109
 
        g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
110
 
 
111
 
        /* Ensure the connection is valid first */
112
 
        success = nm_connection_verify (connection, &error);
113
 
        if (!success) {
114
 
                g_warning ("Invalid connection %s: '%s' / '%s' invalid: %d",
115
 
                           conf_dir,
116
 
                           g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
117
 
                           (error && error->message) ? error->message : "(unknown)",
118
 
                           error ? error->code : -1);
119
 
                g_clear_error (&error);
120
 
                return NULL;
121
 
        }
122
 
 
123
 
        object = g_object_new (NMA_TYPE_GCONF_CONNECTION,
124
 
                               NMA_GCONF_CONNECTION_CLIENT, client,
125
 
                               NMA_GCONF_CONNECTION_DIR, conf_dir,
126
 
                               NM_CONNECTION_SCOPE, NM_CONNECTION_SCOPE_USER,
127
 
                               NULL);
128
 
        if (!object)
129
 
                return NULL;
130
 
 
131
 
        self = NMA_GCONF_CONNECTION (object);
132
 
 
133
 
        /* Fill certs so that the nm_connection_replace_settings verification works */
134
 
        settings = nm_connection_to_hash (connection);
135
 
        success = nm_connection_replace_settings (NM_CONNECTION (self), settings, NULL);
136
 
        g_hash_table_destroy (settings);
137
 
 
138
 
        /* Already verified the settings above, they had better be OK */
139
 
        g_assert (success);
140
 
 
141
 
        return self;
142
 
}
143
 
 
144
 
const char *
145
 
nma_gconf_connection_get_gconf_path (NMAGConfConnection *self)
146
 
{
147
 
        g_return_val_if_fail (NMA_IS_GCONF_CONNECTION (self), NULL);
148
 
 
149
 
        return NMA_GCONF_CONNECTION_GET_PRIVATE (self)->dir;
150
 
}
151
 
 
152
 
static void
153
 
add_vpn_user_name (NMConnection *connection)
154
 
{
155
 
        NMSettingVPN *s_vpn;
156
 
        const char *user_name;
157
 
 
158
 
        /* Insert the default VPN username when NM gets the connection; it doesn't
159
 
         * get stored in GConf since it's always available and could change at any
160
 
         * time, so it's inserted on-the-fly.
161
 
         */
162
 
        s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
163
 
        if (s_vpn) {
164
 
                user_name = g_get_user_name ();
165
 
                g_assert (g_utf8_validate (user_name, -1, NULL));
166
 
                g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, user_name, NULL);
167
 
        }
168
 
}
169
 
 
170
 
gboolean
171
 
nma_gconf_connection_gconf_changed (NMAGConfConnection *self)
172
 
{
173
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (self);
174
 
        NMConnection *new;
175
 
        GHashTable *new_settings;
176
 
        GError *error = NULL;
177
 
        gboolean success;
178
 
 
179
 
        new = nm_gconf_read_connection (priv->client, priv->dir);
180
 
        if (!new) {
181
 
                g_warning ("No connection read from GConf at %s.", priv->dir);
182
 
                goto invalid;
183
 
        }
184
 
 
185
 
        success = nm_connection_verify (new, &error);
186
 
        if (!success) {
187
 
                g_warning ("%s: Invalid connection %s: '%s' / '%s' invalid: %d",
188
 
                           __func__, priv->dir,
189
 
                           g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
190
 
                           error->message, error->code);
191
 
                g_object_unref (new);
192
 
                goto invalid;
193
 
        }
194
 
 
195
 
        /* Ignore the GConf update if nothing changed */
196
 
        if (nm_connection_compare (NM_CONNECTION (self), new, NM_SETTING_COMPARE_FLAG_EXACT)) {
197
 
                g_object_unref (new);
198
 
                return TRUE;
199
 
        }
200
 
 
201
 
        new_settings = nm_connection_to_hash (new);
202
 
        success = nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error);
203
 
        g_hash_table_destroy (new_settings);
204
 
        g_object_unref (new);
205
 
 
206
 
        if (!success) {
207
 
                g_warning ("%s: '%s' / '%s' invalid: %d",
208
 
                           __func__,
209
 
                           error ? g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)) : "(none)",
210
 
                           (error && error->message) ? error->message : "(none)",
211
 
                           error ? error->code : -1);
212
 
                goto invalid;
213
 
        }
214
 
 
215
 
        add_vpn_user_name (NM_CONNECTION (self));
216
 
 
217
 
        nm_settings_connection_interface_emit_updated (NM_SETTINGS_CONNECTION_INTERFACE (self));
218
 
        return TRUE;
219
 
 
220
 
invalid:
221
 
        g_clear_error (&error);
222
 
        g_signal_emit_by_name (self, NM_SETTINGS_CONNECTION_INTERFACE_REMOVED);
223
 
        return FALSE;
224
 
}
225
 
 
226
 
/******************************************************/
227
 
 
228
 
static GValue *
229
 
string_to_gvalue (const char *str)
230
 
{
231
 
        GValue *val;
232
 
 
233
 
        val = g_slice_new0 (GValue);
234
 
        g_value_init (val, G_TYPE_STRING);
235
 
        g_value_set_string (val, str);
236
 
 
237
 
        return val;
238
 
}
239
 
 
240
 
#define FILE_TAG "file://"
241
 
 
242
 
static GValue *
243
 
path_to_gvalue (const char *path)
244
 
{
245
 
        GValue *val;
246
 
        GByteArray *array;
247
 
 
248
 
        array = g_byte_array_sized_new (strlen (FILE_TAG) + strlen (path) + 1);
249
 
        g_byte_array_append (array, (guint8 *) FILE_TAG, strlen (FILE_TAG));
250
 
        g_byte_array_append (array, (guint8 *) path, strlen (path) + 1);  /* +1 for the trailing NULL */
251
 
 
252
 
        val = g_slice_new0 (GValue);
253
 
        g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
254
 
        g_value_take_boxed (val, array);
255
 
 
256
 
        return val;
257
 
}
258
 
 
259
 
static void
260
 
destroy_gvalue (gpointer data)
261
 
{
262
 
        GValue *value = (GValue *) data;
263
 
 
264
 
        g_value_unset (value);
265
 
        g_slice_free (GValue, value);
266
 
}
267
 
 
268
 
static GHashTable *
269
 
nma_gconf_connection_get_keyring_items (NMAGConfConnection *self,
270
 
                                        const char *setting_name,
271
 
                                        GError **error)
272
 
{
273
 
        NMAGConfConnectionPrivate *priv;
274
 
        NMSettingConnection *s_con;
275
 
        GHashTable *secrets;
276
 
        GList *found_list = NULL;
277
 
        GnomeKeyringResult ret;
278
 
        GList *iter;
279
 
        const char *connection_name;
280
 
        char *path = NULL;
281
 
 
282
 
        g_return_val_if_fail (self != NULL, NULL);
283
 
        g_return_val_if_fail (setting_name != NULL, NULL);
284
 
        g_return_val_if_fail (error != NULL, NULL);
285
 
        g_return_val_if_fail (*error == NULL, NULL);
286
 
 
287
 
        priv = NMA_GCONF_CONNECTION_GET_PRIVATE (self);
288
 
 
289
 
        s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION));
290
 
        g_assert (s_con);
291
 
 
292
 
        connection_name = nm_setting_connection_get_id (s_con);
293
 
        g_assert (connection_name);
294
 
 
295
 
        pre_keyring_callback ();
296
 
 
297
 
        ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
298
 
                                              &found_list,
299
 
                                              KEYRING_UUID_TAG,
300
 
                                              GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
301
 
                                                                                  nm_setting_connection_get_uuid (s_con),
302
 
                                              KEYRING_SN_TAG,
303
 
                                              GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
304
 
                                              setting_name,
305
 
                                              NULL);
306
 
        if ((ret != GNOME_KEYRING_RESULT_OK) || (g_list_length (found_list) == 0))
307
 
                return NULL;
308
 
 
309
 
        secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
310
 
 
311
 
        for (iter = found_list; iter != NULL; iter = g_list_next (iter)) {
312
 
                GnomeKeyringFound *found = (GnomeKeyringFound *) iter->data;
313
 
                int i;
314
 
                const char *key_name = NULL;
315
 
 
316
 
                for (i = 0; i < found->attributes->len; i++) {
317
 
                        GnomeKeyringAttribute *attr;
318
 
 
319
 
                        attr = &(gnome_keyring_attribute_list_index (found->attributes, i));
320
 
                        if (   (strcmp (attr->name, KEYRING_SK_TAG) == 0)
321
 
                            && (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING)) {
322
 
                                key_name = attr->value.string;
323
 
                                break;
324
 
                        }
325
 
                }
326
 
 
327
 
                if (key_name == NULL) {
328
 
                        g_set_error (error,
329
 
                                     NM_SETTINGS_INTERFACE_ERROR,
330
 
                                     NM_SETTINGS_INTERFACE_ERROR_SECRETS_UNAVAILABLE,
331
 
                                     "%s.%d - Internal error; keyring item '%s/%s' didn't "
332
 
                                     "have a 'setting-key' attribute.",
333
 
                                     __FILE__, __LINE__, connection_name, setting_name);
334
 
                        break;
335
 
                }
336
 
 
337
 
                g_hash_table_insert (secrets,
338
 
                                     g_strdup (key_name),
339
 
                                     string_to_gvalue (found->secret));
340
 
        }
341
 
 
342
 
        /* The phase1 and phase2 private key are still marked as 'secret' for
343
 
         * backwards compat, but since they don't get stored in the keyring since
344
 
         * they aren't really secret (because we now use paths everywhere and not
345
 
         * the decrypted private key like 0.7.x).  So we need to grab them out of
346
 
         * GConf and add them to the returned secret hash.
347
 
         */
348
 
        /* Private key path */
349
 
        path = NULL;
350
 
        if (nm_gconf_get_string_helper (priv->client,
351
 
                                        priv->dir,
352
 
                                        NM_SETTING_802_1X_PRIVATE_KEY,
353
 
                                        NM_SETTING_802_1X_SETTING_NAME,
354
 
                                        &path)) {
355
 
                g_hash_table_insert (secrets,
356
 
                                     g_strdup (NM_SETTING_802_1X_PRIVATE_KEY),
357
 
                                     path_to_gvalue (path));
358
 
                g_free (path);
359
 
        }
360
 
 
361
 
        /* Phase2 private key path */
362
 
        path = NULL;
363
 
        if (nm_gconf_get_string_helper (priv->client,
364
 
                                        priv->dir,
365
 
                                        NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
366
 
                                        NM_SETTING_802_1X_SETTING_NAME,
367
 
                                        &path)) {
368
 
                g_hash_table_insert (secrets,
369
 
                                     g_strdup (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY),
370
 
                                     path_to_gvalue (path));
371
 
                g_free (path);
372
 
        }
373
 
 
374
 
        if (*error) {
375
 
                nm_warning ("%s: error reading secrets: (%d) %s", __func__,
376
 
                            (*error)->code, (*error)->message);
377
 
                g_hash_table_destroy (secrets);
378
 
                secrets = NULL;
379
 
        }
380
 
 
381
 
        gnome_keyring_found_list_free (found_list);
382
 
        return secrets;
383
 
}
384
 
 
385
 
static void
386
 
delete_done (GnomeKeyringResult result, gpointer user_data)
387
 
{
388
 
}
389
 
 
390
 
static void
391
 
clear_keyring_items (NMAGConfConnection *self)
392
 
{
393
 
        NMSettingConnection *s_con;
394
 
        const char *uuid;
395
 
        GList *found_list = NULL;
396
 
        GnomeKeyringResult ret;
397
 
        GList *iter;
398
 
 
399
 
        g_return_if_fail (self != NULL);
400
 
 
401
 
        s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
402
 
        g_return_if_fail (s_con != NULL);
403
 
 
404
 
        uuid = nm_setting_connection_get_uuid (s_con);
405
 
        g_return_if_fail (uuid != NULL);
406
 
 
407
 
        pre_keyring_callback ();
408
 
 
409
 
        ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
410
 
                                              &found_list,
411
 
                                              KEYRING_UUID_TAG,
412
 
                                              GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
413
 
                                              uuid,
414
 
                                              NULL);
415
 
        if (ret == GNOME_KEYRING_RESULT_OK) {
416
 
                for (iter = found_list; iter != NULL; iter = g_list_next (iter)) {
417
 
                        GnomeKeyringFound *found = (GnomeKeyringFound *) iter->data;
418
 
 
419
 
                        gnome_keyring_item_delete (found->keyring,
420
 
                                                   found->item_id,
421
 
                                                   delete_done,
422
 
                                                   NULL,
423
 
                                                   NULL);
424
 
                }
425
 
                gnome_keyring_found_list_free (found_list);
426
 
        }
427
 
}
428
 
 
429
 
void
430
 
nma_gconf_connection_update (NMAGConfConnection *self,
431
 
                             gboolean ignore_secrets)
432
 
{
433
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (self);
434
 
 
435
 
        nm_gconf_write_connection (NM_CONNECTION (self),
436
 
                                   priv->client,
437
 
                                   priv->dir,
438
 
                                   ignore_secrets);
439
 
        gconf_client_notify (priv->client, priv->dir);
440
 
        gconf_client_suggest_sync (priv->client, NULL);
441
 
}
442
 
 
443
 
/******************************************************/
444
 
 
445
 
static gboolean
446
 
is_otp_always_ask (NMConnection *connection)
447
 
{
448
 
        NMSetting8021x *s_8021x;
449
 
        NMSettingConnection *s_con;
450
 
        const char *uuid, *eap_method, *phase2;
451
 
 
452
 
        s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
453
 
        if (s_8021x) {
454
 
                gboolean can_always_ask = FALSE;
455
 
 
456
 
                /* Check if PEAP or TTLS is used */
457
 
                eap_method = nm_setting_802_1x_get_eap_method (s_8021x, 0);
458
 
                s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
459
 
                if (!strcmp (eap_method, "peap"))
460
 
                        can_always_ask = TRUE;
461
 
                else if (!strcmp (eap_method, "ttls")) {
462
 
                        /* Now make sure the phase2 method isn't TLS */
463
 
                        phase2 = nm_setting_802_1x_get_phase2_auth (s_8021x);
464
 
                        if (phase2 && strcmp (phase2, "tls"))
465
 
                                can_always_ask = TRUE;
466
 
                        else {
467
 
                                phase2 = nm_setting_802_1x_get_phase2_autheap (s_8021x);
468
 
                                if (phase2 && strcmp (phase2, "tls"))
469
 
                                        can_always_ask = TRUE;
470
 
                        }
471
 
                }
472
 
 
473
 
                if (can_always_ask) {
474
 
                        uuid = nm_setting_connection_get_uuid (s_con);
475
 
                        if (nm_gconf_get_8021x_password_always_ask (uuid))
476
 
                                return TRUE;
477
 
                }
478
 
        }
479
 
        return FALSE;
480
 
}
481
 
 
482
 
static gboolean
483
 
update (NMSettingsConnectionInterface *connection,
484
 
            NMSettingsConnectionInterfaceUpdateFunc callback,
485
 
            gpointer user_data)
486
 
{
487
 
        gboolean always_ask;
488
 
 
489
 
        always_ask = is_otp_always_ask (NM_CONNECTION (connection));
490
 
 
491
 
        /* It's assumed that secrets are included in the new connection data.
492
 
         * However, update the secrets only if "always ask" is not set.
493
 
         */
494
 
        nma_gconf_connection_update (NMA_GCONF_CONNECTION (connection), always_ask);
495
 
 
496
 
        return parent_settings_connection_iface->update (connection, callback, user_data);
497
 
}
498
 
 
499
 
static gboolean 
500
 
do_delete (NMSettingsConnectionInterface *connection,
501
 
               NMSettingsConnectionInterfaceDeleteFunc callback,
502
 
               gpointer user_data)
503
 
{
504
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (connection);
505
 
        gboolean success;
506
 
        GError *error = NULL;
507
 
 
508
 
        /* Clean up keyring keys */
509
 
        clear_keyring_items (NMA_GCONF_CONNECTION (connection));
510
 
 
511
 
        success = gconf_client_recursive_unset (priv->client, priv->dir, 0, &error);
512
 
        if (!success) {
513
 
                callback (connection, error, user_data);
514
 
                g_error_free (error);
515
 
                return FALSE;
516
 
        }
517
 
        gconf_client_suggest_sync (priv->client, NULL);
518
 
 
519
 
        return parent_settings_connection_iface->delete (connection, callback, user_data);
520
 
}
521
 
 
522
 
static gboolean
523
 
internal_get_secrets (NMSettingsConnectionInterface *connection,
524
 
                      const char *setting_name,
525
 
                      const char **hints,
526
 
                      gboolean request_new,
527
 
                      gboolean local,
528
 
                      NMANewSecretsRequestedFunc callback,
529
 
                      gpointer callback_data,
530
 
                      GError **error)
531
 
{
532
 
        NMAGConfConnection *self = NMA_GCONF_CONNECTION (connection);
533
 
        GHashTable *settings = NULL;
534
 
        GHashTable *secrets = NULL;
535
 
        NMSettingConnection *s_con;
536
 
        NMSetting *setting;
537
 
        const char *connection_id;
538
 
        const char *connection_type;
539
 
 
540
 
        setting = nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name);
541
 
        if (!setting) {
542
 
                g_set_error (error,
543
 
                             NM_SETTINGS_INTERFACE_ERROR,
544
 
                             NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION,
545
 
                             "%s.%d - Connection didn't have requested setting '%s'.",
546
 
                             __FILE__, __LINE__, setting_name);
547
 
                return FALSE;
548
 
        }
549
 
 
550
 
        s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
551
 
        g_assert (s_con);
552
 
        connection_id = nm_setting_connection_get_id (s_con);
553
 
        connection_type = nm_setting_connection_get_connection_type (s_con);
554
 
 
555
 
        if (!s_con || !connection_id || !strlen (connection_id) || !connection_type) {
556
 
                g_set_error (error,
557
 
                             NM_SETTINGS_INTERFACE_ERROR,
558
 
                             NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION,
559
 
                             "%s.%d - Connection didn't have required '"
560
 
                             NM_SETTING_CONNECTION_SETTING_NAME
561
 
                             "' setting , or the connection name was invalid.",
562
 
                             __FILE__, __LINE__);
563
 
                return FALSE;
564
 
        }
565
 
 
566
 
        /* Only try to get new secrets for D-Bus requests */
567
 
        if (local) {
568
 
                secrets = nma_gconf_connection_get_keyring_items (self, setting_name, error);
569
 
                if (!secrets && error && *error)
570
 
                        return FALSE;
571
 
        } else {
572
 
                /* VPN passwords are handled by the VPN plugin's auth dialog */
573
 
                if (!strcmp (connection_type, NM_SETTING_VPN_SETTING_NAME))
574
 
                        goto get_secrets;
575
 
 
576
 
                if (request_new) {
577
 
                        nm_info ("New secrets for %s/%s requested; ask the user",
578
 
                                 connection_id, setting_name);
579
 
                        nm_connection_clear_secrets (NM_CONNECTION (self));
580
 
                        goto get_secrets;
581
 
                }
582
 
 
583
 
                /* OTP connections marked as always ask */
584
 
                if (is_otp_always_ask (NM_CONNECTION (self)))
585
 
                        goto get_secrets;
586
 
 
587
 
                secrets = nma_gconf_connection_get_keyring_items (self, setting_name, error);
588
 
                if (!secrets) {
589
 
                        if (error && *error)
590
 
                                return FALSE;
591
 
 
592
 
                        nm_info ("No keyring secrets found for %s/%s; asking user.",
593
 
                                 connection_id, setting_name);
594
 
                        goto get_secrets;
595
 
                }
596
 
 
597
 
                if (g_hash_table_size (secrets) == 0) {
598
 
                        g_hash_table_destroy (secrets);
599
 
                        nm_warning ("%s.%d - Secrets were found for setting '%s' but none"
600
 
                                          " were valid.", __FILE__, __LINE__, setting_name);
601
 
                        goto get_secrets;
602
 
                }
603
 
 
604
 
                /* If there were hints, and none of the hints were returned by the keyring,
605
 
                 * get some new secrets.
606
 
                 */
607
 
                if (hints && g_strv_length ((char **) hints)) {
608
 
                        GHashTableIter iter;
609
 
                        gpointer key, value;
610
 
                        gboolean found = FALSE;
611
 
 
612
 
                        g_hash_table_iter_init (&iter, secrets);
613
 
                        while (g_hash_table_iter_next (&iter, &key, &value) && !found) {
614
 
                                const char **hint = hints;
615
 
 
616
 
                                while (!found && *hint) {
617
 
                                        if (!strcmp (*hint, (const char *) key) && value && G_IS_VALUE (value)) {
618
 
                                                found = TRUE;
619
 
                                                break;
620
 
                                        }
621
 
                                        hint++;
622
 
                                }
623
 
                        }
624
 
 
625
 
                        if (!found) {
626
 
                                g_hash_table_destroy (secrets);
627
 
                                goto get_secrets;
628
 
                        }
629
 
                }
630
 
        }
631
 
 
632
 
        /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
633
 
         * will contain all the individual settings hashes.
634
 
         */
635
 
        settings = g_hash_table_new_full (g_str_hash, g_str_equal,
636
 
                                          g_free,
637
 
                                          (GDestroyNotify) g_hash_table_destroy);
638
 
        if (secrets)
639
 
                g_hash_table_insert (settings, g_strdup (setting_name), secrets);
640
 
        callback (NM_SETTINGS_CONNECTION_INTERFACE (self), settings, NULL, callback_data);
641
 
        g_hash_table_destroy (settings);
642
 
        return TRUE;
643
 
 
644
 
get_secrets:
645
 
        g_signal_emit (self,
646
 
                       signals[NEW_SECRETS_REQUESTED],
647
 
                       0,
648
 
                       setting_name,
649
 
                       hints,
650
 
                       request_new,
651
 
                       callback,
652
 
                       callback_data);
653
 
        return TRUE;
654
 
}
655
 
 
656
 
typedef struct {
657
 
        NMSettingsConnectionInterfaceGetSecretsFunc callback;
658
 
        gpointer callback_data;
659
 
} GetSecretsInfo;
660
 
 
661
 
static void
662
 
get_secrets_cb (NMSettingsConnectionInterface *connection,
663
 
                GHashTable *settings,
664
 
                GError *error,
665
 
                gpointer user_data)
666
 
{
667
 
        GetSecretsInfo *info = user_data;
668
 
 
669
 
        info->callback (NM_SETTINGS_CONNECTION_INTERFACE (connection), settings, error, info->callback_data);
670
 
        g_free (info);
671
 
}
672
 
 
673
 
static gboolean
674
 
get_secrets (NMSettingsConnectionInterface *connection,
675
 
                 const char *setting_name,
676
 
             const char **hints,
677
 
             gboolean request_new,
678
 
             NMSettingsConnectionInterfaceGetSecretsFunc callback,
679
 
             gpointer user_data)
680
 
{
681
 
        GetSecretsInfo *info;
682
 
        GError *error = NULL;
683
 
 
684
 
        info = g_malloc0 (sizeof (GetSecretsInfo));
685
 
        info->callback = callback;
686
 
        info->callback_data = user_data;
687
 
 
688
 
        if (!internal_get_secrets (connection,
689
 
                                   setting_name,
690
 
                                   hints,
691
 
                                   request_new,
692
 
                                   TRUE,
693
 
                                   get_secrets_cb,
694
 
                                   info,
695
 
                                   &error)) {
696
 
                callback (NM_SETTINGS_CONNECTION_INTERFACE (connection), NULL, error, user_data);
697
 
                g_error_free (error);
698
 
                g_free (info);
699
 
                return FALSE;
700
 
        }
701
 
 
702
 
        return TRUE;
703
 
}
704
 
 
705
 
/******************************************************/
706
 
 
707
 
static gboolean
708
 
is_dbus_request_authorized (DBusGMethodInvocation *context,
709
 
                            gboolean allow_user,
710
 
                            GError **error)
711
 
{
712
 
        DBusGConnection *bus = NULL;
713
 
        DBusConnection *connection = NULL;
714
 
        char *sender = NULL;
715
 
        gulong sender_uid = G_MAXULONG;
716
 
        DBusError dbus_error;
717
 
        gboolean success = FALSE;
718
 
 
719
 
        sender = dbus_g_method_get_sender (context);
720
 
        if (!sender) {
721
 
                g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
722
 
                             NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR,
723
 
                             "%s", "Could not determine D-Bus requestor");
724
 
                goto out;
725
 
        }
726
 
 
727
 
        bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
728
 
        if (!bus) {
729
 
                g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
730
 
                             NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR,
731
 
                             "%s", "Could not get the system bus");
732
 
                goto out;
733
 
        }
734
 
        connection = dbus_g_connection_get_connection (bus);
735
 
        if (!connection) {
736
 
                g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
737
 
                             NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR,
738
 
                             "%s", "Could not get the D-Bus system bus");
739
 
                goto out;
740
 
        }
741
 
 
742
 
        dbus_error_init (&dbus_error);
743
 
        sender_uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
744
 
        if (dbus_error_is_set (&dbus_error)) {
745
 
                dbus_error_free (&dbus_error);
746
 
                g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
747
 
                             NM_SETTINGS_INTERFACE_ERROR_PERMISSION_DENIED,
748
 
                             "%s", "Could not determine the Unix user ID of the requestor");
749
 
                goto out;
750
 
        }
751
 
 
752
 
        /* And finally, the actual UID check */
753
 
        if (   (allow_user && (sender_uid == geteuid()))
754
 
            || (sender_uid == 0))
755
 
                success = TRUE;
756
 
        else {
757
 
                g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
758
 
                             NM_SETTINGS_INTERFACE_ERROR_PERMISSION_DENIED,
759
 
                             "%s", "Requestor UID does not match the UID of the user settings service");
760
 
        }
761
 
 
762
 
out:
763
 
        if (bus)
764
 
                dbus_g_connection_unref (bus);
765
 
        g_free (sender);
766
 
        return success;
767
 
}
768
 
 
769
 
static void
770
 
con_update_cb (NMSettingsConnectionInterface *connection,
771
 
               GError *error,
772
 
               gpointer user_data)
773
 
{
774
 
        DBusGMethodInvocation *context = user_data;
775
 
 
776
 
        if (error)
777
 
                dbus_g_method_return_error (context, error);
778
 
        else
779
 
                dbus_g_method_return (context);
780
 
}
781
 
 
782
 
static void
783
 
dbus_update (NMExportedConnection *exported,
784
 
             GHashTable *new_settings,
785
 
             DBusGMethodInvocation *context)
786
 
{
787
 
        NMAGConfConnection *self = NMA_GCONF_CONNECTION (exported);
788
 
        NMConnection *new;
789
 
        gboolean success = FALSE;
790
 
        GError *error = NULL;
791
 
 
792
 
        /* Restrict Update to execution by the current user and root for DBus invocation */
793
 
        if (!is_dbus_request_authorized (context, TRUE, &error)) {
794
 
                dbus_g_method_return_error (context, error);
795
 
                g_error_free (error);
796
 
                return;
797
 
        }
798
 
 
799
 
        new = nm_connection_new_from_hash (new_settings, &error);
800
 
        if (!new) {
801
 
                dbus_g_method_return_error (context, error);
802
 
                g_error_free (error);
803
 
                return;
804
 
        }
805
 
        g_object_unref (new);
806
 
        
807
 
        success = nm_connection_replace_settings (NM_CONNECTION (self), new_settings, NULL);
808
 
        /* Settings better be valid; we verified them above */
809
 
        g_assert (success);
810
 
 
811
 
        nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (self),
812
 
                                                 con_update_cb,
813
 
                                                 context);
814
 
}
815
 
 
816
 
static void
817
 
con_delete_cb (NMSettingsConnectionInterface *connection,
818
 
               GError *error,
819
 
               gpointer user_data)
820
 
{
821
 
        DBusGMethodInvocation *context = user_data;
822
 
 
823
 
        if (error)
824
 
                dbus_g_method_return_error (context, error);
825
 
        else
826
 
                dbus_g_method_return (context);
827
 
}
828
 
 
829
 
static void
830
 
dbus_delete (NMExportedConnection *exported,
831
 
             DBusGMethodInvocation *context)
832
 
{
833
 
        NMAGConfConnection *self = NMA_GCONF_CONNECTION (exported);
834
 
        GError *error = NULL;
835
 
 
836
 
        /* Restrict Update to execution by the current user and root for DBus invocation */
837
 
        if (!is_dbus_request_authorized (context, TRUE, &error)) {
838
 
                dbus_g_method_return_error (context, error);
839
 
                g_error_free (error);
840
 
                return;
841
 
        }
842
 
 
843
 
        nm_settings_connection_interface_delete (NM_SETTINGS_CONNECTION_INTERFACE (self),
844
 
                                                 con_delete_cb,
845
 
                                                 context);
846
 
}
847
 
 
848
 
static void
849
 
dbus_get_secrets_cb (NMSettingsConnectionInterface *connection,
850
 
                     GHashTable *settings,
851
 
                     GError *error,
852
 
                     gpointer user_data)
853
 
{
854
 
        DBusGMethodInvocation *context = user_data;
855
 
 
856
 
        if (error)
857
 
                dbus_g_method_return_error (context, error);
858
 
        else
859
 
                dbus_g_method_return (context, settings);
860
 
}
861
 
 
862
 
static void
863
 
dbus_get_secrets (NMExportedConnection *connection,
864
 
                  const gchar *setting_name,
865
 
                  const gchar **hints,
866
 
                  gboolean request_new,
867
 
                  DBusGMethodInvocation *context)
868
 
{
869
 
        GError *error = NULL;
870
 
 
871
 
        /* Restrict GetSecrets to execution by root for DBus invocation */
872
 
        if (!is_dbus_request_authorized (context, FALSE, &error)) {
873
 
                dbus_g_method_return_error (context, error);
874
 
                g_error_free (error);
875
 
                return;
876
 
        }
877
 
 
878
 
        if (!internal_get_secrets (NM_SETTINGS_CONNECTION_INTERFACE (connection),
879
 
                                   setting_name,
880
 
                                   hints,
881
 
                                   request_new,
882
 
                                   FALSE,
883
 
                                   dbus_get_secrets_cb,
884
 
                                   context,
885
 
                                   &error)) {
886
 
                dbus_g_method_return_error (context, error);
887
 
                g_error_free (error);
888
 
        }
889
 
}
890
 
 
891
 
static GHashTable *
892
 
dbus_get_settings (NMExportedConnection *connection, GError **error)
893
 
{
894
 
        add_vpn_user_name (NM_CONNECTION (connection));
895
 
 
896
 
        return NM_EXPORTED_CONNECTION_CLASS (nma_gconf_connection_parent_class)->get_settings (connection, error);
897
 
}
898
 
 
899
 
/************************************************************/
900
 
 
901
 
static void
902
 
settings_connection_interface_init (NMSettingsConnectionInterface *iface)
903
 
{
904
 
        parent_settings_connection_iface = g_type_interface_peek_parent (iface);
905
 
 
906
 
        iface->update = update;
907
 
        iface->delete = do_delete;
908
 
        iface->get_secrets = get_secrets;
909
 
}
910
 
 
911
 
static void
912
 
nma_gconf_connection_init (NMAGConfConnection *connection)
913
 
{
914
 
}
915
 
 
916
 
static GObject *
917
 
constructor (GType type,
918
 
             guint n_construct_params,
919
 
             GObjectConstructParam *construct_params)
920
 
{
921
 
        GObject *object;
922
 
        NMAGConfConnectionPrivate *priv;
923
 
 
924
 
        object = G_OBJECT_CLASS (nma_gconf_connection_parent_class)->constructor (type, n_construct_params, construct_params);
925
 
 
926
 
        if (!object)
927
 
                return NULL;
928
 
 
929
 
        priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
930
 
 
931
 
        if (!priv->client) {
932
 
                nm_warning ("GConfClient not provided.");
933
 
                g_object_unref (object);
934
 
                return NULL;
935
 
        }
936
 
 
937
 
        if (!priv->dir) {
938
 
                nm_warning ("GConf directory not provided.");
939
 
                g_object_unref (object);
940
 
                return NULL;
941
 
        }
942
 
 
943
 
        return object;
944
 
}
945
 
 
946
 
static void
947
 
dispose (GObject *object)
948
 
{
949
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
950
 
 
951
 
        if (priv->disposed)
952
 
                return;
953
 
        priv->disposed = TRUE;
954
 
 
955
 
        g_object_unref (priv->client);
956
 
 
957
 
        G_OBJECT_CLASS (nma_gconf_connection_parent_class)->dispose (object);
958
 
}
959
 
 
960
 
static void
961
 
finalize (GObject *object)
962
 
{
963
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
964
 
 
965
 
        g_free (priv->dir);
966
 
 
967
 
        G_OBJECT_CLASS (nma_gconf_connection_parent_class)->finalize (object);
968
 
}
969
 
 
970
 
static void
971
 
set_property (GObject *object, guint prop_id,
972
 
                    const GValue *value, GParamSpec *pspec)
973
 
{
974
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
975
 
 
976
 
        switch (prop_id) {
977
 
        case PROP_CLIENT:
978
 
                /* Construct only */
979
 
                priv->client = GCONF_CLIENT (g_value_dup_object (value));
980
 
                break;
981
 
        case PROP_DIR:
982
 
                /* Construct only */
983
 
                priv->dir = g_value_dup_string (value);
984
 
                break;
985
 
        default:
986
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
987
 
                break;
988
 
        }
989
 
}
990
 
 
991
 
static void
992
 
get_property (GObject *object, guint prop_id,
993
 
                    GValue *value, GParamSpec *pspec)
994
 
{
995
 
        NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
996
 
 
997
 
        switch (prop_id) {
998
 
        case PROP_CLIENT:
999
 
                g_value_set_object (value, priv->client);
1000
 
                break;
1001
 
        case PROP_DIR:
1002
 
                g_value_set_string (value, priv->dir);
1003
 
                break;
1004
 
        default:
1005
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1006
 
                break;
1007
 
        }
1008
 
}
1009
 
 
1010
 
static void
1011
 
nma_gconf_connection_class_init (NMAGConfConnectionClass *class)
1012
 
{
1013
 
        GObjectClass *object_class = G_OBJECT_CLASS (class);
1014
 
        NMExportedConnectionClass *ec_class = NM_EXPORTED_CONNECTION_CLASS (class);
1015
 
 
1016
 
        g_type_class_add_private (class, sizeof (NMAGConfConnectionPrivate));
1017
 
 
1018
 
        /* Virtual methods */
1019
 
        object_class->constructor  = constructor;
1020
 
        object_class->set_property = set_property;
1021
 
        object_class->get_property = get_property;
1022
 
        object_class->dispose      = dispose;
1023
 
        object_class->finalize     = finalize;
1024
 
 
1025
 
        ec_class->update = dbus_update;
1026
 
        ec_class->delete = dbus_delete;
1027
 
        ec_class->get_secrets = dbus_get_secrets;
1028
 
        ec_class->get_settings = dbus_get_settings;
1029
 
 
1030
 
        /* Properties */
1031
 
        g_object_class_install_property
1032
 
                (object_class, PROP_CLIENT,
1033
 
                 g_param_spec_object (NMA_GCONF_CONNECTION_CLIENT,
1034
 
                                                  "GConfClient",
1035
 
                                                  "GConfClient",
1036
 
                                                  GCONF_TYPE_CLIENT,
1037
 
                                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1038
 
 
1039
 
        g_object_class_install_property
1040
 
                (object_class, PROP_DIR,
1041
 
                 g_param_spec_string (NMA_GCONF_CONNECTION_DIR,
1042
 
                                                  "GConf directory",
1043
 
                                                  "GConf directory",
1044
 
                                                  NULL,
1045
 
                                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1046
 
 
1047
 
        /* Signals */
1048
 
        signals[NEW_SECRETS_REQUESTED] =
1049
 
                g_signal_new ("new-secrets-requested",
1050
 
                                    G_OBJECT_CLASS_TYPE (object_class),
1051
 
                                    G_SIGNAL_RUN_FIRST,
1052
 
                                    G_STRUCT_OFFSET (NMAGConfConnectionClass, new_secrets_requested),
1053
 
                                    NULL, NULL,
1054
 
                                    nma_marshal_VOID__STRING_POINTER_BOOLEAN_POINTER_POINTER,
1055
 
                                    G_TYPE_NONE, 5,
1056
 
                                    G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
1057
 
}