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

« back to all changes in this revision

Viewing changes to src/applet-agent.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
/*
 
3
 * Dan Williams <dcbw@redhat.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License along
 
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
18
 *
 
19
 * Copyright (C) 2011 Red Hat, Inc.
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include <config.h>
 
24
#endif
 
25
 
 
26
#include <glib/gi18n.h>
 
27
#include <string.h>
 
28
#include <gnome-keyring.h>
 
29
#include <dbus/dbus-glib.h>
 
30
#include <nm-setting-connection.h>
 
31
#include <nm-setting-8021x.h>
 
32
#include <nm-setting-vpn.h>
 
33
#include <nm-setting-wireless.h>
 
34
#include <nm-setting-wireless-security.h>
 
35
#include <nm-setting-wired.h>
 
36
#include <nm-setting-pppoe.h>
 
37
 
 
38
#include "applet-agent.h"
 
39
#include "utils.h"
 
40
#include "nma-marshal.h"
 
41
 
 
42
G_DEFINE_TYPE (AppletAgent, applet_agent, NM_TYPE_SECRET_AGENT);
 
43
 
 
44
#define APPLET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APPLET_TYPE_AGENT, AppletAgentPrivate))
 
45
 
 
46
typedef struct {
 
47
        GHashTable *requests;
 
48
 
 
49
        gboolean disposed;
 
50
} AppletAgentPrivate;
 
51
 
 
52
enum {
 
53
        GET_SECRETS,
 
54
        CANCEL_SECRETS,
 
55
        LAST_SIGNAL
 
56
};
 
57
static guint signals[LAST_SIGNAL] = { 0 };
 
58
 
 
59
 
 
60
/*******************************************************/
 
61
 
 
62
#define DBUS_TYPE_G_MAP_OF_STRING (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
 
63
 
 
64
typedef struct {
 
65
        guint id;
 
66
 
 
67
        NMSecretAgent *agent;
 
68
        NMConnection *connection;
 
69
        char *path;
 
70
        char *setting_name;
 
71
        char **hints;
 
72
        guint32 flags;
 
73
        NMSecretAgentGetSecretsFunc get_callback;
 
74
        NMSecretAgentSaveSecretsFunc save_callback;
 
75
        NMSecretAgentDeleteSecretsFunc delete_callback;
 
76
        gpointer callback_data;
 
77
 
 
78
        GSList *keyring_ids;
 
79
        guint32 op_count;
 
80
        gboolean canceled;
 
81
} Request;
 
82
 
 
83
static Request *
 
84
request_new (NMSecretAgent *agent,
 
85
             NMConnection *connection,
 
86
             const char *connection_path,
 
87
             const char *setting_name,
 
88
             const char **hints,
 
89
             guint32 flags,
 
90
             NMSecretAgentGetSecretsFunc get_callback,
 
91
             NMSecretAgentSaveSecretsFunc save_callback,
 
92
             NMSecretAgentDeleteSecretsFunc delete_callback,
 
93
             gpointer callback_data)
 
94
{
 
95
        static guint32 counter = 1;
 
96
        Request *r;
 
97
 
 
98
        r = g_slice_new0 (Request);
 
99
        r->id = counter++;
 
100
        r->agent = agent;
 
101
        r->connection = g_object_ref (connection);
 
102
        r->path = g_strdup (connection_path);
 
103
        r->setting_name = g_strdup (setting_name);
 
104
        if (hints)
 
105
                r->hints = g_strdupv ((gchar **) hints);
 
106
        r->flags = flags;
 
107
        r->get_callback = get_callback;
 
108
        r->save_callback = save_callback;
 
109
        r->delete_callback = delete_callback;
 
110
        r->callback_data = callback_data;
 
111
        return r;
 
112
}
 
113
 
 
114
static void
 
115
request_free (Request *r)
 
