~jbicha/ubuntu/oneiric/gnome-shell/oneiric-3.2.2.1

« back to all changes in this revision

Viewing changes to src/shell-network-agent.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2011-09-07 09:09:05 UTC
  • mfrom: (1.1.29 upstream)
  • Revision ID: package-import@ubuntu.com-20110907090905-kbo4fewcg12zt99u
Tags: 3.1.90.1-0ubuntu1
* New upstream release.
* debian/control: Bump build-depends on new mutter
* debian/patches/01_favorite_apps.patch: Updated
* debian/patches/03_remove-glx-dependency-on-armel.patch: Refreshed
* debian/patches/04_build-without-caribou.patch
  - Build without caribou since Ubuntu uses onboard and our System 
    Settings doesn't support choosing a different screen keyboard yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * Copyright 2011 Red Hat, Inc.
 
4
 *           2011 Giovanni Campagna <scampa.giovanni@gmail.com>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along
 
17
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
#include <string.h>
 
24
#include <gnome-keyring.h>
 
25
 
 
26
#include "shell-network-agent.h"
 
27
#include "shell-marshal.h"
 
28
 
 
29
enum {
 
30
  SIGNAL_NEW_REQUEST,
 
31
  SIGNAL_CANCEL_REQUEST,
 
32
  SIGNAL_LAST
 
33
};
 
34
 
 
35
static gint signals[SIGNAL_LAST];
 
36
 
 
37
typedef struct {
 
38
  gpointer                       keyring_op;
 
39
  ShellNetworkAgent             *self;
 
40
 
 
41
  gchar                         *request_id;
 
42
  NMConnection                  *connection;
 
43
  gchar                         *setting_name;
 
44
  gchar                        **hints;
 
45
  NMSecretAgentGetSecretsFlags   flags;
 
46
  NMSecretAgentGetSecretsFunc    callback;
 
47
  gpointer                       callback_data;
 
48
 
 
49
  /* <gchar *setting_key, gchar *secret> */
 
50
  GHashTable                    *entries;
 
51
} ShellAgentRequest;
 
52
 
 
53
struct _ShellNetworkAgentPrivate {
 
54
  /* <gchar *request_id, ShellAgentRequest *request> */
 
55
  GHashTable *requests;
 
56
};
 
57
 
 
58
G_DEFINE_TYPE (ShellNetworkAgent, shell_network_agent, NM_TYPE_SECRET_AGENT)
 
59
 
 
60
static void
 
61
shell_agent_request_free (gpointer data)
 
62
{
 
63
  ShellAgentRequest *request = data;
 
64
 
 
65
  if (request->keyring_op)
 
66
    gnome_keyring_cancel_request (request->keyring_op);
 
67
 
 
68
  g_object_unref (request->self);
 
69
  g_object_unref (request->connection);
 
70
  g_free (request->setting_name);
 
71
  g_strfreev (request->hints);
 
72
 
 
73
  g_hash_table_destroy (request->entries);
 
74
 
 
75
  g_slice_free (ShellAgentRequest, request);
 
76
}
 
77
 
 
78
static void
 
79
shell_network_agent_init (ShellNetworkAgent *agent)
 
80
{
 
81
  ShellNetworkAgentPrivate *priv;
 
82
 
 
83
  priv = agent->priv = G_TYPE_INSTANCE_GET_PRIVATE (agent, SHELL_TYPE_NETWORK_AGENT, ShellNetworkAgentPrivate);
 
84
 
 
85
  priv->requests = g_hash_table_new_full (g_str_hash, g_str_equal,
 
86
                                          g_free, shell_agent_request_free);
 
87
}
 
88
 
 
89
static void
 
90
shell_network_agent_finalize (GObject *object)
 
