4
* Copyright (C) 2008 Stefan Walter
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.
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.
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
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"
33
#include "prompt/gkd-prompt.h"
35
#include "egg/egg-dh.h"
46
#define PROMPT_IKE_GROUP "ietf-ike-grp-modp-1536"
48
struct _GkdSecretPromptPrivate {
51
GkdSecretService *service;
52
GkdSecretSession *session;
61
G_DEFINE_TYPE (GkdSecretPrompt, gkd_secret_prompt, GKD_TYPE_PROMPT);
63
static guint unique_prompt_number = 0;
65
/* -----------------------------------------------------------------------------
70
setup_transport_params (GkdSecretPrompt *self)
72
GkdPrompt *prompt = GKD_PROMPT (self);
73
gsize n_public, n_prime, n_base;
74
gconstpointer prime, base;
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);
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;
85
gkd_prompt_set_transport_param (prompt, "public", public, n_public);
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 ();
92
gkd_prompt_set_transport_param (prompt, "prime", prime, n_prime);
93
gkd_prompt_set_transport_param (prompt, "base", base, n_base);
97
complete_transport_params (GkdSecretPrompt *self)
99
GkdPrompt *prompt = GKD_PROMPT (self);
104
if (self->pv->negotiated)
107
g_return_val_if_fail (self->pv->session, FALSE);
109
peer = gkd_prompt_get_transport_param (prompt, "public", &n_peer);
111
g_warning ("prompt did not return a public dh key");
115
result = gkd_secret_session_complete (self->pv->session, peer, n_peer);
119
self->pv->negotiated = TRUE;
121
g_warning ("negotiation of transport crypto with prompt failed");
127
on_prompt_attention (gpointer user_data)
129
GkdSecretPrompt *self = user_data;
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);
135
if (self->pv->completed)
138
setup_transport_params (self);
139
return g_object_ref (self);
143
emit_completed (GkdSecretPrompt *self, gboolean dismissed)
146
DBusMessageIter iter;
149
signal = dbus_message_new_signal (self->pv->object_path, SECRET_PROMPT_INTERFACE,
151
dbus_message_set_destination (signal, self->pv->caller);
152
dbus_message_iter_init_append (signal, &iter);
155
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bval);
157
g_return_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result);
158
GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result (self, &iter);
160
gkd_secret_service_send (self->pv->service, signal);
161
dbus_message_unref (signal);
164
/* -----------------------------------------------------------------------------
169
prompt_method_prompt (GkdSecretPrompt *self, DBusMessage *message)
172
const char *window_id;
174
/* Act as if this object no longer exists */
175
if (self->pv->completed)
178
if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING,
179
&window_id, DBUS_TYPE_INVALID))
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.");
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;
192
reply = dbus_message_new_method_return (message);
193
dbus_message_append_args (reply, DBUS_TYPE_INVALID);
198
prompt_method_dismiss (GkdSecretPrompt *self, DBusMessage *message)
202
/* Act as if this object no longer exists */
203
if (self->pv->completed)
206
if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
209
gkd_secret_prompt_dismiss (self);
211
reply = dbus_message_new_method_return (message);
212
dbus_message_append_args (reply, DBUS_TYPE_INVALID);
216
/* -----------------------------------------------------------------------------
221
gkd_secret_prompt_responded (GkdPrompt *base)
223
GkdSecretPrompt *self = GKD_SECRET_PROMPT (base);
226
res = gkd_prompt_get_response (GKD_PROMPT (self));
227
if (res <= GKD_RESPONSE_NO) {
228
gkd_secret_prompt_dismiss (self);
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);
236
/* Not yet done, will display again */
237
if (!self->pv->completed) {
238
setup_transport_params (self);
246
gkd_secret_prompt_ready (GkdSecretPrompt *self)
248
/* Default implementation, unused */
249
g_return_if_reached ();
253
gkd_secret_prompt_encode_result (GkdSecretPrompt *self, DBusMessageIter *iter)
255
/* Default implementation, unused */
256
g_return_if_reached ();
260
gkd_secret_prompt_constructor (GType type, guint n_props, GObjectConstructParam *props)
262
GkdSecretPrompt *self = GKD_SECRET_PROMPT (G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->constructor(type, n_props, props));
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);
268
/* Setup the path for the object */
269
self->pv->object_path = g_strdup_printf (SECRET_PROMPT_PREFIX "/p%d", ++unique_prompt_number);
271
return G_OBJECT (self);
275
gkd_secret_prompt_init (GkdSecretPrompt *self)
277
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKD_SECRET_TYPE_PROMPT, GkdSecretPromptPrivate);
281
gkd_secret_prompt_dispose (GObject *obj)
283
GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
285
g_free (self->pv->object_path);
286
self->pv->object_path = NULL;
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;
294
if (self->pv->session)
295
g_object_unref (self->pv->session);
296
self->pv->session = NULL;
298
G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->dispose (obj);
302
gkd_secret_prompt_finalize (GObject *obj)
304
GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
306
g_assert (!self->pv->object_path);
307
g_assert (!self->pv->service);
308
g_assert (!self->pv->session);
310
g_free (self->pv->caller);
311
self->pv->caller = NULL;
313
G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->finalize (obj);
317
gkd_secret_prompt_set_property (GObject *obj, guint prop_id, const GValue *value,
320
GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
324
g_return_if_fail (!self->pv->caller);
325
self->pv->caller = g_value_dup_string (value);
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));
335
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
341
gkd_secret_prompt_get_property (GObject *obj, guint prop_id, GValue *value,
344
GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
348
g_value_set_string (value, gkd_secret_prompt_get_caller (self));
350
case PROP_OBJECT_PATH:
351
g_value_set_boxed (value, gkd_secret_prompt_get_object_path (self));
354
g_value_set_object (value, self->pv->service);
357
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
363
gkd_secret_prompt_class_init (GkdSecretPromptClass *klass)
365
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
366
GkdPromptClass *prompt_class = GKD_PROMPT_CLASS (klass);
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;
374
prompt_class->responded = gkd_secret_prompt_responded;
376
klass->encode_result = gkd_secret_prompt_encode_result;
377
klass->prompt_ready = gkd_secret_prompt_ready;
379
g_type_class_add_private (klass, sizeof (GkdSecretPromptPrivate));
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 ));
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));
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));
394
/* -----------------------------------------------------------------------------
399
gkd_secret_prompt_dispatch (GkdSecretPrompt *self, DBusMessage *message)
401
DBusMessage *reply = NULL;
404
g_return_val_if_fail (message, NULL);
405
g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
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);
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);
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);
420
else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
421
return gkd_dbus_introspect_handle (message, "prompt");
427
gkd_secret_prompt_get_caller (GkdSecretPrompt *self)
429
g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
430
return self->pv->caller;
434
gkd_secret_prompt_get_object_path (GkdSecretPrompt *self)
436
g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
437
return self->pv->object_path;
441
gkd_secret_prompt_get_pkcs11_session (GkdSecretPrompt *self)
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);
449
gkd_secret_prompt_get_objects (GkdSecretPrompt *self)
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);
457
gkd_secret_prompt_complete (GkdSecretPrompt *self)
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);
466
gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
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);
475
gkd_secret_prompt_get_session (GkdSecretPrompt *self)
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;
483
gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
485
GkdSecretObjects *objects;
487
g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
488
g_return_val_if_fail (path, NULL);
490
objects = gkd_secret_prompt_get_objects (GKD_SECRET_PROMPT (self));
491
return gkd_secret_objects_lookup_collection (objects, self->pv->caller, path);
495
gkd_secret_prompt_get_secret (GkdSecretPrompt *self, const gchar *password_type)
497
gpointer parameter, value;
498
gsize n_parameter, n_value;
500
g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
502
if (!complete_transport_params (self))
505
if (!gkd_prompt_get_transport_password (GKD_PROMPT (self), password_type,
506
¶meter, &n_parameter,
510
return gkd_secret_secret_new_take_memory (self->pv->session,
511
parameter, n_parameter,