LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-secret-service.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.1 % 609 378
Test Date: 2024-04-08 13:24:42 Functions: 75.8 % 62 47

            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              : }
        

Generated by: LCOV version 2.0-1