91
{
 
92
  ShellNetworkAgentPrivate *priv = SHELL_NETWORK_AGENT (object)->priv;
 
93
  GError *error;
 
94
  GHashTableIter iter;
 
95
  gpointer key;
 
96
  gpointer value;
 
97
 
 
98
  error = g_error_new (NM_SECRET_AGENT_ERROR,
 
99
                       NM_SECRET_AGENT_ERROR_AGENT_CANCELED,
 
100
                       "The secret agent is going away");
 
101
 
 
102
  g_hash_table_iter_init (&iter, priv->requests);
 
103
  while (g_hash_table_iter_next (&iter, &key, &value))
 
104
    {
 
105
      ShellAgentRequest *request = value;
 
106
 
 
107
      request->callback (NM_SECRET_AGENT (object),
 
108
                         request->connection,
 
109
                         NULL, error,
 
110
                         request->callback_data);
 
111
    }
 
112
 
 
113
  g_hash_table_destroy (priv->requests);
 
114
  g_error_free (error);
 
115
 
 
116
  G_OBJECT_CLASS (shell_network_agent_parent_class)->finalize (object);
 
117
}
 
118
 
 
119
static void
 
120
request_secrets_from_ui (ShellAgentRequest *request)
 
121
{
 
122
  g_signal_emit (request->self, signals[SIGNAL_NEW_REQUEST], 0,
 
123
                 request->request_id,
 
124
                 request->connection,
 
125
                 request->setting_name,
 
126
                 request->hints);
 
127
}
 
128
 
 
129
static void
 
130
check_always_ask_cb (NMSetting    *setting,
 
131
                     const gchar  *key,
 
132
                     const GValue *value,
 
133
                     GParamFlags   flags,
 
134
                     gpointer      user_data)
 
135
{
 
136
  gboolean *always_ask = user_data;
 
137
  NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
138
 
 
139
  if (flags & NM_SETTING_PARAM_SECRET)
 
140
    {
 
141
      if (nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
 
142
        {
 
143
          if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)
 
144
            *always_ask = TRUE;
 
145
        }
 
146
    }
 
147
}
 
148
 
 
149
static gboolean
 
150
has_always_ask (NMSetting *setting)
 
151
{
 
152
  gboolean always_ask = FALSE;
 
153
 
 
154
  nm_setting_enumerate_values (setting, check_always_ask_cb, &always_ask);
 
155
  return always_ask;
 
156
}
 
157
 
 
158
static gboolean
 
159
is_connection_always_ask (NMConnection *connection)
 
160
{
 
161
  NMSettingConnection *s_con;
 
162
  const gchar *ctype;
 
163
  NMSetting *setting;
 
164
 
 
165
  /* For the given connection type, check if the secrets for that connection
 
166
   * are always-ask or not.
 
167
   */
 
168
  s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
169
  g_assert (s_con);
 
170
  ctype = nm_setting_connection_get_connection_type (s_con);
 
171
 
 
172
  setting = nm_connection_get_setting_by_name (connection, ctype);
 
173
  g_return_val_if_fail (setting != NULL, FALSE);
 
174
 
 
175
  if (has_always_ask (setting))
 
176
    return TRUE;
 
177
 
 
178
  /* Try type-specific settings too; be a bit paranoid and only consider
 
179
   * secrets from settings relevant to the connection type.
 
180
   */
 
181
  if (NM_IS_SETTING_WIRELESS (setting))
 
182
    {
 
183
      setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
 
184
      if (setting && has_always_ask (setting))
 
185
        return TRUE;
 
186
      setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
 
187
      if (setting && has_always_ask (setting))
 
188
        return TRUE;
 
189
        }
 
190
  else if (NM_IS_SETTING_WIRED (setting))
 
191
    {
 
192
      setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
 
193
      if (setting && has_always_ask (setting))
 
194
        return TRUE;
 
195
      setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
 
196
      if (setting && has_always_ask (setting))
 
197
        return TRUE;
 
198
    }
 
199
 
 
200
  return FALSE;
 
201
}
 
202
 
 
203
static void
 
204
gvalue_destroy_notify (gpointer data)
 
205
{
 
206
  GValue *value = data;
 
207
  g_value_unset (value);
 
208
  g_slice_free (GValue, value);
 
209
}
 
210
 
 
211
static gboolean
 
212
strv_has (gchar **haystack,
 
213
          gchar  *needle)
 