116
{
 
117
        if (r->canceled == FALSE)
 
118
                g_hash_table_remove (APPLET_AGENT_GET_PRIVATE (r->agent)->requests, GUINT_TO_POINTER (r->id));
 
119
 
 
120
        g_object_unref (r->connection);
 
121
        g_slist_free (r->keyring_ids);
 
122
        g_free (r->path);
 
123
        g_free (r->setting_name);
 
124
        g_strfreev (r->hints);
 
125
        memset (r, 0, sizeof (*r));
 
126
        g_slice_free (Request, r);
 
127
}
 
128
 
 
129
 
 
130
/*************************************************************/
 
131
 
 
132
/* The keyring doesn't pass the call ID to the callback for the
 
133
 * operation which the call ID represents, so we have to track
 
134
 * it with a small structure.  Ugh.
 
135
 */
 
136
 
 
137
typedef struct {
 
138
        Request *r;
 
139
        gpointer keyring_id;
 
140
} KeyringCall;
 
141
 
 
142
static inline KeyringCall *
 
143
keyring_call_new (Request *r)
 
144
{
 
145
        KeyringCall *call;
 
146
 
 
147
        call = g_malloc0 (sizeof (KeyringCall));
 
148
        call->r = r;
 
149
        return call;
 
150
}
 
151
 
 
152
static inline void
 
153
keyring_call_free (gpointer data)
 
154
{
 
155
        KeyringCall *call = data;
 
156
 
 
157
        memset (call, 0, sizeof (*call));
 
158
        g_free (call);
 
159
}
 
160
 
 
161
/*******************************************************/
 
162
 
 
163
static void
 
164
get_secrets_cb (AppletAgent *self,
 
165
                GHashTable *secrets,
 
166
                GError *error,
 
167
                gpointer user_data)
 
168
{
 
169
        Request *r = user_data;
 
170
 
 
171
        if (r->canceled == FALSE)
 
172
                r->get_callback (NM_SECRET_AGENT (r->agent), r->connection, error ? NULL : secrets, error, r->callback_data);
 
173
        request_free (r);
 
174
}
 
175
 
 
176
static void
 
177
ask_for_secrets (Request *r)
 
178
{
 
179
        /* Ask the applet to get some secrets for us */
 
180
        g_signal_emit (r->agent,
 
181
                       signals[GET_SECRETS],
 
182
                       0,
 
183
                       GUINT_TO_POINTER (r->id),
 
184
                       r->connection,
 
185
                       r->setting_name,
 
186
                       r->hints,
 
187
                       r->flags,
 
188
                       get_secrets_cb,
 
189
                       r);
 
190
}
 
191
 
 
192
static void
 
193
check_always_ask_cb (NMSetting *setting,
 
194
                     const char *key,
 
195
                     const GValue *value,
 
196
                     GParamFlags flags,
 
197
                     gpointer user_data)
 
198
{
 
199
        gboolean *always_ask = user_data;
 
200
        NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
201
 
 
202
        if (flags & NM_SETTING_PARAM_SECRET) {
 
203
                if (nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) {
 
204
                        if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)
 
205
                                *always_ask = TRUE;
 
206
                }
 
207
        }
 
208
}
 
209
 
 
210
static gboolean
 
211
has_always_ask (NMSetting *setting)
 
212
{
 
213
        gboolean always_ask = FALSE;
 
214
 
 
215
        nm_setting_enumerate_values (setting, check_always_ask_cb, &always_ask);
 
216
        return always_ask;
 
217
}
 
218
 
 
219
static gboolean
 
220
is_connection_always_ask (NMConnection *connection)
 
