X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcskr%2Fsilcskr.c;h=7459d43242a02a9f49eb4d3aec58c6604cc176e0;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=1d17c62fd892550144df7fda7a0a5ecdc0568584;hpb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;p=silc.git diff --git a/lib/silcskr/silcskr.c b/lib/silcskr/silcskr.c index 1d17c62f..7459d432 100644 --- a/lib/silcskr/silcskr.c +++ b/lib/silcskr/silcskr.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 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 @@ -51,16 +51,16 @@ typedef struct { #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 */ @@ -77,21 +77,20 @@ static void silc_skr_type_string(SilcSKRFindType type, void *data, switch (type) { case SILC_SKR_FIND_PKCS_TYPE: case SILC_SKR_FIND_USAGE: - snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type], - (int)SILC_PTR_TO_32(data)); + silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type], + (int)SILC_PTR_TO_32(data)); break; case SILC_SKR_FIND_PUBLIC_KEY: - snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], - ((SilcPublicKey)data)->identifier); + case SILC_SKR_FIND_CONTEXT: + silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data); break; default: - snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], - (char *)data); + silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], + (char *)data); } } - #endif /* SILC_DEBUG */ /* Hash table destructor for search constraints */ @@ -100,6 +99,7 @@ static void silc_skr_find_destructor(void *key, void *context, 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: @@ -112,6 +112,12 @@ static void silc_skr_find_destructor(void *key, void *context, 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); } } @@ -122,27 +128,24 @@ static void silc_skr_destructor(void *key, void *context, void *user_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 */ entry->refcnt--; - if (entry->refcnt == 0) { - switch (entry->key.pk_type) { - case SILC_PKCS_SILC: - silc_pkcs_public_key_free(entry->key.key); - break; + if (entry->refcnt > 0) + return; - default: - break; - } + SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key)); - silc_free(entry); - } + silc_pkcs_public_key_free(entry->key.key); + silc_free(entry); } /* Hash table hash function for key entries */ @@ -165,7 +168,7 @@ static SilcUInt32 silc_skr_hash(void *key, void *user_context) break; } - return type->type + silc_hash_string(type->data, user_context); + return type->type + silc_hash_string_case(type->data, user_context); } /* Hash table comparison function for key entries */ @@ -268,6 +271,13 @@ static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type, { 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; @@ -278,18 +288,98 @@ static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type, 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) { - SilcPublicKeyIdentifier ident = NULL; 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_public_key_get_pkcs(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; - SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier)); + SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p", + public_key, ident->username, key_context)); silc_mutex_lock(skr->lock); @@ -298,7 +388,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status; + return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ @@ -309,16 +399,14 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, } key->key.usage = usage; - key->key.pk_type = public_key->pk_type; key->key.key = public_key; key->key.key_context = key_context; - ident = silc_pkcs_decode_identifier(public_key->identifier); - if (!ident) { - silc_mutex_unlock(skr->lock); - silc_pkcs_free_identifier(ident); - return status | SILC_SKR_NO_MEMORY; - } +#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 */ @@ -328,7 +416,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, key->refcnt++; if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE, - SILC_32_TO_PTR(public_key->pk_type), key)) + SILC_32_TO_PTR(SILC_PKCS_SILC), key)) goto err; key->refcnt++; @@ -383,12 +471,13 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, silc_mutex_unlock(skr->lock); - silc_free(ident); + if (return_key) + *return_key = (SilcSKRKey)key; + return SILC_SKR_OK; err: silc_mutex_unlock(skr->lock); - silc_free(ident); return status; } @@ -398,12 +487,16 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, 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 [%s]", public_key->identifier)); + SILC_LOG_DEBUG(("Adding SILC public key")); silc_mutex_lock(skr->lock); @@ -412,7 +505,7 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status; + return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ @@ -423,10 +516,15 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, } key->key.usage = usage; - key->key.pk_type = public_key->pk_type; 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, @@ -443,6 +541,9 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, silc_mutex_unlock(skr->lock); + if (return_key) + *return_key = (SilcSKRKey)key; + return SILC_SKR_OK; err: @@ -450,55 +551,52 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, 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; - } - } + SilcSKRStatus status = SILC_SKR_ERROR; + SilcPublicKeyIdentifier ident; + SilcSILCPublicKey silc_pubkey; + SilcSKRKeyInternal key; + SilcDList entry; - /* 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); + /* Get the SILC public key */ + silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; - return TRUE; - } + SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username)); - 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; + 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; } @@ -506,7 +604,7 @@ static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status, /* Allocate key repository */ -SilcSKR silc_skr_alloc(SilcSchedule scheduler) +SilcSKR silc_skr_alloc(void) { SilcSKR skr; @@ -514,7 +612,7 @@ SilcSKR silc_skr_alloc(SilcSchedule scheduler) if (!skr) return NULL; - if (!silc_skr_init(skr, scheduler)) { + if (!silc_skr_init(skr)) { silc_skr_free(skr); return NULL; } @@ -532,17 +630,12 @@ void silc_skr_free(SilcSKR skr) /* 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; - skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL, + skr->keys = silc_hash_table_alloc(NULL, 0, silc_skr_hash, NULL, silc_skr_compare, NULL, silc_skr_destructor, NULL, TRUE); if (!skr->keys) @@ -565,17 +658,22 @@ void silc_skr_uninit(SilcSKR skr) SilcSKRStatus silc_skr_add_public_key(SilcSKR skr, SilcPublicKey public_key, SilcSKRKeyUsage usage, - void *key_context) + void *key_context, + SilcSKRKey *return_key) { + SilcPKCSType type; + if (!public_key) return SILC_SKR_ERROR; - SILC_LOG_DEBUG(("Adding public key to repository")); + type = silc_pkcs_get_type(public_key); + + SILC_LOG_DEBUG(("Adding public key %p to repository", public_key)); - switch (public_key->pk_type) { + 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: @@ -590,17 +688,51 @@ SilcSKRStatus silc_skr_add_public_key(SilcSKR skr, 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; + if (!public_key) return SILC_SKR_ERROR; - SILC_LOG_DEBUG(("Adding public key to repository")); + type = silc_pkcs_get_type(public_key); + + 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_key); + break; + + default: + break; + } + + 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 (public_key->pk_type) { + switch (type) { case SILC_PKCS_SILC: - return silc_skr_add_silc_simple(skr, public_key, usage, key_context); + return silc_skr_del_silc_public_key(skr, public_key, key_context); break; default: @@ -610,6 +742,39 @@ SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr, 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 **************************/ @@ -623,7 +788,8 @@ SilcSKRFind silc_skr_find_alloc(void) if (!find) return NULL; - find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL, + find->constr = silc_hash_table_alloc(NULL, 0, silc_hash_uint, + NULL, NULL, NULL, silc_skr_find_destructor, NULL, TRUE); if (!find->constr) { silc_skr_find_free(find); @@ -715,6 +881,8 @@ SilcBool silc_skr_find_set_public_key(SilcSKRFind find, 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); } @@ -734,7 +902,8 @@ SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage) 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) { @@ -742,6 +911,9 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, 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")); @@ -754,21 +926,28 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, 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), @@ -809,36 +988,3 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, return NULL; } - -/* Helper function to find specificly SILC style public keys */ - -SilcAsyncOperation silc_skr_find_silc(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRFindCallback callback, - void *callback_context) -{ - SilcSKRFind find = NULL; - SilcAsyncOperation op; - - SILC_LOG_DEBUG(("Finding SILC public key")); - - if (!public_key || public_key->pk_type != SILC_PKCS_SILC) - goto err; - - find = silc_skr_find_alloc(); - if (!find) - goto err; - - if (!silc_skr_find_set_public_key(find, public_key)) - goto err; - - op = silc_skr_find(skr, find, callback, callback_context); - - return op; - - err: - if (find) - silc_skr_find_free(find); - callback(skr, NULL, SILC_SKR_ERROR, NULL, callback_context); - return NULL; -}