214
{
 
215
  gchar *iter;
 
216
  for (iter = *haystack; iter; iter++)
 
217
    {
 
218
      if (g_strcmp0 (iter, needle) == 0)
 
219
        return TRUE;
 
220
    }
 
221
 
 
222
  return FALSE;
 
223
}
 
224
 
 
225
static void
 
226
get_secrets_keyring_cb (GnomeKeyringResult  result,
 
227
                        GList              *list,
 
228
                        gpointer            user_data)
 
229
{
 
230
  ShellAgentRequest *closure = user_data;
 
231
  ShellNetworkAgent *self = closure->self;
 
232
  ShellNetworkAgentPrivate *priv = self->priv;
 
233
  GError *error = NULL;
 
234
  gint n_found = 0;
 
235
  GList *iter;
 
236
  GHashTable *outer;
 
237
 
 
238
  closure->keyring_op = NULL;
 
239
 
 
240
  if (result == GNOME_KEYRING_RESULT_CANCELLED)
 
241
    {
 
242
      g_set_error (&error,
 
243
                   NM_SECRET_AGENT_ERROR,
 
244
                   NM_SECRET_AGENT_ERROR_USER_CANCELED,
 
245
                   "The secret request was cancelled by the user");
 
246
 
 
247
      closure->callback (NM_SECRET_AGENT (closure->self), closure->connection, NULL, error, closure->callback_data);
 
248
 
 
249
      goto out;
 
250
    }
 
251
 
 
252
  if (result != GNOME_KEYRING_RESULT_OK &&
 
253
      result != GNOME_KEYRING_RESULT_NO_MATCH)
 
254
    {
 
255
      g_set_error (&error,
 
256
                   NM_SECRET_AGENT_ERROR,
 
257
                   NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
 
258
                   "Internal error while retrieving secrets from the keyring (result %d)", result);
 
259
 
 
260
      closure->callback (NM_SECRET_AGENT (closure->self), closure->connection, NULL, error, closure->callback_data);
 
261
 
 
262
      goto out;
 
263
    }
 
264
 
 
265
  for (iter = list; iter; iter = g_list_next (iter))
 
266
    {
 
267
      GnomeKeyringFound *item = iter->data;
 
268
      int i;
 
269
 
 
270
      for (i = 0; i < item->attributes->len; i++)
 
271
        {
 
272
          GnomeKeyringAttribute *attr = &gnome_keyring_attribute_list_index (item->attributes, i);
 
273
 
 
274
          if (g_strcmp0 (attr->name, SHELL_KEYRING_SK_TAG) == 0
 
275
              && (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING))
 
276
            {
 
277
              gchar *secret_name = g_strdup (attr->value.string);
 
278
              GValue *secret_value = g_slice_new0 (GValue);
 
279
              g_value_init (secret_value, G_TYPE_STRING);
 
280
              g_value_set_string (secret_value, item->secret);
 
281
 
 
282
              g_hash_table_insert (closure->entries, secret_name, secret_value);
 
283
 
 
284
              if (closure->hints)
 
285
                n_found += strv_has (closure->hints, secret_name);
 
286
              else
 
287
                n_found += 1;
 
288
 
 
289
              break;
 
290
            }
 
291
        }
 
292
    }
 
293
 
 
294
  if (n_found == 0 &&
 
295
      (closure->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION))
 
296
    {
 
297
      /* Even if n_found == 0, secrets is not necessarily empty */
 
298
      nm_connection_update_secrets (closure->connection, closure->setting_name, closure->entries, NULL);
 
299
 
 
300
      request_secrets_from_ui (closure);
 
301
      return;
 
302
    }
 
303
 
 
304
  outer = g_hash_table_new (g_str_hash, g_str_equal);
 
305
  g_hash_table_insert (outer, closure->setting_name, closure->entries);
 
306
 
 
307
  closure->callback (NM_SECRET_AGENT (closure->self), closure->connection, outer, NULL, closure->callback_data);
 
308
 
 
309
  g_hash_table_destroy (outer);
 
310
 
 
311
 out:
 
312
  g_hash_table_remove (priv->requests, closure->request_id);
 
313
  g_clear_error (&error);
 
314
}
 