221
{
 
222
        NMSettingConnection *s_con;
 
223
        const char *ctype;
 
224
        NMSetting *setting;
 
225
 
 
226
        /* For the given connection type, check if the secrets for that connection
 
227
         * are always-ask or not.
 
228
         */
 
229
        s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
230
        g_assert (s_con);
 
231
        ctype = nm_setting_connection_get_connection_type (s_con);
 
232
 
 
233
        setting = nm_connection_get_setting_by_name (connection, ctype);
 
234
        g_return_val_if_fail (setting != NULL, FALSE);
 
235
 
 
236
        if (has_always_ask (setting))
 
237
                return TRUE;
 
238
 
 
239
        /* Try type-specific settings too; be a bit paranoid and only consider
 
240
         * secrets from settings relevant to the connection type.
 
241
         */
 
242
        if (NM_IS_SETTING_WIRELESS (setting)) {
 
243
                setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
 
244
                if (setting && has_always_ask (setting))
 
245
                        return TRUE;
 
246
                setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
 
247
                if (setting && has_always_ask (setting))
 
248
                        return TRUE;
 
249
        } else if (NM_IS_SETTING_WIRED (setting)) {
 
250
                setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
 
251
                if (setting && has_always_ask (setting))
 
252
                        return TRUE;
 
253
                setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
 
254
                if (setting && has_always_ask (setting))
 
255
                        return TRUE;
 
256
        }
 
257
 
 
258
        return FALSE;
 
259
}
 
260
 
 
261
static GValue *
 
262
string_to_gvalue (const char *str)
 
263
{
 
264
        GValue *val;
 
265
 
 
266
        val = g_slice_new0 (GValue);
 
267
        g_value_init (val, G_TYPE_STRING);
 
268
        g_value_set_string (val, str);
 
269
        return val;
 
270
}
 
271
 
 
272
static void
 
273
destroy_gvalue (gpointer data)
 
274
{
 
275
        g_value_unset ((GValue *) data);
 
276
        g_slice_free (GValue, data);
 
277
}
 
278
 
 
279
static void
 
280
keyring_find_secrets_cb (GnomeKeyringResult result,
 
281
                         GList *list,
 
282
                         gpointer user_data)
 
283
{
 
284
        KeyringCall *call = user_data;
 
285
        Request *r = call->r;
 
286
        GError *error = NULL;
 
287
        NMSettingConnection *s_con;
 
288
        const char *connection_id = NULL;
 
289
        GHashTable *secrets = NULL, *settings = NULL;
 
290
        GList *iter;
 
291
        gboolean hint_found = FALSE, ask = FALSE;
 
292
 
 
293
        r->keyring_ids = g_slist_remove (r->keyring_ids, call->keyring_id);
 
294
 
 
295
        if (r->canceled) {
 
296
                /* Callback already called by cancelation handler */
 
297
                request_free (r);
 
298
                return;
 
299
        }
 
300
 
 
301
        s_con = (NMSettingConnection *) nm_connection_get_setting (r->connection, NM_TYPE_SETTING_CONNECTION);
 
302
        g_assert (s_con);
 
303
        connection_id = nm_setting_connection_get_id (s_con);
 
304
 
 
305
        if (result == GNOME_KEYRING_RESULT_CANCELLED) {
 
306
                error = g_error_new_literal (NM_SECRET_AGENT_ERROR,
 
307
                                             NM_SECRET_AGENT_ERROR_USER_CANCELED,
 
308
                                             "The secrets request was canceled by the user");
 
309
                goto done;
 
310
        } else if (   result != GNOME_KEYRING_RESULT_OK
 
311
                   && result != GNOME_KEYRING_RESULT_NO_MATCH) {
 
312
                error = g_error_new (NM_SECRET_AGENT_ERROR,
 
313
                                     NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
 
314
                                     "%s.%d - failed to read secrets from keyring (result %d)",
 
315
                                     __FILE__, __LINE__, result);
 
316
                goto done;
 
317
        }
 
318
 
 
319
        /* Only ask if we're allowed to, ie if flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE */
 
320
        if (r->flags && g_list_length (list) == 0) {
 
321
                g_message ("No keyring secrets found for %s/%s; asking user.", connection_id, r->setting_name);
 
322
                ask_for_secrets (r);
 
323
                return;
 
324
        }
 
325
 
 
326
        secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
 
327
 
 
328
        /* Extract the secrets from the list of matching keyring items */
 
329
        for (iter = list; iter != NULL; iter = g_list_next (iter)) {
 
330
                GnomeKeyringFound *found = iter->data;
 
331
                GnomeKeyringAttribute *attr;
 
332
                const char *key_name = NULL;
 
333
                int i;
 
334
 
 
335
                for (i = 0; i < found->attributes->len; i++) {
 
336
                        attr = &(gnome_keyring_attribute_list_index (found->attributes, i));
 
337
                        if (   (strcmp (attr->name, KEYRING_SK_TAG) == 0)
 
338
                            && (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING)) {
 
339
 
 
340
                                key_name = attr->value.string;
 
341
                                g_hash_table_insert (secrets, g_strdup (key_name), string_to_gvalue (found->secret));
 
342
 
 
343
                                /* See if this property matches a given hint */
 
344
                                if (r->hints && r->hints[0]) {
 
345
                                        if (!g_strcmp0 (r->hints[0], key_name) || !g_strcmp0 (r->hints[1], key_name))
 
346
                                                hint_found = TRUE;
 
347
                                }
 
348
                                break;
 
349
                        }
 
350
                }
 
351
        }
 
352
 
 
353
        /* If there were hints, and none of the hints were returned by the keyring,
 
354
         * get some new secrets.
 
355
         */
 
356
        if (r->flags) {
 
357
                if (r->hints && r->hints[0] && !hint_found)
 
358
                        ask = TRUE;
 
359
                else if (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) {
 
360
                        g_message ("New secrets for %s/%s requested; ask the user", connection_id, r->setting_name);
 
361
                        ask = TRUE;
 
362
                } else if (   (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION)
 
363
                               && is_connection_always_ask (r->connection))
 
364
                        ask = TRUE;
 
365
        }
 
366
 
 
367
        /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
 
368
         * will contain all the individual settings hashes.
 
369
         */
 
370
        settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy);
 
