static GP11Object*
create_credential (GP11Session *session, GP11Object *object,
                   const gchar *secret, GError **error)
{
	GP11Attributes *attrs;
	GP11Object *cred;

	g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
	g_return_val_if_fail (!object || GP11_IS_OBJECT (object), NULL);

	if (!secret)
		secret = "";

	attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_G_CREDENTIAL,
	                              CKA_VALUE, strlen (secret), secret,
	                              CKA_MATE_TRANSIENT, GP11_BOOLEAN, TRUE,
	                              CKA_TOKEN, GP11_BOOLEAN, TRUE,
	                              GP11_INVALID);

	if (object)
		gp11_attributes_add_ulong (attrs, CKA_G_OBJECT,
		                           gp11_object_get_handle (object));

	cred = gp11_session_create_object_full (session, attrs, NULL, error);
	gp11_attributes_unref (attrs);

	if (cred != NULL)
		gp11_object_set_session (cred, session);

	return cred;
}
static void
state_create_object (GcrImporter *self, gboolean async)
{
	GP11Attributes *attrs;
	GP11Object *object;
	GError *error = NULL;
	
	/* No more objects */
	if (g_queue_is_empty (&self->pv->queue)) {
		next_state (self, state_complete);
		
	} else {
		
		/* Pop first one off the list */
		attrs = g_queue_pop_head (&self->pv->queue);
		g_assert (attrs);
		
		gp11_attributes_add_boolean (attrs, CKA_TOKEN, CK_TRUE);
		
		if (async) {
			gp11_session_create_object_async (self->pv->session, attrs, self->pv->cancel, 
			                                  on_create_object, self);
		} else {
			object = gp11_session_create_object_full (self->pv->session, attrs, self->pv->cancel, &error);
			complete_create_object (self, object, error);
		}
	
		gp11_attributes_unref (attrs);
	}
}
static void
cleanup_state_data (GcrImporter *self)
{
	GP11Attributes *attrs;
	
	if (self->pv->buffer)
		g_byte_array_free (self->pv->buffer, TRUE);
	self->pv->buffer = NULL;
	
	if (self->pv->session)
		g_object_unref (self->pv->session);
	self->pv->session = NULL;
	
	while ((attrs = g_queue_pop_head (&self->pv->queue)) != NULL)
		gp11_attributes_unref (attrs);
	g_assert (g_queue_is_empty (&self->pv->queue));
	
	if (self->pv->input)
		g_object_unref (self->pv->input);
	self->pv->input = NULL;
	
	if (self->pv->cancel)
		g_object_unref (self->pv->cancel);
	self->pv->cancel = NULL;
}
/**
 * gp11_object_get:
 * @self: The object to get attributes from.
 * @err: A location to store an error.
 * @...: The attribute types to get.
 *
 * Get the specified attributes from the object. This call may
 * block for an indefinite period.
 * 
 * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
 * The result must be unreffed when you're finished with it.
 **/
GP11Attributes*
gp11_object_get (GP11Object *self, GError **err, ...)
{
	GP11Attributes *attrs;
	va_list va;
	gulong type;
	
	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
	g_return_val_if_fail (!err || !*err, NULL);

	attrs = gp11_attributes_new ();
	va_start (va, err);
	for (;;) {
		type = va_arg (va, gulong);
		if (type == GP11_INVALID)
			break;
		gp11_attributes_add_invalid (attrs, type);
	}
	va_end (va);
	
	if (!gp11_object_get_full (self, attrs, NULL, err)) {
		gp11_attributes_unref (attrs);
		return NULL;
	}

	return attrs;
}
static void
free_set_attributes (SetAttributes *args)
{
	g_assert (args);
	gp11_attributes_unref (args->attrs);
	g_free (args);
}
/**
 * gp11_object_get_template_full:
 * @self: The object to get an attribute template from.
 * @attr_type: The template attribute type.
 * @cancellable: Optional cancellation object, or NULL.
 * @err: A location to store an error.
 *
 * Get an attribute template from the object. The attr_type must be for
 * an attribute which returns a template.
 *
 * This call may block for an indefinite period.
 *
 * Return value: The resulting PKCS#11 attribute template, or NULL if an error occurred.
 **/