315
 
 
316
static void
 
317
shell_network_agent_get_secrets (NMSecretAgent                 *agent,
 
318
                                 NMConnection                  *connection,
 
319
                                 const gchar                   *connection_path,
 
320
                                 const gchar                   *setting_name,
 
321
                                 const gchar                  **hints,
 
322
                                 NMSecretAgentGetSecretsFlags   flags,
 
323
                                 NMSecretAgentGetSecretsFunc    callback,
 
324
                                 gpointer                       callback_data)
 
325
{
 
326
  ShellNetworkAgent *self = SHELL_NETWORK_AGENT (agent);
 
327
  ShellAgentRequest *request = g_slice_new (ShellAgentRequest);
 
328
 
 
329
  request->self = g_object_ref (self);
 
330
  request->connection = g_object_ref (connection);
 
331
  request->setting_name = g_strdup (setting_name);
 
332
  request->hints = g_strdupv ((gchar **)hints);
 
333
  request->flags = flags;
 
334
  request->callback = callback;
 
335
  request->callback_data = callback_data;
 
336
  request->entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, gvalue_destroy_notify);
 
337
 
 
338
  request->request_id = g_strdup_printf ("%s/%s", connection_path, setting_name);
 
339
  g_hash_table_replace (self->priv->requests, request->request_id, request);
 
340
 
 
341
  if ((flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) ||
 
342
      (flags && NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
 
343
       && is_connection_always_ask (request->connection)))
 
344
    {
 
345
      request_secrets_from_ui (request);
 
346
      return;
 
347
    }
 
348
 
 
349
  request->keyring_op = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
350
                                                   get_secrets_keyring_cb,
 
351
                                                   request,
 
352
                                                   NULL, /* GDestroyNotify */
 
353
                                                   SHELL_KEYRING_UUID_TAG,
 
354
                                                   GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
355
                                                   nm_connection_get_uuid (connection),
 
356
                                                   SHELL_KEYRING_SN_TAG,
 
357
                                                   GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
358
                                                   setting_name,
 
359
                                                   NULL);  
 
360
}
 
361
 
 
362
void
 
363
shell_network_agent_set_password (ShellNetworkAgent *self,
 
364
                                  gchar             *request_id,
 
365
                                  gchar             *setting_key,
 
366
                                  gchar             *setting_value)
 
367
{
 
368
  ShellNetworkAgentPrivate *priv;
 
369
  ShellAgentRequest *request;
 
370
  GValue *value;
 
371
 
 
372
  g_return_if_fail (SHELL_IS_NETWORK_AGENT (self));
 
373
 
 
374
  priv = self->priv;
 
375
  request = g_hash_table_lookup (priv->requests, request_id);
 
376
 
 
377
  value = g_slice_new0 (GValue);
 
378
  g_value_init (value, G_TYPE_STRING);
 
379
  g_value_set_string (value, setting_value);
 
380
 
 
381
  g_hash_table_replace (request->entries, g_strdup (setting_key), value);
 
382
}
 
383
 
 
384
void
 
385
shell_network_agent_respond (ShellNetworkAgent *self,
 
386
                             gchar             *request_id,
 
387
                             gboolean           canceled)
 
388
{
 
389
  ShellNetworkAgentPrivate *priv;
 
390
  ShellAgentRequest *request;
 
391
  NMConnection *dup;
 
392
  GHashTable *outer;
 
393
 
 
394
  g_return_if_fail (SHELL_IS_NETWORK_AGENT (self));
 
395
 
 
396
  priv = self->priv;
 
397
  request = g_hash_table_lookup (priv->requests, request_id);
 
398
 
 
399
  if (canceled)
 
400
    {
 
401
      GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
 
402
                                   NM_SECRET_AGENT_ERROR_USER_CANCELED,
 
403
                                   "Network dialog was canceled by the user");
 
404
 
 
405
      request->callback (NM_SECRET_AGENT (self), request->connection, NULL, error, request->callback_data);
 
406
      g_error_free (error);
 
407
      g_hash_table_remove (priv->requests, request_id);
 
408
      return;
 
409
    }
 
