~ubuntu-branches/ubuntu/natty/gnome-keyring/natty

« back to all changes in this revision

Viewing changes to daemon/dbus/gkd-secret-prompt.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-02-16 19:00:06 UTC
  • mfrom: (1.1.58 upstream)
  • Revision ID: james.westby@ubuntu.com-20100216190006-cqpnic4zxlkmmi0o
Tags: 2.29.90git20100218-0ubuntu1
Updated to a git snapshot version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * gnome-keyring
 
3
 *
 
4
 * Copyright (C) 2008 Stefan Walter
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU Lesser General Public License as
 
8
 * published by the Free Software Foundation; either version 2.1 of
 
9
 * the License, or (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include "gkd-dbus-util.h"
 
25
#include "gkd-secret-service.h"
 
26
#include "gkd-secret-prompt.h"
 
27
#include "gkd-secret-objects.h"
 
28
#include "gkd-secret-secret.h"
 
29
#include "gkd-secret-session.h"
 
30
#include "gkd-secret-types.h"
 
31
#include "gkd-secret-util.h"
 
32
 
 
33
#include "prompt/gkd-prompt.h"
 
34
 
 
35
#include "egg/egg-dh.h"
 
36
 
 
37
#include <string.h>
 
38
 
 
39
enum {
 
40
        PROP_0,
 
41
        PROP_CALLER,
 
42
        PROP_OBJECT_PATH,
 
43
        PROP_SERVICE
 
44
};
 
45
 
 
46
#define PROMPT_IKE_GROUP  "ietf-ike-grp-modp-1536"
 
47
 
 
48
struct _GkdSecretPromptPrivate {
 
49
        GkdPrompt parent;
 
50
        gchar *object_path;
 
51
        GkdSecretService *service;
 
52
        GkdSecretSession *session;
 
53
        gboolean prompted;
 
54
        gboolean negotiated;
 
55
        gboolean completed;
 
56
        gchar *caller;
 
57
        gchar *window_id;
 
58
        GList *objects;
 
59
};
 
60
 
 
61
G_DEFINE_TYPE (GkdSecretPrompt, gkd_secret_prompt, GKD_TYPE_PROMPT);
 
62
 
 
63
static guint unique_prompt_number = 0;
 
64
 
 
65
/* -----------------------------------------------------------------------------
 
66
 * INTERNAL
 
67
 */
 
68
 
 
69
static void
 
70
setup_transport_params (GkdSecretPrompt *self)
 
71
{
 
72
        GkdPrompt *prompt = GKD_PROMPT (self);
 
73
        gsize n_public, n_prime, n_base;
 
74
        gconstpointer prime, base;
 
75
        gpointer public;
 
76
 
 
77
        if (self->pv->session)
 
78
                g_object_unref (self->pv->session);
 
79
        self->pv->session = gkd_secret_session_new (self->pv->service, self->pv->caller);
 
80
 
 
81
        public = gkd_secret_session_begin (self->pv->session, PROMPT_IKE_GROUP, &n_public);
 
82
        g_return_if_fail (public);
 
83
        self->pv->negotiated = FALSE;
 
84
 
 
85
        gkd_prompt_set_transport_param (prompt, "public", public, n_public);
 
86
        g_free (public);
 
87
 
 
88
        /* Setup transport crypto */
 
89
        if (!egg_dh_default_params_raw (PROMPT_IKE_GROUP, &prime, &n_prime, &base, &n_base))
 
90
                g_return_if_reached ();
 
91
 
 
92
        gkd_prompt_set_transport_param (prompt, "prime", prime, n_prime);
 
93
        gkd_prompt_set_transport_param (prompt, "base", base, n_base);
 
94
}
 
95
 
 
96
static gboolean
 
97
complete_transport_params (GkdSecretPrompt *self)
 
98
{
 
99
        GkdPrompt *prompt = GKD_PROMPT (self);
 
100
        gboolean result;
 
101
        gsize n_peer;
 
102
        gpointer peer;
 
103
 
 
104
        if (self->pv->negotiated)
 
105
                return TRUE;
 
106
 
 
107
        g_return_val_if_fail (self->pv->session, FALSE);
 
108
 
 
109
        peer = gkd_prompt_get_transport_param (prompt, "public", &n_peer);
 
110
        if (peer == NULL) {
 
111
                g_warning ("prompt did not return a public dh key");
 
112
                return FALSE;
 
113
        }
 
114
 
 
115
        result = gkd_secret_session_complete (self->pv->session, peer, n_peer);
 
116
        g_free (peer);
 
117
 
 
118
        if (result)
 
119
                self->pv->negotiated = TRUE;
 
120
        else
 
121
                g_warning ("negotiation of transport crypto with prompt failed");
 
122
 
 
123
        return result;
 
124
}
 
125
 
 
126
static GkdPrompt*
 
127
on_prompt_attention (gpointer user_data)
 
128
{
 
129
        GkdSecretPrompt *self = user_data;
 
130
 
 
131
        /* Check with the derived class */
 
132
        g_return_val_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->prompt_ready, NULL);
 
133
        GKD_SECRET_PROMPT_GET_CLASS (self)->prompt_ready (self);
 
134
 
 
135
        if (self->pv->completed)
 
136
                return NULL;
 
137
 
 
138
        setup_transport_params (self);
 
139
        return g_object_ref (self);
 
140
}
 