GP11Attributes*
gp11_object_get_template_full (GP11Object *self, gulong attr_type,
                               GCancellable *cancellable, GError **err)
{
	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
	get_template_args args;
	GP11Session *session;
	gboolean ret;

	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
	g_return_val_if_fail (!err || !*err, NULL);

	session = require_session_sync (self, 0, err);
	if (!session)
		return NULL;

	memset (&args, 0, sizeof (args));
	args.object = data->handle;
	args.type = attr_type;

	ret = _gp11_call_sync (session, perform_get_template, NULL, &args, cancellable, err);
	g_object_unref (session);

	_gp11_attributes_unlock (args.attrs);

	/* Free any value if failed */
	if (!ret) {
		gp11_attributes_unref (args.attrs);
		args.attrs = NULL;
	}

	return args.attrs;
}
static void
free_get_template (get_template_args *args)
{
	g_assert (args);
	gp11_attributes_unref (args->attrs);
	g_free (args);
}
static DBusMessage*
service_method_create_collection (GkdSecretService *self, DBusMessage *message)
{
	DBusMessageIter iter, array;
	GP11Attributes *attrs;
	GkdSecretCreate *create;
	ServiceClient *client;
	DBusMessage *reply;
	const gchar *path;
	const char *caller;
	const gchar *coll;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "a{sv}"))
		return NULL;
	if (!dbus_message_iter_init (message, &iter))
		g_return_val_if_reached (NULL);
	attrs = gp11_attributes_new ();
	dbus_message_iter_recurse (&iter, &array);
	if (!gkd_secret_property_parse_all (&array, attrs)) {
		gp11_attributes_unref (attrs);
		return dbus_message_new_error_printf (message, DBUS_ERROR_INVALID_ARGS,
		                                      "Invalid properties");
	}

	gp11_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);

	/* Create the prompt object, for the password */
	caller = dbus_message_get_sender (message);
	create = gkd_secret_create_new (self, caller, attrs);
	gp11_attributes_unref (attrs);

	path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
	client = g_hash_table_lookup (self->clients, caller);
	g_return_val_if_fail (client, NULL);
	g_hash_table_replace (client->prompts, (gpointer)path, create);

	coll = "/";
	reply = dbus_message_new_method_return (message);
	dbus_message_append_args (reply,
	                          DBUS_TYPE_OBJECT_PATH, &coll,
	                          DBUS_TYPE_OBJECT_PATH, &path,
	                          DBUS_TYPE_INVALID);

	return reply;
}
static DBusMessage*
service_method_create_with_master_password (GkdSecretService *self, DBusMessage *message)
{
	DBusError derr = DBUS_ERROR_INIT;
	DBusMessageIter iter, array;
	DBusMessage *reply = NULL;
	GkdSecretSecret *secret = NULL;
	GP11Attributes *attrs = NULL;
	gchar *path;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "a{sv}(oayay)"))
		return NULL;
	if (!dbus_message_iter_init (message, &iter))
		g_return_val_if_reached (NULL);
	attrs = gp11_attributes_new ();
	dbus_message_iter_recurse (&iter, &array);
	if (!gkd_secret_property_parse_all (&array, attrs)) {
		gp11_attributes_unref (attrs);
		return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
		                               "Invalid properties argument");
	}
	dbus_message_iter_next (&iter);
	secret = gkd_secret_secret_parse (self, message, &iter, &derr);
	if (secret == NULL) {
		gp11_attributes_unref (attrs);
		return gkd_secret_error_to_reply (message, &derr);
	}

	gp11_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
	path = gkd_secret_create_with_secret (attrs, secret, &derr);
	gp11_attributes_unref (attrs);
	gkd_secret_secret_free (secret);

	if (path == NULL)
		return gkd_secret_error_to_reply (message, &derr);

	reply = dbus_message_new_method_return (message);
	dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
	g_free (path);

	return reply;
}
/**
 * gp11_object_set:
 * @self: The object to set attributes on.
 * @err: A location to return an error.
 * @...: The attributes to set.
 *
 * Set PKCS#11 attributes on an object.
 * This call may block for an indefinite period.
 * 
 * The arguments must be triples of: attribute type, data type, value
 * 
 * <para>The variable argument list should contain:
 * 	<variablelist>
 *		<varlistentry>
 * 			<term>a)</term>
 * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
 * 		</varlistentry>
 * 		<varlistentry>
 * 			<term>b)</term>
 * 			<listitem><para>The attribute data type (one of GP11_BOOLEAN, GP11_ULONG, 
 * 				GP11_STRING, GP11_DATE) orthe raw attribute value length.</para></listitem>
 * 		</varlistentry>
 * 		<varlistentry>
 * 			<term>c)</term>
 * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or 
 * 				a pointer to a raw attribute value.</para></listitem>
 * 		</varlistentry>
 * 	</variablelist>
 * The variable argument list should be terminated with GP11_INVALID.</para> 
 * 
 * Return value: Whether the call was successful or not.
 **/