410
 
 
411
  /* Save updated secrets */
 
412
  dup = nm_connection_duplicate (request->connection);
 
413
  nm_connection_update_secrets (dup, request->setting_name, request->entries, NULL);
 
414
 
 
415
  nm_secret_agent_save_secrets (NM_SECRET_AGENT (self), dup, NULL, NULL);
 
416
 
 
417
  outer = g_hash_table_new (g_str_hash, g_str_equal);
 
418
  g_hash_table_insert (outer, request->setting_name, request->entries);
 
419
 
 
420
  request->callback (NM_SECRET_AGENT (self), request->connection, outer, NULL, request->callback_data);
 
421
 
 
422
  g_hash_table_destroy (outer);
 
423
  g_object_unref (dup);
 
424
  g_hash_table_remove (priv->requests, request_id);
 
425
}
 
426
 
 
427
static void
 
428
shell_network_agent_cancel_get_secrets (NMSecretAgent *agent,
 
429
                                        const gchar   *connection_path,
 
430
                                        const gchar   *setting_name)
 
431
{
 
432
  ShellNetworkAgent *self = SHELL_NETWORK_AGENT (agent);
 
433
  ShellNetworkAgentPrivate *priv = self->priv;
 
434
 
 
435
  gchar *request_id = g_strdup_printf ("%s/%s", connection_path, setting_name);
 
436
  ShellAgentRequest *request = g_hash_table_lookup (priv->requests, request_id);
 
437
 
 
438
  GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
 
439
                               NM_SECRET_AGENT_ERROR_AGENT_CANCELED,
 
440
                               "Canceled by NetworkManager");
 
441
  request->callback (agent, request->connection, NULL, error, request->callback_data);
 
442
 
 
443
  g_signal_emit (self, signals[SIGNAL_CANCEL_REQUEST], 0, request_id);
 
444
 
 
445
  g_hash_table_remove (priv->requests, request_id);
 
446
  g_free (request_id);
 
447
  g_error_free (error);
 
448
}
 
449
 
 
450
/************************* saving of secrets ****************************************/
 
451
 
 
452
static GnomeKeyringAttributeList *
 
453
create_keyring_add_attr_list (NMConnection *connection,
 
454
                              const gchar  *connection_uuid,
 
455
                              const gchar  *connection_id,
 
456
                              const gchar  *setting_name,
 
457
                              const gchar  *setting_key,
 
458
                              gchar       **out_display_name)
 
459
{
 
460
  GnomeKeyringAttributeList *attrs = NULL;
 
461
  NMSettingConnection *s_con;
 
462
 
 
463
  if (connection)
 
464
    {
 
465
      s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
466
      g_return_val_if_fail (s_con != NULL, NULL);
 
467
      connection_uuid = nm_setting_connection_get_uuid (s_con);
 
468
      connection_id = nm_setting_connection_get_id (s_con);
 
469
    }
 
470
 
 
471
  g_return_val_if_fail (connection_uuid != NULL, NULL);
 
472
  g_return_val_if_fail (connection_id != NULL, NULL);
 
473
  g_return_val_if_fail (setting_name != NULL, NULL);
 
474
  g_return_val_if_fail (setting_key != NULL, NULL);
 
475
 
 
476
  if (out_display_name)
 
477
    {
 
478
      *out_display_name = g_strdup_printf ("Network secret for %s/%s/%s",
 
479
                                           connection_id,
 
480
                                           setting_name,
 
481
                                           setting_key);
 
482
    }
 
483
 
 
484
  attrs = gnome_keyring_attribute_list_new ();
 
485
  gnome_keyring_attribute_list_append_string (attrs,
 
486
                                              SHELL_KEYRING_UUID_TAG,
 
487
                                              connection_uuid);
 
488
  gnome_keyring_attribute_list_append_string (attrs,
 
489
                                              SHELL_KEYRING_SN_TAG,
 
490
                                              setting_name);
 
491
  gnome_keyring_attribute_list_append_string (attrs,
 
492
                                              SHELL_KEYRING_SK_TAG,
 
493
                                              setting_key);
 
494
  return attrs;
 
495
}
 
