changeset 102:b9085fed408e

Security module implemented, to be tested
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 24 Jul 2008 18:29:32 +0900
parents 54c7f5120aa5
children 5c9a4c18d414
files include/waaad/security-api.h waaad/security.c waaad/security.h waaad/tests/Makefile.am waaad/tests/testsec.c
diffstat 5 files changed, 470 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/include/waaad/security-api.h	Wed Jul 23 11:32:40 2008 +0900
+++ b/include/waaad/security-api.h	Thu Jul 24 18:29:32 2008 +0900
@@ -265,6 +265,7 @@
  *  0      	: The module is registered.
  *  EINVAL 	: A parameter is invalid.
  *  ENOMEM	: Not enough memory to complete the operation
+ *  EALREADY	: Another module is already registered with the same sec_insecid value.
  */
 int sec_register ( sec_module_t * module, sec_mod_hdl_t ** handler );
 
--- a/waaad/security.c	Wed Jul 23 11:32:40 2008 +0900
+++ b/waaad/security.c	Thu Jul 24 18:29:32 2008 +0900
@@ -38,39 +38,373 @@
  * See security.h and security-api.h for more information on the functions and types involved.
  */
 
+#include <pthread.h>
 #include <errno.h>
+#include <string.h>
+#include <assert.h>
 
 #include "waaad-internal.h"
 
+
+/* Type of a security module list item = sec_mod_hdl_t */
+typedef struct _sm_ {
+	struct _sm_	*next;	/* The next in the list. List is ordered by module's insecid */
+	struct _sm_	*prev;	/* The prev in the list. */
+	sec_module_t	*sm;	/* Pointer to the extension's module */
+	int		 peers;	/* Number of peers using this module */
+} _sm_t;
+
+#define LI_init( _li ) {	\
+	(_li)->next = (_li);	\
+	(_li)->prev = (_li);	\
+}
+
+#define LI_isempty( _li ) ( (_li)->next == (_li) )
+
+#define LI_remove( _li ) {			\
+	(_li)->next->prev = (_li)->prev;	\
+	(_li)->prev->next = (_li)->next;	\
+	(_li)->next = (_li);			\
+	(_li)->prev = (_li);			\
+}
+
+#define LI_addafter( _ref, _li ) {	\
+	assert(LI_isempty( _li ));	\
+	(_li)->next = (_ref)->next;	\
+	(_li)->prev = (_ref);		\
+	(_ref)->next->prev = (_li);	\
+	(_ref)->next = (_li);		\
+}
+
+
+/* The mutex to protect the list */
+static pthread_mutex_t 	sm_lock;
+
+/* The list sentinel */
+static _sm_t 		sm_senti;
+
+
+
 /* Initialize the module */
 int sec_init ( void )
 {
+	int ret = 0;
+	
 	TRACE_ENTRY( "" );
-	TRACE_DEBUG (INFO, "@@@ Not implemented yet." );
+	
+	memset(&sm_senti, 0, sizeof(sm_senti));
+	
+	LI_init(&sm_senti);
+	
+	ret = pthread_mutex_init(&sm_lock, NULL);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		return ret;
+	}
+	
 	return 0;
 }
 
 /* End of the module */
 int sec_fini ( void )
 {
+	int ret = 0;
+	
 	TRACE_ENTRY( "" );
-	TRACE_DEBUG (INFO, "@@@ Not implemented yet." );
+	
+	/* Unregister any remaining module */
+	while (! LI_isempty( &sm_senti ) ) {
+		ret = sec_unregister((sec_mod_hdl_t *)sm_senti.next);
+		if (ret != 0) {
+			TRACE_DEBUG(INFO, "sec_unregister failed: %s", strerror(ret));
+			return ret;
+		}
+	}
+	
+	ret = pthread_mutex_destroy(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_destroy failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	return 0;
+}
+
+/* Increment a refcount of a module */
+int sec_modlink(sec_mod_hdl_t * module)
+{
+	int ret = 0;
+	_sm_t * h = (_sm_t *)module;
+	
+	TRACE_ENTRY( "%p" );
+	
+	/* Get the mutex */
+	ret = pthread_mutex_lock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	h->peers ++ ;
+	
+	/* Release the mutex */
+	ret = pthread_mutex_unlock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	return 0;
+}
+	
+	
+/* Decrement a refcount of a module */
+int sec_modunlink(sec_mod_hdl_t * module)
+{
+	int ret = 0;
+	_sm_t * h = (_sm_t *)module;
+	
+	TRACE_ENTRY( "%p" );
+	
+	/* Get the mutex */
+	ret = pthread_mutex_lock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	h->peers -- ;
+	
+	/* Release the mutex */
+	ret = pthread_mutex_unlock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret));
+		return ret;
+	}
+	
 	return 0;
 }