gboolean
gp11_object_set (GP11Object *self, GError **err, ...)
{
	GP11Attributes *attrs;
	va_list va;
	CK_RV rv;
	
	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
	g_return_val_if_fail (!err || !*err, FALSE);
	
	va_start (va, err);
	attrs = gp11_attributes_new_valist (g_realloc, va);
	va_end (va);
	
	rv = gp11_object_set_full (self, attrs, NULL, err);
	
	gp11_attributes_unref (attrs);
	return rv;
}
예제 #11
0
static void 
on_open_session(GP11Slot *slot, GAsyncResult *result, SeahorsePkcs11Refresher *self) 
{
	GError *err = NULL;
	GP11Attributes *attrs;
	
	g_return_if_fail (SEAHORSE_IS_PKCS11_REFRESHER (self));
	
	self->session = gp11_slot_open_session_finish (slot, result, &err);
	if (!self->session) {
		seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), err);
		return;
	}
	
	/* Step 2. Load all the objects that we want */
	attrs = gp11_attributes_new ();
	gp11_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
	gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
	gp11_session_find_objects_async (self->session, attrs, self->cancellable, 
	                                 (GAsyncReadyCallback)on_find_objects, self);
	gp11_attributes_unref (attrs);
}
/**
 * gp11_module_enumerate_objects:
 * @self: The module to enumerate objects.
 * @func: Function to call for each object.
 * @user_data: Data to pass to the function.
 * @...: The arguments must be triples of: attribute type, data type, value.
 *
 * Call a function for every matching object on the module. This call may 
 * block for an indefinite period.
 * 
 * 
 * <para>The variable argument list should contain:
 * 	<variablelist>
 *		<varlistentry>
 * 			<term>a)</term>
 * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
 * 		</varlistentry>
 * 		<varlistentry>
 * 			<term>b)</term>
 * 			<listitem><para>The attribute data type (one of GP11_BOOLEAN, GP11_ULONG, 
 * 				GP11_STRING, GP11_DATE) orthe raw attribute value length.</para></listitem>
 * 		</varlistentry>
 * 		<varlistentry>
 * 			<term>c)</term>
 * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or 
 * 				a pointer to a raw attribute value.</para></listitem>
 * 		</varlistentry>
 * 	</variablelist>
 * The variable argument list should be terminated with GP11_INVALID.</para>
 * 
 * This function will open a session per slot. It's recommended that you 
 * set the 'reuse-sessions' property on each slot if you'll be calling 
 * it a lot.
 * 
 * You can access the session in which the object was found, by using the 
 * gp11_object_get_session() function on the resulting objects.
 * 
 * This function skips tokens that are not initialize, and makes a best effort to 
 * find objects on valid tokens. 
 * 
 * The function can return FALSE to stop the enumeration.
 * 
 * Return value: If FALSE then an error prevented all matching objects from being enumerated.
 **/