496
 
 
497
typedef struct
 
498
{
 
499
  /* Sort of ref count, indicates the number of secrets we still need to save */
 
500
  gint           n_secrets;
 
501
 
 
502
  NMSecretAgent *self;
 
503
  NMConnection  *connection;
 
504
  gpointer       callback;
 
505
  gpointer       callback_data;
 
506
} KeyringRequest;
 
507
 
 
508
static void
 
509
keyring_request_free (KeyringRequest *r)
 
510
{
 
511
  g_object_unref (r->self);
 
512
  g_object_unref (r->connection);
 
513
 
 
514
  g_slice_free (KeyringRequest, r);
 
515
}
 
516
 
 
517
static void
 
518
save_secret_cb (GnomeKeyringResult result,
 
519
                guint              val,
 
520
                gpointer           user_data)
 
521
{
 
522
  KeyringRequest *call = user_data;
 
523
  NMSecretAgentSaveSecretsFunc callback = call->callback;
 
524
 
 
525
  call->n_secrets--;
 
526
 
 
527
  if (call->n_secrets == 0)
 
528
    {
 
529
      if (callback)
 
530
        callback (call->self, call->connection, NULL, call->callback_data);
 
531
      keyring_request_free (call);
 
532
    }
 
533
}
 
534
 
 
535
static void
 
536
save_one_secret (KeyringRequest *r,
 
537
                 NMSetting      *setting,
 
538
                 const gchar    *key,
 
539
                 const gchar    *secret,
 
540
                 const gchar    *display_name)
 
541
{
 
542
  GnomeKeyringAttributeList *attrs;
 
543
  gchar *alt_display_name = NULL;
 
544
  const gchar *setting_name;
 
545
  NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
546
 
 
547
  /* Only save agent-owned secrets (not system-owned or always-ask) */
 
548
  nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
 
549
  if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED)
 
550
    return;
 
551
 
 
552
  setting_name = nm_setting_get_name (setting);
 
553
  g_assert (setting_name);
 
554
 
 
555
  attrs = create_keyring_add_attr_list (r->connection, NULL, NULL,
 
556
                                        setting_name,
 
557
                                        key,
 
558
                                        display_name ? NULL : &alt_display_name);
 
559
  g_assert (attrs);
 
560
  r->n_secrets++;
 
561
  gnome_keyring_item_create (NULL,
 
562
                             GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
563
                             display_name ? display_name : alt_display_name,
 
564
                             attrs,
 
565
                             secret,
 
566
                             TRUE,
 
567
                             save_secret_cb,
 
568
                             r,
 
569
                             NULL);
 
570
 
 
571
  gnome_keyring_attribute_list_free (attrs);
 
572
  g_free (alt_display_name);
 
573
}
 
574
 
 
575
static void
 
576
vpn_secret_iter_cb (const gchar *key,
 
577
                    const gchar *secret,
 
578
                    gpointer     user_data)
 
579
{
 
580
  KeyringRequest *r = user_data;
 
581
  NMSetting *setting;
 
582
  const gchar *service_name, *id;
 
583
  gchar *display_name;
 
584
 
 
585
  if (secret && strlen (secret))
 
586
    {
 
587
      setting = nm_connection_get_setting (r->connection, NM_TYPE_SETTING_VPN);
 
588
      g_assert (setting);
 
589
      service_name = nm_setting_vpn_get_service_type (NM_SETTING_VPN (setting));
 
590
      g_assert (service_name);
 
591
      id = nm_connection_get_id (r->connection);
 
592
      g_assert (id);
 
593
 
 
594
      display_name = g_strdup_printf ("VPN %s secret for %s/%s/" NM_SETTING_VPN_SETTING_NAME,
 
595
                                      key,
 
596
                                      id,
 
597
                                      service_name);
 
598
      save_one_secret (r, setting, key, secret, display_name);
 
599
      g_free (display_name);
 
600
    }
 
601
}
 
