+ if (!parse_only)
+ silc_server_query_process(server, query, TRUE);
+
+ return TRUE;
+}
+
+/* Context for holding clients searched by public key. */
+typedef struct {
+ SilcClientEntry **clients;
+ SilcUInt32 *clients_count;
+ SilcBool found;
+} *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
+
+/* SKR find callbcak */
+
+static void silc_server_query_skr_callback(SilcSKR skr,
+ SilcSKRFind find,
+ SilcSKRStatus status,
+ SilcDList keys,
+ void *context)
+{
+ SilcServerPublicKeyUser uc = context;
+ SilcSKRKey key;
+
+ if (keys) {
+ (*uc->clients) = silc_realloc((*uc->clients),
+ sizeof((**uc->clients)) *
+ ((*uc->clients_count) +
+ silc_dlist_count(keys)));
+
+ silc_dlist_start(keys);
+ while ((key = silc_dlist_get(keys)))
+ (*uc->clients)[(*uc->clients_count)++] = key->key_context;
+
+ uc->found = TRUE;
+ silc_dlist_uninit(keys);
+ }
+
+ silc_skr_find_free(find);
+}
+
+/* If clients are set, limit the found clients using the attributes in
+ the query. If clients are not set, try to find some clients using
+ the attributes */
+
+void silc_server_query_check_attributes(SilcServer server,
+ SilcServerQuery query,
+ SilcClientEntry **clients,
+ SilcUInt32 *clients_count) {
+ SilcClientEntry entry;
+ SilcAttributePayload attr;
+ SilcAttribute attribute;
+ SilcAttributeObjPk pk;
+ SilcPublicKey publickey, cmp_pubkey;
+ SilcPKCSType type;
+ SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
+ int i;
+
+ /* If no clients were found, we only check the attributes
+ if the user wasn't searching for nickname/ids */
+ if (!(*clients)) {
+ no_clients = TRUE;
+ if (query->nickname[0] || query->ids_count)
+ return;
+ }
+
+ silc_dlist_start(query->attrs);
+ while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
+ attribute = silc_attribute_get_attribute(attr);
+ switch (attribute) {
+
+ case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
+ SILC_LOG_DEBUG(("Finding clients by public key attribute"));
+
+ if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
+ continue;
+
+ if (!strcmp(pk.type, "silc-rsa"))
+ type = SILC_PKCS_SILC;
+ else if (!strcmp(pk.type, "ssh-rsa"))
+ type = SILC_PKCS_SSH2;
+ else if (!strcmp(pk.type, "x509v3-sign-rsa"))
+ type = SILC_PKCS_X509V3;
+ else if (!strcmp(pk.type, "pgp-sign-rsa"))
+ type = SILC_PKCS_OPENPGP;
+ else
+ continue;
+
+ if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
+ &publickey)) {
+ silc_free(pk.type);
+ silc_free(pk.data);
+ continue;
+ }
+ search_pubkey = TRUE;
+
+ /* If no clients were set on calling this function, we just search
+ for clients, otherwise we try to limit the clients. */
+ if (no_clients) {
+ SilcServerPublicKeyUserStruct usercontext;
+ SilcSKRFind find;
+
+ usercontext.clients = clients;
+ usercontext.clients_count = clients_count;
+ usercontext.found = FALSE;
+
+ find = silc_skr_find_alloc();
+ if (!find)
+ continue;
+
+ silc_skr_find_set_public_key(find, publickey);
+ silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
+ silc_skr_find(server->repository, server->schedule,
+ find, silc_server_query_skr_callback, &usercontext);
+
+ if (usercontext.found == TRUE)
+ found = TRUE;
+ } else {
+ for (i = 0; i < *clients_count; i++) {
+ entry = (*clients)[i];
+
+ if (!entry->data.public_key)
+ continue;
+
+ if (silc_server_get_public_key_by_client(server, entry,
+ &cmp_pubkey)) {
+ if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
+ found = TRUE;
+ continue;
+ }
+ }
+
+ (*clients)[i] = NULL;
+ }
+ }
+ silc_free(pk.type);
+ silc_free(pk.data);
+ silc_pkcs_public_key_free(publickey);
+ break;
+ }
+ }
+
+ if (!found && !query->nickname[0] && !query->ids)
+ silc_server_query_add_error(server, query, 2, 0,
+ search_pubkey ?
+ SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);