5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
23 /************************** Types and definitions ***************************/
25 /* Search constraints */
27 SILC_SKR_FIND_PKCS_TYPE,
28 SILC_SKR_FIND_USERNAME,
30 SILC_SKR_FIND_REALNAME,
33 SILC_SKR_FIND_COUNTRY,
34 SILC_SKR_FIND_PUBLIC_KEY,
35 SILC_SKR_FIND_CONTEXT,
36 SILC_SKR_FIND_USAGE, /* Never added as key specific */
39 /* Hash table key context */
41 SilcSKRFindType type; /* Type of key */
42 void *data; /* Hash table key */
43 } *SilcSKREntry, SilcSKREntryStruct;
45 /* Foreach user context when finding entries from hash table */
49 SilcSKRKeyUsage usage;
52 #if defined(SILC_DEBUG)
53 static const char *find_name[] = {
66 #endif /* SILC_DEBUG */
68 /************************ Static utility functions **************************/
70 #if defined(SILC_DEBUG)
72 /* Returns search constraint string */
74 static void silc_skr_type_string(SilcSKRFindType type, void *data,
75 char *retbuf, SilcUInt32 retbuf_size)
78 case SILC_SKR_FIND_PKCS_TYPE:
79 case SILC_SKR_FIND_USAGE:
80 silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
81 (int)SILC_PTR_TO_32(data));
84 case SILC_SKR_FIND_PUBLIC_KEY:
85 case SILC_SKR_FIND_CONTEXT:
86 silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
90 silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
94 #endif /* SILC_DEBUG */
96 /* Hash table destructor for search constraints */
98 static void silc_skr_find_destructor(void *key, void *context,
101 SilcSKRFindType type = SILC_PTR_TO_32(key);
102 SilcPKCSType pkcs_type = SILC_PTR_TO_32(user_context);
105 case SILC_SKR_FIND_PKCS_TYPE:
106 case SILC_SKR_FIND_USAGE:
107 case SILC_SKR_FIND_CONTEXT:
110 case SILC_SKR_FIND_PUBLIC_KEY:
111 silc_pkcs_public_key_free(context);
115 /* In SILC Public key all entries are referenced from the public key
116 so don't free them. This test is valid only when removing key
117 from the repository. */
118 if (pkcs_type == SILC_PKCS_SILC)
125 /* Hash table destructor for key entries */
127 static void silc_skr_destructor(void *key, void *context, void *user_context)
129 SilcSKREntry type = key;
130 SilcSKRKeyInternal entry = context;
131 SilcPKCSType pkcs_type = silc_pkcs_get_type(entry->key.key);
133 /* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it
134 shares same context with the key entry. */
135 if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY)
136 silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data,
137 SILC_32_TO_PTR(pkcs_type));
142 if (entry->refcnt > 0)
145 SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key));
147 silc_pkcs_public_key_free(entry->key.key);
151 /* Hash table hash function for key entries */
153 static SilcUInt32 silc_skr_hash(void *key, void *user_context)
155 SilcSKREntry type = key;
157 switch (type->type) {
158 case SILC_SKR_FIND_PKCS_TYPE:
159 case SILC_SKR_FIND_CONTEXT:
160 return type->type + (type->type ^ SILC_PTR_TO_32(type->data));
163 case SILC_SKR_FIND_PUBLIC_KEY:
164 return type->type + silc_hash_public_key(type->data, user_context);
171 return type->type + silc_hash_string_case(type->data, user_context);
174 /* Hash table comparison function for key entries */
176 static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context)
178 SilcSKREntry type1 = key1;
179 SilcSKREntry type2 = key2;
181 if (type1->type != type2->type)
184 switch (type1->type) {
185 case SILC_SKR_FIND_PKCS_TYPE:
186 case SILC_SKR_FIND_CONTEXT:
187 return type1->data == type2->data;
190 case SILC_SKR_FIND_PUBLIC_KEY:
191 return silc_hash_public_key_compare(type1->data, type2->data,
199 return silc_utf8_strcasecmp((const char *)type1->data,
200 (const char *)type2->data);
203 /* Foreach function for finding entries in the repository */
205 static void silc_skr_find_foreach(void *key, void *context,
208 SilcSKRFindForeach *f = user_context;
209 SilcSKRKeyInternal k = context;
212 /* If key context is present, it must match the context in the key.
213 This is used only internally when adding keys, to check if the key
214 is added with same context. */
215 if (f->key_context && f->key_context != k->key.key_context)
218 /* Check for usage bits. At least one usage bit must be set. */
219 if (f->usage && k->key.usage && (f->usage & k->key.usage) == 0)
222 silc_dlist_add(f->list, k);
226 /* Finds entry from repository by search constraint type and data */
228 static SilcBool silc_skr_find_entry(SilcSKR skr,
229 SilcSKRStatus *status,
230 SilcSKRFindType type,
234 SilcSKRKeyUsage usage)
236 SilcSKREntryStruct find;
237 SilcSKRFindForeach f;
239 f.list = silc_dlist_init();
241 *status |= SILC_SKR_NO_MEMORY;
244 f.key_context = key_context;
248 find.data = type_data;
250 silc_hash_table_find_foreach(skr->keys, (void *)&find,
251 silc_skr_find_foreach, &f);
253 if (!silc_dlist_count(f.list)) {
254 *status |= SILC_SKR_NOT_FOUND;
255 silc_dlist_uninit(f.list);
262 silc_dlist_uninit(f.list);
267 /* Add a key by search constraint type to repository */
269 static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type,
270 void *type_data, SilcSKRKeyInternal key)
274 #if defined(SILC_DEBUG)
276 memset(tmp, 0, sizeof(tmp));
277 silc_skr_type_string(type, type_data, tmp, sizeof(tmp) - 1);
278 SILC_LOG_DEBUG(("Search constraint %s", tmp));
279 #endif /* SILC_DEBUG */
281 entry = silc_calloc(1, sizeof(*entry));
286 entry->data = type_data;
288 return silc_hash_table_add(skr->keys, entry, key);
291 /* Delete a key by search constraint type from repository */
293 static SilcBool silc_skr_del_entry(SilcSKR skr, SilcSKRFindType type,
294 void *type_data, SilcSKRKeyInternal key)
296 SilcSKREntryStruct entry;
302 entry.data = type_data;
304 return silc_hash_table_del_by_context(skr->keys, &entry, key);
307 /* This performs AND operation. Any entry already in `results' that is not
308 in `list' will be removed from `results'. */
310 static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
313 SilcSKRKeyInternal entry, r;
315 if (*results == NULL) {
316 *results = silc_dlist_init();
317 if (*results == NULL) {
318 *status |= SILC_SKR_NO_MEMORY;
323 /* If results is empty, just add all entries from list to results */
324 if (!silc_dlist_count(*results)) {
325 silc_dlist_start(list);
326 while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
327 silc_dlist_add(*results, entry);
332 silc_dlist_start(*results);
333 while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
335 /* Check if this entry is in list */
336 silc_dlist_start(list);
337 while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
341 if (r != SILC_LIST_END)
344 /* Remove from results */
345 silc_dlist_del(*results, entry);
348 /* If results became empty, we did not find any key */
349 if (!silc_dlist_count(*results)) {
350 SILC_LOG_DEBUG(("Not all search constraints found"));
351 *status |= SILC_SKR_NOT_FOUND;
359 /***************************** SILC Public Key ******************************/
361 /* Add SILC style public key to repository */
363 static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
364 SilcPublicKey public_key,
365 SilcSKRKeyUsage usage,
367 SilcSKRKey *return_key)
369 SilcSKRKeyInternal key;
370 SilcSKRStatus status = SILC_SKR_ERROR;
371 SilcPublicKeyIdentifier ident;
372 SilcSILCPublicKey silc_pubkey;
373 #if defined(SILC_DEBUG)
375 #endif /* SILC_DEBUG */
377 /* Get the SILC public key */
378 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
379 ident = &silc_pubkey->identifier;
381 SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p",
382 public_key, ident->username, key_context));
384 silc_mutex_lock(skr->lock);
386 /* Check that this key hasn't been added already */
387 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
388 public_key, NULL, key_context, 0)) {
389 silc_mutex_unlock(skr->lock);
390 SILC_LOG_DEBUG(("Key already added"));
391 return status | SILC_SKR_ALREADY_EXIST;
394 /* Allocate key entry */
395 key = silc_calloc(1, sizeof(*key));
397 silc_mutex_unlock(skr->lock);
398 return status | SILC_SKR_NO_MEMORY;
401 key->key.usage = usage;
402 key->key.key = public_key;
403 key->key.key_context = key_context;
405 #if defined(SILC_DEBUG)
406 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
407 tmp, sizeof(tmp) - 1);
408 SILC_LOG_DEBUG((" Search constraint %s", tmp));
409 #endif /* SILC_DEBUG */
411 /* Add key specifics */
413 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
418 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
419 SILC_32_TO_PTR(SILC_PKCS_SILC), key))
423 if (ident->username) {
424 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
425 ident->username, key))
431 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST,
437 if (ident->realname) {
438 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME,
439 ident->realname, key))
445 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL,
452 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG,
458 if (ident->country) {
459 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY,
460 ident->country, key))
466 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
472 silc_mutex_unlock(skr->lock);
475 *return_key = (SilcSKRKey)key;
480 silc_mutex_unlock(skr->lock);
484 /* Add SILC style public key to repository, and only the public key, not
485 other details from the key. */
487 static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
488 SilcPublicKey public_key,
489 SilcSKRKeyUsage usage,
491 SilcSKRKey *return_key)
493 SilcSKRKeyInternal key;
494 SilcSKRStatus status = SILC_SKR_ERROR;
495 #if defined(SILC_DEBUG)
497 #endif /* SILC_DEBUG */
499 SILC_LOG_DEBUG(("Adding SILC public key"));
501 silc_mutex_lock(skr->lock);
503 /* Check that this key hasn't been added already */
504 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
505 public_key, NULL, key_context, 0)) {
506 silc_mutex_unlock(skr->lock);
507 SILC_LOG_DEBUG(("Key already added"));
508 return status | SILC_SKR_ALREADY_EXIST;
511 /* Allocate key entry */
512 key = silc_calloc(1, sizeof(*key));
514 silc_mutex_unlock(skr->lock);
515 return status | SILC_SKR_NO_MEMORY;
518 key->key.usage = usage;
519 key->key.key = public_key;
520 key->key.key_context = key_context;
522 #if defined(SILC_DEBUG)
523 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
524 tmp, sizeof(tmp) - 1);
525 SILC_LOG_DEBUG(("Search cons %s", tmp));
526 #endif /* SILC_DEBUG */
528 /* Add key specifics */
530 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
536 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
542 silc_mutex_unlock(skr->lock);
545 *return_key = (SilcSKRKey)key;
550 silc_mutex_unlock(skr->lock);
554 /* Deletes SILC public key from repository */
556 static SilcSKRStatus silc_skr_del_silc_public_key(SilcSKR skr,
557 SilcPublicKey public_key,
560 SilcSKRStatus status = SILC_SKR_ERROR;
561 SilcPublicKeyIdentifier ident;
562 SilcSILCPublicKey silc_pubkey;
563 SilcSKRKeyInternal key;
566 /* Get the SILC public key */
567 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
568 ident = &silc_pubkey->identifier;
570 SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username));
572 silc_mutex_lock(skr->lock);
574 /* Check that this key exists */
575 if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
576 public_key, &entry, key_context, 0)) {
577 silc_mutex_unlock(skr->lock);
578 SILC_LOG_DEBUG(("Key does not exist"));
579 return status | SILC_SKR_NOT_FOUND;
582 silc_dlist_start(entry);
583 key = silc_dlist_get(entry);
584 silc_dlist_uninit(entry);
586 silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key);
587 silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
588 SILC_32_TO_PTR(SILC_PKCS_SILC), key);
589 silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, ident->username, key);
590 silc_skr_del_entry(skr, SILC_SKR_FIND_HOST, ident->host, key);
591 silc_skr_del_entry(skr, SILC_SKR_FIND_REALNAME, ident->realname, key);
592 silc_skr_del_entry(skr, SILC_SKR_FIND_EMAIL, ident->email, key);
593 silc_skr_del_entry(skr, SILC_SKR_FIND_ORG, ident->org, key);
594 silc_skr_del_entry(skr, SILC_SKR_FIND_COUNTRY, ident->country, key);
595 silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key);
597 silc_mutex_unlock(skr->lock);
603 /**************************** Key Repository API ****************************/
605 /* Allocate key repository */
607 SilcSKR silc_skr_alloc(void)
611 skr = silc_calloc(1, sizeof(*skr));
615 if (!silc_skr_init(skr)) {
623 /* Free key repository */
625 void silc_skr_free(SilcSKR skr)
627 silc_skr_uninit(skr);
631 /* Initializes key repository */
633 SilcBool silc_skr_init(SilcSKR skr)
635 if (!silc_mutex_alloc(&skr->lock))
638 skr->keys = silc_hash_table_alloc(NULL, 0, silc_skr_hash, NULL,
639 silc_skr_compare, NULL,
640 silc_skr_destructor, NULL, TRUE);
647 /* Uninitializes key repository */
649 void silc_skr_uninit(SilcSKR skr)
652 silc_hash_table_free(skr->keys);
653 silc_mutex_free(skr->lock);
656 /* Adds public key to key repository */
658 SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
659 SilcPublicKey public_key,
660 SilcSKRKeyUsage usage,
662 SilcSKRKey *return_key)
667 return SILC_SKR_ERROR;
669 type = silc_pkcs_get_type(public_key);
671 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
676 return silc_skr_add_silc(skr, public_key, usage, key_context, return_key);
683 return SILC_SKR_ERROR;
686 /* Adds public key to repository. */
688 SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
689 SilcPublicKey public_key,
690 SilcSKRKeyUsage usage,
692 SilcSKRKey *return_key)
697 return SILC_SKR_ERROR;
699 type = silc_pkcs_get_type(public_key);
701 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
706 return silc_skr_add_silc_simple(skr, public_key, usage, key_context,
714 return SILC_SKR_ERROR;
717 /* Remove key from repository */
719 SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
720 SilcPublicKey public_key,
726 return SILC_SKR_ERROR;
728 type = silc_pkcs_get_type(public_key);
730 SILC_LOG_DEBUG(("Deleting public key %p from repository", public_key));
735 return silc_skr_del_silc_public_key(skr, public_key, key_context);
742 return SILC_SKR_ERROR;
747 void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key)
749 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
751 silc_mutex_lock(skr->lock);
752 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt + 1));
754 silc_mutex_unlock(skr->lock);
757 /* Release key reference. */
759 void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key)
761 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
763 silc_mutex_lock(skr->lock);
765 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt - 1));
768 if (k->refcnt == 0) {
769 /* If reference is zero, the key has been removed from the repository
770 already. Just destroy the public key. */
771 silc_pkcs_public_key_free(key->key);
775 silc_mutex_unlock(skr->lock);
779 /************************** Search Constraints API **************************/
781 /* Allocate search constraints */
783 SilcSKRFind silc_skr_find_alloc(void)
787 find = silc_calloc(1, sizeof(*find));
791 find->constr = silc_hash_table_alloc(NULL, 0, silc_hash_uint,
793 silc_skr_find_destructor, NULL, TRUE);
795 silc_skr_find_free(find);
802 /* Free search constraints */
804 void silc_skr_find_free(SilcSKRFind find)
807 silc_hash_table_free(find->constr);
811 SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type)
813 return silc_hash_table_add(find->constr,
814 SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE),
815 SILC_32_TO_PTR(type));
818 SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username)
820 void *c = silc_memdup(username, strlen(username));
823 return silc_hash_table_add(find->constr,
824 SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c);
827 SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host)
829 void *c = silc_memdup(host, strlen(host));
832 return silc_hash_table_add(find->constr,
833 SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c);
836 SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname)
838 void *c = silc_memdup(realname, strlen(realname));
841 return silc_hash_table_add(find->constr,
842 SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c);
845 SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email)
847 void *c = silc_memdup(email, strlen(email));
850 return silc_hash_table_add(find->constr,
851 SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c);
854 SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org)
856 void *c = silc_memdup(org, strlen(org));
859 return silc_hash_table_add(find->constr,
860 SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c);
863 SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country)
865 void *c = silc_memdup(country, strlen(country));
868 return silc_hash_table_add(find->constr,
869 SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c);
872 SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
873 SilcPublicKey public_key)
875 SilcPublicKey pk = silc_pkcs_public_key_copy(public_key);
878 return silc_hash_table_add(find->constr,
879 SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk);
882 SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
886 return silc_hash_table_add(find->constr,
887 SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
890 SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage)
894 return silc_hash_table_add(find->constr,
895 SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
896 SILC_32_TO_PTR(usage));
899 /******************************** Search API ********************************/
901 /* Finds key(s) by the set search constraints. The callback will be called
902 once keys has been found. */
903 /* This is now synchronous function but may later change async */
905 SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule,
907 SilcSKRFindCallback callback,
908 void *callback_context)
910 SilcSKRStatus status = SILC_SKR_ERROR;
911 SilcHashTableList htl;
912 SilcDList list, results = NULL;
913 void *type, *ctx, *usage = NULL;
914 #if defined(SILC_DEBUG)
916 #endif /* SILC_DEBUG */
918 SILC_LOG_DEBUG(("Finding key from repository"));
920 if (!find || !callback)
923 silc_mutex_lock(skr->lock);
925 /* Get usage bits, if searching by them */
926 silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
929 #if defined(SILC_DEBUG)
931 memset(tmp, 0, sizeof(tmp));
932 silc_skr_type_string(SILC_SKR_FIND_USAGE, usage, tmp, sizeof(tmp) - 1);
933 SILC_LOG_DEBUG(("Finding key by %s", tmp));
935 #endif /* SILC_DEBUG */
937 silc_hash_table_list(find->constr, &htl);
938 while (silc_hash_table_get(&htl, &type, &ctx)) {
940 /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
941 if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
944 #if defined(SILC_DEBUG)
945 memset(tmp, 0, sizeof(tmp));
946 silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
947 ctx, tmp, sizeof(tmp) - 1);
948 SILC_LOG_DEBUG(("Finding key by %s", tmp));
949 #endif /* SILC_DEBUG */
951 /* Find entries by this search constraint */
952 if (!silc_skr_find_entry(skr, &status,
953 (SilcSKRFindType)SILC_32_TO_PTR(type),
954 ctx, &list, NULL, SILC_PTR_TO_32(usage))) {
955 SILC_LOG_DEBUG(("Not found"));
957 silc_dlist_uninit(results);
963 /* For now, our logic rule is AND. All constraints must be found
964 to find the key. Later OR might be added also. */
965 if (!silc_skr_results_and(list, &status, &results)) {
966 SILC_LOG_DEBUG(("Not found"));
968 silc_dlist_uninit(results);
971 silc_dlist_uninit(list);
975 silc_dlist_uninit(list);
977 silc_hash_table_list_reset(&htl);
979 silc_mutex_unlock(skr->lock);
983 callback(skr, find, status, NULL, callback_context);
985 silc_dlist_start(results);
986 callback(skr, find, SILC_SKR_OK, results, callback_context);