/* libp11, a simple layer on to of PKCS#11 API
 * Copyright (C) 2005 Olaf Kirch <okir@lst.de>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

/*
 * Convenience pkcs11 library that can be linked into an application,
 * and will bind to a specific pkcs11 module.
 *
 * Copyright (C) 2002  Olaf Kirch <okir@lst.de>
 */

#include "libp11-int.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

#define MAGIC			0xd00bed00

struct sc_pkcs11_module {
	unsigned int _magic;
	void *handle;
};
typedef struct sc_pkcs11_module sc_pkcs11_module_t;

/*
 * Load a module - this will load the shared object, call
 * C_Initialize, and get the list of function pointers
 */
void *
C_LoadModule(const char *mspec, CK_FUNCTION_LIST_PTR_PTR funcs)
{
	sc_pkcs11_module_t *mod;
	CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
	int rv;

	if (!mspec)
		return NULL;

	mod = OPENSSL_malloc(sizeof(sc_pkcs11_module_t));
	if (!mod)
		return NULL;
	memset(mod, 0, sizeof(sc_pkcs11_module_t));
	mod->_magic = MAGIC;

#ifdef WIN32
	mod->handle = LoadLibraryA(mspec);
#else
	mod->handle = dlopen(mspec, RTLD_LAZY | RTLD_LOCAL);
#endif

	if (!mod->handle) {
#ifndef WIN32
		fprintf(stderr, "%s\n", dlerror());
#endif
		goto failed;
	}

#ifdef WIN32
	c_get_function_list = (CK_C_GetFunctionList)
		GetProcAddress(mod->handle, "C_GetFunctionList");
#else
	{
		/*
		 * Make compiler happy!
		 */
		void *p = dlsym(mod->handle, "C_GetFunctionList");
		memmove(&c_get_function_list, &p, sizeof(void *));
	}
#endif

	if (!c_get_function_list) {
#ifndef WIN32
		fprintf(stderr, "%s\n", dlerror());
#endif
		goto failed;
	}
	rv = c_get_function_list(funcs);
	if (rv == CKR_OK)
		return mod;

failed:
	C_UnloadModule((void *) mod);
	return NULL;
}

/*
 * Unload a pkcs11 module.
 * The calling application is responsible for cleaning up
 * and calling C_Finalize
 */
CK_RV
C_UnloadModule(void *module)
{
	sc_pkcs11_module_t *mod = (sc_pkcs11_module_t *) module;

	if (!mod || mod->_magic != MAGIC)
		return CKR_ARGUMENTS_BAD;

	if (mod->handle) {
#ifdef WIN32
		FreeLibrary(mod->handle);
#else
		dlclose(mod->handle);
#endif
	}

	memset(mod, 0, sizeof(sc_pkcs11_module_t));
	OPENSSL_free(mod);

	return CKR_OK;
}

/* vim: set noexpandtab: */