371
        g_hash_table_insert (settings, g_strdup (r->setting_name), secrets);
 
372
 
 
373
done:
 
374
        if (ask) {
 
375
                GHashTableIter hash_iter;
 
376
                const char *setting_name;
 
377
                GHashTable *setting_hash;
 
378
 
 
379
                /* Stuff all the found secrets into the connection for the UI to use */
 
380
                g_hash_table_iter_init (&hash_iter, settings);
 
381
                while (g_hash_table_iter_next (&hash_iter,
 
382
                                               (gpointer *) &setting_name,
 
383
                                               (gpointer *) &setting_hash)) {
 
384
                        nm_connection_update_secrets (r->connection,
 
385
                                                          setting_name,
 
386
                                                          setting_hash,
 
387
                                                          NULL);
 
388
                }
 
389
 
 
390
                ask_for_secrets (r);
 
391
        } else {
 
392
                /* Otherwise send the secrets back to NetworkManager */
 
393
                r->get_callback (NM_SECRET_AGENT (r->agent), r->connection, error ? NULL : settings, error, r->callback_data);
 
394
                request_free (r);
 
395
        }
 
396
 
 
397
        if (settings)
 
398
                g_hash_table_destroy (settings);
 
399
        g_clear_error (&error);
 
400
}
 
401
 
 
402
static void
 
403
get_secrets (NMSecretAgent *agent,
 
404
             NMConnection *connection,
 
405
             const char *connection_path,
 
406
             const char *setting_name,
 
407
             const char **hints,
 
408
             guint32 flags,
 
409
             NMSecretAgentGetSecretsFunc callback,
 
410
             gpointer callback_data)
 
411
{
 
412
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent);
 
413
        Request *r;
 
414
        GError *error = NULL;
 
415
        NMSettingConnection *s_con;
 
416
        NMSetting *setting;
 
