Blame p11-kit/pin.c

Packit Service 3749ba
/*
Packit Service 3749ba
 * Copyright (C) 2011 Collabora Ltd.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Redistribution and use in source and binary forms, with or without
Packit Service 3749ba
 * modification, are permitted provided that the following conditions
Packit Service 3749ba
 * are met:
Packit Service 3749ba
 *
Packit Service 3749ba
 *     * Redistributions of source code must retain the above
Packit Service 3749ba
 *       copyright notice, this list of conditions and the
Packit Service 3749ba
 *       following disclaimer.
Packit Service 3749ba
 *     * Redistributions in binary form must reproduce the
Packit Service 3749ba
 *       above copyright notice, this list of conditions and
Packit Service 3749ba
 *       the following disclaimer in the documentation and/or
Packit Service 3749ba
 *       other materials provided with the distribution.
Packit Service 3749ba
 *     * The names of contributors to this software may not be
Packit Service 3749ba
 *       used to endorse or promote products derived from this
Packit Service 3749ba
 *       software without specific prior written permission.
Packit Service 3749ba
 *
Packit Service 3749ba
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit Service 3749ba
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit Service 3749ba
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit Service 3749ba
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit Service 3749ba
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 3749ba
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
Packit Service 3749ba
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Packit Service 3749ba
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Packit Service 3749ba
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit Service 3749ba
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
Packit Service 3749ba
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
Packit Service 3749ba
 * DAMAGE.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Author: Stef Walter <stefw@collabora.co.uk>
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
#include "config.h"
Packit Service 3749ba
Packit Service 3749ba
#define P11_DEBUG_FLAG P11_DEBUG_PIN
Packit Service 3749ba
#include "debug.h"
Packit Service 3749ba
#include "dict.h"
Packit Service 3749ba
#include "library.h"
Packit Service 3749ba
#include "message.h"
Packit Service 3749ba
#include "pkcs11.h"
Packit Service 3749ba
#include "p11-kit.h"
Packit Service 3749ba
#include "pin.h"
Packit Service 3749ba
#include "private.h"
Packit Service 3749ba
#include "array.h"
Packit Service 3749ba
Packit Service 3749ba
#include <assert.h>
Packit Service 3749ba
#include <errno.h>
Packit Service 3749ba
#include <fcntl.h>
Packit Service 3749ba
#include <stdlib.h>
Packit Service 3749ba
#include <string.h>
Packit Service 3749ba
#include <unistd.h>
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * SECTION:p11-kit-pin
Packit Service 3749ba
 * @title: PIN Callbacks
Packit Service 3749ba
 * @short_description: PIN Callbacks
Packit Service 3749ba
 *
Packit Service 3749ba
 * Applications can register a callback which will be called to provide a
Packit Service 3749ba
 * password associated with a given pin source.
Packit Service 3749ba
 *
Packit Service 3749ba
 * PKCS\#11 URIs can contain a 'pin-source' attribute. The value of this attribute
Packit Service 3749ba
 * is application dependent, but often references a file containing a PIN to
Packit Service 3749ba
 * use.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Using these functions, an applications or libraries can register a
Packit Service 3749ba
 * callback with p11_kit_pin_register_callback() to be called when a given
Packit Service 3749ba
 * 'pin-source' attribute value is requested. The application can then prompt
Packit Service 3749ba
 * the user or retrieve a PIN for the given context. These registered
Packit Service 3749ba
 * callbacks are only relevant and valid within the current process.
Packit Service 3749ba
 *
Packit Service 3749ba
 * A fallback callback can be registered by passing the %P11_KIT_PIN_FALLBACK
Packit Service 3749ba
 * value to p11_kit_pin_register_callback(). This fallback callback will be
Packit Service 3749ba
 * called for every 'pin-source' attribute request for which no callback has been
Packit Service 3749ba
 * directly registered.
Packit Service 3749ba
 *
Packit Service 3749ba
 * To request a PIN for a given 'pin-source' attribute, use the
Packit Service 3749ba
 * p11_kit_pin_request() function. If this function returns %NULL then either
Packit Service 3749ba
 * no callbacks were registered or none of them could handle the request.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If multiple callbacks are registered for the same PIN source, then they are
Packit Service 3749ba
 * called in last-registered-first-called order. They are called in turn until
Packit Service 3749ba
 * one of them can handle the request. Fallback callbacks are not called if
Packit Service 3749ba
 * a callback was registered specifically for a requested 'pin-source' attribute.
Packit Service 3749ba
 *
Packit Service 3749ba
 * PINs themselves are handled inside of P11KitPin structures. These are thread
Packit Service 3749ba
 * safe and allow the callback to specify how the PIN is stored in memory
Packit Service 3749ba
 * and freed. A callback can use p11_kit_pin_new_for_string() or related
Packit Service 3749ba
 * functions to create a PIN to be returned.
Packit Service 3749ba
 *
Packit Service 3749ba
 * For example in order to handle the following PKCS\#11 URI with a 'pin-source'
Packit Service 3749ba
 * attribute
Packit Service 3749ba
 *
Packit Service 3749ba
 * <literallayout>
Packit Service 3749ba
 *      pkcs11:id=\%69\%95\%3e\%5c\%f4\%bd\%ec\%91;pin-source=my-application
Packit Service 3749ba
 * </literallayout>
Packit Service 3749ba
 *
Packit Service 3749ba
 * an application could register a callback like this:
Packit Service 3749ba
 *
Packit Service 3749ba
 * <informalexample><programlisting>
Packit Service 3749ba
 * static P11KitPin*
Packit Service 3749ba
 * my_application_pin_callback (const char *pin_source, P11KitUri *pin_uri,
Packit Service 3749ba
 *                              const char *pin_description, P11KitPinFlags pin_flags,
Packit Service 3749ba
 *                              void *callback_data)
Packit Service 3749ba
 * {
Packit Service 3749ba
 *     return p11_kit_pin_new_from_string ("pin-value");
Packit Service 3749ba
 * }
Packit Service 3749ba
 *
Packit Service 3749ba
 * p11_kit_pin_register_callback ("my-application", my_application_pin_callback,
Packit Service 3749ba
 *                                NULL, NULL);
Packit Service 3749ba
 * </programlisting></informalexample>
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * P11KitPinFlags:
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_USER_LOGIN: The PIN is for a PKCS\#11 user type login.
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_SO_LOGIN: The PIN is for a PKCS\#11 security officer type login.
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_CONTEXT_LOGIN: The PIN is for a PKCS\#11 contect specific type login.
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_RETRY: The PIN is being requested again, due to an invalid previous PIN.
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_MANY_TRIES: The PIN has failed too many times, and few tries are left.
Packit Service 3749ba
 * @P11_KIT_PIN_FLAGS_FINAL_TRY: The PIN has failed too many times, and this is the last try.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Flags that are passed to p11_kit_pin_request() and registered callbacks.
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * P11_KIT_PIN_FALLBACK:
Packit Service 3749ba
 *
Packit Service 3749ba
 * Used with p11_kit_pin_register_callback() to register a fallback callback.
Packit Service 3749ba
 * This callback will be called if no other callback is registered for a 'pin-source'.
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
typedef struct _PinCallback {
Packit Service 3749ba
	/* Only used/modified within the lock */
