static DBusMessage* service_message_handler (GkdSecretService *self, DBusMessage *message) { g_return_val_if_fail (message, NULL); g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); /* org.freedesktop.Secret.Service.OpenSession() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "OpenSession")) return service_method_open_session (self, message); /* org.freedesktop.Secret.Service.CreateCollection() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "CreateCollection")) return service_method_create_collection (self, message); /* org.freedesktop.Secret.Service.LockService() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "LockService")) return service_method_lock_service (self, message); /* org.freedesktop.Secret.Service.SearchItems() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems")) return gkd_secret_objects_handle_search_items (self->objects, message, NULL); /* org.freedesktop.Secret.Service.GetSecrets() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets")) return gkd_secret_objects_handle_get_secrets (self->objects, message); /* org.freedesktop.Secret.Service.Unlock() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Unlock")) return service_method_unlock (self, message); /* org.freedesktop.Secret.Service.Lock() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Lock")) return service_method_lock (self, message); /* org.mate.keyring.Service.ChangeLock() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ChangeLock")) return service_method_change_lock (self, message); /* org.freedesktop.Secret.Service.ReadAlias() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ReadAlias")) return service_method_read_alias (self, message); /* org.freedesktop.Secret.Service.SetAlias() */ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SetAlias")) return service_method_set_alias (self, message); /* org.mate.keyring.InternalUnsupportedGuiltRiddenInterface.CreateWithMasterPassword */ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "CreateWithMasterPassword")) return service_method_create_with_master_password (self, message); /* org.mate.keyring.InternalUnsupportedGuiltRiddenInterface.ChangeWithMasterPassword() */ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "ChangeWithMasterPassword")) return service_method_change_with_master_password (self, message); /* org.mate.keyring.InternalUnsupportedGuiltRiddenInterface.UnlockWithMasterPassword() */ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "UnlockWithMasterPassword")) return service_method_unlock_with_master_password (self, message); /* org.freedesktop.DBus.Properties.Get() */ if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get")) return service_property_get (self, message); /* org.freedesktop.DBus.Properties.Set() */ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set")) return service_property_set (self, message); /* org.freedesktop.DBus.Properties.GetAll() */ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll")) return service_property_getall (self, message); else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE)) return gkd_dbus_introspect_handle (message, gkd_secret_introspect_service); return NULL; }
GckSession* gkd_secret_service_internal_pkcs11_session (GkdSecretService *self) { GError *error = NULL; GckSlot *slot; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); if (self->internal_session) return self->internal_session; slot = gkd_secret_service_get_pkcs11_slot (self); self->internal_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE, 0, NULL, NULL, NULL, &error); if (!self->internal_session) { g_warning ("couldn't open pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); return NULL; } if (!log_into_pkcs11_session (self->internal_session, &error)) { g_warning ("couldn't log in to pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); g_object_unref (self->internal_session); self->internal_session = NULL; return NULL; } return self->internal_session; }
const gchar* gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias) { g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (alias != NULL, NULL); return g_hash_table_lookup (self->aliases, alias); }
void gkd_secret_service_emit_collection_changed (GkdSecretService *self, const gchar *collection_path) { g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (collection_path != NULL); gkd_exported_service_emit_collection_changed (self->skeleton, collection_path); }
static void on_get_connection_unix_process_id (DBusPendingCall *pending, gpointer user_data) { on_get_connection_unix_process_id_args *args = user_data; DBusMessage *reply = NULL; DBusError error = DBUS_ERROR_INIT; dbus_uint32_t caller_pid = 0; GkdSecretService *self; ServiceClient *client; const gchar *caller; g_return_if_fail (GKD_SECRET_IS_SERVICE (args->self)); self = args->self; /* Get the resulting process ID */ reply = dbus_pending_call_steal_reply (pending); g_return_if_fail (reply); caller = dbus_message_get_sender (args->message); g_return_if_fail (caller); client = g_hash_table_lookup (self->clients, caller); if (client == NULL) { /* An error returned from GetConnectionUnixProcessID */ if (dbus_set_error_from_message (&error, reply)) { g_message ("couldn't get the caller's unix process id: %s", error.message); caller_pid = 0; dbus_error_free (&error); /* A PID was returned from GetConnectionUnixProcessID */ } else { if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID)) g_return_if_reached (); } /* Initialize the client object */ client = g_new0 (ServiceClient, 1); client->caller_peer = g_strdup (caller); client->caller_pid = caller_pid; if (caller_pid != 0) client->caller_exec = egg_unix_credentials_executable (caller_pid); client->app.applicationData = client; client->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref); client->prompts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref); g_hash_table_replace (self->clients, client->caller_peer, client); /* Update default collection each time someone connects */ update_default (self, TRUE); } dbus_message_unref (reply); /* Dispatch the original message again */ service_dispatch_message (self, args->message); }
void gkd_secret_service_set_alias (GkdSecretService *self, const gchar *alias, const gchar *identifier) { g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (alias); g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier)); if (g_str_equal (alias, "default")) store_default (self); }
const gchar* gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias) { const gchar *identifier; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (alias, NULL); identifier = g_hash_table_lookup (self->aliases, alias); if (!identifier && g_str_equal (alias, "default")) { update_default (self, TRUE); identifier = g_hash_table_lookup (self->aliases, alias); } return identifier; }
GkdSecretSession* gkd_secret_service_lookup_session (GkdSecretService *self, const gchar *path, const gchar *caller) { ServiceClient *client; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (path, NULL); g_return_val_if_fail (caller, NULL); client = g_hash_table_lookup (self->clients, caller); g_return_val_if_fail (client, NULL); return g_hash_table_lookup (client->sessions, path); }
void gkd_secret_service_close_session (GkdSecretService *self, GkdSecretSession *session) { ServiceClient *client; const gchar *caller; const gchar *path; g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (GKD_SECRET_IS_SESSION (session)); caller = gkd_secret_session_get_caller (session); client = g_hash_table_lookup (self->clients, caller); g_return_if_fail (client); path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (session)); g_hash_table_remove (client->dispatch, path); }
void gkd_secret_service_emit_collection_deleted (GkdSecretService *self, const gchar *collection_path) { gchar **collections; g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (collection_path != NULL); gkd_secret_objects_unregister_collection (self->objects, collection_path); collections = gkd_secret_service_get_collections (self); gkd_exported_service_set_collections (self->skeleton, (const gchar **) collections); gkd_exported_service_emit_collection_deleted (self->skeleton, collection_path); g_strfreev (collections); }
GP11Session* gkd_secret_service_get_pkcs11_session (GkdSecretService *self, const gchar *caller) { ServiceClient *client; GError *error = NULL; GP11TokenInfo *info; GP11Slot *slot; gulong flags; gboolean login; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (caller, NULL); client = g_hash_table_lookup (self->clients, caller); g_return_val_if_fail (client, NULL); /* Open a new session if necessary */ if (!client->pkcs11_session) { flags = CKF_RW_SESSION | CKF_G_APPLICATION_SESSION; slot = gkd_secret_service_get_pkcs11_slot (self); client->pkcs11_session = gp11_slot_open_session_full (slot, flags, &client->app, NULL, NULL, &error); if (!client->pkcs11_session) { g_warning ("couldn't open pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); return NULL; } /* Perform the necessary 'user' login to secrets token. Doesn't unlock anything */ info = gp11_slot_get_token_info (slot); login = info && (info->flags & CKF_LOGIN_REQUIRED); gp11_token_info_free (info); if (login && !gp11_session_login (client->pkcs11_session, CKU_USER, NULL, 0, &error)) { g_warning ("couldn't log in to pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); g_object_unref (client->pkcs11_session); client->pkcs11_session = NULL; return NULL; } } return client->pkcs11_session; }
void gkd_secret_service_publish_dispatch (GkdSecretService *self, const gchar *caller, GkdSecretDispatch *object) { ServiceClient *client; const gchar *path; g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (caller); g_return_if_fail (GKD_SECRET_IS_DISPATCH (object)); /* Take ownership of the session */ client = g_hash_table_lookup (self->clients, caller); g_return_if_fail (client); path = gkd_secret_dispatch_get_object_path (object); g_return_if_fail (!g_hash_table_lookup (client->dispatch, path)); g_hash_table_replace (client->dispatch, (gpointer)path, g_object_ref (object)); }
GkdSecretSession* gkd_secret_service_lookup_session (GkdSecretService *self, const gchar *path, const gchar *caller) { ServiceClient *client; gpointer object; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (path, NULL); g_return_val_if_fail (caller, NULL); client = g_hash_table_lookup (self->clients, caller); g_return_val_if_fail (client, NULL); object = g_hash_table_lookup (client->dispatch, path); if (object == NULL || !GKD_SECRET_IS_SESSION (object)) return NULL; return GKD_SECRET_SESSION (object); }
static void initialize_service_client (GkdSecretService *self, const gchar *caller) { ServiceClient *client; g_assert (GKD_SECRET_IS_SERVICE (self)); g_assert (caller); /* Initialize the client object */ client = g_new0 (ServiceClient, 1); client->caller_peer = g_strdup (caller); client->app.applicationData = client; client->dispatch = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref); g_hash_table_replace (self->clients, client->caller_peer, client); /* Update default collection each time someone connects */ update_default (self, TRUE); }
void gkd_secret_service_emit_collection_deleted (GkdSecretService *self, const gchar *collection_path) { DBusMessage *message; g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); g_return_if_fail (collection_path != NULL); message = dbus_message_new_signal (SECRET_SERVICE_PATH, SECRET_SERVICE_INTERFACE, "CollectionDeleted"); dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path, DBUS_TYPE_INVALID); if (!dbus_connection_send (self->connection, message, NULL)) g_return_if_reached (); dbus_message_unref (message); emit_collections_properties_changed (self); }
static void initialize_service_client (GkdSecretService *self, DBusMessage *message) { on_get_connection_unix_process_id_args *args; DBusMessage *request; DBusPendingCall *pending; const gchar *caller; g_assert (GKD_SECRET_IS_SERVICE (self)); g_assert (message); args = g_new0 (on_get_connection_unix_process_id_args, 1); args->self = g_object_ref (self); args->message = dbus_message_ref (message); caller = dbus_message_get_sender (message); g_return_if_fail (caller); /* Message org.freedesktop.DBus.GetConnectionUnixProcessID(IN String caller) */ request = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionUnixProcessID"); if (!request || !dbus_message_append_args (request, DBUS_TYPE_STRING, &caller, DBUS_TYPE_INVALID)) g_return_if_reached (); /* * Send of request for GetConnectionUnixProcessID, with lowish timeout. * We're only talking to the session bus, so the reply should be fast. * In addition we want to send off a reply to our caller, before it * times out. */ if (!dbus_connection_send_with_reply (self->connection, request, &pending, 2000)) g_return_if_reached (); dbus_message_unref (request); /* Track our new session object, on this call */ dbus_pending_call_set_notify (pending, on_get_connection_unix_process_id, args, free_on_get_connection_unix_process_id_args); dbus_pending_call_unref (pending); }
GckSession* gkd_secret_service_get_pkcs11_session (GkdSecretService *self, const gchar *caller) { ServiceClient *client; GError *error = NULL; GckSlot *slot; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (caller, NULL); client = g_hash_table_lookup (self->clients, caller); g_return_val_if_fail (client, NULL); /* Open a new session if necessary */ if (!client->pkcs11_session) { slot = gkd_secret_service_get_pkcs11_slot (self); client->pkcs11_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE, CKF_G_APPLICATION_SESSION, &client->app, NULL, NULL, &error); if (!client->pkcs11_session) { g_warning ("couldn't open pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); return NULL; } if (!log_into_pkcs11_session (client->pkcs11_session, &error)) { g_warning ("couldn't log in to pkcs11 session for secret service: %s", egg_error_message (error)); g_clear_error (&error); g_object_unref (client->pkcs11_session); client->pkcs11_session = NULL; return NULL; } } return client->pkcs11_session; }
const gchar* gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias) { const gchar *identifier; g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (alias != NULL, NULL); identifier = g_hash_table_lookup (self->aliases, alias); if (!identifier) { if (g_str_equal (alias, "default")) { update_default (self, TRUE); identifier = g_hash_table_lookup (self->aliases, alias); /* Default to to 'login' if no default keyring */ if (identifier == NULL) { identifier = "login"; g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier)); } } else if (g_str_equal (alias, "session")) { identifier = "session"; g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier)); /* TODO: We should be using CKA_G_LOGIN_COLLECTION */ } else if (g_str_equal (alias, "login")) { identifier = "login"; g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier)); } } return identifier; }
GDBusConnection* gkd_secret_service_get_connection (GkdSecretService *self) { g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); return self->connection; }
void gkd_secret_service_send (GkdSecretService *self, DBusMessage *message) { g_return_if_fail (GKD_SECRET_IS_SERVICE (self)); dbus_connection_send (self->connection, message, NULL); }
static void service_dispatch_message (GkdSecretService *self, DBusMessage *message) { DBusMessage *reply = NULL; const gchar *caller; ServiceClient *client; const gchar *path; gpointer object; g_assert (GKD_SECRET_IS_SERVICE (self)); g_assert (message); /* The first thing we do is try to allocate a client context */ caller = dbus_message_get_sender (message); if (caller == NULL) { reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Could not not identify calling client application"); dbus_connection_send (self->connection, reply, NULL); dbus_message_unref (reply); return; } client = g_hash_table_lookup (self->clients, caller); if (client == NULL) { initialize_service_client (self, message); return; /* This function called again, when client is initialized */ } path = dbus_message_get_path (message); g_return_if_fail (path); /* Dispatched to a session or prompt */ if (object_path_has_prefix (path, SECRET_SESSION_PREFIX) || object_path_has_prefix (path, SECRET_PROMPT_PREFIX)) { object = g_hash_table_lookup (client->dispatch, path); if (object == NULL) reply = gkd_secret_error_no_such_object (message); else reply = gkd_secret_dispatch_message (GKD_SECRET_DISPATCH (object), message); /* Dispatched to a collection, off it goes */ } else if (object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) || object_path_has_prefix (path, SECRET_ALIAS_PREFIX)) { reply = gkd_secret_objects_dispatch (self->objects, message); /* Addressed to the service */ } else if (g_str_equal (path, SECRET_SERVICE_PATH)) { reply = service_message_handler (self, message); } /* Should we send an error? */ if (!reply && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) { if (!dbus_message_get_no_reply (message)) { reply = dbus_message_new_error_printf (message, DBUS_ERROR_UNKNOWN_METHOD, "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n", dbus_message_get_member (message), dbus_message_get_signature (message), dbus_message_get_interface (message)); } } if (reply) { dbus_connection_send (self->connection, reply, NULL); dbus_message_unref (reply); } }
static DBusHandlerResult gkd_secret_service_filter_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data) { GkdSecretService *self = user_data; const gchar *object_name; const gchar *old_owner; const gchar *new_owner; const gchar *path; const gchar *interface; g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* org.freedesktop.DBus.NameOwnerChanged(STRING name, STRING old_owner, STRING new_owner) */ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged") && dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &object_name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID)) { /* * A peer is connecting or disconnecting from the bus, * remove any client info, when client gone. */ g_return_val_if_fail (object_name && new_owner, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); if (g_str_equal (new_owner, "") && object_name[0] == ':') g_hash_table_remove (self->clients, object_name); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* * If the path is a within our object tree, then we do our own dispatch. */ path = dbus_message_get_path (message); switch (dbus_message_get_type (message)) { /* Dispatch any method call on our interfaces, for our objects */ case DBUS_MESSAGE_TYPE_METHOD_CALL: if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) { interface = dbus_message_get_interface (message); if (interface == NULL || g_str_has_prefix (interface, SECRET_INTERFACE_PREFIX) || g_str_equal (interface, DBUS_INTERFACE_PROPERTIES) || g_str_equal (interface, INTERNAL_SERVICE_INTERFACE) || g_str_equal (interface, DBUS_INTERFACE_INTROSPECTABLE)) { service_dispatch_message (self, message); return DBUS_HANDLER_RESULT_HANDLED; } } break; /* Dispatch any signal for one of our objects */ case DBUS_MESSAGE_TYPE_SIGNAL: if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) { service_dispatch_message (self, message); return DBUS_HANDLER_RESULT_HANDLED; } break; default: break; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
GkdSecretObjects* gkd_secret_service_get_objects (GkdSecretService *self) { g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); return self->objects; }
GckSlot* gkd_secret_service_get_pkcs11_slot (GkdSecretService *self) { g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL); return gkd_secret_objects_get_pkcs11_slot (self->objects); }