602
 
 
603
static void
 
604
write_one_secret_to_keyring (NMSetting    *setting,
 
605
                             const gchar  *key,
 
606
                             const GValue *value,
 
607
                             GParamFlags   flags,
 
608
                             gpointer      user_data)
 
609
{
 
610
  KeyringRequest *r = user_data;
 
611
  const gchar *secret;
 
612
 
 
613
  /* Non-secrets obviously don't get saved in the keyring */
 
614
  if (!(flags & NM_SETTING_PARAM_SECRET))
 
615
    return;
 
616
 
 
617
  if (NM_IS_SETTING_VPN (setting) && (g_strcmp0 (key, NM_SETTING_VPN_SECRETS) == 0))
 
618
    {
 
619
      /* Process VPN secrets specially since it's a hash of secrets, not just one */
 
620
      nm_setting_vpn_foreach_secret (NM_SETTING_VPN (setting),
 
621
                                     vpn_secret_iter_cb,
 
622
                                     r);
 
623
    }
 
624
  else
 
625
    {
 
626
      secret = g_value_get_string (value);
 
627
      if (secret && strlen (secret))
 
628
        save_one_secret (r, setting, key, secret, NULL);
 
629
  }
 
630
}
 
631
 
 
632
static void
 
633
save_delete_cb (NMSecretAgent *agent,
 
634
                NMConnection  *connection,
 
635
                GError        *error,
 
636
                gpointer       user_data)
 
637
{
 
638
  KeyringRequest *r = user_data;
 
639
 
 
640
  /* Ignore errors; now save all new secrets */
 
641
  nm_connection_for_each_setting_value (connection, write_one_secret_to_keyring, r);
 
642
 
 
643
  /* If no secrets actually got saved there may be nothing to do so
 
644
   * try to complete the request here. If there were secrets to save the
 
645
   * request will get completed when those keyring calls return (at the next
 
646
   * mainloop iteration).
 
647
   */
 
648
  if (r->n_secrets == 0)
 
649
    {
 
650
      if (r->callback)
 
651
        ((NMSecretAgentSaveSecretsFunc)r->callback) (agent, connection, NULL, r->callback_data);
 
652
      keyring_request_free (r);
 
653
    }
 
654
}
 
655
 
 
656
static void
 
657
shell_network_agent_save_secrets (NMSecretAgent                *agent,
 
658
                                  NMConnection                 *connection,
 
659
                                  const gchar                  *connection_path,
 
660
                                  NMSecretAgentSaveSecretsFunc  callback,
 
661
                                  gpointer                      callback_data)
 
662
{
 
663
  KeyringRequest *r;
 
664
 
 
665
  r = g_slice_new (KeyringRequest);
 
666
  r->n_secrets = 0;
 
667
  r->self = g_object_ref (agent);
 
668
  r->connection = g_object_ref (connection);
 
669
  r->callback = callback;
 
670
  r->callback_data = callback_data;
 
671
 
 
672
  /* First delete any existing items in the keyring */
 
673
  nm_secret_agent_delete_secrets (agent, connection, save_delete_cb, r);
 
674
}
 
675
 
 
676
static void
 
677
keyring_delete_cb (GnomeKeyringResult result, gpointer user_data)
 
678
{
 
679
  /* Ignored */
 
680
}
 
681
 
 
682
static void
 
683
delete_find_items_cb (GnomeKeyringResult result, GList *list, gpointer user_data)
 
