5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 1 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname, normalized */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name, normalized */
57 char *channel_name; /* Queried channel name, normalized */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `type'. If `type' is 0 the index is to query->ids, if
177 it is 1 it is index to the command context arguments, and if it is
178 2 the index is ignored and no argument is included in the error. */
180 void silc_server_query_add_error(SilcServer server,
181 SilcServerQuery query,
186 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187 (query->errors_count + 1));
190 query->errors[query->errors_count].index = index;
191 query->errors[query->errors_count].type = type;
192 query->errors[query->errors_count].error = error;
193 query->errors[query->errors_count].id = NULL;
194 query->errors[query->errors_count].id_type = 0;
195 query->errors_count++;
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199 with error sending with this error type. */
201 void silc_server_query_add_error_id(SilcServer server,
202 SilcServerQuery query,
204 void *id, SilcIdType id_type)
206 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207 (query->errors_count + 1));
210 query->errors[query->errors_count].index = 0;
211 query->errors[query->errors_count].type = 0;
212 query->errors[query->errors_count].error = error;
213 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214 query->errors[query->errors_count].id_type = id_type;
215 query->errors_count++;
218 /* Processes query as command. The `query' is the command that is
219 being processed indicated by the `cmd'. The `query' can be one of
220 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221 SILC_COMMAND_IDENTIFY. This function handles the reply sending
222 to the entity who sent this query to us automatically. Returns
223 TRUE if the query is being processed or FALSE on error. */
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226 SilcServerCommandContext cmd)
228 SilcServerQuery query;
230 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
232 query = silc_calloc(1, sizeof(*query));
233 query->querycmd = querycmd;
234 query->cmd = silc_server_command_dup(cmd);
238 case SILC_COMMAND_WHOIS:
239 /* If we are normal server and query contains nickname OR query
240 doesn't contain nickname or ids BUT attributes, send it to the
242 if (server->server_type != SILC_ROUTER && !server->standalone &&
243 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248 silc_server_query_send_router(server, query);
253 case SILC_COMMAND_WHOWAS:
254 /* WHOWAS query is always sent to router if we are normal server */
255 if (server->server_type == SILC_SERVER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_IDENTIFY:
263 /* If we are normal server and query does not contain IDs, send it
264 directly to router (it contains nickname, server name or channel
266 if (server->server_type == SILC_SERVER && !server->standalone &&
267 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269 silc_server_query_send_router(server, query);
275 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276 silc_server_query_free(query);
280 /* Now parse the request */
281 silc_server_query_parse(server, query);
286 /* Send the received query to our primary router since we could not
287 handle the query directly. We will reprocess the query after our
288 router replies back. */
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
293 SilcUInt16 old_ident;
295 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
297 /* Send WHOIS command to our router */
298 old_ident = silc_command_get_ident(query->cmd->payload);
299 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
300 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
301 silc_server_packet_send(server,
302 SILC_PRIMARY_ROUTE(server),
303 SILC_PACKET_COMMAND, 0,
304 tmpbuf->data, tmpbuf->len, TRUE);
305 silc_command_set_ident(query->cmd->payload, old_ident);
306 silc_buffer_free(tmpbuf);
308 query->resolved = TRUE;
310 /* Continue parsing the query after received reply from router */
311 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
312 silc_server_query_send_router_reply, query);
315 /* Reply callback called after primary router has replied to our initial
316 sending of the query to it. We will proceed the query in this function. */
318 void silc_server_query_send_router_reply(void *context, void *reply)
320 SilcServerQuery query = context;
321 SilcServer server = query->cmd->server;
322 SilcServerCommandReplyContext cmdr = reply;
324 SILC_LOG_DEBUG(("Received reply from router to query"));
326 /* If the original command caller has gone away, just stop. */
327 if (query->cmd->sock->users == 1) {
328 SILC_LOG_DEBUG(("Original command caller vanished"));
329 silc_server_query_free(query);
333 /* Check if router sent error reply */
334 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
337 SILC_LOG_DEBUG(("Sending error to original query"));
339 /* Send the same command reply payload which contains the error */
340 silc_command_set_command(cmdr->payload, query->querycmd);
341 silc_command_set_ident(cmdr->payload,
342 silc_command_get_ident(query->cmd->payload));
343 buffer = silc_command_payload_encode_payload(cmdr->payload);
344 silc_server_packet_send(server, query->cmd->sock,
345 SILC_PACKET_COMMAND_REPLY, 0,
346 buffer->data, buffer->len, FALSE);
347 silc_buffer_free(buffer);
348 silc_server_query_free(query);
352 /* Continue with parsing */
353 silc_server_query_parse(server, query);
356 /* Parse the command query and start processing the queries in detail. */
358 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
360 SilcServerCommandContext cmd = query->cmd;
362 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
367 SILC_LOG_DEBUG(("Parsing %s query",
368 silc_get_command_name(query->querycmd)));
370 switch (query->querycmd) {
372 case SILC_COMMAND_WHOIS:
373 /* Get requested attributes if set */
374 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
375 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
376 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
378 /* When Requested Attributes is present we will assure that this
379 client cannot execute the WHOIS command too fast. This would be
380 same as having SILC_CF_LAG_STRICT. */
381 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
382 cmd->sock->user_data)
383 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
386 /* Get Client IDs if present. Take IDs always instead of nickname. */
387 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
391 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
392 if (!tmp && !query->attrs) {
393 /* No nickname, no ids and no attributes - send error */
394 silc_server_query_send_error(server, query,
395 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
396 silc_server_query_free(query);
400 /* Get the nickname@server string and parse it */
401 if (tmp && ((tmp_len > 128) ||
402 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
403 silc_server_query_send_error(server, query,
404 SILC_STATUS_ERR_BAD_NICKNAME, 0);
405 silc_server_query_free(query);
410 if (query->nickname) {
411 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
412 SILC_STRING_UTF8, 128, &tmp_len);
414 silc_server_query_send_error(server, query,
415 SILC_STATUS_ERR_BAD_NICKNAME, 0);
416 silc_server_query_free(query);
419 silc_free(query->nickname);
420 query->nickname = tmp;
424 /* Parse the IDs included in the query */
425 query->ids = silc_calloc(argc, sizeof(*query->ids));
427 for (i = 0; i < argc; i++) {
428 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
432 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
433 if (!id || id_type != SILC_ID_CLIENT) {
434 silc_server_query_add_error(server, query, 1, i + 4,
435 SILC_STATUS_ERR_BAD_CLIENT_ID);
439 /* Normal server must check whether this ID exist, and if not then
440 send the query to router, unless done so already */
441 if (server->server_type == SILC_SERVER && !query->resolved) {
442 if (!silc_idlist_find_client_by_id(server->local_list,
444 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
445 !silc_idlist_find_client_by_id(server->global_list,
447 silc_server_query_send_router(server, query);
448 for (i = 0; i < query->ids_count; i++)
449 silc_free(query->ids[i].id);
450 silc_free(query->ids);
452 query->ids_count = 0;
459 query->ids[query->ids_count].id = id;
460 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
465 /* Get the max count of reply messages allowed */
466 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
467 if (tmp && tmp_len == sizeof(SilcUInt32))
468 SILC_GET32_MSB(query->reply_count, tmp);
471 case SILC_COMMAND_WHOWAS:
473 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
475 silc_server_query_send_error(server, query,
476 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
477 silc_server_query_free(query);
481 /* Get the nickname@server string and parse it */
483 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
484 silc_server_query_send_error(server, query,
485 SILC_STATUS_ERR_BAD_NICKNAME, 0);
486 silc_server_query_free(query);
491 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
492 SILC_STRING_UTF8, 128, &tmp_len);
494 silc_server_query_send_error(server, query,
495 SILC_STATUS_ERR_BAD_NICKNAME, 0);
496 silc_server_query_free(query);
499 silc_free(query->nickname);
500 query->nickname = tmp;
502 /* Get the max count of reply messages allowed */
503 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
504 if (tmp && tmp_len == sizeof(SilcUInt32))
505 SILC_GET32_MSB(query->reply_count, tmp);
508 case SILC_COMMAND_IDENTIFY:
509 /* Get IDs if present. Take IDs always instead of names. */
510 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
513 /* Try get nickname */
514 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
516 /* Get the nickname@server string and parse it */
518 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
519 silc_server_query_add_error(server, query, 1, 1,
520 SILC_STATUS_ERR_BAD_NICKNAME);
523 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
524 SILC_STRING_UTF8, 128, &tmp_len);
526 silc_server_query_send_error(server, query,
527 SILC_STATUS_ERR_BAD_NICKNAME, 0);
528 silc_server_query_free(query);
531 silc_free(query->nickname);
532 query->nickname = tmp;
535 /* Try get server name */
536 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
538 /* Check server name */
539 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
542 silc_server_query_send_error(server, query,
543 SILC_STATUS_ERR_BAD_SERVER, 0);
544 silc_server_query_free(query);
547 query->server_name = tmp;
550 /* Get channel name */
551 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
552 if (tmp && tmp_len <= 256) {
553 /* Check channel name */
554 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
557 silc_server_query_send_error(server, query,
558 SILC_STATUS_ERR_BAD_CHANNEL, 0);
559 silc_server_query_free(query);
562 query->channel_name = tmp;
565 if (!query->nickname && !query->server_name && !query->channel_name) {
566 silc_server_query_send_error(server, query,
567 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
568 silc_server_query_free(query);
573 /* Parse the IDs included in the query */
574 query->ids = silc_calloc(argc, sizeof(*query->ids));
576 for (i = 0; i < argc; i++) {
577 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
581 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
583 silc_server_query_add_error(server, query, 1, i + 5,
584 SILC_STATUS_ERR_BAD_CLIENT_ID);
588 /* Normal server must check whether this ID exist, and if not then
589 send the query to router, unless done so already */
590 if (server->server_type == SILC_SERVER && !query->resolved) {
591 if (id_type == SILC_ID_CLIENT) {
592 if (!silc_idlist_find_client_by_id(server->local_list,
594 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
595 !silc_idlist_find_client_by_id(server->global_list,
597 silc_server_query_send_router(server, query);
598 for (i = 0; i < query->ids_count; i++)
599 silc_free(query->ids[i].id);
600 silc_free(query->ids);
602 query->ids_count = 0;
608 /* For now all other ID's except Client ID's are explicitly
609 sent to router for resolving. */
610 silc_server_query_send_router(server, query);
611 for (i = 0; i < query->ids_count; i++)
612 silc_free(query->ids[i].id);
613 silc_free(query->ids);
615 query->ids_count = 0;
621 query->ids[query->ids_count].id = id;
622 query->ids[query->ids_count].id_type = id_type;
627 /* Get the max count of reply messages allowed */
628 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
629 if (tmp && tmp_len == sizeof(SilcUInt32))
630 SILC_GET32_MSB(query->reply_count, tmp);
634 /* Start processing the query information */
635 silc_server_query_process(server, query, TRUE);
638 /* Context for holding clients searched by public key. */
640 SilcClientEntry **clients;
641 SilcUInt32 *clients_count;
643 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
645 void silc_server_public_key_hash_foreach(void *key, void *context,
648 SilcServerPublicKeyUser uc = user_context;
649 SilcClientEntry entry = context;
651 /* Nothing was found, just return */
657 (*uc->clients) = silc_realloc((*uc->clients),
658 sizeof((**uc->clients)) *
659 ((*uc->clients_count) + 1));
660 (*uc->clients)[(*uc->clients_count)++] = entry;
663 /* If clients are set, limit the found clients using the attributes in
664 the query. If clients are not set, try to find some clients using
667 void silc_server_query_check_attributes(SilcServer server,
668 SilcServerQuery query,
669 SilcClientEntry **clients,
670 SilcUInt32 *clients_count) {
671 SilcClientEntry entry;
672 SilcAttributePayload attr;
673 SilcAttribute attribute;
674 SilcAttributeObjPk pk;
675 SilcPublicKey publickey;
677 bool found = FALSE, no_clients = FALSE;
679 /* If no clients were found, we only check the attributes
680 if the user wasn't searching for nickname/ids */
683 if (query->nickname || query->ids_count)
687 silc_dlist_start(query->attrs);
688 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
689 attribute = silc_attribute_get_attribute(attr);
692 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
693 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
695 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
698 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
705 /* If no clients were set on calling this function, we
706 just search for clients, otherwise we try to limit
709 SilcServerPublicKeyUserStruct usercontext;
711 usercontext.clients = clients;
712 usercontext.clients_count = clients_count;
713 usercontext.found = FALSE;
715 silc_hash_table_find_foreach(server->pk_hash, publickey,
716 silc_server_public_key_hash_foreach,
719 if (usercontext.found == TRUE)
722 for (i = 0; i < *clients_count; i++) {
723 entry = (*clients)[i];
725 if (!entry->data.public_key)
728 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
730 (*clients)[i] = NULL;
737 silc_pkcs_public_key_free(publickey);
742 if (!found && !query->nickname && !query->ids)
743 silc_server_query_add_error(server, query, 2, 0,
744 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
747 /* Processes the parsed query. This does the actual finding of the
748 queried information and prepares for sending reply to the original
749 sender of the query command. */
751 void silc_server_query_process(SilcServer server, SilcServerQuery query,
754 SilcServerCommandContext cmd = query->cmd;
755 bool check_global = FALSE;
757 SilcClientEntry *clients = NULL, client_entry;
758 SilcChannelEntry *channels = NULL;
759 SilcServerEntry *servers = NULL;
760 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
763 SILC_LOG_DEBUG(("Processing %s query",
764 silc_get_command_name(query->querycmd)));
766 /* Check global lists if query is coming from client or we are not
767 normal server (we know global information). */
768 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
770 else if (server->server_type != SILC_SERVER)
773 if (query->nickname) {
774 /* Get all clients matching nickname from local list */
775 if (!silc_idlist_get_clients_by_hash(server->local_list,
776 query->nickname, server->md5hash,
777 &clients, &clients_count))
778 silc_idlist_get_clients_by_nickname(server->local_list,
781 &clients, &clients_count);
783 /* Check global list as well */
785 if (!silc_idlist_get_clients_by_hash(server->global_list,
786 query->nickname, server->md5hash,
787 &clients, &clients_count))
788 silc_idlist_get_clients_by_nickname(server->global_list,
791 &clients, &clients_count);
795 silc_server_query_add_error(server, query, 1, 1,
796 SILC_STATUS_ERR_NO_SUCH_NICK);
799 if (query->server_name) {
800 /* Find server by name */
801 entry = silc_idlist_find_server_by_name(server->local_list,
802 query->server_name, TRUE, NULL);
803 if (!entry && check_global)
804 entry = silc_idlist_find_server_by_name(server->global_list,
805 query->server_name, TRUE, NULL);
807 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
808 servers[servers_count++] = (SilcServerEntry)entry;
812 silc_server_query_add_error(server, query, 1, 2,
813 SILC_STATUS_ERR_NO_SUCH_SERVER);
816 if (query->channel_name) {
817 /* Find channel by name */
818 entry = silc_idlist_find_channel_by_name(server->local_list,
819 query->channel_name, NULL);
820 if (!entry && check_global)
821 entry = silc_idlist_find_channel_by_name(server->global_list,
822 query->channel_name, NULL);
824 channels = silc_realloc(channels, sizeof(*channels) *
825 (channels_count + 1));
826 channels[channels_count++] = (SilcChannelEntry)entry;
830 silc_server_query_add_error(server, query, 1, 3,
831 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
834 if (query->ids_count) {
835 /* Find entries by the queried IDs */
836 for (i = 0; i < query->ids_count; i++) {
837 void *id = query->ids[i].id;
841 switch (query->ids[i].id_type) {
844 /* Get client entry */
845 entry = silc_idlist_find_client_by_id(server->local_list,
847 if (!entry && check_global)
848 entry = silc_idlist_find_client_by_id(server->global_list,
851 silc_server_query_add_error(server, query, 0, i,
852 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
856 clients = silc_realloc(clients, sizeof(*clients) *
857 (clients_count + 1));
858 clients[clients_count++] = (SilcClientEntry)entry;
862 /* Get server entry */
863 entry = silc_idlist_find_server_by_id(server->local_list,
865 if (!entry && check_global)
866 entry = silc_idlist_find_server_by_id(server->global_list,
869 silc_server_query_add_error(server, query, 0, i,
870 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
874 servers = silc_realloc(servers, sizeof(*servers) *
875 (servers_count + 1));
876 servers[servers_count++] = (SilcServerEntry)entry;
879 case SILC_ID_CHANNEL:
880 /* Get channel entry */
881 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
882 if (!entry && check_global)
883 entry = silc_idlist_find_channel_by_id(server->global_list, id,
886 silc_server_query_add_error(server, query, 0, i,
887 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
891 channels = silc_realloc(channels, sizeof(*channels) *
892 (channels_count + 1));
893 channels[channels_count++] = (SilcChannelEntry)entry;
902 /* Check the attributes to narrow down the search by using them. */
904 silc_server_query_check_attributes(server, query, &clients,
907 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
908 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
909 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
911 /* If nothing was found, then just send the errors */
912 if (!clients && !channels && !servers) {
913 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
917 /* If caller does not want us to resolve anything (has resolved already)
918 then just continue with sending the reply */
920 silc_server_query_send_reply(server, query, clients, clients_count,
921 servers, servers_count, channels,
929 /* Now process all found information and if necessary do some more
931 switch (query->querycmd) {
933 case SILC_COMMAND_WHOIS:
934 for (i = 0; i < clients_count; i++) {
935 client_entry = clients[i];
937 /* Check if cannot query this anyway, so take next one */
939 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
942 /* If Requested Attributes is set then we always resolve the client
943 information, if not then check whether the entry is complete or not
944 and decide whether we need to resolve or not. */
947 /* Even if nickname and stuff are present, we may need to resolve
949 if (client_entry->nickname && client_entry->username &&
950 client_entry->userinfo) {
951 /* Check if cannot query this anyway, so take next one */
952 if (!client_entry->router)
955 /* If we are router, client is local to us, or client is on channel
956 we do not need to resolve the client information. */
957 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
958 || silc_hash_table_count(client_entry->channels) ||
964 /* Remove the NOATTR status periodically */
965 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
966 client_entry->updated + 600 < time(NULL))
967 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
969 /* When requested attributes is present and local client is detached
970 we cannot send the command to the client, we'll reply on behalf of
971 the client instead. */
972 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
973 (client_entry->mode & SILC_UMODE_DETACHED ||
974 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
977 /* If attributes are present in query, and in the entry and we have
978 done resolvings already we don't need to resolve anymore */
979 if (query->resolved && query->attrs && client_entry->attrs)
982 /* Resolve the detailed client information. If client is local we
983 know that attributes were present and we will resolve directly
984 from the client. Otherwise resolve from client's owner. */
985 silc_server_query_resolve(server, query,
986 (SILC_IS_LOCAL(client_entry) ?
987 client_entry->connection :
988 client_entry->router->connection),
993 case SILC_COMMAND_WHOWAS:
994 for (i = 0; i < clients_count; i++) {
995 client_entry = clients[i];
997 /* Check if cannot query this anyway, so take next one */
998 if (!client_entry || !client_entry->router ||
999 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1002 /* If both nickname and username are present no resolving is needed */
1003 if (client_entry->nickname && client_entry->username)
1006 /* Resolve the detailed client information */
1007 silc_server_query_resolve(server, query,
1008 client_entry->router->connection,
1013 case SILC_COMMAND_IDENTIFY:
1014 for (i = 0; i < clients_count; i++) {
1015 client_entry = clients[i];
1017 /* Check if cannot query this anyway, so take next one */
1018 if (!client_entry || !client_entry->router ||
1019 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1022 /* Even if nickname is present, we may need to resolve the entry */
1023 if (client_entry->nickname) {
1025 /* If we are router, client is local to us, or client is on channel
1026 we do not need to resolve the client information. */
1027 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1028 || silc_hash_table_count(client_entry->channels) ||
1033 /* Resolve the detailed client information */
1034 silc_server_query_resolve(server, query,
1035 client_entry->router->connection,
1041 if (!query->queries_count)
1042 /* If we didn't have to do any resolving, continue with sending the
1043 command reply to the original sender. */
1044 silc_server_query_send_reply(server, query, clients, clients_count,
1045 servers, servers_count, channels,
1048 /* Now actually send the resolvings we gathered earlier */
1049 silc_server_query_resolve(server, query, NULL, NULL);
1053 silc_free(channels);
1056 /* Resolve the detailed information for the `client_entry'. Only client
1057 information needs to be resolved for being incomplete. Each incomplete
1058 client entry calls this function to do the resolving. */
1060 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1061 SilcSocketConnection sock,
1062 SilcClientEntry client_entry)
1064 SilcServerCommandContext cmd = query->cmd;
1065 SilcServerQueryList r = NULL;
1072 if (!sock && client_entry)
1075 /* If arguments are NULL we will now actually send the resolvings
1076 that earlier has been gathered by calling this function. */
1077 if (!sock && !client_entry) {
1080 SILC_LOG_DEBUG(("Sending the resolvings"));
1082 /* WHOWAS resolving has been done at the same time this function
1083 was called to add the resolving for WHOWAS, so just return. */
1084 if (query->querycmd == SILC_COMMAND_WHOWAS)
1087 for (i = 0; i < query->querylist_count; i++) {
1088 r = &query->querylist[i];
1090 /* If Requested Attributes were present put them to this resolving */
1091 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1093 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1094 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1095 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1097 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1099 r->arg[r->argc] = silc_memdup(tmp, len);
1100 r->arg_lens[r->argc] = len;
1101 r->arg_types[r->argc] = 3;
1105 /* Send WHOIS command */
1106 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1107 r->argc, r->arg, r->arg_lens,
1108 r->arg_types, r->ident);
1109 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1110 res_cmd->data, res_cmd->len, FALSE);
1111 silc_buffer_free(res_cmd);
1113 /* Reprocess this packet after received reply */
1114 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1116 silc_server_query_resolve_reply,
1118 query->queries_left++;
1121 /* Cleanup this temporary context */
1122 for (i = 0; i < query->querylist_count; i++) {
1124 for (k = 0; k < query->querylist[i].argc; k++)
1125 silc_free(query->querylist[i].arg[k]);
1126 silc_free(query->querylist[i].arg);
1127 silc_free(query->querylist[i].arg_lens);
1128 silc_free(query->querylist[i].arg_types);
1130 silc_free(query->querylist);
1131 query->querylist = NULL;
1132 query->querylist_count = 0;
1136 SILC_LOG_DEBUG(("Resolving client information"));
1138 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1139 /* The entry is being resolved by some other external query already.
1140 Attach to that query instead of resolving again. */
1141 ident = client_entry->resolve_cmd_ident;
1142 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1143 silc_server_query_resolve_reply, query))
1144 query->queries_left++;
1146 /* This entry will be resolved */
1147 ident = ++server->cmd_ident;
1149 switch (query->querycmd) {
1151 case SILC_COMMAND_WHOIS:
1152 case SILC_COMMAND_IDENTIFY:
1153 /* Take existing query context if exist for this connection */
1154 for (i = 0; i < query->querylist_count; i++)
1155 if (query->querylist[i].sock == sock) {
1156 r = &query->querylist[i];
1161 /* Allocate new temp query list context */
1162 query->querylist = silc_realloc(query->querylist,
1163 sizeof(*query->querylist) *
1164 (query->querylist_count + 1));
1165 r = &query->querylist[query->querylist_count];
1166 query->querylist_count++;
1167 memset(r, 0, sizeof(*r));
1170 if (SILC_IS_LOCAL(client_entry))
1175 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1176 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1177 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1179 /* Add the client entry to be resolved */
1180 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1181 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1182 r->arg_lens[r->argc] = idp->len;
1183 r->arg_types[r->argc] = r->argc + 4;
1185 silc_buffer_free(idp);
1189 case SILC_COMMAND_WHOWAS:
1190 /* We must send WHOWAS command since it's the only the way of
1191 resolving clients that are not present in the network anymore. */
1192 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1193 1, query->nickname, strlen(query->nickname));
1194 if (silc_server_command_pending(server, query->querycmd, ident,
1195 silc_server_query_resolve_reply, query))
1196 query->queries_left++;
1201 /* Mark the entry as being resolved */
1202 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1203 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1204 client_entry->resolve_cmd_ident = ident;
1205 client_entry->updated = time(NULL);
1207 /* Save the queried ID, which we will reprocess after we get this and
1208 all other queries back. */
1209 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1210 (query->queries_count + 1));
1211 if (query->queries) {
1212 i = query->queries_count;
1213 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1214 query->queries[i].id_type = SILC_ID_CLIENT;
1215 query->queries[i].ident = ident;
1216 query->queries_count++;
1220 /* Reply callback called after one resolving has been completed. If
1221 all resolvings has been received then we will continue with sending
1222 the command reply to the original sender of the query. */
1224 void silc_server_query_resolve_reply(void *context, void *reply)
1226 SilcServerQuery query = context;
1227 SilcServer server = query->cmd->server;
1228 SilcServerCommandReplyContext cmdr = reply;
1229 SilcUInt16 ident = cmdr->ident;
1230 SilcStatus error = SILC_STATUS_OK;
1231 SilcServerQueryID id = NULL;
1232 SilcClientEntry client_entry;
1235 /* One less query left */
1236 query->queries_left--;
1238 silc_command_get_status(cmdr->payload, NULL, &error);
1239 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1240 query->queries_left, error));
1242 /* If no error then skip to other stuff */
1243 if (error == SILC_STATUS_OK)
1246 /* Error occurred during resolving */
1248 /* Find the resolved client ID */
1249 for (i = 0; i < query->queries_count; i++) {
1250 if (query->queries[i].ident != ident)
1253 id = &query->queries[i];
1255 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1257 /* If timeout occurred for local entry when resolving attributes
1258 mark that this client doesn't support attributes in WHOIS. This
1259 assures we won't send the request again to the client. */
1260 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1261 client_entry = silc_idlist_find_client_by_id(server->local_list,
1262 id->id, TRUE, NULL);
1263 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1264 silc_id_render(id->id, SILC_ID_CLIENT)));
1265 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1266 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1267 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1272 /* Remove the RESOLVING status from the client entry */
1273 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1274 client_entry = silc_idlist_find_client_by_id(server->local_list,
1275 id->id, TRUE, NULL);
1277 client_entry = silc_idlist_find_client_by_id(server->global_list,
1278 id->id, TRUE, NULL);
1280 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1287 /* If there are queries left then wait for them */
1288 if (query->queries_left)
1291 SILC_LOG_DEBUG(("Reprocess the query"));
1293 /* If the original command caller has gone away, just stop. */
1294 if (query->cmd->sock->users == 1) {
1295 SILC_LOG_DEBUG(("Original command caller vanished"));
1296 silc_server_query_free(query);
1300 /* We have received all queries. Now re-search all information required
1301 to complete this query. Reason we cannot save the values found in
1302 the first search is that SilcClientEntry, SilcServerEntry and
1303 SilcChannelEntry pointers may become invalid while we were waiting
1304 for these resolvings. */
1305 silc_server_query_process(server, query, FALSE);
1308 /* Send the reply to the original query. If arguments are NULL then this
1309 sends only the errors that has occurred during the processing of the
1310 query. This sends the errors always after sending all the found
1311 information. The query is over after this function returns and the
1312 `query' will become invalid. This is called only after all informations
1313 has been resolved. This means that if something is not found or is
1314 incomplete in this function we were unable to resolve the information
1315 or it does not exist at all. */
1317 void silc_server_query_send_reply(SilcServer server,
1318 SilcServerQuery query,
1319 SilcClientEntry *clients,
1320 SilcUInt32 clients_count,
1321 SilcServerEntry *servers,
1322 SilcUInt32 servers_count,
1323 SilcChannelEntry *channels,
1324 SilcUInt32 channels_count)
1326 SilcServerCommandContext cmd = query->cmd;
1327 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1332 int i, k, valid_count;
1333 char nh[384], uh[384];
1334 bool sent_reply = FALSE;
1336 SILC_LOG_DEBUG(("Sending reply to query"));
1337 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1338 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1339 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1340 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1342 status = SILC_STATUS_OK;
1345 if (clients_count) {
1346 SilcClientEntry entry;
1347 SilcSocketConnection hsock;
1349 /* Mark all invalid entries */
1350 for (i = 0, valid_count = 0; i < clients_count; i++) {
1355 switch (query->querycmd) {
1356 case SILC_COMMAND_WHOIS:
1357 if (!entry->nickname || !entry->username || !entry->userinfo ||
1358 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1359 /* When querying by ID, every "unfound" entry must cause error */
1361 silc_server_query_add_error_id(server, query,
1362 SILC_STATUS_ERR_TIMEDOUT,
1363 entry->id, SILC_ID_CLIENT);
1369 case SILC_COMMAND_IDENTIFY:
1370 if (!entry->nickname ||
1371 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1372 /* When querying by ID, every "unfound" entry must cause error */
1374 silc_server_query_add_error_id(server, query,
1375 SILC_STATUS_ERR_TIMEDOUT,
1376 entry->id, SILC_ID_CLIENT);
1382 case SILC_COMMAND_WHOWAS:
1383 if (!entry->nickname || !entry->username ||
1384 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1393 /* Start processing found clients */
1394 status = SILC_STATUS_OK;
1395 if (valid_count > 1)
1396 status = SILC_STATUS_LIST_START;
1398 /* Now do the sending of valid entries */
1400 for (i = 0; i < clients_count && valid_count; i++) {
1406 status = SILC_STATUS_LIST_ITEM;
1407 if (valid_count > 1 && k == valid_count - 1
1408 && !servers_count && !channels_count && !query->errors_count)
1409 status = SILC_STATUS_LIST_END;
1410 if (query->reply_count && k - 1 == query->reply_count)
1411 status = SILC_STATUS_LIST_END;
1413 SILC_LOG_DEBUG(("%s: client %s",
1414 (status == SILC_STATUS_OK ? " OK" :
1415 status == SILC_STATUS_LIST_START ? "START" :
1416 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1417 status == SILC_STATUS_LIST_END ? " END" :
1418 " : "), entry->nickname));
1420 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1421 memset(nh, 0, sizeof(nh));
1423 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1424 if (!strchr(entry->nickname, '@')) {
1425 silc_strncat(nh, sizeof(nh), "@", 1);
1426 if (entry->servername) {
1427 silc_strncat(nh, sizeof(nh), entry->servername,
1428 strlen(entry->servername));
1430 len = entry->router ? strlen(entry->router->server_name) :
1431 strlen(server->server_name);
1432 silc_strncat(nh, sizeof(nh), entry->router ?
1433 entry->router->server_name :
1434 server->server_name, len);
1438 switch (query->querycmd) {
1440 case SILC_COMMAND_WHOIS:
1442 unsigned char idle[4], mode[4];
1443 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1444 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1446 memset(fempty, 0, sizeof(fempty));
1447 memset(idle, 0, sizeof(idle));
1448 memset(uh, 0, sizeof(uh));
1450 silc_strncat(uh, sizeof(uh), entry->username,
1451 strlen(entry->username));
1452 if (!strchr(entry->username, '@') && entry->connection) {
1453 hsock = entry->connection;
1454 silc_strncat(uh, sizeof(uh), "@", 1);
1455 len = strlen(hsock->hostname);
1456 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1459 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1461 silc_server_get_client_channel_list(server, entry, FALSE,
1462 FALSE, &umode_list);
1465 silc_server_get_client_channel_list(server, entry, TRUE,
1468 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1469 fingerprint = entry->data.fingerprint;
1473 SILC_PUT32_MSB(entry->mode, mode);
1474 if (entry->connection)
1475 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1477 /* If Requested Attribute were present, and we do not have the
1478 attributes we will reply to them on behalf of the client. */
1481 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1482 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1483 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1484 entry->attrs_len = len;
1485 silc_buffer_free(tmpattrs);
1487 attrs = entry->attrs;
1488 len = entry->attrs_len;
1491 /* Send command reply */
1492 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1493 status, 0, ident, 10,
1494 2, idp->data, idp->len,
1498 strlen(entry->userinfo),
1499 6, channels ? channels->data : NULL,
1500 channels ? channels->len : 0,
1504 fingerprint ? 20 : 0,
1505 10, umode_list ? umode_list->data :
1506 NULL, umode_list ? umode_list->len :
1511 /* For now we always delete Requested Attributes, unless the client
1512 is detached, in which case we don't want to reconstruct the
1513 same data everytime */
1514 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1515 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1516 silc_free(entry->attrs);
1517 entry->attrs = NULL;
1521 silc_buffer_free(channels);
1523 silc_buffer_free(umode_list);
1529 case SILC_COMMAND_IDENTIFY:
1530 if (!entry->username) {
1531 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1532 status, 0, ident, 2,
1533 2, idp->data, idp->len,
1537 silc_strncat(uh, sizeof(uh), entry->username,
1538 strlen(entry->username));
1539 if (!strchr(entry->username, '@') && entry->connection) {
1540 hsock = entry->connection;
1541 silc_strncat(uh, sizeof(uh), "@", 1);
1542 len = strlen(hsock->hostname);
1543 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1546 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1547 status, 0, ident, 3,
1548 2, idp->data, idp->len,
1555 case SILC_COMMAND_WHOWAS:
1556 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1557 if (!strchr(entry->username, '@'))
1558 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1560 /* Send command reply */
1561 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1562 status, 0, ident, 4,
1563 2, idp->data, idp->len,
1568 strlen(entry->userinfo) : 0);
1573 silc_buffer_free(idp);
1575 if (status == SILC_STATUS_LIST_END)
1581 /* Not one valid entry was found, send error. If nickname was used
1582 in query send error based on that, otherwise the query->errors
1583 already includes proper errors. */
1584 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1585 silc_server_query_add_error(server, query, 1, 1,
1586 SILC_STATUS_ERR_NO_SUCH_NICK);
1591 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1592 SilcServerEntry entry;
1594 if (status == SILC_STATUS_OK && servers_count > 1)
1595 status = SILC_STATUS_LIST_START;
1598 for (i = 0; i < servers_count; i++) {
1602 status = SILC_STATUS_LIST_ITEM;
1603 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1604 !query->errors_count)
1605 status = SILC_STATUS_LIST_END;
1606 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1607 !query->errors_count)
1608 status = SILC_STATUS_LIST_END;
1609 if (query->reply_count && k - 1 == query->reply_count)
1610 status = SILC_STATUS_LIST_END;
1612 SILC_LOG_DEBUG(("%s: server %s",
1613 (status == SILC_STATUS_OK ? " OK" :
1614 status == SILC_STATUS_LIST_START ? "START" :
1615 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1616 status == SILC_STATUS_LIST_END ? " END" :
1618 entry->server_name ? entry->server_name : ""));
1620 /* Send command reply */
1621 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1622 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1623 status, 0, ident, 2,
1624 2, idp->data, idp->len,
1625 3, entry->server_name,
1626 entry->server_name ?
1627 strlen(entry->server_name) : 0);
1628 silc_buffer_free(idp);
1631 if (status == SILC_STATUS_LIST_END)
1638 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1639 SilcChannelEntry entry;
1641 if (status == SILC_STATUS_OK && channels_count > 1)
1642 status = SILC_STATUS_LIST_START;
1645 for (i = 0; i < channels_count; i++) {
1646 entry = channels[i];
1649 status = SILC_STATUS_LIST_ITEM;
1650 if (channels_count == 1 && status != SILC_STATUS_OK &&
1651 !query->errors_count)
1652 status = SILC_STATUS_LIST_END;
1653 if (channels_count > 1 && k == channels_count - 1 &&
1654 !query->errors_count)
1655 status = SILC_STATUS_LIST_END;
1656 if (query->reply_count && k - 1 == query->reply_count)
1657 status = SILC_STATUS_LIST_END;
1659 SILC_LOG_DEBUG(("%s: channel %s",
1660 (status == SILC_STATUS_OK ? " OK" :
1661 status == SILC_STATUS_LIST_START ? "START" :
1662 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1663 status == SILC_STATUS_LIST_END ? " END" :
1665 entry->channel_name ? entry->channel_name : ""));
1667 /* Send command reply */
1668 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1669 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1670 status, 0, ident, 2,
1671 2, idp->data, idp->len,
1672 3, entry->channel_name,
1673 entry->channel_name ?
1674 strlen(entry->channel_name) : 0);
1675 silc_buffer_free(idp);
1678 if (status == SILC_STATUS_LIST_END)
1685 if (query->errors_count) {
1688 if (status == SILC_STATUS_OK && query->errors_count > 1)
1689 status = SILC_STATUS_LIST_START;
1692 for (i = 0; i < query->errors_count; i++) {
1695 /* Take error argument */
1696 if (query->errors[i].type == 1) {
1697 /* Take from sent arguments */
1699 tmp = silc_argument_get_arg_type(cmd->args,
1700 query->errors[i].index, &len);
1702 } else if (query->errors[i].type == 2) {
1707 } else if (!query->errors[i].id) {
1708 /* Take from query->ids */
1710 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1711 query->ids[query->errors[k].index].id_type);
1716 /* Take added ID. */
1717 idp = silc_id_payload_encode(query->errors[i].id,
1718 query->errors[k].id_type);
1725 status = SILC_STATUS_LIST_ITEM;
1726 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1727 status = SILC_STATUS_LIST_END;
1728 if (query->errors_count > 1 && k == query->errors_count - 1)
1729 status = SILC_STATUS_LIST_END;
1730 if (query->reply_count && k - 1 == query->reply_count)
1731 status = SILC_STATUS_LIST_END;
1733 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1734 (status == SILC_STATUS_OK ? " OK" :
1735 status == SILC_STATUS_LIST_START ? "START" :
1736 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1737 status == SILC_STATUS_LIST_END ? " END" :
1739 silc_get_status_message(query->errors[i].error),
1740 query->errors[i].error));
1742 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1743 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1745 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1746 (status == SILC_STATUS_OK ?
1747 query->errors[i].error : status),
1748 (status == SILC_STATUS_OK ?
1749 0 : query->errors[i].error), ident, 2,
1755 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1756 (status == SILC_STATUS_OK ?
1757 query->errors[i].error : status),
1758 (status == SILC_STATUS_OK ?
1759 0 : query->errors[i].error), ident, 1,
1762 silc_buffer_free(idp);
1765 if (status == SILC_STATUS_LIST_END)
1772 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1773 SILC_LOG_ERROR(("BUG: Sending %d clients", clients_count));
1774 SILC_LOG_ERROR(("BUG: Sending %d servers", servers_count));
1775 SILC_LOG_ERROR(("BUG: Sending %d channels", channels_count));
1776 SILC_LOG_ERROR(("BUG: Sending %d errors", query->errors_count));
1780 silc_server_query_free(query);
1783 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1784 of the client since we were unable to resolve them from the client.
1785 Either client does not support Requested Attributes or isn't replying
1786 to them like it should. */
1788 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1789 SilcServerQuery query,
1790 SilcClientEntry client_entry)
1792 SilcBuffer buffer = NULL;
1793 SilcAttribute attribute;
1794 SilcAttributePayload attr;
1795 SilcAttributeObjPk pk;
1796 SilcAttributeObjService service;
1798 unsigned char sign[2048 + 1];
1799 SilcUInt32 sign_len;
1801 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1803 /* Go through all requested attributes */
1804 silc_dlist_start(query->attrs);
1805 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1806 attribute = silc_attribute_get_attribute(attr);
1807 switch (attribute) {
1809 case SILC_ATTRIBUTE_SERVICE:
1810 /* Put SERVICE. Put only SILC service. */
1811 memset(&service, 0, sizeof(service));
1812 service.port = (server->config->server_info->primary ?
1813 server->config->server_info->primary->port : SILC_PORT);
1814 silc_strncat(service.address, sizeof(service.address),
1815 server->server_name, strlen(server->server_name));
1816 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1817 if (client_entry->connection)
1818 service.idle = time(NULL) - client_entry->data.last_receive;
1819 buffer = silc_attribute_payload_encode(buffer, attribute,
1820 SILC_ATTRIBUTE_FLAG_VALID,
1821 &service, sizeof(service));
1826 case SILC_ATTRIBUTE_STATUS_MOOD:
1827 /* Put STATUS_MOOD */
1828 buffer = silc_attribute_payload_encode(buffer, attribute,
1829 SILC_ATTRIBUTE_FLAG_VALID,
1831 SILC_ATTRIBUTE_MOOD_NORMAL,
1832 sizeof(SilcUInt32));
1837 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1838 /* Put STATUS_FREETEXT. We just tell in the message that we are
1839 replying on behalf of the client. */
1841 "This information was provided by the server on behalf of the user";
1842 buffer = silc_attribute_payload_encode(buffer, attribute,
1843 SILC_ATTRIBUTE_FLAG_VALID,
1849 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1850 /* Put PREFERRED_CONTACT */
1851 buffer = silc_attribute_payload_encode(buffer, attribute,
1852 SILC_ATTRIBUTE_FLAG_VALID,
1854 SILC_ATTRIBUTE_CONTACT_CHAT,
1855 sizeof(SilcUInt32));
1860 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1861 /* Put USER_PUBLIC_KEY */
1862 if (client_entry->data.public_key) {
1863 pk.type = "silc-rsa";
1864 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1866 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1867 SILC_ATTRIBUTE_FLAG_VALID :
1868 SILC_ATTRIBUTE_FLAG_INVALID,
1876 /* No public key available */
1877 buffer = silc_attribute_payload_encode(buffer, attribute,
1878 SILC_ATTRIBUTE_FLAG_INVALID,
1885 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1886 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1887 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1890 /* For other attributes we cannot reply so mark it invalid */
1891 buffer = silc_attribute_payload_encode(buffer, attribute,
1892 SILC_ATTRIBUTE_FLAG_INVALID,
1900 /* Always put our public key. This assures that we send at least
1901 something valid back always. */
1902 pk.type = "silc-rsa";
1903 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1904 buffer = silc_attribute_payload_encode(buffer,
1905 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1906 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1907 SILC_ATTRIBUTE_FLAG_INVALID,
1913 /* Finally compute the digital signature of all the data we provided
1914 as an indication that we provided rightfull information, and this
1915 also authenticates our public key. */
1916 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1917 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1918 buffer->data, buffer->len,
1922 pk.data_len = sign_len;
1924 silc_attribute_payload_encode(buffer,
1925 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1926 SILC_ATTRIBUTE_FLAG_VALID,
1935 /* Find client by the Client ID indicated by the `client_id', and if not
1936 found then query it by using WHOIS command. The client information
1937 is also resolved if the cached information is incomplete or if the
1938 `always_resolve' is set to TRUE. The indication whether requested
1939 client was being resolved is saved into `resolved'. If the client
1940 is not being resolved its entry is returned by this function. NULL
1941 is returned if client is resolved. */
1943 SilcClientEntry silc_server_query_client(SilcServer server,
1944 const SilcClientID *client_id,
1945 bool always_resolve,
1948 SilcClientEntry client;
1950 SILC_LOG_DEBUG(("Resolving client by client ID"));
1955 client = silc_idlist_find_client_by_id(server->local_list,
1956 (SilcClientID *)client_id,
1959 client = silc_idlist_find_client_by_id(server->global_list,
1960 (SilcClientID *)client_id,
1962 if (!client && server->server_type == SILC_ROUTER)
1966 if (!client && server->standalone)
1969 if (!client || !client->nickname || !client->username ||
1971 SilcBuffer buffer, idp;
1974 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1975 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1976 client->resolve_cmd_ident = ++server->cmd_ident;
1979 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1980 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1981 server->cmd_ident, 1,
1982 4, idp->data, idp->len);
1983 silc_server_packet_send(server, client ? client->router->connection :
1984 SILC_PRIMARY_ROUTE(server),
1985 SILC_PACKET_COMMAND, 0,
1986 buffer->data, buffer->len, FALSE);
1987 silc_buffer_free(idp);
1988 silc_buffer_free(buffer);