+	
+/* Destroy a list of _sec_item_t */
+int sec_freemodules(_sec_item_t * modules)
+{
+	int ret = 0;
+	_sec_item_t *l = modules;
+	
+	TRACE_ENTRY( "%p" );
+
+	while (l != NULL) {
+		_sec_item_t *i = l;
+		l = l->next;
+		ret = sec_modunlink(i->hdl);
+		if (ret != 0) {
+			TRACE_DEBUG(INFO, "sec_modunlink failed: %s", strerror(ret));
+			return ret;
+		}
+		free(i);
+	}
+	
+	return 0;
+}
+	
+/* Create a list of _sec_item_t */
+int sec_getmodules(char * diamid, struct sockaddr * sa, _sec_item_t **modules)
+{
+	int ret = 0;
+	int prio;
+	_sec_item_t sentinel = { .next = NULL };
+	_sm_t * mod;
+	
+	TRACE_ENTRY( "%s %p %p", diamid, sa, modules );
+	
+	if (!diamid || !sa || !modules) {
+		TRACE_DEBUG(INFO, "Invalid parameter");
+		return EINVAL;
+	}
+	
+	*modules = NULL;
+	
+	/* Get the mutex */
+	ret = pthread_mutex_lock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	/* For each module */
+	for (mod = sm_senti.next; mod != &sm_senti; mod = mod->next) {
+		_sec_item_t * new;
+		_sec_item_t * prev;
+		
+		/* Get the priority of this module */
+		ret = mod->sm->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",
+					mod->sm->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)",
+					mod->sm->sec_insecid, diamid, prio);
+			continue;
+		}
+		
+		/* Create a new element */
+		new = (_sec_item_t *) malloc(sizeof(_sec_item_t));
+		if (new == NULL) {
+			log_error("Memory allocation failed: %s\n", strerror(errno));
+			TRACE_DEBUG(INFO, "malloc failed");
+			ret = ENOMEM;
+			goto failed;
+		}
+		
+		memset(new, 0, sizeof(_sec_item_t));
+		
+		new->prio = prio;
+		new->sm   = mod->sm;
+		new->hdl  = (sec_mod_hdl_t *) mod;
+		/* increment the refcount of this module */
+		mod->peers ++;
+		
+		/* Ok, then put it in the list. the list is in decreasing order */
+		for (prev = &sentinel; (prev->next != NULL) && (prev->next->prio > prio); prev = prev->next);
+		
+		new->next = prev->next;
+		prev->next = new;
+	}
+	
+	/* Release the mutex */
+	ret = pthread_mutex_unlock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	/* Save the reference to be returned */
+	*modules = sentinel.next;
+	
+	return 0;
+	
+failed:
+	(void)pthread_mutex_unlock(&sm_lock);
+
+	/* destroy the temporary list */
+	(void)sec_freemodules(sentinel.next);
+	
+	return ret;
+}
 
 /* Register a new module. */
 int sec_register ( sec_module_t * module, sec_mod_hdl_t ** handler )
 {
+	int ret=0, already=0;
+	_sm_t * prev = &sm_senti;
+	_sm_t * new = NULL;
+	
 	TRACE_ENTRY( "%p %p", module, handler );
-	TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
+	
+	/* First check the parameters are valid */
+	if (       !handler 
+		|| !module 
+		|| !module->sec_is_supported_peer
+		|| !module->sec_send_protect
+		|| !module->sec_recv_unprotect ) {
+		TRACE_DEBUG(INFO, "Invalid parameter");
+		return EINVAL;
+	}
+	
+	*handler = NULL;
+	
+	/* Create a new entry */
+	new = (_sm_t *) malloc(sizeof(_sm_t));
+	if (new == NULL) {
+		log_error("Memory allocation failed: %s\n", strerror(errno));
+		TRACE_DEBUG(INFO, "malloc failed");
+		return ENOMEM;
+	}
+	memset(new, 0, sizeof(_sm_t));
+	new->sm = module;
+	LI_init(new);
+	
+	/* Get the list mutex */
+	ret = pthread_mutex_lock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		free(new);
+		return ret;
+	}
+	
+	/* Search the location in the list */
+	while ((prev->next != &sm_senti) && (prev->next->sm->sec_insecid < module->sec_insecid))
+		prev = prev->next;
+	
+	/* Check we don't have an equal extension already */
+	if ((prev->next != &sm_senti) && (prev->next->sm->sec_insecid == 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 */
+		LI_addafter(prev, new);
+	}
+	
+	/* Release the mutex */
+	ret = pthread_mutex_unlock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	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 ret=0, cnt;
+	_sm_t * h = (_sm_t *)handle;
+	
 	TRACE_ENTRY( "%p", handle );
-	TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
+	
+	if (handle == NULL) {
+		TRACE_DEBUG(INFO, "Invalid parameter");
+		return EINVAL;
+	}
+	
+	/* Lock the list */
+	ret = pthread_mutex_lock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	cnt = h->peers;
+	if (cnt == 0) {
+		/* Unlink the element */
+		LI_remove(h);
+	}
+	
+	/* Release the mutex */
+	ret = pthread_mutex_unlock(&sm_lock);
+	if (ret != 0) {
+		TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret));
+		return ret;
+	}
+	
+	if (cnt != 0) {
+		TRACE_DEBUG(INFO, "Cannot unregister the module, it is still referenced by some peers");
+		return EBUSY;
+	}
+		
+	/* Free the element */
+	free(h);
+	
+	return 0;
 }
 
