/* silcskr.c Author: 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 the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "silc.h" #include "silcskr.h" /************************** Types and definitions ***************************/ /* Search constraints */ typedef enum { SILC_SKR_FIND_PKCS_TYPE, SILC_SKR_FIND_USERNAME, SILC_SKR_FIND_HOST, SILC_SKR_FIND_REALNAME, SILC_SKR_FIND_EMAIL, SILC_SKR_FIND_ORG, SILC_SKR_FIND_COUNTRY, SILC_SKR_FIND_PUBLIC_KEY, SILC_SKR_FIND_CONTEXT, SILC_SKR_FIND_USAGE, /* Never added as key specific */ } SilcSKRFindType; /* Hash table key context */ typedef struct { SilcSKRFindType type; /* Type of key */ void *data; /* Hash table key */ } *SilcSKREntry, SilcSKREntryStruct; /* Foreach user context when finding entries from hash table */ typedef struct { SilcDList list; void *key_context; SilcSKRKeyUsage usage; } SilcSKRFindForeach; #if defined(SILC_DEBUG) static const char *find_name[] = { "PKCS TYPE ", "USERNAME ", "HOST ", "REALNAME ", "EMAIL ", "ORG ", "COUNTRY ", "PUBLIC KEY", "CONTEXT ", "USAGE ", NULL }; #endif /* SILC_DEBUG */ /************************ Static utility functions **************************/ #if defined(SILC_DEBUG) /* Returns search constraint string */ static void silc_skr_type_string(SilcSKRFindType type, void *data, char *retbuf, SilcUInt32 retbuf_size) { switch (type) { 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)); 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); } } #endif /* SILC_DEBUG */ /* Hash table destructor for search constraints */ 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: case SILC_SKR_FIND_USAGE: case SILC_SKR_FIND_CONTEXT: break; case SILC_SKR_FIND_PUBLIC_KEY: silc_pkcs_public_key_free(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); } } /* Hash table destructor for key entries */ 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, SILC_32_TO_PTR(pkcs_type)); silc_free(type); /* Destroy key */ entry->refcnt--; 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); } /* Hash table hash function for key entries */ static SilcUInt32 silc_skr_hash(void *key, void *user_context) { SilcSKREntry type = key; switch (type->type) { case SILC_SKR_FIND_PKCS_TYPE: case SILC_SKR_FIND_CONTEXT: return type->type + (type->type ^ SILC_PTR_TO_32(type->data)); break; case SILC_SKR_FIND_PUBLIC_KEY: return type->type + silc_hash_public_key(type->data, user_context); break; default: break; } return type->type + silc_hash_string(type->data, user_context); } /* Hash table comparison function for key entries */ static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context) { SilcSKREntry type1 = key1; SilcSKREntry type2 = key2; if (type1->type != type2->type) return FALSE; switch (type1->type) { case SILC_SKR_FIND_PKCS_TYPE: case SILC_SKR_FIND_CONTEXT: return type1->data == type2->data; break; case SILC_SKR_FIND_PUBLIC_KEY: return silc_hash_public_key_compare(type1->data, type2->data, user_context); break; default: break; } return silc_utf8_strcasecmp((const char *)type1->data, (const char *)type2->data); } /* Foreach function for finding entries in the repository */ static void silc_skr_find_foreach(void *key, void *context, void *user_context) { SilcSKRFindForeach *f = user_context; SilcSKRKeyInternal k = context; if (k) { /* If key context is present, it must match the context in the key. This is used only internally when adding keys, to check if the key is added with same context. */ if (f->key_context && f->key_context != k->key.key_context) return; /* Check for usage bits. At least one usage bit must be set. */ if (f->usage && k->key.usage && (f->usage & k->key.usage) == 0) return; silc_dlist_add(f->list, k); } } /* Finds entry from repository by search constraint type and data */ static SilcBool silc_skr_find_entry(SilcSKR skr, SilcSKRStatus *status, SilcSKRFindType type, void *type_data, SilcDList *results, void *key_context, SilcSKRKeyUsage usage) { SilcSKREntryStruct find; SilcSKRFindForeach f; f.list = silc_dlist_init(); if (!f.list) { *status |= SILC_SKR_NO_MEMORY; return FALSE; } f.key_context = key_context; f.usage = usage; find.type = type; find.data = type_data; silc_hash_table_find_foreach(skr->keys, (void *)&find, silc_skr_find_foreach, &f); if (!silc_dlist_count(f.list)) { *status |= SILC_SKR_NOT_FOUND; silc_dlist_uninit(f.list); return FALSE; } if (results) *results = f.list; else silc_dlist_uninit(f.list); return TRUE; } /* Add a key by search constraint type to repository */ static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type, void *type_data, SilcSKRKeyInternal key) { 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; entry->type = type; entry->data = type_data; 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, 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 %p [%s], context %p", public_key, ident->username, key_context)); silc_mutex_lock(skr->lock); /* Check that this key hasn't been added already */ if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ key = silc_calloc(1, sizeof(*key)); if (!key) { silc_mutex_unlock(skr->lock); return status | SILC_SKR_NO_MEMORY; } key->key.usage = usage; 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, public_key, key)) goto err; key->refcnt++; if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE, SILC_32_TO_PTR(SILC_PKCS_SILC), key)) goto err; key->refcnt++; if (ident->username) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME, ident->username, key)) goto err; key->refcnt++; } if (ident->host) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST, ident->host, key)) goto err; key->refcnt++; } if (ident->realname) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME, ident->realname, key)) goto err; key->refcnt++; } if (ident->email) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL, ident->email, key)) goto err; key->refcnt++; } if (ident->org) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG, ident->org, key)) goto err; key->refcnt++; } if (ident->country) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY, ident->country, key)) goto err; key->refcnt++; } if (key_context) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key)) goto err; key->refcnt++; } silc_mutex_unlock(skr->lock); if (return_key) *return_key = (SilcSKRKey)key; return SILC_SKR_OK; err: silc_mutex_unlock(skr->lock); return status; } /* Add SILC style public key to repository, and only the public key, not other details from the key. */ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, SilcPublicKey public_key, SilcSKRKeyUsage usage, 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")); silc_mutex_lock(skr->lock); /* Check that this key hasn't been added already */ if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ key = silc_calloc(1, sizeof(*key)); if (!key) { silc_mutex_unlock(skr->lock); return status | SILC_SKR_NO_MEMORY; } key->key.usage = usage; 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, public_key, key)) goto err; key->refcnt++; if (key_context) { if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key)) goto err; key->refcnt++; } silc_mutex_unlock(skr->lock); if (return_key) *return_key = (SilcSKRKey)key; return SILC_SKR_OK; err: silc_mutex_unlock(skr->lock); return status; } /* Deletes SILC public key from repository */ static SilcSKRStatus silc_skr_del_silc_public_key(SilcSKR skr, SilcPublicKey public_key, void *key_context) { SilcSKRStatus status = SILC_SKR_ERROR; SilcPublicKeyIdentifier ident; SilcSILCPublicKey silc_pubkey; SilcSKRKeyInternal key; SilcDList entry; /* Get the SILC public key */ silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); ident = &silc_pubkey->identifier; SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username)); silc_mutex_lock(skr->lock); /* 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; } 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); silc_mutex_unlock(skr->lock); return SILC_SKR_OK; } /**************************** Key Repository API ****************************/ /* Allocate key repository */ SilcSKR silc_skr_alloc(void) { SilcSKR skr; skr = silc_calloc(1, sizeof(*skr)); if (!skr) return NULL; if (!silc_skr_init(skr)) { silc_skr_free(skr); return NULL; } return skr; } /* Free key repository */ void silc_skr_free(SilcSKR skr) { silc_skr_uninit(skr); silc_free(skr); } /* Initializes key repository */ SilcBool silc_skr_init(SilcSKR skr) { silc_mutex_alloc(&skr->lock); skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL, silc_skr_compare, NULL, silc_skr_destructor, NULL, TRUE); if (!skr->keys) return FALSE; return TRUE; } /* Uninitializes key repository */ void silc_skr_uninit(SilcSKR skr) { if (skr->keys) silc_hash_table_free(skr->keys); silc_mutex_free(skr->lock); } /* Adds public key to key repository */ SilcSKRStatus silc_skr_add_public_key(SilcSKR skr, SilcPublicKey public_key, SilcSKRKeyUsage usage, void *key_context, SilcSKRKey *return_key) { SilcPKCSType type; if (!public_key) return SILC_SKR_ERROR; 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(skr, public_key, usage, key_context, return_key); break; default: break; } return SILC_SKR_ERROR; } /* Adds public key to repository. */ SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr, SilcPublicKey public_key, SilcSKRKeyUsage usage, void *key_context, SilcSKRKey *return_key) { SilcPKCSType type; if (!public_key) return SILC_SKR_ERROR; 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 (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 **************************/ /* Allocate search constraints */ SilcSKRFind silc_skr_find_alloc(void) { SilcSKRFind find; find = silc_calloc(1, sizeof(*find)); if (!find) return NULL; find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL, silc_skr_find_destructor, NULL, TRUE); if (!find->constr) { silc_skr_find_free(find); return NULL; } return find; } /* Free search constraints */ void silc_skr_find_free(SilcSKRFind find) { if (find->constr) silc_hash_table_free(find->constr); silc_free(find); } SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type) { return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE), SILC_32_TO_PTR(type)); } SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username) { void *c = silc_memdup(username, strlen(username)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c); } SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host) { void *c = silc_memdup(host, strlen(host)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c); } SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname) { void *c = silc_memdup(realname, strlen(realname)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c); } SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email) { void *c = silc_memdup(email, strlen(email)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c); } SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org) { void *c = silc_memdup(org, strlen(org)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c); } SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country) { void *c = silc_memdup(country, strlen(country)); if (!c) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c); } SilcBool silc_skr_find_set_public_key(SilcSKRFind find, SilcPublicKey public_key) { SilcPublicKey pk = silc_pkcs_public_key_copy(public_key); if (!pk) return FALSE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk); } 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); } SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage) { if (!usage) return TRUE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE), SILC_32_TO_PTR(usage)); } /******************************** Search API ********************************/ /* Finds key(s) by the set search constraints. The callback will be called once keys has been found. */ /* This is now synchronous function but may later change async */ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule, SilcSKRFind find, SilcSKRFindCallback callback, void *callback_context) { SilcSKRStatus status = SILC_SKR_ERROR; 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")); if (!find || !callback) return NULL; silc_mutex_lock(skr->lock); /* Get usage bits, if searching by them */ 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) 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 */ /* Find entries by this search constraint */ if (!silc_skr_find_entry(skr, &status, (SilcSKRFindType)SILC_32_TO_PTR(type), ctx, &list, NULL, SILC_PTR_TO_32(usage))) { SILC_LOG_DEBUG(("Not found")); if (results) { silc_dlist_uninit(results); results = NULL; } break; } /* For now, our logic rule is AND. All constraints must be found to find the key. Later OR might be added also. */ if (!silc_skr_results_and(list, &status, &results)) { SILC_LOG_DEBUG(("Not found")); if (results) { silc_dlist_uninit(results); results = NULL; } silc_dlist_uninit(list); break; } silc_dlist_uninit(list); } silc_hash_table_list_reset(&htl); silc_mutex_unlock(skr->lock); /* Return results */ if (!results) { callback(skr, find, status, NULL, callback_context); } else { silc_dlist_start(results); callback(skr, find, SILC_SKR_OK, results, callback_context); } return NULL; }