417
        const char *id;
 
418
        const char *ctype;
 
419
        KeyringCall *call;
 
420
 
 
421
        setting = nm_connection_get_setting_by_name (connection, setting_name);
 
422
        if (!setting) {
 
423
                error = g_error_new (NM_SECRET_AGENT_ERROR,
 
424
                                     NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
 
425
                                     "%s.%d - Connection didn't have requested setting '%s'.",
 
426
                                     __FILE__, __LINE__, setting_name);
 
427
                callback (agent, connection, NULL, error, callback_data);
 
428
                g_error_free (error);
 
429
                return;
 
430
        }
 
431
 
 
432
        s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
433
        g_assert (s_con);
 
434
        id = nm_setting_connection_get_id (s_con);
 
435
        ctype = nm_setting_connection_get_connection_type (s_con);
 
436
 
 
437
        if (!s_con || !id || !strlen (id) || !ctype) {
 
438
                error = g_error_new (NM_SECRET_AGENT_ERROR,
 
439
                                     NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
 
440
                                     "%s.%d - Connection didn't have required '"
 
441
                                     NM_SETTING_CONNECTION_SETTING_NAME
 
442
                                     "' setting , or the connection name was invalid.",
 
443
                                     __FILE__, __LINE__);
 
444
                callback (agent, connection, NULL, error, callback_data);
 
445
                g_error_free (error);
 
446
                return;
 
447
        }
 
448
 
 
449
        /* Track the secrets request */
 
450
        r = request_new (agent, connection, connection_path, setting_name, hints, flags, callback, NULL, NULL, callback_data);
 
451
        g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r);
 
452
 
 
453
        /* VPN passwords are handled by the VPN plugin's auth dialog */
 
454
        if (!strcmp (ctype, NM_SETTING_VPN_SETTING_NAME)) {
 
455
                ask_for_secrets (r);
 
456
                return;
 
457
        }
 
458
 
 
459
        /* For everything else we scrape the keyring for secrets first, and ask
 
460
         * later if required.
 
461
         */
 
462
        call = keyring_call_new (r);
 
463
        call->keyring_id = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
464
                                                      keyring_find_secrets_cb,
 
465
                                                      call,
 
466
                                                      keyring_call_free,
 
467
                                                      KEYRING_UUID_TAG,
 
468
                                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
469
                                                      nm_setting_connection_get_uuid (s_con),
 
470
                                                      KEYRING_SN_TAG,
 
471
                                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
472
                                                      setting_name,
 
473
                                                      NULL);
 
474
}
 
475
 
 
476
/*******************************************************/
 
477
 
 
478
static void
 
479
cancel_get_secrets (NMSecretAgent *agent,
 
480
                    const char *connection_path,
 
481
                    const char *setting_name)
 
482
{
 
483
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent);
 
484
        GHashTableIter iter;
 
485
        gpointer data;
 
486
        GError *error;
 
487
 
 
488
        error = g_error_new_literal (NM_SECRET_AGENT_ERROR,
 
489
                                     NM_SECRET_AGENT_ERROR_AGENT_CANCELED,
 
490
                                     "Canceled by NetworkManager");
 
491
 
 
492
        g_hash_table_iter_init (&iter, priv->requests);
 
493
        while (g_hash_table_iter_next (&iter, NULL, &data)) {
 
494
                Request *r = data;
 
495
 
 
496
                if (r->get_callback == NULL)
 
497
                        continue;
 
498
 
 
499
                /* Cancel any matching GetSecrets call */
 
500
                if (!g_strcmp0 (r->path, connection_path) && !g_strcmp0 (r->setting_name, setting_name)) {
 
501
                        GSList *kiter;
 
502
 
 
503
                        /* cancel outstanding keyring operations */
 
504
                        for (kiter = r->keyring_ids; kiter; kiter = g_slist_next (kiter))
 
505
                                gnome_keyring_cancel_request (kiter->data);
 
506
                        g_slist_free (r->keyring_ids);
 
507
                        r->keyring_ids = NULL;
 
508
 
 
509
                        r->canceled = TRUE;
 
510
                        r->get_callback (NM_SECRET_AGENT (r->agent), r->connection, NULL, error, r->callback_data);
 
511
                        g_hash_table_remove (priv->requests, GUINT_TO_POINTER (r->id));
 
512
                        g_signal_emit (r->agent, signals[CANCEL_SECRETS], 0, GUINT_TO_POINTER (r->id));
 
513
                }
 
514
        }
 
