5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2003 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 */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name */
57 char *channel_name; /* Queried channel name */
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 /* Parse the IDs included in the query */
404 query->ids = silc_calloc(argc, sizeof(*query->ids));
406 for (i = 0; i < argc; i++) {
407 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
411 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
412 if (!id || id_type != SILC_ID_CLIENT) {
413 silc_server_query_add_error(server, query, 1, i + 4,
414 SILC_STATUS_ERR_BAD_CLIENT_ID);
418 /* Normal server must check whether this ID exist, and if not then
419 send the query to router, unless done so already */
420 if (server->server_type == SILC_SERVER && !query->resolved) {
421 if (!silc_idlist_find_client_by_id(server->local_list,
423 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
424 !silc_idlist_find_client_by_id(server->global_list,
426 silc_server_query_send_router(server, query);
427 for (i = 0; i < query->ids_count; i++)
428 silc_free(query->ids[i].id);
429 silc_free(query->ids);
431 query->ids_count = 0;
438 query->ids[query->ids_count].id = id;
439 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
444 /* Get the max count of reply messages allowed */
445 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
446 if (tmp && tmp_len == sizeof(SilcUInt32))
447 SILC_GET32_MSB(query->reply_count, tmp);
450 case SILC_COMMAND_WHOWAS:
452 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
454 silc_server_query_send_error(server, query,
455 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
456 silc_server_query_free(query);
460 /* Get the nickname@server string and parse it */
462 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
463 silc_server_query_send_error(server, query,
464 SILC_STATUS_ERR_BAD_NICKNAME, 0);
465 silc_server_query_free(query);
469 /* Get the max count of reply messages allowed */
470 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
471 if (tmp && tmp_len == sizeof(SilcUInt32))
472 SILC_GET32_MSB(query->reply_count, tmp);
475 case SILC_COMMAND_IDENTIFY:
476 /* Get IDs if present. Take IDs always instead of names. */
477 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
480 /* Try get nickname */
481 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
483 /* Get the nickname@server string and parse it */
485 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
486 silc_server_query_add_error(server, query, 1, 1,
487 SILC_STATUS_ERR_BAD_NICKNAME);
490 /* Try get server name */
491 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
493 query->server_name = silc_memdup(tmp, tmp_len);
495 /* Get channel name */
496 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
497 if (tmp && tmp_len <= 256)
498 query->channel_name = silc_memdup(tmp, tmp_len);
500 if (!query->nickname && !query->server_name && !query->channel_name) {
501 silc_server_query_send_error(server, query,
502 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
503 silc_server_query_free(query);
508 /* Parse the IDs included in the query */
509 query->ids = silc_calloc(argc, sizeof(*query->ids));
511 for (i = 0; i < argc; i++) {
512 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
516 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
518 silc_server_query_add_error(server, query, 1, i + 5,
519 SILC_STATUS_ERR_BAD_CLIENT_ID);
523 /* Normal server must check whether this ID exist, and if not then
524 send the query to router, unless done so already */
525 if (server->server_type == SILC_SERVER && !query->resolved) {
526 if (id_type == SILC_ID_CLIENT) {
527 if (!silc_idlist_find_client_by_id(server->local_list,
529 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
530 !silc_idlist_find_client_by_id(server->global_list,
532 silc_server_query_send_router(server, query);
533 for (i = 0; i < query->ids_count; i++)
534 silc_free(query->ids[i].id);
535 silc_free(query->ids);
537 query->ids_count = 0;
543 /* For now all other ID's except Client ID's are explicitly
544 sent to router for resolving. */
545 silc_server_query_send_router(server, query);
546 for (i = 0; i < query->ids_count; i++)
547 silc_free(query->ids[i].id);
548 silc_free(query->ids);
550 query->ids_count = 0;
556 query->ids[query->ids_count].id = id;
557 query->ids[query->ids_count].id_type = id_type;
562 /* Get the max count of reply messages allowed */
563 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
564 if (tmp && tmp_len == sizeof(SilcUInt32))
565 SILC_GET32_MSB(query->reply_count, tmp);
569 /* Start processing the query information */
570 silc_server_query_process(server, query, TRUE);
573 /* Context for holding clients searched by public key. */
575 SilcClientEntry **clients;
576 SilcUInt32 *clients_count;
578 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
580 void silc_server_public_key_hash_foreach(void *key, void *context,
583 SilcServerPublicKeyUser uc = user_context;
584 SilcClientEntry entry = context;
586 /* Nothing was found, just return */
592 (*uc->clients) = silc_realloc((*uc->clients),
593 sizeof((**uc->clients)) *
594 ((*uc->clients_count) + 1));
595 (*uc->clients)[(*uc->clients_count)++] = entry;
598 /* If clients are set, limit the found clients using the attributes in
599 the query. If clients are not set, try to find some clients using
602 void silc_server_query_check_attributes(SilcServer server,
603 SilcServerQuery query,
604 SilcClientEntry **clients,
605 SilcUInt32 *clients_count) {
606 SilcClientEntry entry;
607 SilcAttributePayload attr;
608 SilcAttribute attribute;
609 SilcAttributeObjPk pk;
610 SilcPublicKey publickey;
612 bool found = FALSE, no_clients = FALSE;
614 /* If no clients were found, we only check the attributes
615 if the user wasn't searching for nickname/ids */
618 if (query->nickname || query->ids_count)
622 silc_dlist_start(query->attrs);
623 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
624 attribute = silc_attribute_get_attribute(attr);
627 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
628 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
630 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
633 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
640 /* If no clients were set on calling this function, we
641 just search for clients, otherwise we try to limit
644 SilcServerPublicKeyUserStruct usercontext;
646 usercontext.clients = clients;
647 usercontext.clients_count = clients_count;
648 usercontext.found = FALSE;
650 silc_hash_table_find_foreach(server->pk_hash, publickey,
651 silc_server_public_key_hash_foreach,
654 if (usercontext.found == TRUE)
657 for (i = 0; i < *clients_count; i++) {
658 entry = (*clients)[i];
660 if (!entry->data.public_key)
663 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
665 (*clients)[i] = NULL;
672 silc_pkcs_public_key_free(publickey);
677 if (!found && !query->nickname && !query->ids)
678 silc_server_query_add_error(server, query, 2, 0,
679 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
682 /* Processes the parsed query. This does the actual finding of the
683 queried information and prepares for sending reply to the original
684 sender of the query command. */
686 void silc_server_query_process(SilcServer server, SilcServerQuery query,
689 SilcServerCommandContext cmd = query->cmd;
690 bool check_global = FALSE;
692 SilcClientEntry *clients = NULL, client_entry;
693 SilcChannelEntry *channels = NULL;
694 SilcServerEntry *servers = NULL;
695 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
698 SILC_LOG_DEBUG(("Processing %s query",
699 silc_get_command_name(query->querycmd)));
701 /* Check global lists if query is coming from client or we are not
702 normal server (we know global information). */
703 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
705 else if (server->server_type != SILC_SERVER)
708 if (query->nickname) {
709 /* Get all clients matching nickname from local list */
710 if (!silc_idlist_get_clients_by_hash(server->local_list,
711 query->nickname, server->md5hash,
712 &clients, &clients_count))
713 silc_idlist_get_clients_by_nickname(server->local_list,
716 &clients, &clients_count);
718 /* Check global list as well */
720 if (!silc_idlist_get_clients_by_hash(server->global_list,
721 query->nickname, server->md5hash,
722 &clients, &clients_count))
723 silc_idlist_get_clients_by_nickname(server->global_list,
726 &clients, &clients_count);
730 silc_server_query_add_error(server, query, 1, 1,
731 SILC_STATUS_ERR_NO_SUCH_NICK);
734 if (query->server_name) {
735 /* Find server by name */
736 entry = silc_idlist_find_server_by_name(server->local_list,
737 query->server_name, TRUE, NULL);
738 if (!entry && check_global)
739 entry = silc_idlist_find_server_by_name(server->global_list,
740 query->server_name, TRUE, NULL);
742 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
743 servers[servers_count++] = (SilcServerEntry)entry;
747 silc_server_query_add_error(server, query, 1, 2,
748 SILC_STATUS_ERR_NO_SUCH_SERVER);
751 if (query->channel_name) {
752 /* Find channel by name */
753 entry = silc_idlist_find_channel_by_name(server->local_list,
754 query->channel_name, NULL);
755 if (!entry && check_global)
756 entry = silc_idlist_find_channel_by_name(server->global_list,
757 query->channel_name, NULL);
759 channels = silc_realloc(channels, sizeof(*channels) *
760 (channels_count + 1));
761 channels[channels_count++] = (SilcChannelEntry)entry;
765 silc_server_query_add_error(server, query, 1, 3,
766 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
769 if (query->ids_count) {
770 /* Find entries by the queried IDs */
771 for (i = 0; i < query->ids_count; i++) {
772 void *id = query->ids[i].id;
776 switch (query->ids[i].id_type) {
779 /* Get client entry */
780 entry = silc_idlist_find_client_by_id(server->local_list,
782 if (!entry && check_global)
783 entry = silc_idlist_find_client_by_id(server->global_list,
786 silc_server_query_add_error(server, query, 0, i,
787 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
791 clients = silc_realloc(clients, sizeof(*clients) *
792 (clients_count + 1));
793 clients[clients_count++] = (SilcClientEntry)entry;
797 /* Get server entry */
798 entry = silc_idlist_find_server_by_id(server->local_list,
800 if (!entry && check_global)
801 entry = silc_idlist_find_server_by_id(server->global_list,
804 silc_server_query_add_error(server, query, 0, i,
805 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
809 servers = silc_realloc(servers, sizeof(*servers) *
810 (servers_count + 1));
811 servers[servers_count++] = (SilcServerEntry)entry;
814 case SILC_ID_CHANNEL:
815 /* Get channel entry */
816 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
817 if (!entry && check_global)
818 entry = silc_idlist_find_channel_by_id(server->global_list, id,
821 silc_server_query_add_error(server, query, 0, i,
822 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
826 channels = silc_realloc(channels, sizeof(*channels) *
827 (channels_count + 1));
828 channels[channels_count++] = (SilcChannelEntry)entry;
837 /* Check the attributes to narrow down the search by using them. */
839 silc_server_query_check_attributes(server, query, &clients,
842 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
843 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
844 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
846 /* If nothing was found, then just send the errors */
847 if (!clients && !channels && !servers) {
848 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
852 /* If caller does not want us to resolve anything (has resolved already)
853 then just continue with sending the reply */
855 silc_server_query_send_reply(server, query, clients, clients_count,
856 servers, servers_count, channels,
864 /* Now process all found information and if necessary do some more
866 switch (query->querycmd) {
868 case SILC_COMMAND_WHOIS:
869 for (i = 0; i < clients_count; i++) {
870 client_entry = clients[i];
872 /* Check if cannot query this anyway, so take next one */
874 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
877 /* If Requested Attributes is set then we always resolve the client
878 information, if not then check whether the entry is complete or not
879 and decide whether we need to resolve or not. */
882 /* Even if nickname and stuff are present, we may need to resolve
884 if (client_entry->nickname && client_entry->username &&
885 client_entry->userinfo) {
886 /* Check if cannot query this anyway, so take next one */
887 if (!client_entry->router)
890 /* If we are router, client is local to us, or client is on channel
891 we do not need to resolve the client information. */
892 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
893 || silc_hash_table_count(client_entry->channels) ||
899 /* Remove the NOATTR status periodically */
900 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
901 client_entry->updated + 600 < time(NULL))
902 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
904 /* When requested attributes is present and local client is detached
905 we cannot send the command to the client, we'll reply on behalf of
906 the client instead. */
907 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
908 (client_entry->mode & SILC_UMODE_DETACHED ||
909 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
912 /* If attributes are present in query, and in the entry and we have
913 done resolvings already we don't need to resolve anymore */
914 if (query->resolved && query->attrs && client_entry->attrs)
917 /* Resolve the detailed client information. If client is local we
918 know that attributes were present and we will resolve directly
919 from the client. Otherwise resolve from client's owner. */
920 silc_server_query_resolve(server, query,
921 (SILC_IS_LOCAL(client_entry) ?
922 client_entry->connection :
923 client_entry->router->connection),
928 case SILC_COMMAND_WHOWAS:
929 for (i = 0; i < clients_count; i++) {
930 client_entry = clients[i];
932 /* Check if cannot query this anyway, so take next one */
933 if (!client_entry || !client_entry->router ||
934 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
937 /* If both nickname and username are present no resolving is needed */
938 if (client_entry->nickname && client_entry->username)
941 /* Resolve the detailed client information */
942 silc_server_query_resolve(server, query,
943 client_entry->router->connection,
948 case SILC_COMMAND_IDENTIFY:
949 for (i = 0; i < clients_count; i++) {
950 client_entry = clients[i];
952 /* Check if cannot query this anyway, so take next one */
953 if (!client_entry || !client_entry->router ||
954 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
957 /* Even if nickname is present, we may need to resolve the entry */
958 if (client_entry->nickname) {
960 /* If we are router, client is local to us, or client is on channel
961 we do not need to resolve the client information. */
962 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
963 || silc_hash_table_count(client_entry->channels) ||
968 /* Resolve the detailed client information */
969 silc_server_query_resolve(server, query,
970 client_entry->router->connection,
976 if (!query->queries_count)
977 /* If we didn't have to do any resolving, continue with sending the
978 command reply to the original sender. */
979 silc_server_query_send_reply(server, query, clients, clients_count,
980 servers, servers_count, channels,
983 /* Now actually send the resolvings we gathered earlier */
984 silc_server_query_resolve(server, query, NULL, NULL);
991 /* Resolve the detailed information for the `client_entry'. Only client
992 information needs to be resolved for being incomplete. Each incomplete
993 client entry calls this function to do the resolving. */
995 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
996 SilcSocketConnection sock,
997 SilcClientEntry client_entry)
999 SilcServerCommandContext cmd = query->cmd;
1000 SilcServerQueryList r = NULL;
1007 if (!sock && client_entry)
1010 /* If arguments are NULL we will now actually send the resolvings
1011 that earlier has been gathered by calling this function. */
1012 if (!sock && !client_entry) {
1015 SILC_LOG_DEBUG(("Sending the resolvings"));
1017 /* WHOWAS resolving has been done at the same time this function
1018 was called to add the resolving for WHOWAS, so just return. */
1019 if (query->querycmd == SILC_COMMAND_WHOWAS)
1022 for (i = 0; i < query->querylist_count; i++) {
1023 r = &query->querylist[i];
1025 /* If Requested Attributes were present put them to this resolving */
1026 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1028 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1029 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1030 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1032 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1034 r->arg[r->argc] = silc_memdup(tmp, len);
1035 r->arg_lens[r->argc] = len;
1036 r->arg_types[r->argc] = 3;
1040 /* Send WHOIS command */
1041 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1042 r->argc, r->arg, r->arg_lens,
1043 r->arg_types, r->ident);
1044 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1045 res_cmd->data, res_cmd->len, FALSE);
1046 silc_buffer_free(res_cmd);
1048 /* Reprocess this packet after received reply */
1049 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1051 silc_server_query_resolve_reply,
1053 query->queries_left++;
1056 /* Cleanup this temporary context */
1057 for (i = 0; i < query->querylist_count; i++) {
1059 for (k = 0; k < query->querylist[i].argc; k++)
1060 silc_free(query->querylist[i].arg[k]);
1061 silc_free(query->querylist[i].arg);
1062 silc_free(query->querylist[i].arg_lens);
1063 silc_free(query->querylist[i].arg_types);
1065 silc_free(query->querylist);
1066 query->querylist = NULL;
1067 query->querylist_count = 0;
1071 SILC_LOG_DEBUG(("Resolving client information"));
1073 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1074 /* The entry is being resolved by some other external query already.
1075 Attach to that query instead of resolving again. */
1076 ident = client_entry->resolve_cmd_ident;
1077 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1078 silc_server_query_resolve_reply, query))
1079 query->queries_left++;
1081 /* This entry will be resolved */
1082 ident = ++server->cmd_ident;
1084 switch (query->querycmd) {
1086 case SILC_COMMAND_WHOIS:
1087 case SILC_COMMAND_IDENTIFY:
1088 /* Take existing query context if exist for this connection */
1089 for (i = 0; i < query->querylist_count; i++)
1090 if (query->querylist[i].sock == sock) {
1091 r = &query->querylist[i];
1096 /* Allocate new temp query list context */
1097 query->querylist = silc_realloc(query->querylist,
1098 sizeof(*query->querylist) *
1099 (query->querylist_count + 1));
1100 r = &query->querylist[query->querylist_count];
1101 query->querylist_count++;
1102 memset(r, 0, sizeof(*r));
1105 if (SILC_IS_LOCAL(client_entry))
1110 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1111 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1112 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1114 /* Add the client entry to be resolved */
1115 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1116 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1117 r->arg_lens[r->argc] = idp->len;
1118 r->arg_types[r->argc] = r->argc + 4;
1120 silc_buffer_free(idp);
1124 case SILC_COMMAND_WHOWAS:
1125 /* We must send WHOWAS command since it's the only the way of
1126 resolving clients that are not present in the network anymore. */
1127 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1128 1, query->nickname, strlen(query->nickname));
1129 if (silc_server_command_pending(server, query->querycmd, ident,
1130 silc_server_query_resolve_reply, query))
1131 query->queries_left++;
1136 /* Mark the entry as being resolved */
1137 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1138 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1139 client_entry->resolve_cmd_ident = ident;
1140 client_entry->updated = time(NULL);
1142 /* Save the queried ID, which we will reprocess after we get this and
1143 all other queries back. */
1144 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1145 (query->queries_count + 1));
1146 if (query->queries) {
1147 i = query->queries_count;
1148 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1149 query->queries[i].id_type = SILC_ID_CLIENT;
1150 query->queries[i].ident = ident;
1151 query->queries_count++;
1155 /* Reply callback called after one resolving has been completed. If
1156 all resolvings has been received then we will continue with sending
1157 the command reply to the original sender of the query. */
1159 void silc_server_query_resolve_reply(void *context, void *reply)
1161 SilcServerQuery query = context;
1162 SilcServer server = query->cmd->server;
1163 SilcServerCommandReplyContext cmdr = reply;
1164 SilcUInt16 ident = cmdr->ident;
1165 SilcStatus error = SILC_STATUS_OK;
1166 SilcServerQueryID id = NULL;
1167 SilcClientEntry client_entry;
1170 /* One less query left */
1171 query->queries_left--;
1173 silc_command_get_status(cmdr->payload, NULL, &error);
1174 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1175 query->queries_left, error));
1177 /* If no error then skip to other stuff */
1178 if (error == SILC_STATUS_OK)
1181 /* Error occurred during resolving */
1183 /* Find the resolved client ID */
1184 for (i = 0; i < query->queries_count; i++) {
1185 if (query->queries[i].ident != ident)
1188 id = &query->queries[i];
1190 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1192 /* If timeout occurred for local entry when resolving attributes
1193 mark that this client doesn't support attributes in WHOIS. This
1194 assures we won't send the request again to the client. */
1195 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1196 client_entry = silc_idlist_find_client_by_id(server->local_list,
1197 id->id, TRUE, NULL);
1198 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1199 silc_id_render(id->id, SILC_ID_CLIENT)));
1200 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1201 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1202 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1207 /* Remove the RESOLVING status from the client entry */
1208 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1209 client_entry = silc_idlist_find_client_by_id(server->local_list,
1210 id->id, TRUE, NULL);
1212 client_entry = silc_idlist_find_client_by_id(server->global_list,
1213 id->id, TRUE, NULL);
1215 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1222 /* If there are queries left then wait for them */
1223 if (query->queries_left)
1226 SILC_LOG_DEBUG(("Reprocess the query"));
1228 /* We have received all queries. Now re-search all information required
1229 to complete this query. Reason we cannot save the values found in
1230 the first search is that SilcClientEntry, SilcServerEntry and
1231 SilcChannelEntry pointers may become invalid while we were waiting
1232 for these resolvings. */
1233 silc_server_query_process(server, query, FALSE);
1236 /* Send the reply to the original query. If arguments are NULL then this
1237 sends only the errors that has occurred during the processing of the
1238 query. This sends the errors always after sending all the found
1239 information. The query is over after this function returns and the
1240 `query' will become invalid. This is called only after all informations
1241 has been resolved. This means that if something is not found or is
1242 incomplete in this function we were unable to resolve the information
1243 or it does not exist at all. */
1245 void silc_server_query_send_reply(SilcServer server,
1246 SilcServerQuery query,
1247 SilcClientEntry *clients,
1248 SilcUInt32 clients_count,
1249 SilcServerEntry *servers,
1250 SilcUInt32 servers_count,
1251 SilcChannelEntry *channels,
1252 SilcUInt32 channels_count)
1254 SilcServerCommandContext cmd = query->cmd;
1255 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1260 int i, k, valid_count;
1261 char nh[256], uh[256];
1262 bool sent_reply = FALSE;
1264 SILC_LOG_DEBUG(("Sending reply to query"));
1265 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1266 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1267 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1268 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1270 status = SILC_STATUS_OK;
1273 if (clients_count) {
1274 SilcClientEntry entry;
1275 SilcSocketConnection hsock;
1277 /* Mark all invalid entries */
1278 for (i = 0, valid_count = 0; i < clients_count; i++) {
1283 switch (query->querycmd) {
1284 case SILC_COMMAND_WHOIS:
1285 if (!entry->nickname || !entry->username || !entry->userinfo ||
1286 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1287 /* When querying by ID, every "unfound" entry must cause error */
1289 silc_server_query_add_error_id(server, query,
1290 SILC_STATUS_ERR_TIMEDOUT,
1291 entry->id, SILC_ID_CLIENT);
1297 case SILC_COMMAND_IDENTIFY:
1298 if (!entry->nickname ||
1299 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1300 /* When querying by ID, every "unfound" entry must cause error */
1302 silc_server_query_add_error_id(server, query,
1303 SILC_STATUS_ERR_TIMEDOUT,
1304 entry->id, SILC_ID_CLIENT);
1310 case SILC_COMMAND_WHOWAS:
1311 if (!entry->nickname || !entry->username ||
1312 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1321 /* Start processing found clients */
1322 status = SILC_STATUS_OK;
1323 if (valid_count > 1)
1324 status = SILC_STATUS_LIST_START;
1326 /* Now do the sending of valid entries */
1328 for (i = 0; i < clients_count && valid_count; i++) {
1334 status = SILC_STATUS_LIST_ITEM;
1335 if (valid_count > 1 && k == valid_count - 1
1336 && !servers_count && !channels_count && !query->errors_count)
1337 status = SILC_STATUS_LIST_END;
1338 if (query->reply_count && k - 1 == query->reply_count)
1339 status = SILC_STATUS_LIST_END;
1341 SILC_LOG_DEBUG(("%s: client %s",
1342 (status == SILC_STATUS_OK ? " OK" :
1343 status == SILC_STATUS_LIST_START ? "START" :
1344 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1345 status == SILC_STATUS_LIST_END ? " END" :
1346 " : "), entry->nickname));
1348 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1349 memset(uh, 0, sizeof(uh));
1350 memset(nh, 0, sizeof(nh));
1352 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1353 if (!strchr(entry->nickname, '@')) {
1354 silc_strncat(nh, sizeof(nh), "@", 1);
1355 if (entry->servername) {
1356 silc_strncat(nh, sizeof(nh), entry->servername,
1357 strlen(entry->servername));
1359 len = entry->router ? strlen(entry->router->server_name) :
1360 strlen(server->server_name);
1361 silc_strncat(nh, sizeof(nh), entry->router ?
1362 entry->router->server_name :
1363 server->server_name, len);
1367 switch (query->querycmd) {
1369 case SILC_COMMAND_WHOIS:
1371 unsigned char idle[4], mode[4];
1372 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1373 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1375 memset(fempty, 0, sizeof(fempty));
1376 memset(idle, 0, sizeof(idle));
1377 silc_strncat(uh, sizeof(uh), entry->username,
1378 strlen(entry->username));
1379 if (!strchr(entry->username, '@') && entry->connection) {
1380 hsock = entry->connection;
1381 silc_strncat(uh, sizeof(uh), "@", 1);
1382 len = strlen(hsock->hostname);
1383 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1386 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1388 silc_server_get_client_channel_list(server, entry, FALSE,
1389 FALSE, &umode_list);
1392 silc_server_get_client_channel_list(server, entry, TRUE,
1395 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1396 fingerprint = entry->data.fingerprint;
1400 SILC_PUT32_MSB(entry->mode, mode);
1401 if (entry->connection)
1402 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1404 /* If Requested Attribute were present, and we do not have the
1405 attributes we will reply to them on behalf of the client. */
1408 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1409 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1410 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1411 entry->attrs_len = len;
1412 silc_buffer_free(tmpattrs);
1414 attrs = entry->attrs;
1415 len = entry->attrs_len;
1418 /* Send command reply */
1419 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1420 status, 0, ident, 10,
1421 2, idp->data, idp->len,
1425 strlen(entry->userinfo),
1426 6, channels ? channels->data : NULL,
1427 channels ? channels->len : 0,
1431 fingerprint ? 20 : 0,
1432 10, umode_list ? umode_list->data :
1433 NULL, umode_list ? umode_list->len :
1438 /* For now we always delete Requested Attributes, unless the client
1439 is detached, in which case we don't want to reconstruct the
1440 same data everytime */
1441 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1442 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1443 silc_free(entry->attrs);
1444 entry->attrs = NULL;
1448 silc_buffer_free(channels);
1450 silc_buffer_free(umode_list);
1456 case SILC_COMMAND_IDENTIFY:
1457 if (!entry->username) {
1458 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1459 status, 0, ident, 2,
1460 2, idp->data, idp->len,
1464 silc_strncat(uh, sizeof(uh), entry->username,
1465 strlen(entry->username));
1466 if (!strchr(entry->username, '@') && entry->connection) {
1467 hsock = entry->connection;
1468 silc_strncat(uh, sizeof(uh), "@", 1);
1469 len = strlen(hsock->hostname);
1470 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1473 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1474 status, 0, ident, 3,
1475 2, idp->data, idp->len,
1482 case SILC_COMMAND_WHOWAS:
1483 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1484 if (!strchr(entry->username, '@'))
1485 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1487 /* Send command reply */
1488 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1489 status, 0, ident, 4,
1490 2, idp->data, idp->len,
1495 strlen(entry->userinfo) : 0);
1500 silc_buffer_free(idp);
1502 if (status == SILC_STATUS_LIST_END)
1508 /* Not one valid entry was found, send error. If nickname was used
1509 in query send error based on that, otherwise the query->errors
1510 already includes proper errors. */
1511 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1512 silc_server_query_add_error(server, query, 1, 1,
1513 SILC_STATUS_ERR_NO_SUCH_NICK);
1518 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1519 SilcServerEntry entry;
1521 if (status == SILC_STATUS_OK && servers_count > 1)
1522 status = SILC_STATUS_LIST_START;
1525 for (i = 0; i < servers_count; i++) {
1529 status = SILC_STATUS_LIST_ITEM;
1530 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1531 !query->errors_count)
1532 status = SILC_STATUS_LIST_END;
1533 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1534 !query->errors_count)
1535 status = SILC_STATUS_LIST_END;
1536 if (query->reply_count && k - 1 == query->reply_count)
1537 status = SILC_STATUS_LIST_END;
1539 SILC_LOG_DEBUG(("%s: server %s",
1540 (status == SILC_STATUS_OK ? " OK" :
1541 status == SILC_STATUS_LIST_START ? "START" :
1542 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1543 status == SILC_STATUS_LIST_END ? " END" :
1545 entry->server_name ? entry->server_name : ""));
1547 /* Send command reply */
1548 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1549 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1550 status, 0, ident, 2,
1551 2, idp->data, idp->len,
1552 3, entry->server_name,
1553 entry->server_name ?
1554 strlen(entry->server_name) : 0);
1555 silc_buffer_free(idp);
1558 if (status == SILC_STATUS_LIST_END)
1565 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1566 SilcChannelEntry entry;
1568 if (status == SILC_STATUS_OK && channels_count > 1)
1569 status = SILC_STATUS_LIST_START;
1572 for (i = 0; i < channels_count; i++) {
1573 entry = channels[i];
1576 status = SILC_STATUS_LIST_ITEM;
1577 if (channels_count == 1 && status != SILC_STATUS_OK &&
1578 !query->errors_count)
1579 status = SILC_STATUS_LIST_END;
1580 if (channels_count > 1 && k == channels_count - 1 &&
1581 !query->errors_count)
1582 status = SILC_STATUS_LIST_END;
1583 if (query->reply_count && k - 1 == query->reply_count)
1584 status = SILC_STATUS_LIST_END;
1586 SILC_LOG_DEBUG(("%s: channel %s",
1587 (status == SILC_STATUS_OK ? " OK" :
1588 status == SILC_STATUS_LIST_START ? "START" :
1589 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1590 status == SILC_STATUS_LIST_END ? " END" :
1592 entry->channel_name ? entry->channel_name : ""));
1594 /* Send command reply */
1595 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1596 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1597 status, 0, ident, 2,
1598 2, idp->data, idp->len,
1599 3, entry->channel_name,
1600 entry->channel_name ?
1601 strlen(entry->channel_name) : 0);
1602 silc_buffer_free(idp);
1605 if (status == SILC_STATUS_LIST_END)
1612 if (query->errors_count) {
1615 if (status == SILC_STATUS_OK && query->errors_count > 1)
1616 status = SILC_STATUS_LIST_START;
1619 for (i = 0; i < query->errors_count; i++) {
1622 /* Take error argument */
1623 if (query->errors[i].type == 1) {
1624 /* Take from sent arguments */
1626 tmp = silc_argument_get_arg_type(cmd->args,
1627 query->errors[i].index, &len);
1629 } else if (query->errors[i].type == 2) {
1634 } else if (!query->errors[i].id) {
1635 /* Take from query->ids */
1637 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1638 query->ids[query->errors[k].index].id_type);
1643 /* Take added ID. */
1644 idp = silc_id_payload_encode(query->errors[i].id,
1645 query->errors[k].id_type);
1652 status = SILC_STATUS_LIST_ITEM;
1653 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1654 status = SILC_STATUS_LIST_END;
1655 if (query->errors_count > 1 && k == query->errors_count - 1)
1656 status = SILC_STATUS_LIST_END;
1657 if (query->reply_count && k - 1 == query->reply_count)
1658 status = SILC_STATUS_LIST_END;
1660 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1661 (status == SILC_STATUS_OK ? " OK" :
1662 status == SILC_STATUS_LIST_START ? "START" :
1663 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1664 status == SILC_STATUS_LIST_END ? " END" :
1666 silc_get_status_message(query->errors[i].error),
1667 query->errors[i].error));
1670 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1671 (status == SILC_STATUS_OK ?
1672 query->errors[i].error : status),
1673 (status == SILC_STATUS_OK ?
1674 0 : query->errors[i].error), ident, 1,
1676 silc_buffer_free(idp);
1679 if (status == SILC_STATUS_LIST_END)
1686 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1689 silc_server_query_free(query);
1692 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1693 of the client since we were unable to resolve them from the client.
1694 Either client does not support Requested Attributes or isn't replying
1695 to them like it should. */
1697 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1698 SilcServerQuery query,
1699 SilcClientEntry client_entry)
1701 SilcBuffer buffer = NULL;
1702 SilcAttribute attribute;
1703 SilcAttributePayload attr;
1704 SilcAttributeObjPk pk;
1705 SilcAttributeObjService service;
1707 unsigned char sign[2048 + 1];
1708 SilcUInt32 sign_len;
1710 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1712 /* Go through all requested attributes */
1713 silc_dlist_start(query->attrs);
1714 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1715 attribute = silc_attribute_get_attribute(attr);
1716 switch (attribute) {
1718 case SILC_ATTRIBUTE_SERVICE:
1719 /* Put SERVICE. Put only SILC service. */
1720 memset(&service, 0, sizeof(service));
1721 service.port = (server->config->server_info->primary ?
1722 server->config->server_info->primary->port : SILC_PORT);
1723 silc_strncat(service.address, sizeof(service.address),
1724 server->server_name, strlen(server->server_name));
1725 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1726 if (client_entry->connection)
1727 service.idle = time(NULL) - client_entry->data.last_receive;
1728 buffer = silc_attribute_payload_encode(buffer, attribute,
1729 SILC_ATTRIBUTE_FLAG_VALID,
1730 &service, sizeof(service));
1735 case SILC_ATTRIBUTE_STATUS_MOOD:
1736 /* Put STATUS_MOOD */
1737 buffer = silc_attribute_payload_encode(buffer, attribute,
1738 SILC_ATTRIBUTE_FLAG_VALID,
1740 SILC_ATTRIBUTE_MOOD_NORMAL,
1741 sizeof(SilcUInt32));
1746 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1747 /* Put STATUS_FREETEXT. We just tell in the message that we are
1748 replying on behalf of the client. */
1750 "This information was provided by the server on behalf of the user";
1751 buffer = silc_attribute_payload_encode(buffer, attribute,
1752 SILC_ATTRIBUTE_FLAG_VALID,
1758 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1759 /* Put PREFERRED_CONTACT */
1760 buffer = silc_attribute_payload_encode(buffer, attribute,
1761 SILC_ATTRIBUTE_FLAG_VALID,
1763 SILC_ATTRIBUTE_CONTACT_CHAT,
1764 sizeof(SilcUInt32));
1769 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1770 /* Put USER_PUBLIC_KEY */
1771 if (client_entry->data.public_key) {
1772 pk.type = "silc-rsa";
1773 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1775 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1776 SILC_ATTRIBUTE_FLAG_VALID :
1777 SILC_ATTRIBUTE_FLAG_INVALID,
1785 /* No public key available */
1786 buffer = silc_attribute_payload_encode(buffer, attribute,
1787 SILC_ATTRIBUTE_FLAG_INVALID,
1794 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1795 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1796 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1799 /* For other attributes we cannot reply so mark it invalid */
1800 buffer = silc_attribute_payload_encode(buffer, attribute,
1801 SILC_ATTRIBUTE_FLAG_INVALID,
1809 /* Always put our public key. This assures that we send at least
1810 something valid back always. */
1811 pk.type = "silc-rsa";
1812 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1813 buffer = silc_attribute_payload_encode(buffer,
1814 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1815 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1816 SILC_ATTRIBUTE_FLAG_INVALID,
1822 /* Finally compute the digital signature of all the data we provided
1823 as an indication that we provided rightfull information, and this
1824 also authenticates our public key. */
1825 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1826 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1827 buffer->data, buffer->len,
1831 pk.data_len = sign_len;
1833 silc_attribute_payload_encode(buffer,
1834 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1835 SILC_ATTRIBUTE_FLAG_VALID,
1844 /* Find client by the Client ID indicated by the `client_id', and if not
1845 found then query it by using WHOIS command. The client information
1846 is also resolved if the cached information is incomplete or if the
1847 `always_resolve' is set to TRUE. The indication whether requested
1848 client was being resolved is saved into `resolved'. If the client
1849 is not being resolved its entry is returned by this function. NULL
1850 is returned if client is resolved. */
1852 SilcClientEntry silc_server_query_client(SilcServer server,
1853 const SilcClientID *client_id,
1854 bool always_resolve,
1857 SilcClientEntry client;
1859 SILC_LOG_DEBUG(("Resolving client by client ID"));
1864 client = silc_idlist_find_client_by_id(server->local_list,
1865 (SilcClientID *)client_id,
1868 client = silc_idlist_find_client_by_id(server->global_list,
1869 (SilcClientID *)client_id,
1871 if (!client && server->server_type == SILC_ROUTER)
1875 if (!client && server->standalone)
1878 if (!client || !client->nickname || !client->username ||
1880 SilcBuffer buffer, idp;
1883 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1884 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1885 client->resolve_cmd_ident = ++server->cmd_ident;
1888 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1889 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1890 server->cmd_ident, 1,
1891 4, idp->data, idp->len);
1892 silc_server_packet_send(server, client ? client->router->connection :
1893 SILC_PRIMARY_ROUTE(server),
1894 SILC_PACKET_COMMAND, 0,
1895 buffer->data, buffer->len, FALSE);
1896 silc_buffer_free(idp);
1897 silc_buffer_free(buffer);