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-secret-change.h"
24 : #include "gkd-secret-create.h"
25 : #include "gkd-secret-dispatch.h"
26 : #include "gkd-secret-error.h"
27 : #include "gkd-secret-lock.h"
28 : #include "gkd-secret-objects.h"
29 : #include "gkd-secret-portal.h"
30 : #include "gkd-secret-prompt.h"
31 : #include "gkd-secret-property.h"
32 : #include "gkd-secret-secret.h"
33 : #include "gkd-secret-service.h"
34 : #include "gkd-secret-session.h"
35 : #include "gkd-secret-types.h"
36 : #include "gkd-secret-unlock.h"
37 : #include "gkd-secret-util.h"
38 :
39 : #include "gkd-internal-generated.h"
40 : #include "gkd-secrets-generated.h"
41 :
42 : #include "egg/egg-error.h"
43 : #include "egg/egg-unix-credentials.h"
44 :
45 : #include <gck/gck.h>
46 : #include <gcrypt.h>
47 :
48 : #include "pkcs11/pkcs11i.h"
49 :
50 : #include <string.h>
51 :
52 : /* -----------------------------------------------------------------------------
53 : * SKELETON
54 : */
55 : typedef struct {
56 : GkdExportedServiceSkeleton parent;
57 : GkdSecretService *service;
58 : } GkdSecretServiceSkeleton;
59 : typedef struct {
60 : GkdExportedServiceSkeletonClass parent_class;
61 : } GkdSecretServiceSkeletonClass;
62 :
63 : GType gkd_secret_service_skeleton_get_type (void);
64 75 : G_DEFINE_TYPE (GkdSecretServiceSkeleton, gkd_secret_service_skeleton, GKD_TYPE_EXPORTED_SERVICE_SKELETON)
65 :
66 : enum {
67 : PROP_COLLECTIONS = 1
68 : };
69 :
70 : static void
71 0 : gkd_secret_service_skeleton_get_property (GObject *object,
72 : guint prop_id,
73 : GValue *value,
74 : GParamSpec *pspec)
75 : {
76 0 : GkdSecretServiceSkeleton *skeleton = (GkdSecretServiceSkeleton *) object;
77 :
78 0 : switch (prop_id) {
79 0 : case PROP_COLLECTIONS:
80 0 : g_value_take_boxed (value, gkd_secret_service_get_collections (skeleton->service));
81 0 : break;
82 0 : default:
83 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
84 0 : break;
85 : }
86 0 : }
87 :
88 : static void
89 3 : gkd_secret_service_skeleton_set_property (GObject *object,
90 : guint prop_id,
91 : const GValue *value,
92 : GParamSpec *pspec)
93 : {
94 3 : G_OBJECT_CLASS (gkd_secret_service_skeleton_parent_class)->set_property (object, prop_id, value, pspec);
95 3 : }
96 :
97 : static void
98 25 : gkd_secret_service_skeleton_class_init (GkdSecretServiceSkeletonClass *klass)
99 : {
100 25 : GObjectClass *oclass = G_OBJECT_CLASS (klass);
101 25 : oclass->get_property = gkd_secret_service_skeleton_get_property;
102 25 : oclass->set_property = gkd_secret_service_skeleton_set_property;
103 25 : gkd_exported_service_override_properties (oclass, PROP_COLLECTIONS);
104 25 : }
105 :
106 : static void
107 25 : gkd_secret_service_skeleton_init (GkdSecretServiceSkeleton *self)
108 : {
109 25 : }
110 :
111 : static GkdExportedService *
112 25 : gkd_secret_service_skeleton_new (GkdSecretService *service)
113 : {
114 25 : GkdExportedService *skeleton = g_object_new (gkd_secret_service_skeleton_get_type (), NULL);
115 25 : ((GkdSecretServiceSkeleton *) skeleton)->service = service;
116 25 : return skeleton;
117 : }
118 :
119 : enum {
120 : PROP_0,
121 : PROP_CONNECTION,
122 : PROP_PKCS11_SLOT,
123 : };
124 :
125 : struct _GkdSecretService {
126 : GObject parent;
127 :
128 : GDBusConnection *connection;
129 : GkdExportedService *skeleton;
130 : GkdExportedInternal *internal_skeleton;
131 : GkdSecretPortal *portal;
132 : guint name_owner_id;
133 : guint filter_id;
134 :
135 : GHashTable *clients;
136 : GkdSecretObjects *objects;
137 : GHashTable *aliases;
138 : GckSession *internal_session;
139 : gchar *default_path;
140 : };
141 :
142 : typedef struct _ServiceClient {
143 : gchar *caller_peer;
144 : CK_G_APPLICATION app;
145 : GckSession *pkcs11_session;
146 : GHashTable *dispatch;
147 : } ServiceClient;
148 :
149 765 : G_DEFINE_TYPE (GkdSecretService, gkd_secret_service, G_TYPE_OBJECT);
150 :
151 : /* -----------------------------------------------------------------------------
152 : * INTERNAL
153 : */
154 :
155 : static gchar*
156 25 : get_default_path (void)
157 : {
158 : gchar *old_directory;
159 : gchar *new_directory;
160 25 : gchar *alias_directory = NULL;
161 :
162 : #if WITH_DEBUG
163 25 : const gchar *path = g_getenv ("GNOME_KEYRING_TEST_PATH");
164 25 : if (path && path[0]) {
165 25 : alias_directory = g_strdup (path);
166 25 : g_debug ("Alias directory was overridden by tests: %s", path);
167 : }
168 : #endif
169 :
170 25 : if (alias_directory == NULL) {
171 0 : new_directory = g_build_filename (g_get_user_data_dir (), "keyrings", NULL);
172 0 : old_directory = g_build_filename (g_get_home_dir (), ".gnome2", "keyrings", NULL);
173 :
174 0 : if (!g_file_test (new_directory, G_FILE_TEST_IS_DIR) &&
175 0 : g_file_test (old_directory, G_FILE_TEST_IS_DIR)) {
176 0 : alias_directory = old_directory;
177 0 : old_directory = NULL;
178 : } else {
179 0 : alias_directory = new_directory;
180 0 : new_directory = NULL;
181 : }
182 :
183 0 : g_free (old_directory);
184 0 : g_free (new_directory);
185 0 : g_debug ("keyring alias directory: %s", alias_directory);
186 : }
187 :
188 25 : return g_build_filename (alias_directory, "default", NULL);
189 : }
190 :
191 : static void
192 69 : update_default (GkdSecretService *self)
193 : {
194 69 : gchar *contents = NULL;
195 :
196 69 : if (g_file_get_contents (self->default_path, &contents, NULL, NULL)) {
197 0 : g_strstrip (contents);
198 0 : if (!contents[0]) {
199 0 : g_free (contents);
200 0 : contents = NULL;
201 : }
202 : }
203 :
204 : /* Default to to 'login' if no default keyring */
205 69 : if (contents == NULL)
206 69 : contents = g_strdup ("login");
207 138 : g_hash_table_replace (self->aliases, g_strdup ("default"), contents);
208 69 : }
209 :
210 : static void
211 0 : store_default (GkdSecretService *self)
212 : {
213 0 : GError *error = NULL;
214 : const gchar *identifier;
215 :
216 0 : identifier = g_hash_table_lookup (self->aliases, "default");
217 0 : if (!identifier)
218 0 : return;
219 :
220 0 : if (!g_file_set_contents (self->default_path, identifier, -1, &error))
221 0 : g_message ("couldn't store default keyring: %s", egg_error_message (error));
222 : }
223 :
224 : static gboolean
225 0 : object_path_has_prefix (const gchar *path, const gchar *prefix)
226 : {
227 : gsize len;
228 :
229 0 : g_assert (prefix);
230 :
231 0 : if (!path)
232 0 : return FALSE;
233 :
234 0 : len = strlen (prefix);
235 0 : return g_ascii_strncasecmp (path, prefix, len) == 0 &&
236 0 : (path[len] == '\0' || path[len] == '/');
237 : }
238 :
239 : static void
240 43 : dispose_and_unref (gpointer object)
241 : {
242 43 : g_return_if_fail (G_IS_OBJECT (object));
243 43 : g_object_run_dispose (G_OBJECT (object));
244 43 : g_object_unref (object);
245 : }
246 :
247 : static void
248 44 : free_client (gpointer data)
249 : {
250 44 : ServiceClient *client = data;
251 :
252 44 : if (!client)
253 0 : return;
254 :
255 : /* Info about our client */
256 44 : g_free (client->caller_peer);
257 :
258 : /* The session we use for accessing as our client */
259 44 : if (client->pkcs11_session) {
260 : #if 0
261 : gck_session_close (client->pkcs11_session, NULL);
262 : #endif
263 16 : g_object_unref (client->pkcs11_session);
264 : }
265 :
266 : /* The sessions and prompts the client has open */
267 44 : g_hash_table_destroy (client->dispatch);
268 :
269 44 : g_free (client);
270 : }
271 :
272 : static void
273 44 : initialize_service_client (GkdSecretService *self,
274 : const gchar *caller)
275 : {
276 : ServiceClient *client;
277 :
278 44 : g_assert (GKD_SECRET_IS_SERVICE (self));
279 44 : g_assert (caller);
280 :
281 : /* Initialize the client object */
282 44 : client = g_new0 (ServiceClient, 1);
283 44 : client->caller_peer = g_strdup (caller);
284 44 : client->app.applicationData = client;
285 44 : client->dispatch = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref);
286 :
287 44 : g_hash_table_replace (self->clients, client->caller_peer, client);
288 :
289 : /* Update default collection each time someone connects */
290 44 : update_default (self);
291 44 : }
292 :
293 : static void
294 245 : gkd_secret_service_ensure_client (GkdSecretService *self,
295 : const gchar *caller)
296 : {
297 : ServiceClient *client;
298 :
299 245 : client = g_hash_table_lookup (self->clients, caller);
300 245 : if (client == NULL) {
301 44 : initialize_service_client (self, caller);
302 : }
303 245 : }
304 :
305 : typedef struct {
306 : GkdSecretService *service;
307 : GDBusMessage *message;
308 : } MessageFilterData;
309 :
310 : static gboolean
311 245 : ensure_client_for_sender (gpointer user_data)
312 : {
313 245 : MessageFilterData *data = user_data;
314 : const gchar *sender;
315 :
316 : /* Ensure clients for our incoming connections */
317 245 : sender = g_dbus_message_get_sender (data->message);
318 245 : gkd_secret_service_ensure_client (data->service, sender);
319 :
320 245 : g_clear_object (&data->service);
321 245 : g_clear_object (&data->message);
322 245 : g_slice_free (MessageFilterData, data);
323 :
324 245 : return FALSE;
325 : }
326 :
327 : static GDBusMessage *
328 245 : rewrite_default_alias (GkdSecretService *self,
329 : GDBusMessage *message)
330 : {
331 245 : const char *path = g_dbus_message_get_path (message);
332 : const char *replace;
333 245 : char *collection = NULL, *item = NULL;
334 : char *collection_path, *item_path;
335 : GDBusMessage *rewritten;
336 245 : GError *error = NULL;
337 :
338 245 : if (path == NULL)
339 73 : return message;
340 :
341 172 : if (!g_str_has_prefix (path, SECRET_ALIAS_PREFIX))
342 172 : return message;
343 :
344 0 : if (!gkd_secret_util_parse_path (path, &collection, &item))
345 0 : return message;
346 :
347 0 : replace = gkd_secret_service_get_alias (self, collection);
348 0 : if (!replace) {
349 0 : g_free (item);
350 0 : g_free (collection);
351 0 : return message;
352 : }
353 :
354 0 : rewritten = g_dbus_message_copy (message, &error);
355 0 : if (error != NULL) {
356 0 : g_error_free (error);
357 0 : return message;
358 : }
359 :
360 0 : collection_path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX,
361 : replace, -1);
362 :
363 0 : if (item != NULL) {
364 0 : item_path = gkd_secret_util_build_path (collection_path,
365 : item, -1);
366 0 : g_dbus_message_set_path (rewritten, item_path);
367 0 : g_free (item_path);
368 : } else {
369 0 : g_dbus_message_set_path (rewritten, collection_path);
370 : }
371 :
372 0 : g_free (collection_path);
373 0 : g_free (item);
374 0 : g_free (collection);
375 0 : g_object_unref (message);
376 :
377 0 : return rewritten;
378 : }
379 :
380 : static GDBusMessage *
381 454 : service_message_filter (GDBusConnection *connection,
382 : GDBusMessage *message,
383 : gboolean incoming,
384 : gpointer user_data)
385 : {
386 454 : GkdSecretService *self = user_data;
387 : MessageFilterData *data;
388 : GDBusMessage *filtered;
389 :
390 454 : if (!incoming)
391 209 : return message;
392 :
393 245 : filtered = rewrite_default_alias (self, message);
394 :
395 245 : data = g_slice_new0 (MessageFilterData);
396 245 : data->service = g_object_ref (self);
397 245 : data->message = g_object_ref (filtered);
398 :
399 : /* We use G_PRIORITY_HIGH to make sure this timeout is
400 : * scheduled before the actual method call.
401 : */
402 245 : g_idle_add_full (G_PRIORITY_HIGH, ensure_client_for_sender,
403 : data, NULL);
404 :
405 245 : return filtered;
406 : }
407 :
408 : /* -----------------------------------------------------------------------------
409 : * DBUS
410 : */
411 :
412 : static gboolean
413 16 : service_method_open_session (GkdExportedService *skeleton,
414 : GDBusMethodInvocation *invocation,
415 : gchar *algorithm,
416 : GVariant *input,
417 : GkdSecretService *self)
418 : {
419 : GkdSecretSession *session;
420 16 : GVariant *output = NULL;
421 16 : gchar *result = NULL;
422 16 : GError *error = NULL;
423 : const gchar *caller;
424 : GVariant *input_payload;
425 :
426 16 : caller = g_dbus_method_invocation_get_sender (invocation);
427 :
428 : /* Now we can create a session with this information */
429 16 : session = gkd_secret_session_new (self, caller);
430 16 : input_payload = g_variant_get_variant (input);
431 16 : gkd_secret_session_handle_open (session, algorithm, input_payload,
432 : &output, &result,
433 : &error);
434 16 : g_variant_unref (input_payload);
435 :
436 16 : if (error != NULL) {
437 0 : g_dbus_method_invocation_take_error (invocation, error);
438 : } else {
439 16 : gkd_secret_service_publish_dispatch (self, caller,
440 16 : GKD_SECRET_DISPATCH (session));
441 16 : gkd_exported_service_complete_open_session (skeleton, invocation, output, result);
442 16 : g_free (result);
443 : }
444 :
445 16 : g_object_unref (session);
446 16 : return TRUE;
447 : }
448 :
449 : static gboolean
450 1 : service_method_search_items (GkdExportedService *skeleton,
451 : GDBusMethodInvocation *invocation,
452 : GVariant *attributes,
453 : GkdSecretService *self)
454 : {
455 1 : return gkd_secret_objects_handle_search_items (self->objects, invocation,
456 : attributes, NULL, TRUE);
457 : }
458 :
459 : static gboolean
460 0 : service_method_get_secrets (GkdExportedService *skeleton,
461 : GDBusMethodInvocation *invocation,
462 : gchar **items,
463 : gchar *session,
464 : GkdSecretService *self)
465 : {
466 0 : return gkd_secret_objects_handle_get_secrets (self->objects, invocation,
467 : (const gchar **) items, session);
468 : }
469 :
470 : static gboolean
471 1 : service_method_create_collection (GkdExportedService *skeleton,
472 : GDBusMethodInvocation *invocation,
473 : GVariant *properties,
474 : gchar *alias,
475 : GkdSecretService *self)
476 : {
477 1 : GckBuilder builder = GCK_BUILDER_INIT;
478 : GckAttributes *attrs;
479 : GkdSecretCreate *create;
480 : const gchar *path;
481 : const char *caller;
482 :
483 1 : if (!gkd_secret_property_parse_all (properties, SECRET_COLLECTION_INTERFACE, &builder)) {
484 0 : gck_builder_clear (&builder);
485 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
486 : G_DBUS_ERROR_INVALID_ARGS,
487 : "Invalid properties");
488 0 : return TRUE;
489 : }
490 :
491 : /* Empty alias is no alias */
492 1 : if (alias) {
493 1 : if (!alias[0]) {
494 1 : alias = NULL;
495 0 : } else if (!g_str_equal (alias, "default")) {
496 0 : gck_builder_clear (&builder);
497 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
498 : G_DBUS_ERROR_NOT_SUPPORTED,
499 : "Only the 'default' alias is supported");
500 0 : return TRUE;
501 : }
502 : }
503 :
504 1 : gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
505 1 : attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
506 :
507 : /* Create the prompt object, for the password */
508 1 : caller = g_dbus_method_invocation_get_sender (invocation);
509 1 : create = gkd_secret_create_new (self, caller, attrs, alias);
510 1 : gck_attributes_unref (attrs);
511 :
512 1 : path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
513 1 : gkd_secret_service_publish_dispatch (self, caller,
514 1 : GKD_SECRET_DISPATCH (create));
515 :
516 1 : gkd_exported_service_complete_create_collection (skeleton, invocation,
517 : "/", path);
518 1 : return TRUE;
519 : }
520 :
521 : static gboolean
522 1 : service_method_lock_service (GkdExportedService *skeleton,
523 : GDBusMethodInvocation *invocation,
524 : GkdSecretService *self)
525 : {
526 1 : GError *error = NULL;
527 : GckSession *session;
528 : const char *caller;
529 :
530 1 : caller = g_dbus_method_invocation_get_sender (invocation);
531 1 : session = gkd_secret_service_get_pkcs11_session (self, caller);
532 1 : g_return_val_if_fail (session != NULL, FALSE);
533 :
534 1 : if (!gkd_secret_lock_all (session, &error))
535 0 : g_dbus_method_invocation_take_error (invocation, error);
536 : else
537 1 : gkd_exported_service_complete_lock_service (skeleton, invocation);
538 :
539 1 : return TRUE;
540 : }
541 :
542 : static gboolean
543 1 : service_method_unlock (GkdExportedService *skeleton,
544 : GDBusMethodInvocation *invocation,
545 : gchar **objpaths,
546 : GkdSecretService *self)
547 : {
548 : GkdSecretUnlock *unlock;
549 : const char *caller;
550 : const gchar *path;
551 : int i, n_unlocked;
552 : gchar **unlocked;
553 :
554 1 : caller = g_dbus_method_invocation_get_sender (invocation);
555 1 : unlock = gkd_secret_unlock_new (self, caller, NULL);
556 2 : for (i = 0; objpaths[i] != NULL; ++i)
557 1 : gkd_secret_unlock_queue (unlock, objpaths[i]);
558 :
559 : /* So do we need to prompt? */
560 1 : if (gkd_secret_unlock_have_queued (unlock)) {
561 1 : gkd_secret_service_publish_dispatch (self, caller,
562 1 : GKD_SECRET_DISPATCH (unlock));
563 1 : path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (unlock));
564 :
565 : /* No need to prompt */
566 : } else {
567 0 : path = "/";
568 : }
569 :
570 1 : unlocked = gkd_secret_unlock_get_results (unlock, &n_unlocked);
571 1 : gkd_exported_service_complete_unlock (skeleton, invocation,
572 : (const gchar **) unlocked, path);
573 :
574 1 : gkd_secret_unlock_reset_results (unlock);
575 1 : g_object_unref (unlock);
576 :
577 1 : return TRUE;
578 : }
579 :
580 : static gboolean
581 4 : service_method_lock (GkdExportedService *skeleton,
582 : GDBusMethodInvocation *invocation,
583 : gchar **objpaths,
584 : GkdSecretService *self)
585 : {
586 : const char *caller;
587 : GckObject *collection;
588 : int i;
589 : char **locked;
590 : GPtrArray *array;
591 :
592 4 : caller = g_dbus_method_invocation_get_sender (invocation);
593 4 : array = g_ptr_array_new ();
594 8 : for (i = 0; objpaths[i] != NULL; ++i) {
595 4 : collection = gkd_secret_objects_lookup_collection (self->objects, caller, objpaths[i]);
596 4 : if (collection != NULL) {
597 4 : if (gkd_secret_lock (collection, NULL)) {
598 4 : g_ptr_array_add (array, objpaths[i]);
599 4 : gkd_secret_objects_emit_collection_locked (self->objects,
600 : collection);
601 : }
602 4 : g_object_unref (collection);
603 : }
604 : }
605 :
606 4 : g_ptr_array_add (array, NULL);
607 :
608 4 : locked = (gchar **) g_ptr_array_free (array, FALSE);
609 4 : gkd_exported_service_complete_lock (skeleton, invocation,
610 : (const gchar **) locked, "/");
611 :
612 4 : return TRUE;
613 : }
614 :
615 : static gboolean
616 0 : method_change_lock_internal (GkdSecretService *self,
617 : GDBusMethodInvocation *invocation,
618 : const gchar *collection_path)
619 : {
620 : GkdSecretChange *change;
621 : const char *caller;
622 : const gchar *path;
623 : GckObject *collection;
624 :
625 0 : caller = g_dbus_method_invocation_get_sender (invocation);
626 :
627 : /* Make sure it exists */
628 0 : collection = gkd_secret_objects_lookup_collection (self->objects, caller, collection_path);
629 0 : if (!collection) {
630 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
631 : GKD_SECRET_ERROR_NO_SUCH_OBJECT,
632 : "The collection does not exist");
633 0 : return TRUE;
634 : }
635 :
636 0 : g_object_unref (collection);
637 :
638 0 : change = gkd_secret_change_new (self, caller, collection_path);
639 0 : path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (change));
640 0 : gkd_secret_service_publish_dispatch (self, caller,
641 0 : GKD_SECRET_DISPATCH (change));
642 :
643 0 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
644 0 : g_object_unref (change);
645 :
646 0 : return TRUE;
647 : }
648 :
649 : static gboolean
650 0 : service_method_change_lock (GkdExportedService *skeleton,
651 : GDBusMethodInvocation *invocation,
652 : gchar *collection_path,
653 : GkdSecretService *self)
654 : {
655 0 : return method_change_lock_internal (self, invocation, collection_path);
656 : }
657 :
658 : static gboolean
659 0 : service_method_change_with_prompt (GkdExportedInternal *skeleton,
660 : GDBusMethodInvocation *invocation,
661 : gchar *collection_path,
662 : GkdSecretService *self)
663 : {
664 0 : return method_change_lock_internal (self, invocation, collection_path);
665 : }
666 :
667 : static gboolean
668 0 : service_method_read_alias (GkdExportedService *skeleton,
669 : GDBusMethodInvocation *invocation,
670 : gchar *alias,
671 : GkdSecretService *self)
672 : {
673 0 : gchar *path = NULL;
674 : const gchar *identifier;
675 0 : GckObject *collection = NULL;
676 :
677 0 : identifier = gkd_secret_service_get_alias (self, alias);
678 0 : if (identifier)
679 0 : path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, -1);
680 :
681 : /* Make sure it actually exists */
682 0 : if (path)
683 0 : collection = gkd_secret_objects_lookup_collection (self->objects,
684 : g_dbus_method_invocation_get_sender (invocation),
685 : path);
686 0 : if (collection == NULL) {
687 0 : g_free (path);
688 0 : path = NULL;
689 : } else {
690 0 : g_object_unref (collection);
691 : }
692 :
693 0 : if (path == NULL)
694 0 : path = g_strdup ("/");
695 :
696 0 : gkd_exported_service_complete_read_alias (skeleton, invocation, path);
697 0 : g_free (path);
698 :
699 0 : return TRUE;
700 : }
701 :
702 : static gboolean
703 0 : service_method_set_alias (GkdExportedService *skeleton,
704 : GDBusMethodInvocation *invocation,
705 : gchar *alias,
706 : gchar *path,
707 : GkdSecretService *self)
708 : {
709 : GckObject *collection;
710 : gchar *identifier;
711 :
712 0 : if (!g_str_equal (alias, "default")) {
713 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
714 : G_DBUS_ERROR_NOT_SUPPORTED,
715 : "Only the 'default' alias is supported");
716 0 : return TRUE;
717 : }
718 :
719 : /* No default collection */
720 0 : if (g_str_equal (path, "/")) {
721 0 : identifier = g_strdup ("");
722 :
723 : /* Find a collection with that path */
724 : } else {
725 0 : if (!object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) ||
726 0 : !gkd_secret_util_parse_path (path, &identifier, NULL)) {
727 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
728 : G_DBUS_ERROR_INVALID_ARGS,
729 : "Invalid collection object path");
730 0 : return TRUE;
731 : }
732 :
733 0 : collection = gkd_secret_objects_lookup_collection (self->objects,
734 : g_dbus_method_invocation_get_sender (invocation),
735 : path);
736 0 : if (collection == NULL) {
737 0 : g_free (identifier);
738 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
739 : GKD_SECRET_ERROR_NO_SUCH_OBJECT,
740 : "The collection does not exist");
741 0 : return TRUE;
742 : }
743 :
744 0 : g_object_unref (collection);
745 : }
746 :
747 0 : gkd_secret_service_set_alias (self, alias, identifier);
748 0 : g_free (identifier);
749 :
750 0 : gkd_exported_service_complete_set_alias (skeleton, invocation);
751 :
752 0 : return TRUE;
753 : }
754 :
755 : static gboolean
756 1 : service_method_create_with_master_password (GkdExportedInternal *skeleton,
757 : GDBusMethodInvocation *invocation,
758 : GVariant *attributes,
759 : GVariant *master,
760 : GkdSecretService *self)
761 : {
762 1 : GckBuilder builder = GCK_BUILDER_INIT;
763 1 : GkdSecretSecret *secret = NULL;
764 1 : GckAttributes *attrs = NULL;
765 1 : GError *error = NULL;
766 : gchar *path;
767 : const gchar *caller;
768 :
769 1 : if (!gkd_secret_property_parse_all (attributes, SECRET_COLLECTION_INTERFACE, &builder)) {
770 0 : gck_builder_clear (&builder);
771 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
772 : G_DBUS_ERROR_INVALID_ARGS,
773 : "Invalid properties argument");
774 0 : return TRUE;
775 : }
776 :
777 1 : caller = g_dbus_method_invocation_get_sender (invocation);
778 1 : secret = gkd_secret_secret_parse (self,
779 : caller,
780 : master, &error);
781 1 : if (secret == NULL) {
782 0 : gck_builder_clear (&builder);
783 0 : g_dbus_method_invocation_take_error (invocation, error);
784 0 : return TRUE;
785 : }
786 :
787 1 : gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
788 1 : attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
789 1 : path = gkd_secret_create_with_secret (attrs, secret, &error);
790 1 : gck_attributes_unref (attrs);
791 1 : gkd_secret_secret_free (secret);
792 :
793 1 : if (path == NULL) {
794 0 : gkd_secret_propagate_error (invocation, "Couldn't create collection", error);
795 0 : return TRUE;
796 : }
797 :
798 : /* Notify the callers that a collection was created */
799 1 : g_message ("emit collection_Created");
800 1 : gkd_secret_service_emit_collection_created (self, path);
801 :
802 1 : gkd_exported_internal_complete_create_with_master_password
803 : (skeleton, invocation, path);
804 1 : g_free (path);
805 :
806 1 : return TRUE;
807 : }
808 :
809 : static gboolean
810 0 : service_method_change_with_master_password (GkdExportedInternal *skeleton,
811 : GDBusMethodInvocation *invocation,
812 : gchar *path,
813 : GVariant *original_variant,
814 : GVariant *master_variant,
815 : GkdSecretService *self)
816 : {
817 : GkdSecretSecret *original, *master;
818 : GckObject *collection;
819 0 : GError *error = NULL;
820 : const gchar *sender;
821 :
822 0 : sender = g_dbus_method_invocation_get_sender (invocation);
823 :
824 : /* Parse the incoming message */
825 0 : original = gkd_secret_secret_parse (self, sender,
826 : original_variant, &error);
827 0 : if (original == NULL) {
828 0 : g_dbus_method_invocation_take_error (invocation, error);
829 0 : return TRUE;
830 : }
831 :
832 0 : master = gkd_secret_secret_parse (self, sender,
833 : master_variant, &error);
834 0 : if (master == NULL) {
835 0 : g_dbus_method_invocation_take_error (invocation, error);
836 0 : return TRUE;
837 : }
838 :
839 : /* Make sure we have such a collection */
840 0 : collection = gkd_secret_objects_lookup_collection (self->objects, sender,
841 : path);
842 :
843 : /* No such collection */
844 0 : if (collection == NULL) {
845 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
846 : GKD_SECRET_ERROR_NO_SUCH_OBJECT,
847 : "The collection does not exist");
848 : }
849 :
850 : /* Success */
851 0 : else if (gkd_secret_change_with_secrets (collection, NULL, original, master, &error))
852 0 : gkd_exported_internal_complete_change_with_master_password
853 : (skeleton, invocation);
854 :
855 : /* Failure */
856 : else
857 0 : gkd_secret_propagate_error (invocation, "Couldn't change collection password", error);
858 :
859 0 : gkd_secret_secret_free (original);
860 0 : gkd_secret_secret_free (master);
861 :
862 0 : if (collection)
863 0 : g_object_unref (collection);
864 :
865 0 : return TRUE;
866 : }
867 :
868 : static gboolean
869 15 : service_method_unlock_with_master_password (GkdExportedInternal *skeleton,
870 : GDBusMethodInvocation *invocation,
871 : gchar *path,
872 : GVariant *master_variant,
873 : GkdSecretService *self)
874 : {
875 : GkdSecretSecret *master;
876 15 : GError *error = NULL;
877 : GckObject *collection;
878 : const gchar *sender;
879 :
880 15 : sender = g_dbus_method_invocation_get_sender (invocation);
881 :
882 : /* Parse the incoming message */
883 15 : master = gkd_secret_secret_parse (self, sender, master_variant, &error);
884 15 : if (master == NULL) {
885 0 : g_dbus_method_invocation_take_error (invocation, error);
886 0 : return TRUE;
887 : }
888 :
889 : /* Make sure we have such a collection */
890 15 : collection = gkd_secret_objects_lookup_collection (self->objects, sender, path);
891 :
892 : /* No such collection */
893 15 : if (collection == NULL) {
894 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
895 : GKD_SECRET_ERROR_NO_SUCH_OBJECT,
896 : "The collection does not exist");
897 :
898 : /* Success */
899 15 : } else if (gkd_secret_unlock_with_secret (collection, master, &error)) {
900 15 : gkd_secret_objects_emit_collection_locked (self->objects, collection);
901 15 : gkd_exported_internal_complete_unlock_with_master_password
902 : (skeleton, invocation);
903 :
904 : /* Failure */
905 : } else {
906 0 : gkd_secret_propagate_error (invocation, "Couldn't unlock collection", error);
907 : }
908 :
909 15 : gkd_secret_secret_free (master);
910 :
911 15 : if (collection)
912 15 : g_object_unref (collection);
913 :
914 15 : return TRUE;
915 : }
916 :
917 : static void
918 99 : service_name_owner_changed (GDBusConnection *connection,
919 : const gchar *sender_name,
920 : const gchar *object_path,
921 : const gchar *interface_name,
922 : const gchar *signal_name,
923 : GVariant *parameters,
924 : gpointer user_data)
925 : {
926 : const gchar *object_name;
927 : const gchar *old_owner;
928 : const gchar *new_owner;
929 99 : GkdSecretService *self = user_data;
930 :
931 : /* A peer is connecting or disconnecting from the bus,
932 : * remove any client info, when client gone.
933 : */
934 99 : g_variant_get (parameters, "(&s&s&s)", &object_name, &old_owner, &new_owner);
935 :
936 99 : if (g_str_equal (new_owner, "") && object_name[0] == ':')
937 34 : g_hash_table_remove (self->clients, object_name);
938 99 : }
939 :
940 : /* -----------------------------------------------------------------------------
941 : * OBJECT
942 : */
943 :
944 : static void
945 25 : gkd_secret_service_init_collections (GkdSecretService *self)
946 : {
947 25 : gchar **collections = gkd_secret_service_get_collections (self);
948 : gint idx;
949 :
950 73 : for (idx = 0; collections[idx] != NULL; idx++)
951 48 : gkd_secret_objects_register_collection (self->objects, collections[idx]);
952 :
953 25 : g_strfreev (collections);
954 25 : }
955 :
956 : static void
957 25 : gkd_secret_service_init_aliases (GkdSecretService *self)
958 : {
959 25 : self->aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
960 25 : g_hash_table_insert (self->aliases, g_strdup ("session"), g_strdup ("session"));
961 : /* TODO: We should be using CKA_G_LOGIN_COLLECTION */
962 25 : g_hash_table_insert (self->aliases, g_strdup ("login"), g_strdup ("login"));
963 :
964 25 : update_default (self);
965 25 : }
966 :
967 : static GObject*
968 25 : gkd_secret_service_constructor (GType type,
969 : guint n_props,
970 : GObjectConstructParam *props)
971 : {
972 25 : GkdSecretService *self = GKD_SECRET_SERVICE (G_OBJECT_CLASS (gkd_secret_service_parent_class)->constructor(type, n_props, props));
973 25 : GError *error = NULL;
974 25 : GckSlot *slot = NULL;
975 : guint i;
976 :
977 25 : g_return_val_if_fail (self, NULL);
978 25 : g_return_val_if_fail (self->connection, NULL);
979 :
980 : /* Find the pkcs11-slot parameter */
981 75 : for (i = 0; !slot && i < n_props; ++i) {
982 50 : if (g_str_equal (props[i].pspec->name, "pkcs11-slot"))
983 25 : slot = g_value_get_object (props[i].value);
984 : }
985 :
986 : /* Create our objects proxy */
987 25 : g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
988 25 : self->objects = g_object_new (GKD_SECRET_TYPE_OBJECTS,
989 : "pkcs11-slot", slot, "service", self, NULL);
990 :
991 25 : self->skeleton = gkd_secret_service_skeleton_new (self);
992 25 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
993 : self->connection,
994 : SECRET_SERVICE_PATH, &error);
995 25 : if (error != NULL) {
996 0 : g_warning ("could not register secret service on session bus: %s", error->message);
997 0 : g_clear_error (&error);
998 : }
999 :
1000 25 : g_signal_connect (self->skeleton, "handle-change-lock",
1001 : G_CALLBACK (service_method_change_lock), self);
1002 25 : g_signal_connect (self->skeleton, "handle-create-collection",
1003 : G_CALLBACK (service_method_create_collection), self);
1004 25 : g_signal_connect (self->skeleton, "handle-get-secrets",
1005 : G_CALLBACK (service_method_get_secrets), self);
1006 25 : g_signal_connect (self->skeleton, "handle-lock",
1007 : G_CALLBACK (service_method_lock), self);
1008 25 : g_signal_connect (self->skeleton, "handle-lock-service",
1009 : G_CALLBACK (service_method_lock_service), self);
1010 25 : g_signal_connect (self->skeleton, "handle-open-session",
1011 : G_CALLBACK (service_method_open_session), self);
1012 25 : g_signal_connect (self->skeleton, "handle-read-alias",
1013 : G_CALLBACK (service_method_read_alias), self);
1014 25 : g_signal_connect (self->skeleton, "handle-search-items",
1015 : G_CALLBACK (service_method_search_items), self);
1016 25 : g_signal_connect (self->skeleton, "handle-set-alias",
1017 : G_CALLBACK (service_method_set_alias), self);
1018 25 : g_signal_connect (self->skeleton, "handle-unlock",
1019 : G_CALLBACK (service_method_unlock), self);
1020 :
1021 25 : self->internal_skeleton = gkd_exported_internal_skeleton_new ();
1022 25 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->internal_skeleton),
1023 : self->connection,
1024 : SECRET_SERVICE_PATH, &error);
1025 :
1026 25 : if (error != NULL) {
1027 0 : g_warning ("could not register internal interface service on session bus: %s", error->message);
1028 0 : g_clear_error (&error);
1029 : }
1030 :
1031 25 : g_signal_connect (self->internal_skeleton, "handle-change-with-master-password",
1032 : G_CALLBACK (service_method_change_with_master_password), self);
1033 25 : g_signal_connect (self->internal_skeleton, "handle-change-with-prompt",
1034 : G_CALLBACK (service_method_change_with_prompt), self);
1035 25 : g_signal_connect (self->internal_skeleton, "handle-create-with-master-password",
1036 : G_CALLBACK (service_method_create_with_master_password), self);
1037 25 : g_signal_connect (self->internal_skeleton, "handle-unlock-with-master-password",
1038 : G_CALLBACK (service_method_unlock_with_master_password), self);
1039 :
1040 25 : self->portal = g_object_new (GKD_SECRET_TYPE_PORTAL, "service", self, NULL);
1041 :
1042 25 : self->name_owner_id = g_dbus_connection_signal_subscribe (self->connection,
1043 : NULL,
1044 : "org.freedesktop.DBus",
1045 : "NameOwnerChanged",
1046 : NULL, NULL,
1047 : G_DBUS_SIGNAL_FLAGS_NONE,
1048 : service_name_owner_changed,
1049 : self, NULL);
1050 :
1051 25 : self->filter_id = g_dbus_connection_add_filter (self->connection,
1052 : service_message_filter,
1053 : self, NULL);
1054 :
1055 25 : gkd_secret_service_init_collections (self);
1056 :
1057 25 : return G_OBJECT (self);
1058 : }
1059 :
1060 : static void
1061 25 : gkd_secret_service_init (GkdSecretService *self)
1062 : {
1063 25 : self->clients = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_client);
1064 25 : self->default_path = get_default_path ();
1065 25 : gkd_secret_service_init_aliases (self);
1066 25 : }
1067 :
1068 : static void
1069 25 : gkd_secret_service_dispose (GObject *obj)
1070 : {
1071 25 : GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1072 :
1073 25 : if (self->name_owner_id) {
1074 25 : g_dbus_connection_signal_unsubscribe (self->connection, self->name_owner_id);
1075 25 : self->name_owner_id = 0;
1076 : }
1077 :
1078 25 : if (self->filter_id) {
1079 25 : g_dbus_connection_remove_filter (self->connection, self->filter_id);
1080 25 : self->filter_id = 0;
1081 : }
1082 :
1083 : /* Closes all the clients */
1084 25 : g_hash_table_remove_all (self->clients);
1085 :
1086 : /* Hide all the objects */
1087 25 : if (self->objects) {
1088 25 : g_object_run_dispose (G_OBJECT (self->objects));
1089 25 : g_object_unref (self->objects);
1090 25 : self->objects = NULL;
1091 : }
1092 :
1093 25 : g_clear_object (&self->connection);
1094 :
1095 25 : if (self->internal_session) {
1096 25 : dispose_and_unref (self->internal_session);
1097 25 : self->internal_session = NULL;
1098 : }
1099 :
1100 25 : g_clear_object (&self->portal);
1101 :
1102 25 : G_OBJECT_CLASS (gkd_secret_service_parent_class)->dispose (obj);
1103 25 : }
1104 :
1105 : static void
1106 0 : gkd_secret_service_finalize (GObject *obj)
1107 : {
1108 0 : GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1109 :
1110 0 : g_assert (g_hash_table_size (self->clients) == 0);
1111 0 : g_hash_table_destroy (self->clients);
1112 0 : self->clients = NULL;
1113 :
1114 0 : g_hash_table_destroy (self->aliases);
1115 0 : self->aliases = NULL;
1116 :
1117 0 : g_free (self->default_path);
1118 0 : self->default_path = NULL;
1119 :
1120 0 : G_OBJECT_CLASS (gkd_secret_service_parent_class)->finalize (obj);
1121 0 : }
1122 :
1123 : static void
1124 50 : gkd_secret_service_set_property (GObject *obj, guint prop_id, const GValue *value,
1125 : GParamSpec *pspec)
1126 : {
1127 50 : GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1128 :
1129 50 : switch (prop_id) {
1130 25 : case PROP_CONNECTION:
1131 25 : g_return_if_fail (!self->connection);
1132 25 : self->connection = g_value_dup_object (value);
1133 25 : g_return_if_fail (self->connection);
1134 25 : break;
1135 25 : case PROP_PKCS11_SLOT:
1136 25 : g_return_if_fail (!self->objects);
1137 25 : break;
1138 0 : default:
1139 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1140 0 : break;
1141 : }
1142 : }
1143 :
1144 : static void
1145 0 : gkd_secret_service_get_property (GObject *obj, guint prop_id, GValue *value,
1146 : GParamSpec *pspec)
1147 : {
1148 0 : GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1149 :
1150 0 : switch (prop_id) {
1151 0 : case PROP_CONNECTION:
1152 0 : g_value_set_object (value, gkd_secret_service_get_connection (self));
1153 0 : break;
1154 0 : case PROP_PKCS11_SLOT:
1155 0 : g_value_set_object (value, gkd_secret_service_get_pkcs11_slot (self));
1156 0 : break;
1157 0 : default:
1158 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1159 0 : break;
1160 : }
1161 0 : }
1162 :
1163 : static void
1164 25 : gkd_secret_service_class_init (GkdSecretServiceClass *klass)
1165 : {
1166 25 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1167 :
1168 25 : gobject_class->constructor = gkd_secret_service_constructor;
1169 25 : gobject_class->dispose = gkd_secret_service_dispose;
1170 25 : gobject_class->finalize = gkd_secret_service_finalize;
1171 25 : gobject_class->set_property = gkd_secret_service_set_property;
1172 25 : gobject_class->get_property = gkd_secret_service_get_property;
1173 :
1174 25 : g_object_class_install_property (gobject_class, PROP_CONNECTION,
1175 : g_param_spec_object ("connection", "Connection", "DBus Connection",
1176 : G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1177 :
1178 25 : g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
1179 : g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
1180 : GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1181 25 : }
1182 :
1183 : /* -----------------------------------------------------------------------------
1184 : * PUBLIC
1185 : */
1186 :
1187 : GkdSecretObjects*
1188 3 : gkd_secret_service_get_objects (GkdSecretService *self)
1189 : {
1190 3 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1191 3 : return self->objects;
1192 : }
1193 :
1194 : GDBusConnection*
1195 119 : gkd_secret_service_get_connection (GkdSecretService *self)
1196 : {
1197 119 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1198 119 : return self->connection;
1199 : }
1200 :
1201 : GckSlot*
1202 41 : gkd_secret_service_get_pkcs11_slot (GkdSecretService *self)
1203 : {
1204 41 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1205 41 : return gkd_secret_objects_get_pkcs11_slot (self->objects);
1206 : }
1207 :
1208 : static gboolean
1209 41 : log_into_pkcs11_session (GckSession *session, GError **error)
1210 : {
1211 : GckSessionInfo *sess;
1212 : GckTokenInfo *info;
1213 : GckSlot *slot;
1214 : gboolean login;
1215 :
1216 : /* Perform the necessary 'user' login to secrets token. Doesn't unlock anything */
1217 41 : slot = gck_session_get_slot (session);
1218 41 : info = gck_slot_get_token_info (slot);
1219 41 : login = info && (info->flags & CKF_LOGIN_REQUIRED);
1220 41 : gck_token_info_free (info);
1221 41 : g_object_unref (slot);
1222 :
1223 41 : if (login) {
1224 41 : sess = gck_session_get_info (session);
1225 41 : if (sess->state == CKS_RO_USER_FUNCTIONS ||
1226 41 : sess->state == CKS_RW_USER_FUNCTIONS)
1227 0 : login = FALSE;
1228 41 : gck_session_info_free (sess);
1229 : }
1230 :
1231 41 : if (login && !gck_session_login (session, CKU_USER, NULL, 0, NULL, error))
1232 0 : return FALSE;
1233 :
1234 41 : return TRUE;
1235 : }
1236 :
1237 : GckSession*
1238 78 : gkd_secret_service_get_pkcs11_session (GkdSecretService *self, const gchar *caller)
1239 : {
1240 : ServiceClient *client;
1241 78 : GError *error = NULL;
1242 : GckSlot *slot;
1243 :
1244 78 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1245 78 : g_return_val_if_fail (caller, NULL);
1246 :
1247 78 : client = g_hash_table_lookup (self->clients, caller);
1248 78 : g_return_val_if_fail (client, NULL);
1249 :
1250 : /* Open a new session if necessary */
1251 78 : if (!client->pkcs11_session) {
1252 16 : slot = gkd_secret_service_get_pkcs11_slot (self);
1253 32 : client->pkcs11_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
1254 16 : CKF_G_APPLICATION_SESSION, &client->app,
1255 : NULL, NULL, &error);
1256 16 : if (!client->pkcs11_session) {
1257 0 : g_warning ("couldn't open pkcs11 session for secret service: %s",
1258 : egg_error_message (error));
1259 0 : g_clear_error (&error);
1260 0 : return NULL;
1261 : }
1262 :
1263 16 : if (!log_into_pkcs11_session (client->pkcs11_session, &error)) {
1264 0 : g_warning ("couldn't log in to pkcs11 session for secret service: %s",
1265 : egg_error_message (error));
1266 0 : g_clear_error (&error);
1267 0 : g_object_unref (client->pkcs11_session);
1268 0 : client->pkcs11_session = NULL;
1269 0 : return NULL;
1270 : }
1271 : }
1272 :
1273 78 : return client->pkcs11_session;
1274 : }
1275 :
1276 : GckSession*
1277 113 : gkd_secret_service_internal_pkcs11_session (GkdSecretService *self)
1278 : {
1279 113 : GError *error = NULL;
1280 : GckSlot *slot;
1281 :
1282 113 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1283 :
1284 113 : if (self->internal_session)
1285 88 : return self->internal_session;
1286 :
1287 25 : slot = gkd_secret_service_get_pkcs11_slot (self);
1288 25 : self->internal_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
1289 : 0, NULL, NULL, NULL, &error);
1290 25 : if (!self->internal_session) {
1291 0 : g_warning ("couldn't open pkcs11 session for secret service: %s",
1292 : egg_error_message (error));
1293 0 : g_clear_error (&error);
1294 0 : return NULL;
1295 : }
1296 :
1297 25 : if (!log_into_pkcs11_session (self->internal_session, &error)) {
1298 0 : g_warning ("couldn't log in to pkcs11 session for secret service: %s",
1299 : egg_error_message (error));
1300 0 : g_clear_error (&error);
1301 0 : g_object_unref (self->internal_session);
1302 0 : self->internal_session = NULL;
1303 0 : return NULL;
1304 : }
1305 :
1306 25 : return self->internal_session;
1307 : }
1308 :
1309 : GkdSecretSession*
1310 18 : gkd_secret_service_lookup_session (GkdSecretService *self, const gchar *path,
1311 : const gchar *caller)
1312 : {
1313 : ServiceClient *client;
1314 : gpointer object;
1315 :
1316 18 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1317 18 : g_return_val_if_fail (path, NULL);
1318 18 : g_return_val_if_fail (caller, NULL);
1319 :
1320 18 : client = g_hash_table_lookup (self->clients, caller);
1321 18 : g_return_val_if_fail (client, NULL);
1322 :
1323 18 : object = g_hash_table_lookup (client->dispatch, path);
1324 18 : if (object == NULL || !GKD_SECRET_IS_SESSION (object))
1325 0 : return NULL;
1326 :
1327 18 : return GKD_SECRET_SESSION (object);
1328 : }
1329 :
1330 : void
1331 0 : gkd_secret_service_close_session (GkdSecretService *self, GkdSecretSession *session)
1332 : {
1333 : ServiceClient *client;
1334 : const gchar *caller;
1335 : const gchar *path;
1336 :
1337 0 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1338 0 : g_return_if_fail (GKD_SECRET_IS_SESSION (session));
1339 :
1340 0 : caller = gkd_secret_session_get_caller (session);
1341 0 : client = g_hash_table_lookup (self->clients, caller);
1342 0 : g_return_if_fail (client);
1343 :
1344 0 : path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (session));
1345 0 : g_hash_table_remove (client->dispatch, path);
1346 : }
1347 :
1348 : const gchar*
1349 0 : gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias)
1350 : {
1351 0 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1352 0 : g_return_val_if_fail (alias != NULL, NULL);
1353 :
1354 0 : return g_hash_table_lookup (self->aliases, alias);
1355 : }
1356 :
1357 : void
1358 0 : gkd_secret_service_set_alias (GkdSecretService *self, const gchar *alias,
1359 : const gchar *identifier)
1360 : {
1361 0 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1362 0 : g_return_if_fail (alias);
1363 :
1364 0 : g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier));
1365 :
1366 0 : if (g_str_equal (alias, "default"))
1367 0 : store_default (self);
1368 : }
1369 :
1370 : void
1371 18 : gkd_secret_service_publish_dispatch (GkdSecretService *self, const gchar *caller,
1372 : GkdSecretDispatch *object)
1373 : {
1374 : ServiceClient *client;
1375 : const gchar *path;
1376 :
1377 18 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1378 18 : g_return_if_fail (caller);
1379 18 : g_return_if_fail (GKD_SECRET_IS_DISPATCH (object));
1380 :
1381 : /* Take ownership of the session */
1382 18 : client = g_hash_table_lookup (self->clients, caller);
1383 18 : g_return_if_fail (client);
1384 18 : path = gkd_secret_dispatch_get_object_path (object);
1385 18 : g_return_if_fail (!g_hash_table_lookup (client->dispatch, path));
1386 18 : g_hash_table_replace (client->dispatch, (gpointer)path, g_object_ref (object));
1387 : }
1388 :
1389 : gchar **
1390 28 : gkd_secret_service_get_collections (GkdSecretService *self)
1391 : {
1392 : GVariant *collections_variant;
1393 : gchar **collections;
1394 :
1395 28 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1396 :
1397 28 : collections_variant = gkd_secret_objects_append_collection_paths (self->objects, NULL);
1398 28 : collections = g_variant_dup_objv (collections_variant, NULL);
1399 28 : g_variant_unref (collections_variant);
1400 :
1401 28 : return collections;
1402 : }
1403 :
1404 : void
1405 2 : gkd_secret_service_emit_collection_created (GkdSecretService *self,
1406 : const gchar *collection_path)
1407 : {
1408 : gchar **collections;
1409 :
1410 2 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1411 2 : g_return_if_fail (collection_path != NULL);
1412 :
1413 2 : gkd_secret_objects_register_collection (self->objects, collection_path);
1414 :
1415 2 : collections = gkd_secret_service_get_collections (self);
1416 2 : gkd_exported_service_set_collections (self->skeleton, (const gchar **) collections);
1417 2 : gkd_exported_service_emit_collection_created (self->skeleton, collection_path);
1418 :
1419 2 : g_strfreev (collections);
1420 : }
1421 :
1422 : void
1423 1 : gkd_secret_service_emit_collection_deleted (GkdSecretService *self,
1424 : const gchar *collection_path)
1425 : {
1426 : gchar **collections;
1427 :
1428 1 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1429 1 : g_return_if_fail (collection_path != NULL);
1430 :
1431 1 : gkd_secret_objects_unregister_collection (self->objects, collection_path);
1432 :
1433 1 : collections = gkd_secret_service_get_collections (self);
1434 1 : gkd_exported_service_set_collections (self->skeleton, (const gchar **) collections);
1435 1 : gkd_exported_service_emit_collection_deleted (self->skeleton, collection_path);
1436 :
1437 1 : g_strfreev (collections);
1438 : }
1439 :
1440 : void
1441 21 : gkd_secret_service_emit_collection_changed (GkdSecretService *self,
1442 : const gchar *collection_path)
1443 : {
1444 21 : g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1445 21 : g_return_if_fail (collection_path != NULL);
1446 :
1447 21 : gkd_exported_service_emit_collection_changed (self->skeleton, collection_path);
1448 : }
|