684
{
 
685
  KeyringRequest *r = user_data;
 
686
  GList *iter;
 
687
  GError *error = NULL;
 
688
  NMSecretAgentDeleteSecretsFunc callback = r->callback;
 
689
 
 
690
  if ((result == GNOME_KEYRING_RESULT_OK) || (result == GNOME_KEYRING_RESULT_NO_MATCH))
 
691
    {
 
692
      for (iter = list; iter != NULL; iter = g_list_next (iter))
 
693
        {
 
694
          GnomeKeyringFound *found = (GnomeKeyringFound *) iter->data;
 
695
 
 
696
          gnome_keyring_item_delete (found->keyring, found->item_id, keyring_delete_cb, NULL, NULL);
 
697
        }
 
698
    }
 
699
  else
 
700
    {
 
701
      error = g_error_new (NM_SECRET_AGENT_ERROR,
 
702
                           NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
 
703
                           "The request could not be completed.  Keyring result: %d",
 
704
                           result);
 
705
    }
 
706
 
 
707
  callback (r->self, r->connection, error, r->callback_data);
 
708
  g_clear_error (&error);
 
709
}
 
710
 
 
711
static void
 
712
shell_network_agent_delete_secrets (NMSecretAgent                  *agent,
 
713
                                    NMConnection                   *connection,
 
714
                                    const gchar                    *connection_path,
 
715
                                    NMSecretAgentDeleteSecretsFunc  callback,
 
716
                                    gpointer                        callback_data)
 
717
{
 
718
  KeyringRequest *r;
 
719
  NMSettingConnection *s_con;
 
720
  const gchar *uuid;
 
721
 
 
722
  r = g_slice_new (KeyringRequest);
 
723
  r->n_secrets = 0; /* ignored by delete secrets calls */
 
724
  r->self = g_object_ref (agent);
 
725
  r->connection = g_object_ref (connection);
 
726
  r->callback = callback;
 
727
  r->callback_data = callback_data;
 
728
 
 
729
  s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
 
730
  g_assert (s_con);
 
731
  uuid = nm_setting_connection_get_uuid (s_con);
 
732
  g_assert (uuid);
 
733
 
 
734
  gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
 
735
                             delete_find_items_cb,
 
736
                             r,
 
737
                             (GDestroyNotify)keyring_request_free,
 
738
                             SHELL_KEYRING_UUID_TAG,
 
739
                             GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
 
740
                             uuid,
 
741
                             NULL);
 
742
}
 
743
 
 
744
void
 
745
shell_network_agent_class_init (ShellNetworkAgentClass *klass)
 
746
{
 
747
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
748
  NMSecretAgentClass *agent_class = NM_SECRET_AGENT_CLASS (klass);
 
749
 
 
750
  gobject_class->finalize = shell_network_agent_finalize;
 
751
 
 
752
  agent_class->get_secrets = shell_network_agent_get_secrets;
 
753
  agent_class->cancel_get_secrets = shell_network_agent_cancel_get_secrets;
 
754
  agent_class->save_secrets = shell_network_agent_save_secrets;
 
755
  agent_class->delete_secrets = shell_network_agent_delete_secrets;
 
756
 
 
757
  signals[SIGNAL_NEW_REQUEST] = g_signal_new ("new-request",
 
758
                                              G_TYPE_FROM_CLASS (klass),
 
759
                                              0, /* flags */
 
760
                                              0, /* class offset */
 
761
                                              NULL, /* accumulator */
 
762
                                              NULL, /* accu_data */
 
763
                                              _shell_marshal_VOID__STRING_OBJECT_STRING_BOXED,
 
764
                                              G_TYPE_NONE, /* return */
 
765
                                              3, /* n_params */
 
766
                                              G_TYPE_STRING,
 
767
                                              NM_TYPE_CONNECTION,
 
768
                                              G_TYPE_STRING,
 
769
                                              G_TYPE_STRV);
 
770
 
 
771
  signals[SIGNAL_CANCEL_REQUEST] = g_signal_new ("cancel-request",
 
772
                                                 G_TYPE_FROM_CLASS (klass),
 
773
                                                 0, /* flags */
 
774
                                                 0, /* class offset */
 
775
                                                 NULL, /* accumulator */
 
776
                                                 NULL, /* accu_data */
 
777
                                                 g_cclosure_marshal_VOID__STRING,
 
778
                                                 G_TYPE_NONE,
 
779
                                                 1, /* n_params */
 
780
                                                 G_TYPE_STRING);
 
781
 
 
782
  g_type_class_add_private (klass, sizeof (ShellNetworkAgentPrivate));
 
783
}