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"));
297 /* Send WHOIS command to our router */
298 old_ident = silc_command_get_ident(query->cmd->payload);
299 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
300 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
301 silc_server_packet_send(server,
302 SILC_PRIMARY_ROUTE(server),
303 SILC_PACKET_COMMAND, 0,
304 tmpbuf->data, tmpbuf->len, TRUE);
305 silc_command_set_ident(query->cmd->payload, old_ident);
306 silc_buffer_free(tmpbuf);
308 query->resolved = TRUE;
310 /* Continue parsing the query after received reply from router */
311 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
312 silc_server_query_send_router_reply, query);
315 /* Reply callback called after primary router has replied to our initial
316 sending of the query to it. We will proceed the query in this function. */
318 void silc_server_query_send_router_reply(void *context, void *reply)
320 SilcServerQuery query = context;
321 SilcServer server = query->cmd->server;
322 SilcServerCommandReplyContext cmdr = reply;
324 SILC_LOG_DEBUG(("Received reply from router to query"));
326 /* If the original command caller has gone away, just stop. */
327 if (query->cmd->sock->users == 1) {
328 SILC_LOG_DEBUG(("Original command caller vanished"));
329 silc_server_query_free(query);
333 /* Check if router sent error reply */
334 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
337 SILC_LOG_DEBUG(("Sending error to original query"));
339 /* Send the same command reply payload which contains the error */
340 silc_command_set_command(cmdr->payload, query->querycmd);
341 silc_command_set_ident(cmdr->payload,
342 silc_command_get_ident(query->cmd->payload));
343 buffer = silc_command_payload_encode_payload(cmdr->payload);
344 silc_server_packet_send(server, query->cmd->sock,
345 SILC_PACKET_COMMAND_REPLY, 0,
346 buffer->data, buffer->len, FALSE);
347 silc_buffer_free(buffer);
348 silc_server_query_free(query);
352 /* Continue with parsing */
353 silc_server_query_parse(server, query);
356 /* Parse the command query and start processing the queries in detail. */
358 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
360 SilcServerCommandContext cmd = query->cmd;
362 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
367 SILC_LOG_DEBUG(("Parsing %s query",
368 silc_get_command_name(query->querycmd)));
370 switch (query->querycmd) {
372 case SILC_COMMAND_WHOIS:
373 /* Get requested attributes if set */
374 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
375 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
376 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
378 /* When Requested Attributes is present we will assure that this
379 client cannot execute the WHOIS command too fast. This would be
380 same as having SILC_CF_LAG_STRICT. */
381 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
382 cmd->sock->user_data)
383 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
386 /* Get Client IDs if present. Take IDs always instead of nickname. */
387 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
391 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
392 if (!tmp && !query->attrs) {
393 /* No nickname, no ids and no attributes - send error */
394 silc_server_query_send_error(server, query,
395 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
396 silc_server_query_free(query);
400 /* Get the nickname@server string and parse it */
401 if (tmp && ((tmp_len > 128) ||
402 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
403 silc_server_query_send_error(server, query,
404 SILC_STATUS_ERR_BAD_NICKNAME, 0);
405 silc_server_query_free(query);
410 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
411 SILC_STRING_UTF8, 128, &tmp_len);
413 silc_server_query_send_error(server, query,
414 SILC_STATUS_ERR_BAD_NICKNAME, 0);
415 silc_server_query_free(query);
418 silc_free(query->nickname);
419 query->nickname = tmp;
422 /* Parse the IDs included in the query */
423 query->ids = silc_calloc(argc, sizeof(*query->ids));
425 for (i = 0; i < argc; i++) {
426 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
430 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
431 if (!id || id_type != SILC_ID_CLIENT) {
432 silc_server_query_add_error(server, query, 1, i + 4,
433 SILC_STATUS_ERR_BAD_CLIENT_ID);
437 /* Normal server must check whether this ID exist, and if not then
438 send the query to router, unless done so already */
439 if (server->server_type == SILC_SERVER && !query->resolved) {
440 if (!silc_idlist_find_client_by_id(server->local_list,
442 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
443 !silc_idlist_find_client_by_id(server->global_list,
445 silc_server_query_send_router(server, query);
446 for (i = 0; i < query->ids_count; i++)
447 silc_free(query->ids[i].id);
448 silc_free(query->ids);
450 query->ids_count = 0;
457 query->ids[query->ids_count].id = id;
458 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
463 /* Get the max count of reply messages allowed */
464 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
465 if (tmp && tmp_len == sizeof(SilcUInt32))
466 SILC_GET32_MSB(query->reply_count, tmp);
469 case SILC_COMMAND_WHOWAS:
471 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
473 silc_server_query_send_error(server, query,
474 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
475 silc_server_query_free(query);
479 /* Get the nickname@server string and parse it */
481 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
482 silc_server_query_send_error(server, query,
483 SILC_STATUS_ERR_BAD_NICKNAME, 0);
484 silc_server_query_free(query);
489 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
490 SILC_STRING_UTF8, 128, &tmp_len);
492 silc_server_query_send_error(server, query,
493 SILC_STATUS_ERR_BAD_NICKNAME, 0);
494 silc_server_query_free(query);
497 silc_free(query->nickname);
498 query->nickname = tmp;
500 /* Get the max count of reply messages allowed */
501 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
502 if (tmp && tmp_len == sizeof(SilcUInt32))
503 SILC_GET32_MSB(query->reply_count, tmp);
506 case SILC_COMMAND_IDENTIFY:
507 /* Get IDs if present. Take IDs always instead of names. */
508 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
511 /* Try get nickname */
512 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
514 /* Get the nickname@server string and parse it */
516 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
517 silc_server_query_add_error(server, query, 1, 1,
518 SILC_STATUS_ERR_BAD_NICKNAME);
521 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
522 SILC_STRING_UTF8, 128, &tmp_len);
524 silc_server_query_send_error(server, query,
525 SILC_STATUS_ERR_BAD_NICKNAME, 0);
526 silc_server_query_free(query);
529 silc_free(query->nickname);
530 query->nickname = tmp;
533 /* Try get server name */
534 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
536 /* Check server name */
537 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
540 silc_server_query_send_error(server, query,
541 SILC_STATUS_ERR_BAD_SERVER, 0);
542 silc_server_query_free(query);
545 query->server_name = tmp;
548 /* Get channel name */
549 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
550 if (tmp && tmp_len <= 256) {
551 /* Check channel name */
552 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
555 silc_server_query_send_error(server, query,
556 SILC_STATUS_ERR_BAD_CHANNEL, 0);
557 silc_server_query_free(query);
560 query->channel_name = tmp;
563 if (!query->nickname && !query->server_name && !query->channel_name) {
564 silc_server_query_send_error(server, query,
565 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
566 silc_server_query_free(query);
571 /* Parse the IDs included in the query */
572 query->ids = silc_calloc(argc, sizeof(*query->ids));
574 for (i = 0; i < argc; i++) {
575 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
579 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
581 silc_server_query_add_error(server, query, 1, i + 5,
582 SILC_STATUS_ERR_BAD_CLIENT_ID);
586 /* Normal server must check whether this ID exist, and if not then
587 send the query to router, unless done so already */
588 if (server->server_type == SILC_SERVER && !query->resolved) {
589 if (id_type == SILC_ID_CLIENT) {
590 if (!silc_idlist_find_client_by_id(server->local_list,
592 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
593 !silc_idlist_find_client_by_id(server->global_list,
595 silc_server_query_send_router(server, query);
596 for (i = 0; i < query->ids_count; i++)
597 silc_free(query->ids[i].id);
598 silc_free(query->ids);
600 query->ids_count = 0;
606 /* For now all other ID's except Client ID's are explicitly
607 sent to router for resolving. */
608 silc_server_query_send_router(server, query);
609 for (i = 0; i < query->ids_count; i++)
610 silc_free(query->ids[i].id);
611 silc_free(query->ids);
613 query->ids_count = 0;
619 query->ids[query->ids_count].id = id;
620 query->ids[query->ids_count].id_type = id_type;
625 /* Get the max count of reply messages allowed */
626 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
627 if (tmp && tmp_len == sizeof(SilcUInt32))
628 SILC_GET32_MSB(query->reply_count, tmp);
632 /* Start processing the query information */
633 silc_server_query_process(server, query, TRUE);
636 /* Context for holding clients searched by public key. */
638 SilcClientEntry **clients;
639 SilcUInt32 *clients_count;
641 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
643 void silc_server_public_key_hash_foreach(void *key, void *context,
646 SilcServerPublicKeyUser uc = user_context;
647 SilcClientEntry entry = context;
649 /* Nothing was found, just return */
655 (*uc->clients) = silc_realloc((*uc->clients),
656 sizeof((**uc->clients)) *
657 ((*uc->clients_count) + 1));
658 (*uc->clients)[(*uc->clients_count)++] = entry;
661 /* If clients are set, limit the found clients using the attributes in
662 the query. If clients are not set, try to find some clients using
665 void silc_server_query_check_attributes(SilcServer server,
666 SilcServerQuery query,
667 SilcClientEntry **clients,
668 SilcUInt32 *clients_count) {
669 SilcClientEntry entry;
670 SilcAttributePayload attr;
671 SilcAttribute attribute;
672 SilcAttributeObjPk pk;
673 SilcPublicKey publickey;
675 bool found = FALSE, no_clients = FALSE;
677 /* If no clients were found, we only check the attributes
678 if the user wasn't searching for nickname/ids */
681 if (query->nickname || query->ids_count)
685 silc_dlist_start(query->attrs);
686 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
687 attribute = silc_attribute_get_attribute(attr);
690 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
691 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
693 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
696 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
703 /* If no clients were set on calling this function, we
704 just search for clients, otherwise we try to limit
707 SilcServerPublicKeyUserStruct usercontext;
709 usercontext.clients = clients;
710 usercontext.clients_count = clients_count;
711 usercontext.found = FALSE;
713 silc_hash_table_find_foreach(server->pk_hash, publickey,
714 silc_server_public_key_hash_foreach,
717 if (usercontext.found == TRUE)
720 for (i = 0; i < *clients_count; i++) {
721 entry = (*clients)[i];
723 if (!entry->data.public_key)
726 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
728 (*clients)[i] = NULL;
735 silc_pkcs_public_key_free(publickey);
740 if (!found && !query->nickname && !query->ids)
741 silc_server_query_add_error(server, query, 2, 0,
742 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
745 /* Processes the parsed query. This does the actual finding of the
746 queried information and prepares for sending reply to the original
747 sender of the query command. */
749 void silc_server_query_process(SilcServer server, SilcServerQuery query,
752 SilcServerCommandContext cmd = query->cmd;
753 bool check_global = FALSE;
755 SilcClientEntry *clients = NULL, client_entry;
756 SilcChannelEntry *channels = NULL;
757 SilcServerEntry *servers = NULL;
758 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
761 SILC_LOG_DEBUG(("Processing %s query",
762 silc_get_command_name(query->querycmd)));
764 /* Check global lists if query is coming from client or we are not
765 normal server (we know global information). */
766 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
768 else if (server->server_type != SILC_SERVER)
771 if (query->nickname) {
772 /* Get all clients matching nickname from local list */
773 if (!silc_idlist_get_clients_by_hash(server->local_list,
774 query->nickname, server->md5hash,
775 &clients, &clients_count))
776 silc_idlist_get_clients_by_nickname(server->local_list,
779 &clients, &clients_count);
781 /* Check global list as well */
783 if (!silc_idlist_get_clients_by_hash(server->global_list,
784 query->nickname, server->md5hash,
785 &clients, &clients_count))
786 silc_idlist_get_clients_by_nickname(server->global_list,
789 &clients, &clients_count);
793 silc_server_query_add_error(server, query, 1, 1,
794 SILC_STATUS_ERR_NO_SUCH_NICK);
797 if (query->server_name) {
798 /* Find server by name */
799 entry = silc_idlist_find_server_by_name(server->local_list,
800 query->server_name, TRUE, NULL);
801 if (!entry && check_global)
802 entry = silc_idlist_find_server_by_name(server->global_list,
803 query->server_name, TRUE, NULL);
805 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
806 servers[servers_count++] = (SilcServerEntry)entry;
810 silc_server_query_add_error(server, query, 1, 2,
811 SILC_STATUS_ERR_NO_SUCH_SERVER);
814 if (query->channel_name) {
815 /* Find channel by name */
816 entry = silc_idlist_find_channel_by_name(server->local_list,
817 query->channel_name, NULL);
818 if (!entry && check_global)
819 entry = silc_idlist_find_channel_by_name(server->global_list,
820 query->channel_name, NULL);
822 channels = silc_realloc(channels, sizeof(*channels) *
823 (channels_count + 1));
824 channels[channels_count++] = (SilcChannelEntry)entry;
828 silc_server_query_add_error(server, query, 1, 3,
829 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
832 if (query->ids_count) {
833 /* Find entries by the queried IDs */
834 for (i = 0; i < query->ids_count; i++) {
835 void *id = query->ids[i].id;
839 switch (query->ids[i].id_type) {
842 /* Get client entry */
843 entry = silc_idlist_find_client_by_id(server->local_list,
845 if (!entry && check_global)
846 entry = silc_idlist_find_client_by_id(server->global_list,
849 silc_server_query_add_error(server, query, 0, i,
850 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
854 clients = silc_realloc(clients, sizeof(*clients) *
855 (clients_count + 1));
856 clients[clients_count++] = (SilcClientEntry)entry;
860 /* Get server entry */
861 entry = silc_idlist_find_server_by_id(server->local_list,
863 if (!entry && check_global)
864 entry = silc_idlist_find_server_by_id(server->global_list,
867 silc_server_query_add_error(server, query, 0, i,
868 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
872 servers = silc_realloc(servers, sizeof(*servers) *
873 (servers_count + 1));
874 servers[servers_count++] = (SilcServerEntry)entry;
877 case SILC_ID_CHANNEL:
878 /* Get channel entry */
879 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
880 if (!entry && check_global)
881 entry = silc_idlist_find_channel_by_id(server->global_list, id,
884 silc_server_query_add_error(server, query, 0, i,
885 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
889 channels = silc_realloc(channels, sizeof(*channels) *
890 (channels_count + 1));
891 channels[channels_count++] = (SilcChannelEntry)entry;
900 /* Check the attributes to narrow down the search by using them. */
902 silc_server_query_check_attributes(server, query, &clients,
905 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
906 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
907 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
909 /* If nothing was found, then just send the errors */
910 if (!clients && !channels && !servers) {
911 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
915 /* If caller does not want us to resolve anything (has resolved already)
916 then just continue with sending the reply */
918 silc_server_query_send_reply(server, query, clients, clients_count,
919 servers, servers_count, channels,
927 /* Now process all found information and if necessary do some more
929 switch (query->querycmd) {
931 case SILC_COMMAND_WHOIS:
932 for (i = 0; i < clients_count; i++) {
933 client_entry = clients[i];
935 /* Check if cannot query this anyway, so take next one */
937 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
940 /* If Requested Attributes is set then we always resolve the client
941 information, if not then check whether the entry is complete or not
942 and decide whether we need to resolve or not. */
945 /* Even if nickname and stuff are present, we may need to resolve
947 if (client_entry->nickname && client_entry->username &&
948 client_entry->userinfo) {
949 /* Check if cannot query this anyway, so take next one */
950 if (!client_entry->router)
953 /* If we are router, client is local to us, or client is on channel
954 we do not need to resolve the client information. */
955 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
956 || silc_hash_table_count(client_entry->channels) ||
962 /* Remove the NOATTR status periodically */
963 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
964 client_entry->updated + 600 < time(NULL))
965 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
967 /* When requested attributes is present and local client is detached
968 we cannot send the command to the client, we'll reply on behalf of
969 the client instead. */
970 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
971 (client_entry->mode & SILC_UMODE_DETACHED ||
972 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
975 /* If attributes are present in query, and in the entry and we have
976 done resolvings already we don't need to resolve anymore */
977 if (query->resolved && query->attrs && client_entry->attrs)
980 /* Resolve the detailed client information. If client is local we
981 know that attributes were present and we will resolve directly
982 from the client. Otherwise resolve from client's owner. */
983 silc_server_query_resolve(server, query,
984 (SILC_IS_LOCAL(client_entry) ?
985 client_entry->connection :
986 client_entry->router->connection),
991 case SILC_COMMAND_WHOWAS:
992 for (i = 0; i < clients_count; i++) {
993 client_entry = clients[i];
995 /* Check if cannot query this anyway, so take next one */
996 if (!client_entry || !client_entry->router ||
997 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1000 /* If both nickname and username are present no resolving is needed */
1001 if (client_entry->nickname && client_entry->username)
1004 /* Resolve the detailed client information */
1005 silc_server_query_resolve(server, query,
1006 client_entry->router->connection,
1011 case SILC_COMMAND_IDENTIFY:
1012 for (i = 0; i < clients_count; i++) {
1013 client_entry = clients[i];
1015 /* Check if cannot query this anyway, so take next one */
1016 if (!client_entry || !client_entry->router ||
1017 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1020 /* Even if nickname is present, we may need to resolve the entry */
1021 if (client_entry->nickname) {
1023 /* If we are router, client is local to us, or client is on channel
1024 we do not need to resolve the client information. */
1025 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1026 || silc_hash_table_count(client_entry->channels) ||
1031 /* Resolve the detailed client information */
1032 silc_server_query_resolve(server, query,
1033 client_entry->router->connection,
1039 if (!query->queries_count)
1040 /* If we didn't have to do any resolving, continue with sending the
1041 command reply to the original sender. */
1042 silc_server_query_send_reply(server, query, clients, clients_count,
1043 servers, servers_count, channels,
1046 /* Now actually send the resolvings we gathered earlier */
1047 silc_server_query_resolve(server, query, NULL, NULL);
1051 silc_free(channels);
1054 /* Resolve the detailed information for the `client_entry'. Only client
1055 information needs to be resolved for being incomplete. Each incomplete
1056 client entry calls this function to do the resolving. */
1058 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1059 SilcSocketConnection sock,
1060 SilcClientEntry client_entry)
1062 SilcServerCommandContext cmd = query->cmd;
1063 SilcServerQueryList r = NULL;
1070 if (!sock && client_entry)
1073 /* If arguments are NULL we will now actually send the resolvings
1074 that earlier has been gathered by calling this function. */
1075 if (!sock && !client_entry) {
1078 SILC_LOG_DEBUG(("Sending the resolvings"));
1080 /* WHOWAS resolving has been done at the same time this function
1081 was called to add the resolving for WHOWAS, so just return. */
1082 if (query->querycmd == SILC_COMMAND_WHOWAS)
1085 for (i = 0; i < query->querylist_count; i++) {
1086 r = &query->querylist[i];
1088 /* If Requested Attributes were present put them to this resolving */
1089 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1091 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1092 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1093 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1095 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1097 r->arg[r->argc] = silc_memdup(tmp, len);
1098 r->arg_lens[r->argc] = len;
1099 r->arg_types[r->argc] = 3;
1103 /* Send WHOIS command */
1104 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1105 r->argc, r->arg, r->arg_lens,
1106 r->arg_types, r->ident);
1107 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1108 res_cmd->data, res_cmd->len, FALSE);
1109 silc_buffer_free(res_cmd);
1111 /* Reprocess this packet after received reply */
1112 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1114 silc_server_query_resolve_reply,
1116 query->queries_left++;
1119 /* Cleanup this temporary context */
1120 for (i = 0; i < query->querylist_count; i++) {
1122 for (k = 0; k < query->querylist[i].argc; k++)
1123 silc_free(query->querylist[i].arg[k]);
1124 silc_free(query->querylist[i].arg);
1125 silc_free(query->querylist[i].arg_lens);
1126 silc_free(query->querylist[i].arg_types);
1128 silc_free(query->querylist);
1129 query->querylist = NULL;
1130 query->querylist_count = 0;
1134 SILC_LOG_DEBUG(("Resolving client information"));
1136 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1137 /* The entry is being resolved by some other external query already.
1138 Attach to that query instead of resolving again. */
1139 ident = client_entry->resolve_cmd_ident;
1140 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1141 silc_server_query_resolve_reply, query))
1142 query->queries_left++;
1144 /* This entry will be resolved */
1145 ident = ++server->cmd_ident;
1147 switch (query->querycmd) {
1149 case SILC_COMMAND_WHOIS:
1150 case SILC_COMMAND_IDENTIFY:
1151 /* Take existing query context if exist for this connection */
1152 for (i = 0; i < query->querylist_count; i++)
1153 if (query->querylist[i].sock == sock) {
1154 r = &query->querylist[i];
1159 /* Allocate new temp query list context */
1160 query->querylist = silc_realloc(query->querylist,
1161 sizeof(*query->querylist) *
1162 (query->querylist_count + 1));
1163 r = &query->querylist[query->querylist_count];
1164 query->querylist_count++;
1165 memset(r, 0, sizeof(*r));
1168 if (SILC_IS_LOCAL(client_entry))
1173 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1174 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1175 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1177 /* Add the client entry to be resolved */
1178 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1179 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1180 r->arg_lens[r->argc] = idp->len;
1181 r->arg_types[r->argc] = r->argc + 4;
1183 silc_buffer_free(idp);
1187 case SILC_COMMAND_WHOWAS:
1188 /* We must send WHOWAS command since it's the only the way of
1189 resolving clients that are not present in the network anymore. */
1190 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1191 1, query->nickname, strlen(query->nickname));
1192 if (silc_server_command_pending(server, query->querycmd, ident,
1193 silc_server_query_resolve_reply, query))
1194 query->queries_left++;
1199 /* Mark the entry as being resolved */
1200 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1201 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1202 client_entry->resolve_cmd_ident = ident;
1203 client_entry->updated = time(NULL);
1205 /* Save the queried ID, which we will reprocess after we get this and
1206 all other queries back. */
1207 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1208 (query->queries_count + 1));
1209 if (query->queries) {
1210 i = query->queries_count;
1211 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1212 query->queries[i].id_type = SILC_ID_CLIENT;
1213 query->queries[i].ident = ident;
1214 query->queries_count++;
1218 /* Reply callback called after one resolving has been completed. If
1219 all resolvings has been received then we will continue with sending
1220 the command reply to the original sender of the query. */
1222 void silc_server_query_resolve_reply(void *context, void *reply)
1224 SilcServerQuery query = context;
1225 SilcServer server = query->cmd->server;
1226 SilcServerCommandReplyContext cmdr = reply;
1227 SilcUInt16 ident = cmdr->ident;
1228 SilcStatus error = SILC_STATUS_OK;
1229 SilcServerQueryID id = NULL;
1230 SilcClientEntry client_entry;
1233 /* One less query left */
1234 query->queries_left--;
1236 silc_command_get_status(cmdr->payload, NULL, &error);
1237 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1238 query->queries_left, error));
1240 /* If no error then skip to other stuff */
1241 if (error == SILC_STATUS_OK)
1244 /* Error occurred during resolving */
1246 /* Find the resolved client ID */
1247 for (i = 0; i < query->queries_count; i++) {
1248 if (query->queries[i].ident != ident)
1251 id = &query->queries[i];
1253 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1255 /* If timeout occurred for local entry when resolving attributes
1256 mark that this client doesn't support attributes in WHOIS. This
1257 assures we won't send the request again to the client. */
1258 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1259 client_entry = silc_idlist_find_client_by_id(server->local_list,
1260 id->id, TRUE, NULL);
1261 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1262 silc_id_render(id->id, SILC_ID_CLIENT)));
1263 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1264 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1265 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1270 /* Remove the RESOLVING status from the client entry */
1271 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1272 client_entry = silc_idlist_find_client_by_id(server->local_list,
1273 id->id, TRUE, NULL);
1275 client_entry = silc_idlist_find_client_by_id(server->global_list,
1276 id->id, TRUE, NULL);
1278 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1285 /* If there are queries left then wait for them */
1286 if (query->queries_left)
1289 SILC_LOG_DEBUG(("Reprocess the query"));
1291 /* If the original command caller has gone away, just stop. */
1292 if (query->cmd->sock->users == 1) {
1293 SILC_LOG_DEBUG(("Original command caller vanished"));
1294 silc_server_query_free(query);
1298 /* We have received all queries. Now re-search all information required
1299 to complete this query. Reason we cannot save the values found in
1300 the first search is that SilcClientEntry, SilcServerEntry and
1301 SilcChannelEntry pointers may become invalid while we were waiting
1302 for these resolvings. */
1303 silc_server_query_process(server, query, FALSE);
1306 /* Send the reply to the original query. If arguments are NULL then this
1307 sends only the errors that has occurred during the processing of the
1308 query. This sends the errors always after sending all the found
1309 information. The query is over after this function returns and the
1310 `query' will become invalid. This is called only after all informations
1311 has been resolved. This means that if something is not found or is
1312 incomplete in this function we were unable to resolve the information
1313 or it does not exist at all. */
1315 void silc_server_query_send_reply(SilcServer server,
1316 SilcServerQuery query,
1317 SilcClientEntry *clients,
1318 SilcUInt32 clients_count,
1319 SilcServerEntry *servers,
1320 SilcUInt32 servers_count,
1321 SilcChannelEntry *channels,
1322 SilcUInt32 channels_count)
1324 SilcServerCommandContext cmd = query->cmd;
1325 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1330 int i, k, valid_count;
1331 char nh[384], uh[384];
1332 bool sent_reply = FALSE;
1334 SILC_LOG_DEBUG(("Sending reply to query"));
1335 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1336 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1337 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1338 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1340 status = SILC_STATUS_OK;
1343 if (clients_count) {
1344 SilcClientEntry entry;
1345 SilcSocketConnection hsock;
1347 /* Mark all invalid entries */
1348 for (i = 0, valid_count = 0; i < clients_count; i++) {
1353 switch (query->querycmd) {
1354 case SILC_COMMAND_WHOIS:
1355 if (!entry->nickname || !entry->username || !entry->userinfo ||
1356 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1357 /* When querying by ID, every "unfound" entry must cause error */
1359 silc_server_query_add_error_id(server, query,
1360 SILC_STATUS_ERR_TIMEDOUT,
1361 entry->id, SILC_ID_CLIENT);
1367 case SILC_COMMAND_IDENTIFY:
1368 if (!entry->nickname ||
1369 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1370 /* When querying by ID, every "unfound" entry must cause error */
1372 silc_server_query_add_error_id(server, query,
1373 SILC_STATUS_ERR_TIMEDOUT,
1374 entry->id, SILC_ID_CLIENT);
1380 case SILC_COMMAND_WHOWAS:
1381 if (!entry->nickname || !entry->username ||
1382 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1391 /* Start processing found clients */
1392 status = SILC_STATUS_OK;
1393 if (valid_count > 1)
1394 status = SILC_STATUS_LIST_START;
1396 /* Now do the sending of valid entries */
1398 for (i = 0; i < clients_count && valid_count; i++) {
1404 status = SILC_STATUS_LIST_ITEM;
1405 if (valid_count > 1 && k == valid_count - 1
1406 && !servers_count && !channels_count && !query->errors_count)
1407 status = SILC_STATUS_LIST_END;
1408 if (query->reply_count && k - 1 == query->reply_count)
1409 status = SILC_STATUS_LIST_END;
1411 SILC_LOG_DEBUG(("%s: client %s",
1412 (status == SILC_STATUS_OK ? " OK" :
1413 status == SILC_STATUS_LIST_START ? "START" :
1414 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1415 status == SILC_STATUS_LIST_END ? " END" :
1416 " : "), entry->nickname));
1418 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1419 memset(nh, 0, sizeof(nh));
1421 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1422 if (!strchr(entry->nickname, '@')) {
1423 silc_strncat(nh, sizeof(nh), "@", 1);
1424 if (entry->servername) {
1425 silc_strncat(nh, sizeof(nh), entry->servername,
1426 strlen(entry->servername));
1428 len = entry->router ? strlen(entry->router->server_name) :
1429 strlen(server->server_name);
1430 silc_strncat(nh, sizeof(nh), entry->router ?
1431 entry->router->server_name :
1432 server->server_name, len);
1436 switch (query->querycmd) {
1438 case SILC_COMMAND_WHOIS:
1440 unsigned char idle[4], mode[4];
1441 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1442 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1444 memset(fempty, 0, sizeof(fempty));
1445 memset(idle, 0, sizeof(idle));
1446 memset(uh, 0, sizeof(uh));
1448 silc_strncat(uh, sizeof(uh), entry->username,
1449 strlen(entry->username));
1450 if (!strchr(entry->username, '@') && entry->connection) {
1451 hsock = entry->connection;
1452 silc_strncat(uh, sizeof(uh), "@", 1);
1453 len = strlen(hsock->hostname);
1454 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1457 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1459 silc_server_get_client_channel_list(server, entry, FALSE,
1460 FALSE, &umode_list);
1463 silc_server_get_client_channel_list(server, entry, TRUE,
1466 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1467 fingerprint = entry->data.fingerprint;
1471 SILC_PUT32_MSB(entry->mode, mode);
1472 if (entry->connection)
1473 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1475 /* If Requested Attribute were present, and we do not have the
1476 attributes we will reply to them on behalf of the client. */
1479 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1480 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1481 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1482 entry->attrs_len = len;
1483 silc_buffer_free(tmpattrs);
1485 attrs = entry->attrs;
1486 len = entry->attrs_len;
1489 /* Send command reply */
1490 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1491 status, 0, ident, 10,
1492 2, idp->data, idp->len,
1496 strlen(entry->userinfo),
1497 6, channels ? channels->data : NULL,
1498 channels ? channels->len : 0,
1502 fingerprint ? 20 : 0,
1503 10, umode_list ? umode_list->data :
1504 NULL, umode_list ? umode_list->len :
1509 /* For now we always delete Requested Attributes, unless the client
1510 is detached, in which case we don't want to reconstruct the
1511 same data everytime */
1512 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1513 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1514 silc_free(entry->attrs);
1515 entry->attrs = NULL;
1519 silc_buffer_free(channels);
1521 silc_buffer_free(umode_list);
1527 case SILC_COMMAND_IDENTIFY:
1528 if (!entry->username) {
1529 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1530 status, 0, ident, 2,
1531 2, idp->data, idp->len,
1535 silc_strncat(uh, sizeof(uh), entry->username,
1536 strlen(entry->username));
1537 if (!strchr(entry->username, '@') && entry->connection) {
1538 hsock = entry->connection;
1539 silc_strncat(uh, sizeof(uh), "@", 1);
1540 len = strlen(hsock->hostname);
1541 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1544 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1545 status, 0, ident, 3,
1546 2, idp->data, idp->len,
1553 case SILC_COMMAND_WHOWAS:
1554 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1555 if (!strchr(entry->username, '@'))
1556 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1558 /* Send command reply */
1559 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1560 status, 0, ident, 4,
1561 2, idp->data, idp->len,
1566 strlen(entry->userinfo) : 0);
1571 silc_buffer_free(idp);
1573 if (status == SILC_STATUS_LIST_END)
1579 /* Not one valid entry was found, send error. If nickname was used
1580 in query send error based on that, otherwise the query->errors
1581 already includes proper errors. */
1582 if (query->nickname || (!query->ids && query->attrs))
1583 silc_server_query_add_error(server, query, 1, 1,
1584 SILC_STATUS_ERR_NO_SUCH_NICK);
1586 /* Make sure some error is sent */
1587 if (!query->errors_count && !servers_count && !channels_count)
1588 silc_server_query_add_error(server, query, 2, 0,
1589 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1594 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1595 SilcServerEntry entry;
1597 if (status == SILC_STATUS_OK && servers_count > 1)
1598 status = SILC_STATUS_LIST_START;
1601 for (i = 0; i < servers_count; i++) {
1605 status = SILC_STATUS_LIST_ITEM;
1606 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1607 !query->errors_count)
1608 status = SILC_STATUS_LIST_END;
1609 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1610 !query->errors_count)
1611 status = SILC_STATUS_LIST_END;
1612 if (query->reply_count && k - 1 == query->reply_count)
1613 status = SILC_STATUS_LIST_END;
1615 SILC_LOG_DEBUG(("%s: server %s",
1616 (status == SILC_STATUS_OK ? " OK" :
1617 status == SILC_STATUS_LIST_START ? "START" :
1618 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1619 status == SILC_STATUS_LIST_END ? " END" :
1621 entry->server_name ? entry->server_name : ""));
1623 /* Send command reply */
1624 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1625 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1626 status, 0, ident, 2,
1627 2, idp->data, idp->len,
1628 3, entry->server_name,
1629 entry->server_name ?
1630 strlen(entry->server_name) : 0);
1631 silc_buffer_free(idp);
1634 if (status == SILC_STATUS_LIST_END)
1641 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1642 SilcChannelEntry entry;
1644 if (status == SILC_STATUS_OK && channels_count > 1)
1645 status = SILC_STATUS_LIST_START;
1648 for (i = 0; i < channels_count; i++) {
1649 entry = channels[i];
1652 status = SILC_STATUS_LIST_ITEM;
1653 if (channels_count == 1 && status != SILC_STATUS_OK &&
1654 !query->errors_count)
1655 status = SILC_STATUS_LIST_END;
1656 if (channels_count > 1 && k == channels_count - 1 &&
1657 !query->errors_count)
1658 status = SILC_STATUS_LIST_END;
1659 if (query->reply_count && k - 1 == query->reply_count)
1660 status = SILC_STATUS_LIST_END;
1662 SILC_LOG_DEBUG(("%s: channel %s",
1663 (status == SILC_STATUS_OK ? " OK" :
1664 status == SILC_STATUS_LIST_START ? "START" :
1665 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1666 status == SILC_STATUS_LIST_END ? " END" :
1668 entry->channel_name ? entry->channel_name : ""));
1670 /* Send command reply */
1671 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1672 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1673 status, 0, ident, 2,
1674 2, idp->data, idp->len,
1675 3, entry->channel_name,
1676 entry->channel_name ?
1677 strlen(entry->channel_name) : 0);
1678 silc_buffer_free(idp);
1681 if (status == SILC_STATUS_LIST_END)
1688 if (query->errors_count) {
1691 if (status == SILC_STATUS_OK && query->errors_count > 1)
1692 status = SILC_STATUS_LIST_START;
1695 for (i = 0; i < query->errors_count; i++) {
1698 /* Take error argument */
1699 if (query->errors[i].type == 1) {
1700 /* Take from sent arguments */
1702 tmp = silc_argument_get_arg_type(cmd->args,
1703 query->errors[i].index, &len);
1705 } else if (query->errors[i].type == 2) {
1710 } else if (!query->errors[i].id) {
1711 /* Take from query->ids */
1713 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1714 query->ids[query->errors[k].index].id_type);
1719 /* Take added ID. */
1720 idp = silc_id_payload_encode(query->errors[i].id,
1721 query->errors[k].id_type);
1728 status = SILC_STATUS_LIST_ITEM;
1729 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1730 status = SILC_STATUS_LIST_END;
1731 if (query->errors_count > 1 && k == query->errors_count - 1)
1732 status = SILC_STATUS_LIST_END;
1733 if (query->reply_count && k - 1 == query->reply_count)
1734 status = SILC_STATUS_LIST_END;
1736 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1737 (status == SILC_STATUS_OK ? " OK" :
1738 status == SILC_STATUS_LIST_START ? "START" :
1739 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1740 status == SILC_STATUS_LIST_END ? " END" :
1742 silc_get_status_message(query->errors[i].error),
1743 query->errors[i].error));
1745 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1746 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1748 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1749 (status == SILC_STATUS_OK ?
1750 query->errors[i].error : status),
1751 (status == SILC_STATUS_OK ?
1752 0 : query->errors[i].error), ident, 2,
1758 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1759 (status == SILC_STATUS_OK ?
1760 query->errors[i].error : status),
1761 (status == SILC_STATUS_OK ?
1762 0 : query->errors[i].error), ident, 1,
1765 silc_buffer_free(idp);
1768 if (status == SILC_STATUS_LIST_END)
1775 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1778 silc_server_query_free(query);
1781 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1782 of the client since we were unable to resolve them from the client.
1783 Either client does not support Requested Attributes or isn't replying
1784 to them like it should. */
1786 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1787 SilcServerQuery query,
1788 SilcClientEntry client_entry)
1790 SilcBuffer buffer = NULL;
1791 SilcAttribute attribute;
1792 SilcAttributePayload attr;
1793 SilcAttributeObjPk pk;
1794 SilcAttributeObjService service;
1796 unsigned char sign[2048 + 1];
1797 SilcUInt32 sign_len;
1799 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1801 /* Go through all requested attributes */
1802 silc_dlist_start(query->attrs);
1803 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1804 attribute = silc_attribute_get_attribute(attr);
1805 switch (attribute) {
1807 case SILC_ATTRIBUTE_SERVICE:
1808 /* Put SERVICE. Put only SILC service. */
1809 memset(&service, 0, sizeof(service));
1810 service.port = (server->config->server_info->primary ?
1811 server->config->server_info->primary->port : SILC_PORT);
1812 silc_strncat(service.address, sizeof(service.address),
1813 server->server_name, strlen(server->server_name));
1814 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1815 if (client_entry->connection)
1816 service.idle = time(NULL) - client_entry->data.last_receive;
1817 buffer = silc_attribute_payload_encode(buffer, attribute,
1818 SILC_ATTRIBUTE_FLAG_VALID,
1819 &service, sizeof(service));
1824 case SILC_ATTRIBUTE_STATUS_MOOD:
1825 /* Put STATUS_MOOD */
1826 buffer = silc_attribute_payload_encode(buffer, attribute,
1827 SILC_ATTRIBUTE_FLAG_VALID,
1829 SILC_ATTRIBUTE_MOOD_NORMAL,
1830 sizeof(SilcUInt32));
1835 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1836 /* Put STATUS_FREETEXT. We just tell in the message that we are
1837 replying on behalf of the client. */
1839 "This information was provided by the server on behalf of the user";
1840 buffer = silc_attribute_payload_encode(buffer, attribute,
1841 SILC_ATTRIBUTE_FLAG_VALID,
1847 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1848 /* Put PREFERRED_CONTACT */
1849 buffer = silc_attribute_payload_encode(buffer, attribute,
1850 SILC_ATTRIBUTE_FLAG_VALID,
1852 SILC_ATTRIBUTE_CONTACT_CHAT,
1853 sizeof(SilcUInt32));
1858 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1859 /* Put USER_PUBLIC_KEY */
1860 if (client_entry->data.public_key) {
1861 pk.type = "silc-rsa";
1862 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1864 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1865 SILC_ATTRIBUTE_FLAG_VALID :
1866 SILC_ATTRIBUTE_FLAG_INVALID,
1874 /* No public key available */
1875 buffer = silc_attribute_payload_encode(buffer, attribute,
1876 SILC_ATTRIBUTE_FLAG_INVALID,
1883 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1884 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1885 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1888 /* For other attributes we cannot reply so mark it invalid */
1889 buffer = silc_attribute_payload_encode(buffer, attribute,
1890 SILC_ATTRIBUTE_FLAG_INVALID,
1898 /* Always put our public key. This assures that we send at least
1899 something valid back always. */
1900 pk.type = "silc-rsa";
1901 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1902 buffer = silc_attribute_payload_encode(buffer,
1903 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1904 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1905 SILC_ATTRIBUTE_FLAG_INVALID,
1911 /* Finally compute the digital signature of all the data we provided
1912 as an indication that we provided rightfull information, and this
1913 also authenticates our public key. */
1914 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1915 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1916 buffer->data, buffer->len,
1920 pk.data_len = sign_len;
1922 silc_attribute_payload_encode(buffer,
1923 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1924 SILC_ATTRIBUTE_FLAG_VALID,
1933 /* Find client by the Client ID indicated by the `client_id', and if not
1934 found then query it by using WHOIS command. The client information
1935 is also resolved if the cached information is incomplete or if the
1936 `always_resolve' is set to TRUE. The indication whether requested
1937 client was being resolved is saved into `resolved'. If the client
1938 is not being resolved its entry is returned by this function. NULL
1939 is returned if client is resolved. */
1941 SilcClientEntry silc_server_query_client(SilcServer server,
1942 const SilcClientID *client_id,
1943 bool always_resolve,
1946 SilcClientEntry client;
1948 SILC_LOG_DEBUG(("Resolving client by client ID"));
1953 client = silc_idlist_find_client_by_id(server->local_list,
1954 (SilcClientID *)client_id,
1957 client = silc_idlist_find_client_by_id(server->global_list,
1958 (SilcClientID *)client_id,
1960 if (!client && server->server_type == SILC_ROUTER)
1964 if (!client && server->standalone)
1967 if (!client || !client->nickname || !client->username ||
1969 SilcBuffer buffer, idp;
1972 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1973 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1974 client->resolve_cmd_ident = ++server->cmd_ident;
1977 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1978 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1979 server->cmd_ident, 1,
1980 4, idp->data, idp->len);
1981 silc_server_packet_send(server, client ? client->router->connection :
1982 SILC_PRIMARY_ROUTE(server),
1983 SILC_PACKET_COMMAND, 0,
1984 buffer->data, buffer->len, FALSE);
1985 silc_buffer_free(idp);
1986 silc_buffer_free(buffer);