static void
modem_get_sim_ready (MMModem *modem,
                     GAsyncResult *res,
                     BroadbandDeviceInfo *info)
{
	GHashTable *attrs;

	info->mm_sim = mm_modem_get_sim_finish (modem, res, NULL);
	if (!info->mm_sim)
		/* Ok, the modem may not need it actually */
		return;

	/* Do nothing if we're not locked */
	if (mm_modem_get_state (info->mm_modem) != MM_MODEM_STATE_LOCKED)
		return;

	/* If we have a device ID ask the keyring for any saved SIM-PIN codes */
	if (mm_modem_get_device_identifier (info->mm_modem) &&
	    mm_modem_get_unlock_required (info->mm_modem) == MM_MODEM_LOCK_SIM_PIN) {
		attrs = secret_attributes_build (&mobile_secret_schema, "devid",
		                                 mm_modem_get_device_identifier (info->mm_modem),
		                                 NULL);
		secret_service_search (NULL, &mobile_secret_schema, attrs,
		                       SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
		                       info->cancellable, keyring_pin_check_cb, info);
		g_hash_table_unref (attrs);
	} else {
		/* Couldn't get a device ID, but unlock required; present dialog */
		unlock_dialog_new (info->device, info);
	}

	/* Couldn't get a device ID, but unlock required; present dialog */
	unlock_dialog_new (info->device, info);
}
static void
get_secrets (NMSecretAgent *agent,
             NMConnection *connection,
             const char *connection_path,
             const char *setting_name,
             const char **hints,
             guint32 flags,
             NMSecretAgentGetSecretsFunc callback,
             gpointer callback_data)
{
	AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent);
	Request *r;
	GError *error = NULL;
	NMSettingConnection *s_con;
	NMSetting *setting;
	const char *uuid, *ctype;
	GHashTable *attrs;

	setting = nm_connection_get_setting_by_name (connection, setting_name);
	if (!setting) {
		error = g_error_new (NM_SECRET_AGENT_ERROR,
		                     NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
		                     "%s.%d - Connection didn't have requested setting '%s'.",
		                     __FILE__, __LINE__, setting_name);
		callback (agent, connection, NULL, error, callback_data);
		g_error_free (error);
		return;
	}

	uuid = nm_connection_get_uuid (connection);

	s_con = nm_connection_get_setting_connection (connection);
	g_assert (s_con);
	ctype = nm_setting_connection_get_connection_type (s_con);

	if (!uuid || !ctype) {
		error = g_error_new (NM_SECRET_AGENT_ERROR,
		                     NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
		                     "%s.%d - Connection didn't have required UUID.",
		                     __FILE__, __LINE__);
		callback (agent, connection, NULL, error, callback_data);
		g_error_free (error);
		return;
	}

	/* Track the secrets request */
	r = request_new (agent, connection, connection_path, setting_name, hints, flags, callback, NULL, NULL, callback_data);
	g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r);

	/* VPN passwords are handled by the VPN plugin's auth dialog */
	if (!strcmp (ctype, NM_SETTING_VPN_SETTING_NAME)) {
		ask_for_secrets (r);
		return;
	}

	/* Only handle non-VPN secrets if we're supposed to */
	if (priv->vpn_only == TRUE) {
		error = g_error_new_literal (NM_SECRET_AGENT_ERROR,
		                             NM_SECRET_AGENT_ERROR_NO_SECRETS,
		                             "Only handling VPN secrets at this time.");
		callback (agent, connection, NULL, error, callback_data);
		g_error_free (error);
		return;
	}

	/* For everything else we scrape the keyring for secrets first, and ask
	 * later if required.
	 */
	attrs = secret_attributes_build (&network_manager_secret_schema,
	                                 KEYRING_UUID_TAG, uuid,
	                                 KEYRING_SN_TAG, setting_name,
	                                 NULL);

	secret_service_search (NULL, &network_manager_secret_schema, attrs,
	                       SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
	                       r->cancellable, keyring_find_secrets_cb, r);

	r->keyring_calls++;
	g_hash_table_unref (attrs);
}
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
}