/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Copyright (C) 2007 Wind River Systems * ****************************************************************************** */ /* modification history -------------------- 01a,17jul07,ps initial checkin of dhcpv6 authentication key database module */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include "ipdhcps6.h" #include "ipdhcps6_h.h" #include "ipdhcps6_host.h" #include "ipdhcps6_prefix.h" #include "ipdhcps6_subnet.h" #include "ipdhcps6_duid.h" #include "ipdhcps6_cvthex.h" #include "ipdhcps6_authhash.h" #define IPDHCPS6_DUID_LL_ACTUALSIZE 10 #define IPDHCPS6_DUID_LLT_ACTUALSIZE 14 #define IPDHCPS6_DUID_EN_ACTUALSIZE 14 /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipdhcps6_authdata_obj_hash *=========================================================================== * Description: Returns a hash value based on an authkey value. * Parameters: dbentry - The option to return a hash value for. * Returns: * */ IP_STATIC unsigned ipdhcps6_authdb_obj_hash (Ipdhcps6_authkey_dbentry *dbentry) { #ifdef DEBUG_DHCPV6_AUTH int i; unsigned char *cptr; printf ("ipdhcps6_authdb_obj_hash called: "); cptr = (unsigned char *) &(dbentry->duid.data.ll.link_addr); for (i = 0 ; i < 6 ; i++) { printf ("%2x ", cptr [i]); } printf ("\n"); #endif return ipcom_hash_update(&(dbentry->duid.data), dbentry->duid.len, 0); } /* *=========================================================================== * ipdhcps6_authdb_key_hash *=========================================================================== * Description: Returns a hash value for a DUID key. * Parameters: key - Pointer to the Ipdhcps6_authkey_duid structure * Returns: * */ IP_STATIC unsigned ipdhcps6_authdb_key_hash(Ipdhcps6_duid *key) { #ifdef DEBUG_DHCPV6_AUTH int i; unsigned char *cptr; printf ("ipdhcps6_authdb_key_hash called: "); cptr = (unsigned char *) &(key->data.ll.link_addr); for (i = 0 ; i < 6 ; i++) { printf ("%2x ", cptr [i]); } printf ("\n"); #endif return ipcom_hash_update(&(key->data), key->len, 0); } /* *=========================================================================== * ipdhcps6_authdb_hash_cmp *=========================================================================== * Description: Compares a hash object and a hash key for equality. * Parameters: dbentry - An authkey_dbentry structure. * key - A pointer to the search key. * Returns: IP_TRUE if the search key matches the prefix entry. * */ IP_STATIC Ip_bool ipdhcps6_authdb_hash_cmp(Ipdhcps6_authkey_dbentry *dbentry, Ipdhcps6_duid *key) { #ifdef DEBUG_DHCPV6_AUTH printf ("ipdhcps6_authdb_hash_cmp called\n"); #endif if (dbentry->duid.len != key->len) return IP_FALSE; return ipcom_memcmp(&(dbentry->duid.data), &(key->data), key->len) == 0; } /*************/ /* *=========================================================================== * ipdhcps6_authtrans_obj_hash *=========================================================================== * Description: Returns a hash value based on an authkey value. * Parameters: dbentry - The option to return a hash value for. * Returns: * */ IP_STATIC unsigned ipdhcps6_authtrans_obj_hash (Ipdhcps6_authtrans_dbentry *dbentry) { #ifdef DEBUG_DHCPV6_AUTH int i; unsigned char *cptr; printf ("ipdhcps6_authtrans_obj_hash called: "); cptr = (unsigned char *) &(dbentry->duid.data); switch (dbentry->duid.data.generic.content) { case IPDHCPS6_DUID_LL: printf ("LL content\n"); break; case IPDHCPS6_DUID_LLT: printf ("LLT content\n"); break; case IPDHCPS6_DUID_EN: printf ("EN content\n"); break; default: printf ("default case content\n"); } for (i = 0 ; i < dbentry->duid.len ; i++) { printf ("%2x ", cptr [i]); } printf ("\n"); #endif return ipcom_hash_update(&(dbentry->duid.data), dbentry->duid.len, 0); } /* *=========================================================================== * ipdhcps6_authtrans_key_hash *=========================================================================== * Description: Returns a hash value for a DUID key. * Parameters: key - Pointer to the Ipdhcps6_authkey_duid structure * Returns: * */ IP_STATIC unsigned ipdhcps6_authtrans_key_hash(Ipdhcps6_duid *key) { #ifdef DEBUG_DHCPV6_AUTH int i; unsigned char *cptr; printf ("ipdhcps6_authtrans_key_hash called: "); cptr = (unsigned char *) &(key->data); switch (key->data.generic.content) { case IPDHCPS6_DUID_LL: printf ("LL content\n"); break; case IPDHCPS6_DUID_LLT: printf ("LLT content\n"); break; case IPDHCPS6_DUID_EN: printf ("EN content\n"); break; default: printf ("default case content\n"); } for (i = 0 ; i < key->len ; i++) { printf ("%2x ", cptr [i]); } printf ("\n"); #endif return ipcom_hash_update(&(key->data), key->len, 0); } /* *=========================================================================== * ipdhcps6_authtrans_hash_cmp *=========================================================================== * Description: Compares a hash object and a hash key for equality. * Parameters: prefix - A prefix structure. * key - A pointer to the search key. * Returns: IP_TRUE if the search key matches the prefix entry. * */ IP_STATIC Ip_bool ipdhcps6_authtrans_hash_cmp(Ipdhcps6_authtrans_dbentry *dbentry, Ipdhcps6_duid *key) { #ifdef DEBUG_DHCPV6_AUTH printf ("ipdhcps6_authtrans_hash_cmp called\n"); #endif if (dbentry->duid.len != key->len) return IP_FALSE; return ipcom_memcmp(&(dbentry->duid.data), &(key->data), key->len) == 0; } /*****************/ /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_STATIC Ipcom_hash *client_authkey_db; IP_STATIC Ipcom_hash *client_transaction_db; IP_GLOBAL Ipcom_hash * ipdhcps6_authdb_hash_create(void) { return ipcom_hash_new ((Ipcom_hash_obj_func) ipdhcps6_authdb_obj_hash, (Ipcom_hash_key_func) ipdhcps6_authdb_key_hash, (Ipcom_hash_cmp_func) ipdhcps6_authdb_hash_cmp); } IP_GLOBAL Ipcom_hash * ipdhcps6_authtrans_hash_create(void) { return ipcom_hash_new ((Ipcom_hash_obj_func) ipdhcps6_authtrans_obj_hash, (Ipcom_hash_key_func) ipdhcps6_authtrans_key_hash, (Ipcom_hash_cmp_func) ipdhcps6_authtrans_hash_cmp); } IP_GLOBAL Ipdhcps6_duid *ipdhcps6_authdb_create_ll_duid (int len, Ip_u16 hwtype, Ip_u8 *link_addr) { Ipdhcps6_duid *retval = (Ipdhcps6_duid *) ipcom_malloc (sizeof (struct Ipdhcps6_duid_struct)); (void)len; if (IP_NULL == retval) return IP_NULL; retval->len = IPDHCPS6_DUID_LL_ACTUALSIZE; retval->data.ll.content = IPDHCPS6_DUID_LL; retval->data.ll.hardware_type = hwtype; ipcom_memcpy (retval->data.ll.link_addr, link_addr, 6); return retval; } IP_GLOBAL Ip_err ipdhcps6_add_client_authkey (Ipdhcps6_duid *client_duid, Ip_u8 *key, int keylen) { Ip_u16 duid_content; Ipdhcps6_authkey_dbentry *new_authdb_entry = (Ipdhcps6_authkey_dbentry *) ipcom_malloc (sizeof (struct Ipdhcps6_authkey_dbentry)); if (IP_NULL == new_authdb_entry) return IPCOM_ERR_FAILED; new_authdb_entry->secret.key = (Ip_u8 *) ipcom_malloc ((Ip_size_t)keylen); if (IP_NULL == new_authdb_entry->secret.key) { ipcom_free (new_authdb_entry); IPCOM_LOG0 (DEBUG, "ipdhcps6_add_client_authkey: no memory!\n"); return IPCOM_ERR_NO_MEMORY; } /* * copy in key */ ipcom_memcpy (new_authdb_entry->secret.key, key, (Ip_size_t)keylen); new_authdb_entry->secret.len = keylen; /* * copy in duid data */ new_authdb_entry->duid.len = client_duid->len; duid_content = client_duid->data.ll.content; switch (duid_content) { case IPDHCPS6_DUID_LL: new_authdb_entry->duid.data.ll.hardware_type = client_duid->data.ll.hardware_type; new_authdb_entry->duid.data.ll.content = IPDHCPS6_DUID_LL; ipcom_memcpy (new_authdb_entry->duid.data.ll.link_addr, client_duid->data.ll.link_addr, 6); break; case IPDHCPS6_DUID_EN: /* not yet implemented */ case IPDHCPS6_DUID_LLT: /* not yet implemented */ default: /* Coverity defect fix for RESOURCE_LEAK */ ipcom_free( new_authdb_entry->secret.key); ipcom_free (new_authdb_entry); return IPCOM_ERR_FAILED; } if (IPCOM_SUCCESS != ipcom_hash_add (client_authkey_db, new_authdb_entry)) { return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } IP_GLOBAL Ip_err ipdhcps6_client_wants_auth (union Ipdhcps6_duid_data *client, int len) { Ip_u16 client_duid_content; Ipdhcps6_authtrans_dbentry *client_dbentry = IP_NULL; client_dbentry = (Ipdhcps6_authtrans_dbentry *) ipcom_malloc (sizeof (struct Ipdhcps6_authtrans_dbentry)); if (IP_NULL == client_dbentry) return IPCOM_ERR_NO_MEMORY; client_duid_content = ip_ntohs (client->generic.content); switch (client_duid_content) { case IPDHCPS6_DUID_LLT: client_dbentry->duid.len = IPDHCPS6_DUID_LLT_ACTUALSIZE; client_dbentry->duid.data.llt.content = IPDHCPS6_DUID_LLT; client_dbentry->duid.data.llt.hardware_type = client->llt.hardware_type; client_dbentry->duid.data.llt.time = client->llt.time; ipcom_memcpy (client_dbentry->duid.data.llt.link_addr, client->llt.link_addr, 6); break; case IPDHCPS6_DUID_EN: /* * FIXME * using the duid union structure we have, we know we will have * enough space to copy in the first 8 bytes of the enterprise * ID. This may or may not be enough to be unique; we'll need * to revisit this later. Look at "len" to see if we were given * less than 8 bytes for the ID; if so, only copy the bytes * given. */ client_dbentry->duid.len = (Ip_u16)(len < IPDHCPS6_DUID_EN_ACTUALSIZE ? len : IPDHCPS6_DUID_EN_ACTUALSIZE); client_dbentry->duid.data.en.content = IPDHCPS6_DUID_EN; client_dbentry->duid.data.en.enterprise_number_1 = client->en.enterprise_number_1; client_dbentry->duid.data.en.enterprise_number_2 = client->en.enterprise_number_2; ipcom_memcpy (client_dbentry->duid.data.en.id, client->en.id, (Ip_size_t)(8 - (IPDHCPS6_DUID_EN_ACTUALSIZE - len))); break; case IPDHCPS6_DUID_LL: client_dbentry->duid.len = IPDHCPS6_DUID_LL_ACTUALSIZE; client_dbentry->duid.data.ll.content = IPDHCPS6_DUID_LL; client_dbentry->duid.data.ll.hardware_type = client->ll.hardware_type; ipcom_memcpy (client_dbentry->duid.data.ll.link_addr, client->ll.link_addr, 6); break; default: break; } /* * set replay counters */ client_dbentry->server_replay1 = 0xdeadbeef; client_dbentry->server_replay2 = 0x0; client_dbentry->client_replay1 = 0x0; client_dbentry->client_replay2 = 0x0; if (IPCOM_SUCCESS != ipcom_hash_add (client_transaction_db, client_dbentry)) return IPCOM_ERR_FAILED; return IPCOM_SUCCESS; } IP_GLOBAL Ip_err ipdhcps6_client_no_auth (union Ipdhcps6_duid_data *client, int len) { Ip_u16 client_duid_content; Ipdhcps6_duid client_dbkey; Ipdhcps6_authkey_dbentry *client_dbobj = IP_NULL; client_duid_content = ip_ntohs (client->generic.content); switch (client_duid_content) { case IPDHCPS6_DUID_LLT: client_dbkey.len = IPDHCPS6_DUID_LLT_ACTUALSIZE; client_dbkey.data.llt.content = IPDHCPS6_DUID_LLT; client_dbkey.data.llt.hardware_type = client->llt.hardware_type; client_dbkey.data.llt.time = client->llt.time; ipcom_memcpy (client_dbkey.data.llt.link_addr, client->llt.link_addr, 6); break; case IPDHCPS6_DUID_EN: /* * FIXME * using the duid union structure we have, we know we will have * enough space to copy in the first 8 bytes of the enterprise * ID. This may or may not be enough to be unique; we'll need * to revisit this later. Look at "len" to see if we were given * less than 8 bytes for the ID; if so, only copy the bytes * given. */ client_dbkey.len = (Ip_u16)(len < IPDHCPS6_DUID_EN_ACTUALSIZE ? len : IPDHCPS6_DUID_EN_ACTUALSIZE); client_dbkey.data.en.content = IPDHCPS6_DUID_EN; client_dbkey.data.en.enterprise_number_1 = client->en.enterprise_number_1; client_dbkey.data.en.enterprise_number_2 = client->en.enterprise_number_2; ipcom_memcpy (client_dbkey.data.en.id, client->en.id, (Ip_size_t)(8 - (IPDHCPS6_DUID_EN_ACTUALSIZE - len))); break; case IPDHCPS6_DUID_LL: client_dbkey.len = IPDHCPS6_DUID_LL_ACTUALSIZE; client_dbkey.data.ll.content = IPDHCPS6_DUID_LL; client_dbkey.data.ll.hardware_type = client->ll.hardware_type; ipcom_memcpy (client_dbkey.data.ll.link_addr, client->ll.link_addr, 6); break; default: return IPCOM_ERR_FAILED; } client_dbobj = ipcom_hash_get (client_transaction_db, &client_dbkey); if (IP_NULL == client_dbobj) { return IPCOM_SUCCESS; } else { ipcom_hash_remove (client_transaction_db, client_dbobj); return IPCOM_SUCCESS; } } IP_GLOBAL Ipdhcps6_authtrans_dbentry * ipdhcps6_client_requested_auth (union Ipdhcps6_duid_data *client, int len) { Ip_u16 client_duid_content; Ipdhcps6_duid client_dbkey; Ipdhcps6_authtrans_dbentry *client_dbobj = IP_NULL; client_duid_content = ip_ntohs (client->generic.content); switch (client_duid_content) { case IPDHCPS6_DUID_LLT: client_dbkey.len = IPDHCPS6_DUID_LLT_ACTUALSIZE; client_dbkey.data.llt.content = IPDHCPS6_DUID_LLT; client_dbkey.data.llt.hardware_type = client->llt.hardware_type; client_dbkey.data.llt.time = client->llt.time; ipcom_memcpy (client_dbkey.data.llt.link_addr, client->llt.link_addr, 6); break; case IPDHCPS6_DUID_EN: /* * FIXME * using the duid union structure we have, we know we will have * enough space to copy in the first 8 bytes of the enterprise * ID. This may or may not be enough to be unique; we'll need * to revisit this later. Look at "len" to see if we were given * less than 8 bytes for the ID; if so, only copy the bytes * given. */ client_dbkey.len = (Ip_u16)(len < IPDHCPS6_DUID_EN_ACTUALSIZE ? len : IPDHCPS6_DUID_EN_ACTUALSIZE); client_dbkey.data.en.content = IPDHCPS6_DUID_EN; client_dbkey.data.en.enterprise_number_1 = client->en.enterprise_number_1; client_dbkey.data.en.enterprise_number_2 = client->en.enterprise_number_2; ipcom_memcpy (client_dbkey.data.en.id, client->en.id, (Ip_size_t)(8 - (IPDHCPS6_DUID_EN_ACTUALSIZE - len))); break; case IPDHCPS6_DUID_LL: client_dbkey.len = IPDHCPS6_DUID_LL_ACTUALSIZE; client_dbkey.data.ll.content = IPDHCPS6_DUID_LL; client_dbkey.data.ll.hardware_type = client->ll.hardware_type; ipcom_memcpy (client_dbkey.data.ll.link_addr, client->ll.link_addr, 6); break; default: /* invalid DUID type; ignore it and return failure */ return IP_NULL; } client_dbobj = ipcom_hash_get (client_transaction_db, &client_dbkey); if (IP_NULL == client_dbobj) return IP_NULL; return client_dbobj; } #define MAX_IPDHCPV6_AUTH_KEY_SIZE 128 IP_STATIC int authKeyInitialized = 0; IP_STATIC int authRealmInitialized = 0; IP_STATIC Ip_u8 authKeyFromSysVars [256]; IP_STATIC Ip_size_t authKeyLenFromSysVars = 0; IP_STATIC Ip_u8 authKey [128]; IP_STATIC Ip_size_t authKeyLen = 0; IP_STATIC Ip_u8 authRealmFromSysVars [128]; IP_STATIC Ip_size_t authRealmLenFromSysVars = 0; IP_STATIC Ip_err ipdhcps6_set_default_auth_key_from_sysvars (void) { authKeyLenFromSysVars = sizeof (authKeyFromSysVars); (void)ipcom_sysvar_get("ipdhcps6.authkey", (char *) authKeyFromSysVars, &authKeyLenFromSysVars); /* * check if the value we read is a valid hex key; convert to * a key buffer. */ if (ipdhcps6_check_is_hex_string ((char *) authKeyFromSysVars)) { /* we need at least 4 characters to proceed here; "0x--" or more */ if (authKeyLenFromSysVars >= 4) { char *kptr = (char *) authKeyFromSysVars; kptr += 2; /* get past leading "0x" */ authKeyLen = (authKeyLenFromSysVars - 2) / 2; if (! ipdhcps6_cvt_hex_to_membuf (kptr, authKey, (int)authKeyLen) ) { authKeyLen = 0; return IPCOM_ERR_FAILED; } } } else { authKeyLen = 0; return IPCOM_ERR_FAILED; } authKeyInitialized = 1; return IPCOM_SUCCESS; } IP_GLOBAL Ip_err ipdhcps6_set_default_auth_key (char *authkey) { Ip_size_t auth_key_len; auth_key_len = strlen (authkey); if (auth_key_len > ((MAX_IPDHCPV6_AUTH_KEY_SIZE + 1) * 2)) { return IPCOM_ERR_FAILED; /* given key is too large */ } /* * check if the value we read is a valid hex key; convert to * a key buffer. */ if (ipdhcps6_check_is_hex_string (authkey)) { /* we need at least 4 characters to proceed here; "0x--" or more */ if (auth_key_len >= 4) { char *kptr = authkey; kptr += 2; /* get past leading "0x" */ authKeyLen = (auth_key_len - 2) / 2; if (! ipdhcps6_cvt_hex_to_membuf (kptr, authKey, (int)authKeyLen) ) { authKeyLen = 0; return IPCOM_ERR_FAILED; } } } else { authKeyLen = 0; return IPCOM_ERR_FAILED; } authKeyInitialized = 1; return IPCOM_SUCCESS; } IP_GLOBAL Ip_err ipdhcps6_get_default_auth_key (Ip_size_t *len, Ip_u8 **key) { if (authKeyInitialized) { *len = authKeyLen; *key = authKey; return IPCOM_SUCCESS; } else { if (IPCOM_SUCCESS == ipdhcps6_set_default_auth_key_from_sysvars ()) { *len = authKeyLen; *key = authKey; return IPCOM_SUCCESS; } } *key = IP_NULL; *len = 0; return IPCOM_ERR_FAILED; } IP_STATIC Ip_err ipdhcps6_set_auth_realm_from_sysvars () { authRealmLenFromSysVars = sizeof (authRealmFromSysVars); if (ipcom_sysvar_get("ipdhcps6.authrealm", (char *) authRealmFromSysVars, &authRealmLenFromSysVars) == IP_NULL) { /* Don't set it if we dont got it */ authRealmLenFromSysVars = 0; } if (authRealmLenFromSysVars > 0) { authRealmInitialized = 1; return IPCOM_SUCCESS; } return IPCOM_ERR_FAILED; } IP_GLOBAL Ip_err ipdhcps6_set_auth_realm (char *auth_realm) { Ip_size_t realm_len; authRealmInitialized = 0; realm_len = strlen (auth_realm); if ((unsigned)realm_len > (sizeof (authRealmFromSysVars) - 1)) { /* passed in realm is too large. */ return IPCOM_ERR_FAILED; } strncpy ((char *) authRealmFromSysVars, auth_realm, realm_len); authRealmFromSysVars [realm_len] = '\0'; authRealmLenFromSysVars = realm_len; authRealmInitialized = 1; return IPCOM_SUCCESS; } IP_GLOBAL Ip_err ipdhcps6_get_auth_realm (Ip_size_t *len, Ip_u8 **realm) { if (authRealmInitialized) { *len = authRealmLenFromSysVars; *realm = authRealmFromSysVars; return IPCOM_SUCCESS; } else { if (IPCOM_SUCCESS == ipdhcps6_set_auth_realm_from_sysvars ()) { *len = authRealmLenFromSysVars; *realm = authRealmFromSysVars; return IPCOM_SUCCESS; } } *len = 0; return IPCOM_ERR_FAILED; } IP_GLOBAL void ipdhcps6_authdb_init (void) { client_authkey_db = ipdhcps6_authdb_hash_create (); client_transaction_db = ipdhcps6_authtrans_hash_create (); } IP_GLOBAL Ip_err ipdhcps6_find_key_for_client (union Ipdhcps6_duid_data *client, int duid_len, Ip_u8 **key, Ip_size_t *key_len) { Ip_u16 client_duid_content; Ipdhcps6_duid client_dbkey; Ipdhcps6_authkey_dbentry *client_dbobj = IP_NULL; client_duid_content = ip_ntohs (client->generic.content); switch (client_duid_content) { case IPDHCPS6_DUID_LLT: client_dbkey.len = IPDHCPS6_DUID_LL_ACTUALSIZE; client_dbkey.data.ll.content = IPDHCPS6_DUID_LL; client_dbkey.data.ll.hardware_type = client->llt.hardware_type; ipcom_memcpy (client_dbkey.data.ll.link_addr, client->llt.link_addr, 6); break; case IPDHCPS6_DUID_EN: /* * FIXME * using the duid union structure we have, we know we will have * enough space to copy in the first 8 bytes of the enterprise * ID. This may or may not be enough to be unique; we'll need * to revisit this later. Look at "len" to see if we were given * less than 8 bytes for the ID; if so, only copy the bytes * given. */ client_dbkey.len = (Ip_u16)(duid_len < IPDHCPS6_DUID_EN_ACTUALSIZE ? duid_len : IPDHCPS6_DUID_EN_ACTUALSIZE); client_dbkey.data.en.content = IPDHCPS6_DUID_EN; client_dbkey.data.en.enterprise_number_1 = client->en.enterprise_number_1; client_dbkey.data.en.enterprise_number_2 = client->en.enterprise_number_2; ipcom_memcpy (client_dbkey.data.en.id, client->en.id, (Ip_size_t)(8 - (IPDHCPS6_DUID_EN_ACTUALSIZE - duid_len))); break; case IPDHCPS6_DUID_LL: client_dbkey.len = IPDHCPS6_DUID_LL_ACTUALSIZE; client_dbkey.data.ll.content = IPDHCPS6_DUID_LL; client_dbkey.data.ll.hardware_type = client->ll.hardware_type; ipcom_memcpy (client_dbkey.data.ll.link_addr, client->ll.link_addr, 6); break; default: return IPCOM_ERR_FAILED; } client_dbobj = ipcom_hash_get (client_authkey_db, &client_dbkey); if (IP_NULL == client_dbobj) { /* use default system auth key */ return IPCOM_ERR_FAILED; } else { /* use client specific key */ *key_len = (Ip_size_t)client_dbobj->secret.len; *key = client_dbobj->secret.key; return IPCOM_SUCCESS; } } /* **************************************************************************** * END OF FILE **************************************************************************** */