141
 
 
142
static void
 
143
emit_completed (GkdSecretPrompt *self, gboolean dismissed)
 
144
{
 
145
        DBusMessage *signal;
 
146
        DBusMessageIter iter;
 
147
        dbus_bool_t bval;
 
148
 
 
149
        signal = dbus_message_new_signal (self->pv->object_path, SECRET_PROMPT_INTERFACE,
 
150
                                          "Completed");
 
151
        dbus_message_set_destination (signal, self->pv->caller);
 
152
        dbus_message_iter_init_append (signal, &iter);
 
153
 
 
154
        bval = dismissed;
 
155
        dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bval);
 
156
 
 
157
        g_return_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result);
 
158
        GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result (self, &iter);
 
159
 
 
160
        gkd_secret_service_send (self->pv->service, signal);
 
161
        dbus_message_unref (signal);
 
162
}
 
163
 
 
164
/* -----------------------------------------------------------------------------
 
165
 * DBUS
 
166
 */
 
167
 
 
168
static DBusMessage*
 
169
prompt_method_prompt (GkdSecretPrompt *self, DBusMessage *message)
 
170
{
 
171
        DBusMessage *reply;
 
172
        const char *window_id;
 
173
 
 
174
        /* Act as if this object no longer exists */
 
175
        if (self->pv->completed)
 
176
                return NULL;
 
177
 
 
178
        if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING,
 
179
                                    &window_id, DBUS_TYPE_INVALID))
 
180
                return NULL;
 
181
 
 
182
        /* Prompt can only be called once */
 
183
        if (self->pv->prompted)
 
184
                return dbus_message_new_error (message, SECRET_ERROR_ALREADY_EXISTS,
 
185
                                               "This prompt has already been shown.");
 
186
 
 
187
        gkd_prompt_set_window_id (GKD_PROMPT (self), window_id);
 
188
        gkd_prompt_request_attention_async (window_id, on_prompt_attention,
 
189
                                            g_object_ref (self), g_object_unref);
 
190
        self->pv->prompted = TRUE;
 
191
 
 
192
        reply = dbus_message_new_method_return (message);
 
193
        dbus_message_append_args (reply, DBUS_TYPE_INVALID);
 
194
        return reply;
 
195
}
 
196
 
 
197
static DBusMessage*
 
198
prompt_method_dismiss (GkdSecretPrompt *self, DBusMessage *message)
 
