Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 - 2006 Pekka Riikonen
+ Copyright (C) 2005 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "silc.h"
#include "silcskr.h"
-/* XXX Locking, when removing keys */
-
/************************** Types and definitions ***************************/
/* Search constraints */
#if defined(SILC_DEBUG)
static const char *find_name[] = {
- "PKCS TYPE",
- "USERNAME",
- "HOST",
- "REALNAME",
- "EMAIL",
- "ORG",
- "COUNTRY",
+ "PKCS TYPE ",
+ "USERNAME ",
+ "HOST ",
+ "REALNAME ",
+ "EMAIL ",
+ "ORG ",
+ "COUNTRY ",
"PUBLIC KEY",
- "CONTEXT",
- "USAGE",
+ "CONTEXT ",
+ "USAGE ",
NULL
};
#endif /* SILC_DEBUG */
case SILC_SKR_FIND_PKCS_TYPE:
case SILC_SKR_FIND_USAGE:
silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
- (int)SILC_PTR_TO_32(data));
+ (int)SILC_PTR_TO_32(data));
break;
case SILC_SKR_FIND_PUBLIC_KEY:
+ case SILC_SKR_FIND_CONTEXT:
silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
break;
default:
silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
- (char *)data);
+ (char *)data);
}
}
-
#endif /* SILC_DEBUG */
/* Hash table destructor for search constraints */
void *user_context)
{
SilcSKRFindType type = SILC_PTR_TO_32(key);
+ SilcPKCSType pkcs_type = SILC_PTR_TO_32(user_context);
switch (type) {
case SILC_SKR_FIND_PKCS_TYPE:
break;
default:
+ /* In SILC Public key all entries are referenced from the public key
+ so don't free them. This test is valid only when removing key
+ from the repository. */
+ if (pkcs_type == SILC_PKCS_SILC)
+ break;
+
silc_free(context);
}
}
{
SilcSKREntry type = key;
SilcSKRKeyInternal entry = context;
+ SilcPKCSType pkcs_type = silc_pkcs_get_type(entry->key.key);
/* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it
shares same context with the key entry. */
if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY)
- silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data, NULL);
+ silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data,
+ SILC_32_TO_PTR(pkcs_type));
silc_free(type);
/* Destroy key */
if (entry->refcnt > 0)
return;
+ SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key));
+
silc_pkcs_public_key_free(entry->key.key);
silc_free(entry);
}
{
SilcSKREntry entry;
+#if defined(SILC_DEBUG)
+ char tmp[256];
+ memset(tmp, 0, sizeof(tmp));
+ silc_skr_type_string(type, type_data, tmp, sizeof(tmp) - 1);
+ SILC_LOG_DEBUG(("Search constraint %s", tmp));
+#endif /* SILC_DEBUG */
+
entry = silc_calloc(1, sizeof(*entry));
if (!entry)
return FALSE;
return silc_hash_table_add(skr->keys, entry, key);
}
+/* Delete a key by search constraint type from repository */
+
+static SilcBool silc_skr_del_entry(SilcSKR skr, SilcSKRFindType type,
+ void *type_data, SilcSKRKeyInternal key)
+{
+ SilcSKREntryStruct entry;
+
+ if (!type_data)
+ return FALSE;
+
+ entry.type = type;
+ entry.data = type_data;
+
+ return silc_hash_table_del_by_context(skr->keys, &entry, key);
+}
+
+/* This performs AND operation. Any entry already in `results' that is not
+ in `list' will be removed from `results'. */
+
+static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
+ SilcDList *results)
+{
+ SilcSKRKeyInternal entry, r;
+
+ if (*results == NULL) {
+ *results = silc_dlist_init();
+ if (*results == NULL) {
+ *status |= SILC_SKR_NO_MEMORY;
+ return FALSE;
+ }
+ }
+
+ /* If results is empty, just add all entries from list to results */
+ if (!silc_dlist_count(*results)) {
+ silc_dlist_start(list);
+ while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
+ silc_dlist_add(*results, entry);
+
+ return TRUE;
+ }
+
+ silc_dlist_start(*results);
+ while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
+
+ /* Check if this entry is in list */
+ silc_dlist_start(list);
+ while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
+ if (r == entry)
+ break;
+ }
+ if (r != SILC_LIST_END)
+ continue;
+
+ /* Remove from results */
+ silc_dlist_del(*results, entry);
+ }
+
+ /* If results became empty, we did not find any key */
+ if (!silc_dlist_count(*results)) {
+ SILC_LOG_DEBUG(("Not all search constraints found"));
+ *status |= SILC_SKR_NOT_FOUND;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/***************************** SILC Public Key ******************************/
+
/* Add SILC style public key to repository */
static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcSKRKeyInternal key;
SilcSKRStatus status = SILC_SKR_ERROR;
SilcPublicKeyIdentifier ident;
SilcSILCPublicKey silc_pubkey;
+#if defined(SILC_DEBUG)
+ char tmp[256];
+#endif /* SILC_DEBUG */
/* Get the SILC public key */
silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
ident = &silc_pubkey->identifier;
- SILC_LOG_DEBUG(("Adding SILC public key [%s]", ident->username));
+ SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p",
+ public_key, ident->username, key_context));
silc_mutex_lock(skr->lock);
key->key.key = public_key;
key->key.key_context = key_context;
+#if defined(SILC_DEBUG)
+ silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
+ tmp, sizeof(tmp) - 1);
+ SILC_LOG_DEBUG((" Search constraint %s", tmp));
+#endif /* SILC_DEBUG */
+
/* Add key specifics */
if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
silc_mutex_unlock(skr->lock);
+ if (return_key)
+ *return_key = (SilcSKRKey)key;
+
return SILC_SKR_OK;
err:
static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcSKRKeyInternal key;
SilcSKRStatus status = SILC_SKR_ERROR;
+#if defined(SILC_DEBUG)
+ char tmp[256];
+#endif /* SILC_DEBUG */
SILC_LOG_DEBUG(("Adding SILC public key"));
key->key.key = public_key;
key->key.key_context = key_context;
+#if defined(SILC_DEBUG)
+ silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
+ tmp, sizeof(tmp) - 1);
+ SILC_LOG_DEBUG(("Search cons %s", tmp));
+#endif /* SILC_DEBUG */
+
/* Add key specifics */
if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
silc_mutex_unlock(skr->lock);
+ if (return_key)
+ *return_key = (SilcSKRKey)key;
+
return SILC_SKR_OK;
err:
return status;
}
-/* This performs AND operation. Any entry already in `results' that is not
- in `list' will be removed from `results'. */
+/* Deletes SILC public key from repository */
-static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
- SilcDList *results)
+static SilcSKRStatus silc_skr_del_silc_public_key(SilcSKR skr,
+ SilcPublicKey public_key,
+ void *key_context)
{
- SilcSKRKeyInternal entry, r;
-
- if (*results == NULL) {
- *results = silc_dlist_init();
- if (*results == NULL) {
- *status |= SILC_SKR_NO_MEMORY;
- return FALSE;
- }
- }
-
- /* If results is empty, just add all entries from list to results */
- if (!silc_dlist_count(*results)) {
- silc_dlist_start(list);
- while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
- silc_dlist_add(*results, entry);
+ SilcSKRStatus status = SILC_SKR_ERROR;
+ SilcPublicKeyIdentifier ident;
+ SilcSILCPublicKey silc_pubkey;
+ SilcSKRKeyInternal key;
+ SilcDList entry;
- return TRUE;
- }
+ /* Get the SILC public key */
+ silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
+ ident = &silc_pubkey->identifier;
- silc_dlist_start(*results);
- while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
+ SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username));
- /* Check if this entry is in list */
- silc_dlist_start(list);
- while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
- if (r == entry)
- break;
- }
- if (r != SILC_LIST_END)
- continue;
+ silc_mutex_lock(skr->lock);
- /* Remove from results */
- silc_dlist_del(*results, entry);
+ /* Check that this key exists */
+ if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
+ public_key, &entry, key_context, 0)) {
+ silc_mutex_unlock(skr->lock);
+ SILC_LOG_DEBUG(("Key does not exist"));
+ return status | SILC_SKR_NOT_FOUND;
}
- /* If results became empty, we did not find any key */
- if (!silc_dlist_count(*results)) {
- SILC_LOG_DEBUG(("Not all search constraints found"));
- *status |= SILC_SKR_NOT_FOUND;
- return FALSE;
- }
+ silc_dlist_start(entry);
+ key = silc_dlist_get(entry);
+ silc_dlist_uninit(entry);
+
+ silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
+ SILC_32_TO_PTR(SILC_PKCS_SILC), key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, ident->username, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_HOST, ident->host, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_REALNAME, ident->realname, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_EMAIL, ident->email, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_ORG, ident->org, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_COUNTRY, ident->country, key);
+ silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key);
- return TRUE;
+ silc_mutex_unlock(skr->lock);
+
+ return SILC_SKR_OK;
}
/* Allocate key repository */
-SilcSKR silc_skr_alloc(SilcSchedule scheduler)
+SilcSKR silc_skr_alloc(void)
{
SilcSKR skr;
if (!skr)
return NULL;
- if (!silc_skr_init(skr, scheduler)) {
+ if (!silc_skr_init(skr)) {
silc_skr_free(skr);
return NULL;
}
/* Initializes key repository */
-SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler)
+SilcBool silc_skr_init(SilcSKR skr)
{
- if (!scheduler)
- return FALSE;
-
- skr->scheduler = scheduler;
-
- if (!silc_mutex_alloc(&skr->lock))
- return FALSE;
+ silc_mutex_alloc(&skr->lock);
skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL,
silc_skr_compare, NULL,
SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcPKCSType type;
type = silc_pkcs_get_type(public_key);
- SILC_LOG_DEBUG(("Adding public key to repository"));
+ SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
switch (type) {
case SILC_PKCS_SILC:
- return silc_skr_add_silc(skr, public_key, usage, key_context);
+ return silc_skr_add_silc(skr, public_key, usage, key_context, return_key);
break;
default:
SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcPKCSType type;
type = silc_pkcs_get_type(public_key);
- SILC_LOG_DEBUG(("Adding public key to repository"));
+ SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
switch (type) {
case SILC_PKCS_SILC:
- return silc_skr_add_silc_simple(skr, public_key, usage, key_context);
+ return silc_skr_add_silc_simple(skr, public_key, usage, key_context,
+ return_key);
break;
default:
return SILC_SKR_ERROR;
}
+/* Remove key from repository */
+
+SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
+ SilcPublicKey public_key,
+ void *key_context)
+{
+ SilcPKCSType type;
+
+ if (!public_key)
+ return SILC_SKR_ERROR;
+
+ type = silc_pkcs_get_type(public_key);
+
+ SILC_LOG_DEBUG(("Deleting public key %p from repository", public_key));
+
+ switch (type) {
+
+ case SILC_PKCS_SILC:
+ return silc_skr_del_silc_public_key(skr, public_key, key_context);
+ break;
+
+ default:
+ break;
+ }
+
+ return SILC_SKR_ERROR;
+}
+
+/* Reference key */
+
+void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key)
+{
+ SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
+
+ silc_mutex_lock(skr->lock);
+ SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt + 1));
+ k->refcnt++;
+ silc_mutex_unlock(skr->lock);
+}
+
+/* Release key reference. */
+
+void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key)
+{
+ SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
+
+ silc_mutex_lock(skr->lock);
+
+ SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt - 1));
+ k->refcnt--;
+
+ if (k->refcnt == 0) {
+ /* If reference is zero, the key has been removed from the repository
+ already. Just destroy the public key. */
+ silc_pkcs_public_key_free(key->key);
+ silc_free(key);
+ }
+
+ silc_mutex_unlock(skr->lock);
+}
+
/************************** Search Constraints API **************************/
SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
{
+ if (!context)
+ return TRUE;
return silc_hash_table_add(find->constr,
SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
}
once keys has been found. */
/* This is now synchronous function but may later change async */
-SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
+SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule,
+ SilcSKRFind find,
SilcSKRFindCallback callback,
void *callback_context)
{
SilcHashTableList htl;
SilcDList list, results = NULL;
void *type, *ctx, *usage = NULL;
+#if defined(SILC_DEBUG)
+ char tmp[256];
+#endif /* SILC_DEBUG */
SILC_LOG_DEBUG(("Finding key from repository"));
silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
NULL, &usage);
+#if defined(SILC_DEBUG)
+ if (usage) {
+ memset(tmp, 0, sizeof(tmp));
+ silc_skr_type_string(SILC_SKR_FIND_USAGE, usage, tmp, sizeof(tmp) - 1);
+ SILC_LOG_DEBUG(("Finding key by %s", tmp));
+ }
+#endif /* SILC_DEBUG */
+
silc_hash_table_list(find->constr, &htl);
while (silc_hash_table_get(&htl, &type, &ctx)) {
+ /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
+ if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
+ continue;
+
#if defined(SILC_DEBUG)
- char tmp[256];
memset(tmp, 0, sizeof(tmp));
silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
ctx, tmp, sizeof(tmp) - 1);
SILC_LOG_DEBUG(("Finding key by %s", tmp));
#endif /* SILC_DEBUG */
- /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
- if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
- continue;
-
/* Find entries by this search constraint */
if (!silc_skr_find_entry(skr, &status,
(SilcSKRFindType)SILC_32_TO_PTR(type),