515
 
 
516
        g_error_free (error);
 
517
}
 
518
 
 
519
/*******************************************************/
 
520
 
 
521
static void
 
522
save_secret_cb (GnomeKeyringResult result, guint val, gpointer user_data)
 
523
{
 
524
        KeyringCall *call = user_data;
 
525
        Request *r = call->r;
 
526
 
 
527
        r->keyring_ids = g_slist_remove (r->keyring_ids, call->keyring_id);
 
528
 
 
529
        /* Only call the SaveSecrets callback and free the request when all the
 
530
         * secrets have been saved to the keyring.
 
531
         */
 
532
        r->op_count--;
 
533
        if (r->op_count == 0) {
 
534
                r->save_callback (NM_SECRET_AGENT (r->agent), r->connection, NULL, r->callback_data);
 
535
                request_free (r);
 
536
        }
 
537
}
 
538
 
 
539
static void
 
540
write_one_secret_to_keyring (NMSetting *setting,
 
541
                             const char *key,
 
542
                             const GValue *value,
 
543
                             GParamFlags flags,
 
544
                             gpointer user_data)
 
545
{
 
546
        Request *r = user_data;
 
547
        GType type = G_VALUE_TYPE (value);
 
548
        const char *secret;
 
549
        const char *setting_name;
 
550
        GnomeKeyringAttributeList *attrs;
 
551
        char *display_name = NULL;
 
552
        KeyringCall *call;
 
553
        NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
554
 
 
555
        /* Non-secrets obviously don't get saved in the keyring */
 
556
        if (!(flags & NM_SETTING_PARAM_SECRET))
 
557
                return;
 
558
 
 
559
        /* Don't system-owned or always-ask secrets */
 
560
        if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
 
561
                return;
 
562
        if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED)
 
563
                return;
 
564
 
 
565
        /* VPN secrets are handled by the VPN plugins */
 
566
        if (   (type == DBUS_TYPE_G_MAP_OF_STRING)
 
567
            && NM_IS_SETTING_VPN (setting)
 
568
            && !strcmp (key, NM_SETTING_VPN_SECRETS))
 
569
                return;
 
570
 
 
571
        setting_name = nm_setting_get_name (setting);
 
572
        if (type != G_TYPE_STRING) {
 
573
                g_warning ("Unhandled setting secret type (write) '%s/%s' : '%s'", 
 
574
                                 setting_name, key, g_type_name (type));
 
575
                return;
 
576
        }
 
577
 
 
578
        secret = g_value_get_string (value);
 
579
        if (!secret || !strlen (secret))
 
580
                return;
 
581
                
 
582
        attrs = utils_create_keyring_add_attr_list (r->connection, NULL, NULL,
 
583
                                                    setting_name,
 
584
                                                    key,
 
585
                                                    &display_name);
 
586
        g_assert (attrs);
 
587
        call = keyring_call_new (r);
 
588
        call->keyring_id = gnome_keyring_item_create (NULL,
 
589
                                                      GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
590
                                                      display_name,
 
591
                                                      attrs,
 
592
                                                      secret,
 
593
                                                      TRUE,
 
594
                                                      save_secret_cb,
 
595
                                                      call,
 
596
                                                      keyring_call_free);
 
597
        r->op_count++;
 
598
        gnome_keyring_attribute_list_free (attrs);
 