199
{
 
200
        DBusMessage *reply;
 
201
 
 
202
        /* Act as if this object no longer exists */
 
203
        if (self->pv->completed)
 
204
                return NULL;
 
205
 
 
206
        if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
 
207
                return NULL;
 
208
 
 
209
        gkd_secret_prompt_dismiss (self);
 
210
 
 
211
        reply = dbus_message_new_method_return (message);
 
212
        dbus_message_append_args (reply, DBUS_TYPE_INVALID);
 
213
        return reply;
 
214
}
 
215
 
 
216
/* -----------------------------------------------------------------------------
 
217
 * OBJECT
 
218
 */
 
219
 
 
220
static gboolean
 
221
gkd_secret_prompt_responded (GkdPrompt *base)
 
222
{
 
223
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (base);
 
224
        gint res;
 
225
 
 
226
        res = gkd_prompt_get_response (GKD_PROMPT (self));
 
227
        if (res <= GKD_RESPONSE_NO) {
 
228
                gkd_secret_prompt_dismiss (self);
 
229
                return FALSE;
 
230
        }
 
231
 
 
232
        /* Check with the prompt ready guys */
 
233
        g_return_val_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->prompt_ready, TRUE);
 
234
        GKD_SECRET_PROMPT_GET_CLASS (self)->prompt_ready (self);
 
235
 
 
236
        /* Not yet done, will display again */
 
237
        if (!self->pv->completed) {
 
238
                setup_transport_params (self);
 
239
                return TRUE;
 
240
        }
 
241
 
 
242
        return FALSE;
 
243
}
 
244
 
 
245
static void
 
246
gkd_secret_prompt_ready (GkdSecretPrompt *self)
 
247
{
 
248
        /* Default implementation, unused */
 
249
        g_return_if_reached ();
 
250
}
 
251
 
 
252
static void
 
253
gkd_secret_prompt_encode_result (GkdSecretPrompt *self, DBusMessageIter *iter)
 
254
{
 
255
        /* Default implementation, unused */
 
256
        g_return_if_reached ();
 
257
}
 
258
 
 
259
static GObject*
 
260
gkd_secret_prompt_constructor (GType type, guint n_props, GObjectConstructParam *props)
 
261
{
 
262
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->constructor(type, n_props, props));
 
263
 
 
264
        g_return_val_if_fail (self, NULL);
 
265
        g_return_val_if_fail (self->pv->caller, NULL);
 
266
        g_return_val_if_fail (self->pv->service, NULL);
 
267
 
 
268
        /* Setup the path for the object */
 
269
        self->pv->object_path = g_strdup_printf (SECRET_PROMPT_PREFIX "/p%d", ++unique_prompt_number);
 
270
 
 
271
        return G_OBJECT (self);
 
272
}
 
273
 
 
274
static void
 
275
gkd_secret_prompt_init (GkdSecretPrompt *self)
 
276
{
 
277
        self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKD_SECRET_TYPE_PROMPT, GkdSecretPromptPrivate);
 
278
}
 
279
 
 
280
static void
 
281
gkd_secret_prompt_dispose (GObject *obj)
 
282
{
 
283
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
 
284
 
 
285
        g_free (self->pv->object_path);
 
286
        self->pv->object_path = NULL;
 
287
 
 
288
        if (self->pv->service) {
 
289
                g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
 
290
                                              (gpointer*)&(self->pv->service));
 
291
                self->pv->service = NULL;
 
292
        }
 
293
 
 
294
        if (self->pv->session)
 
295
                g_object_unref (self->pv->session);
 
296
        self->pv->session = NULL;
 
297
 
 
298
        G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->dispose (obj);
 
299
}
 
300
 
 
301
static void
 
302
gkd_secret_prompt_finalize (GObject *obj)
 
303
{
 
304
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
 
305
 
 
306
        g_assert (!self->pv->object_path);
 
307
        g_assert (!self->pv->service);
 
308
        g_assert (!self->pv->session);
 
309
 
 
310
        g_free (self->pv->caller);
 
311
        self->pv->caller = NULL;
 
312
 
 
313
        G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->finalize (obj);
 
314
}
 
