Line data Source code
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, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkd-dbus.h"
24 : #include "gkd-secret-dispatch.h"
25 : #include "gkd-secret-error.h"
26 : #include "gkd-secret-exchange.h"
27 : #include "gkd-secret-service.h"
28 : #include "gkd-secret-prompt.h"
29 : #include "gkd-secret-objects.h"
30 : #include "gkd-secret-secret.h"
31 : #include "gkd-secret-session.h"
32 : #include "gkd-secret-types.h"
33 : #include "gkd-secret-util.h"
34 : #include "gkd-secrets-generated.h"
35 :
36 : #include "egg/egg-dh.h"
37 : #include "egg/egg-error.h"
38 :
39 : #include <string.h>
40 :
41 : enum {
42 : PROP_0,
43 : PROP_CALLER,
44 : PROP_OBJECT_PATH,
45 : PROP_SERVICE
46 : };
47 :
48 : struct _GkdSecretPromptPrivate {
49 : gchar *object_path;
50 : GkdSecretService *service;
51 : GkdSecretExchange *exchange;
52 : GkdExportedPrompt *skeleton;
53 : GCancellable *cancellable;
54 : gboolean prompted;
55 : gboolean completed;
56 : gchar *caller;
57 : gchar *window_id;
58 : GList *objects;
59 : };
60 :
61 : static void gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface);
62 21 : G_DEFINE_TYPE_WITH_CODE (GkdSecretPrompt, gkd_secret_prompt, GCR_TYPE_SYSTEM_PROMPT,
63 : G_ADD_PRIVATE (GkdSecretPrompt)
64 : G_IMPLEMENT_INTERFACE (GKD_SECRET_TYPE_DISPATCH, gkd_secret_dispatch_iface));
65 :
66 : static guint unique_prompt_number = 0;
67 :
68 : static void
69 1 : emit_completed (GkdSecretPrompt *self, gboolean dismissed)
70 : {
71 : GVariant *variant;
72 :
73 1 : g_return_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result);
74 1 : variant = GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result (self);
75 :
76 : /* Emit signal manually, so that we can set the caller as destination */
77 3 : g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton)),
78 1 : self->pv->caller,
79 1 : g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton)),
80 : "org.freedesktop.Secret.Prompt", "Completed",
81 : g_variant_new ("(b@v)", dismissed, variant),
82 : NULL);
83 : }
84 :
85 : static void
86 1 : on_system_prompt_inited (GObject *source,
87 : GAsyncResult *result,
88 : gpointer user_data)
89 : {
90 1 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (source);
91 : GkdSecretPromptClass *klass;
92 1 : GError *error = NULL;
93 :
94 1 : if (g_async_initable_init_finish (G_ASYNC_INITABLE (source), result, &error)) {
95 1 : klass = GKD_SECRET_PROMPT_GET_CLASS (self);
96 1 : g_assert (klass->prompt_ready);
97 1 : (klass->prompt_ready) (self);
98 : } else {
99 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
100 0 : g_message ("couldn't initialize prompt: %s", error->message);
101 0 : g_error_free (error);
102 0 : if (!self->pv->completed)
103 0 : gkd_secret_prompt_dismiss (self);
104 : }
105 1 : }
106 :
107 : static gboolean
108 1 : prompt_method_prompt (GkdExportedPrompt *skeleton,
109 : GDBusMethodInvocation *invocation,
110 : gchar *window_id,
111 : GkdSecretPrompt *self)
112 : {
113 1 : if (!gkd_dbus_invocation_matches_caller (invocation, self->pv->caller))
114 0 : return FALSE;
115 :
116 : /* Act as if this object no longer exists */
117 1 : if (self->pv->completed)
118 0 : return FALSE;
119 :
120 : /* Prompt can only be called once */
121 1 : if (self->pv->prompted) {
122 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
123 : GKD_SECRET_ERROR_ALREADY_EXISTS,
124 : "This prompt has already been shown.");
125 0 : return TRUE;
126 : }
127 :
128 1 : self->pv->prompted = TRUE;
129 :
130 1 : gcr_prompt_set_caller_window (GCR_PROMPT (self), window_id);
131 :
132 1 : g_async_initable_init_async (G_ASYNC_INITABLE (self), G_PRIORITY_DEFAULT,
133 1 : self->pv->cancellable, on_system_prompt_inited, NULL);
134 :
135 1 : gkd_exported_prompt_complete_prompt (skeleton, invocation);
136 1 : return TRUE;
137 : }
138 :
139 : static gboolean
140 0 : prompt_method_dismiss (GkdExportedPrompt *skeleton,
141 : GDBusMethodInvocation *invocation,
142 : GkdSecretPrompt *self)
143 : {
144 0 : if (!gkd_dbus_invocation_matches_caller (invocation, self->pv->caller))
145 0 : return FALSE;
146 :
147 : /* Act as if this object no longer exists */
148 0 : if (self->pv->completed)
149 0 : return FALSE;
150 :
151 0 : gkd_secret_prompt_dismiss (self);
152 :
153 0 : gkd_exported_prompt_complete_dismiss (skeleton, invocation);
154 0 : return TRUE;
155 : }
156 :
157 : static void
158 0 : gkd_secret_prompt_real_prompt_ready (GkdSecretPrompt *self)
159 : {
160 : /* Default implementation, unused */
161 0 : g_return_if_reached ();
162 : }
163 :
164 : static GVariant *
165 0 : gkd_secret_prompt_real_encode_result (GkdSecretPrompt *self)
166 : {
167 : /* Default implementation, unused */
168 0 : g_return_val_if_reached (NULL);
169 : }
170 :
171 : static void
172 1 : gkd_secret_prompt_constructed (GObject *obj)
173 : {
174 1 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
175 1 : GError *error = NULL;
176 :
177 1 : G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->constructed (obj);
178 :
179 1 : g_return_if_fail (self->pv->caller);
180 1 : g_return_if_fail (self->pv->service);
181 :
182 : /* Setup the path for the object */
183 1 : self->pv->object_path = g_strdup_printf (SECRET_PROMPT_PREFIX "/p%d", ++unique_prompt_number);
184 :
185 1 : self->pv->exchange = gkd_secret_exchange_new (self->pv->service, self->pv->caller);
186 :
187 : /* Set the exchange for the prompt */
188 1 : g_object_set (self, "secret-exchange", self->pv->exchange, NULL);
189 :
190 1 : self->pv->skeleton = gkd_exported_prompt_skeleton_new ();
191 1 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton),
192 1 : gkd_secret_service_get_connection (self->pv->service), self->pv->object_path,
193 : &error);
194 :
195 1 : if (error != NULL) {
196 0 : g_warning ("could not register secret prompt on session bus: %s", error->message);
197 0 : g_error_free (error);
198 : }
199 :
200 1 : g_signal_connect (self->pv->skeleton, "handle-dismiss",
201 : G_CALLBACK (prompt_method_dismiss), self);
202 1 : g_signal_connect (self->pv->skeleton, "handle-prompt",
203 : G_CALLBACK (prompt_method_prompt), self);
204 : }
205 :
206 : void
207 0 : gkd_secret_prompt_unexport (GkdSecretPrompt *self)
208 : {
209 0 : g_return_if_fail (self->pv->skeleton != NULL);
210 0 : g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton));
211 0 : g_clear_object (&self->pv->skeleton);
212 : }
213 :
214 : static void
215 1 : gkd_secret_prompt_init (GkdSecretPrompt *self)
216 : {
217 1 : self->pv = gkd_secret_prompt_get_instance_private (self);
218 1 : self->pv->cancellable = g_cancellable_new ();
219 1 : }
220 :
221 : static void
222 2 : gkd_secret_prompt_dispose (GObject *obj)
223 : {
224 2 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
225 :
226 2 : g_cancellable_cancel (self->pv->cancellable);
227 :
228 2 : g_free (self->pv->object_path);
229 2 : self->pv->object_path = NULL;
230 :
231 2 : if (self->pv->service) {
232 1 : g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
233 1 : (gpointer*)&(self->pv->service));
234 1 : self->pv->service = NULL;
235 : }
236 :
237 2 : g_clear_object (&self->pv->exchange);
238 :
239 2 : G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->dispose (obj);
240 2 : }
241 :
242 : static void
243 0 : gkd_secret_prompt_finalize (GObject *obj)
244 : {
245 0 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
246 :
247 0 : g_assert (!self->pv->object_path);
248 0 : g_assert (!self->pv->service);
249 :
250 0 : g_free (self->pv->caller);
251 0 : self->pv->caller = NULL;
252 :
253 0 : g_clear_object (&self->pv->cancellable);
254 :
255 0 : G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->finalize (obj);
256 0 : }
257 :
258 : static void
259 2 : gkd_secret_prompt_set_property (GObject *obj, guint prop_id, const GValue *value,
260 : GParamSpec *pspec)
261 : {
262 2 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
263 :
264 2 : switch (prop_id) {
265 1 : case PROP_CALLER:
266 1 : g_return_if_fail (!self->pv->caller);
267 1 : self->pv->caller = g_value_dup_string (value);
268 1 : break;
269 1 : case PROP_SERVICE:
270 1 : g_return_if_fail (!self->pv->service);
271 1 : self->pv->service = g_value_get_object (value);
272 1 : g_return_if_fail (self->pv->service);
273 1 : g_object_add_weak_pointer (G_OBJECT (self->pv->service),
274 1 : (gpointer*)&(self->pv->service));
275 1 : break;
276 0 : default:
277 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
278 0 : break;
279 : }
280 : }
281 :
282 : static void
283 2 : gkd_secret_prompt_get_property (GObject *obj, guint prop_id, GValue *value,
284 : GParamSpec *pspec)
285 : {
286 2 : GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
287 :
288 2 : switch (prop_id) {
289 0 : case PROP_CALLER:
290 0 : g_value_set_string (value, gkd_secret_prompt_get_caller (self));
291 0 : break;
292 2 : case PROP_OBJECT_PATH:
293 2 : g_value_set_pointer (value, self->pv->object_path);
294 2 : break;
295 0 : case PROP_SERVICE:
296 0 : g_value_set_object (value, self->pv->service);
297 0 : break;
298 0 : default:
299 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
300 0 : break;
301 : }
302 2 : }
303 :
304 : static void
305 1 : gkd_secret_prompt_class_init (GkdSecretPromptClass *klass)
306 : {
307 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
308 :
309 1 : gobject_class->constructed = gkd_secret_prompt_constructed;
310 1 : gobject_class->dispose = gkd_secret_prompt_dispose;
311 1 : gobject_class->finalize = gkd_secret_prompt_finalize;
312 1 : gobject_class->set_property = gkd_secret_prompt_set_property;
313 1 : gobject_class->get_property = gkd_secret_prompt_get_property;
314 :
315 1 : klass->encode_result = gkd_secret_prompt_real_encode_result;
316 1 : klass->prompt_ready = gkd_secret_prompt_real_prompt_ready;
317 :
318 1 : g_object_class_install_property (gobject_class, PROP_CALLER,
319 : g_param_spec_string ("caller", "Caller", "DBus caller name",
320 : NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
321 :
322 1 : g_object_class_install_property (gobject_class, PROP_OBJECT_PATH,
323 : g_param_spec_pointer ("object-path", "Object Path", "DBus Object Path",
324 : G_PARAM_READABLE));
325 :
326 1 : g_object_class_install_property (gobject_class, PROP_SERVICE,
327 : g_param_spec_object ("service", "Service", "Service which owns this prompt",
328 : GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
329 1 : }
330 :
331 : static void
332 1 : gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface)
333 : {
334 1 : }
335 :
336 : /* -----------------------------------------------------------------------------
337 : * PUBLIC
338 : */
339 :
340 : const gchar*
341 0 : gkd_secret_prompt_get_caller (GkdSecretPrompt *self)
342 : {
343 0 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
344 0 : return self->pv->caller;
345 : }
346 :
347 : const gchar*
348 0 : gkd_secret_prompt_get_window_id (GkdSecretPrompt *self)
349 : {
350 0 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
351 0 : return self->pv->window_id;
352 : }
353 :
354 : GckSession*
355 0 : gkd_secret_prompt_get_pkcs11_session (GkdSecretPrompt *self)
356 : {
357 0 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
358 0 : g_return_val_if_fail (self->pv->service, NULL);
359 0 : return gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
360 : }
361 :
362 : GkdSecretService*
363 1 : gkd_secret_prompt_get_service (GkdSecretPrompt *self)
364 : {
365 1 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
366 1 : g_return_val_if_fail (self->pv->service, NULL);
367 1 : return self->pv->service;
368 : }
369 :
370 : GkdSecretObjects*
371 0 : gkd_secret_prompt_get_objects (GkdSecretPrompt *self)
372 : {
373 0 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
374 0 : g_return_val_if_fail (self->pv->service, NULL);
375 0 : return gkd_secret_service_get_objects (self->pv->service);
376 : }
377 :
378 : void
379 1 : gkd_secret_prompt_complete (GkdSecretPrompt *self)
380 : {
381 1 : g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
382 1 : g_return_if_fail (!self->pv->completed);
383 1 : self->pv->completed = TRUE;
384 1 : emit_completed (self, FALSE);
385 :
386 : /* Make this object go away */
387 1 : g_object_run_dispose (G_OBJECT (self));
388 : }
389 :
390 : void
391 0 : gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
392 : {
393 0 : g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
394 0 : g_return_if_fail (!self->pv->completed);
395 0 : self->pv->completed = TRUE;
396 0 : emit_completed (self, TRUE);
397 :
398 : /* Make this object go away */
399 0 : g_object_run_dispose (G_OBJECT (self));
400 : }
401 :
402 : void
403 0 : gkd_secret_prompt_dismiss_with_error (GkdSecretPrompt *self,
404 : GError *error)
405 : {
406 0 : g_warning ("prompting failed: %s", egg_error_message (error));
407 0 : gkd_secret_prompt_dismiss (self);
408 0 : }
409 :
410 : GckObject*
411 0 : gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
412 : {
413 : GkdSecretObjects *objects;
414 :
415 0 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
416 0 : g_return_val_if_fail (path, NULL);
417 :
418 0 : objects = gkd_secret_prompt_get_objects (GKD_SECRET_PROMPT (self));
419 0 : return gkd_secret_objects_lookup_collection (objects, self->pv->caller, path);
420 : }
421 :
422 : GkdSecretSecret *
423 1 : gkd_secret_prompt_take_secret (GkdSecretPrompt *self)
424 : {
425 1 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
426 :
427 : /* ... instead it stashes away the raw cipher text, and makes it available here */
428 1 : return gkd_secret_exchange_take_last_secret (self->pv->exchange);
429 : }
430 :
431 : GCancellable *
432 1 : gkd_secret_prompt_get_cancellable (GkdSecretPrompt *self)
433 : {
434 1 : g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
435 1 : return self->pv->cancellable;
436 : }
|