/*	$CoreSDI: modules.c,v 1.28 2001/10/05 23:14:58 claudio Exp $	*/

/*
 *   Copyright (c) 2000, 2001, Core SDI S.A., Argentina
 *   All rights reserved
 *  
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither name of the Core SDI S.A. nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *  
 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef WIN32
#include <sys/param.h>
#endif

#ifdef __linux__
#include <netinet/in.h>		/* in_addr_t */
#endif

#ifndef WIN32
#include <dlfcn.h>
#endif

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sysdep.h"
#include "packet.h"
#include "version.h"
#include "resource.h"
#include "modtypes.h"
#include "modules.h"
#include "ia_list.h"
#include "iaargs.h"
#include "log.h"

static const char *_modules_path = NULL;


/*
 * _load()
 *	Load and initialize specified module.
 */
static void *
_load(const char *module_name, void *init_args)
{
	void * 		(*init)(void *);
	int		(*proc)(int, void *, void *);
	void		*h;
	void		*context;
	struct module	*mod;

	h = load_module(module_name);
	if (h == NULL)
		return (NULL);
	init = load_function(h, SYMBOL_PREFIX "init", 1);
	if (init != NULL) {
		context = init(init_args);
		if (context != NULL) {
			proc = load_function(h, SYMBOL_PREFIX "proc_entry", 1);
			if (proc != NULL) {
				mod = (struct module *) context;
				mod->handle = h;
				mod->proc_entry = proc;
				return (context);
			}
			release_module(context);
		}
		dlclose(h);
	}
	return (NULL);
}


/*
 * set_modules_path()
 *	Set modules path.
 */
void
set_modules_path(const char *path)
{
	_modules_path = path;
}


/*
 * full_module_pathname()
 *	Get full module path name; dst should have at least MAXPATHLEN bytes.
 */
char *
full_module_pathname(char *dst, const char *type, const char *modname)
{
	if (modname && dst) {
#ifndef WIN32
		if (_modules_path != NULL && *_modules_path != '\0')
			snprintf(dst, MAXPATHLEN, "%s/lib%s_%s.so."
			    AUDIT_VERSION, _modules_path, type, modname);
		else
			snprintf(dst, MAXPATHLEN, "lib%s_%s.so." AUDIT_VERSION,
			    type, modname);
#else
		snprintf(dst, MAXPATHLEN, "%s_%s.dll", type, modname);
#endif /* WIN32 */
	}
	return (dst);
}


/*
 * load_auth()
 *	Load authentication module and initialize context members.
 */
AUTHCON *
load_auth(const char *name, PACKET *packet)
{
	char	 fullname[MAXPATHLEN] = { "" };
	AUTHCON	*aucon;

	if (name != NULL) {
		log_debug("Loading '%s' authentication module.", name);
		full_module_pathname(fullname, "auth", name);
		aucon = (AUTHCON *) _load(fullname, NULL);
		if (aucon != NULL) {
			aucon->peername[0] = '\0';
			aucon->packet = packet;
			aucon->rlist = NULL;
		}
		return (aucon);
	}
	return (NULL);
}


/*
 * load_ia()
 *	Load information accessing module and initialize context members.
 */
IACON *
load_ia(const char *name)
{
	char	 fullname[MAXPATHLEN] = { "" };
	IACON	*iacon;

	if (name == NULL)
		return (NULL);

	log_debug("Loading '%s' information accessing module.", name);

	full_module_pathname(fullname, "ia", name);
	iacon = (IACON *) _load(fullname, NULL);
	return (iacon);
}


/*
 * load_attr():
 *	Load attribute module and initialize context members.
 */
ATTRCON *
load_attr(const char *name, SESSION *session, void *args)
{
	char	 fullname[MAXPATHLEN] = { "" };
	ATTRCON	*atcon;

	if (name == NULL)
		return (NULL);

	log_debug("Loading '%s' attribute module.", name);

	full_module_pathname(fullname, "attr", name);
	atcon = (ATTRCON *) _load(fullname, args);
	if (atcon != NULL)
		atcon->s = session;
	return (atcon);
}


/*
 * release_module()
 *	Release a module given its context.
 */
void
release_module(void *context)
{
	void	(*release)(void *);
	void	*h;

	if (context != NULL) {
		h = ((struct module *) context)->handle;
		release = load_function(h, SYMBOL_PREFIX "release", 0);
		if (release != NULL)
			release(context);
		else
			free(context);
		dlclose(h);
	}
}


/*
 * release_ia()
 *	Release an initialized IA module (l context member is a
 *	LOGSET_INFO pointer or NULL).
 */
void
release_ia(IACON *iacon)
{
	if (iacon != NULL) {
		release_logset_info(iacon->logset);
		release_module(iacon);
	}
}


/*
 * release_auth()
 *	Release an authentication module (do not close connection).
 */
void
release_auth(AUTHCON *aucon)
{
	if (aucon != NULL) {
		res_release_list(aucon->rlist);
		release_module((void *) aucon);
	}	
}