315
 
 
316
static void
 
317
gkd_secret_prompt_set_property (GObject *obj, guint prop_id, const GValue *value,
 
318
                                GParamSpec *pspec)
 
319
{
 
320
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
 
321
 
 
322
        switch (prop_id) {
 
323
        case PROP_CALLER:
 
324
                g_return_if_fail (!self->pv->caller);
 
325
                self->pv->caller = g_value_dup_string (value);
 
326
                break;
 
327
        case PROP_SERVICE:
 
328
                g_return_if_fail (!self->pv->service);
 
329
                self->pv->service = g_value_get_object (value);
 
330
                g_return_if_fail (self->pv->service);
 
331
                g_object_add_weak_pointer (G_OBJECT (self->pv->service),
 
332
                                           (gpointer*)&(self->pv->service));
 
333
                break;
 
334
        default:
 
335
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
336
                break;
 
337
        }
 
338
}
 
339
 
 
340
static void
 
341
gkd_secret_prompt_get_property (GObject *obj, guint prop_id, GValue *value,
 
342
                                GParamSpec *pspec)
 
343
{
 
344
        GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
 
345
 
 
346
        switch (prop_id) {
 
347
        case PROP_CALLER:
 
348
                g_value_set_string (value, gkd_secret_prompt_get_caller (self));
 
349
                break;
 
350
        case PROP_OBJECT_PATH:
 
351
                g_value_set_boxed (value, gkd_secret_prompt_get_object_path (self));
 
352
                break;
 
353
        case PROP_SERVICE:
 
354
                g_value_set_object (value, self->pv->service);
 
355
                break;
 
356
        default:
 
357
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
358
                break;
 
359
        }
 
360
}
 
361
 
 
362
static void
 
363
gkd_secret_prompt_class_init (GkdSecretPromptClass *klass)
 
