view waaad/security.c @ 328:502470023dc5

Fix possible issue in sec_getmodules
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 19 Mar 2009 13:27:07 +0900
parents efbca5bc0d9f
children e86dba02630a
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2008, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * 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.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.								 *
*********************************************************************************************************/

/* Security module.
 * 
 * See security.h and security-api.h for more information on the functions and types involved.
 */

#include "waaad-internal.h"

/* Type of a security module list item = sec_mod_hdl_t */
typedef struct {
	uti_list_t	links;	/* List is ordered by module's insecid. the "o" field of the list points to the sec_module_t of this item. */
	int		peers;	/* Number of peers using this module */
} _smh_t;

#define _SMH( _o )  ((_smh_t *)( _o ))
#define _SM( _smh ) ((sec_module_t *)( _LIST(_smh)->o ))

/* The mutex to protect the list */
static pthread_mutex_t 	smh_lock = PTHREAD_MUTEX_INITIALIZER;

/* The list sentinel */
static uti_list_t  smh_senti;

/* Initialize the module */
int sec_init ( void )
{
	TRACE_ENTRY( "" );
	
	uti_list_init(&smh_senti, NULL);
	
	return 0;
}

/* End of the module */
int sec_fini ( void )
{
	TRACE_ENTRY( "" );
	
	/* Unregister any remaining module */
	while (! IS_LIST_EMPTY( &smh_senti ) ) {
		CHECK_FCT(	sec_unregister((sec_mod_hdl_t *)smh_senti.next)	);
	}
	
	return 0;
}

/* Increment a refcount of a module */
int sec_modlink(sec_mod_hdl_t * module)
{
	TRACE_ENTRY( "%p" );
	
	/* Get the mutex */
	CHECK_POSIX(	pthread_mutex_lock(&smh_lock)	);
	
	_SMH(module)->peers ++ ;
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	return 0;
}
	
/* Decrement a refcount of a module */
int sec_modunlink(sec_mod_hdl_t * module)
{
	TRACE_ENTRY( "%p" );
	
	/* Get the mutex */
	CHECK_POSIX(	pthread_mutex_lock(&smh_lock)	);
	
	_SMH(module)->peers -- ;
	/* This counter is just an indication, we don't use it to free the module when no more user remains. */
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	return 0;
}

/* Find a module by its insecid */
int sec_module(uint32_t insecid, _sec_item_t *module)
{
	uti_list_t * li;
	
	TRACE_ENTRY( "%d %p", insecid, module );
	
	CHECK_PARAMS(  module != NULL  );
	
	memset(module, 0, sizeof(_sec_item_t));
	
	/* Get the mutex */
	CHECK_POSIX(	pthread_mutex_lock(&smh_lock)	);
	
	/* Seach a corresponding module */
	for (li = smh_senti.next; li != &smh_senti; li = li->next) {
		
		if (_SM(li)->sec_insecid < insecid)
			continue;
		
		if (_SM(li)->sec_insecid > insecid)
			break;
		
		/* We found it */
		uti_list_init(_LIST(module), _SM(li));
		module->hdl= (sec_mod_hdl_t *) li;
		/* increment the refcount of this module */
		_SMH(li)->peers ++;
		
		break;
	}
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	return 	(module->hdl == NULL) ? ENOENT : 0;
}

/* Return the module corresponding to a handler */
int sec_getmodfromhdl(sec_mod_hdl_t * hdl, sec_module_t ** mod)
{
	CHECK_PARAMS( hdl && mod );
	*mod = _SM(hdl);
	return 0;
}
	