599
        g_free (display_name);
 
600
}
 
601
 
 
602
static void
 
603
save_delete_cb (NMSecretAgent *agent,
 
604
                NMConnection *connection,
 
605
                GError *error,
 
606
                gpointer user_data)
 
607
{
 
608
        Request *r = user_data;
 
609
 
 
610
        /* Ignore errors; now save all new secrets */
 
611
        nm_connection_for_each_setting_value (connection, write_one_secret_to_keyring, r);
 
612
}
 
613
 
 
614
static void
 
615
save_secrets (NMSecretAgent *agent,
 
616
              NMConnection *connection,
 
617
              const char *connection_path,
 
618
              NMSecretAgentSaveSecretsFunc callback,
 
619
              gpointer callback_data)
 
620
{
 
621
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent);
 
622
        Request *r;
 
623
 
 
624
        r = request_new (agent, connection, connection_path, NULL, NULL, FALSE, NULL, callback, NULL, callback_data);
 
625
        g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r);
 
626
 
 
627
        /* First delete any existing items in the keyring */
 
628
        nm_secret_agent_delete_secrets (agent, connection, save_delete_cb, r);
 
629
}
 
630
 
 
631
/*******************************************************/
 
632
 
 
633
static void
 
634
keyring_delete_cb (GnomeKeyringResult result, gpointer user_data)
 
635
{
 
636
        /* Ignored */
 
637
}
 
638
 
 
639
static void
 
640
delete_find_items_cb (GnomeKeyringResult result, GList *list, gpointer user_data)
 
641
{
 
642
        KeyringCall *call = user_data;
 
643
        Request *r = call->r;
 
644
        GList *iter;
 
645
        GError *error = NULL;
 
646
 
 
647
        r->keyring_ids = g_slist_remove (r->keyring_ids, call->keyring_id);
 
648
 
 
649
        if ((result == GNOME_KEYRING_RESULT_OK) || (result == GNOME_KEYRING_RESULT_NO_MATCH)) {
 
650
                for (iter = list; iter != NULL; iter = g_list_next (iter)) {
 
651
                        GnomeKeyringFound *found = (GnomeKeyringFound *) iter->data;
 
652
 
 
653
                        gnome_keyring_item_delete (found->keyring, found->item_id, keyring_delete_cb, NULL, NULL);
 
654
                }
 
655
        } else {
 
656
                error = g_error_new (NM_SECRET_AGENT_ERROR,
 
657
                                     NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
 
658
                                     "The request could not be completed.  Keyring result: %d",
 
659
                                     result);
 
660
        }
 
661
 
 
662
        r->delete_callback (r->agent, r->connection, error, r->callback_data);
 
663
        request_free (r);
 
664
}
 
665
 
 
666
static void
 
667
delete_secrets (NMSecretAgent *agent,
 
668
                NMConnection *connection,
 
669
                const char *connection_path,
 
670
                NMSecretAgentDeleteSecretsFunc callback,
 
671
                gpointer callback_data)
 
672
{
 
673
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent);
 
674
        Request *r;
 
675
        NMSettingConnection *s_con;
 
676
        const char *uuid;
 
677
        KeyringCall *call;
 
678
 
 
679
        r = request_new (agent, connection, connection_path, NULL, NULL, FALSE, NULL, NULL, callback, callback_data);
 
680
        g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r);
 
681
 
 
682
        s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
683
        g_assert (s_con);
 
684
        uuid = nm_setting_connection_get_uuid (s_con);
 
685
        g_assert (uuid);
 
686
 
 
687
        call = keyring_call_new (r);
 
688
        call->keyring_id = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
689
                                                      delete_find_items_cb,
 
690
                                                      call,
 
691
                                                      keyring_call_free,
 
692
                                                      KEYRING_UUID_TAG,
 
693
                                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
694
                                                      uuid,
 
695
                                                      NULL);
 
696
}
 
