static char * keyring_lookup_secret (const char *uuid, const char *secret_name) { GHashTable *attrs; GList *list; char *secret = NULL; attrs = secret_attributes_build (&network_manager_secret_schema, KEYRING_UUID_TAG, uuid, KEYRING_SN_TAG, NM_SETTING_VPN_SETTING_NAME, KEYRING_SK_TAG, secret_name, NULL); list = secret_service_search_sync (NULL, &network_manager_secret_schema, attrs, SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS, NULL, NULL); if (list && list->data) { SecretItem *item = list->data; SecretValue *value = secret_item_get_secret (item); if (value) { secret = g_strdup (secret_value_get (value, NULL)); secret_value_unref (value); } } g_list_free_full (list, g_object_unref); g_hash_table_unref (attrs); return secret; }
static char * keyring_lookup_secret (const char *uuid, const char *secret_name) { #if defined(HAVE_LIBSECRET) GHashTable *attrs; GList *list; #else GList *found_list = NULL; GnomeKeyringResult ret; GnomeKeyringFound *found; #endif char *secret = NULL; #if defined(HAVE_LIBSECRET) attrs = secret_attributes_build(&network_manager_secret_schema, KEYRING_UUID_TAG, uuid, KEYRING_SN_TAG, NM_SETTING_VPN_SETTING_NAME, KEYRING_SK_TAG, secret_name, NULL); list = secret_service_search_sync(NULL, &network_manager_secret_schema, attrs, SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS, NULL, NULL); if (list && list->data) { SecretItem *item = list->data; SecretValue *value = secret_item_get_secret(item); if (value) { secret = g_strdup(secret_value_get(value, NULL)); secret_value_unref(value); } } g_list_free_full(list, g_object_unref); g_hash_table_unref(attrs); #else ret = gnome_keyring_find_itemsv_sync(GNOME_KEYRING_ITEM_GENERIC_SECRET, &found_list, KEYRING_UUID_TAG, GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, uuid, KEYRING_SN_TAG, GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, NM_SETTING_VPN_SETTING_NAME, KEYRING_SK_TAG, GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, secret_name, NULL); if (ret == GNOME_KEYRING_RESULT_OK && found_list) { found = g_list_nth_data(found_list, 0); secret = gnome_keyring_memory_strdup(found->secret); } gnome_keyring_found_list_free(found_list); #endif return secret; }
static gboolean service_encode_aes_secret (SecretSession *session, SecretValue *value, GVariantBuilder *builder) { gcry_cipher_hd_t cih; guchar *padded; gsize n_padded, pos; gcry_error_t gcry; gpointer iv; gconstpointer secret; gsize n_secret; GVariant *child; g_variant_builder_add (builder, "o", session->path); /* Create the cipher */ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) { g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); return FALSE; } secret = secret_value_get (value, &n_secret); /* Perform the encoding here */ padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded); g_assert (padded != NULL); /* Setup the IV */ iv = g_malloc0 (16); gcry_create_nonce (iv, 16); gcry = gcry_cipher_setiv (cih, iv, 16); g_return_val_if_fail (gcry == 0, FALSE); /* Setup the key */ gcry = gcry_cipher_setkey (cih, session->key, session->n_key); g_return_val_if_fail (gcry == 0, FALSE); /* Perform the encryption */ for (pos = 0; pos < n_padded; pos += 16) { gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0); g_return_val_if_fail (gcry == 0, FALSE); } gcry_cipher_close (cih); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv); g_variant_builder_add_value (builder, child); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded); g_variant_builder_add_value (builder, child); g_variant_builder_add (builder, "s", secret_value_get_content_type (value)); return TRUE; }
static gboolean is_password_value (SecretValue *value) { const gchar *content_type; const gchar *data; gsize length; content_type = secret_value_get_content_type (value); if (content_type && g_str_equal (content_type, "text/plain")) return TRUE; data = secret_value_get (value, &length); /* gnome-keyring-daemon used to return passwords like this, so support this, but validate */ if (!content_type || g_str_equal (content_type, "application/octet-stream")) return g_utf8_validate (data, length, NULL); return FALSE; }
static void write_password_data (SecretValue *value) { const gchar *at; gsize length; int r; at = secret_value_get (value, &length); while (length > 0) { r = write (1, at, length); if (r == -1) { if (errno != EAGAIN && errno != EINTR) { g_printerr ("%s: couldn't write password: %s\n", g_get_prgname (), g_strerror (errno)); exit (1); } } else { at += r; length -= r; } } }
static gboolean service_encode_plain_secret (SecretSession *session, SecretValue *value, GVariantBuilder *builder) { gconstpointer secret; gsize n_secret; GVariant *child; g_variant_builder_add (builder, "o", session->path); secret = secret_value_get (value, &n_secret); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL); g_variant_builder_add_value (builder, child); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE, secret_value_unref, secret_value_ref (value)); g_variant_builder_add_value (builder, child); g_variant_builder_add (builder, "s", secret_value_get_content_type (value)); return TRUE; }
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 */ }