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 SilcUInt16 index; /* Index to IDs */
46 unsigned int from_cmd : 1; /* TRUE if `index' is from command args,
47 otherwise from query->ids */
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 `from_cmd'. */
178 void silc_server_query_add_error(SilcServer server,
179 SilcServerQuery query,
184 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
185 (query->errors_count + 1));
188 query->errors[query->errors_count].index = index;
189 query->errors[query->errors_count].from_cmd = from_cmd;
190 query->errors[query->errors_count].error = error;
191 query->errors[query->errors_count].id = NULL;
192 query->errors[query->errors_count].id_type = 0;
193 query->errors_count++;
196 /* Same as silc_server_query_add_error but adds the ID data to be used
197 with error sending with this error type. */
199 void silc_server_query_add_error_id(SilcServer server,
200 SilcServerQuery query,
202 void *id, SilcIdType id_type)
204 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
205 (query->errors_count + 1));
208 query->errors[query->errors_count].index = 0;
209 query->errors[query->errors_count].from_cmd = FALSE;
210 query->errors[query->errors_count].error = error;
211 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
212 query->errors[query->errors_count].id_type = id_type;
213 query->errors_count++;
216 /* Processes query as command. The `query' is the command that is
217 being processed indicated by the `cmd'. The `query' can be one of
218 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
219 SILC_COMMAND_IDENTIFY. This function handles the reply sending
220 to the entity who sent this query to us automatically. Returns
221 TRUE if the query is being processed or FALSE on error. */
223 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
224 SilcServerCommandContext cmd)
226 SilcServerQuery query;
228 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
230 query = silc_calloc(1, sizeof(*query));
231 query->querycmd = querycmd;
232 query->cmd = silc_server_command_dup(cmd);
236 case SILC_COMMAND_WHOIS:
237 /* If we are normal server and query contains nickname, send it
238 directly to router. */
239 if (server->server_type == SILC_SERVER && !server->standalone &&
240 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
241 silc_argument_get_arg_type(cmd->args, 1, NULL)) {
242 silc_server_query_send_router(server, query);
247 case SILC_COMMAND_WHOWAS:
248 /* WHOWAS query is always sent to router if we are normal server */
249 if (server->server_type == SILC_SERVER && !server->standalone &&
250 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
251 silc_server_query_send_router(server, query);
256 case SILC_COMMAND_IDENTIFY:
257 /* If we are normal server and query does not contain IDs, send it
258 directly to router (it contains nickname, server name or channel
260 if (server->server_type == SILC_SERVER && !server->standalone &&
261 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
262 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
263 silc_server_query_send_router(server, query);
269 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
270 silc_server_query_free(query);
274 /* Now parse the request */
275 silc_server_query_parse(server, query);
280 /* Send the received query to our primary router since we could not
281 handle the query directly. We will reprocess the query after our
282 router replies back. */
284 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
287 SilcUInt16 old_ident;
289 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
291 /* Send WHOIS command to our router */
292 old_ident = silc_command_get_ident(query->cmd->payload);
293 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
294 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
295 silc_server_packet_send(server,
296 SILC_PRIMARY_ROUTE(server),
297 SILC_PACKET_COMMAND, 0,
298 tmpbuf->data, tmpbuf->len, TRUE);
299 silc_command_set_ident(query->cmd->payload, old_ident);
300 silc_buffer_free(tmpbuf);
302 query->resolved = TRUE;
304 /* Continue parsing the query after received reply from router */
305 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
306 silc_server_query_send_router_reply, query);
309 /* Reply callback called after primary router has replied to our initial
310 sending of the query to it. We will proceed the query in this function. */
312 void silc_server_query_send_router_reply(void *context, void *reply)
314 SilcServerQuery query = context;
315 SilcServer server = query->cmd->server;
316 SilcServerCommandReplyContext cmdr = reply;
318 SILC_LOG_DEBUG(("Received reply from router to query"));
320 /* Check if router sent error reply */
321 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
324 SILC_LOG_DEBUG(("Sending error to original query"));
326 /* Send the same command reply payload which contains the error */
327 silc_command_set_command(cmdr->payload, query->querycmd);
328 silc_command_set_ident(cmdr->payload,
329 silc_command_get_ident(query->cmd->payload));
330 buffer = silc_command_payload_encode_payload(cmdr->payload);
331 silc_server_packet_send(server, query->cmd->sock,
332 SILC_PACKET_COMMAND_REPLY, 0,
333 buffer->data, buffer->len, FALSE);
334 silc_buffer_free(buffer);
335 silc_server_query_free(query);
339 /* Continue with parsing */
340 silc_server_query_parse(server, query);
343 /* Parse the command query and start processing the queries in detail. */
345 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
347 SilcServerCommandContext cmd = query->cmd;
349 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
354 SILC_LOG_DEBUG(("Parsing %s query",
355 silc_get_command_name(query->querycmd)));
357 switch (query->querycmd) {
359 case SILC_COMMAND_WHOIS:
360 /* Get Client IDs if present. Take IDs always instead of nickname. */
361 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
365 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
367 silc_server_query_send_error(server, query,
368 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
369 silc_server_query_free(query);
373 /* Get the nickname@server string and parse it */
375 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
376 silc_server_query_send_error(server, query,
377 SILC_STATUS_ERR_BAD_NICKNAME, 0);
378 silc_server_query_free(query);
383 /* Parse the IDs included in the query */
384 query->ids = silc_calloc(argc, sizeof(*query->ids));
386 for (i = 0; i < argc; i++) {
387 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
391 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
392 if (!id || id_type != SILC_ID_CLIENT) {
393 silc_server_query_add_error(server, query, TRUE, i + 4,
394 SILC_STATUS_ERR_BAD_CLIENT_ID);
398 /* Normal server must check whether this ID exist, and if not then
399 send the query to router, unless done so already */
400 if (server->server_type == SILC_SERVER && !query->resolved) {
401 if (!silc_idlist_find_client_by_id(server->local_list,
403 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
404 !silc_idlist_find_client_by_id(server->global_list,
406 silc_server_query_send_router(server, query);
407 for (i = 0; i < query->ids_count; i++)
408 silc_free(query->ids[i].id);
409 silc_free(query->ids);
411 query->ids_count = 0;
418 query->ids[query->ids_count].id = id;
419 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
424 /* Get the max count of reply messages allowed */
425 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
426 if (tmp && tmp_len == sizeof(SilcUInt32))
427 SILC_GET32_MSB(query->reply_count, tmp);
429 /* Get requested attributes if set */
430 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
431 if (tmp && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
432 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
434 /* When Requested Attributes is present we will assure that this
435 client cannot execute the WHOIS command too fast. This would be
436 same as having SILC_CF_LAG_STRICT. */
437 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
438 cmd->sock->user_data)
439 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
443 case SILC_COMMAND_WHOWAS:
445 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
447 silc_server_query_send_error(server, query,
448 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
449 silc_server_query_free(query);
453 /* Get the nickname@server string and parse it */
455 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
456 silc_server_query_send_error(server, query,
457 SILC_STATUS_ERR_BAD_NICKNAME, 0);
458 silc_server_query_free(query);
462 /* Get the max count of reply messages allowed */
463 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
464 if (tmp && tmp_len == sizeof(SilcUInt32))
465 SILC_GET32_MSB(query->reply_count, tmp);
468 case SILC_COMMAND_IDENTIFY:
469 /* Get IDs if present. Take IDs always instead of names. */
470 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
473 /* Try get nickname */
474 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
476 /* Get the nickname@server string and parse it */
478 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
479 silc_server_query_add_error(server, query, TRUE, 1,
480 SILC_STATUS_ERR_BAD_NICKNAME);
483 /* Try get server name */
484 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
486 query->server_name = silc_memdup(tmp, tmp_len);
488 /* Get channel name */
489 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
490 if (tmp && tmp_len <= 256)
491 query->channel_name = silc_memdup(tmp, tmp_len);
493 if (!query->nickname && !query->server_name && !query->channel_name) {
494 silc_server_query_send_error(server, query,
495 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
496 silc_server_query_free(query);
501 /* Parse the IDs included in the query */
502 query->ids = silc_calloc(argc, sizeof(*query->ids));
504 for (i = 0; i < argc; i++) {
505 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
509 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
511 silc_server_query_add_error(server, query, TRUE, i + 5,
512 SILC_STATUS_ERR_BAD_CLIENT_ID);
516 /* Normal server must check whether this ID exist, and if not then
517 send the query to router, unless done so already */
518 if (server->server_type == SILC_SERVER && !query->resolved) {
519 if (id_type == SILC_ID_CLIENT) {
520 if (!silc_idlist_find_client_by_id(server->local_list,
522 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
523 !silc_idlist_find_client_by_id(server->global_list,
525 silc_server_query_send_router(server, query);
526 for (i = 0; i < query->ids_count; i++)
527 silc_free(query->ids[i].id);
528 silc_free(query->ids);
530 query->ids_count = 0;
536 /* For now all other ID's except Client ID's are explicitly
537 sent to router for resolving. */
538 silc_server_query_send_router(server, query);
539 for (i = 0; i < query->ids_count; i++)
540 silc_free(query->ids[i].id);
541 silc_free(query->ids);
543 query->ids_count = 0;
549 query->ids[query->ids_count].id = id;
550 query->ids[query->ids_count].id_type = id_type;
555 /* Get the max count of reply messages allowed */
556 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
557 if (tmp && tmp_len == sizeof(SilcUInt32))
558 SILC_GET32_MSB(query->reply_count, tmp);
562 /* Start processing the query information */
563 silc_server_query_process(server, query, TRUE);
566 /* Processes the parsed query. This does the actual finding of the
567 queried information and prepares for sending reply to the original
568 sender of the query command. */
570 void silc_server_query_process(SilcServer server, SilcServerQuery query,
573 SilcServerCommandContext cmd = query->cmd;
574 bool check_global = FALSE;
576 SilcClientEntry *clients = NULL, client_entry;
577 SilcChannelEntry *channels = NULL;
578 SilcServerEntry *servers = NULL;
579 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
582 SILC_LOG_DEBUG(("Processing %s query",
583 silc_get_command_name(query->querycmd)));
585 /* Check global lists if query is coming from client or we are not
586 normal server (we know global information). */
587 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
589 else if (server->server_type != SILC_SERVER)
592 if (query->nickname) {
593 /* Get all clients matching nickname from local list */
594 if (!silc_idlist_get_clients_by_hash(server->local_list,
595 query->nickname, server->md5hash,
596 &clients, &clients_count))
597 silc_idlist_get_clients_by_nickname(server->local_list,
600 &clients, &clients_count);
602 /* Check global list as well */
604 if (!silc_idlist_get_clients_by_hash(server->global_list,
605 query->nickname, server->md5hash,
606 &clients, &clients_count))
607 silc_idlist_get_clients_by_nickname(server->global_list,
610 &clients, &clients_count);
614 silc_server_query_add_error(server, query, TRUE, 1,
615 SILC_STATUS_ERR_NO_SUCH_NICK);
618 if (query->server_name) {
619 /* Find server by name */
620 entry = silc_idlist_find_server_by_name(server->local_list,
621 query->server_name, TRUE, NULL);
622 if (!entry && check_global)
623 entry = silc_idlist_find_server_by_name(server->global_list,
624 query->server_name, TRUE, NULL);
626 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
627 servers[servers_count++] = (SilcServerEntry)entry;
631 silc_server_query_add_error(server, query, TRUE, 2,
632 SILC_STATUS_ERR_NO_SUCH_SERVER);
635 if (query->channel_name) {
636 /* Find channel by name */
637 entry = silc_idlist_find_channel_by_name(server->local_list,
638 query->channel_name, NULL);
639 if (!entry && check_global)
640 entry = silc_idlist_find_channel_by_name(server->global_list,
641 query->channel_name, NULL);
643 channels = silc_realloc(channels, sizeof(*channels) *
644 (channels_count + 1));
645 channels[channels_count++] = (SilcChannelEntry)entry;
649 silc_server_query_add_error(server, query, TRUE, 3,
650 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
653 if (query->ids_count) {
654 /* Find entries by the queried IDs */
655 for (i = 0; i < query->ids_count; i++) {
656 void *id = query->ids[i].id;
660 switch (query->ids[i].id_type) {
663 /* Get client entry */
664 entry = silc_idlist_find_client_by_id(server->local_list,
666 if (!entry && check_global)
667 entry = silc_idlist_find_client_by_id(server->global_list,
670 silc_server_query_add_error(server, query, FALSE, i,
671 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
675 clients = silc_realloc(clients, sizeof(*clients) *
676 (clients_count + 1));
677 clients[clients_count++] = (SilcClientEntry)entry;
681 /* Get server entry */
682 entry = silc_idlist_find_server_by_id(server->local_list,
684 if (!entry && check_global)
685 entry = silc_idlist_find_server_by_id(server->global_list,
688 silc_server_query_add_error(server, query, FALSE, i,
689 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
693 servers = silc_realloc(servers, sizeof(*servers) *
694 (servers_count + 1));
695 servers[servers_count++] = (SilcServerEntry)entry;
698 case SILC_ID_CHANNEL:
699 /* Get channel entry */
700 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
701 if (!entry && check_global)
702 entry = silc_idlist_find_channel_by_id(server->global_list, id,
705 silc_server_query_add_error(server, query, FALSE, i,
706 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
710 channels = silc_realloc(channels, sizeof(*channels) *
711 (channels_count + 1));
712 channels[channels_count++] = (SilcChannelEntry)entry;
721 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
722 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
723 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
725 /* If nothing was found, then just send the errors */
726 if (!clients && !channels && !servers) {
727 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
731 /* If caller does not want us to resolve anything (has resolved already)
732 then just continue with sending the reply */
734 silc_server_query_send_reply(server, query, clients, clients_count,
735 servers, servers_count, channels,
743 /* Now process all found information and if necessary do some more
745 switch (query->querycmd) {
747 case SILC_COMMAND_WHOIS:
748 for (i = 0; i < clients_count; i++) {
749 client_entry = clients[i];
751 /* Check if cannot query this anyway, so take next one */
753 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
756 /* If Requested Attributes is set then we always resolve the client
757 information, if not then check whether the entry is complete or not
758 and decide whether we need to resolve or not. */
761 /* Even if nickname and stuff are present, we may need to resolve
763 if (client_entry->nickname && client_entry->username &&
764 client_entry->userinfo) {
765 /* Check if cannot query this anyway, so take next one */
766 if (!client_entry->router)
769 /* If we are router, client is local to us, or client is on channel
770 we do not need to resolve the client information. */
771 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
772 || silc_hash_table_count(client_entry->channels) ||
778 /* Remove the NOATTR status periodically */
779 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
780 client_entry->updated + 600 < time(NULL))
781 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
783 /* When requested attributes is present and local client is detached
784 we cannot send the command to the client, we'll reply on behalf of
785 the client instead. */
786 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
787 (client_entry->mode & SILC_UMODE_DETACHED ||
788 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
791 /* Resolve the detailed client information. If client is local we
792 know that attributes were present and we will resolve directly
793 from the client. Otherwise resolve from client's owner. */
794 silc_server_query_resolve(server, query,
795 (SILC_IS_LOCAL(client_entry) ?
796 client_entry->connection :
797 client_entry->router->connection),
802 case SILC_COMMAND_WHOWAS:
803 for (i = 0; i < clients_count; i++) {
804 client_entry = clients[i];
806 /* Check if cannot query this anyway, so take next one */
807 if (!client_entry || !client_entry->router ||
808 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
811 /* If both nickname and username are present no resolving is needed */
812 if (client_entry->nickname && client_entry->username)
815 /* Resolve the detailed client information */
816 silc_server_query_resolve(server, query,
817 client_entry->router->connection,
822 case SILC_COMMAND_IDENTIFY:
823 for (i = 0; i < clients_count; i++) {
824 client_entry = clients[i];
826 /* Check if cannot query this anyway, so take next one */
827 if (!client_entry || !client_entry->router ||
828 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
831 /* Even if nickname is present, we may need to resolve the entry */
832 if (client_entry->nickname) {
834 /* If we are router, client is local to us, or client is on channel
835 we do not need to resolve the client information. */
836 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
837 || silc_hash_table_count(client_entry->channels) ||
842 /* Resolve the detailed client information */
843 silc_server_query_resolve(server, query,
844 client_entry->router->connection,
850 if (!query->queries_count)
851 /* If we didn't have to do any resolving, continue with sending the
852 command reply to the original sender. */
853 silc_server_query_send_reply(server, query, clients, clients_count,
854 servers, servers_count, channels,
857 /* Now actually send the resolvings we gathered earlier */
858 silc_server_query_resolve(server, query, NULL, NULL);
865 /* Resolve the detailed information for the `client_entry'. Only client
866 information needs to be resolved for being incomplete. Each incomplete
867 client entry calls this function to do the resolving. */
869 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
870 SilcSocketConnection sock,
871 SilcClientEntry client_entry)
873 SilcServerCommandContext cmd = query->cmd;
874 SilcServerQueryList r = NULL;
881 if (!sock && client_entry)
884 /* If arguments are NULL we will now actually send the resolvings
885 that earlier has been gathered by calling this function. */
886 if (!sock && !client_entry) {
889 SILC_LOG_DEBUG(("Sending the resolvings"));
891 /* WHOWAS resolving has been done at the same time this function
892 was called to add the resolving for WHOWAS, so just return. */
893 if (query->querycmd == SILC_COMMAND_WHOWAS)
896 for (i = 0; i < query->querylist_count; i++) {
897 r = &query->querylist[i];
899 /* If Requested Attributes were present put them to this resolving */
900 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
902 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
903 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
904 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
906 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
908 r->arg[r->argc] = silc_memdup(tmp, len);
909 r->arg_lens[r->argc] = len;
910 r->arg_types[r->argc] = 3;
914 /* Send WHOIS command */
915 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
916 r->argc, r->arg, r->arg_lens,
917 r->arg_types, r->ident);
918 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
919 res_cmd->data, res_cmd->len, FALSE);
920 silc_buffer_free(res_cmd);
922 /* Reprocess this packet after received reply */
923 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
925 silc_server_query_resolve_reply,
927 query->queries_left++;
930 /* Cleanup this temporary context */
931 for (i = 0; i < query->querylist_count; i++) {
933 for (k = 0; k < query->querylist[i].argc; k++)
934 silc_free(query->querylist[i].arg[k]);
935 silc_free(query->querylist[i].arg);
936 silc_free(query->querylist[i].arg_lens);
937 silc_free(query->querylist[i].arg_types);
939 silc_free(query->querylist);
940 query->querylist = NULL;
941 query->querylist_count = 0;
945 SILC_LOG_DEBUG(("Resolving client information"));
947 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
948 /* The entry is being resolved by some other external query already.
949 Attach to that query instead of resolving again. */
950 ident = client_entry->resolve_cmd_ident;
951 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
952 silc_server_query_resolve_reply, query))
953 query->queries_left++;
955 /* This entry will be resolved */
956 ident = ++server->cmd_ident;
958 switch (query->querycmd) {
960 case SILC_COMMAND_WHOIS:
961 case SILC_COMMAND_IDENTIFY:
962 /* Take existing query context if exist for this connection */
963 for (i = 0; i < query->querylist_count; i++)
964 if (query->querylist[i].sock == sock) {
965 r = &query->querylist[i];
970 /* Allocate new temp query list context */
971 query->querylist = silc_realloc(query->querylist,
972 sizeof(*query->querylist) *
973 (query->querylist_count + 1));
974 r = &query->querylist[query->querylist_count];
975 query->querylist_count++;
976 memset(r, 0, sizeof(*r));
979 if (SILC_IS_LOCAL(client_entry))
984 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
985 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
986 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
988 /* Add the client entry to be resolved */
989 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
990 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
991 r->arg_lens[r->argc] = idp->len;
992 r->arg_types[r->argc] = r->argc + 4;
994 silc_buffer_free(idp);
998 case SILC_COMMAND_WHOWAS:
999 /* We must send WHOWAS command since it's the only the way of
1000 resolving clients that are not present in the network anymore. */
1001 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1002 1, query->nickname, strlen(query->nickname));
1003 if (silc_server_command_pending(server, query->querycmd, ident,
1004 silc_server_query_resolve_reply, query))
1005 query->queries_left++;
1010 /* Mark the entry as being resolved */
1011 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1012 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1013 client_entry->resolve_cmd_ident = ident;
1014 client_entry->updated = time(NULL);
1016 /* Save the queried ID, which we will reprocess after we get this and
1017 all other queries back. */
1018 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1019 (query->queries_count + 1));
1020 if (query->queries) {
1021 i = query->queries_count;
1022 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1023 query->queries[i].id_type = SILC_ID_CLIENT;
1024 query->queries[i].ident = ident;
1025 query->queries_count++;
1029 /* Reply callback called after one resolving has been completed. If
1030 all resolvings has been received then we will continue with sending
1031 the command reply to the original sender of the query. */
1033 void silc_server_query_resolve_reply(void *context, void *reply)
1035 SilcServerQuery query = context;
1036 SilcServer server = query->cmd->server;
1037 SilcServerCommandReplyContext cmdr = reply;
1038 SilcUInt16 ident = cmdr->ident;
1039 SilcStatus error = SILC_STATUS_OK;
1040 SilcServerQueryID id = NULL;
1041 SilcClientEntry client_entry;
1044 /* One less query left */
1045 query->queries_left--;
1047 silc_command_get_status(cmdr->payload, NULL, &error);
1048 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1049 query->queries_left, error));
1051 /* If no error then skip to other stuff */
1052 if (error == SILC_STATUS_OK)
1055 /* Error occurred during resolving */
1057 /* Find the resolved client ID */
1058 for (i = 0; i < query->queries_count; i++) {
1059 if (query->queries[i].ident != ident)
1062 id = &query->queries[i];
1064 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1066 /* If timeout occurred for local entry when resolving attributes
1067 mark that this client doesn't support attributes in WHOIS. This
1068 assures we won't send the request again to the client. */
1069 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1070 client_entry = silc_idlist_find_client_by_id(server->local_list,
1071 id->id, TRUE, NULL);
1072 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1073 silc_id_render(id->id, SILC_ID_CLIENT)));
1074 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1075 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1076 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1081 /* Remove the RESOLVING status from the client entry */
1082 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1083 client_entry = silc_idlist_find_client_by_id(server->local_list,
1084 id->id, TRUE, NULL);
1086 client_entry = silc_idlist_find_client_by_id(server->global_list,
1087 id->id, TRUE, NULL);
1089 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1096 /* If there are queries left then wait for them */
1097 if (query->queries_left)
1100 SILC_LOG_DEBUG(("Reprocess the query"));
1102 /* We have received all queries. Now re-search all information required
1103 to complete this query. Reason we cannot save the values found in
1104 the first search is that SilcClientEntry, SilcServerEntry and
1105 SilcChannelEntry pointers may become invalid while we were waiting
1106 for these resolvings. */
1107 silc_server_query_process(server, query, FALSE);
1110 /* Send the reply to the original query. If arguments are NULL then this
1111 sends only the errors that has occurred during the processing of the
1112 query. This sends the errors always after sending all the found
1113 information. The query is over after this function returns and the
1114 `query' will become invalid. This is called only after all informations
1115 has been resolved. This means that if something is not found or is
1116 incomplete in this function we were unable to resolve the information
1117 or it does not exist at all. */
1119 void silc_server_query_send_reply(SilcServer server,
1120 SilcServerQuery query,
1121 SilcClientEntry *clients,
1122 SilcUInt32 clients_count,
1123 SilcServerEntry *servers,
1124 SilcUInt32 servers_count,
1125 SilcChannelEntry *channels,
1126 SilcUInt32 channels_count)
1128 SilcServerCommandContext cmd = query->cmd;
1129 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1134 int i, k, valid_count;
1135 char nh[256], uh[256];
1136 bool sent_reply = FALSE;
1138 SILC_LOG_DEBUG(("Sending reply to query"));
1139 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1140 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1141 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1142 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1144 status = SILC_STATUS_OK;
1147 if (clients_count) {
1148 SilcClientEntry entry;
1149 SilcSocketConnection hsock;
1151 /* Mark all invalid entries */
1152 for (i = 0, valid_count = 0; i < clients_count; i++) {
1154 switch (query->querycmd) {
1155 case SILC_COMMAND_WHOIS:
1156 if (!entry->nickname || !entry->username || !entry->userinfo ||
1157 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1158 /* When querying by ID, every "unfound" entry must cause error */
1160 silc_server_query_add_error_id(server, query,
1161 SILC_STATUS_ERR_TIMEDOUT,
1162 entry->id, SILC_ID_CLIENT);
1168 case SILC_COMMAND_IDENTIFY:
1169 if (!entry->nickname ||
1170 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1171 /* When querying by ID, every "unfound" entry must cause error */
1173 silc_server_query_add_error_id(server, query,
1174 SILC_STATUS_ERR_TIMEDOUT,
1175 entry->id, SILC_ID_CLIENT);
1181 case SILC_COMMAND_WHOWAS:
1182 if (!entry->nickname || !entry->username ||
1183 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1192 /* Start processing found clients */
1193 status = SILC_STATUS_OK;
1194 if (valid_count > 1)
1195 status = SILC_STATUS_LIST_START;
1197 /* Now do the sending of valid entries */
1199 for (i = 0; i < clients_count && valid_count; i++) {
1205 status = SILC_STATUS_LIST_ITEM;
1206 if (valid_count > 1 && k == valid_count - 1
1207 && !servers_count && !channels_count && !query->errors_count)
1208 status = SILC_STATUS_LIST_END;
1209 if (query->reply_count && k - 1 == query->reply_count)
1210 status = SILC_STATUS_LIST_END;
1212 SILC_LOG_DEBUG(("%s: client %s",
1213 (status == SILC_STATUS_OK ? " OK" :
1214 status == SILC_STATUS_LIST_START ? "START" :
1215 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1216 status == SILC_STATUS_LIST_END ? " END" :
1217 " : "), entry->nickname));
1219 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1220 memset(uh, 0, sizeof(uh));
1221 memset(nh, 0, sizeof(nh));
1223 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1224 if (!strchr(entry->nickname, '@')) {
1225 silc_strncat(nh, sizeof(nh), "@", 1);
1226 if (entry->servername) {
1227 silc_strncat(nh, sizeof(nh), entry->servername,
1228 strlen(entry->servername));
1230 len = entry->router ? strlen(entry->router->server_name) :
1231 strlen(server->server_name);
1232 silc_strncat(nh, sizeof(nh), entry->router ?
1233 entry->router->server_name :
1234 server->server_name, len);
1238 switch (query->querycmd) {
1240 case SILC_COMMAND_WHOIS:
1242 unsigned char idle[4], mode[4];
1243 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1244 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1246 memset(fempty, 0, sizeof(fempty));
1247 memset(idle, 0, sizeof(idle));
1248 silc_strncat(uh, sizeof(uh), entry->username,
1249 strlen(entry->username));
1250 if (!strchr(entry->username, '@') && entry->connection) {
1251 hsock = entry->connection;
1252 silc_strncat(uh, sizeof(uh), "@", 1);
1253 len = strlen(hsock->hostname);
1254 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1257 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1259 silc_server_get_client_channel_list(server, entry, FALSE,
1260 FALSE, &umode_list);
1263 silc_server_get_client_channel_list(server, entry, TRUE,
1266 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1267 fingerprint = entry->data.fingerprint;
1271 SILC_PUT32_MSB(entry->mode, mode);
1272 if (entry->connection)
1273 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1275 /* If Requested Attribute were present, and we do not have the
1276 attributes we will reply to them on behalf of the client. */
1279 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1280 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1281 entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
1282 entry->attrs_len = tmpattrs->len;
1283 silc_buffer_free(tmpattrs);
1285 attrs = entry->attrs;
1286 len = entry->attrs_len;
1289 /* Send command reply */
1290 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1291 status, 0, ident, 10,
1292 2, idp->data, idp->len,
1296 strlen(entry->userinfo),
1297 6, channels ? channels->data : NULL,
1298 channels ? channels->len : 0,
1302 fingerprint ? 20 : 0,
1303 10, umode_list ? umode_list->data :
1304 NULL, umode_list ? umode_list->len :
1309 /* For now we always delete Requested Attributes, unless the client
1310 is detached, in which case we don't want to reconstruct the
1311 same data everytime */
1312 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1313 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1314 silc_free(entry->attrs);
1315 entry->attrs = NULL;
1319 silc_buffer_free(channels);
1321 silc_buffer_free(umode_list);
1327 case SILC_COMMAND_IDENTIFY:
1328 if (!entry->username) {
1329 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1330 status, 0, ident, 2,
1331 2, idp->data, idp->len,
1335 silc_strncat(uh, sizeof(uh), entry->username,
1336 strlen(entry->username));
1337 if (!strchr(entry->username, '@') && entry->connection) {
1338 hsock = entry->connection;
1339 silc_strncat(uh, sizeof(uh), "@", 1);
1340 len = strlen(hsock->hostname);
1341 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1344 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1345 status, 0, ident, 3,
1346 2, idp->data, idp->len,
1353 case SILC_COMMAND_WHOWAS:
1354 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1355 if (!strchr(entry->username, '@'))
1356 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1358 /* Send command reply */
1359 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1360 status, 0, ident, 4,
1361 2, idp->data, idp->len,
1366 strlen(entry->userinfo) : 0);
1371 silc_buffer_free(idp);
1373 if (status == SILC_STATUS_LIST_END)
1379 /* Not one valid entry was found, send error. If nickname was used
1380 in query send error based on that, otherwise the query->errors
1381 already includes proper errors. */
1382 if (query->nickname)
1383 silc_server_query_add_error(server, query, TRUE, 1,
1384 SILC_STATUS_ERR_NO_SUCH_NICK);
1389 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1390 SilcServerEntry entry;
1392 if (status == SILC_STATUS_OK && servers_count > 1)
1393 status = SILC_STATUS_LIST_START;
1396 for (i = 0; i < servers_count; i++) {
1400 status = SILC_STATUS_LIST_ITEM;
1401 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1402 !query->errors_count)
1403 status = SILC_STATUS_LIST_END;
1404 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1405 !query->errors_count)
1406 status = SILC_STATUS_LIST_END;
1407 if (query->reply_count && k - 1 == query->reply_count)
1408 status = SILC_STATUS_LIST_END;
1410 SILC_LOG_DEBUG(("%s: server %s",
1411 (status == SILC_STATUS_OK ? " OK" :
1412 status == SILC_STATUS_LIST_START ? "START" :
1413 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1414 status == SILC_STATUS_LIST_END ? " END" :
1416 entry->server_name ? entry->server_name : ""));
1418 /* Send command reply */
1419 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1420 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1421 status, 0, ident, 2,
1422 2, idp->data, idp->len,
1423 3, entry->server_name,
1424 entry->server_name ?
1425 strlen(entry->server_name) : 0);
1426 silc_buffer_free(idp);
1429 if (status == SILC_STATUS_LIST_END)
1436 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1437 SilcChannelEntry entry;
1439 if (status == SILC_STATUS_OK && channels_count > 1)
1440 status = SILC_STATUS_LIST_START;
1443 for (i = 0; i < channels_count; i++) {
1444 entry = channels[i];
1447 status = SILC_STATUS_LIST_ITEM;
1448 if (channels_count == 1 && status != SILC_STATUS_OK &&
1449 !query->errors_count)
1450 status = SILC_STATUS_LIST_END;
1451 if (channels_count > 1 && k == channels_count - 1 &&
1452 !query->errors_count)
1453 status = SILC_STATUS_LIST_END;
1454 if (query->reply_count && k - 1 == query->reply_count)
1455 status = SILC_STATUS_LIST_END;
1457 SILC_LOG_DEBUG(("%s: channel %s",
1458 (status == SILC_STATUS_OK ? " OK" :
1459 status == SILC_STATUS_LIST_START ? "START" :
1460 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1461 status == SILC_STATUS_LIST_END ? " END" :
1463 entry->channel_name ? entry->channel_name : ""));
1465 /* Send command reply */
1466 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1467 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1468 status, 0, ident, 2,
1469 2, idp->data, idp->len,
1470 3, entry->channel_name,
1471 entry->channel_name ?
1472 strlen(entry->channel_name) : 0);
1473 silc_buffer_free(idp);
1476 if (status == SILC_STATUS_LIST_END)
1483 if (query->errors_count) {
1486 if (status == SILC_STATUS_OK && query->errors_count > 1)
1487 status = SILC_STATUS_LIST_START;
1490 for (i = 0; i < query->errors_count; i++) {
1493 /* Take error argument */
1494 if (query->errors[i].from_cmd) {
1496 tmp = silc_argument_get_arg_type(cmd->args,
1497 query->errors[i].index, &len);
1498 if (query->errors[i].index == 1)
1499 type = 3; /* Nickname */
1502 } else if (!query->errors[i].id) {
1504 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1505 query->ids[query->errors[k].index].id_type);
1510 idp = silc_id_payload_encode(query->errors[i].id,
1511 query->errors[k].id_type);
1518 status = SILC_STATUS_LIST_ITEM;
1519 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1520 status = SILC_STATUS_LIST_END;
1521 if (query->errors_count > 1 && k == query->errors_count - 1)
1522 status = SILC_STATUS_LIST_END;
1523 if (query->reply_count && k - 1 == query->reply_count)
1524 status = SILC_STATUS_LIST_END;
1526 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1527 (status == SILC_STATUS_OK ? " OK" :
1528 status == SILC_STATUS_LIST_START ? "START" :
1529 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1530 status == SILC_STATUS_LIST_END ? " END" :
1532 silc_get_status_message(query->errors[i].error),
1533 query->errors[i].error));
1536 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1537 (status == SILC_STATUS_OK ?
1538 query->errors[i].error : status),
1539 (status == SILC_STATUS_OK ?
1540 0 : query->errors[i].error), ident, 1,
1542 silc_buffer_free(idp);
1545 if (status == SILC_STATUS_LIST_END)
1552 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1555 silc_server_query_free(query);
1558 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1559 of the client since we were unable to resolve them from the client.
1560 Either client does not support Requested Attributes or isn't replying
1561 to them like it should. */
1563 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1564 SilcServerQuery query,
1565 SilcClientEntry client_entry)
1567 SilcBuffer buffer = NULL;
1568 SilcAttribute attribute;
1569 SilcAttributePayload attr;
1570 SilcAttributeObjPk pk;
1571 SilcAttributeObjService service;
1573 unsigned char sign[2048 + 1];
1574 SilcUInt32 sign_len;
1576 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1578 /* Go through all requested attributes */
1579 silc_dlist_start(query->attrs);
1580 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1581 attribute = silc_attribute_get_attribute(attr);
1582 switch (attribute) {
1584 case SILC_ATTRIBUTE_SERVICE:
1585 /* Put SERVICE. Put only SILC service. */
1586 memset(&service, 0, sizeof(service));
1587 service.port = (server->config->server_info->primary ?
1588 server->config->server_info->primary->port : SILC_PORT);
1589 silc_strncat(service.address, sizeof(service.address),
1590 server->server_name, strlen(server->server_name));
1591 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1592 if (client_entry->connection)
1593 service.idle = time(NULL) - client_entry->data.last_receive;
1594 buffer = silc_attribute_payload_encode(buffer, attribute,
1595 SILC_ATTRIBUTE_FLAG_VALID,
1596 &service, sizeof(service));
1601 case SILC_ATTRIBUTE_STATUS_MOOD:
1602 /* Put STATUS_MOOD */
1603 buffer = silc_attribute_payload_encode(buffer, attribute,
1604 SILC_ATTRIBUTE_FLAG_VALID,
1606 SILC_ATTRIBUTE_MOOD_NORMAL,
1607 sizeof(SilcUInt32));
1612 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1613 /* Put STATUS_FREETEXT. We just tell in the message that we are
1614 replying on behalf of the client. */
1616 "This information was provided by the server on behalf of the user";
1617 buffer = silc_attribute_payload_encode(buffer, attribute,
1618 SILC_ATTRIBUTE_FLAG_VALID,
1624 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1625 /* Put PREFERRED_CONTACT */
1626 buffer = silc_attribute_payload_encode(buffer, attribute,
1627 SILC_ATTRIBUTE_FLAG_VALID,
1629 SILC_ATTRIBUTE_CONTACT_CHAT,
1630 sizeof(SilcUInt32));
1635 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1636 /* Put USER_PUBLIC_KEY */
1637 if (client_entry->data.public_key) {
1638 pk.type = "silc-rsa";
1639 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1641 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1642 SILC_ATTRIBUTE_FLAG_VALID :
1643 SILC_ATTRIBUTE_FLAG_INVALID,
1651 /* No public key available */
1652 buffer = silc_attribute_payload_encode(buffer, attribute,
1653 SILC_ATTRIBUTE_FLAG_INVALID,
1660 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1661 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1662 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1665 /* For other attributes we cannot reply so mark it invalid */
1666 buffer = silc_attribute_payload_encode(buffer, attribute,
1667 SILC_ATTRIBUTE_FLAG_INVALID,
1675 /* Always put our public key. This assures that we send at least
1676 something valid back always. */
1677 pk.type = "silc-rsa";
1678 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1679 buffer = silc_attribute_payload_encode(buffer,
1680 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1681 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1682 SILC_ATTRIBUTE_FLAG_INVALID,
1688 /* Finally compute the digital signature of all the data we provided
1689 as an indication that we provided rightfull information, and this
1690 also authenticates our public key. */
1691 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1692 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1693 buffer->data, buffer->len,
1697 pk.data_len = sign_len;
1699 silc_attribute_payload_encode(buffer,
1700 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1701 SILC_ATTRIBUTE_FLAG_VALID,
1710 /* Find client by the Client ID indicated by the `client_id', and if not
1711 found then query it by using WHOIS command. The client information
1712 is also resolved if the cached information is incomplete or if the
1713 `always_resolve' is set to TRUE. The indication whether requested
1714 client was being resolved is saved into `resolved'. If the client
1715 is not being resolved its entry is returned by this function. NULL
1716 is returned if client is resolved. */
1718 SilcClientEntry silc_server_query_client(SilcServer server,
1719 const SilcClientID *client_id,
1720 bool always_resolve,
1723 SilcClientEntry client;
1725 SILC_LOG_DEBUG(("Resolving client by client ID"));
1730 client = silc_idlist_find_client_by_id(server->local_list,
1731 (SilcClientID *)client_id,
1734 client = silc_idlist_find_client_by_id(server->global_list,
1735 (SilcClientID *)client_id,
1737 if (!client && server->server_type == SILC_ROUTER)
1741 if (!client && server->standalone)
1744 if (!client || !client->nickname || !client->username ||
1746 SilcBuffer buffer, idp;
1749 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1750 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1751 client->resolve_cmd_ident = ++server->cmd_ident;
1754 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1755 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1756 server->cmd_ident, 1,
1757 4, idp->data, idp->len);
1758 silc_server_packet_send(server, client ? client->router->connection :
1759 SILC_PRIMARY_ROUTE(server),
1760 SILC_PACKET_COMMAND, 0,
1761 buffer->data, buffer->len, FALSE);
1762 silc_buffer_free(idp);
1763 silc_buffer_free(buffer);