697
 
 
698
/*******************************************************/
 
699
 
 
700
AppletAgent *
 
701
applet_agent_new (void)
 
702
{
 
703
        return (AppletAgent *) g_object_new (APPLET_TYPE_AGENT,
 
704
                                             NM_SECRET_AGENT_IDENTIFIER, "org.freedesktop.nm-applet",
 
705
                                             NULL);
 
706
}
 
707
 
 
708
static void
 
709
agent_registration_result_cb (NMSecretAgent *agent, GError *error, gpointer user_data)
 
710
{
 
711
        if (error)
 
712
                g_warning ("Failed to register as an agent: (%d) %s", error->code, error->message);
 
713
}
 
714
 
 
715
static void
 
716
applet_agent_init (AppletAgent *self)
 
717
{
 
718
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (self);
 
719
 
 
720
        priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal);
 
721
 
 
722
        g_signal_connect (self, NM_SECRET_AGENT_REGISTRATION_RESULT,
 
723
                          G_CALLBACK (agent_registration_result_cb), NULL);
 
724
}
 
725
 
 
726
static void
 
727
dispose (GObject *object)
 
728
{
 
729
        AppletAgent *self = APPLET_AGENT (object);
 
730
        AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (self);
 
731
 
 
732
        if (!priv->disposed) {
 
733
                GHashTableIter iter;
 
734
                gpointer data;
 
735
 
 
736
                /* Mark any outstanding requests as canceled */
 
737
                g_hash_table_iter_init (&iter, priv->requests);
 
738
                while (g_hash_table_iter_next (&iter, NULL, &data)) {
 
739
                        Request *r = data;
 
740
 
 
741
                        r->canceled = TRUE;
 
742
                }
 
743
 
 
744
                g_hash_table_destroy (priv->requests);
 
745
                priv->disposed = TRUE;
 
746
        }
 
747
 
 
748
        G_OBJECT_CLASS (applet_agent_parent_class)->dispose (object);
 
749
}
 
750
 
 
751
static void
 
752
applet_agent_class_init (AppletAgentClass *agent_class)
 
753
{
 
754
        GObjectClass *object_class = G_OBJECT_CLASS (agent_class);
 
755
        NMSecretAgentClass *parent_class = NM_SECRET_AGENT_CLASS (agent_class);
 
756
 
 
757
        g_type_class_add_private (agent_class, sizeof (AppletAgentPrivate));
 
758
 
 
759
        /* virtual methods */
 
760
        object_class->dispose = dispose;
 
761
        parent_class->get_secrets = get_secrets;
 
762
        parent_class->cancel_get_secrets = cancel_get_secrets;
 
763
        parent_class->save_secrets = save_secrets;
 
764
        parent_class->delete_secrets = delete_secrets;
 
765
 
 
766
        /* Signals */
 
767
        signals[GET_SECRETS] =
 
768
                g_signal_new (APPLET_AGENT_GET_SECRETS,
 
769
                              G_OBJECT_CLASS_TYPE (object_class),
 
770
                              G_SIGNAL_RUN_FIRST,
 
771
                              G_STRUCT_OFFSET (AppletAgentClass, get_secrets),
 
772
                              NULL, NULL,
 
773
                              nma_marshal_VOID__POINTER_POINTER_STRING_POINTER_UINT_POINTER_POINTER,
 
774
                              G_TYPE_NONE, 7,
 
775
                              G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
 
776
 
 
777
        signals[CANCEL_SECRETS] =
 
778
                g_signal_new (APPLET_AGENT_CANCEL_SECRETS,
 
779
                              G_OBJECT_CLASS_TYPE (object_class),
 
780
                              G_SIGNAL_RUN_FIRST,
 
781
                              G_STRUCT_OFFSET (AppletAgentClass, cancel_secrets),
 
782
                              NULL, NULL,
 
783
                              g_cclosure_marshal_VOID__POINTER,
 
784
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
785
}
 
786