5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 1 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname, normalized */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name, normalized */
57 char *channel_name; /* Queried channel name, normalized */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `type'. If `type' is 0 the index is to query->ids, if
177 it is 1 it is index to the command context arguments, and if it is
178 2 the index is ignored and no argument is included in the error. */
180 void silc_server_query_add_error(SilcServer server,
181 SilcServerQuery query,
186 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187 (query->errors_count + 1));
190 query->errors[query->errors_count].index = index;
191 query->errors[query->errors_count].type = type;
192 query->errors[query->errors_count].error = error;
193 query->errors[query->errors_count].id = NULL;
194 query->errors[query->errors_count].id_type = 0;
195 query->errors_count++;
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199 with error sending with this error type. */
201 void silc_server_query_add_error_id(SilcServer server,
202 SilcServerQuery query,
204 void *id, SilcIdType id_type)
206 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207 (query->errors_count + 1));
210 query->errors[query->errors_count].index = 0;
211 query->errors[query->errors_count].type = 0;
212 query->errors[query->errors_count].error = error;
213 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214 query->errors[query->errors_count].id_type = id_type;
215 query->errors_count++;
218 /* Processes query as command. The `query' is the command that is
219 being processed indicated by the `cmd'. The `query' can be one of
220 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221 SILC_COMMAND_IDENTIFY. This function handles the reply sending
222 to the entity who sent this query to us automatically. Returns
223 TRUE if the query is being processed or FALSE on error. */
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226 SilcServerCommandContext cmd)
228 SilcServerQuery query;
230 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
232 query = silc_calloc(1, sizeof(*query));
233 query->querycmd = querycmd;
234 query->cmd = silc_server_command_dup(cmd);
238 case SILC_COMMAND_WHOIS:
239 /* If we are normal server and query contains nickname OR query
240 doesn't contain nickname or ids BUT attributes, send it to the
242 if (server->server_type != SILC_ROUTER && !server->standalone &&
243 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248 silc_server_query_send_router(server, query);
253 case SILC_COMMAND_WHOWAS:
254 /* WHOWAS query is always sent to router if we are normal server */
255 if (server->server_type == SILC_SERVER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_IDENTIFY:
263 /* If we are normal server and query does not contain IDs, send it
264 directly to router (it contains nickname, server name or channel
266 if (server->server_type == SILC_SERVER && !server->standalone &&
267 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269 silc_server_query_send_router(server, query);
275 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276 silc_server_query_free(query);
280 /* Now parse the request */
281 silc_server_query_parse(server, query);
286 /* Send the received query to our primary router since we could not
287 handle the query directly. We will reprocess the query after our
288 router replies back. */
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
293 SilcUInt16 old_ident;
295 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
298 server->stat.commands_sent++;
300 /* Send WHOIS command to our router */
301 old_ident = silc_command_get_ident(query->cmd->payload);
302 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
303 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
304 silc_server_packet_send(server,
305 SILC_PRIMARY_ROUTE(server),
306 SILC_PACKET_COMMAND, 0,
307 tmpbuf->data, tmpbuf->len, TRUE);
308 silc_command_set_ident(query->cmd->payload, old_ident);
309 silc_buffer_free(tmpbuf);
311 query->resolved = TRUE;
313 /* Continue parsing the query after received reply from router */
314 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
315 silc_server_query_send_router_reply, query);
318 /* Reply callback called after primary router has replied to our initial
319 sending of the query to it. We will proceed the query in this function. */
321 void silc_server_query_send_router_reply(void *context, void *reply)
323 SilcServerQuery query = context;
324 SilcServer server = query->cmd->server;
325 SilcServerCommandReplyContext cmdr = reply;
327 SILC_LOG_DEBUG(("Received reply from router to query"));
329 /* If the original command caller has gone away, just stop. */
330 if (query->cmd->sock->users == 1) {
331 SILC_LOG_DEBUG(("Original command caller vanished"));
332 silc_server_query_free(query);
336 /* Check if router sent error reply */
337 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
340 SILC_LOG_DEBUG(("Sending error to original query"));
343 server->stat.commands_sent++;
345 /* Send the same command reply payload which contains the error */
346 silc_command_set_command(cmdr->payload, query->querycmd);
347 silc_command_set_ident(cmdr->payload,
348 silc_command_get_ident(query->cmd->payload));
349 buffer = silc_command_payload_encode_payload(cmdr->payload);
350 silc_server_packet_send(server, query->cmd->sock,
351 SILC_PACKET_COMMAND_REPLY, 0,
352 buffer->data, buffer->len, FALSE);
353 silc_buffer_free(buffer);
354 silc_server_query_free(query);
358 /* Continue with parsing */
359 silc_server_query_parse(server, query);
362 /* Parse the command query and start processing the queries in detail. */
364 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
366 SilcServerCommandContext cmd = query->cmd;
368 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
373 SILC_LOG_DEBUG(("Parsing %s query",
374 silc_get_command_name(query->querycmd)));
376 switch (query->querycmd) {
378 case SILC_COMMAND_WHOIS:
379 /* Get requested attributes if set */
380 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
381 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
382 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
384 /* When Requested Attributes is present we will assure that this
385 client cannot execute the WHOIS command too fast. This would be
386 same as having SILC_CF_LAG_STRICT. */
387 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
388 cmd->sock->user_data)
389 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
392 /* Get Client IDs if present. Take IDs always instead of nickname. */
393 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
397 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
398 if (!tmp && !query->attrs) {
399 /* No nickname, no ids and no attributes - send error */
400 silc_server_query_send_error(server, query,
401 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
402 silc_server_query_free(query);
406 /* Get the nickname@server string and parse it */
407 if (tmp && ((tmp_len > 128) ||
408 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
409 silc_server_query_send_error(server, query,
410 SILC_STATUS_ERR_BAD_NICKNAME, 0);
411 silc_server_query_free(query);
417 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
418 SILC_STRING_UTF8, 128, &tmp_len);
420 silc_server_query_send_error(server, query,
421 SILC_STATUS_ERR_BAD_NICKNAME, 0);
422 silc_server_query_free(query);
425 silc_free(query->nickname);
426 query->nickname = tmp;
430 /* Parse the IDs included in the query */
431 query->ids = silc_calloc(argc, sizeof(*query->ids));
433 for (i = 0; i < argc; i++) {
434 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
438 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
439 if (!id || id_type != SILC_ID_CLIENT) {
440 silc_server_query_add_error(server, query, 1, i + 4,
441 SILC_STATUS_ERR_BAD_CLIENT_ID);
445 /* Normal server must check whether this ID exist, and if not then
446 send the query to router, unless done so already */
447 if (server->server_type == SILC_SERVER && !query->resolved) {
448 if (!silc_idlist_find_client_by_id(server->local_list,
450 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
451 !silc_idlist_find_client_by_id(server->global_list,
453 silc_server_query_send_router(server, query);
454 for (i = 0; i < query->ids_count; i++)
455 silc_free(query->ids[i].id);
456 silc_free(query->ids);
458 query->ids_count = 0;
465 query->ids[query->ids_count].id = id;
466 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
471 /* Get the max count of reply messages allowed */
472 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
473 if (tmp && tmp_len == sizeof(SilcUInt32))
474 SILC_GET32_MSB(query->reply_count, tmp);
477 case SILC_COMMAND_WHOWAS:
479 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
481 silc_server_query_send_error(server, query,
482 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
483 silc_server_query_free(query);
487 /* Get the nickname@server string and parse it */
489 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
490 silc_server_query_send_error(server, query,
491 SILC_STATUS_ERR_BAD_NICKNAME, 0);
492 silc_server_query_free(query);
497 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
498 SILC_STRING_UTF8, 128, &tmp_len);
500 silc_server_query_send_error(server, query,
501 SILC_STATUS_ERR_BAD_NICKNAME, 0);
502 silc_server_query_free(query);
505 silc_free(query->nickname);
506 query->nickname = tmp;
508 /* Get the max count of reply messages allowed */
509 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
510 if (tmp && tmp_len == sizeof(SilcUInt32))
511 SILC_GET32_MSB(query->reply_count, tmp);
514 case SILC_COMMAND_IDENTIFY:
515 /* Get IDs if present. Take IDs always instead of names. */
516 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
519 /* Try get nickname */
520 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
522 /* Get the nickname@server string and parse it */
524 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
525 silc_server_query_add_error(server, query, 1, 1,
526 SILC_STATUS_ERR_BAD_NICKNAME);
529 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
530 SILC_STRING_UTF8, 128, &tmp_len);
532 silc_server_query_send_error(server, query,
533 SILC_STATUS_ERR_BAD_NICKNAME, 0);
534 silc_server_query_free(query);
537 silc_free(query->nickname);
538 query->nickname = tmp;
541 /* Try get server name */
542 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
544 /* Check server name */
545 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
548 silc_server_query_send_error(server, query,
549 SILC_STATUS_ERR_BAD_SERVER, 0);
550 silc_server_query_free(query);
553 query->server_name = tmp;
556 /* Get channel name */
557 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
558 if (tmp && tmp_len <= 256) {
559 /* Check channel name */
560 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
563 silc_server_query_send_error(server, query,
564 SILC_STATUS_ERR_BAD_CHANNEL, 0);
565 silc_server_query_free(query);
568 query->channel_name = tmp;
571 if (!query->nickname && !query->server_name && !query->channel_name) {
572 silc_server_query_send_error(server, query,
573 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
574 silc_server_query_free(query);
579 /* Parse the IDs included in the query */
580 query->ids = silc_calloc(argc, sizeof(*query->ids));
582 for (i = 0; i < argc; i++) {
583 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
587 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
589 silc_server_query_add_error(server, query, 1, i + 5,
590 SILC_STATUS_ERR_BAD_CLIENT_ID);
594 /* Normal server must check whether this ID exist, and if not then
595 send the query to router, unless done so already */
596 if (server->server_type == SILC_SERVER && !query->resolved) {
597 if (id_type == SILC_ID_CLIENT) {
598 if (!silc_idlist_find_client_by_id(server->local_list,
600 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
601 !silc_idlist_find_client_by_id(server->global_list,
603 silc_server_query_send_router(server, query);
604 for (i = 0; i < query->ids_count; i++)
605 silc_free(query->ids[i].id);
606 silc_free(query->ids);
608 query->ids_count = 0;
614 /* For now all other ID's except Client ID's are explicitly
615 sent to router for resolving. */
616 silc_server_query_send_router(server, query);
617 for (i = 0; i < query->ids_count; i++)
618 silc_free(query->ids[i].id);
619 silc_free(query->ids);
621 query->ids_count = 0;
627 query->ids[query->ids_count].id = id;
628 query->ids[query->ids_count].id_type = id_type;
633 /* Get the max count of reply messages allowed */
634 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
635 if (tmp && tmp_len == sizeof(SilcUInt32))
636 SILC_GET32_MSB(query->reply_count, tmp);
640 /* Start processing the query information */
641 silc_server_query_process(server, query, TRUE);
644 /* Context for holding clients searched by public key. */
646 SilcClientEntry **clients;
647 SilcUInt32 *clients_count;
649 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
651 void silc_server_public_key_hash_foreach(void *key, void *context,
654 SilcServerPublicKeyUser uc = user_context;
655 SilcClientEntry entry = context;
657 /* Nothing was found, just return */
663 (*uc->clients) = silc_realloc((*uc->clients),
664 sizeof((**uc->clients)) *
665 ((*uc->clients_count) + 1));
666 (*uc->clients)[(*uc->clients_count)++] = entry;
669 /* If clients are set, limit the found clients using the attributes in
670 the query. If clients are not set, try to find some clients using
673 void silc_server_query_check_attributes(SilcServer server,
674 SilcServerQuery query,
675 SilcClientEntry **clients,
676 SilcUInt32 *clients_count) {
677 SilcClientEntry entry;
678 SilcAttributePayload attr;
679 SilcAttribute attribute;
680 SilcAttributeObjPk pk;
681 SilcPublicKey publickey;
683 bool found = FALSE, no_clients = FALSE;
685 /* If no clients were found, we only check the attributes
686 if the user wasn't searching for nickname/ids */
689 if (query->nickname || query->ids_count)
693 silc_dlist_start(query->attrs);
694 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
695 attribute = silc_attribute_get_attribute(attr);
698 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
699 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
701 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
704 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
711 /* If no clients were set on calling this function, we
712 just search for clients, otherwise we try to limit
715 SilcServerPublicKeyUserStruct usercontext;
717 usercontext.clients = clients;
718 usercontext.clients_count = clients_count;
719 usercontext.found = FALSE;
721 silc_hash_table_find_foreach(server->pk_hash, publickey,
722 silc_server_public_key_hash_foreach,
725 if (usercontext.found == TRUE)
728 for (i = 0; i < *clients_count; i++) {
729 entry = (*clients)[i];
731 if (!entry->data.public_key)
734 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
736 (*clients)[i] = NULL;
743 silc_pkcs_public_key_free(publickey);
748 if (!found && !query->nickname && !query->ids)
749 silc_server_query_add_error(server, query, 2, 0,
750 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
753 /* Processes the parsed query. This does the actual finding of the
754 queried information and prepares for sending reply to the original
755 sender of the query command. */
757 void silc_server_query_process(SilcServer server, SilcServerQuery query,
760 SilcServerCommandContext cmd = query->cmd;
761 bool check_global = FALSE;
763 SilcClientEntry *clients = NULL, client_entry;
764 SilcChannelEntry *channels = NULL;
765 SilcServerEntry *servers = NULL;
766 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
769 SILC_LOG_DEBUG(("Processing %s query",
770 silc_get_command_name(query->querycmd)));
772 /* Check global lists if query is coming from client or we are not
773 normal server (we know global information). */
774 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
776 else if (server->server_type != SILC_SERVER)
779 if (query->nickname) {
780 /* Get all clients matching nickname from local list */
781 if (!silc_idlist_get_clients_by_hash(server->local_list,
782 query->nickname, server->md5hash,
783 &clients, &clients_count))
784 silc_idlist_get_clients_by_nickname(server->local_list,
787 &clients, &clients_count);
789 /* Check global list as well */
791 if (!silc_idlist_get_clients_by_hash(server->global_list,
792 query->nickname, server->md5hash,
793 &clients, &clients_count))
794 silc_idlist_get_clients_by_nickname(server->global_list,
797 &clients, &clients_count);
801 silc_server_query_add_error(server, query, 1, 1,
802 SILC_STATUS_ERR_NO_SUCH_NICK);
805 if (query->server_name) {
806 /* Find server by name */
807 entry = silc_idlist_find_server_by_name(server->local_list,
808 query->server_name, TRUE, NULL);
809 if (!entry && check_global)
810 entry = silc_idlist_find_server_by_name(server->global_list,
811 query->server_name, TRUE, NULL);
813 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
814 servers[servers_count++] = (SilcServerEntry)entry;
818 silc_server_query_add_error(server, query, 1, 2,
819 SILC_STATUS_ERR_NO_SUCH_SERVER);
822 if (query->channel_name) {
823 /* Find channel by name */
824 entry = silc_idlist_find_channel_by_name(server->local_list,
825 query->channel_name, NULL);
826 if (!entry && check_global)
827 entry = silc_idlist_find_channel_by_name(server->global_list,
828 query->channel_name, NULL);
830 channels = silc_realloc(channels, sizeof(*channels) *
831 (channels_count + 1));
832 channels[channels_count++] = (SilcChannelEntry)entry;
836 silc_server_query_add_error(server, query, 1, 3,
837 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
840 if (query->ids_count) {
841 /* Find entries by the queried IDs */
842 for (i = 0; i < query->ids_count; i++) {
843 void *id = query->ids[i].id;
847 switch (query->ids[i].id_type) {
850 /* Get client entry */
851 entry = silc_idlist_find_client_by_id(server->local_list,
853 if (!entry && check_global)
854 entry = silc_idlist_find_client_by_id(server->global_list,
857 silc_server_query_add_error(server, query, 0, i,
858 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
862 clients = silc_realloc(clients, sizeof(*clients) *
863 (clients_count + 1));
864 clients[clients_count++] = (SilcClientEntry)entry;
868 /* Get server entry */
869 entry = silc_idlist_find_server_by_id(server->local_list,
871 if (!entry && check_global)
872 entry = silc_idlist_find_server_by_id(server->global_list,
875 silc_server_query_add_error(server, query, 0, i,
876 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
880 servers = silc_realloc(servers, sizeof(*servers) *
881 (servers_count + 1));
882 servers[servers_count++] = (SilcServerEntry)entry;
885 case SILC_ID_CHANNEL:
886 /* Get channel entry */
887 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
888 if (!entry && check_global)
889 entry = silc_idlist_find_channel_by_id(server->global_list, id,
892 silc_server_query_add_error(server, query, 0, i,
893 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
897 channels = silc_realloc(channels, sizeof(*channels) *
898 (channels_count + 1));
899 channels[channels_count++] = (SilcChannelEntry)entry;
908 /* Check the attributes to narrow down the search by using them. */
910 silc_server_query_check_attributes(server, query, &clients,
913 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
914 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
915 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
917 /* If nothing was found, then just send the errors */
918 if (!clients && !channels && !servers) {
919 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
923 /* If caller does not want us to resolve anything (has resolved already)
924 then just continue with sending the reply */
926 silc_server_query_send_reply(server, query, clients, clients_count,
927 servers, servers_count, channels,
935 /* Now process all found information and if necessary do some more
937 switch (query->querycmd) {
939 case SILC_COMMAND_WHOIS:
940 for (i = 0; i < clients_count; i++) {
941 client_entry = clients[i];
943 /* Check if cannot query this anyway, so take next one */
945 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
948 /* If Requested Attributes is set then we always resolve the client
949 information, if not then check whether the entry is complete or not
950 and decide whether we need to resolve or not. */
953 /* Even if nickname and stuff are present, we may need to resolve
955 if (client_entry->nickname && client_entry->username &&
956 client_entry->userinfo) {
957 /* Check if cannot query this anyway, so take next one */
958 if (!client_entry->router)
961 /* If we are router, client is local to us, or client is on channel
962 we do not need to resolve the client information. */
963 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
964 || silc_hash_table_count(client_entry->channels) ||
970 /* Remove the NOATTR status periodically */
971 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
972 client_entry->updated + 600 < time(NULL))
973 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
975 /* When requested attributes is present and local client is detached
976 we cannot send the command to the client, we'll reply on behalf of
977 the client instead. */
978 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
979 (client_entry->mode & SILC_UMODE_DETACHED ||
980 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
983 /* If attributes are present in query, and in the entry and we have
984 done resolvings already we don't need to resolve anymore */
985 if (query->resolved && query->attrs && client_entry->attrs)
988 /* Resolve the detailed client information. If client is local we
989 know that attributes were present and we will resolve directly
990 from the client. Otherwise resolve from client's owner. */
991 silc_server_query_resolve(server, query,
992 (SILC_IS_LOCAL(client_entry) ?
993 client_entry->connection :
994 client_entry->router->connection),
999 case SILC_COMMAND_WHOWAS:
1000 for (i = 0; i < clients_count; i++) {
1001 client_entry = clients[i];
1003 /* Check if cannot query this anyway, so take next one */
1004 if (!client_entry || !client_entry->router ||
1005 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1008 /* If both nickname and username are present no resolving is needed */
1009 if (client_entry->nickname && client_entry->username)
1012 /* Resolve the detailed client information */
1013 silc_server_query_resolve(server, query,
1014 client_entry->router->connection,
1019 case SILC_COMMAND_IDENTIFY:
1020 for (i = 0; i < clients_count; i++) {
1021 client_entry = clients[i];
1023 /* Check if cannot query this anyway, so take next one */
1024 if (!client_entry || !client_entry->router ||
1025 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1028 /* Even if nickname is present, we may need to resolve the entry */
1029 if (client_entry->nickname) {
1031 /* If we are router, client is local to us, or client is on channel
1032 we do not need to resolve the client information. */
1033 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1034 || silc_hash_table_count(client_entry->channels) ||
1039 /* Resolve the detailed client information */
1040 silc_server_query_resolve(server, query,
1041 client_entry->router->connection,
1047 if (!query->queries_count)
1048 /* If we didn't have to do any resolving, continue with sending the
1049 command reply to the original sender. */
1050 silc_server_query_send_reply(server, query, clients, clients_count,
1051 servers, servers_count, channels,
1054 /* Now actually send the resolvings we gathered earlier */
1055 silc_server_query_resolve(server, query, NULL, NULL);
1059 silc_free(channels);
1062 /* Resolve the detailed information for the `client_entry'. Only client
1063 information needs to be resolved for being incomplete. Each incomplete
1064 client entry calls this function to do the resolving. */
1066 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1067 SilcSocketConnection sock,
1068 SilcClientEntry client_entry)
1070 SilcServerCommandContext cmd = query->cmd;
1071 SilcServerQueryList r = NULL;
1078 if (!sock && client_entry)
1081 /* If arguments are NULL we will now actually send the resolvings
1082 that earlier has been gathered by calling this function. */
1083 if (!sock && !client_entry) {
1086 SILC_LOG_DEBUG(("Sending the resolvings"));
1088 /* WHOWAS resolving has been done at the same time this function
1089 was called to add the resolving for WHOWAS, so just return. */
1090 if (query->querycmd == SILC_COMMAND_WHOWAS)
1093 for (i = 0; i < query->querylist_count; i++) {
1094 r = &query->querylist[i];
1096 /* If Requested Attributes were present put them to this resolving */
1097 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1099 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1100 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1101 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1103 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1105 r->arg[r->argc] = silc_memdup(tmp, len);
1106 r->arg_lens[r->argc] = len;
1107 r->arg_types[r->argc] = 3;
1112 server->stat.commands_sent++;
1114 /* Send WHOIS command */
1115 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1116 r->argc, r->arg, r->arg_lens,
1117 r->arg_types, r->ident);
1118 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1119 res_cmd->data, res_cmd->len, FALSE);
1120 silc_buffer_free(res_cmd);
1122 /* Reprocess this packet after received reply */
1123 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1125 silc_server_query_resolve_reply,
1127 query->queries_left++;
1130 /* Cleanup this temporary context */
1131 for (i = 0; i < query->querylist_count; i++) {
1133 for (k = 0; k < query->querylist[i].argc; k++)
1134 silc_free(query->querylist[i].arg[k]);
1135 silc_free(query->querylist[i].arg);
1136 silc_free(query->querylist[i].arg_lens);
1137 silc_free(query->querylist[i].arg_types);
1139 silc_free(query->querylist);
1140 query->querylist = NULL;
1141 query->querylist_count = 0;
1145 SILC_LOG_DEBUG(("Resolving client information"));
1147 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1148 /* The entry is being resolved by some other external query already.
1149 Attach to that query instead of resolving again. */
1150 ident = client_entry->resolve_cmd_ident;
1151 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1152 silc_server_query_resolve_reply, query))
1153 query->queries_left++;
1155 /* This entry will be resolved */
1156 ident = ++server->cmd_ident;
1158 switch (query->querycmd) {
1160 case SILC_COMMAND_WHOIS:
1161 case SILC_COMMAND_IDENTIFY:
1162 /* Take existing query context if exist for this connection */
1163 for (i = 0; i < query->querylist_count; i++)
1164 if (query->querylist[i].sock == sock) {
1165 r = &query->querylist[i];
1170 /* Allocate new temp query list context */
1171 query->querylist = silc_realloc(query->querylist,
1172 sizeof(*query->querylist) *
1173 (query->querylist_count + 1));
1174 r = &query->querylist[query->querylist_count];
1175 query->querylist_count++;
1176 memset(r, 0, sizeof(*r));
1179 if (SILC_IS_LOCAL(client_entry))
1184 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1185 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1186 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1188 /* Add the client entry to be resolved */
1189 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1190 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1191 r->arg_lens[r->argc] = idp->len;
1192 r->arg_types[r->argc] = r->argc + 4;
1194 silc_buffer_free(idp);
1198 case SILC_COMMAND_WHOWAS:
1199 /* We must send WHOWAS command since it's the only the way of
1200 resolving clients that are not present in the network anymore. */
1201 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1202 1, query->nickname, strlen(query->nickname));
1203 if (silc_server_command_pending(server, query->querycmd, ident,
1204 silc_server_query_resolve_reply, query))
1205 query->queries_left++;
1210 /* Mark the entry as being resolved */
1211 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1212 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1213 client_entry->resolve_cmd_ident = ident;
1214 client_entry->updated = time(NULL);
1216 /* Save the queried ID, which we will reprocess after we get this and
1217 all other queries back. */
1218 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1219 (query->queries_count + 1));
1220 if (query->queries) {
1221 i = query->queries_count;
1222 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1223 query->queries[i].id_type = SILC_ID_CLIENT;
1224 query->queries[i].ident = ident;
1225 query->queries_count++;
1229 /* Reply callback called after one resolving has been completed. If
1230 all resolvings has been received then we will continue with sending
1231 the command reply to the original sender of the query. */
1233 void silc_server_query_resolve_reply(void *context, void *reply)
1235 SilcServerQuery query = context;
1236 SilcServer server = query->cmd->server;
1237 SilcServerCommandReplyContext cmdr = reply;
1238 SilcUInt16 ident = cmdr->ident;
1239 SilcStatus error = SILC_STATUS_OK;
1240 SilcServerQueryID id = NULL;
1241 SilcClientEntry client_entry;
1244 /* One less query left */
1245 query->queries_left--;
1247 silc_command_get_status(cmdr->payload, NULL, &error);
1248 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1249 query->queries_left, error));
1251 /* If no error then skip to other stuff */
1252 if (error == SILC_STATUS_OK)
1255 /* Error occurred during resolving */
1257 /* Find the resolved client ID */
1258 for (i = 0; i < query->queries_count; i++) {
1259 if (query->queries[i].ident != ident)
1262 id = &query->queries[i];
1264 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1266 /* If timeout occurred for local entry when resolving attributes
1267 mark that this client doesn't support attributes in WHOIS. This
1268 assures we won't send the request again to the client. */
1269 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1270 client_entry = silc_idlist_find_client_by_id(server->local_list,
1271 id->id, TRUE, NULL);
1272 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1273 silc_id_render(id->id, SILC_ID_CLIENT)));
1274 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1275 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1276 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1281 /* Remove the RESOLVING status from the client entry */
1282 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1283 client_entry = silc_idlist_find_client_by_id(server->local_list,
1284 id->id, TRUE, NULL);
1286 client_entry = silc_idlist_find_client_by_id(server->global_list,
1287 id->id, TRUE, NULL);
1289 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1296 /* If there are queries left then wait for them */
1297 if (query->queries_left)
1300 SILC_LOG_DEBUG(("Reprocess the query"));
1302 /* If the original command caller has gone away, just stop. */
1303 if (query->cmd->sock->users == 1) {
1304 SILC_LOG_DEBUG(("Original command caller vanished"));
1305 silc_server_query_free(query);
1309 /* We have received all queries. Now re-search all information required
1310 to complete this query. Reason we cannot save the values found in
1311 the first search is that SilcClientEntry, SilcServerEntry and
1312 SilcChannelEntry pointers may become invalid while we were waiting
1313 for these resolvings. */
1314 silc_server_query_process(server, query, FALSE);
1317 /* Send the reply to the original query. If arguments are NULL then this
1318 sends only the errors that has occurred during the processing of the
1319 query. This sends the errors always after sending all the found
1320 information. The query is over after this function returns and the
1321 `query' will become invalid. This is called only after all informations
1322 has been resolved. This means that if something is not found or is
1323 incomplete in this function we were unable to resolve the information
1324 or it does not exist at all. */
1326 void silc_server_query_send_reply(SilcServer server,
1327 SilcServerQuery query,
1328 SilcClientEntry *clients,
1329 SilcUInt32 clients_count,
1330 SilcServerEntry *servers,
1331 SilcUInt32 servers_count,
1332 SilcChannelEntry *channels,
1333 SilcUInt32 channels_count)
1335 SilcServerCommandContext cmd = query->cmd;
1336 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1341 int i, k, valid_count;
1342 char nh[384], uh[384];
1343 bool sent_reply = FALSE;
1345 SILC_LOG_DEBUG(("Sending reply to query"));
1346 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1347 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1348 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1349 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1351 status = SILC_STATUS_OK;
1354 if (clients_count) {
1355 SilcClientEntry entry;
1356 SilcSocketConnection hsock;
1358 /* Mark all invalid entries */
1359 for (i = 0, valid_count = 0; i < clients_count; i++) {
1364 switch (query->querycmd) {
1365 case SILC_COMMAND_WHOIS:
1366 if (!entry->nickname || !entry->username || !entry->userinfo ||
1367 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1368 /* When querying by ID, every "unfound" entry must cause error */
1370 silc_server_query_add_error_id(server, query,
1371 SILC_STATUS_ERR_TIMEDOUT,
1372 entry->id, SILC_ID_CLIENT);
1378 case SILC_COMMAND_IDENTIFY:
1379 if (!entry->nickname ||
1380 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1381 /* When querying by ID, every "unfound" entry must cause error */
1383 silc_server_query_add_error_id(server, query,
1384 SILC_STATUS_ERR_TIMEDOUT,
1385 entry->id, SILC_ID_CLIENT);
1391 case SILC_COMMAND_WHOWAS:
1392 if (!entry->nickname || !entry->username ||
1393 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1402 /* Start processing found clients */
1403 status = SILC_STATUS_OK;
1404 if (valid_count > 1)
1405 status = SILC_STATUS_LIST_START;
1407 /* Now do the sending of valid entries */
1409 for (i = 0; i < clients_count && valid_count; i++) {
1415 status = SILC_STATUS_LIST_ITEM;
1416 if (valid_count > 1 && k == valid_count - 1
1417 && !servers_count && !channels_count && !query->errors_count)
1418 status = SILC_STATUS_LIST_END;
1419 if (query->reply_count && k - 1 == query->reply_count)
1420 status = SILC_STATUS_LIST_END;
1422 SILC_LOG_DEBUG(("%s: client %s",
1423 (status == SILC_STATUS_OK ? " OK" :
1424 status == SILC_STATUS_LIST_START ? "START" :
1425 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1426 status == SILC_STATUS_LIST_END ? " END" :
1427 " : "), entry->nickname));
1429 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1430 memset(nh, 0, sizeof(nh));
1432 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1433 if (!strchr(entry->nickname, '@')) {
1434 silc_strncat(nh, sizeof(nh), "@", 1);
1435 if (entry->servername) {
1436 silc_strncat(nh, sizeof(nh), entry->servername,
1437 strlen(entry->servername));
1439 len = entry->router ? strlen(entry->router->server_name) :
1440 strlen(server->server_name);
1441 silc_strncat(nh, sizeof(nh), entry->router ?
1442 entry->router->server_name :
1443 server->server_name, len);
1447 switch (query->querycmd) {
1449 case SILC_COMMAND_WHOIS:
1451 unsigned char idle[4], mode[4];
1452 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1453 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1455 memset(fempty, 0, sizeof(fempty));
1456 memset(idle, 0, sizeof(idle));
1457 memset(uh, 0, sizeof(uh));
1459 silc_strncat(uh, sizeof(uh), entry->username,
1460 strlen(entry->username));
1461 if (!strchr(entry->username, '@') && entry->connection) {
1462 hsock = entry->connection;
1463 silc_strncat(uh, sizeof(uh), "@", 1);
1464 len = strlen(hsock->hostname);
1465 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1468 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1470 silc_server_get_client_channel_list(server, entry, FALSE,
1471 FALSE, &umode_list);
1474 silc_server_get_client_channel_list(server, entry, TRUE,
1477 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1478 fingerprint = entry->data.fingerprint;
1482 SILC_PUT32_MSB(entry->mode, mode);
1483 if (entry->connection)
1484 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1486 /* If Requested Attribute were present, and we do not have the
1487 attributes we will reply to them on behalf of the client. */
1490 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1491 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1492 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1493 entry->attrs_len = len;
1494 silc_buffer_free(tmpattrs);
1496 attrs = entry->attrs;
1497 len = entry->attrs_len;
1500 /* Send command reply */
1501 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1502 status, 0, ident, 10,
1503 2, idp->data, idp->len,
1507 strlen(entry->userinfo),
1508 6, channels ? channels->data : NULL,
1509 channels ? channels->len : 0,
1513 fingerprint ? 20 : 0,
1514 10, umode_list ? umode_list->data :
1515 NULL, umode_list ? umode_list->len :
1520 /* For now we always delete Requested Attributes, unless the client
1521 is detached, in which case we don't want to reconstruct the
1522 same data everytime */
1523 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1524 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1525 silc_free(entry->attrs);
1526 entry->attrs = NULL;
1530 silc_buffer_free(channels);
1532 silc_buffer_free(umode_list);
1538 case SILC_COMMAND_IDENTIFY:
1539 if (!entry->username) {
1540 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1541 status, 0, ident, 2,
1542 2, idp->data, idp->len,
1546 memset(uh, 0, sizeof(uh));
1547 silc_strncat(uh, sizeof(uh), entry->username,
1548 strlen(entry->username));
1549 if (!strchr(entry->username, '@') && entry->connection) {
1550 hsock = entry->connection;
1551 silc_strncat(uh, sizeof(uh), "@", 1);
1552 len = strlen(hsock->hostname);
1553 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1556 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1557 status, 0, ident, 3,
1558 2, idp->data, idp->len,
1565 case SILC_COMMAND_WHOWAS:
1566 memset(uh, 0, sizeof(uh));
1567 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1568 if (!strchr(entry->username, '@'))
1569 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1571 /* Send command reply */
1572 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1573 status, 0, ident, 4,
1574 2, idp->data, idp->len,
1579 strlen(entry->userinfo) : 0);
1584 silc_buffer_free(idp);
1586 if (status == SILC_STATUS_LIST_END)
1592 /* Not one valid entry was found, send error. If nickname was used
1593 in query send error based on that, otherwise the query->errors
1594 already includes proper errors. */
1595 if (query->nickname || (!query->ids && query->attrs))
1596 silc_server_query_add_error(server, query, 1, 1,
1597 SILC_STATUS_ERR_NO_SUCH_NICK);
1599 /* Make sure some error is sent */
1600 if (!query->errors_count && !servers_count && !channels_count)
1601 silc_server_query_add_error(server, query, 2, 0,
1602 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1607 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1608 SilcServerEntry entry;
1610 if (status == SILC_STATUS_OK && servers_count > 1)
1611 status = SILC_STATUS_LIST_START;
1614 for (i = 0; i < servers_count; i++) {
1618 status = SILC_STATUS_LIST_ITEM;
1619 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1620 !query->errors_count)
1621 status = SILC_STATUS_LIST_END;
1622 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1623 !query->errors_count)
1624 status = SILC_STATUS_LIST_END;
1625 if (query->reply_count && k - 1 == query->reply_count)
1626 status = SILC_STATUS_LIST_END;
1628 SILC_LOG_DEBUG(("%s: server %s",
1629 (status == SILC_STATUS_OK ? " OK" :
1630 status == SILC_STATUS_LIST_START ? "START" :
1631 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1632 status == SILC_STATUS_LIST_END ? " END" :
1634 entry->server_name ? entry->server_name : ""));
1636 /* Send command reply */
1637 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1638 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1639 status, 0, ident, 2,
1640 2, idp->data, idp->len,
1641 3, entry->server_name,
1642 entry->server_name ?
1643 strlen(entry->server_name) : 0);
1644 silc_buffer_free(idp);
1647 if (status == SILC_STATUS_LIST_END)
1654 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1655 SilcChannelEntry entry;
1657 if (status == SILC_STATUS_OK && channels_count > 1)
1658 status = SILC_STATUS_LIST_START;
1661 for (i = 0; i < channels_count; i++) {
1662 entry = channels[i];
1665 status = SILC_STATUS_LIST_ITEM;
1666 if (channels_count == 1 && status != SILC_STATUS_OK &&
1667 !query->errors_count)
1668 status = SILC_STATUS_LIST_END;
1669 if (channels_count > 1 && k == channels_count - 1 &&
1670 !query->errors_count)
1671 status = SILC_STATUS_LIST_END;
1672 if (query->reply_count && k - 1 == query->reply_count)
1673 status = SILC_STATUS_LIST_END;
1675 SILC_LOG_DEBUG(("%s: channel %s",
1676 (status == SILC_STATUS_OK ? " OK" :
1677 status == SILC_STATUS_LIST_START ? "START" :
1678 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1679 status == SILC_STATUS_LIST_END ? " END" :
1681 entry->channel_name ? entry->channel_name : ""));
1683 /* Send command reply */
1684 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1685 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1686 status, 0, ident, 2,
1687 2, idp->data, idp->len,
1688 3, entry->channel_name,
1689 entry->channel_name ?
1690 strlen(entry->channel_name) : 0);
1691 silc_buffer_free(idp);
1694 if (status == SILC_STATUS_LIST_END)
1701 if (query->errors_count) {
1704 if (status == SILC_STATUS_OK && query->errors_count > 1)
1705 status = SILC_STATUS_LIST_START;
1708 for (i = 0; i < query->errors_count; i++) {
1711 /* Take error argument */
1712 if (query->errors[i].type == 1) {
1713 /* Take from sent arguments */
1715 tmp = silc_argument_get_arg_type(cmd->args,
1716 query->errors[i].index, &len);
1718 } else if (query->errors[i].type == 2) {
1723 } else if (!query->errors[i].id) {
1724 /* Take from query->ids */
1726 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1727 query->ids[query->errors[k].index].id_type);
1732 /* Take added ID. */
1733 idp = silc_id_payload_encode(query->errors[i].id,
1734 query->errors[k].id_type);
1741 status = SILC_STATUS_LIST_ITEM;
1742 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1743 status = SILC_STATUS_LIST_END;
1744 if (query->errors_count > 1 && k == query->errors_count - 1)
1745 status = SILC_STATUS_LIST_END;
1746 if (query->reply_count && k - 1 == query->reply_count)
1747 status = SILC_STATUS_LIST_END;
1749 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1750 (status == SILC_STATUS_OK ? " OK" :
1751 status == SILC_STATUS_LIST_START ? "START" :
1752 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1753 status == SILC_STATUS_LIST_END ? " END" :
1755 silc_get_status_message(query->errors[i].error),
1756 query->errors[i].error));
1758 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1759 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1761 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1762 (status == SILC_STATUS_OK ?
1763 query->errors[i].error : status),
1764 (status == SILC_STATUS_OK ?
1765 0 : query->errors[i].error), ident, 2,
1771 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1772 (status == SILC_STATUS_OK ?
1773 query->errors[i].error : status),
1774 (status == SILC_STATUS_OK ?
1775 0 : query->errors[i].error), ident, 1,
1778 silc_buffer_free(idp);
1781 if (status == SILC_STATUS_LIST_END)
1788 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1791 silc_server_query_free(query);
1794 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1795 of the client since we were unable to resolve them from the client.
1796 Either client does not support Requested Attributes or isn't replying
1797 to them like it should. */
1799 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1800 SilcServerQuery query,
1801 SilcClientEntry client_entry)
1803 SilcBuffer buffer = NULL;
1804 SilcAttribute attribute;
1805 SilcAttributePayload attr;
1806 SilcAttributeObjPk pk;
1807 SilcAttributeObjService service;
1809 unsigned char sign[2048 + 1];
1810 SilcUInt32 sign_len;
1812 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1814 /* Go through all requested attributes */
1815 silc_dlist_start(query->attrs);
1816 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1817 attribute = silc_attribute_get_attribute(attr);
1818 switch (attribute) {
1820 case SILC_ATTRIBUTE_SERVICE:
1821 /* Put SERVICE. Put only SILC service. */
1822 memset(&service, 0, sizeof(service));
1823 service.port = (server->config->server_info->primary ?
1824 server->config->server_info->primary->port : SILC_PORT);
1825 silc_strncat(service.address, sizeof(service.address),
1826 server->server_name, strlen(server->server_name));
1827 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1828 if (client_entry->connection)
1829 service.idle = time(NULL) - client_entry->data.last_receive;
1830 buffer = silc_attribute_payload_encode(buffer, attribute,
1831 SILC_ATTRIBUTE_FLAG_VALID,
1832 &service, sizeof(service));
1837 case SILC_ATTRIBUTE_STATUS_MOOD:
1838 /* Put STATUS_MOOD */
1839 buffer = silc_attribute_payload_encode(buffer, attribute,
1840 SILC_ATTRIBUTE_FLAG_VALID,
1842 SILC_ATTRIBUTE_MOOD_NORMAL,
1843 sizeof(SilcUInt32));
1848 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1849 /* Put STATUS_FREETEXT. We just tell in the message that we are
1850 replying on behalf of the client. */
1852 "This information was provided by the server on behalf of the user";
1853 buffer = silc_attribute_payload_encode(buffer, attribute,
1854 SILC_ATTRIBUTE_FLAG_VALID,
1860 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1861 /* Put PREFERRED_CONTACT */
1862 buffer = silc_attribute_payload_encode(buffer, attribute,
1863 SILC_ATTRIBUTE_FLAG_VALID,
1865 SILC_ATTRIBUTE_CONTACT_CHAT,
1866 sizeof(SilcUInt32));
1871 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1872 /* Put USER_PUBLIC_KEY */
1873 if (client_entry->data.public_key) {
1874 pk.type = "silc-rsa";
1875 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1877 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1878 SILC_ATTRIBUTE_FLAG_VALID :
1879 SILC_ATTRIBUTE_FLAG_INVALID,
1887 /* No public key available */
1888 buffer = silc_attribute_payload_encode(buffer, attribute,
1889 SILC_ATTRIBUTE_FLAG_INVALID,
1896 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1897 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1898 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1901 /* For other attributes we cannot reply so mark it invalid */
1902 buffer = silc_attribute_payload_encode(buffer, attribute,
1903 SILC_ATTRIBUTE_FLAG_INVALID,
1911 /* Always put our public key. This assures that we send at least
1912 something valid back always. */
1913 pk.type = "silc-rsa";
1914 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1915 buffer = silc_attribute_payload_encode(buffer,
1916 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1917 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1918 SILC_ATTRIBUTE_FLAG_INVALID,
1924 /* Finally compute the digital signature of all the data we provided
1925 as an indication that we provided rightfull information, and this
1926 also authenticates our public key. */
1927 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1928 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1929 buffer->data, buffer->len,
1933 pk.data_len = sign_len;
1935 silc_attribute_payload_encode(buffer,
1936 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1937 SILC_ATTRIBUTE_FLAG_VALID,
1946 /* Find client by the Client ID indicated by the `client_id', and if not
1947 found then query it by using WHOIS command. The client information
1948 is also resolved if the cached information is incomplete or if the
1949 `always_resolve' is set to TRUE. The indication whether requested
1950 client was being resolved is saved into `resolved'. If the client
1951 is not being resolved its entry is returned by this function. NULL
1952 is returned if client is resolved. */
1954 SilcClientEntry silc_server_query_client(SilcServer server,
1955 const SilcClientID *client_id,
1956 bool always_resolve,
1959 SilcClientEntry client;
1961 SILC_LOG_DEBUG(("Resolving client by client ID"));
1966 client = silc_idlist_find_client_by_id(server->local_list,
1967 (SilcClientID *)client_id,
1970 client = silc_idlist_find_client_by_id(server->global_list,
1971 (SilcClientID *)client_id,
1973 if (!client && server->server_type == SILC_ROUTER)
1977 if (!client && server->standalone)
1980 if (!client || !client->nickname || !client->username ||
1982 SilcBuffer buffer, idp;
1985 server->stat.commands_sent++;
1988 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1989 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1990 client->resolve_cmd_ident = ++server->cmd_ident;
1993 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1994 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1995 server->cmd_ident, 1,
1996 4, idp->data, idp->len);
1997 silc_server_packet_send(server, client ? client->router->connection :
1998 SILC_PRIMARY_ROUTE(server),
1999 SILC_PACKET_COMMAND, 0,
2000 buffer->data, buffer->len, FALSE);
2001 silc_buffer_free(idp);
2002 silc_buffer_free(buffer);