gboolean
gp11_module_enumerate_objects (GP11Module *self, GP11ObjectForeachFunc func,
                               gpointer user_data, ...)
{
	GP11Attributes *attrs;
	GError *error = NULL;
	va_list va;
	
	va_start (va, user_data);
	attrs = gp11_attributes_new_valist (g_realloc, va);
	va_end (va);

	gp11_module_enumerate_objects_full (self, attrs, NULL, func, user_data, &error);
	gp11_attributes_unref (attrs);
	
	if (error != NULL) {
		g_warning ("enumerating objects failed: %s", error->message);
		g_clear_error (&error);
		return FALSE;
	}
	
	return TRUE;
}
/**
 * gp11_module_enumerate_objects_full:
 * @self: The module to enumerate objects.
 * @attrs: Attributes that the objects must have, or empty for all objects.
 * @cancellable: Optional cancellation object, or NULL.
 * @func: Function to call for each object.
 * @user_data: Data to pass to the function.
 * @error: Location to return error information.
 * 
 * Call a function for every matching object on the module. This call may 
 * block for an indefinite period. 
 * 
 * This function will open a session per slot. It's recommended that you 
 * set the 'reuse-sessions' property on each slot if you'll be calling 
 * it a lot.
 * 
 * You can access the session in which the object was found, by using the 
 * gp11_object_get_session() function on the resulting objects.
 * 
 * The function can return FALSE to stop the enumeration.
 * 
 * Return value: If FALSE then an error prevented all matching objects from being enumerated.
 **/
gboolean
gp11_module_enumerate_objects_full (GP11Module *self, GP11Attributes *attrs, 
                                    GCancellable *cancellable, GP11ObjectForeachFunc func, 
                                    gpointer user_data, GError **err)
{
	gboolean stop = FALSE;
	gboolean ret = TRUE;
	GList *objects, *o;
	GList *slots, *l;
	GError *error = NULL;
	GP11Session *session;
	
	g_return_val_if_fail (GP11_IS_MODULE (self), FALSE);
	g_return_val_if_fail (attrs, FALSE);
	g_return_val_if_fail (func, FALSE);
	
	gp11_attributes_ref (attrs);
	slots = gp11_module_get_slots (self, TRUE);
	
	for (l = slots; ret && !stop && l; l = g_list_next (l)) {

		/* TODO: We really should allow the caller to specify the flags, at least read-write */
		session = gp11_slot_open_session (l->data, CKF_RW_SESSION | CKF_SERIAL_SESSION, &error);
		if (!session) {
			g_return_val_if_fail (error != NULL, FALSE);
			
			/* Ignore these errors when enumerating */
			if (g_error_matches (error, GP11_ERROR, CKR_USER_PIN_NOT_INITIALIZED)) {
				g_clear_error (&error);
				
			} else {
				ret = FALSE;
				g_propagate_error (err, error);
				error = NULL;
			}
			continue;
		}
		
		objects = gp11_session_find_objects_full (session, attrs, cancellable, &error);
		if (error) {
			ret = FALSE;
			g_object_unref (session);
			g_propagate_error (err, error);
			error = NULL;
			continue;
		}
		
		for (o = objects; !stop && o; o = g_list_next (o)) {
			gp11_object_set_session (o->data, session);
			if (!(func)(o->data, user_data)) {
				stop = TRUE;
				break;
			}
		}
		
		g_object_unref (session);
		gp11_list_unref_free (objects);
	}
	
	gp11_list_unref_free (slots);
	gp11_attributes_unref (attrs);
	
	return ret;
}