Packit Service 3749ba
	int refs;
Packit Service 3749ba
Packit Service 3749ba
	/* Readonly after construct */
Packit Service 3749ba
	p11_kit_pin_callback func;
Packit Service 3749ba
	void *user_data;
Packit Service 3749ba
	p11_kit_pin_destroy_func destroy;
Packit Service 3749ba
} PinCallback;
Packit Service 3749ba
Packit Service 3749ba
/*
Packit Service 3749ba
 * Shared data between threads, protected by the mutex, a structure so
Packit Service 3749ba
 * we can audit thread safety easier.
Packit Service 3749ba
 */
Packit Service 3749ba
static struct _Shared {
Packit Service 3749ba
	p11_dict *pin_sources;
Packit Service 3749ba
} gl = { NULL };
Packit Service 3749ba
Packit Service 3749ba
static void*
Packit Service 3749ba
ref_pin_callback (void *pointer)
Packit Service 3749ba
{
Packit Service 3749ba
	PinCallback *cb = pointer;
Packit Service 3749ba
	cb->refs++;
Packit Service 3749ba
	return pointer;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static void
Packit Service 3749ba
unref_pin_callback (void *pointer)
Packit Service 3749ba
{
Packit Service 3749ba
	PinCallback *cb = pointer;
Packit Service 3749ba
	assert (cb->refs >= 1);
Packit Service 3749ba
Packit Service 3749ba
	cb->refs--;
Packit Service 3749ba
	if (cb->refs == 0) {
Packit Service 3749ba
		if (cb->destroy)
Packit Service 3749ba
			(cb->destroy) (cb->user_data);
Packit Service 3749ba
		free (cb);
Packit Service 3749ba
	}
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static bool
Packit Service 3749ba
register_callback_unlocked (const char *pin_source,
Packit Service 3749ba
                            PinCallback *cb)
Packit Service 3749ba
{
Packit Service 3749ba
	p11_array *callbacks = NULL;
Packit Service 3749ba
	char *name;
Packit Service 3749ba
Packit Service 3749ba
	name = strdup (pin_source);
Packit Service 3749ba
	return_val_if_fail (name != NULL, false);
Packit Service 3749ba
Packit Service 3749ba
	if (gl.pin_sources == NULL) {
Packit Service 3749ba
		gl.pin_sources = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal,
Packit Service 3749ba
		                               free, (p11_destroyer)p11_array_free);
Packit Service 3749ba
		return_val_if_fail (gl.pin_sources != NULL, false);
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	if (gl.pin_sources != NULL)
Packit Service 3749ba
		callbacks = p11_dict_get (gl.pin_sources, name);
Packit Service 3749ba
Packit Service 3749ba
	if (callbacks == NULL) {
Packit Service 3749ba
		callbacks = p11_array_new (unref_pin_callback);
Packit Service 3749ba
		return_val_if_fail (callbacks != NULL, false);
Packit Service 3749ba
		if (!p11_dict_set (gl.pin_sources, name, callbacks))
Packit Service 3749ba
			return_val_if_reached (false);
Packit Service 3749ba
		name = NULL;
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	if (!p11_array_push (callbacks, cb))
Packit Service 3749ba
		return_val_if_reached (false);
Packit Service 3749ba
Packit Service 3749ba
	free (name);
Packit Service 3749ba
	return true;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_register_callback:
Packit Service 3749ba
 * @pin_source: the 'pin-source' attribute this this callback is for
Packit Service 3749ba
 * @callback: the callback function
Packit Service 3749ba
 * @callback_data: data that will be passed to the callback
Packit Service 3749ba
 * @callback_destroy: a function that will be called with @callback_data when
Packit Service 3749ba
 *     the callback is unregistered.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Register a callback to handle PIN requests for a given 'pin-source' attribute.
Packit Service 3749ba
 * If @pin_source is set to P11_KIT_PIN_FALLBACK then this will be a fallback
Packit Service 3749ba
 * callback and will be called for requests for which no other callback has
Packit Service 3749ba
 * been specifically registered.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If multiple callbacks are registered for the same @pin_source value, then
Packit Service 3749ba
 * the last registered callback will be the first to be called.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: Returns negative if registering fails.
Packit Service 3749ba
 */
Packit Service 3749ba
int
Packit Service 3749ba
p11_kit_pin_register_callback (const char *pin_source,
Packit Service 3749ba
                               p11_kit_pin_callback callback,
Packit Service 3749ba
                               void *callback_data,
Packit Service 3749ba
                               p11_kit_pin_destroy_func callback_destroy)
Packit Service 3749ba
{
Packit Service 3749ba
	PinCallback *cb;
Packit Service 3749ba
	bool ret;
Packit Service 3749ba
Packit Service 3749ba
	return_val_if_fail (pin_source != NULL, -1);
Packit Service 3749ba
	return_val_if_fail (callback != NULL, -1);
Packit Service 3749ba
Packit Service 3749ba
	cb = calloc (1, sizeof (PinCallback));
Packit Service 3749ba
	return_val_if_fail (cb != NULL, -1);
Packit Service 3749ba
Packit Service 3749ba
	cb->refs = 1;
Packit Service 3749ba
	cb->func = callback;
Packit Service 3749ba
	cb->user_data = callback_data;
Packit Service 3749ba
	cb->destroy = callback_destroy;
Packit Service 3749ba
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
Packit Service 3749ba
	ret = register_callback_unlocked (pin_source, cb);
Packit Service 3749ba
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
Packit Service 3749ba
	return ret ? 0 : -1;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_unregister_callback:
Packit Service 3749ba
 * @pin_source: the 'pin-source' attribute the callback was registered for
Packit Service 3749ba
 * @callback: the callback function that was registered
Packit Service 3749ba
 * @callback_data: data that was registered for the callback
Packit Service 3749ba
 *
Packit Service 3749ba
 * Unregister a callback that was previously registered with the
Packit Service 3749ba
 * p11_kit_pin_register_callback() function. If more than one registered
Packit Service 3749ba
 * callback matches the given arguments, then only one of those will be
Packit Service 3749ba
 * removed.
Packit Service 3749ba
 */
Packit Service 3749ba
void
Packit Service 3749ba
p11_kit_pin_unregister_callback (const char *pin_source,
Packit Service 3749ba
                                 p11_kit_pin_callback callback,
Packit Service 3749ba
                                 void *callback_data)
Packit Service 3749ba
{
Packit Service 3749ba
	PinCallback *cb;
Packit Service 3749ba
	p11_array *callbacks;
Packit Service 3749ba
	unsigned int i;
Packit Service 3749ba
Packit Service 3749ba
	return_if_fail (pin_source != NULL);
Packit Service 3749ba
	return_if_fail (callback != NULL);
Packit Service 3749ba
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
Packit Service 3749ba
		if (gl.pin_sources) {
Packit Service 3749ba
			callbacks = p11_dict_get (gl.pin_sources, pin_source);
Packit Service 3749ba
			if (callbacks) {
Packit Service 3749ba
				for (i = 0; i < callbacks->num; i++) {
Packit Service 3749ba
					cb = callbacks->elem[i];
Packit Service 3749ba
					if (cb->func == callback && cb->user_data == callback_data) {
Packit Service 3749ba
						p11_array_remove (callbacks, i);
Packit Service 3749ba
						break;
Packit Service 3749ba
					}
Packit Service 3749ba
				}
Packit Service 3749ba
Packit Service 3749ba
				if (callbacks->num == 0)
Packit Service 3749ba
					p11_dict_remove (gl.pin_sources, pin_source);
Packit Service 3749ba
			}
Packit Service 3749ba
Packit Service 3749ba
			/* When there are no more pin sources, get rid of the hash table */
Packit Service 3749ba
			if (p11_dict_size (gl.pin_sources) == 0) {
Packit Service 3749ba
				p11_dict_free (gl.pin_sources);
Packit Service 3749ba
				gl.pin_sources = NULL;
Packit Service 3749ba
			}
Packit Service 3749ba
		}
Packit Service 3749ba
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_request:
Packit Service 3749ba
 * @pin_source: the 'pin-source' attribute that is being requested
Packit Service 3749ba
 * @pin_uri: a PKCS\#11 URI that the PIN is being requested for, optionally %NULL.
Packit Service 3749ba
 * @pin_description: a description of what the PIN is for, must not be %NULL.
Packit Service 3749ba
 * @pin_flags: various flags for this request
Packit Service 3749ba
 *
Packit Service 3749ba
 * Request a PIN for a given 'pin-source' attribute. The result depends on the
Packit Service 3749ba
 * registered callbacks.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If not %NULL, then the @pin_uri attribute should point to the thing that the
Packit Service 3749ba
 * PIN is being requested for. In most use cases this should be a PKCS\#11 URI
Packit Service 3749ba
 * pointing to a token.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The @pin_description should always be specified. It is a string describing
Packit Service 3749ba
 * what the PIN is for. For example this would be the token label, if the PIN
Packit Service 3749ba
 * is for a token.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If more than one callback is registered for the @pin_source, then the latest
Packit Service 3749ba
 * registered one will be called first. If that callback does not return a
Packit Service 3749ba
 * PIN, then the next will be called in turn.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If no callback is registered for @pin_source, then the fallback callbacks will
Packit Service 3749ba
 * be invoked in the same way. The fallback callbacks will not be called if any
Packit Service 3749ba
 * callback has been registered specifically for @pin_source.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The PIN returned should be released with p11_kit_pin_unref().
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: the PIN which should be released with p11_kit_pin_unref(), or %NULL
Packit Service 3749ba
 *     if no callback was registered or could proivde a PIN
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_request (const char *pin_source,
Packit Service 3749ba
                     P11KitUri *pin_uri,
Packit Service 3749ba
                     const char *pin_description,
Packit Service 3749ba
                     P11KitPinFlags pin_flags)
Packit Service 3749ba
{
Packit Service 3749ba
	PinCallback **snapshot = NULL;
Packit Service 3749ba
	unsigned int snapshot_count = 0;
Packit Service 3749ba
	p11_array *callbacks;
Packit Service 3749ba
	P11KitPin *pin;
Packit Service 3749ba
	unsigned int i;
Packit Service 3749ba
Packit Service 3749ba
	return_val_if_fail (pin_source != NULL, NULL);
Packit Service 3749ba
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
Packit Service 3749ba
		/* Find and ref the pin source data */
Packit Service 3749ba
		if (gl.pin_sources) {
Packit Service 3749ba
			callbacks = p11_dict_get (gl.pin_sources, pin_source);
Packit Service 3749ba
Packit Service 3749ba
			/* If we didn't find any snapshots try the global ones */
Packit Service 3749ba
			if (callbacks == NULL)
Packit Service 3749ba
				callbacks = p11_dict_get (gl.pin_sources, P11_KIT_PIN_FALLBACK);
Packit Service 3749ba
Packit Service 3749ba
			if (callbacks != NULL && callbacks->num) {
Packit Service 3749ba
				snapshot = memdup (callbacks->elem, sizeof (void *) * callbacks->num);
Packit Service 3749ba
				snapshot_count = callbacks->num;
Packit Service 3749ba
				for (i = 0; snapshot && i < snapshot_count; i++)
Packit Service 3749ba
					ref_pin_callback (snapshot[i]);
Packit Service 3749ba
			}
Packit Service 3749ba
		}
Packit Service 3749ba
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
Packit Service 3749ba
	if (snapshot == NULL)
Packit Service 3749ba
		return NULL;
Packit Service 3749ba
Packit Service 3749ba
	for (pin = NULL, i = snapshot_count; pin == NULL && i > 0; i--) {
Packit Service 3749ba
		pin = (snapshot[i - 1]->func) (pin_source, pin_uri, pin_description, pin_flags,
Packit Service 3749ba
		                               snapshot[i - 1]->user_data);
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
		for (i = 0; i < snapshot_count; i++)
Packit Service 3749ba
			unref_pin_callback (snapshot[i]);
Packit Service 3749ba
		free (snapshot);
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
Packit Service 3749ba
	return pin;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_callback:
Packit Service 3749ba
 * @pin_source: a 'pin-source' attribute string
Packit Service 3749ba
 * @pin_uri: a PKCS\#11 URI that the PIN is for, or %NULL
Packit Service 3749ba
 * @pin_description: a descrption of what the PIN is for
Packit Service 3749ba
 * @pin_flags: flags describing the PIN request
Packit Service 3749ba
 * @callback_data: data that was provided when registering this callback
Packit Service 3749ba
 *
Packit Service 3749ba
 * Represents a PIN callback function.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The various arguments are the same as the ones passed to
Packit Service 3749ba
 * p11_kit_pin_request(). The @callback_data argument was the one passed to
Packit Service 3749ba
 * p11_kit_pin_register_callback() when registering this callback.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The function should return %NULL if it could not provide a PIN, either
Packit Service 3749ba
 * because of an error or a user cancellation.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If a PIN is returned, it will be unreferenced by the caller. So it should be
Packit Service 3749ba
 * either newly allocated, or referenced before returning.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: A PIN or %NULL
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_destroy_func:
Packit Service 3749ba
 * @data: the data to destroy
Packit Service 3749ba
 *
Packit Service 3749ba
 * A function called to free or cleanup @data.
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_file_callback:
Packit Service 3749ba
 * @pin_source: a 'pin-source' attribute string
Packit Service 3749ba
 * @pin_uri: a PKCS\#11 URI that the PIN is for, or %NULL
Packit Service 3749ba
 * @pin_description: a descrption of what the PIN is for
Packit Service 3749ba
 * @pin_flags: flags describing the PIN request
Packit Service 3749ba
 * @callback_data: unused, should be %NULL
Packit Service 3749ba
 *
Packit Service 3749ba
 * This is a PIN callback function that looks up the 'pin-source' attribute in
Packit Service 3749ba
 * a file with that name. This can be used to enable the normal PKCS\#11 URI
Packit Service 3749ba
 * behavior described in the RFC.
Packit Service 3749ba
 *
Packit Service 3749ba
 * If @pin_flags contains the %P11_KIT_PIN_FLAGS_RETRY flag, then this
Packit Service 3749ba
 * callback will always return %NULL. This is to prevent endless loops
Packit Service 3749ba
 * where an application is expecting to interact with a prompter, but
Packit Service 3749ba
 * instead is interacting with this callback reading a file over and over.
Packit Service 3749ba
 *
Packit Service 3749ba
 * This callback fails on files larger than 4 Kilobytes.
Packit Service 3749ba
 *
Packit Service 3749ba
 * This callback is not registered by default. It may have security
Packit Service 3749ba
 * implications depending on the source of the PKCS\#11 URI and the PKCS\#11
Packit Service 3749ba
 * in use. To register it, use code like the following:
Packit Service 3749ba
 *
Packit Service 3749ba
 * <informalexample><programlisting>
Packit Service 3749ba
 * p11_kit_pin_register_callback (P11_KIT_PIN_FALLBACK, p11_kit_pin_file_callback,
Packit Service 3749ba
 *                                NULL, NULL);
Packit Service 3749ba
 * </programlisting></informalexample>
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: a referenced PIN with the file contents, or %NULL if the file
Packit Service 3749ba
 *          could not be read
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_file_callback (const char *pin_source,
Packit Service 3749ba
                           P11KitUri *pin_uri,
Packit Service 3749ba
                           const char *pin_description,
Packit Service 3749ba
                           P11KitPinFlags pin_flags,
Packit Service 3749ba
                           void *callback_data)
Packit Service 3749ba
{
Packit Service 3749ba
	const size_t block = 1024;
Packit Service 3749ba
	unsigned char *buffer;
Packit Service 3749ba
	unsigned char *memory;
Packit Service 3749ba
	size_t used, allocated;
Packit Service 3749ba
	int error = 0;
Packit Service 3749ba
	int fd;
Packit Service 3749ba
	int res;
Packit Service 3749ba
Packit Service 3749ba
	return_val_if_fail (pin_source != NULL, NULL);
Packit Service 3749ba
Packit Service 3749ba
	/* We don't support retries */
Packit Service 3749ba
	if (pin_flags & P11_KIT_PIN_FLAGS_RETRY)
Packit Service 3749ba
		return NULL;
Packit Service 3749ba
Packit Service 3749ba
	fd = open (pin_source, O_BINARY | O_RDONLY | O_CLOEXEC);
Packit Service 3749ba
	if (fd == -1)
Packit Service 3749ba
		return NULL;
Packit Service 3749ba
Packit Service 3749ba
	buffer = NULL;
Packit Service 3749ba
	used = 0;
Packit Service 3749ba
	allocated = 0;
Packit Service 3749ba
Packit Service 3749ba
	for (;;) {
Packit Service 3749ba
		if (used + block > 4096) {
Packit Service 3749ba
			error = EFBIG;
Packit Service 3749ba
			break;
Packit Service 3749ba
		}
Packit Service 3749ba
		if (used + block > allocated) {
Packit Service 3749ba
			memory = realloc (buffer, used + block);
Packit Service 3749ba
			if (memory == NULL) {
Packit Service 3749ba
				error = ENOMEM;
Packit Service 3749ba
				break;
Packit Service 3749ba
			}
Packit Service 3749ba
			buffer = memory;
Packit Service 3749ba
			allocated = used + block;
Packit Service 3749ba
		}
Packit Service 3749ba
Packit Service 3749ba
		res = read (fd, buffer + used, allocated - used);
Packit Service 3749ba
		if (res < 0) {
Packit Service 3749ba
			if (errno == EAGAIN)
Packit Service 3749ba
				continue;
Packit Service 3749ba
			error = errno;
Packit Service 3749ba
			break;
Packit Service 3749ba
		} else if (res == 0) {
Packit Service 3749ba
			break;
Packit Service 3749ba
		} else {
Packit Service 3749ba
			used += res;
Packit Service 3749ba
		}
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	close (fd);
Packit Service 3749ba
Packit Service 3749ba
	if (error != 0) {
Packit Service 3749ba
		free (buffer);
Packit Service 3749ba
		errno = error;
Packit Service 3749ba
		return NULL;
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	return p11_kit_pin_new_for_buffer (buffer, used, free);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * P11KitPin:
Packit Service 3749ba
 *
Packit Service 3749ba
 * A structure representing a PKCS\#11 PIN. There are no public fields
Packit Service 3749ba
 * visible in this structure. Use the various accessor functions.
Packit Service 3749ba
 */
Packit Service 3749ba
struct p11_kit_pin {
Packit Service 3749ba
	int ref_count;
Packit Service 3749ba
	unsigned char *buffer;
Packit Service 3749ba
	size_t length;
Packit Service 3749ba
	p11_kit_pin_destroy_func destroy;
Packit Service 3749ba
};
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_new:
Packit Service 3749ba
 * @value: the value of the PIN
Packit Service 3749ba
 * @length: the length of @value
Packit Service 3749ba
 *
Packit Service 3749ba
 * Create a new P11KitPin with the given PIN value. This function is
Packit Service 3749ba
 * usually used from within registered PIN callbacks.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Exactly @length bytes from @value are used. Null terminated strings,
Packit Service 3749ba
 * or encodings are not considered. A copy of the @value will be made.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: The newly allocated P11KitPin, which should be freed with
Packit Service 3749ba
 *          p11_kit_pin_unref() when no longer needed.
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_new (const unsigned char *value, size_t length)
Packit Service 3749ba
{
Packit Service 3749ba
	unsigned char *copy;
Packit Service 3749ba
	P11KitPin *pin;
Packit Service 3749ba
Packit Service 3749ba
	copy = malloc (length);
Packit Service 3749ba
	return_val_if_fail (copy != NULL, NULL);
Packit Service 3749ba
Packit Service 3749ba
	memcpy (copy, value, length);
Packit Service 3749ba
	pin = p11_kit_pin_new_for_buffer (copy, length, free);
Packit Service 3749ba
	return_val_if_fail (pin != NULL, NULL);
Packit Service 3749ba
Packit Service 3749ba
	return pin;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_new_for_string:
Packit Service 3749ba
 * @value: the value of the PIN
Packit Service 3749ba
 *
Packit Service 3749ba
 * Create a new P11KitPin for the given null-terminated string, such as a
Packit Service 3749ba
 * password. This function is usually used from within registered
Packit Service 3749ba
 * PIN callbacks.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The PIN will consist of the string not including the null terminator.
Packit Service 3749ba
 * String encoding is not considered. A copy of the @value will be made.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: The newly allocated P11KitPin, which should be freed with
Packit Service 3749ba
 *     p11_kit_pin_unref() when no longer needed.
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_new_for_string (const char *value)
Packit Service 3749ba
{
Packit Service 3749ba
	return p11_kit_pin_new ((const unsigned char *)value, strlen (value));
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_new_for_buffer:
Packit Service 3749ba
 * @buffer: the value of the PIN
Packit Service 3749ba
 * @length: the length of @buffer
Packit Service 3749ba
 * @destroy: if not %NULL, then called when PIN is destroyed.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Create a new P11KitPin which will use @buffer for the PIN value.
Packit Service 3749ba
 * This function is usually used from within registered PIN callbacks.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The buffer will not be copied. String encodings and null characters
Packit Service 3749ba
 * are not considered.
Packit Service 3749ba
 *
Packit Service 3749ba
 * When the last reference to this PIN is lost, then the @destroy callback
Packit Service 3749ba
 * function will be called passing @buffer as an argument. This allows the
Packit Service 3749ba
 * caller to use a buffer as a PIN without copying it.
Packit Service 3749ba
 *
Packit Service 3749ba
 * <informalexample><programlisting>
Packit Service 3749ba
 * char *buffer = malloc (128);
Packit Service 3749ba
 * P11KitPin *pin;
Packit Service 3749ba
 *  ....
Packit Service 3749ba
 * pin = p11_kit_pin_new_for_buffer (buffer, 128, free);
Packit Service 3749ba
 * </programlisting></informalexample>
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: The newly allocated P11KitPin, which should be freed with
Packit Service 3749ba
 *          p11_kit_pin_unref() when no longer needed.
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_new_for_buffer (unsigned char *buffer, size_t length,
Packit Service 3749ba
                            p11_kit_pin_destroy_func destroy)
Packit Service 3749ba
{
Packit Service 3749ba
	P11KitPin *pin;
Packit Service 3749ba
Packit Service 3749ba
	pin = calloc (1, sizeof (P11KitPin));
Packit Service 3749ba
	return_val_if_fail (pin != NULL, NULL);
Packit Service 3749ba
Packit Service 3749ba
	pin->ref_count = 1;
Packit Service 3749ba
	pin->buffer = buffer;
Packit Service 3749ba
	pin->length = length;
Packit Service 3749ba
	pin->destroy = destroy;
Packit Service 3749ba
Packit Service 3749ba
	return pin;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_get_value:
Packit Service 3749ba
 * @pin: the P11KitPin
Packit Service 3749ba
 * @length: a location to return the value length
Packit Service 3749ba
 *
Packit Service 3749ba
 * Get the PIN value from a P11KitPin. @length will be set to the
Packit Service 3749ba
 * length of the value.
Packit Service 3749ba
 *
Packit Service 3749ba
 * The value returned is owned by the P11KitPin and should not be modified.
Packit Service 3749ba
 * It remains valid as long as a reference to the PIN is held. The PIN value
Packit Service 3749ba
 * will not contain an extra null-terminator character.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: the value for the PIN.
Packit Service 3749ba
 */
Packit Service 3749ba
const unsigned char *
Packit Service 3749ba
p11_kit_pin_get_value (P11KitPin *pin, size_t *length)
Packit Service 3749ba
{
Packit Service 3749ba
	if (length)
Packit Service 3749ba
		*length = pin->length;
Packit Service 3749ba
	return pin->buffer;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_get_length
Packit Service 3749ba
 * @pin: the P11KitPin
Packit Service 3749ba
 *
Packit Service 3749ba
 * Get the length of the PIN value from a P11KitPin.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: the length of the PIN value.
Packit Service 3749ba
 */
Packit Service 3749ba
size_t
Packit Service 3749ba
p11_kit_pin_get_length (P11KitPin *pin)
Packit Service 3749ba
{
Packit Service 3749ba
	return pin->length;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_ref:
Packit Service 3749ba
 * @pin: the P11KitPin
Packit Service 3749ba
 *
Packit Service 3749ba
 * Add a reference to a P11KitPin. This should be matched with a later call
Packit Service 3749ba
 * to p11_kit_pin_unref(). As long as at least one reference is held, the PIN
Packit Service 3749ba
 * will remain valid and in memory.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Returns: the @pin pointer, for convenience sake.
Packit Service 3749ba
 */
Packit Service 3749ba
P11KitPin *
Packit Service 3749ba
p11_kit_pin_ref (P11KitPin *pin)
Packit Service 3749ba
{
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
Packit Service 3749ba
		pin->ref_count++;
Packit Service 3749ba
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
Packit Service 3749ba
	return pin;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/**
Packit Service 3749ba
 * p11_kit_pin_unref:
Packit Service 3749ba
 * @pin: the P11KitPin
Packit Service 3749ba
 *
Packit Service 3749ba
 * Remove a reference from a P11KitPin. When all references have been removed
Packit Service 3749ba
 * then the PIN will be freed and will no longer be in memory.
Packit Service 3749ba
 */
Packit Service 3749ba
void
Packit Service 3749ba
p11_kit_pin_unref (P11KitPin *pin)
Packit Service 3749ba
{
Packit Service 3749ba
	bool last = false;
Packit Service 3749ba
Packit Service 3749ba
	p11_lock ();
Packit Service 3749ba
Packit Service 3749ba
		last = (pin->ref_count == 1);
Packit Service 3749ba
		pin->ref_count--;
Packit Service 3749ba
Packit Service 3749ba
	p11_unlock ();
Packit Service 3749ba
Packit Service 3749ba
	if (last) {
Packit Service 3749ba
		if (pin->destroy)
Packit Service 3749ba
			(pin->destroy) (pin->buffer);
Packit Service 3749ba
		free (pin);
Packit Service 3749ba
	}
Packit Service 3749ba
}