5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 0 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name */
57 char *channel_name; /* Queried channel name */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `type'. If `type' is 0 the index is to query->ids, if
177 it is 1 it is index to the command context arguments, and if it is
178 2 the index is ignored and no argument is included in the error. */
180 void silc_server_query_add_error(SilcServer server,
181 SilcServerQuery query,
186 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187 (query->errors_count + 1));
190 query->errors[query->errors_count].index = index;
191 query->errors[query->errors_count].type = type;
192 query->errors[query->errors_count].error = error;
193 query->errors[query->errors_count].id = NULL;
194 query->errors[query->errors_count].id_type = 0;
195 query->errors_count++;
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199 with error sending with this error type. */
201 void silc_server_query_add_error_id(SilcServer server,
202 SilcServerQuery query,
204 void *id, SilcIdType id_type)
206 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207 (query->errors_count + 1));
210 query->errors[query->errors_count].index = 0;
211 query->errors[query->errors_count].type = 0;
212 query->errors[query->errors_count].error = error;
213 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214 query->errors[query->errors_count].id_type = id_type;
215 query->errors_count++;
218 /* Processes query as command. The `query' is the command that is
219 being processed indicated by the `cmd'. The `query' can be one of
220 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221 SILC_COMMAND_IDENTIFY. This function handles the reply sending
222 to the entity who sent this query to us automatically. Returns
223 TRUE if the query is being processed or FALSE on error. */
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226 SilcServerCommandContext cmd)
228 SilcServerQuery query;
230 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
232 query = silc_calloc(1, sizeof(*query));
233 query->querycmd = querycmd;
234 query->cmd = silc_server_command_dup(cmd);
238 case SILC_COMMAND_WHOIS:
239 /* If we are normal server and query contains nickname OR query
240 doesn't contain nickname or ids BUT attributes, send it to the
242 if (server->server_type != SILC_ROUTER && !server->standalone &&
243 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248 silc_server_query_send_router(server, query);
253 case SILC_COMMAND_WHOWAS:
254 /* WHOWAS query is always sent to router if we are normal server */
255 if (server->server_type == SILC_SERVER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_IDENTIFY:
263 /* If we are normal server and query does not contain IDs, send it
264 directly to router (it contains nickname, server name or channel
266 if (server->server_type == SILC_SERVER && !server->standalone &&
267 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269 silc_server_query_send_router(server, query);
275 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276 silc_server_query_free(query);
280 /* Now parse the request */
281 silc_server_query_parse(server, query);
286 /* Send the received query to our primary router since we could not
287 handle the query directly. We will reprocess the query after our
288 router replies back. */
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
293 SilcUInt16 old_ident;
295 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
297 /* Send WHOIS command to our router */
298 old_ident = silc_command_get_ident(query->cmd->payload);
299 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
300 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
301 silc_server_packet_send(server,
302 SILC_PRIMARY_ROUTE(server),
303 SILC_PACKET_COMMAND, 0,
304 tmpbuf->data, tmpbuf->len, TRUE);
305 silc_command_set_ident(query->cmd->payload, old_ident);
306 silc_buffer_free(tmpbuf);
308 query->resolved = TRUE;
310 /* Continue parsing the query after received reply from router */
311 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
312 silc_server_query_send_router_reply, query);
315 /* Reply callback called after primary router has replied to our initial
316 sending of the query to it. We will proceed the query in this function. */
318 void silc_server_query_send_router_reply(void *context, void *reply)
320 SilcServerQuery query = context;
321 SilcServer server = query->cmd->server;
322 SilcServerCommandReplyContext cmdr = reply;
324 SILC_LOG_DEBUG(("Received reply from router to query"));
326 /* Check if router sent error reply */
327 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
330 SILC_LOG_DEBUG(("Sending error to original query"));
332 /* Send the same command reply payload which contains the error */
333 silc_command_set_command(cmdr->payload, query->querycmd);
334 silc_command_set_ident(cmdr->payload,
335 silc_command_get_ident(query->cmd->payload));
336 buffer = silc_command_payload_encode_payload(cmdr->payload);
337 silc_server_packet_send(server, query->cmd->sock,
338 SILC_PACKET_COMMAND_REPLY, 0,
339 buffer->data, buffer->len, FALSE);
340 silc_buffer_free(buffer);
341 silc_server_query_free(query);
345 /* Continue with parsing */
346 silc_server_query_parse(server, query);
349 /* Parse the command query and start processing the queries in detail. */
351 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
353 SilcServerCommandContext cmd = query->cmd;
355 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
360 SILC_LOG_DEBUG(("Parsing %s query",
361 silc_get_command_name(query->querycmd)));
363 switch (query->querycmd) {
365 case SILC_COMMAND_WHOIS:
366 /* Get requested attributes if set */
367 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
368 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
369 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
371 /* When Requested Attributes is present we will assure that this
372 client cannot execute the WHOIS command too fast. This would be
373 same as having SILC_CF_LAG_STRICT. */
374 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
375 cmd->sock->user_data)
376 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
379 /* Get Client IDs if present. Take IDs always instead of nickname. */
380 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
384 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
385 if (!tmp && !query->attrs) {
386 /* No nickname, no ids and no attributes - send error */
387 silc_server_query_send_error(server, query,
388 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
389 silc_server_query_free(query);
393 /* Get the nickname@server string and parse it */
394 if (tmp && ((tmp_len > 128) ||
395 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
396 silc_server_query_send_error(server, query,
397 SILC_STATUS_ERR_BAD_NICKNAME, 0);
398 silc_server_query_free(query);
403 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
404 SILC_STRING_UTF8, 128, &tmp_len);
406 silc_server_query_send_error(server, query,
407 SILC_STATUS_ERR_BAD_NICKNAME, 0);
408 silc_server_query_free(query);
410 silc_free(query->nickname);
411 query->nickname = tmp;
414 /* Parse the IDs included in the query */
415 query->ids = silc_calloc(argc, sizeof(*query->ids));
417 for (i = 0; i < argc; i++) {
418 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
422 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
423 if (!id || id_type != SILC_ID_CLIENT) {
424 silc_server_query_add_error(server, query, 1, i + 4,
425 SILC_STATUS_ERR_BAD_CLIENT_ID);
429 /* Normal server must check whether this ID exist, and if not then
430 send the query to router, unless done so already */
431 if (server->server_type == SILC_SERVER && !query->resolved) {
432 if (!silc_idlist_find_client_by_id(server->local_list,
434 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
435 !silc_idlist_find_client_by_id(server->global_list,
437 silc_server_query_send_router(server, query);
438 for (i = 0; i < query->ids_count; i++)
439 silc_free(query->ids[i].id);
440 silc_free(query->ids);
442 query->ids_count = 0;
449 query->ids[query->ids_count].id = id;
450 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
455 /* Get the max count of reply messages allowed */
456 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
457 if (tmp && tmp_len == sizeof(SilcUInt32))
458 SILC_GET32_MSB(query->reply_count, tmp);
461 case SILC_COMMAND_WHOWAS:
463 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
465 silc_server_query_send_error(server, query,
466 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
467 silc_server_query_free(query);
471 /* Get the nickname@server string and parse it */
473 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
474 silc_server_query_send_error(server, query,
475 SILC_STATUS_ERR_BAD_NICKNAME, 0);
476 silc_server_query_free(query);
481 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
482 SILC_STRING_UTF8, 128, &tmp_len);
484 silc_server_query_send_error(server, query,
485 SILC_STATUS_ERR_BAD_NICKNAME, 0);
486 silc_server_query_free(query);
488 silc_free(query->nickname);
489 query->nickname = tmp;
491 /* Get the max count of reply messages allowed */
492 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
493 if (tmp && tmp_len == sizeof(SilcUInt32))
494 SILC_GET32_MSB(query->reply_count, tmp);
497 case SILC_COMMAND_IDENTIFY:
498 /* Get IDs if present. Take IDs always instead of names. */
499 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
502 /* Try get nickname */
503 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
505 /* Get the nickname@server string and parse it */
507 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
508 silc_server_query_add_error(server, query, 1, 1,
509 SILC_STATUS_ERR_BAD_NICKNAME);
512 /* Try get server name */
513 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
515 query->server_name = silc_memdup(tmp, tmp_len);
517 /* Get channel name */
518 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
519 if (tmp && tmp_len <= 256)
520 query->channel_name = silc_memdup(tmp, tmp_len);
522 if (!query->nickname && !query->server_name && !query->channel_name) {
523 silc_server_query_send_error(server, query,
524 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
525 silc_server_query_free(query);
530 /* Parse the IDs included in the query */
531 query->ids = silc_calloc(argc, sizeof(*query->ids));
533 for (i = 0; i < argc; i++) {
534 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
538 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
540 silc_server_query_add_error(server, query, 1, i + 5,
541 SILC_STATUS_ERR_BAD_CLIENT_ID);
545 /* Normal server must check whether this ID exist, and if not then
546 send the query to router, unless done so already */
547 if (server->server_type == SILC_SERVER && !query->resolved) {
548 if (id_type == SILC_ID_CLIENT) {
549 if (!silc_idlist_find_client_by_id(server->local_list,
551 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
552 !silc_idlist_find_client_by_id(server->global_list,
554 silc_server_query_send_router(server, query);
555 for (i = 0; i < query->ids_count; i++)
556 silc_free(query->ids[i].id);
557 silc_free(query->ids);
559 query->ids_count = 0;
565 /* For now all other ID's except Client ID's are explicitly
566 sent to router for resolving. */
567 silc_server_query_send_router(server, query);
568 for (i = 0; i < query->ids_count; i++)
569 silc_free(query->ids[i].id);
570 silc_free(query->ids);
572 query->ids_count = 0;
578 query->ids[query->ids_count].id = id;
579 query->ids[query->ids_count].id_type = id_type;
584 /* Get the max count of reply messages allowed */
585 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
586 if (tmp && tmp_len == sizeof(SilcUInt32))
587 SILC_GET32_MSB(query->reply_count, tmp);
591 /* Start processing the query information */
592 silc_server_query_process(server, query, TRUE);
595 /* Context for holding clients searched by public key. */
597 SilcClientEntry **clients;
598 SilcUInt32 *clients_count;
600 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
602 void silc_server_public_key_hash_foreach(void *key, void *context,
605 SilcServerPublicKeyUser uc = user_context;
606 SilcClientEntry entry = context;
608 /* Nothing was found, just return */
614 (*uc->clients) = silc_realloc((*uc->clients),
615 sizeof((**uc->clients)) *
616 ((*uc->clients_count) + 1));
617 (*uc->clients)[(*uc->clients_count)++] = entry;
620 /* If clients are set, limit the found clients using the attributes in
621 the query. If clients are not set, try to find some clients using
624 void silc_server_query_check_attributes(SilcServer server,
625 SilcServerQuery query,
626 SilcClientEntry **clients,
627 SilcUInt32 *clients_count) {
628 SilcClientEntry entry;
629 SilcAttributePayload attr;
630 SilcAttribute attribute;
631 SilcAttributeObjPk pk;
632 SilcPublicKey publickey;
634 bool found = FALSE, no_clients = FALSE;
636 /* If no clients were found, we only check the attributes
637 if the user wasn't searching for nickname/ids */
640 if (query->nickname || query->ids_count)
644 silc_dlist_start(query->attrs);
645 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
646 attribute = silc_attribute_get_attribute(attr);
649 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
650 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
652 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
655 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
662 /* If no clients were set on calling this function, we
663 just search for clients, otherwise we try to limit
666 SilcServerPublicKeyUserStruct usercontext;
668 usercontext.clients = clients;
669 usercontext.clients_count = clients_count;
670 usercontext.found = FALSE;
672 silc_hash_table_find_foreach(server->pk_hash, publickey,
673 silc_server_public_key_hash_foreach,
676 if (usercontext.found == TRUE)
679 for (i = 0; i < *clients_count; i++) {
680 entry = (*clients)[i];
682 if (!entry->data.public_key)
685 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
687 (*clients)[i] = NULL;
694 silc_pkcs_public_key_free(publickey);
699 if (!found && !query->nickname && !query->ids)
700 silc_server_query_add_error(server, query, 2, 0,
701 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
704 /* Processes the parsed query. This does the actual finding of the
705 queried information and prepares for sending reply to the original
706 sender of the query command. */
708 void silc_server_query_process(SilcServer server, SilcServerQuery query,
711 SilcServerCommandContext cmd = query->cmd;
712 bool check_global = FALSE;
714 SilcClientEntry *clients = NULL, client_entry;
715 SilcChannelEntry *channels = NULL;
716 SilcServerEntry *servers = NULL;
717 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
720 SILC_LOG_DEBUG(("Processing %s query",
721 silc_get_command_name(query->querycmd)));
723 /* Check global lists if query is coming from client or we are not
724 normal server (we know global information). */
725 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
727 else if (server->server_type != SILC_SERVER)
730 if (query->nickname) {
731 /* Get all clients matching nickname from local list */
732 if (!silc_idlist_get_clients_by_hash(server->local_list,
733 query->nickname, server->md5hash,
734 &clients, &clients_count))
735 silc_idlist_get_clients_by_nickname(server->local_list,
738 &clients, &clients_count);
740 /* Check global list as well */
742 if (!silc_idlist_get_clients_by_hash(server->global_list,
743 query->nickname, server->md5hash,
744 &clients, &clients_count))
745 silc_idlist_get_clients_by_nickname(server->global_list,
748 &clients, &clients_count);
752 silc_server_query_add_error(server, query, 1, 1,
753 SILC_STATUS_ERR_NO_SUCH_NICK);
756 if (query->server_name) {
757 /* Find server by name */
758 entry = silc_idlist_find_server_by_name(server->local_list,
759 query->server_name, TRUE, NULL);
760 if (!entry && check_global)
761 entry = silc_idlist_find_server_by_name(server->global_list,
762 query->server_name, TRUE, NULL);
764 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
765 servers[servers_count++] = (SilcServerEntry)entry;
769 silc_server_query_add_error(server, query, 1, 2,
770 SILC_STATUS_ERR_NO_SUCH_SERVER);
773 if (query->channel_name) {
774 /* Find channel by name */
775 entry = silc_idlist_find_channel_by_name(server->local_list,
776 query->channel_name, NULL);
777 if (!entry && check_global)
778 entry = silc_idlist_find_channel_by_name(server->global_list,
779 query->channel_name, NULL);
781 channels = silc_realloc(channels, sizeof(*channels) *
782 (channels_count + 1));
783 channels[channels_count++] = (SilcChannelEntry)entry;
787 silc_server_query_add_error(server, query, 1, 3,
788 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
791 if (query->ids_count) {
792 /* Find entries by the queried IDs */
793 for (i = 0; i < query->ids_count; i++) {
794 void *id = query->ids[i].id;
798 switch (query->ids[i].id_type) {
801 /* Get client entry */
802 entry = silc_idlist_find_client_by_id(server->local_list,
804 if (!entry && check_global)
805 entry = silc_idlist_find_client_by_id(server->global_list,
808 silc_server_query_add_error(server, query, 0, i,
809 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
813 clients = silc_realloc(clients, sizeof(*clients) *
814 (clients_count + 1));
815 clients[clients_count++] = (SilcClientEntry)entry;
819 /* Get server entry */
820 entry = silc_idlist_find_server_by_id(server->local_list,
822 if (!entry && check_global)
823 entry = silc_idlist_find_server_by_id(server->global_list,
826 silc_server_query_add_error(server, query, 0, i,
827 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
831 servers = silc_realloc(servers, sizeof(*servers) *
832 (servers_count + 1));
833 servers[servers_count++] = (SilcServerEntry)entry;
836 case SILC_ID_CHANNEL:
837 /* Get channel entry */
838 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
839 if (!entry && check_global)
840 entry = silc_idlist_find_channel_by_id(server->global_list, id,
843 silc_server_query_add_error(server, query, 0, i,
844 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
848 channels = silc_realloc(channels, sizeof(*channels) *
849 (channels_count + 1));
850 channels[channels_count++] = (SilcChannelEntry)entry;
859 /* Check the attributes to narrow down the search by using them. */
861 silc_server_query_check_attributes(server, query, &clients,
864 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
865 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
866 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
868 /* If nothing was found, then just send the errors */
869 if (!clients && !channels && !servers) {
870 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
874 /* If caller does not want us to resolve anything (has resolved already)
875 then just continue with sending the reply */
877 silc_server_query_send_reply(server, query, clients, clients_count,
878 servers, servers_count, channels,
886 /* Now process all found information and if necessary do some more
888 switch (query->querycmd) {
890 case SILC_COMMAND_WHOIS:
891 for (i = 0; i < clients_count; i++) {
892 client_entry = clients[i];
894 /* Check if cannot query this anyway, so take next one */
896 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
899 /* If Requested Attributes is set then we always resolve the client
900 information, if not then check whether the entry is complete or not
901 and decide whether we need to resolve or not. */
904 /* Even if nickname and stuff are present, we may need to resolve
906 if (client_entry->nickname && client_entry->username &&
907 client_entry->userinfo) {
908 /* Check if cannot query this anyway, so take next one */
909 if (!client_entry->router)
912 /* If we are router, client is local to us, or client is on channel
913 we do not need to resolve the client information. */
914 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
915 || silc_hash_table_count(client_entry->channels) ||
921 /* Remove the NOATTR status periodically */
922 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
923 client_entry->updated + 600 < time(NULL))
924 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
926 /* When requested attributes is present and local client is detached
927 we cannot send the command to the client, we'll reply on behalf of
928 the client instead. */
929 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
930 (client_entry->mode & SILC_UMODE_DETACHED ||
931 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
934 /* If attributes are present in query, and in the entry and we have
935 done resolvings already we don't need to resolve anymore */
936 if (query->resolved && query->attrs && client_entry->attrs)
939 /* Resolve the detailed client information. If client is local we
940 know that attributes were present and we will resolve directly
941 from the client. Otherwise resolve from client's owner. */
942 silc_server_query_resolve(server, query,
943 (SILC_IS_LOCAL(client_entry) ?
944 client_entry->connection :
945 client_entry->router->connection),
950 case SILC_COMMAND_WHOWAS:
951 for (i = 0; i < clients_count; i++) {
952 client_entry = clients[i];
954 /* Check if cannot query this anyway, so take next one */
955 if (!client_entry || !client_entry->router ||
956 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
959 /* If both nickname and username are present no resolving is needed */
960 if (client_entry->nickname && client_entry->username)
963 /* Resolve the detailed client information */
964 silc_server_query_resolve(server, query,
965 client_entry->router->connection,
970 case SILC_COMMAND_IDENTIFY:
971 for (i = 0; i < clients_count; i++) {
972 client_entry = clients[i];
974 /* Check if cannot query this anyway, so take next one */
975 if (!client_entry || !client_entry->router ||
976 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
979 /* Even if nickname is present, we may need to resolve the entry */
980 if (client_entry->nickname) {
982 /* If we are router, client is local to us, or client is on channel
983 we do not need to resolve the client information. */
984 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
985 || silc_hash_table_count(client_entry->channels) ||
990 /* Resolve the detailed client information */
991 silc_server_query_resolve(server, query,
992 client_entry->router->connection,
998 if (!query->queries_count)
999 /* If we didn't have to do any resolving, continue with sending the
1000 command reply to the original sender. */
1001 silc_server_query_send_reply(server, query, clients, clients_count,
1002 servers, servers_count, channels,
1005 /* Now actually send the resolvings we gathered earlier */
1006 silc_server_query_resolve(server, query, NULL, NULL);
1010 silc_free(channels);
1013 /* Resolve the detailed information for the `client_entry'. Only client
1014 information needs to be resolved for being incomplete. Each incomplete
1015 client entry calls this function to do the resolving. */
1017 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1018 SilcSocketConnection sock,
1019 SilcClientEntry client_entry)
1021 SilcServerCommandContext cmd = query->cmd;
1022 SilcServerQueryList r = NULL;
1029 if (!sock && client_entry)
1032 /* If arguments are NULL we will now actually send the resolvings
1033 that earlier has been gathered by calling this function. */
1034 if (!sock && !client_entry) {
1037 SILC_LOG_DEBUG(("Sending the resolvings"));
1039 /* WHOWAS resolving has been done at the same time this function
1040 was called to add the resolving for WHOWAS, so just return. */
1041 if (query->querycmd == SILC_COMMAND_WHOWAS)
1044 for (i = 0; i < query->querylist_count; i++) {
1045 r = &query->querylist[i];
1047 /* If Requested Attributes were present put them to this resolving */
1048 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1050 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1051 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1052 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1054 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1056 r->arg[r->argc] = silc_memdup(tmp, len);
1057 r->arg_lens[r->argc] = len;
1058 r->arg_types[r->argc] = 3;
1062 /* Send WHOIS command */
1063 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1064 r->argc, r->arg, r->arg_lens,
1065 r->arg_types, r->ident);
1066 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1067 res_cmd->data, res_cmd->len, FALSE);
1068 silc_buffer_free(res_cmd);
1070 /* Reprocess this packet after received reply */
1071 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1073 silc_server_query_resolve_reply,
1075 query->queries_left++;
1078 /* Cleanup this temporary context */
1079 for (i = 0; i < query->querylist_count; i++) {
1081 for (k = 0; k < query->querylist[i].argc; k++)
1082 silc_free(query->querylist[i].arg[k]);
1083 silc_free(query->querylist[i].arg);
1084 silc_free(query->querylist[i].arg_lens);
1085 silc_free(query->querylist[i].arg_types);
1087 silc_free(query->querylist);
1088 query->querylist = NULL;
1089 query->querylist_count = 0;
1093 SILC_LOG_DEBUG(("Resolving client information"));
1095 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1096 /* The entry is being resolved by some other external query already.
1097 Attach to that query instead of resolving again. */
1098 ident = client_entry->resolve_cmd_ident;
1099 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1100 silc_server_query_resolve_reply, query))
1101 query->queries_left++;
1103 /* This entry will be resolved */
1104 ident = ++server->cmd_ident;
1106 switch (query->querycmd) {
1108 case SILC_COMMAND_WHOIS:
1109 case SILC_COMMAND_IDENTIFY:
1110 /* Take existing query context if exist for this connection */
1111 for (i = 0; i < query->querylist_count; i++)
1112 if (query->querylist[i].sock == sock) {
1113 r = &query->querylist[i];
1118 /* Allocate new temp query list context */
1119 query->querylist = silc_realloc(query->querylist,
1120 sizeof(*query->querylist) *
1121 (query->querylist_count + 1));
1122 r = &query->querylist[query->querylist_count];
1123 query->querylist_count++;
1124 memset(r, 0, sizeof(*r));
1127 if (SILC_IS_LOCAL(client_entry))
1132 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1133 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1134 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1136 /* Add the client entry to be resolved */
1137 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1138 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1139 r->arg_lens[r->argc] = idp->len;
1140 r->arg_types[r->argc] = r->argc + 4;
1142 silc_buffer_free(idp);
1146 case SILC_COMMAND_WHOWAS:
1147 /* We must send WHOWAS command since it's the only the way of
1148 resolving clients that are not present in the network anymore. */
1149 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1150 1, query->nickname, strlen(query->nickname));
1151 if (silc_server_command_pending(server, query->querycmd, ident,
1152 silc_server_query_resolve_reply, query))
1153 query->queries_left++;
1158 /* Mark the entry as being resolved */
1159 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1160 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1161 client_entry->resolve_cmd_ident = ident;
1162 client_entry->updated = time(NULL);
1164 /* Save the queried ID, which we will reprocess after we get this and
1165 all other queries back. */
1166 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1167 (query->queries_count + 1));
1168 if (query->queries) {
1169 i = query->queries_count;
1170 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1171 query->queries[i].id_type = SILC_ID_CLIENT;
1172 query->queries[i].ident = ident;
1173 query->queries_count++;
1177 /* Reply callback called after one resolving has been completed. If
1178 all resolvings has been received then we will continue with sending
1179 the command reply to the original sender of the query. */
1181 void silc_server_query_resolve_reply(void *context, void *reply)
1183 SilcServerQuery query = context;
1184 SilcServer server = query->cmd->server;
1185 SilcServerCommandReplyContext cmdr = reply;
1186 SilcUInt16 ident = cmdr->ident;
1187 SilcStatus error = SILC_STATUS_OK;
1188 SilcServerQueryID id = NULL;
1189 SilcClientEntry client_entry;
1192 /* One less query left */
1193 query->queries_left--;
1195 silc_command_get_status(cmdr->payload, NULL, &error);
1196 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1197 query->queries_left, error));
1199 /* If no error then skip to other stuff */
1200 if (error == SILC_STATUS_OK)
1203 /* Error occurred during resolving */
1205 /* Find the resolved client ID */
1206 for (i = 0; i < query->queries_count; i++) {
1207 if (query->queries[i].ident != ident)
1210 id = &query->queries[i];
1212 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1214 /* If timeout occurred for local entry when resolving attributes
1215 mark that this client doesn't support attributes in WHOIS. This
1216 assures we won't send the request again to the client. */
1217 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1218 client_entry = silc_idlist_find_client_by_id(server->local_list,
1219 id->id, TRUE, NULL);
1220 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1221 silc_id_render(id->id, SILC_ID_CLIENT)));
1222 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1223 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1224 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1229 /* Remove the RESOLVING status from the client entry */
1230 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1231 client_entry = silc_idlist_find_client_by_id(server->local_list,
1232 id->id, TRUE, NULL);
1234 client_entry = silc_idlist_find_client_by_id(server->global_list,
1235 id->id, TRUE, NULL);
1237 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1244 /* If there are queries left then wait for them */
1245 if (query->queries_left)
1248 SILC_LOG_DEBUG(("Reprocess the query"));
1250 /* We have received all queries. Now re-search all information required
1251 to complete this query. Reason we cannot save the values found in
1252 the first search is that SilcClientEntry, SilcServerEntry and
1253 SilcChannelEntry pointers may become invalid while we were waiting
1254 for these resolvings. */
1255 silc_server_query_process(server, query, FALSE);
1258 /* Send the reply to the original query. If arguments are NULL then this
1259 sends only the errors that has occurred during the processing of the
1260 query. This sends the errors always after sending all the found
1261 information. The query is over after this function returns and the
1262 `query' will become invalid. This is called only after all informations
1263 has been resolved. This means that if something is not found or is
1264 incomplete in this function we were unable to resolve the information
1265 or it does not exist at all. */
1267 void silc_server_query_send_reply(SilcServer server,
1268 SilcServerQuery query,
1269 SilcClientEntry *clients,
1270 SilcUInt32 clients_count,
1271 SilcServerEntry *servers,
1272 SilcUInt32 servers_count,
1273 SilcChannelEntry *channels,
1274 SilcUInt32 channels_count)
1276 SilcServerCommandContext cmd = query->cmd;
1277 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1282 int i, k, valid_count;
1283 char nh[256], uh[256];
1284 bool sent_reply = FALSE;
1286 SILC_LOG_DEBUG(("Sending reply to query"));
1287 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1288 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1289 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1290 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1292 status = SILC_STATUS_OK;
1295 if (clients_count) {
1296 SilcClientEntry entry;
1297 SilcSocketConnection hsock;
1299 /* Mark all invalid entries */
1300 for (i = 0, valid_count = 0; i < clients_count; i++) {
1305 switch (query->querycmd) {
1306 case SILC_COMMAND_WHOIS:
1307 if (!entry->nickname || !entry->username || !entry->userinfo ||
1308 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1309 /* When querying by ID, every "unfound" entry must cause error */
1311 silc_server_query_add_error_id(server, query,
1312 SILC_STATUS_ERR_TIMEDOUT,
1313 entry->id, SILC_ID_CLIENT);
1319 case SILC_COMMAND_IDENTIFY:
1320 if (!entry->nickname ||
1321 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1322 /* When querying by ID, every "unfound" entry must cause error */
1324 silc_server_query_add_error_id(server, query,
1325 SILC_STATUS_ERR_TIMEDOUT,
1326 entry->id, SILC_ID_CLIENT);
1332 case SILC_COMMAND_WHOWAS:
1333 if (!entry->nickname || !entry->username ||
1334 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1343 /* Start processing found clients */
1344 status = SILC_STATUS_OK;
1345 if (valid_count > 1)
1346 status = SILC_STATUS_LIST_START;
1348 /* Now do the sending of valid entries */
1350 for (i = 0; i < clients_count && valid_count; i++) {
1356 status = SILC_STATUS_LIST_ITEM;
1357 if (valid_count > 1 && k == valid_count - 1
1358 && !servers_count && !channels_count && !query->errors_count)
1359 status = SILC_STATUS_LIST_END;
1360 if (query->reply_count && k - 1 == query->reply_count)
1361 status = SILC_STATUS_LIST_END;
1363 SILC_LOG_DEBUG(("%s: client %s",
1364 (status == SILC_STATUS_OK ? " OK" :
1365 status == SILC_STATUS_LIST_START ? "START" :
1366 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1367 status == SILC_STATUS_LIST_END ? " END" :
1368 " : "), entry->nickname));
1370 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1371 memset(uh, 0, sizeof(uh));
1372 memset(nh, 0, sizeof(nh));
1374 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1375 if (!strchr(entry->nickname, '@')) {
1376 silc_strncat(nh, sizeof(nh), "@", 1);
1377 if (entry->servername) {
1378 silc_strncat(nh, sizeof(nh), entry->servername,
1379 strlen(entry->servername));
1381 len = entry->router ? strlen(entry->router->server_name) :
1382 strlen(server->server_name);
1383 silc_strncat(nh, sizeof(nh), entry->router ?
1384 entry->router->server_name :
1385 server->server_name, len);
1389 switch (query->querycmd) {
1391 case SILC_COMMAND_WHOIS:
1393 unsigned char idle[4], mode[4];
1394 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1395 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1397 memset(fempty, 0, sizeof(fempty));
1398 memset(idle, 0, sizeof(idle));
1399 silc_strncat(uh, sizeof(uh), entry->username,
1400 strlen(entry->username));
1401 if (!strchr(entry->username, '@') && entry->connection) {
1402 hsock = entry->connection;
1403 silc_strncat(uh, sizeof(uh), "@", 1);
1404 len = strlen(hsock->hostname);
1405 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1408 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1410 silc_server_get_client_channel_list(server, entry, FALSE,
1411 FALSE, &umode_list);
1414 silc_server_get_client_channel_list(server, entry, TRUE,
1417 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1418 fingerprint = entry->data.fingerprint;
1422 SILC_PUT32_MSB(entry->mode, mode);
1423 if (entry->connection)
1424 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1426 /* If Requested Attribute were present, and we do not have the
1427 attributes we will reply to them on behalf of the client. */
1430 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1431 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1432 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1433 entry->attrs_len = len;
1434 silc_buffer_free(tmpattrs);
1436 attrs = entry->attrs;
1437 len = entry->attrs_len;
1440 /* Send command reply */
1441 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1442 status, 0, ident, 10,
1443 2, idp->data, idp->len,
1447 strlen(entry->userinfo),
1448 6, channels ? channels->data : NULL,
1449 channels ? channels->len : 0,
1453 fingerprint ? 20 : 0,
1454 10, umode_list ? umode_list->data :
1455 NULL, umode_list ? umode_list->len :
1460 /* For now we always delete Requested Attributes, unless the client
1461 is detached, in which case we don't want to reconstruct the
1462 same data everytime */
1463 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1464 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1465 silc_free(entry->attrs);
1466 entry->attrs = NULL;
1470 silc_buffer_free(channels);
1472 silc_buffer_free(umode_list);
1478 case SILC_COMMAND_IDENTIFY:
1479 if (!entry->username) {
1480 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1481 status, 0, ident, 2,
1482 2, idp->data, idp->len,
1486 silc_strncat(uh, sizeof(uh), entry->username,
1487 strlen(entry->username));
1488 if (!strchr(entry->username, '@') && entry->connection) {
1489 hsock = entry->connection;
1490 silc_strncat(uh, sizeof(uh), "@", 1);
1491 len = strlen(hsock->hostname);
1492 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1495 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1496 status, 0, ident, 3,
1497 2, idp->data, idp->len,
1504 case SILC_COMMAND_WHOWAS:
1505 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1506 if (!strchr(entry->username, '@'))
1507 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1509 /* Send command reply */
1510 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1511 status, 0, ident, 4,
1512 2, idp->data, idp->len,
1517 strlen(entry->userinfo) : 0);
1522 silc_buffer_free(idp);
1524 if (status == SILC_STATUS_LIST_END)
1530 /* Not one valid entry was found, send error. If nickname was used
1531 in query send error based on that, otherwise the query->errors
1532 already includes proper errors. */
1533 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1534 silc_server_query_add_error(server, query, 1, 1,
1535 SILC_STATUS_ERR_NO_SUCH_NICK);
1540 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1541 SilcServerEntry entry;
1543 if (status == SILC_STATUS_OK && servers_count > 1)
1544 status = SILC_STATUS_LIST_START;
1547 for (i = 0; i < servers_count; i++) {
1551 status = SILC_STATUS_LIST_ITEM;
1552 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1553 !query->errors_count)
1554 status = SILC_STATUS_LIST_END;
1555 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1556 !query->errors_count)
1557 status = SILC_STATUS_LIST_END;
1558 if (query->reply_count && k - 1 == query->reply_count)
1559 status = SILC_STATUS_LIST_END;
1561 SILC_LOG_DEBUG(("%s: server %s",
1562 (status == SILC_STATUS_OK ? " OK" :
1563 status == SILC_STATUS_LIST_START ? "START" :
1564 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1565 status == SILC_STATUS_LIST_END ? " END" :
1567 entry->server_name ? entry->server_name : ""));
1569 /* Send command reply */
1570 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1571 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1572 status, 0, ident, 2,
1573 2, idp->data, idp->len,
1574 3, entry->server_name,
1575 entry->server_name ?
1576 strlen(entry->server_name) : 0);
1577 silc_buffer_free(idp);
1580 if (status == SILC_STATUS_LIST_END)
1587 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1588 SilcChannelEntry entry;
1590 if (status == SILC_STATUS_OK && channels_count > 1)
1591 status = SILC_STATUS_LIST_START;
1594 for (i = 0; i < channels_count; i++) {
1595 entry = channels[i];
1598 status = SILC_STATUS_LIST_ITEM;
1599 if (channels_count == 1 && status != SILC_STATUS_OK &&
1600 !query->errors_count)
1601 status = SILC_STATUS_LIST_END;
1602 if (channels_count > 1 && k == channels_count - 1 &&
1603 !query->errors_count)
1604 status = SILC_STATUS_LIST_END;
1605 if (query->reply_count && k - 1 == query->reply_count)
1606 status = SILC_STATUS_LIST_END;
1608 SILC_LOG_DEBUG(("%s: channel %s",
1609 (status == SILC_STATUS_OK ? " OK" :
1610 status == SILC_STATUS_LIST_START ? "START" :
1611 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1612 status == SILC_STATUS_LIST_END ? " END" :
1614 entry->channel_name ? entry->channel_name : ""));
1616 /* Send command reply */
1617 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1618 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1619 status, 0, ident, 2,
1620 2, idp->data, idp->len,
1621 3, entry->channel_name,
1622 entry->channel_name ?
1623 strlen(entry->channel_name) : 0);
1624 silc_buffer_free(idp);
1627 if (status == SILC_STATUS_LIST_END)
1634 if (query->errors_count) {
1637 if (status == SILC_STATUS_OK && query->errors_count > 1)
1638 status = SILC_STATUS_LIST_START;
1641 for (i = 0; i < query->errors_count; i++) {
1644 /* Take error argument */
1645 if (query->errors[i].type == 1) {
1646 /* Take from sent arguments */
1648 tmp = silc_argument_get_arg_type(cmd->args,
1649 query->errors[i].index, &len);
1651 } else if (query->errors[i].type == 2) {
1656 } else if (!query->errors[i].id) {
1657 /* Take from query->ids */
1659 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1660 query->ids[query->errors[k].index].id_type);
1665 /* Take added ID. */
1666 idp = silc_id_payload_encode(query->errors[i].id,
1667 query->errors[k].id_type);
1674 status = SILC_STATUS_LIST_ITEM;
1675 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1676 status = SILC_STATUS_LIST_END;
1677 if (query->errors_count > 1 && k == query->errors_count - 1)
1678 status = SILC_STATUS_LIST_END;
1679 if (query->reply_count && k - 1 == query->reply_count)
1680 status = SILC_STATUS_LIST_END;
1682 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1683 (status == SILC_STATUS_OK ? " OK" :
1684 status == SILC_STATUS_LIST_START ? "START" :
1685 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1686 status == SILC_STATUS_LIST_END ? " END" :
1688 silc_get_status_message(query->errors[i].error),
1689 query->errors[i].error));
1691 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1692 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1694 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1695 (status == SILC_STATUS_OK ?
1696 query->errors[i].error : status),
1697 (status == SILC_STATUS_OK ?
1698 0 : query->errors[i].error), ident, 2,
1704 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1705 (status == SILC_STATUS_OK ?
1706 query->errors[i].error : status),
1707 (status == SILC_STATUS_OK ?
1708 0 : query->errors[i].error), ident, 1,
1711 silc_buffer_free(idp);
1714 if (status == SILC_STATUS_LIST_END)
1721 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1724 silc_server_query_free(query);
1727 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1728 of the client since we were unable to resolve them from the client.
1729 Either client does not support Requested Attributes or isn't replying
1730 to them like it should. */
1732 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1733 SilcServerQuery query,
1734 SilcClientEntry client_entry)
1736 SilcBuffer buffer = NULL;
1737 SilcAttribute attribute;
1738 SilcAttributePayload attr;
1739 SilcAttributeObjPk pk;
1740 SilcAttributeObjService service;
1742 unsigned char sign[2048 + 1];
1743 SilcUInt32 sign_len;
1745 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1747 /* Go through all requested attributes */
1748 silc_dlist_start(query->attrs);
1749 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1750 attribute = silc_attribute_get_attribute(attr);
1751 switch (attribute) {
1753 case SILC_ATTRIBUTE_SERVICE:
1754 /* Put SERVICE. Put only SILC service. */
1755 memset(&service, 0, sizeof(service));
1756 service.port = (server->config->server_info->primary ?
1757 server->config->server_info->primary->port : SILC_PORT);
1758 silc_strncat(service.address, sizeof(service.address),
1759 server->server_name, strlen(server->server_name));
1760 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1761 if (client_entry->connection)
1762 service.idle = time(NULL) - client_entry->data.last_receive;
1763 buffer = silc_attribute_payload_encode(buffer, attribute,
1764 SILC_ATTRIBUTE_FLAG_VALID,
1765 &service, sizeof(service));
1770 case SILC_ATTRIBUTE_STATUS_MOOD:
1771 /* Put STATUS_MOOD */
1772 buffer = silc_attribute_payload_encode(buffer, attribute,
1773 SILC_ATTRIBUTE_FLAG_VALID,
1775 SILC_ATTRIBUTE_MOOD_NORMAL,
1776 sizeof(SilcUInt32));
1781 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1782 /* Put STATUS_FREETEXT. We just tell in the message that we are
1783 replying on behalf of the client. */
1785 "This information was provided by the server on behalf of the user";
1786 buffer = silc_attribute_payload_encode(buffer, attribute,
1787 SILC_ATTRIBUTE_FLAG_VALID,
1793 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1794 /* Put PREFERRED_CONTACT */
1795 buffer = silc_attribute_payload_encode(buffer, attribute,
1796 SILC_ATTRIBUTE_FLAG_VALID,
1798 SILC_ATTRIBUTE_CONTACT_CHAT,
1799 sizeof(SilcUInt32));
1804 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1805 /* Put USER_PUBLIC_KEY */
1806 if (client_entry->data.public_key) {
1807 pk.type = "silc-rsa";
1808 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1810 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1811 SILC_ATTRIBUTE_FLAG_VALID :
1812 SILC_ATTRIBUTE_FLAG_INVALID,
1820 /* No public key available */
1821 buffer = silc_attribute_payload_encode(buffer, attribute,
1822 SILC_ATTRIBUTE_FLAG_INVALID,
1829 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1830 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1831 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1834 /* For other attributes we cannot reply so mark it invalid */
1835 buffer = silc_attribute_payload_encode(buffer, attribute,
1836 SILC_ATTRIBUTE_FLAG_INVALID,
1844 /* Always put our public key. This assures that we send at least
1845 something valid back always. */
1846 pk.type = "silc-rsa";
1847 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1848 buffer = silc_attribute_payload_encode(buffer,
1849 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1850 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1851 SILC_ATTRIBUTE_FLAG_INVALID,
1857 /* Finally compute the digital signature of all the data we provided
1858 as an indication that we provided rightfull information, and this
1859 also authenticates our public key. */
1860 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1861 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1862 buffer->data, buffer->len,
1866 pk.data_len = sign_len;
1868 silc_attribute_payload_encode(buffer,
1869 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1870 SILC_ATTRIBUTE_FLAG_VALID,
1879 /* Find client by the Client ID indicated by the `client_id', and if not
1880 found then query it by using WHOIS command. The client information
1881 is also resolved if the cached information is incomplete or if the
1882 `always_resolve' is set to TRUE. The indication whether requested
1883 client was being resolved is saved into `resolved'. If the client
1884 is not being resolved its entry is returned by this function. NULL
1885 is returned if client is resolved. */
1887 SilcClientEntry silc_server_query_client(SilcServer server,
1888 const SilcClientID *client_id,
1889 bool always_resolve,
1892 SilcClientEntry client;
1894 SILC_LOG_DEBUG(("Resolving client by client ID"));
1899 client = silc_idlist_find_client_by_id(server->local_list,
1900 (SilcClientID *)client_id,
1903 client = silc_idlist_find_client_by_id(server->global_list,
1904 (SilcClientID *)client_id,
1906 if (!client && server->server_type == SILC_ROUTER)
1910 if (!client && server->standalone)
1913 if (!client || !client->nickname || !client->username ||
1915 SilcBuffer buffer, idp;
1918 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1919 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1920 client->resolve_cmd_ident = ++server->cmd_ident;
1923 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1924 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1925 server->cmd_ident, 1,
1926 4, idp->data, idp->len);
1927 silc_server_packet_send(server, client ? client->router->connection :
1928 SILC_PRIMARY_ROUTE(server),
1929 SILC_PACKET_COMMAND, 0,
1930 buffer->data, buffer->len, FALSE);
1931 silc_buffer_free(idp);
1932 silc_buffer_free(buffer);