5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 1 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname, normalized */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name, normalized */
57 char *channel_name; /* Queried channel name, normalized */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `type'. If `type' is 0 the index is to query->ids, if
177 it is 1 it is index to the command context arguments, and if it is
178 2 the index is ignored and no argument is included in the error. */
180 void silc_server_query_add_error(SilcServer server,
181 SilcServerQuery query,
186 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187 (query->errors_count + 1));
190 query->errors[query->errors_count].index = index;
191 query->errors[query->errors_count].type = type;
192 query->errors[query->errors_count].error = error;
193 query->errors[query->errors_count].id = NULL;
194 query->errors[query->errors_count].id_type = 0;
195 query->errors_count++;
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199 with error sending with this error type. */
201 void silc_server_query_add_error_id(SilcServer server,
202 SilcServerQuery query,
204 void *id, SilcIdType id_type)
206 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207 (query->errors_count + 1));
210 query->errors[query->errors_count].index = 0;
211 query->errors[query->errors_count].type = 0;
212 query->errors[query->errors_count].error = error;
213 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214 query->errors[query->errors_count].id_type = id_type;
215 query->errors_count++;
218 /* Processes query as command. The `query' is the command that is
219 being processed indicated by the `cmd'. The `query' can be one of
220 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221 SILC_COMMAND_IDENTIFY. This function handles the reply sending
222 to the entity who sent this query to us automatically. Returns
223 TRUE if the query is being processed or FALSE on error. */
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226 SilcServerCommandContext cmd)
228 SilcServerQuery query;
230 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
232 query = silc_calloc(1, sizeof(*query));
233 query->querycmd = querycmd;
234 query->cmd = silc_server_command_dup(cmd);
238 case SILC_COMMAND_WHOIS:
239 /* If we are normal server and query contains nickname OR query
240 doesn't contain nickname or ids BUT attributes, send it to the
242 if (server->server_type != SILC_ROUTER && !server->standalone &&
243 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248 silc_server_query_send_router(server, query);
253 case SILC_COMMAND_WHOWAS:
254 /* WHOWAS query is always sent to router if we are normal server */
255 if (server->server_type == SILC_SERVER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_IDENTIFY:
263 /* If we are normal server and query does not contain IDs, send it
264 directly to router (it contains nickname, server name or channel
266 if (server->server_type == SILC_SERVER && !server->standalone &&
267 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269 silc_server_query_send_router(server, query);
275 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276 silc_server_query_free(query);
280 /* Now parse the request */
281 silc_server_query_parse(server, query);
286 /* Send the received query to our primary router since we could not
287 handle the query directly. We will reprocess the query after our
288 router replies back. */
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
293 SilcUInt16 old_ident;
295 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
298 server->stat.commands_sent++;
300 /* Send WHOIS command to our router */
301 old_ident = silc_command_get_ident(query->cmd->payload);
302 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
303 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
304 silc_server_packet_send(server,
305 SILC_PRIMARY_ROUTE(server),
306 SILC_PACKET_COMMAND, 0,
307 tmpbuf->data, tmpbuf->len, TRUE);
308 silc_command_set_ident(query->cmd->payload, old_ident);
309 silc_buffer_free(tmpbuf);
311 query->resolved = TRUE;
313 /* Continue parsing the query after received reply from router */
314 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
315 silc_server_query_send_router_reply, query);
318 /* Reply callback called after primary router has replied to our initial
319 sending of the query to it. We will proceed the query in this function. */
321 void silc_server_query_send_router_reply(void *context, void *reply)
323 SilcServerQuery query = context;
324 SilcServer server = query->cmd->server;
325 SilcServerCommandReplyContext cmdr = reply;
327 SILC_LOG_DEBUG(("Received reply from router to query"));
329 /* If the original command caller has gone away, just stop. */
330 if (query->cmd->sock->users == 1) {
331 SILC_LOG_DEBUG(("Original command caller vanished"));
332 silc_server_query_free(query);
336 /* Check if router sent error reply */
337 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
340 SILC_LOG_DEBUG(("Sending error to original query"));
343 server->stat.commands_sent++;
345 /* Send the same command reply payload which contains the error */
346 silc_command_set_command(cmdr->payload, query->querycmd);
347 silc_command_set_ident(cmdr->payload,
348 silc_command_get_ident(query->cmd->payload));
349 buffer = silc_command_payload_encode_payload(cmdr->payload);
350 silc_server_packet_send(server, query->cmd->sock,
351 SILC_PACKET_COMMAND_REPLY, 0,
352 buffer->data, buffer->len, FALSE);
353 silc_buffer_free(buffer);
354 silc_server_query_free(query);
358 /* Continue with parsing */
359 silc_server_query_parse(server, query);
362 /* Parse the command query and start processing the queries in detail. */
364 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
366 SilcServerCommandContext cmd = query->cmd;
368 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
373 SILC_LOG_DEBUG(("Parsing %s query",
374 silc_get_command_name(query->querycmd)));
376 switch (query->querycmd) {
378 case SILC_COMMAND_WHOIS:
379 /* Get requested attributes if set */
380 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
381 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
382 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
384 /* When Requested Attributes is present we will assure that this
385 client cannot execute the WHOIS command too fast. This would be
386 same as having SILC_CF_LAG_STRICT. */
387 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
388 cmd->sock->user_data)
389 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
392 /* Get Client IDs if present. Take IDs always instead of nickname. */
393 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
397 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
398 if (!tmp && !query->attrs) {
399 /* No nickname, no ids and no attributes - send error */
400 silc_server_query_send_error(server, query,
401 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
402 silc_server_query_free(query);
406 /* Get the nickname@server string and parse it */
407 if (tmp && ((tmp_len > 128) ||
408 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
409 silc_server_query_send_error(server, query,
410 SILC_STATUS_ERR_BAD_NICKNAME, 0);
411 silc_server_query_free(query);
416 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
417 SILC_STRING_UTF8, 128, &tmp_len);
419 silc_server_query_send_error(server, query,
420 SILC_STATUS_ERR_BAD_NICKNAME, 0);
421 silc_server_query_free(query);
424 silc_free(query->nickname);
425 query->nickname = tmp;
428 /* Parse the IDs included in the query */
429 query->ids = silc_calloc(argc, sizeof(*query->ids));
431 for (i = 0; i < argc; i++) {
432 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
436 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
437 if (!id || id_type != SILC_ID_CLIENT) {
438 silc_server_query_add_error(server, query, 1, i + 4,
439 SILC_STATUS_ERR_BAD_CLIENT_ID);
443 /* Normal server must check whether this ID exist, and if not then
444 send the query to router, unless done so already */
445 if (server->server_type == SILC_SERVER && !query->resolved) {
446 if (!silc_idlist_find_client_by_id(server->local_list,
448 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
449 !silc_idlist_find_client_by_id(server->global_list,
451 silc_server_query_send_router(server, query);
452 for (i = 0; i < query->ids_count; i++)
453 silc_free(query->ids[i].id);
454 silc_free(query->ids);
456 query->ids_count = 0;
463 query->ids[query->ids_count].id = id;
464 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
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_WHOWAS:
477 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
479 silc_server_query_send_error(server, query,
480 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
481 silc_server_query_free(query);
485 /* Get the nickname@server string and parse it */
487 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
488 silc_server_query_send_error(server, query,
489 SILC_STATUS_ERR_BAD_NICKNAME, 0);
490 silc_server_query_free(query);
495 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
496 SILC_STRING_UTF8, 128, &tmp_len);
498 silc_server_query_send_error(server, query,
499 SILC_STATUS_ERR_BAD_NICKNAME, 0);
500 silc_server_query_free(query);
503 silc_free(query->nickname);
504 query->nickname = tmp;
506 /* Get the max count of reply messages allowed */
507 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
508 if (tmp && tmp_len == sizeof(SilcUInt32))
509 SILC_GET32_MSB(query->reply_count, tmp);
512 case SILC_COMMAND_IDENTIFY:
513 /* Get IDs if present. Take IDs always instead of names. */
514 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
517 /* Try get nickname */
518 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
520 /* Get the nickname@server string and parse it */
522 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
523 silc_server_query_add_error(server, query, 1, 1,
524 SILC_STATUS_ERR_BAD_NICKNAME);
527 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
528 SILC_STRING_UTF8, 128, &tmp_len);
530 silc_server_query_send_error(server, query,
531 SILC_STATUS_ERR_BAD_NICKNAME, 0);
532 silc_server_query_free(query);
535 silc_free(query->nickname);
536 query->nickname = tmp;
539 /* Try get server name */
540 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
542 /* Check server name */
543 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
546 silc_server_query_send_error(server, query,
547 SILC_STATUS_ERR_BAD_SERVER, 0);
548 silc_server_query_free(query);
551 query->server_name = tmp;
554 /* Get channel name */
555 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
556 if (tmp && tmp_len <= 256) {
557 /* Check channel name */
558 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
561 silc_server_query_send_error(server, query,
562 SILC_STATUS_ERR_BAD_CHANNEL, 0);
563 silc_server_query_free(query);
566 query->channel_name = tmp;
569 if (!query->nickname && !query->server_name && !query->channel_name) {
570 silc_server_query_send_error(server, query,
571 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
572 silc_server_query_free(query);
577 /* Parse the IDs included in the query */
578 query->ids = silc_calloc(argc, sizeof(*query->ids));
580 for (i = 0; i < argc; i++) {
581 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
585 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
587 silc_server_query_add_error(server, query, 1, i + 5,
588 SILC_STATUS_ERR_BAD_CLIENT_ID);
592 /* Normal server must check whether this ID exist, and if not then
593 send the query to router, unless done so already */
594 if (server->server_type == SILC_SERVER && !query->resolved) {
595 if (id_type == SILC_ID_CLIENT) {
596 if (!silc_idlist_find_client_by_id(server->local_list,
598 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
599 !silc_idlist_find_client_by_id(server->global_list,
601 silc_server_query_send_router(server, query);
602 for (i = 0; i < query->ids_count; i++)
603 silc_free(query->ids[i].id);
604 silc_free(query->ids);
606 query->ids_count = 0;
612 /* For now all other ID's except Client ID's are explicitly
613 sent to router for resolving. */
614 silc_server_query_send_router(server, query);
615 for (i = 0; i < query->ids_count; i++)
616 silc_free(query->ids[i].id);
617 silc_free(query->ids);
619 query->ids_count = 0;
625 query->ids[query->ids_count].id = id;
626 query->ids[query->ids_count].id_type = id_type;
631 /* Get the max count of reply messages allowed */
632 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
633 if (tmp && tmp_len == sizeof(SilcUInt32))
634 SILC_GET32_MSB(query->reply_count, tmp);
638 /* Start processing the query information */
639 silc_server_query_process(server, query, TRUE);
642 /* Context for holding clients searched by public key. */
644 SilcClientEntry **clients;
645 SilcUInt32 *clients_count;
647 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
649 void silc_server_public_key_hash_foreach(void *key, void *context,
652 SilcServerPublicKeyUser uc = user_context;
653 SilcClientEntry entry = context;
655 /* Nothing was found, just return */
661 (*uc->clients) = silc_realloc((*uc->clients),
662 sizeof((**uc->clients)) *
663 ((*uc->clients_count) + 1));
664 (*uc->clients)[(*uc->clients_count)++] = entry;
667 /* If clients are set, limit the found clients using the attributes in
668 the query. If clients are not set, try to find some clients using
671 void silc_server_query_check_attributes(SilcServer server,
672 SilcServerQuery query,
673 SilcClientEntry **clients,
674 SilcUInt32 *clients_count) {
675 SilcClientEntry entry;
676 SilcAttributePayload attr;
677 SilcAttribute attribute;
678 SilcAttributeObjPk pk;
679 SilcPublicKey publickey;
681 bool found = FALSE, no_clients = FALSE;
683 /* If no clients were found, we only check the attributes
684 if the user wasn't searching for nickname/ids */
687 if (query->nickname || query->ids_count)
691 silc_dlist_start(query->attrs);
692 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
693 attribute = silc_attribute_get_attribute(attr);
696 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
697 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
699 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
702 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
709 /* If no clients were set on calling this function, we
710 just search for clients, otherwise we try to limit
713 SilcServerPublicKeyUserStruct usercontext;
715 usercontext.clients = clients;
716 usercontext.clients_count = clients_count;
717 usercontext.found = FALSE;
719 silc_hash_table_find_foreach(server->pk_hash, publickey,
720 silc_server_public_key_hash_foreach,
723 if (usercontext.found == TRUE)
726 for (i = 0; i < *clients_count; i++) {
727 entry = (*clients)[i];
729 if (!entry->data.public_key)
732 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
734 (*clients)[i] = NULL;
741 silc_pkcs_public_key_free(publickey);
746 if (!found && !query->nickname && !query->ids)
747 silc_server_query_add_error(server, query, 2, 0,
748 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
751 /* Processes the parsed query. This does the actual finding of the
752 queried information and prepares for sending reply to the original
753 sender of the query command. */
755 void silc_server_query_process(SilcServer server, SilcServerQuery query,
758 SilcServerCommandContext cmd = query->cmd;
759 bool check_global = FALSE;
761 SilcClientEntry *clients = NULL, client_entry;
762 SilcChannelEntry *channels = NULL;
763 SilcServerEntry *servers = NULL;
764 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
767 SILC_LOG_DEBUG(("Processing %s query",
768 silc_get_command_name(query->querycmd)));
770 /* Check global lists if query is coming from client or we are not
771 normal server (we know global information). */
772 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
774 else if (server->server_type != SILC_SERVER)
777 if (query->nickname) {
778 /* Get all clients matching nickname from local list */
779 if (!silc_idlist_get_clients_by_hash(server->local_list,
780 query->nickname, server->md5hash,
781 &clients, &clients_count))
782 silc_idlist_get_clients_by_nickname(server->local_list,
785 &clients, &clients_count);
787 /* Check global list as well */
789 if (!silc_idlist_get_clients_by_hash(server->global_list,
790 query->nickname, server->md5hash,
791 &clients, &clients_count))
792 silc_idlist_get_clients_by_nickname(server->global_list,
795 &clients, &clients_count);
799 silc_server_query_add_error(server, query, 1, 1,
800 SILC_STATUS_ERR_NO_SUCH_NICK);
803 if (query->server_name) {
804 /* Find server by name */
805 entry = silc_idlist_find_server_by_name(server->local_list,
806 query->server_name, TRUE, NULL);
807 if (!entry && check_global)
808 entry = silc_idlist_find_server_by_name(server->global_list,
809 query->server_name, TRUE, NULL);
811 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
812 servers[servers_count++] = (SilcServerEntry)entry;
816 silc_server_query_add_error(server, query, 1, 2,
817 SILC_STATUS_ERR_NO_SUCH_SERVER);
820 if (query->channel_name) {
821 /* Find channel by name */
822 entry = silc_idlist_find_channel_by_name(server->local_list,
823 query->channel_name, NULL);
824 if (!entry && check_global)
825 entry = silc_idlist_find_channel_by_name(server->global_list,
826 query->channel_name, NULL);
828 channels = silc_realloc(channels, sizeof(*channels) *
829 (channels_count + 1));
830 channels[channels_count++] = (SilcChannelEntry)entry;
834 silc_server_query_add_error(server, query, 1, 3,
835 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
838 if (query->ids_count) {
839 /* Find entries by the queried IDs */
840 for (i = 0; i < query->ids_count; i++) {
841 void *id = query->ids[i].id;
845 switch (query->ids[i].id_type) {
848 /* Get client entry */
849 entry = silc_idlist_find_client_by_id(server->local_list,
851 if (!entry && check_global)
852 entry = silc_idlist_find_client_by_id(server->global_list,
855 silc_server_query_add_error(server, query, 0, i,
856 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
860 clients = silc_realloc(clients, sizeof(*clients) *
861 (clients_count + 1));
862 clients[clients_count++] = (SilcClientEntry)entry;
866 /* Get server entry */
867 entry = silc_idlist_find_server_by_id(server->local_list,
869 if (!entry && check_global)
870 entry = silc_idlist_find_server_by_id(server->global_list,
873 silc_server_query_add_error(server, query, 0, i,
874 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
878 servers = silc_realloc(servers, sizeof(*servers) *
879 (servers_count + 1));
880 servers[servers_count++] = (SilcServerEntry)entry;
883 case SILC_ID_CHANNEL:
884 /* Get channel entry */
885 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
886 if (!entry && check_global)
887 entry = silc_idlist_find_channel_by_id(server->global_list, id,
890 silc_server_query_add_error(server, query, 0, i,
891 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
895 channels = silc_realloc(channels, sizeof(*channels) *
896 (channels_count + 1));
897 channels[channels_count++] = (SilcChannelEntry)entry;
906 /* Check the attributes to narrow down the search by using them. */
908 silc_server_query_check_attributes(server, query, &clients,
911 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
912 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
913 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
915 /* If nothing was found, then just send the errors */
916 if (!clients && !channels && !servers) {
917 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
921 /* If caller does not want us to resolve anything (has resolved already)
922 then just continue with sending the reply */
924 silc_server_query_send_reply(server, query, clients, clients_count,
925 servers, servers_count, channels,
933 /* Now process all found information and if necessary do some more
935 switch (query->querycmd) {
937 case SILC_COMMAND_WHOIS:
938 for (i = 0; i < clients_count; i++) {
939 client_entry = clients[i];
941 /* Check if cannot query this anyway, so take next one */
943 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
946 /* If Requested Attributes is set then we always resolve the client
947 information, if not then check whether the entry is complete or not
948 and decide whether we need to resolve or not. */
951 /* Even if nickname and stuff are present, we may need to resolve
953 if (client_entry->nickname && client_entry->username &&
954 client_entry->userinfo) {
955 /* Check if cannot query this anyway, so take next one */
956 if (!client_entry->router)
959 /* If we are router, client is local to us, or client is on channel
960 we do not need to resolve the client information. */
961 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
962 || silc_hash_table_count(client_entry->channels) ||
968 /* Remove the NOATTR status periodically */
969 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
970 client_entry->updated + 600 < time(NULL))
971 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
973 /* When requested attributes is present and local client is detached
974 we cannot send the command to the client, we'll reply on behalf of
975 the client instead. */
976 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
977 (client_entry->mode & SILC_UMODE_DETACHED ||
978 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
981 /* If attributes are present in query, and in the entry and we have
982 done resolvings already we don't need to resolve anymore */
983 if (query->resolved && query->attrs && client_entry->attrs)
986 /* Resolve the detailed client information. If client is local we
987 know that attributes were present and we will resolve directly
988 from the client. Otherwise resolve from client's owner. */
989 silc_server_query_resolve(server, query,
990 (SILC_IS_LOCAL(client_entry) ?
991 client_entry->connection :
992 client_entry->router->connection),
997 case SILC_COMMAND_WHOWAS:
998 for (i = 0; i < clients_count; i++) {
999 client_entry = clients[i];
1001 /* Check if cannot query this anyway, so take next one */
1002 if (!client_entry || !client_entry->router ||
1003 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1006 /* If both nickname and username are present no resolving is needed */
1007 if (client_entry->nickname && client_entry->username)
1010 /* Resolve the detailed client information */
1011 silc_server_query_resolve(server, query,
1012 client_entry->router->connection,
1017 case SILC_COMMAND_IDENTIFY:
1018 for (i = 0; i < clients_count; i++) {
1019 client_entry = clients[i];
1021 /* Check if cannot query this anyway, so take next one */
1022 if (!client_entry || !client_entry->router ||
1023 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1026 /* Even if nickname is present, we may need to resolve the entry */
1027 if (client_entry->nickname) {
1029 /* If we are router, client is local to us, or client is on channel
1030 we do not need to resolve the client information. */
1031 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1032 || silc_hash_table_count(client_entry->channels) ||
1037 /* Resolve the detailed client information */
1038 silc_server_query_resolve(server, query,
1039 client_entry->router->connection,
1045 if (!query->queries_count)
1046 /* If we didn't have to do any resolving, continue with sending the
1047 command reply to the original sender. */
1048 silc_server_query_send_reply(server, query, clients, clients_count,
1049 servers, servers_count, channels,
1052 /* Now actually send the resolvings we gathered earlier */
1053 silc_server_query_resolve(server, query, NULL, NULL);
1057 silc_free(channels);
1060 /* Resolve the detailed information for the `client_entry'. Only client
1061 information needs to be resolved for being incomplete. Each incomplete
1062 client entry calls this function to do the resolving. */
1064 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1065 SilcSocketConnection sock,
1066 SilcClientEntry client_entry)
1068 SilcServerCommandContext cmd = query->cmd;
1069 SilcServerQueryList r = NULL;
1076 if (!sock && client_entry)
1079 /* If arguments are NULL we will now actually send the resolvings
1080 that earlier has been gathered by calling this function. */
1081 if (!sock && !client_entry) {
1084 SILC_LOG_DEBUG(("Sending the resolvings"));
1086 /* WHOWAS resolving has been done at the same time this function
1087 was called to add the resolving for WHOWAS, so just return. */
1088 if (query->querycmd == SILC_COMMAND_WHOWAS)
1091 for (i = 0; i < query->querylist_count; i++) {
1092 r = &query->querylist[i];
1094 /* If Requested Attributes were present put them to this resolving */
1095 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1097 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1098 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1099 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1101 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1103 r->arg[r->argc] = silc_memdup(tmp, len);
1104 r->arg_lens[r->argc] = len;
1105 r->arg_types[r->argc] = 3;
1110 server->stat.commands_sent++;
1112 /* Send WHOIS command */
1113 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1114 r->argc, r->arg, r->arg_lens,
1115 r->arg_types, r->ident);
1116 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1117 res_cmd->data, res_cmd->len, FALSE);
1118 silc_buffer_free(res_cmd);
1120 /* Reprocess this packet after received reply */
1121 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1123 silc_server_query_resolve_reply,
1125 query->queries_left++;
1128 /* Cleanup this temporary context */
1129 for (i = 0; i < query->querylist_count; i++) {
1131 for (k = 0; k < query->querylist[i].argc; k++)
1132 silc_free(query->querylist[i].arg[k]);
1133 silc_free(query->querylist[i].arg);
1134 silc_free(query->querylist[i].arg_lens);
1135 silc_free(query->querylist[i].arg_types);
1137 silc_free(query->querylist);
1138 query->querylist = NULL;
1139 query->querylist_count = 0;
1143 SILC_LOG_DEBUG(("Resolving client information"));
1145 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1146 /* The entry is being resolved by some other external query already.
1147 Attach to that query instead of resolving again. */
1148 ident = client_entry->resolve_cmd_ident;
1149 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1150 silc_server_query_resolve_reply, query))
1151 query->queries_left++;
1153 /* This entry will be resolved */
1154 ident = ++server->cmd_ident;
1156 switch (query->querycmd) {
1158 case SILC_COMMAND_WHOIS:
1159 case SILC_COMMAND_IDENTIFY:
1160 /* Take existing query context if exist for this connection */
1161 for (i = 0; i < query->querylist_count; i++)
1162 if (query->querylist[i].sock == sock) {
1163 r = &query->querylist[i];
1168 /* Allocate new temp query list context */
1169 query->querylist = silc_realloc(query->querylist,
1170 sizeof(*query->querylist) *
1171 (query->querylist_count + 1));
1172 r = &query->querylist[query->querylist_count];
1173 query->querylist_count++;
1174 memset(r, 0, sizeof(*r));
1177 if (SILC_IS_LOCAL(client_entry))
1182 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1183 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1184 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1186 /* Add the client entry to be resolved */
1187 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1188 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1189 r->arg_lens[r->argc] = idp->len;
1190 r->arg_types[r->argc] = r->argc + 4;
1192 silc_buffer_free(idp);
1196 case SILC_COMMAND_WHOWAS:
1197 /* We must send WHOWAS command since it's the only the way of
1198 resolving clients that are not present in the network anymore. */
1199 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1200 1, query->nickname, strlen(query->nickname));
1201 if (silc_server_command_pending(server, query->querycmd, ident,
1202 silc_server_query_resolve_reply, query))
1203 query->queries_left++;
1208 /* Mark the entry as being resolved */
1209 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1210 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1211 client_entry->resolve_cmd_ident = ident;
1212 client_entry->updated = time(NULL);
1214 /* Save the queried ID, which we will reprocess after we get this and
1215 all other queries back. */
1216 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1217 (query->queries_count + 1));
1218 if (query->queries) {
1219 i = query->queries_count;
1220 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1221 query->queries[i].id_type = SILC_ID_CLIENT;
1222 query->queries[i].ident = ident;
1223 query->queries_count++;
1227 /* Reply callback called after one resolving has been completed. If
1228 all resolvings has been received then we will continue with sending
1229 the command reply to the original sender of the query. */
1231 void silc_server_query_resolve_reply(void *context, void *reply)
1233 SilcServerQuery query = context;
1234 SilcServer server = query->cmd->server;
1235 SilcServerCommandReplyContext cmdr = reply;
1236 SilcUInt16 ident = cmdr->ident;
1237 SilcStatus error = SILC_STATUS_OK;
1238 SilcServerQueryID id = NULL;
1239 SilcClientEntry client_entry;
1242 /* One less query left */
1243 query->queries_left--;
1245 silc_command_get_status(cmdr->payload, NULL, &error);
1246 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1247 query->queries_left, error));
1249 /* If no error then skip to other stuff */
1250 if (error == SILC_STATUS_OK)
1253 /* Error occurred during resolving */
1255 /* Find the resolved client ID */
1256 for (i = 0; i < query->queries_count; i++) {
1257 if (query->queries[i].ident != ident)
1260 id = &query->queries[i];
1262 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1264 /* If timeout occurred for local entry when resolving attributes
1265 mark that this client doesn't support attributes in WHOIS. This
1266 assures we won't send the request again to the client. */
1267 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1268 client_entry = silc_idlist_find_client_by_id(server->local_list,
1269 id->id, TRUE, NULL);
1270 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1271 silc_id_render(id->id, SILC_ID_CLIENT)));
1272 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1273 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1274 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1279 /* Remove the RESOLVING status from the client entry */
1280 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1281 client_entry = silc_idlist_find_client_by_id(server->local_list,
1282 id->id, TRUE, NULL);
1284 client_entry = silc_idlist_find_client_by_id(server->global_list,
1285 id->id, TRUE, NULL);
1287 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1294 /* If there are queries left then wait for them */
1295 if (query->queries_left)
1298 SILC_LOG_DEBUG(("Reprocess the query"));
1300 /* If the original command caller has gone away, just stop. */
1301 if (query->cmd->sock->users == 1) {
1302 SILC_LOG_DEBUG(("Original command caller vanished"));
1303 silc_server_query_free(query);
1307 /* We have received all queries. Now re-search all information required
1308 to complete this query. Reason we cannot save the values found in
1309 the first search is that SilcClientEntry, SilcServerEntry and
1310 SilcChannelEntry pointers may become invalid while we were waiting
1311 for these resolvings. */
1312 silc_server_query_process(server, query, FALSE);
1315 /* Send the reply to the original query. If arguments are NULL then this
1316 sends only the errors that has occurred during the processing of the
1317 query. This sends the errors always after sending all the found
1318 information. The query is over after this function returns and the
1319 `query' will become invalid. This is called only after all informations
1320 has been resolved. This means that if something is not found or is
1321 incomplete in this function we were unable to resolve the information
1322 or it does not exist at all. */
1324 void silc_server_query_send_reply(SilcServer server,
1325 SilcServerQuery query,
1326 SilcClientEntry *clients,
1327 SilcUInt32 clients_count,
1328 SilcServerEntry *servers,
1329 SilcUInt32 servers_count,
1330 SilcChannelEntry *channels,
1331 SilcUInt32 channels_count)
1333 SilcServerCommandContext cmd = query->cmd;
1334 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1339 int i, k, valid_count;
1340 char nh[384], uh[384];
1341 bool sent_reply = FALSE;
1343 SILC_LOG_DEBUG(("Sending reply to query"));
1344 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1345 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1346 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1347 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1349 status = SILC_STATUS_OK;
1352 if (clients_count) {
1353 SilcClientEntry entry;
1354 SilcSocketConnection hsock;
1356 /* Mark all invalid entries */
1357 for (i = 0, valid_count = 0; i < clients_count; i++) {
1362 switch (query->querycmd) {
1363 case SILC_COMMAND_WHOIS:
1364 if (!entry->nickname || !entry->username || !entry->userinfo ||
1365 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1366 /* When querying by ID, every "unfound" entry must cause error */
1368 silc_server_query_add_error_id(server, query,
1369 SILC_STATUS_ERR_TIMEDOUT,
1370 entry->id, SILC_ID_CLIENT);
1376 case SILC_COMMAND_IDENTIFY:
1377 if (!entry->nickname ||
1378 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1379 /* When querying by ID, every "unfound" entry must cause error */
1381 silc_server_query_add_error_id(server, query,
1382 SILC_STATUS_ERR_TIMEDOUT,
1383 entry->id, SILC_ID_CLIENT);
1389 case SILC_COMMAND_WHOWAS:
1390 if (!entry->nickname || !entry->username ||
1391 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1400 /* Start processing found clients */
1401 status = SILC_STATUS_OK;
1402 if (valid_count > 1)
1403 status = SILC_STATUS_LIST_START;
1405 /* Now do the sending of valid entries */
1407 for (i = 0; i < clients_count && valid_count; i++) {
1413 status = SILC_STATUS_LIST_ITEM;
1414 if (valid_count > 1 && k == valid_count - 1
1415 && !servers_count && !channels_count && !query->errors_count)
1416 status = SILC_STATUS_LIST_END;
1417 if (query->reply_count && k - 1 == query->reply_count)
1418 status = SILC_STATUS_LIST_END;
1420 SILC_LOG_DEBUG(("%s: client %s",
1421 (status == SILC_STATUS_OK ? " OK" :
1422 status == SILC_STATUS_LIST_START ? "START" :
1423 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1424 status == SILC_STATUS_LIST_END ? " END" :
1425 " : "), entry->nickname));
1427 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1428 memset(nh, 0, sizeof(nh));
1430 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1431 if (!strchr(entry->nickname, '@')) {
1432 silc_strncat(nh, sizeof(nh), "@", 1);
1433 if (entry->servername) {
1434 silc_strncat(nh, sizeof(nh), entry->servername,
1435 strlen(entry->servername));
1437 len = entry->router ? strlen(entry->router->server_name) :
1438 strlen(server->server_name);
1439 silc_strncat(nh, sizeof(nh), entry->router ?
1440 entry->router->server_name :
1441 server->server_name, len);
1445 switch (query->querycmd) {
1447 case SILC_COMMAND_WHOIS:
1449 unsigned char idle[4], mode[4];
1450 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1451 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1453 memset(fempty, 0, sizeof(fempty));
1454 memset(idle, 0, sizeof(idle));
1455 memset(uh, 0, sizeof(uh));
1457 silc_strncat(uh, sizeof(uh), entry->username,
1458 strlen(entry->username));
1459 if (!strchr(entry->username, '@') && entry->connection) {
1460 hsock = entry->connection;
1461 silc_strncat(uh, sizeof(uh), "@", 1);
1462 len = strlen(hsock->hostname);
1463 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1466 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1468 silc_server_get_client_channel_list(server, entry, FALSE,
1469 FALSE, &umode_list);
1472 silc_server_get_client_channel_list(server, entry, TRUE,
1475 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1476 fingerprint = entry->data.fingerprint;
1480 SILC_PUT32_MSB(entry->mode, mode);
1481 if (entry->connection)
1482 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1484 /* If Requested Attribute were present, and we do not have the
1485 attributes we will reply to them on behalf of the client. */
1488 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1489 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1490 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1491 entry->attrs_len = len;
1492 silc_buffer_free(tmpattrs);
1494 attrs = entry->attrs;
1495 len = entry->attrs_len;
1498 /* Send command reply */
1499 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1500 status, 0, ident, 10,
1501 2, idp->data, idp->len,
1505 strlen(entry->userinfo),
1506 6, channels ? channels->data : NULL,
1507 channels ? channels->len : 0,
1511 fingerprint ? 20 : 0,
1512 10, umode_list ? umode_list->data :
1513 NULL, umode_list ? umode_list->len :
1518 /* For now we always delete Requested Attributes, unless the client
1519 is detached, in which case we don't want to reconstruct the
1520 same data everytime */
1521 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1522 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1523 silc_free(entry->attrs);
1524 entry->attrs = NULL;
1528 silc_buffer_free(channels);
1530 silc_buffer_free(umode_list);
1536 case SILC_COMMAND_IDENTIFY:
1537 if (!entry->username) {
1538 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1539 status, 0, ident, 2,
1540 2, idp->data, idp->len,
1544 silc_strncat(uh, sizeof(uh), entry->username,
1545 strlen(entry->username));
1546 if (!strchr(entry->username, '@') && entry->connection) {
1547 hsock = entry->connection;
1548 silc_strncat(uh, sizeof(uh), "@", 1);
1549 len = strlen(hsock->hostname);
1550 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1553 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1554 status, 0, ident, 3,
1555 2, idp->data, idp->len,
1562 case SILC_COMMAND_WHOWAS:
1563 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1564 if (!strchr(entry->username, '@'))
1565 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1567 /* Send command reply */
1568 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1569 status, 0, ident, 4,
1570 2, idp->data, idp->len,
1575 strlen(entry->userinfo) : 0);
1580 silc_buffer_free(idp);
1582 if (status == SILC_STATUS_LIST_END)
1588 /* Not one valid entry was found, send error. If nickname was used
1589 in query send error based on that, otherwise the query->errors
1590 already includes proper errors. */
1591 if (query->nickname || (!query->ids && query->attrs))
1592 silc_server_query_add_error(server, query, 1, 1,
1593 SILC_STATUS_ERR_NO_SUCH_NICK);
1595 /* Make sure some error is sent */
1596 if (!query->errors_count && !servers_count && !channels_count)
1597 silc_server_query_add_error(server, query, 2, 0,
1598 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1603 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1604 SilcServerEntry entry;
1606 if (status == SILC_STATUS_OK && servers_count > 1)
1607 status = SILC_STATUS_LIST_START;
1610 for (i = 0; i < servers_count; i++) {
1614 status = SILC_STATUS_LIST_ITEM;
1615 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1616 !query->errors_count)
1617 status = SILC_STATUS_LIST_END;
1618 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1619 !query->errors_count)
1620 status = SILC_STATUS_LIST_END;
1621 if (query->reply_count && k - 1 == query->reply_count)
1622 status = SILC_STATUS_LIST_END;
1624 SILC_LOG_DEBUG(("%s: server %s",
1625 (status == SILC_STATUS_OK ? " OK" :
1626 status == SILC_STATUS_LIST_START ? "START" :
1627 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1628 status == SILC_STATUS_LIST_END ? " END" :
1630 entry->server_name ? entry->server_name : ""));
1632 /* Send command reply */
1633 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1634 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1635 status, 0, ident, 2,
1636 2, idp->data, idp->len,
1637 3, entry->server_name,
1638 entry->server_name ?
1639 strlen(entry->server_name) : 0);
1640 silc_buffer_free(idp);
1643 if (status == SILC_STATUS_LIST_END)
1650 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1651 SilcChannelEntry entry;
1653 if (status == SILC_STATUS_OK && channels_count > 1)
1654 status = SILC_STATUS_LIST_START;
1657 for (i = 0; i < channels_count; i++) {
1658 entry = channels[i];
1661 status = SILC_STATUS_LIST_ITEM;
1662 if (channels_count == 1 && status != SILC_STATUS_OK &&
1663 !query->errors_count)
1664 status = SILC_STATUS_LIST_END;
1665 if (channels_count > 1 && k == channels_count - 1 &&
1666 !query->errors_count)
1667 status = SILC_STATUS_LIST_END;
1668 if (query->reply_count && k - 1 == query->reply_count)
1669 status = SILC_STATUS_LIST_END;
1671 SILC_LOG_DEBUG(("%s: channel %s",
1672 (status == SILC_STATUS_OK ? " OK" :
1673 status == SILC_STATUS_LIST_START ? "START" :
1674 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1675 status == SILC_STATUS_LIST_END ? " END" :
1677 entry->channel_name ? entry->channel_name : ""));
1679 /* Send command reply */
1680 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1681 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1682 status, 0, ident, 2,
1683 2, idp->data, idp->len,
1684 3, entry->channel_name,
1685 entry->channel_name ?
1686 strlen(entry->channel_name) : 0);
1687 silc_buffer_free(idp);
1690 if (status == SILC_STATUS_LIST_END)
1697 if (query->errors_count) {
1700 if (status == SILC_STATUS_OK && query->errors_count > 1)
1701 status = SILC_STATUS_LIST_START;
1704 for (i = 0; i < query->errors_count; i++) {
1707 /* Take error argument */
1708 if (query->errors[i].type == 1) {
1709 /* Take from sent arguments */
1711 tmp = silc_argument_get_arg_type(cmd->args,
1712 query->errors[i].index, &len);
1714 } else if (query->errors[i].type == 2) {
1719 } else if (!query->errors[i].id) {
1720 /* Take from query->ids */
1722 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1723 query->ids[query->errors[k].index].id_type);
1728 /* Take added ID. */
1729 idp = silc_id_payload_encode(query->errors[i].id,
1730 query->errors[k].id_type);
1737 status = SILC_STATUS_LIST_ITEM;
1738 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1739 status = SILC_STATUS_LIST_END;
1740 if (query->errors_count > 1 && k == query->errors_count - 1)
1741 status = SILC_STATUS_LIST_END;
1742 if (query->reply_count && k - 1 == query->reply_count)
1743 status = SILC_STATUS_LIST_END;
1745 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1746 (status == SILC_STATUS_OK ? " OK" :
1747 status == SILC_STATUS_LIST_START ? "START" :
1748 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1749 status == SILC_STATUS_LIST_END ? " END" :
1751 silc_get_status_message(query->errors[i].error),
1752 query->errors[i].error));
1754 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1755 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1757 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1758 (status == SILC_STATUS_OK ?
1759 query->errors[i].error : status),
1760 (status == SILC_STATUS_OK ?
1761 0 : query->errors[i].error), ident, 2,
1767 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1768 (status == SILC_STATUS_OK ?
1769 query->errors[i].error : status),
1770 (status == SILC_STATUS_OK ?
1771 0 : query->errors[i].error), ident, 1,
1774 silc_buffer_free(idp);
1777 if (status == SILC_STATUS_LIST_END)
1784 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1787 silc_server_query_free(query);
1790 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1791 of the client since we were unable to resolve them from the client.
1792 Either client does not support Requested Attributes or isn't replying
1793 to them like it should. */
1795 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1796 SilcServerQuery query,
1797 SilcClientEntry client_entry)
1799 SilcBuffer buffer = NULL;
1800 SilcAttribute attribute;
1801 SilcAttributePayload attr;
1802 SilcAttributeObjPk pk;
1803 SilcAttributeObjService service;
1805 unsigned char sign[2048 + 1];
1806 SilcUInt32 sign_len;
1808 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1810 /* Go through all requested attributes */
1811 silc_dlist_start(query->attrs);
1812 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1813 attribute = silc_attribute_get_attribute(attr);
1814 switch (attribute) {
1816 case SILC_ATTRIBUTE_SERVICE:
1817 /* Put SERVICE. Put only SILC service. */
1818 memset(&service, 0, sizeof(service));
1819 service.port = (server->config->server_info->primary ?
1820 server->config->server_info->primary->port : SILC_PORT);
1821 silc_strncat(service.address, sizeof(service.address),
1822 server->server_name, strlen(server->server_name));
1823 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1824 if (client_entry->connection)
1825 service.idle = time(NULL) - client_entry->data.last_receive;
1826 buffer = silc_attribute_payload_encode(buffer, attribute,
1827 SILC_ATTRIBUTE_FLAG_VALID,
1828 &service, sizeof(service));
1833 case SILC_ATTRIBUTE_STATUS_MOOD:
1834 /* Put STATUS_MOOD */
1835 buffer = silc_attribute_payload_encode(buffer, attribute,
1836 SILC_ATTRIBUTE_FLAG_VALID,
1838 SILC_ATTRIBUTE_MOOD_NORMAL,
1839 sizeof(SilcUInt32));
1844 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1845 /* Put STATUS_FREETEXT. We just tell in the message that we are
1846 replying on behalf of the client. */
1848 "This information was provided by the server on behalf of the user";
1849 buffer = silc_attribute_payload_encode(buffer, attribute,
1850 SILC_ATTRIBUTE_FLAG_VALID,
1856 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1857 /* Put PREFERRED_CONTACT */
1858 buffer = silc_attribute_payload_encode(buffer, attribute,
1859 SILC_ATTRIBUTE_FLAG_VALID,
1861 SILC_ATTRIBUTE_CONTACT_CHAT,
1862 sizeof(SilcUInt32));
1867 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1868 /* Put USER_PUBLIC_KEY */
1869 if (client_entry->data.public_key) {
1870 pk.type = "silc-rsa";
1871 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1873 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1874 SILC_ATTRIBUTE_FLAG_VALID :
1875 SILC_ATTRIBUTE_FLAG_INVALID,
1883 /* No public key available */
1884 buffer = silc_attribute_payload_encode(buffer, attribute,
1885 SILC_ATTRIBUTE_FLAG_INVALID,
1892 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1893 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1894 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1897 /* For other attributes we cannot reply so mark it invalid */
1898 buffer = silc_attribute_payload_encode(buffer, attribute,
1899 SILC_ATTRIBUTE_FLAG_INVALID,
1907 /* Always put our public key. This assures that we send at least
1908 something valid back always. */
1909 pk.type = "silc-rsa";
1910 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1911 buffer = silc_attribute_payload_encode(buffer,
1912 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1913 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1914 SILC_ATTRIBUTE_FLAG_INVALID,
1920 /* Finally compute the digital signature of all the data we provided
1921 as an indication that we provided rightfull information, and this
1922 also authenticates our public key. */
1923 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1924 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1925 buffer->data, buffer->len,
1929 pk.data_len = sign_len;
1931 silc_attribute_payload_encode(buffer,
1932 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1933 SILC_ATTRIBUTE_FLAG_VALID,
1942 /* Find client by the Client ID indicated by the `client_id', and if not
1943 found then query it by using WHOIS command. The client information
1944 is also resolved if the cached information is incomplete or if the
1945 `always_resolve' is set to TRUE. The indication whether requested
1946 client was being resolved is saved into `resolved'. If the client
1947 is not being resolved its entry is returned by this function. NULL
1948 is returned if client is resolved. */
1950 SilcClientEntry silc_server_query_client(SilcServer server,
1951 const SilcClientID *client_id,
1952 bool always_resolve,
1955 SilcClientEntry client;
1957 SILC_LOG_DEBUG(("Resolving client by client ID"));
1962 client = silc_idlist_find_client_by_id(server->local_list,
1963 (SilcClientID *)client_id,
1966 client = silc_idlist_find_client_by_id(server->global_list,
1967 (SilcClientID *)client_id,
1969 if (!client && server->server_type == SILC_ROUTER)
1973 if (!client && server->standalone)
1976 if (!client || !client->nickname || !client->username ||
1978 SilcBuffer buffer, idp;
1981 server->stat.commands_sent++;
1984 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1985 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1986 client->resolve_cmd_ident = ++server->cmd_ident;
1989 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1990 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1991 server->cmd_ident, 1,
1992 4, idp->data, idp->len);
1993 silc_server_packet_send(server, client ? client->router->connection :
1994 SILC_PRIMARY_ROUTE(server),
1995 SILC_PACKET_COMMAND, 0,
1996 buffer->data, buffer->len, FALSE);
1997 silc_buffer_free(idp);
1998 silc_buffer_free(buffer);