--- a/waaad/security.h	Wed Jul 23 11:32:40 2008 +0900
+++ b/waaad/security.h	Thu Jul 24 18:29:32 2008 +0900
@@ -46,6 +46,15 @@
 /* Include the API definitions for the module */
 #include <waaad/security-api.h>
 
+/* For daemon's internal use only */
+typedef struct _sec_item {
+	int	 	  prio;	/* priority of this module -- only to build the list ordered */
+	sec_module_t	 *sm;	/* pointer to the security module data */
+	sec_mod_hdl_t	 *hdl;	/* pointer to the security module handle */
+	struct _sec_item *next; /* The next module available to this peer with lesser priority, if any, or NULL. */
+} _sec_item_t;
+
+
 /* The following functions are called only from the daemon */
 
 /*
@@ -78,5 +87,70 @@
  */
 int sec_fini ( void );
 
+/*
+ * FUNCTION:	sec_getmodules
+ *
+ * PARAMETERS:
+ *  diamid : diameter identity of the peer.
+ *  sa     : Information about the location and port of the peer.
+ *  modules: upon success, the security modules available for this peer.
+ *
+ * DESCRIPTION: 
+ *  Get a list of security modules available to a peer, ordered by priority.
+ * The list must be freed with sec_freemodules.
+ * If the peer makes a successful CER/CEA exchange with one of the modules, it must call 
+ * sec_modlink on its hdl; then call sec_modunlink when it does not need it anymore.
+ *
+ * RETURN VALUE:
+ *   0 : List created properly
+ *  !0 : an error occurred
+ */
+int sec_getmodules(char * diamid, struct sockaddr * sa, _sec_item_t **modules);
+
+/*
+ * FUNCTION:	sec_freemodules
+ *
+ * PARAMETERS:
+ *  modules: The list of security modules to free.
+ *
+ * DESCRIPTION: 
+ *  Release a list of modules returned by sec_getmodules.
+ *
+ * RETURN VALUE:
+ *   0 : List freed properly
+ *  !0 : an error occurred
+ */
+int sec_freemodules(_sec_item_t * modules);
+
+/*
+ * FUNCTION:	sec_modlink
+ *
+ * PARAMETERS:
+ *  module: A security module to lock for use in a peer, after successful CER/CEA.
+ *
+ * DESCRIPTION: 
+ *  Increment a refcount on a module.
+ *
+ * RETURN VALUE:
+ *   0 : OK
+ *  !0 : an error occurred
+ */
+int sec_modlink(sec_mod_hdl_t * module);
+
+/*
+ * FUNCTION:	sec_modunlink
+ *
+ * PARAMETERS:
+ *  module: A security module to unlock after use in a peer.
+ *
+ * DESCRIPTION: 
+ *  Decrement a refcount on a module.
+ *
+ * RETURN VALUE:
+ *   0 : OK
+ *  !0 : an error occurred
+ */
+int sec_modunlink(sec_mod_hdl_t * module);
+
 
 #endif /* _SECURITY_H */
--- a/waaad/tests/Makefile.am	Wed Jul 23 11:32:40 2008 +0900
+++ b/waaad/tests/Makefile.am	Thu Jul 24 18:29:32 2008 +0900
@@ -39,6 +39,9 @@
 # Testing the sessions:
 testsess_SOURCES = testsess.c tests.h $(WAAADSOURCES)
 
-check_PROGRAMS = testdict testmesg testmeq testsess
+# Testing the security:
+testsec_SOURCES = testsec.c tests.h $(WAAADSOURCES)
+
+check_PROGRAMS = testdict testmesg testmeq testsess testsec
 
 TESTS = $(check_PROGRAMS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/waaad/tests/testsec.c	Thu Jul 24 18:29:32 2008 +0900
@@ -0,0 +1,51 @@
+/*********************************************************************************************************
+* 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.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+/* Test for the security module */
+
+
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	
+	/* First, initialize the daemon modules */
+	INIT_WAAAD();
+	
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
+	
"Welcome to our mercurial repository"