364
{
 
365
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
366
        GkdPromptClass *prompt_class = GKD_PROMPT_CLASS (klass);
 
367
 
 
368
        gobject_class->constructor = gkd_secret_prompt_constructor;
 
369
        gobject_class->dispose = gkd_secret_prompt_dispose;
 
370
        gobject_class->finalize = gkd_secret_prompt_finalize;
 
371
        gobject_class->set_property = gkd_secret_prompt_set_property;
 
372
        gobject_class->get_property = gkd_secret_prompt_get_property;
 
373
 
 
374
        prompt_class->responded = gkd_secret_prompt_responded;
 
375
 
 
376
        klass->encode_result = gkd_secret_prompt_encode_result;
 
377
        klass->prompt_ready = gkd_secret_prompt_ready;
 
378
 
 
379
        g_type_class_add_private (klass, sizeof (GkdSecretPromptPrivate));
 
380
 
 
381
        g_object_class_install_property (gobject_class, PROP_CALLER,
 
382
                g_param_spec_string ("caller", "Caller", "DBus caller name",
 
383
                                     NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
 
384
 
 
385
        g_object_class_install_property (gobject_class, PROP_OBJECT_PATH,
 
386
                g_param_spec_string ("object-path", "Object Path", "DBus Object Path",
 
387
                                     NULL, G_PARAM_READABLE));
 
388
 
 
389
        g_object_class_install_property (gobject_class, PROP_SERVICE,
 
390
                g_param_spec_object ("service", "Service", "Service which owns this prompt",
 
391
                                     GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
392
}
 
393
 
 
394
/* -----------------------------------------------------------------------------
 
395
 * PUBLIC
 
396
 */
 
397
 
 
398
DBusMessage*
 
399
gkd_secret_prompt_dispatch (GkdSecretPrompt *self, DBusMessage *message)
 
400
{
 
401
        DBusMessage *reply = NULL;
 
402
        const gchar *caller;
 
403
 
 
404
        g_return_val_if_fail (message, NULL);
 
405
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
406
 
 
407
        /* This should already have been caught elsewhere */
 
408
        caller = dbus_message_get_sender (message);
 
409
        if (!caller || !g_str_equal (caller, self->pv->caller))
 
410
                g_return_val_if_reached (NULL);
 
411
 
 
412
        /* org.freedesktop.Secrets.Prompt.Prompt() */
 
413
        else if (dbus_message_is_method_call (message, SECRET_PROMPT_INTERFACE, "Prompt"))
 
414
                reply = prompt_method_prompt (self, message);
 
415
 
 
416
        /* org.freedesktop.Secrets.Prompt.Negotiate() */
 
417
        else if (dbus_message_is_method_call (message, SECRET_PROMPT_INTERFACE, "Dismiss"))
 
418
                reply = prompt_method_dismiss (self, message);
 
419
 
 
420
        else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
 
421
                return gkd_dbus_introspect_handle (message, "prompt");
 
422
 
 
423
        return reply;
 
424
}
 
425
 
 
426
const gchar*
 
427
gkd_secret_prompt_get_caller (GkdSecretPrompt *self)
 
428
{
 
429
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
430
        return self->pv->caller;
 
431
}
 
432
 
 
433
const gchar*
 
434
gkd_secret_prompt_get_object_path (GkdSecretPrompt *self)
 
435
{
 
436
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
437
        return self->pv->object_path;
 
438
}
 
439
 
 
440
GP11Session*
 
441
gkd_secret_prompt_get_pkcs11_session (GkdSecretPrompt *self)
 
442
{
 
443
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
444
        g_return_val_if_fail (self->pv->service, NULL);
 
445
        return gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
 
446
}
 
447
 
 
448
GkdSecretObjects*
 
449
gkd_secret_prompt_get_objects (GkdSecretPrompt *self)
 
450
{
 
451
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
452
        g_return_val_if_fail (self->pv->service, NULL);
 
453
        return gkd_secret_service_get_objects (self->pv->service);
 
454
}
 
455
 
 
456
void
 
457
gkd_secret_prompt_complete (GkdSecretPrompt *self)
 
458
{
 
459
        g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
 
460
        g_return_if_fail (!self->pv->completed);
 
461
        self->pv->completed = TRUE;
 
462
        emit_completed (self, FALSE);
 
463
}
 
464
 
 
465
void
 
466
gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
 
467
{
 
468
        g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
 
469
        g_return_if_fail (!self->pv->completed);
 
470
        self->pv->completed = TRUE;
 
471
        emit_completed (self, TRUE);
 
472
}
 
473
 
 
474
GkdSecretSession*
 
475
gkd_secret_prompt_get_session (GkdSecretPrompt *self)
 
476
{
 
477
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
478
        g_return_val_if_fail (self->pv->service, NULL);
 
479
        return self->pv->session;
 
480
}
 
481
 
 
482
GP11Object*
 
483
gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
 
484
{
 
485
        GkdSecretObjects *objects;
 
486
 
 
487
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
488
        g_return_val_if_fail (path, NULL);
 
489
 
 
490
        objects = gkd_secret_prompt_get_objects (GKD_SECRET_PROMPT (self));
 
491
        return gkd_secret_objects_lookup_collection (objects, self->pv->caller, path);
 
492
}
 
493
 
 
494
GkdSecretSecret*
 
495
gkd_secret_prompt_get_secret (GkdSecretPrompt *self, const gchar *password_type)
 
496
{
 
497
        gpointer parameter, value;
 
498
        gsize n_parameter, n_value;
 
499
 
 
500
        g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 
501
 
 
502
        if (!complete_transport_params (self))
 
503
                return NULL;
 
504
 
 
505
        if (!gkd_prompt_get_transport_password (GKD_PROMPT (self), password_type,
 
506
                                                &parameter, &n_parameter,
 
507
                                                &value, &n_value))
 
508
                return NULL;
 
509
 
 
510
        return gkd_secret_secret_new_take_memory (self->pv->session,
 
511
                                                  parameter, n_parameter,
 
512
                                                  value, n_value);
 
513
}