5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 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.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 0 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname, normalized */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name, normalized */
57 char *channel_name; /* Queried channel name, normalized */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `type'. If `type' is 0 the index is to query->ids, if
177 it is 1 it is index to the command context arguments, and if it is
178 2 the index is ignored and no argument is included in the error. */
180 void silc_server_query_add_error(SilcServer server,
181 SilcServerQuery query,
186 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187 (query->errors_count + 1));
190 query->errors[query->errors_count].index = index;
191 query->errors[query->errors_count].type = type;
192 query->errors[query->errors_count].error = error;
193 query->errors[query->errors_count].id = NULL;
194 query->errors[query->errors_count].id_type = 0;
195 query->errors_count++;
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199 with error sending with this error type. */
201 void silc_server_query_add_error_id(SilcServer server,
202 SilcServerQuery query,
204 void *id, SilcIdType id_type)
206 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207 (query->errors_count + 1));
210 query->errors[query->errors_count].index = 0;
211 query->errors[query->errors_count].type = 0;
212 query->errors[query->errors_count].error = error;
213 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214 query->errors[query->errors_count].id_type = id_type;
215 query->errors_count++;
218 /* Processes query as command. The `query' is the command that is
219 being processed indicated by the `cmd'. The `query' can be one of
220 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221 SILC_COMMAND_IDENTIFY. This function handles the reply sending
222 to the entity who sent this query to us automatically. Returns
223 TRUE if the query is being processed or FALSE on error. */
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226 SilcServerCommandContext cmd)
228 SilcServerQuery query;
230 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
232 query = silc_calloc(1, sizeof(*query));
233 query->querycmd = querycmd;
234 query->cmd = silc_server_command_dup(cmd);
238 case SILC_COMMAND_WHOIS:
239 /* If we are normal server and query contains nickname OR query
240 doesn't contain nickname or ids BUT attributes, send it to the
242 if (server->server_type != SILC_ROUTER && !server->standalone &&
243 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248 silc_server_query_send_router(server, query);
253 case SILC_COMMAND_WHOWAS:
254 /* WHOWAS query is always sent to router if we are normal server */
255 if (server->server_type == SILC_SERVER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_IDENTIFY:
263 /* If we are normal server and query does not contain IDs, send it
264 directly to router (it contains nickname, server name or channel
266 if (server->server_type == SILC_SERVER && !server->standalone &&
267 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269 silc_server_query_send_router(server, query);
275 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276 silc_server_query_free(query);
280 /* Now parse the request */
281 silc_server_query_parse(server, query);
286 /* Send the received query to our primary router since we could not
287 handle the query directly. We will reprocess the query after our
288 router replies back. */
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
293 SilcUInt16 old_ident;
295 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
297 /* Send WHOIS command to our router */
298 old_ident = silc_command_get_ident(query->cmd->payload);
299 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
300 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
301 silc_server_packet_send(server,
302 SILC_PRIMARY_ROUTE(server),
303 SILC_PACKET_COMMAND, 0,
304 tmpbuf->data, tmpbuf->len, TRUE);
305 silc_command_set_ident(query->cmd->payload, old_ident);
306 silc_buffer_free(tmpbuf);
308 query->resolved = TRUE;
310 /* Continue parsing the query after received reply from router */
311 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
312 silc_server_query_send_router_reply, query);
315 /* Reply callback called after primary router has replied to our initial
316 sending of the query to it. We will proceed the query in this function. */
318 void silc_server_query_send_router_reply(void *context, void *reply)
320 SilcServerQuery query = context;
321 SilcServer server = query->cmd->server;
322 SilcServerCommandReplyContext cmdr = reply;
324 SILC_LOG_DEBUG(("Received reply from router to query"));
326 /* Check if router sent error reply */
327 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
330 SILC_LOG_DEBUG(("Sending error to original query"));
332 /* Send the same command reply payload which contains the error */
333 silc_command_set_command(cmdr->payload, query->querycmd);
334 silc_command_set_ident(cmdr->payload,
335 silc_command_get_ident(query->cmd->payload));
336 buffer = silc_command_payload_encode_payload(cmdr->payload);
337 silc_server_packet_send(server, query->cmd->sock,
338 SILC_PACKET_COMMAND_REPLY, 0,
339 buffer->data, buffer->len, FALSE);
340 silc_buffer_free(buffer);
341 silc_server_query_free(query);
345 /* Continue with parsing */
346 silc_server_query_parse(server, query);
349 /* Parse the command query and start processing the queries in detail. */
351 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
353 SilcServerCommandContext cmd = query->cmd;
355 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
360 SILC_LOG_DEBUG(("Parsing %s query",
361 silc_get_command_name(query->querycmd)));
363 switch (query->querycmd) {
365 case SILC_COMMAND_WHOIS:
366 /* Get requested attributes if set */
367 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
368 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
369 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
371 /* When Requested Attributes is present we will assure that this
372 client cannot execute the WHOIS command too fast. This would be
373 same as having SILC_CF_LAG_STRICT. */
374 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
375 cmd->sock->user_data)
376 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
379 /* Get Client IDs if present. Take IDs always instead of nickname. */
380 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
384 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
385 if (!tmp && !query->attrs) {
386 /* No nickname, no ids and no attributes - send error */
387 silc_server_query_send_error(server, query,
388 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
389 silc_server_query_free(query);
393 /* Get the nickname@server string and parse it */
394 if (tmp && ((tmp_len > 128) ||
395 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
396 silc_server_query_send_error(server, query,
397 SILC_STATUS_ERR_BAD_NICKNAME, 0);
398 silc_server_query_free(query);
403 if (query->nickname) {
404 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
405 SILC_STRING_UTF8, 128, &tmp_len);
407 silc_server_query_send_error(server, query,
408 SILC_STATUS_ERR_BAD_NICKNAME, 0);
409 silc_server_query_free(query);
412 silc_free(query->nickname);
413 query->nickname = tmp;
417 /* Parse the IDs included in the query */
418 query->ids = silc_calloc(argc, sizeof(*query->ids));
420 for (i = 0; i < argc; i++) {
421 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
425 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
426 if (!id || id_type != SILC_ID_CLIENT) {
427 silc_server_query_add_error(server, query, 1, i + 4,
428 SILC_STATUS_ERR_BAD_CLIENT_ID);
432 /* Normal server must check whether this ID exist, and if not then
433 send the query to router, unless done so already */
434 if (server->server_type == SILC_SERVER && !query->resolved) {
435 if (!silc_idlist_find_client_by_id(server->local_list,
437 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
438 !silc_idlist_find_client_by_id(server->global_list,
440 silc_server_query_send_router(server, query);
441 for (i = 0; i < query->ids_count; i++)
442 silc_free(query->ids[i].id);
443 silc_free(query->ids);
445 query->ids_count = 0;
452 query->ids[query->ids_count].id = id;
453 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
458 /* Get the max count of reply messages allowed */
459 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
460 if (tmp && tmp_len == sizeof(SilcUInt32))
461 SILC_GET32_MSB(query->reply_count, tmp);
464 case SILC_COMMAND_WHOWAS:
466 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
468 silc_server_query_send_error(server, query,
469 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
470 silc_server_query_free(query);
474 /* Get the nickname@server string and parse it */
476 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
477 silc_server_query_send_error(server, query,
478 SILC_STATUS_ERR_BAD_NICKNAME, 0);
479 silc_server_query_free(query);
484 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
485 SILC_STRING_UTF8, 128, &tmp_len);
487 silc_server_query_send_error(server, query,
488 SILC_STATUS_ERR_BAD_NICKNAME, 0);
489 silc_server_query_free(query);
492 silc_free(query->nickname);
493 query->nickname = tmp;
495 /* Get the max count of reply messages allowed */
496 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
497 if (tmp && tmp_len == sizeof(SilcUInt32))
498 SILC_GET32_MSB(query->reply_count, tmp);
501 case SILC_COMMAND_IDENTIFY:
502 /* Get IDs if present. Take IDs always instead of names. */
503 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
506 /* Try get nickname */
507 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
509 /* Get the nickname@server string and parse it */
511 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
512 silc_server_query_add_error(server, query, 1, 1,
513 SILC_STATUS_ERR_BAD_NICKNAME);
516 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
517 SILC_STRING_UTF8, 128, &tmp_len);
518 silc_free(query->nickname);
520 silc_server_query_add_error(server, query, 1, 1,
521 SILC_STATUS_ERR_BAD_NICKNAME);
522 query->nickname = NULL;
524 query->nickname = tmp;
528 /* Try get server name */
529 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
531 /* Check server name */
532 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
535 silc_server_query_add_error(server, query, 1, 1,
536 SILC_STATUS_ERR_BAD_SERVER);
538 query->server_name = tmp;
541 /* Get channel name */
542 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
543 if (tmp && tmp_len <= 256) {
544 /* Check channel name */
545 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
548 silc_server_query_add_error(server, query, 1, 1,
549 SILC_STATUS_ERR_BAD_SERVER);
551 query->channel_name = tmp;
554 if (!query->nickname && !query->server_name && !query->channel_name) {
555 silc_server_query_send_error(server, query,
556 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
557 silc_server_query_free(query);
562 /* Parse the IDs included in the query */
563 query->ids = silc_calloc(argc, sizeof(*query->ids));
565 for (i = 0; i < argc; i++) {
566 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
570 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
572 silc_server_query_add_error(server, query, 1, i + 5,
573 SILC_STATUS_ERR_BAD_CLIENT_ID);
577 /* Normal server must check whether this ID exist, and if not then
578 send the query to router, unless done so already */
579 if (server->server_type == SILC_SERVER && !query->resolved) {
580 if (id_type == SILC_ID_CLIENT) {
581 if (!silc_idlist_find_client_by_id(server->local_list,
583 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
584 !silc_idlist_find_client_by_id(server->global_list,
586 silc_server_query_send_router(server, query);
587 for (i = 0; i < query->ids_count; i++)
588 silc_free(query->ids[i].id);
589 silc_free(query->ids);
591 query->ids_count = 0;
597 /* For now all other ID's except Client ID's are explicitly
598 sent to router for resolving. */
599 silc_server_query_send_router(server, query);
600 for (i = 0; i < query->ids_count; i++)
601 silc_free(query->ids[i].id);
602 silc_free(query->ids);
604 query->ids_count = 0;
610 query->ids[query->ids_count].id = id;
611 query->ids[query->ids_count].id_type = id_type;
616 /* Get the max count of reply messages allowed */
617 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
618 if (tmp && tmp_len == sizeof(SilcUInt32))
619 SILC_GET32_MSB(query->reply_count, tmp);
623 /* Start processing the query information */
624 silc_server_query_process(server, query, TRUE);
627 /* Context for holding clients searched by public key. */
629 SilcClientEntry **clients;
630 SilcUInt32 *clients_count;
632 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
634 void silc_server_public_key_hash_foreach(void *key, void *context,
637 SilcServerPublicKeyUser uc = user_context;
638 SilcClientEntry entry = context;
640 /* Nothing was found, just return */
646 (*uc->clients) = silc_realloc((*uc->clients),
647 sizeof((**uc->clients)) *
648 ((*uc->clients_count) + 1));
649 (*uc->clients)[(*uc->clients_count)++] = entry;
652 /* If clients are set, limit the found clients using the attributes in
653 the query. If clients are not set, try to find some clients using
656 void silc_server_query_check_attributes(SilcServer server,
657 SilcServerQuery query,
658 SilcClientEntry **clients,
659 SilcUInt32 *clients_count) {
660 SilcClientEntry entry;
661 SilcAttributePayload attr;
662 SilcAttribute attribute;
663 SilcAttributeObjPk pk;
664 SilcPublicKey publickey;
666 bool found = FALSE, no_clients = FALSE;
668 /* If no clients were found, we only check the attributes
669 if the user wasn't searching for nickname/ids */
672 if (query->nickname || query->ids_count)
676 silc_dlist_start(query->attrs);
677 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
678 attribute = silc_attribute_get_attribute(attr);
681 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
682 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
684 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
687 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
694 /* If no clients were set on calling this function, we
695 just search for clients, otherwise we try to limit
698 SilcServerPublicKeyUserStruct usercontext;
700 usercontext.clients = clients;
701 usercontext.clients_count = clients_count;
702 usercontext.found = FALSE;
704 silc_hash_table_find_foreach(server->pk_hash, publickey,
705 silc_server_public_key_hash_foreach,
708 if (usercontext.found == TRUE)
711 for (i = 0; i < *clients_count; i++) {
712 entry = (*clients)[i];
714 if (!entry->data.public_key)
717 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
719 (*clients)[i] = NULL;
726 silc_pkcs_public_key_free(publickey);
731 if (!found && !query->nickname && !query->ids)
732 silc_server_query_add_error(server, query, 2, 0,
733 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
736 /* Processes the parsed query. This does the actual finding of the
737 queried information and prepares for sending reply to the original
738 sender of the query command. */
740 void silc_server_query_process(SilcServer server, SilcServerQuery query,
743 SilcServerCommandContext cmd = query->cmd;
744 bool check_global = FALSE;
746 SilcClientEntry *clients = NULL, client_entry;
747 SilcChannelEntry *channels = NULL;
748 SilcServerEntry *servers = NULL;
749 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
752 SILC_LOG_DEBUG(("Processing %s query",
753 silc_get_command_name(query->querycmd)));
755 /* Check global lists if query is coming from client or we are not
756 normal server (we know global information). */
757 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
759 else if (server->server_type != SILC_SERVER)
762 if (query->nickname) {
763 /* Get all clients matching nickname from local list */
764 if (!silc_idlist_get_clients_by_hash(server->local_list,
765 query->nickname, server->md5hash,
766 &clients, &clients_count))
767 silc_idlist_get_clients_by_nickname(server->local_list,
770 &clients, &clients_count);
772 /* Check global list as well */
774 if (!silc_idlist_get_clients_by_hash(server->global_list,
775 query->nickname, server->md5hash,
776 &clients, &clients_count))
777 silc_idlist_get_clients_by_nickname(server->global_list,
780 &clients, &clients_count);
784 silc_server_query_add_error(server, query, 1, 1,
785 SILC_STATUS_ERR_NO_SUCH_NICK);
788 if (query->server_name) {
789 /* Find server by name */
790 entry = silc_idlist_find_server_by_name(server->local_list,
791 query->server_name, TRUE, NULL);
792 if (!entry && check_global)
793 entry = silc_idlist_find_server_by_name(server->global_list,
794 query->server_name, TRUE, NULL);
796 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
797 servers[servers_count++] = (SilcServerEntry)entry;
801 silc_server_query_add_error(server, query, 1, 2,
802 SILC_STATUS_ERR_NO_SUCH_SERVER);
805 if (query->channel_name) {
806 /* Find channel by name */
807 entry = silc_idlist_find_channel_by_name(server->local_list,
808 query->channel_name, NULL);
809 if (!entry && check_global)
810 entry = silc_idlist_find_channel_by_name(server->global_list,
811 query->channel_name, NULL);
813 channels = silc_realloc(channels, sizeof(*channels) *
814 (channels_count + 1));
815 channels[channels_count++] = (SilcChannelEntry)entry;
819 silc_server_query_add_error(server, query, 1, 3,
820 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
823 if (query->ids_count) {
824 /* Find entries by the queried IDs */
825 for (i = 0; i < query->ids_count; i++) {
826 void *id = query->ids[i].id;
830 switch (query->ids[i].id_type) {
833 /* Get client entry */
834 entry = silc_idlist_find_client_by_id(server->local_list,
836 if (!entry && check_global)
837 entry = silc_idlist_find_client_by_id(server->global_list,
840 silc_server_query_add_error(server, query, 0, i,
841 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
845 clients = silc_realloc(clients, sizeof(*clients) *
846 (clients_count + 1));
847 clients[clients_count++] = (SilcClientEntry)entry;
851 /* Get server entry */
852 entry = silc_idlist_find_server_by_id(server->local_list,
854 if (!entry && check_global)
855 entry = silc_idlist_find_server_by_id(server->global_list,
858 silc_server_query_add_error(server, query, 0, i,
859 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
863 servers = silc_realloc(servers, sizeof(*servers) *
864 (servers_count + 1));
865 servers[servers_count++] = (SilcServerEntry)entry;
868 case SILC_ID_CHANNEL:
869 /* Get channel entry */
870 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
871 if (!entry && check_global)
872 entry = silc_idlist_find_channel_by_id(server->global_list, id,
875 silc_server_query_add_error(server, query, 0, i,
876 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
880 channels = silc_realloc(channels, sizeof(*channels) *
881 (channels_count + 1));
882 channels[channels_count++] = (SilcChannelEntry)entry;
891 /* Check the attributes to narrow down the search by using them. */
893 silc_server_query_check_attributes(server, query, &clients,
896 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
897 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
898 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
900 /* If nothing was found, then just send the errors */
901 if (!clients && !channels && !servers) {
902 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
906 /* If caller does not want us to resolve anything (has resolved already)
907 then just continue with sending the reply */
909 silc_server_query_send_reply(server, query, clients, clients_count,
910 servers, servers_count, channels,
918 /* Now process all found information and if necessary do some more
920 switch (query->querycmd) {
922 case SILC_COMMAND_WHOIS:
923 for (i = 0; i < clients_count; i++) {
924 client_entry = clients[i];
926 /* Check if cannot query this anyway, so take next one */
928 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
931 /* If Requested Attributes is set then we always resolve the client
932 information, if not then check whether the entry is complete or not
933 and decide whether we need to resolve or not. */
936 /* Even if nickname and stuff are present, we may need to resolve
938 if (client_entry->nickname && client_entry->username &&
939 client_entry->userinfo) {
940 /* Check if cannot query this anyway, so take next one */
941 if (!client_entry->router)
944 /* If we are router, client is local to us, or client is on channel
945 we do not need to resolve the client information. */
946 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
947 || silc_hash_table_count(client_entry->channels) ||
953 /* Remove the NOATTR status periodically */
954 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
955 client_entry->updated + 600 < time(NULL))
956 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
958 /* When requested attributes is present and local client is detached
959 we cannot send the command to the client, we'll reply on behalf of
960 the client instead. */
961 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
962 (client_entry->mode & SILC_UMODE_DETACHED ||
963 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
966 /* If attributes are present in query, and in the entry and we have
967 done resolvings already we don't need to resolve anymore */
968 if (query->resolved && query->attrs && client_entry->attrs)
971 /* Resolve the detailed client information. If client is local we
972 know that attributes were present and we will resolve directly
973 from the client. Otherwise resolve from client's owner. */
974 silc_server_query_resolve(server, query,
975 (SILC_IS_LOCAL(client_entry) ?
976 client_entry->connection :
977 client_entry->router->connection),
982 case SILC_COMMAND_WHOWAS:
983 for (i = 0; i < clients_count; i++) {
984 client_entry = clients[i];
986 /* Check if cannot query this anyway, so take next one */
987 if (!client_entry || !client_entry->router ||
988 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
991 /* If both nickname and username are present no resolving is needed */
992 if (client_entry->nickname && client_entry->username)
995 /* Resolve the detailed client information */
996 silc_server_query_resolve(server, query,
997 client_entry->router->connection,
1002 case SILC_COMMAND_IDENTIFY:
1003 for (i = 0; i < clients_count; i++) {
1004 client_entry = clients[i];
1006 /* Check if cannot query this anyway, so take next one */
1007 if (!client_entry || !client_entry->router ||
1008 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1011 /* Even if nickname is present, we may need to resolve the entry */
1012 if (client_entry->nickname) {
1014 /* If we are router, client is local to us, or client is on channel
1015 we do not need to resolve the client information. */
1016 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1017 || silc_hash_table_count(client_entry->channels) ||
1022 /* Resolve the detailed client information */
1023 silc_server_query_resolve(server, query,
1024 client_entry->router->connection,
1030 if (!query->queries_count)
1031 /* If we didn't have to do any resolving, continue with sending the
1032 command reply to the original sender. */
1033 silc_server_query_send_reply(server, query, clients, clients_count,
1034 servers, servers_count, channels,
1037 /* Now actually send the resolvings we gathered earlier */
1038 silc_server_query_resolve(server, query, NULL, NULL);
1042 silc_free(channels);
1045 /* Resolve the detailed information for the `client_entry'. Only client
1046 information needs to be resolved for being incomplete. Each incomplete
1047 client entry calls this function to do the resolving. */
1049 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1050 SilcSocketConnection sock,
1051 SilcClientEntry client_entry)
1053 SilcServerCommandContext cmd = query->cmd;
1054 SilcServerQueryList r = NULL;
1061 if (!sock && client_entry)
1064 /* If arguments are NULL we will now actually send the resolvings
1065 that earlier has been gathered by calling this function. */
1066 if (!sock && !client_entry) {
1069 SILC_LOG_DEBUG(("Sending the resolvings"));
1071 /* WHOWAS resolving has been done at the same time this function
1072 was called to add the resolving for WHOWAS, so just return. */
1073 if (query->querycmd == SILC_COMMAND_WHOWAS)
1076 for (i = 0; i < query->querylist_count; i++) {
1077 r = &query->querylist[i];
1079 /* If Requested Attributes were present put them to this resolving */
1080 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1082 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1083 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1084 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1086 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1088 r->arg[r->argc] = silc_memdup(tmp, len);
1089 r->arg_lens[r->argc] = len;
1090 r->arg_types[r->argc] = 3;
1094 /* Send WHOIS command */
1095 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1096 r->argc, r->arg, r->arg_lens,
1097 r->arg_types, r->ident);
1098 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1099 res_cmd->data, res_cmd->len, FALSE);
1100 silc_buffer_free(res_cmd);
1102 /* Reprocess this packet after received reply */
1103 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1105 silc_server_query_resolve_reply,
1107 query->queries_left++;
1110 /* Cleanup this temporary context */
1111 for (i = 0; i < query->querylist_count; i++) {
1113 for (k = 0; k < query->querylist[i].argc; k++)
1114 silc_free(query->querylist[i].arg[k]);
1115 silc_free(query->querylist[i].arg);
1116 silc_free(query->querylist[i].arg_lens);
1117 silc_free(query->querylist[i].arg_types);
1119 silc_free(query->querylist);
1120 query->querylist = NULL;
1121 query->querylist_count = 0;
1125 SILC_LOG_DEBUG(("Resolving client information"));
1127 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1128 /* The entry is being resolved by some other external query already.
1129 Attach to that query instead of resolving again. */
1130 ident = client_entry->resolve_cmd_ident;
1131 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1132 silc_server_query_resolve_reply, query))
1133 query->queries_left++;
1135 /* This entry will be resolved */
1136 ident = ++server->cmd_ident;
1138 switch (query->querycmd) {
1140 case SILC_COMMAND_WHOIS:
1141 case SILC_COMMAND_IDENTIFY:
1142 /* Take existing query context if exist for this connection */
1143 for (i = 0; i < query->querylist_count; i++)
1144 if (query->querylist[i].sock == sock) {
1145 r = &query->querylist[i];
1150 /* Allocate new temp query list context */
1151 query->querylist = silc_realloc(query->querylist,
1152 sizeof(*query->querylist) *
1153 (query->querylist_count + 1));
1154 r = &query->querylist[query->querylist_count];
1155 query->querylist_count++;
1156 memset(r, 0, sizeof(*r));
1159 if (SILC_IS_LOCAL(client_entry))
1164 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1165 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1166 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1168 /* Add the client entry to be resolved */
1169 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1170 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1171 r->arg_lens[r->argc] = idp->len;
1172 r->arg_types[r->argc] = r->argc + 4;
1174 silc_buffer_free(idp);
1178 case SILC_COMMAND_WHOWAS:
1179 /* We must send WHOWAS command since it's the only the way of
1180 resolving clients that are not present in the network anymore. */
1181 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1182 1, query->nickname, strlen(query->nickname));
1183 if (silc_server_command_pending(server, query->querycmd, ident,
1184 silc_server_query_resolve_reply, query))
1185 query->queries_left++;
1190 /* Mark the entry as being resolved */
1191 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1192 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1193 client_entry->resolve_cmd_ident = ident;
1194 client_entry->updated = time(NULL);
1196 /* Save the queried ID, which we will reprocess after we get this and
1197 all other queries back. */
1198 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1199 (query->queries_count + 1));
1200 if (query->queries) {
1201 i = query->queries_count;
1202 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1203 query->queries[i].id_type = SILC_ID_CLIENT;
1204 query->queries[i].ident = ident;
1205 query->queries_count++;
1209 /* Reply callback called after one resolving has been completed. If
1210 all resolvings has been received then we will continue with sending
1211 the command reply to the original sender of the query. */
1213 void silc_server_query_resolve_reply(void *context, void *reply)
1215 SilcServerQuery query = context;
1216 SilcServer server = query->cmd->server;
1217 SilcServerCommandReplyContext cmdr = reply;
1218 SilcUInt16 ident = cmdr->ident;
1219 SilcStatus error = SILC_STATUS_OK;
1220 SilcServerQueryID id = NULL;
1221 SilcClientEntry client_entry;
1224 /* One less query left */
1225 query->queries_left--;
1227 silc_command_get_status(cmdr->payload, NULL, &error);
1228 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1229 query->queries_left, error));
1231 /* If no error then skip to other stuff */
1232 if (error == SILC_STATUS_OK)
1235 /* Error occurred during resolving */
1237 /* Find the resolved client ID */
1238 for (i = 0; i < query->queries_count; i++) {
1239 if (query->queries[i].ident != ident)
1242 id = &query->queries[i];
1244 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1246 /* If timeout occurred for local entry when resolving attributes
1247 mark that this client doesn't support attributes in WHOIS. This
1248 assures we won't send the request again to the client. */
1249 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1250 client_entry = silc_idlist_find_client_by_id(server->local_list,
1251 id->id, TRUE, NULL);
1252 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1253 silc_id_render(id->id, SILC_ID_CLIENT)));
1254 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1255 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1256 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1261 /* Remove the RESOLVING status from the client entry */
1262 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1263 client_entry = silc_idlist_find_client_by_id(server->local_list,
1264 id->id, TRUE, NULL);
1266 client_entry = silc_idlist_find_client_by_id(server->global_list,
1267 id->id, TRUE, NULL);
1269 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1276 /* If there are queries left then wait for them */
1277 if (query->queries_left)
1280 SILC_LOG_DEBUG(("Reprocess the query"));
1282 /* We have received all queries. Now re-search all information required
1283 to complete this query. Reason we cannot save the values found in
1284 the first search is that SilcClientEntry, SilcServerEntry and
1285 SilcChannelEntry pointers may become invalid while we were waiting
1286 for these resolvings. */
1287 silc_server_query_process(server, query, FALSE);
1290 /* Send the reply to the original query. If arguments are NULL then this
1291 sends only the errors that has occurred during the processing of the
1292 query. This sends the errors always after sending all the found
1293 information. The query is over after this function returns and the
1294 `query' will become invalid. This is called only after all informations
1295 has been resolved. This means that if something is not found or is
1296 incomplete in this function we were unable to resolve the information
1297 or it does not exist at all. */
1299 void silc_server_query_send_reply(SilcServer server,
1300 SilcServerQuery query,
1301 SilcClientEntry *clients,
1302 SilcUInt32 clients_count,
1303 SilcServerEntry *servers,
1304 SilcUInt32 servers_count,
1305 SilcChannelEntry *channels,
1306 SilcUInt32 channels_count)
1308 SilcServerCommandContext cmd = query->cmd;
1309 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1314 int i, k, valid_count;
1315 char nh[256], uh[256];
1316 bool sent_reply = FALSE;
1318 SILC_LOG_DEBUG(("Sending reply to query"));
1319 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1320 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1321 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1322 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1324 status = SILC_STATUS_OK;
1327 if (clients_count) {
1328 SilcClientEntry entry;
1329 SilcSocketConnection hsock;
1331 /* Mark all invalid entries */
1332 for (i = 0, valid_count = 0; i < clients_count; i++) {
1337 switch (query->querycmd) {
1338 case SILC_COMMAND_WHOIS:
1339 if (!entry->nickname || !entry->username || !entry->userinfo ||
1340 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1341 /* When querying by ID, every "unfound" entry must cause error */
1343 silc_server_query_add_error_id(server, query,
1344 SILC_STATUS_ERR_TIMEDOUT,
1345 entry->id, SILC_ID_CLIENT);
1351 case SILC_COMMAND_IDENTIFY:
1352 if (!entry->nickname ||
1353 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1354 /* When querying by ID, every "unfound" entry must cause error */
1356 silc_server_query_add_error_id(server, query,
1357 SILC_STATUS_ERR_TIMEDOUT,
1358 entry->id, SILC_ID_CLIENT);
1364 case SILC_COMMAND_WHOWAS:
1365 if (!entry->nickname || !entry->username ||
1366 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1375 /* Start processing found clients */
1376 status = SILC_STATUS_OK;
1377 if (valid_count > 1)
1378 status = SILC_STATUS_LIST_START;
1380 /* Now do the sending of valid entries */
1382 for (i = 0; i < clients_count && valid_count; i++) {
1388 status = SILC_STATUS_LIST_ITEM;
1389 if (valid_count > 1 && k == valid_count - 1
1390 && !servers_count && !channels_count && !query->errors_count)
1391 status = SILC_STATUS_LIST_END;
1392 if (query->reply_count && k - 1 == query->reply_count)
1393 status = SILC_STATUS_LIST_END;
1395 SILC_LOG_DEBUG(("%s: client %s",
1396 (status == SILC_STATUS_OK ? " OK" :
1397 status == SILC_STATUS_LIST_START ? "START" :
1398 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1399 status == SILC_STATUS_LIST_END ? " END" :
1400 " : "), entry->nickname));
1402 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1403 memset(uh, 0, sizeof(uh));
1404 memset(nh, 0, sizeof(nh));
1406 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1407 if (!strchr(entry->nickname, '@')) {
1408 silc_strncat(nh, sizeof(nh), "@", 1);
1409 if (entry->servername) {
1410 silc_strncat(nh, sizeof(nh), entry->servername,
1411 strlen(entry->servername));
1413 len = entry->router ? strlen(entry->router->server_name) :
1414 strlen(server->server_name);
1415 silc_strncat(nh, sizeof(nh), entry->router ?
1416 entry->router->server_name :
1417 server->server_name, len);
1421 switch (query->querycmd) {
1423 case SILC_COMMAND_WHOIS:
1425 unsigned char idle[4], mode[4];
1426 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1427 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1429 memset(fempty, 0, sizeof(fempty));
1430 memset(idle, 0, sizeof(idle));
1431 silc_strncat(uh, sizeof(uh), entry->username,
1432 strlen(entry->username));
1433 if (!strchr(entry->username, '@') && entry->connection) {
1434 hsock = entry->connection;
1435 silc_strncat(uh, sizeof(uh), "@", 1);
1436 len = strlen(hsock->hostname);
1437 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1440 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1442 silc_server_get_client_channel_list(server, entry, FALSE,
1443 FALSE, &umode_list);
1446 silc_server_get_client_channel_list(server, entry, TRUE,
1449 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1450 fingerprint = entry->data.fingerprint;
1454 SILC_PUT32_MSB(entry->mode, mode);
1455 if (entry->connection)
1456 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1458 /* If Requested Attribute were present, and we do not have the
1459 attributes we will reply to them on behalf of the client. */
1462 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1463 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1464 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1465 entry->attrs_len = len;
1466 silc_buffer_free(tmpattrs);
1468 attrs = entry->attrs;
1469 len = entry->attrs_len;
1472 /* Send command reply */
1473 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1474 status, 0, ident, 10,
1475 2, idp->data, idp->len,
1479 strlen(entry->userinfo),
1480 6, channels ? channels->data : NULL,
1481 channels ? channels->len : 0,
1485 fingerprint ? 20 : 0,
1486 10, umode_list ? umode_list->data :
1487 NULL, umode_list ? umode_list->len :
1492 /* For now we always delete Requested Attributes, unless the client
1493 is detached, in which case we don't want to reconstruct the
1494 same data everytime */
1495 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1496 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1497 silc_free(entry->attrs);
1498 entry->attrs = NULL;
1502 silc_buffer_free(channels);
1504 silc_buffer_free(umode_list);
1510 case SILC_COMMAND_IDENTIFY:
1511 if (!entry->username) {
1512 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1513 status, 0, ident, 2,
1514 2, idp->data, idp->len,
1518 silc_strncat(uh, sizeof(uh), entry->username,
1519 strlen(entry->username));
1520 if (!strchr(entry->username, '@') && entry->connection) {
1521 hsock = entry->connection;
1522 silc_strncat(uh, sizeof(uh), "@", 1);
1523 len = strlen(hsock->hostname);
1524 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1527 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1528 status, 0, ident, 3,
1529 2, idp->data, idp->len,
1536 case SILC_COMMAND_WHOWAS:
1537 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1538 if (!strchr(entry->username, '@'))
1539 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1541 /* Send command reply */
1542 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1543 status, 0, ident, 4,
1544 2, idp->data, idp->len,
1549 strlen(entry->userinfo) : 0);
1554 silc_buffer_free(idp);
1556 if (status == SILC_STATUS_LIST_END)
1562 /* Not one valid entry was found, send error. If nickname was used
1563 in query send error based on that, otherwise the query->errors
1564 already includes proper errors. */
1565 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1566 silc_server_query_add_error(server, query, 1, 1,
1567 SILC_STATUS_ERR_NO_SUCH_NICK);
1572 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1573 SilcServerEntry entry;
1575 if (status == SILC_STATUS_OK && servers_count > 1)
1576 status = SILC_STATUS_LIST_START;
1579 for (i = 0; i < servers_count; i++) {
1583 status = SILC_STATUS_LIST_ITEM;
1584 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1585 !query->errors_count)
1586 status = SILC_STATUS_LIST_END;
1587 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1588 !query->errors_count)
1589 status = SILC_STATUS_LIST_END;
1590 if (query->reply_count && k - 1 == query->reply_count)
1591 status = SILC_STATUS_LIST_END;
1593 SILC_LOG_DEBUG(("%s: server %s",
1594 (status == SILC_STATUS_OK ? " OK" :
1595 status == SILC_STATUS_LIST_START ? "START" :
1596 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1597 status == SILC_STATUS_LIST_END ? " END" :
1599 entry->server_name ? entry->server_name : ""));
1601 /* Send command reply */
1602 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1603 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1604 status, 0, ident, 2,
1605 2, idp->data, idp->len,
1606 3, entry->server_name,
1607 entry->server_name ?
1608 strlen(entry->server_name) : 0);
1609 silc_buffer_free(idp);
1612 if (status == SILC_STATUS_LIST_END)
1619 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1620 SilcChannelEntry entry;
1622 if (status == SILC_STATUS_OK && channels_count > 1)
1623 status = SILC_STATUS_LIST_START;
1626 for (i = 0; i < channels_count; i++) {
1627 entry = channels[i];
1630 status = SILC_STATUS_LIST_ITEM;
1631 if (channels_count == 1 && status != SILC_STATUS_OK &&
1632 !query->errors_count)
1633 status = SILC_STATUS_LIST_END;
1634 if (channels_count > 1 && k == channels_count - 1 &&
1635 !query->errors_count)
1636 status = SILC_STATUS_LIST_END;
1637 if (query->reply_count && k - 1 == query->reply_count)
1638 status = SILC_STATUS_LIST_END;
1640 SILC_LOG_DEBUG(("%s: channel %s",
1641 (status == SILC_STATUS_OK ? " OK" :
1642 status == SILC_STATUS_LIST_START ? "START" :
1643 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1644 status == SILC_STATUS_LIST_END ? " END" :
1646 entry->channel_name ? entry->channel_name : ""));
1648 /* Send command reply */
1649 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1650 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1651 status, 0, ident, 2,
1652 2, idp->data, idp->len,
1653 3, entry->channel_name,
1654 entry->channel_name ?
1655 strlen(entry->channel_name) : 0);
1656 silc_buffer_free(idp);
1659 if (status == SILC_STATUS_LIST_END)
1666 if (query->errors_count) {
1669 if (status == SILC_STATUS_OK && query->errors_count > 1)
1670 status = SILC_STATUS_LIST_START;
1673 for (i = 0; i < query->errors_count; i++) {
1676 /* Take error argument */
1677 if (query->errors[i].type == 1) {
1678 /* Take from sent arguments */
1680 tmp = silc_argument_get_arg_type(cmd->args,
1681 query->errors[i].index, &len);
1683 } else if (query->errors[i].type == 2) {
1688 } else if (!query->errors[i].id) {
1689 /* Take from query->ids */
1691 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1692 query->ids[query->errors[k].index].id_type);
1697 /* Take added ID. */
1698 idp = silc_id_payload_encode(query->errors[i].id,
1699 query->errors[k].id_type);
1706 status = SILC_STATUS_LIST_ITEM;
1707 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1708 status = SILC_STATUS_LIST_END;
1709 if (query->errors_count > 1 && k == query->errors_count - 1)
1710 status = SILC_STATUS_LIST_END;
1711 if (query->reply_count && k - 1 == query->reply_count)
1712 status = SILC_STATUS_LIST_END;
1714 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1715 (status == SILC_STATUS_OK ? " OK" :
1716 status == SILC_STATUS_LIST_START ? "START" :
1717 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1718 status == SILC_STATUS_LIST_END ? " END" :
1720 silc_get_status_message(query->errors[i].error),
1721 query->errors[i].error));
1723 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1724 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1726 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1727 (status == SILC_STATUS_OK ?
1728 query->errors[i].error : status),
1729 (status == SILC_STATUS_OK ?
1730 0 : query->errors[i].error), ident, 2,
1736 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1737 (status == SILC_STATUS_OK ?
1738 query->errors[i].error : status),
1739 (status == SILC_STATUS_OK ?
1740 0 : query->errors[i].error), ident, 1,
1743 silc_buffer_free(idp);
1746 if (status == SILC_STATUS_LIST_END)
1753 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1756 silc_server_query_free(query);
1759 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1760 of the client since we were unable to resolve them from the client.
1761 Either client does not support Requested Attributes or isn't replying
1762 to them like it should. */
1764 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1765 SilcServerQuery query,
1766 SilcClientEntry client_entry)
1768 SilcBuffer buffer = NULL;
1769 SilcAttribute attribute;
1770 SilcAttributePayload attr;
1771 SilcAttributeObjPk pk;
1772 SilcAttributeObjService service;
1774 unsigned char sign[2048 + 1];
1775 SilcUInt32 sign_len;
1777 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1779 /* Go through all requested attributes */
1780 silc_dlist_start(query->attrs);
1781 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1782 attribute = silc_attribute_get_attribute(attr);
1783 switch (attribute) {
1785 case SILC_ATTRIBUTE_SERVICE:
1786 /* Put SERVICE. Put only SILC service. */
1787 memset(&service, 0, sizeof(service));
1788 service.port = (server->config->server_info->primary ?
1789 server->config->server_info->primary->port : SILC_PORT);
1790 silc_strncat(service.address, sizeof(service.address),
1791 server->server_name, strlen(server->server_name));
1792 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1793 if (client_entry->connection)
1794 service.idle = time(NULL) - client_entry->data.last_receive;
1795 buffer = silc_attribute_payload_encode(buffer, attribute,
1796 SILC_ATTRIBUTE_FLAG_VALID,
1797 &service, sizeof(service));
1802 case SILC_ATTRIBUTE_STATUS_MOOD:
1803 /* Put STATUS_MOOD */
1804 buffer = silc_attribute_payload_encode(buffer, attribute,
1805 SILC_ATTRIBUTE_FLAG_VALID,
1807 SILC_ATTRIBUTE_MOOD_NORMAL,
1808 sizeof(SilcUInt32));
1813 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1814 /* Put STATUS_FREETEXT. We just tell in the message that we are
1815 replying on behalf of the client. */
1817 "This information was provided by the server on behalf of the user";
1818 buffer = silc_attribute_payload_encode(buffer, attribute,
1819 SILC_ATTRIBUTE_FLAG_VALID,
1825 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1826 /* Put PREFERRED_CONTACT */
1827 buffer = silc_attribute_payload_encode(buffer, attribute,
1828 SILC_ATTRIBUTE_FLAG_VALID,
1830 SILC_ATTRIBUTE_CONTACT_CHAT,
1831 sizeof(SilcUInt32));
1836 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1837 /* Put USER_PUBLIC_KEY */
1838 if (client_entry->data.public_key) {
1839 pk.type = "silc-rsa";
1840 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1842 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1843 SILC_ATTRIBUTE_FLAG_VALID :
1844 SILC_ATTRIBUTE_FLAG_INVALID,
1852 /* No public key available */
1853 buffer = silc_attribute_payload_encode(buffer, attribute,
1854 SILC_ATTRIBUTE_FLAG_INVALID,
1861 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1862 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1863 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1866 /* For other attributes we cannot reply so mark it invalid */
1867 buffer = silc_attribute_payload_encode(buffer, attribute,
1868 SILC_ATTRIBUTE_FLAG_INVALID,
1876 /* Always put our public key. This assures that we send at least
1877 something valid back always. */
1878 pk.type = "silc-rsa";
1879 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1880 buffer = silc_attribute_payload_encode(buffer,
1881 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1882 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1883 SILC_ATTRIBUTE_FLAG_INVALID,
1889 /* Finally compute the digital signature of all the data we provided
1890 as an indication that we provided rightfull information, and this
1891 also authenticates our public key. */
1892 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1893 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1894 buffer->data, buffer->len,
1898 pk.data_len = sign_len;
1900 silc_attribute_payload_encode(buffer,
1901 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1902 SILC_ATTRIBUTE_FLAG_VALID,
1911 /* Find client by the Client ID indicated by the `client_id', and if not
1912 found then query it by using WHOIS command. The client information
1913 is also resolved if the cached information is incomplete or if the
1914 `always_resolve' is set to TRUE. The indication whether requested
1915 client was being resolved is saved into `resolved'. If the client
1916 is not being resolved its entry is returned by this function. NULL
1917 is returned if client is resolved. */
1919 SilcClientEntry silc_server_query_client(SilcServer server,
1920 const SilcClientID *client_id,
1921 bool always_resolve,
1924 SilcClientEntry client;
1926 SILC_LOG_DEBUG(("Resolving client by client ID"));
1931 client = silc_idlist_find_client_by_id(server->local_list,
1932 (SilcClientID *)client_id,
1935 client = silc_idlist_find_client_by_id(server->global_list,
1936 (SilcClientID *)client_id,
1938 if (!client && server->server_type == SILC_ROUTER)
1942 if (!client && server->standalone)
1945 if (!client || !client->nickname || !client->username ||
1947 SilcBuffer buffer, idp;
1950 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1951 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1952 client->resolve_cmd_ident = ++server->cmd_ident;
1955 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1956 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1957 server->cmd_ident, 1,
1958 4, idp->data, idp->len);
1959 silc_server_packet_send(server, client ? client->router->connection :
1960 SILC_PRIMARY_ROUTE(server),
1961 SILC_PACKET_COMMAND, 0,
1962 buffer->data, buffer->len, FALSE);
1963 silc_buffer_free(idp);
1964 silc_buffer_free(buffer);