/* Create a list of _sec_item_t: modules able to handle a peer */
int sec_getmodules(char * diamid, sSA * sa, uti_list_t *modules)
{
	int ret = 0;
	uti_list_t * li;
	
	TRACE_ENTRY( "%s %p %p", diamid, sa, modules );
	
	CHECK_PARAMS(  diamid && sa && modules  );
	
	/* Initialize the module list */
	uti_list_init(modules, NULL);
	
	/* Get the mutex */
	CHECK_POSIX(	pthread_mutex_lock(&smh_lock)	);
	
	/* For each module */
	for (li = smh_senti.next; li != &smh_senti; li = li->next) {
		_sec_item_t * new;
		uti_list_t * prev;
		int prio;
		
		/* Get the priority of this module */
		ret = _SM(li)->sec_is_supported_peer(diamid, sa, &prio);
		if (ret != 0) {
			TRACE_DEBUG(INFO, "The security module with insecid: %d failed to give a priority to peer %s: %s",
					_SM(li)->sec_insecid, diamid, strerror(ret));
			continue;
		}
		
		/* does that module handle this peer? */
		if (prio < 0) {
			TRACE_DEBUG(FULL, "Security module with insecid: %d will not handle peer %s (%d)",
					_SM(li)->sec_insecid, diamid, prio);
			continue;
		}
		
		/* Create a new element */
		
		CHECK_MALLOC_DO( new = (_sec_item_t *) malloc(sizeof(_sec_item_t)),
			{ ret = ENOMEM;	goto failed; }  );
		
		memset(new, 0, sizeof(_sec_item_t));
		uti_list_init(&new->chain, _SM(li));
		new->prio = prio;
		new->hdl  = _SMH(li);
		
		/* Ok, then save this new element in the returned module list. the list is in decreasing prio order */
		for (prev = modules; (prev->next != modules) && (((_sec_item_t *)(prev->next))->prio > prio); prev = prev->next)
			/* just loop */;
		
		/* then insert */
		uti_list_insert_after(prev, _LIST(new));
	}
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	return 0;
	
failed:
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	return ret;
}

/* Register a new module. */
int sec_register ( sec_module_t * module, sec_mod_hdl_t ** handler )
{
	int ret=0, already=0;
	uti_list_t * prev = &smh_senti;
	_smh_t * new = NULL;
	
	TRACE_ENTRY( "%p %p", module, handler );
	
	/* First check the parameters are valid */
	CHECK_PARAMS(  handler  && module 
				&& module->sec_is_supported_peer 
			        && module->sec_send_protect
				&& module->sec_recv_unprotect  );
	
	*handler = NULL;
	
	/* Create a new entry */
	CHECK_MALLOC(	new = (_smh_t *) malloc(sizeof(_smh_t))	);
	memset(new, 0, sizeof(_smh_t));
	uti_list_init(&new->links, (void *)module);
	
	/* Get the list mutex */
	CHECK_POSIX_DO(	ret = pthread_mutex_lock(&smh_lock),   { free(new); return ret; }	);
	
	/* Search the location in the list */
	while ((prev->next != &smh_senti) && (_SM(prev->next)->sec_insecid < module->sec_insecid))
		prev = prev->next;
	
	/* Check we don't have an extension with equal insecid already */
	if ((prev->next != &smh_senti) && (_SM(prev->next)->sec_insecid == module->sec_insecid)) {
		log_error("More than one security extension with Inband-Security-Id value '%d' is registering.\n", module->sec_insecid);
		TRACE_DEBUG(INFO, "A module with the same Inband-Security-Id value has been found.");
		already = 1;
		free(new);
	} else {
		/* Insert in the list */
		uti_list_insert_after(prev, &new->links);
	}
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	if (already)
		return EALREADY;
	
	*handler = (sec_mod_hdl_t *)new;
	return 0;
}

/* Remove a registered module. */
int sec_unregister ( sec_mod_hdl_t * handle )
{
	int cnt;
	
	TRACE_ENTRY( "%p", handle );
	
	CHECK_PARAMS(  handle  );
	
	/* Lock the list */
	CHECK_POSIX(	pthread_mutex_lock(&smh_lock)	);
	
	cnt = _SMH(handle)->peers;
	if (cnt == 0) {
		/* Unlink the element */
		uti_list_unlink(_LIST(handle));
	}
	
	/* Release the mutex */
	CHECK_POSIX(	pthread_mutex_unlock(&smh_lock)	);
	
	if (cnt != 0) {
		TRACE_DEBUG(INFO, "Cannot unregister the module, it is still referenced by some peers");
		return EBUSY;
	}
		
	/* Free the element */
	free(handle);
	
	return 0;
}

"Welcome to our mercurial repository"