static int keyring_get(struct credential *c) { SecretService *service = NULL; GHashTable *attributes = NULL; GError *error = NULL; GList *items = NULL; if (!c->protocol || !(c->host || c->path)) return EXIT_FAILURE; service = secret_service_get_sync(0, NULL, &error); if (error != NULL) { g_critical("could not connect to Secret Service: %s", error->message); g_error_free(error); return EXIT_FAILURE; } attributes = make_attr_list(c); items = secret_service_search_sync(service, SECRET_SCHEMA_COMPAT_NETWORK, attributes, SECRET_SEARCH_LOAD_SECRETS, NULL, &error); g_hash_table_unref(attributes); if (error != NULL) { g_critical("lookup failed: %s", error->message); g_error_free(error); return EXIT_FAILURE; } if (items != NULL) { SecretItem *item; SecretValue *secret; const char *s; item = items->data; secret = secret_item_get_secret(item); attributes = secret_item_get_attributes(item); s = g_hash_table_lookup(attributes, "user"); if (s) { g_free(c->username); c->username = g_strdup(s); } s = secret_value_get_text(secret); if (s) { g_free(c->password); c->password = g_strdup(s); } g_hash_table_unref(attributes); secret_value_unref(secret); g_list_free_full(items, g_object_unref); } return EXIT_SUCCESS; }
static void print_item_details (SecretItem *item) { SecretValue *secret; GHashTableIter iter; GHashTable *attributes; gchar *value, *key; guint64 when; const gchar *part; const gchar *path; path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); g_return_if_fail (path != NULL); /* The item identifier */ part = strrchr (path, '/'); if (part == NULL) part = path; g_print ("[%s]\n", path); /* The label */ value = secret_item_get_label (item); g_print ("label = %s\n", value); g_free (value); /* The secret value */ secret = secret_item_get_secret (item); g_print ("secret = "); if (secret != NULL) { write_password_data (secret); secret_value_unref (secret); } g_print ("\n"); /* The dates */ when = secret_item_get_created (item); print_item_when ("created", when); when = secret_item_get_modified (item); print_item_when ("modified", when); /* The schema */ value = secret_item_get_schema_name (item); g_print ("schema = %s\n", value); g_free (value); /* The attributes */ attributes = secret_item_get_attributes (item); g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (void **)&key, (void **)&value)) { if (strcmp (key, "xdg:schema") != 0) g_printerr ("attribute.%s = %s\n", key, value); } g_hash_table_unref (attributes); }
gint compare_specificity (gconstpointer a, gconstpointer b) { GHashTable *attributes_a, *attributes_b; SecretItem *item_a, *item_b; int res; item_a = SECRET_ITEM (a); attributes_a = secret_item_get_attributes (item_a); item_b = SECRET_ITEM (b); attributes_b = secret_item_get_attributes (item_b); res = g_hash_table_size (attributes_a) - g_hash_table_size (attributes_b); g_hash_table_unref (attributes_a); g_hash_table_unref (attributes_b); return res; }
static void keyring_find_secrets_cb (GObject *source, GAsyncResult *result, gpointer user_data) { Request *r = user_data; GError *error = NULL; GError *search_error = NULL; const char *connection_id = NULL; GHashTable *secrets = NULL, *settings = NULL; GList *list = NULL; GList *iter; gboolean hint_found = FALSE, ask = FALSE; r->keyring_calls--; if (g_cancellable_is_cancelled (r->cancellable)) { /* Callback already called by NM or dispose */ request_free (r); return; } list = secret_service_search_finish (NULL, result, &search_error); connection_id = nm_connection_get_id (r->connection); if (g_error_matches (search_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { error = g_error_new_literal (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED, "The secrets request was canceled by the user"); g_error_free (search_error); goto done; } else if (search_error) { error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, "%s.%d - failed to read secrets from keyring (%s)", __FILE__, __LINE__, search_error->message); g_error_free (search_error); goto done; } /* Only ask if we're allowed to, so that eg a connection editor which * requests secrets for its UI, for a connection which doesn't have any * secrets yet, doesn't trigger the applet secrets dialog. */ if ( (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) && g_list_length (list) == 0) { g_message ("No keyring secrets found for %s/%s; asking user.", connection_id, r->setting_name); ask_for_secrets (r); return; } secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue); /* Extract the secrets from the list of matching keyring items */ for (iter = list; iter != NULL; iter = g_list_next (iter)) { SecretItem *item = iter->data; SecretValue *secret; const char *key_name; GHashTable *attributes; secret = secret_item_get_secret (item); if (secret) { attributes = secret_item_get_attributes (item); key_name = g_hash_table_lookup (attributes, KEYRING_SK_TAG); if (!key_name) { g_hash_table_unref (attributes); secret_value_unref (secret); continue; } g_hash_table_insert (secrets, g_strdup (key_name), string_to_gvalue (secret_value_get (secret, NULL))); /* See if this property matches a given hint */ if (r->hints && r->hints[0]) { if (!g_strcmp0 (r->hints[0], key_name) || !g_strcmp0 (r->hints[1], key_name)) hint_found = TRUE; } g_hash_table_unref (attributes); secret_value_unref (secret); break; } } /* If there were hints, and none of the hints were returned by the keyring, * get some new secrets. */ if (r->flags) { if (r->hints && r->hints[0] && !hint_found) ask = TRUE; else if (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) { g_message ("New secrets for %s/%s requested; ask the user", connection_id, r->setting_name); ask = TRUE; } else if ( (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) && is_connection_always_ask (r->connection)) ask = TRUE; } /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that * will contain all the individual settings hashes. */ settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy); g_hash_table_insert (settings, g_strdup (r->setting_name), secrets); done: g_list_free_full (list, g_object_unref); if (ask) { GHashTableIter hash_iter; const char *setting_name; GHashTable *setting_hash; /* Stuff all the found secrets into the connection for the UI to use */ g_hash_table_iter_init (&hash_iter, settings); while (g_hash_table_iter_next (&hash_iter, (gpointer *) &setting_name, (gpointer *) &setting_hash)) { nm_connection_update_secrets (r->connection, setting_name, setting_hash, NULL); } ask_for_secrets (r); } else { /* Otherwise send the secrets back to NetworkManager */ r->get_callback (NM_SECRET_AGENT (r->agent), r->connection, error ? NULL : settings, error, r->callback_data); request_free (r); } if (settings) g_hash_table_destroy (settings); g_clear_error (&error); }
void NetworkStorageSession::getCredentialFromPersistentStorage(const ProtectionSpace& protectionSpace, Function<void (Credential&&)> completionHandler) { #if USE(LIBSECRET) if (m_sessionID.isEphemeral()) { completionHandler({ }); return; } const String& realm = protectionSpace.realm(); if (realm.isEmpty()) { completionHandler({ }); return; } GRefPtr<GHashTable> attributes = adoptGRef(secret_attributes_build(SECRET_SCHEMA_COMPAT_NETWORK, "domain", realm.utf8().data(), "server", protectionSpace.host().utf8().data(), "port", protectionSpace.port(), "protocol", schemeFromProtectionSpaceServerType(protectionSpace.serverType()), "authtype", authTypeFromProtectionSpaceAuthenticationScheme(protectionSpace.authenticationScheme()), nullptr)); if (!attributes) { completionHandler({ }); return; } m_persisentStorageCancellable = adoptGRef(g_cancellable_new()); m_persisentStorageCompletionHandler = WTFMove(completionHandler); secret_service_search(nullptr, SECRET_SCHEMA_COMPAT_NETWORK, attributes.get(), static_cast<SecretSearchFlags>(SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS), m_persisentStorageCancellable.get(), [](GObject* source, GAsyncResult* result, gpointer userData) { GUniqueOutPtr<GError> error; GUniquePtr<GList> elements(secret_service_search_finish(SECRET_SERVICE(source), result, &error.outPtr())); if (g_error_matches (error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; NetworkStorageSession* session = static_cast<NetworkStorageSession*>(userData); auto completionHandler = std::exchange(session->m_persisentStorageCompletionHandler, nullptr); if (error || !elements || !elements->data) { completionHandler({ }); return; } GRefPtr<SecretItem> secretItem = adoptGRef(static_cast<SecretItem*>(elements->data)); GRefPtr<GHashTable> attributes = adoptGRef(secret_item_get_attributes(secretItem.get())); String user = String::fromUTF8(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "user"))); if (user.isEmpty()) { completionHandler({ }); return; } size_t length; GRefPtr<SecretValue> secretValue = adoptGRef(secret_item_get_secret(secretItem.get())); const char* passwordData = secret_value_get(secretValue.get(), &length); completionHandler(Credential(user, String::fromUTF8(passwordData, length), CredentialPersistencePermanent)); }, this); #else UNUSED_PARAM(protectionSpace); completionHandler({ }); #endif }
static void keyring_pin_check_cb (GObject *source, GAsyncResult *result, gpointer user_data) { BroadbandDeviceInfo *info = user_data; GList *iter; GList *list; SecretItem *item; SecretValue *pin = NULL; GHashTable *attributes; GError *error = NULL; const char *simid; list = secret_service_search_finish (NULL, result, &error); if (error != NULL) { /* No saved PIN, just ask the user */ unlock_dialog_new (info->device, info); g_error_free (error); return; } /* Look for a result with a matching "simid" attribute since that's * better than just using a matching "devid". The PIN is really tied * to the SIM, not the modem itself. */ simid = mm_sim_get_identifier (info->mm_sim); if (simid) { for (iter = list; (pin == NULL) && iter; iter = g_list_next (iter)) { item = iter->data; /* Look for a matching "simid" attribute */ attributes = secret_item_get_attributes (item); if (g_strcmp0 (simid, g_hash_table_lookup (attributes, "simid"))) pin = secret_item_get_secret (item); else pin = NULL; g_hash_table_unref (attributes); if (pin != NULL) break; } } if (pin == NULL) { /* Fall back to the first result's PIN if we have one */ if (list) pin = secret_item_get_secret (list->data); if (pin == NULL) { unlock_dialog_new (info->device, info); return; } } /* Send the PIN code to ModemManager */ mm_sim_send_pin (info->mm_sim, secret_value_get (pin, NULL), NULL, /* cancellable */ (GAsyncReadyCallback)autounlock_sim_send_pin_ready, info); secret_value_unref (pin); }
gboolean g_vfs_keyring_lookup_password (const gchar *username, const gchar *host, const gchar *domain, const gchar *protocol, const gchar *object, const gchar *authtype, guint32 port, gchar **username_out, gchar **domain_out, gchar **password_out) { #ifdef HAVE_KEYRING GHashTable *attributes; SecretItem *item; SecretValue *secret; GList *plist; GError *error = NULL; attributes = build_network_attributes (username, host, domain, protocol, object, authtype, port); plist = secret_service_search_sync (NULL, SECRET_SCHEMA_COMPAT_NETWORK, attributes, SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_ALL, NULL, &error); g_hash_table_unref (attributes); if (error != NULL) { g_error_free (error); return FALSE; } if (plist == NULL) return FALSE; /* We want the least specific result, so we sort the return values. For instance, given both items for ftp://host:port and ftp://host in the keyring we always want to use the ftp://host one for i.e. ftp://host/some/path. */ plist = g_list_sort (plist, compare_specificity); item = SECRET_ITEM (plist->data); secret = secret_item_get_secret (item); attributes = secret_item_get_attributes (item); g_list_free_full (plist, g_object_unref); if (secret == NULL) { if (attributes) g_hash_table_unref (attributes); return FALSE; } *password_out = g_strdup (secret_value_get (secret, NULL)); secret_value_unref (secret); if (username_out) *username_out = g_strdup (g_hash_table_lookup (attributes, "user")); if (domain_out) *domain_out = g_strdup (g_hash_table_lookup (attributes, "domain")); g_hash_table_unref (attributes); return TRUE; #else return FALSE; #endif /* HAVE_KEYRING */ }