static gboolean create_collection_with_secret (GkdSecretCreate *self, GkdSecretSecret *master) { DBusError derr = DBUS_ERROR_INIT; GkdSecretService *service; gchar *identifier; g_assert (GKD_SECRET_IS_CREATE (self)); g_assert (master); g_assert (!self->result_path); self->result_path = gkd_secret_create_with_secret (self->pkcs11_attrs, master, &derr); if (!self->result_path) { g_warning ("couldn't create new collection: %s", derr.message); dbus_error_free (&derr); return FALSE; } if (self->alias) { if (!gkd_secret_util_parse_path (self->result_path, &identifier, NULL)) g_assert_not_reached (); service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self)); gkd_secret_service_set_alias (service, self->alias, identifier); g_free (identifier); } return TRUE; }
static gboolean create_collection_with_secret (GkdSecretCreate *self, GkdSecretSecret *master) { GError *error = NULL; GkdSecretService *service; gchar *identifier; g_assert (GKD_SECRET_IS_CREATE (self)); g_assert (master); g_assert (!self->result_path); self->result_path = gkd_secret_create_with_secret (self->attributes, master, &error); if (!self->result_path) { g_warning ("couldn't create new collection: %s", error->message); g_error_free (error); return FALSE; } service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self)); if (self->alias) { if (!gkd_secret_util_parse_path (self->result_path, &identifier, NULL)) g_assert_not_reached (); gkd_secret_service_set_alias (service, self->alias, identifier); g_free (identifier); } /* Notify the callers that a collection was created */ gkd_secret_service_emit_collection_created (service, self->result_path); return TRUE; }
static gboolean parse_object_path (GkdSecretObjects *self, const gchar *path, gchar **collection, gchar **item) { const gchar *replace; g_assert (self); g_assert (path); g_assert (collection); if (!gkd_secret_util_parse_path (path, collection, item)) return FALSE; if (g_str_has_prefix (path, SECRET_ALIAS_PREFIX)) { replace = gkd_secret_service_get_alias (self->service, *collection); if (!replace) { g_free (*collection); *collection = NULL; if (item) { g_free (*item); *item = NULL; } return FALSE; } g_free (*collection); *collection = g_strdup (replace); } return TRUE; }
static GckObject * secret_objects_lookup_gck_object_for_path (GkdSecretObjects *self, const gchar *sender, const gchar *path, GError **error_out) { GckBuilder builder = GCK_BUILDER_INIT; GList *objects; GckSession *session; gchar *c_ident; gchar *i_ident; GckObject *object = NULL; GError *error = NULL; g_return_val_if_fail (path, FALSE); if (!gkd_secret_util_parse_path (path, &c_ident, &i_ident) || !c_ident) goto out; /* The session we're using to access the object */ session = gkd_secret_service_get_pkcs11_session (self->service, sender); g_return_val_if_fail (session, FALSE); if (i_ident) { gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY); gck_builder_add_string (&builder, CKA_G_COLLECTION, c_ident); gck_builder_add_string (&builder, CKA_ID, i_ident); } else { gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION); gck_builder_add_string (&builder, CKA_ID, c_ident); } objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error); g_free (c_ident); g_free (i_ident); if (error != NULL) { g_warning ("couldn't lookup object: %s: %s", path, egg_error_message (error)); g_clear_error (&error); } if (!objects) goto out; object = g_object_ref (objects->data); gck_list_unref_free (objects); out: if (!object) g_set_error (error_out, GKD_SECRET_ERROR, GKD_SECRET_ERROR_NO_SUCH_OBJECT, "The '%s' object does not exist", path); return object; }
static gboolean service_method_set_alias (GkdExportedService *skeleton, GDBusMethodInvocation *invocation, gchar *alias, gchar *path, GkdSecretService *self) { GckObject *collection; gchar *identifier; if (!g_str_equal (alias, "default")) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Only the 'default' alias is supported"); return TRUE; } /* No default collection */ if (g_str_equal (path, "/")) { identifier = g_strdup (""); /* Find a collection with that path */ } else { if (!object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) || !gkd_secret_util_parse_path (path, &identifier, NULL)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid collection object path"); return TRUE; } collection = gkd_secret_objects_lookup_collection (self->objects, g_dbus_method_invocation_get_sender (invocation), path); if (collection == NULL) { g_free (identifier); g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR, GKD_SECRET_ERROR_NO_SUCH_OBJECT, "The collection does not exist"); return TRUE; } g_object_unref (collection); } gkd_secret_service_set_alias (self, alias, identifier); g_free (identifier); gkd_exported_service_complete_set_alias (skeleton, invocation); return TRUE; }
static GDBusMessage * rewrite_default_alias (GkdSecretService *self, GDBusMessage *message) { const char *path = g_dbus_message_get_path (message); const char *replace; char *collection = NULL, *item = NULL; char *collection_path, *item_path; GDBusMessage *rewritten; GError *error = NULL; if (path == NULL) return message; if (!g_str_has_prefix (path, SECRET_ALIAS_PREFIX)) return message; if (!gkd_secret_util_parse_path (path, &collection, &item)) return message; replace = gkd_secret_service_get_alias (self, collection); if (!replace) { g_free (item); g_free (collection); return message; } rewritten = g_dbus_message_copy (message, &error); if (error != NULL) { g_error_free (error); return message; } collection_path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, replace, -1); if (item != NULL) { item_path = gkd_secret_util_build_path (collection_path, item, -1); g_dbus_message_set_path (rewritten, item_path); g_free (item_path); } else { g_dbus_message_set_path (rewritten, collection_path); } g_free (collection_path); g_free (item); g_free (collection); g_object_unref (message); return rewritten; }
static DBusMessage* service_method_set_alias (GkdSecretService *self, DBusMessage *message) { GckObject *collection; gchar *identifier; const char *alias; const char *path; if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &alias, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return NULL; g_return_val_if_fail (alias, NULL); g_return_val_if_fail (path, NULL); if (!g_str_equal (alias, "default")) return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED, "Only the 'default' alias is supported"); /* No default collection */ if (g_str_equal (path, "/")) { identifier = g_strdup (""); /* Find a collection with that path */ } else { if (!object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) || !gkd_secret_util_parse_path (path, &identifier, NULL)) return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS, "Invalid collection object path"); collection = gkd_secret_objects_lookup_collection (self->objects, dbus_message_get_sender (message), path); if (collection == NULL) { g_free (identifier); return dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT, "No such collection exists"); } g_object_unref (collection); } gkd_secret_service_set_alias (self, alias, identifier); g_free (identifier); return dbus_message_new_method_return (message); }
void gkd_secret_objects_foreach_item (GkdSecretObjects *self, const gchar *caller, const gchar *base, GkdSecretObjectsForeach callback, gpointer user_data) { GckBuilder builder = GCK_BUILDER_INIT; GckSession *session; GError *error = NULL; gchar *identifier; GList *items; g_return_if_fail (GKD_SECRET_IS_OBJECTS (self)); g_return_if_fail (base != NULL); g_return_if_fail (callback != NULL); /* The session we're using to access the object */ if (caller == NULL) { session = gkd_secret_service_internal_pkcs11_session (self->service); } else { session = gkd_secret_service_get_pkcs11_session (self->service, caller); } if (!gkd_secret_util_parse_path (base, &identifier, NULL)) g_return_if_reached (); gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY); gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier); items = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error); if (error == NULL) { objects_foreach_item (self, items, base, callback, user_data); } else { g_warning ("couldn't lookup items in '%s' collection: %s", identifier, egg_error_message (error)); g_clear_error (&error); } gck_list_unref_free (items); g_free (identifier); }
GckObject* gkd_secret_objects_lookup_item (GkdSecretObjects *self, const gchar *caller, const gchar *path) { GckBuilder builder = GCK_BUILDER_INIT; GckObject *object = NULL; GError *error = NULL; GList *objects; GckSession *session; gchar *collection; gchar *identifier; g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL); g_return_val_if_fail (caller, NULL); g_return_val_if_fail (path, NULL); if (!gkd_secret_util_parse_path (path, &collection, &identifier)) return NULL; /* The session we're using to access the object */ session = gkd_secret_service_get_pkcs11_session (self->service, caller); g_return_val_if_fail (session, NULL); gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY); gck_builder_add_string (&builder, CKA_ID, identifier); gck_builder_add_string (&builder, CKA_G_COLLECTION, collection); objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error); g_free (identifier); g_free (collection); if (error != NULL) { g_warning ("couldn't lookup item: %s: %s", path, egg_error_message (error)); g_clear_error (&error); } if (objects) object = g_object_ref (objects->data); gck_list_unref_free (objects); return object; }
static gboolean collection_method_create_item (GkdExportedCollection *skeleton, GDBusMethodInvocation *invocation, GVariant *properties, GVariant *secret_variant, gboolean replace, GkdSecretObjects *self) { GckBuilder builder = GCK_BUILDER_INIT; GckSession *pkcs11_session = NULL; GkdSecretSecret *secret = NULL; GckAttributes *attrs = NULL; const GckAttribute *fields; GckObject *item = NULL; const gchar *base; GError *error = NULL; gchar *path = NULL; gchar *identifier; gboolean created = FALSE; GckObject *object; object = secret_objects_lookup_gck_object_for_invocation (self, invocation); if (!object) { return TRUE; } if (!gkd_secret_property_parse_all (properties, SECRET_ITEM_INTERFACE, &builder)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid properties argument"); goto cleanup; } base = g_dbus_method_invocation_get_object_path (invocation); secret = gkd_secret_secret_parse (self->service, g_dbus_method_invocation_get_sender (invocation), secret_variant, &error); if (secret == NULL) { g_dbus_method_invocation_take_error (invocation, error); error = NULL; goto cleanup; } if (!gkd_secret_util_parse_path (base, &identifier, NULL)) g_return_val_if_reached (FALSE); g_return_val_if_fail (identifier, FALSE); pkcs11_session = gck_object_get_session (object); g_return_val_if_fail (pkcs11_session, FALSE); attrs = gck_attributes_ref_sink (gck_builder_end (&builder)); if (replace) { fields = gck_attributes_find (attrs, CKA_G_FIELDS); if (fields) item = collection_find_matching_item (self, pkcs11_session, identifier, fields); } /* Replace the item */ if (item) { if (!gck_object_set (item, attrs, NULL, &error)) goto cleanup; /* Create a new item */ } else { gck_builder_add_all (&builder, attrs); gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier); gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY); item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error); if (item == NULL) goto cleanup; created = TRUE; } /* Set the secret */ if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &error)) { if (created) /* If we created, then try to destroy on failure */ gck_object_destroy (item, NULL, NULL); goto cleanup; } path = object_path_for_item (base, item); gkd_secret_objects_emit_item_created (self, object, path); gkd_exported_collection_complete_create_item (skeleton, invocation, path, "/"); cleanup: if (error) { if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN)) g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR, GKD_SECRET_ERROR_IS_LOCKED, "Cannot create an item in a locked collection"); else g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Couldn't create item: %s", egg_error_message (error)); g_clear_error (&error); } gkd_secret_secret_free (secret); gck_attributes_unref (attrs); if (item) g_object_unref (item); if (pkcs11_session) g_object_unref (pkcs11_session); g_free (path); g_object_unref (object); return TRUE; }
gboolean gkd_secret_objects_handle_search_items (GkdSecretObjects *self, GDBusMethodInvocation *invocation, GVariant *attributes, const gchar *base, gboolean separate_locked) { GckBuilder builder = GCK_BUILDER_INIT; GckObject *search; GckSession *session; GError *error = NULL; gchar *identifier; gpointer data; gsize n_data; GList *locked, *unlocked; GList *items; GVariantBuilder result; if (!gkd_secret_property_parse_fields (attributes, &builder)) { gck_builder_clear (&builder); g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid data in attributes argument"); return TRUE; } if (base != NULL) { if (!gkd_secret_util_parse_path (base, &identifier, NULL)) g_return_val_if_reached (FALSE); gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier); g_free (identifier); } gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH); gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE); /* The session we're using to access the object */ session = gkd_secret_service_get_pkcs11_session (self->service, g_dbus_method_invocation_get_sender (invocation)); g_return_val_if_fail (session, FALSE); /* Create the search object */ search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error); if (error != NULL) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Couldn't search for items: %s", egg_error_message (error)); g_clear_error (&error); return TRUE; } /* Get the matched item handles, and delete the search object */ data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error); gck_object_destroy (search, NULL, NULL); g_object_unref (search); if (error != NULL) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Couldn't retrieve matched items: %s", egg_error_message (error)); g_clear_error (&error); return TRUE; } /* Build a list of object handles */ items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE)); g_free (data); /* Filter out the locked items */ if (separate_locked) { GVariant *unlocked_variant, *locked_variant; item_cleanup_search_results (session, items, &locked, &unlocked); g_variant_builder_init (&result, G_VARIANT_TYPE ("ao")); objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_builder, &result); unlocked_variant = g_variant_builder_end (&result); g_variant_builder_init (&result, G_VARIANT_TYPE ("ao")); objects_foreach_item (self, locked, NULL, on_object_path_append_to_builder, &result); locked_variant = g_variant_builder_end (&result); g_list_free (locked); g_list_free (unlocked); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@ao@ao)", unlocked_variant, locked_variant)); } else { g_variant_builder_init (&result, G_VARIANT_TYPE ("ao")); objects_foreach_item (self, items, NULL, on_object_path_append_to_builder, &result); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@ao)", g_variant_builder_end (&result))); } gck_list_unref_free (items); return TRUE; }