static void
gkm_ssh_module_class_init (GkmSshModuleClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
	GkmModuleClass *module_class = GKM_MODULE_CLASS (klass);

	gobject_class->constructor = gkm_ssh_module_constructor;
	gobject_class->dispose = gkm_ssh_module_dispose;
	gobject_class->finalize = gkm_ssh_module_finalize;

	module_class->get_slot_info = gkm_ssh_module_real_get_slot_info;
	module_class->get_token_info = gkm_ssh_module_real_get_token_info;
	module_class->parse_argument = gkm_ssh_module_real_parse_argument;
	module_class->refresh_token = gkm_ssh_module_real_refresh_token;
}
static CK_RV
gkm_user_module_real_login_so (GkmModule *base, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
{
	GkmUserModule *self = GKM_USER_MODULE (base);

	/* See if this application has unlocked, in which case we can't login */
	if (g_hash_table_lookup (self->unlocked_apps, &slot_id))
		return CKR_USER_ALREADY_LOGGED_IN;

	/* Note that for an SO login, we don't actually unlock, and pin is always blank */
	if (n_pin != 0)
		return CKR_PIN_INCORRECT;

	return GKM_MODULE_CLASS (gkm_user_module_parent_class)->login_so (base, slot_id, pin, n_pin);
}
static CK_RV
gkm_user_module_real_logout_user (GkmModule *base, CK_SLOT_ID slot_id)
{
	GkmUserModule *self = GKM_USER_MODULE (base);
	CK_RV rv;

	if (!g_hash_table_remove (self->unlocked_apps, &slot_id))
		return CKR_USER_NOT_LOGGED_IN;

	if (g_hash_table_size (self->unlocked_apps) > 0)
		return CKR_OK;

	rv = gkm_user_storage_lock (self->storage);
	if (rv == CKR_OK)
		rv = GKM_MODULE_CLASS (gkm_user_module_parent_class)->logout_user (base, slot_id);

	return rv;
}
static CK_RV
gkm_user_module_real_login_user (GkmModule *base, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
{
	GkmUserModule *self = GKM_USER_MODULE (base);
	GkmSecret *login;
	CK_RV rv;

	/* See if this application has logged in */
	if (g_hash_table_lookup (self->unlocked_apps, &slot_id))
		return CKR_USER_ALREADY_LOGGED_IN;

	login = gkm_user_storage_get_login (self->storage);

	/* No application is logged in */
	if (g_hash_table_size (self->unlocked_apps) == 0) {

		g_return_val_if_fail (login == NULL, CKR_GENERAL_ERROR);

		/* So actually unlock the store */
		login = gkm_secret_new_from_login (pin, n_pin);
		rv = gkm_user_storage_unlock (self->storage, login);
		g_object_unref (login);

	/* An application is already logged in */
	} else {

		g_return_val_if_fail (login != NULL, CKR_GENERAL_ERROR);

		/* Compare our pin to the one used originally */
		if (!gkm_secret_equals (login, pin, n_pin))
			rv = CKR_PIN_INCORRECT;
		else
			rv = CKR_OK;
	}

	/* Note that this application logged in */
	if (rv == CKR_OK) {
		g_hash_table_insert (self->unlocked_apps, gkm_util_ulong_alloc (slot_id), UNUSED_VALUE);
		rv = GKM_MODULE_CLASS (gkm_user_module_parent_class)->login_user (base, slot_id, pin, n_pin);
	}

	return rv;
}
static void
gkm_user_module_class_init (GkmUserModuleClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
	GkmModuleClass *module_class = GKM_MODULE_CLASS (klass);

	gobject_class->constructor = gkm_user_module_constructor;
	gobject_class->dispose = gkm_user_module_dispose;
	gobject_class->finalize = gkm_user_module_finalize;

	module_class->get_slot_info = gkm_user_module_real_get_slot_info;
	module_class->get_token_info = gkm_user_module_real_get_token_info;
	module_class->parse_argument = gkm_user_module_real_parse_argument;
	module_class->refresh_token = gkm_user_module_real_refresh_token;
	module_class->add_token_object = gkm_user_module_real_add_token_object;
	module_class->store_token_object = gkm_user_module_real_store_token_object;
	module_class->remove_token_object = gkm_user_module_real_remove_token_object;
	module_class->login_user = gkm_user_module_real_login_user;
	module_class->login_so = gkm_user_module_real_login_so;
	module_class->logout_user = gkm_user_module_real_logout_user;
	module_class->login_change = gkm_user_module_real_login_change;
}