5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 0 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname, 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 /* Check if router sent error reply */
327 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
330 SILC_LOG_DEBUG(("Sending error to original query"));
332 /* Send the same command reply payload which contains the error */
333 silc_command_set_command(cmdr->payload, query->querycmd);
334 silc_command_set_ident(cmdr->payload,
335 silc_command_get_ident(query->cmd->payload));
336 buffer = silc_command_payload_encode_payload(cmdr->payload);
337 silc_server_packet_send(server, query->cmd->sock,
338 SILC_PACKET_COMMAND_REPLY, 0,
339 buffer->data, buffer->len, FALSE);
340 silc_buffer_free(buffer);
341 silc_server_query_free(query);
345 /* Continue with parsing */
346 silc_server_query_parse(server, query);
349 /* Parse the command query and start processing the queries in detail. */
351 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
353 SilcServerCommandContext cmd = query->cmd;
355 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
360 SILC_LOG_DEBUG(("Parsing %s query",
361 silc_get_command_name(query->querycmd)));
363 switch (query->querycmd) {
365 case SILC_COMMAND_WHOIS:
366 /* Get requested attributes if set */
367 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
368 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
369 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
371 /* When Requested Attributes is present we will assure that this
372 client cannot execute the WHOIS command too fast. This would be
373 same as having SILC_CF_LAG_STRICT. */
374 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
375 cmd->sock->user_data)
376 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
379 /* Get Client IDs if present. Take IDs always instead of nickname. */
380 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
384 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
385 if (!tmp && !query->attrs) {
386 /* No nickname, no ids and no attributes - send error */
387 silc_server_query_send_error(server, query,
388 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
389 silc_server_query_free(query);
393 /* Get the nickname@server string and parse it */
394 if (tmp && ((tmp_len > 128) ||
395 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
396 silc_server_query_send_error(server, query,
397 SILC_STATUS_ERR_BAD_NICKNAME, 0);
398 silc_server_query_free(query);
403 if (query->nickname) {
404 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
405 SILC_STRING_UTF8, 128, &tmp_len);
407 silc_server_query_send_error(server, query,
408 SILC_STATUS_ERR_BAD_NICKNAME, 0);
409 silc_server_query_free(query);
412 silc_free(query->nickname);
413 query->nickname = tmp;
417 /* Parse the IDs included in the query */
418 query->ids = silc_calloc(argc, sizeof(*query->ids));
420 for (i = 0; i < argc; i++) {
421 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
425 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
426 if (!id || id_type != SILC_ID_CLIENT) {
427 silc_server_query_add_error(server, query, 1, i + 4,
428 SILC_STATUS_ERR_BAD_CLIENT_ID);
432 /* Normal server must check whether this ID exist, and if not then
433 send the query to router, unless done so already */
434 if (server->server_type == SILC_SERVER && !query->resolved) {
435 if (!silc_idlist_find_client_by_id(server->local_list,
437 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
438 !silc_idlist_find_client_by_id(server->global_list,
440 silc_server_query_send_router(server, query);
441 for (i = 0; i < query->ids_count; i++)
442 silc_free(query->ids[i].id);
443 silc_free(query->ids);
445 query->ids_count = 0;
452 query->ids[query->ids_count].id = id;
453 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
458 /* Get the max count of reply messages allowed */
459 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
460 if (tmp && tmp_len == sizeof(SilcUInt32))
461 SILC_GET32_MSB(query->reply_count, tmp);
464 case SILC_COMMAND_WHOWAS:
466 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
468 silc_server_query_send_error(server, query,
469 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
470 silc_server_query_free(query);
474 /* Get the nickname@server string and parse it */
476 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
477 silc_server_query_send_error(server, query,
478 SILC_STATUS_ERR_BAD_NICKNAME, 0);
479 silc_server_query_free(query);
484 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
485 SILC_STRING_UTF8, 128, &tmp_len);
487 silc_server_query_send_error(server, query,
488 SILC_STATUS_ERR_BAD_NICKNAME, 0);
489 silc_server_query_free(query);
492 silc_free(query->nickname);
493 query->nickname = tmp;
495 /* Get the max count of reply messages allowed */
496 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
497 if (tmp && tmp_len == sizeof(SilcUInt32))
498 SILC_GET32_MSB(query->reply_count, tmp);
501 case SILC_COMMAND_IDENTIFY:
502 /* Get IDs if present. Take IDs always instead of names. */
503 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
506 /* Try get nickname */
507 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
509 /* Get the nickname@server string and parse it */
511 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
512 silc_server_query_add_error(server, query, 1, 1,
513 SILC_STATUS_ERR_BAD_NICKNAME);
516 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
517 SILC_STRING_UTF8, 128, &tmp_len);
519 silc_server_query_send_error(server, query,
520 SILC_STATUS_ERR_BAD_NICKNAME, 0);
521 silc_server_query_free(query);
524 silc_free(query->nickname);
525 query->nickname = tmp;
528 /* Try get server name */
529 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
531 /* Check server name */
532 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
535 silc_server_query_send_error(server, query,
536 SILC_STATUS_ERR_BAD_SERVER, 0);
537 silc_server_query_free(query);
540 query->server_name = tmp;
543 /* Get channel name */
544 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
545 if (tmp && tmp_len <= 256) {
546 /* Check channel name */
547 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
550 silc_server_query_send_error(server, query,
551 SILC_STATUS_ERR_BAD_CHANNEL, 0);
552 silc_server_query_free(query);
555 query->channel_name = tmp;
558 if (!query->nickname && !query->server_name && !query->channel_name) {
559 silc_server_query_send_error(server, query,
560 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
561 silc_server_query_free(query);
566 /* Parse the IDs included in the query */
567 query->ids = silc_calloc(argc, sizeof(*query->ids));
569 for (i = 0; i < argc; i++) {
570 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
574 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
576 silc_server_query_add_error(server, query, 1, i + 5,
577 SILC_STATUS_ERR_BAD_CLIENT_ID);
581 /* Normal server must check whether this ID exist, and if not then
582 send the query to router, unless done so already */
583 if (server->server_type == SILC_SERVER && !query->resolved) {
584 if (id_type == SILC_ID_CLIENT) {
585 if (!silc_idlist_find_client_by_id(server->local_list,
587 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
588 !silc_idlist_find_client_by_id(server->global_list,
590 silc_server_query_send_router(server, query);
591 for (i = 0; i < query->ids_count; i++)
592 silc_free(query->ids[i].id);
593 silc_free(query->ids);
595 query->ids_count = 0;
601 /* For now all other ID's except Client ID's are explicitly
602 sent to router for resolving. */
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 query->ids[query->ids_count].id = id;
615 query->ids[query->ids_count].id_type = id_type;
620 /* Get the max count of reply messages allowed */
621 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
622 if (tmp && tmp_len == sizeof(SilcUInt32))
623 SILC_GET32_MSB(query->reply_count, tmp);
627 /* Start processing the query information */
628 silc_server_query_process(server, query, TRUE);
631 /* Context for holding clients searched by public key. */
633 SilcClientEntry **clients;
634 SilcUInt32 *clients_count;
636 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
638 void silc_server_public_key_hash_foreach(void *key, void *context,
641 SilcServerPublicKeyUser uc = user_context;
642 SilcClientEntry entry = context;
644 /* Nothing was found, just return */
650 (*uc->clients) = silc_realloc((*uc->clients),
651 sizeof((**uc->clients)) *
652 ((*uc->clients_count) + 1));
653 (*uc->clients)[(*uc->clients_count)++] = entry;
656 /* If clients are set, limit the found clients using the attributes in
657 the query. If clients are not set, try to find some clients using
660 void silc_server_query_check_attributes(SilcServer server,
661 SilcServerQuery query,
662 SilcClientEntry **clients,
663 SilcUInt32 *clients_count) {
664 SilcClientEntry entry;
665 SilcAttributePayload attr;
666 SilcAttribute attribute;
667 SilcAttributeObjPk pk;
668 SilcPublicKey publickey;
670 bool found = FALSE, no_clients = FALSE;
672 /* If no clients were found, we only check the attributes
673 if the user wasn't searching for nickname/ids */
676 if (query->nickname || query->ids_count)
680 silc_dlist_start(query->attrs);
681 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
682 attribute = silc_attribute_get_attribute(attr);
685 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
686 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
688 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
691 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
698 /* If no clients were set on calling this function, we
699 just search for clients, otherwise we try to limit
702 SilcServerPublicKeyUserStruct usercontext;
704 usercontext.clients = clients;
705 usercontext.clients_count = clients_count;
706 usercontext.found = FALSE;
708 silc_hash_table_find_foreach(server->pk_hash, publickey,
709 silc_server_public_key_hash_foreach,
712 if (usercontext.found == TRUE)
715 for (i = 0; i < *clients_count; i++) {
716 entry = (*clients)[i];
718 if (!entry->data.public_key)
721 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
723 (*clients)[i] = NULL;
730 silc_pkcs_public_key_free(publickey);
735 if (!found && !query->nickname && !query->ids)
736 silc_server_query_add_error(server, query, 2, 0,
737 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
740 /* Processes the parsed query. This does the actual finding of the
741 queried information and prepares for sending reply to the original
742 sender of the query command. */
744 void silc_server_query_process(SilcServer server, SilcServerQuery query,
747 SilcServerCommandContext cmd = query->cmd;
748 bool check_global = FALSE;
750 SilcClientEntry *clients = NULL, client_entry;
751 SilcChannelEntry *channels = NULL;
752 SilcServerEntry *servers = NULL;
753 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
756 SILC_LOG_DEBUG(("Processing %s query",
757 silc_get_command_name(query->querycmd)));
759 /* Check global lists if query is coming from client or we are not
760 normal server (we know global information). */
761 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
763 else if (server->server_type != SILC_SERVER)
766 if (query->nickname) {
767 /* Get all clients matching nickname from local list */
768 if (!silc_idlist_get_clients_by_hash(server->local_list,
769 query->nickname, server->md5hash,
770 &clients, &clients_count))
771 silc_idlist_get_clients_by_nickname(server->local_list,
774 &clients, &clients_count);
776 /* Check global list as well */
778 if (!silc_idlist_get_clients_by_hash(server->global_list,
779 query->nickname, server->md5hash,
780 &clients, &clients_count))
781 silc_idlist_get_clients_by_nickname(server->global_list,
784 &clients, &clients_count);
788 silc_server_query_add_error(server, query, 1, 1,
789 SILC_STATUS_ERR_NO_SUCH_NICK);
792 if (query->server_name) {
793 /* Find server by name */
794 entry = silc_idlist_find_server_by_name(server->local_list,
795 query->server_name, TRUE, NULL);
796 if (!entry && check_global)
797 entry = silc_idlist_find_server_by_name(server->global_list,
798 query->server_name, TRUE, NULL);
800 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
801 servers[servers_count++] = (SilcServerEntry)entry;
805 silc_server_query_add_error(server, query, 1, 2,
806 SILC_STATUS_ERR_NO_SUCH_SERVER);
809 if (query->channel_name) {
810 /* Find channel by name */
811 entry = silc_idlist_find_channel_by_name(server->local_list,
812 query->channel_name, NULL);
813 if (!entry && check_global)
814 entry = silc_idlist_find_channel_by_name(server->global_list,
815 query->channel_name, NULL);
817 channels = silc_realloc(channels, sizeof(*channels) *
818 (channels_count + 1));
819 channels[channels_count++] = (SilcChannelEntry)entry;
823 silc_server_query_add_error(server, query, 1, 3,
824 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
827 if (query->ids_count) {
828 /* Find entries by the queried IDs */
829 for (i = 0; i < query->ids_count; i++) {
830 void *id = query->ids[i].id;
834 switch (query->ids[i].id_type) {
837 /* Get client entry */
838 entry = silc_idlist_find_client_by_id(server->local_list,
840 if (!entry && check_global)
841 entry = silc_idlist_find_client_by_id(server->global_list,
844 silc_server_query_add_error(server, query, 0, i,
845 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
849 clients = silc_realloc(clients, sizeof(*clients) *
850 (clients_count + 1));
851 clients[clients_count++] = (SilcClientEntry)entry;
855 /* Get server entry */
856 entry = silc_idlist_find_server_by_id(server->local_list,
858 if (!entry && check_global)
859 entry = silc_idlist_find_server_by_id(server->global_list,
862 silc_server_query_add_error(server, query, 0, i,
863 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
867 servers = silc_realloc(servers, sizeof(*servers) *
868 (servers_count + 1));
869 servers[servers_count++] = (SilcServerEntry)entry;
872 case SILC_ID_CHANNEL:
873 /* Get channel entry */
874 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
875 if (!entry && check_global)
876 entry = silc_idlist_find_channel_by_id(server->global_list, id,
879 silc_server_query_add_error(server, query, 0, i,
880 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
884 channels = silc_realloc(channels, sizeof(*channels) *
885 (channels_count + 1));
886 channels[channels_count++] = (SilcChannelEntry)entry;
895 /* Check the attributes to narrow down the search by using them. */
897 silc_server_query_check_attributes(server, query, &clients,
900 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
901 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
902 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
904 /* If nothing was found, then just send the errors */
905 if (!clients && !channels && !servers) {
906 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
910 /* If caller does not want us to resolve anything (has resolved already)
911 then just continue with sending the reply */
913 silc_server_query_send_reply(server, query, clients, clients_count,
914 servers, servers_count, channels,
922 /* Now process all found information and if necessary do some more
924 switch (query->querycmd) {
926 case SILC_COMMAND_WHOIS:
927 for (i = 0; i < clients_count; i++) {
928 client_entry = clients[i];
930 /* Check if cannot query this anyway, so take next one */
932 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
935 /* If Requested Attributes is set then we always resolve the client
936 information, if not then check whether the entry is complete or not
937 and decide whether we need to resolve or not. */
940 /* Even if nickname and stuff are present, we may need to resolve
942 if (client_entry->nickname && client_entry->username &&
943 client_entry->userinfo) {
944 /* Check if cannot query this anyway, so take next one */
945 if (!client_entry->router)
948 /* If we are router, client is local to us, or client is on channel
949 we do not need to resolve the client information. */
950 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
951 || silc_hash_table_count(client_entry->channels) ||
957 /* Remove the NOATTR status periodically */
958 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
959 client_entry->updated + 600 < time(NULL))
960 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
962 /* When requested attributes is present and local client is detached
963 we cannot send the command to the client, we'll reply on behalf of
964 the client instead. */
965 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
966 (client_entry->mode & SILC_UMODE_DETACHED ||
967 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
970 /* If attributes are present in query, and in the entry and we have
971 done resolvings already we don't need to resolve anymore */
972 if (query->resolved && query->attrs && client_entry->attrs)
975 /* Resolve the detailed client information. If client is local we
976 know that attributes were present and we will resolve directly
977 from the client. Otherwise resolve from client's owner. */
978 silc_server_query_resolve(server, query,
979 (SILC_IS_LOCAL(client_entry) ?
980 client_entry->connection :
981 client_entry->router->connection),
986 case SILC_COMMAND_WHOWAS:
987 for (i = 0; i < clients_count; i++) {
988 client_entry = clients[i];
990 /* Check if cannot query this anyway, so take next one */
991 if (!client_entry || !client_entry->router ||
992 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
995 /* If both nickname and username are present no resolving is needed */
996 if (client_entry->nickname && client_entry->username)
999 /* Resolve the detailed client information */
1000 silc_server_query_resolve(server, query,
1001 client_entry->router->connection,
1006 case SILC_COMMAND_IDENTIFY:
1007 for (i = 0; i < clients_count; i++) {
1008 client_entry = clients[i];
1010 /* Check if cannot query this anyway, so take next one */
1011 if (!client_entry || !client_entry->router ||
1012 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1015 /* Even if nickname is present, we may need to resolve the entry */
1016 if (client_entry->nickname) {
1018 /* If we are router, client is local to us, or client is on channel
1019 we do not need to resolve the client information. */
1020 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1021 || silc_hash_table_count(client_entry->channels) ||
1026 /* Resolve the detailed client information */
1027 silc_server_query_resolve(server, query,
1028 client_entry->router->connection,
1034 if (!query->queries_count)
1035 /* If we didn't have to do any resolving, continue with sending the
1036 command reply to the original sender. */
1037 silc_server_query_send_reply(server, query, clients, clients_count,
1038 servers, servers_count, channels,
1041 /* Now actually send the resolvings we gathered earlier */
1042 silc_server_query_resolve(server, query, NULL, NULL);
1046 silc_free(channels);
1049 /* Resolve the detailed information for the `client_entry'. Only client
1050 information needs to be resolved for being incomplete. Each incomplete
1051 client entry calls this function to do the resolving. */
1053 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1054 SilcSocketConnection sock,
1055 SilcClientEntry client_entry)
1057 SilcServerCommandContext cmd = query->cmd;
1058 SilcServerQueryList r = NULL;
1065 if (!sock && client_entry)
1068 /* If arguments are NULL we will now actually send the resolvings
1069 that earlier has been gathered by calling this function. */
1070 if (!sock && !client_entry) {
1073 SILC_LOG_DEBUG(("Sending the resolvings"));
1075 /* WHOWAS resolving has been done at the same time this function
1076 was called to add the resolving for WHOWAS, so just return. */
1077 if (query->querycmd == SILC_COMMAND_WHOWAS)
1080 for (i = 0; i < query->querylist_count; i++) {
1081 r = &query->querylist[i];
1083 /* If Requested Attributes were present put them to this resolving */
1084 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1086 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1087 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1088 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1090 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1092 r->arg[r->argc] = silc_memdup(tmp, len);
1093 r->arg_lens[r->argc] = len;
1094 r->arg_types[r->argc] = 3;
1098 /* Send WHOIS command */
1099 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1100 r->argc, r->arg, r->arg_lens,
1101 r->arg_types, r->ident);
1102 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1103 res_cmd->data, res_cmd->len, FALSE);
1104 silc_buffer_free(res_cmd);
1106 /* Reprocess this packet after received reply */
1107 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1109 silc_server_query_resolve_reply,
1111 query->queries_left++;
1114 /* Cleanup this temporary context */
1115 for (i = 0; i < query->querylist_count; i++) {
1117 for (k = 0; k < query->querylist[i].argc; k++)
1118 silc_free(query->querylist[i].arg[k]);
1119 silc_free(query->querylist[i].arg);
1120 silc_free(query->querylist[i].arg_lens);
1121 silc_free(query->querylist[i].arg_types);
1123 silc_free(query->querylist);
1124 query->querylist = NULL;
1125 query->querylist_count = 0;
1129 SILC_LOG_DEBUG(("Resolving client information"));
1131 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1132 /* The entry is being resolved by some other external query already.
1133 Attach to that query instead of resolving again. */
1134 ident = client_entry->resolve_cmd_ident;
1135 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1136 silc_server_query_resolve_reply, query))
1137 query->queries_left++;
1139 /* This entry will be resolved */
1140 ident = ++server->cmd_ident;
1142 switch (query->querycmd) {
1144 case SILC_COMMAND_WHOIS:
1145 case SILC_COMMAND_IDENTIFY:
1146 /* Take existing query context if exist for this connection */
1147 for (i = 0; i < query->querylist_count; i++)
1148 if (query->querylist[i].sock == sock) {
1149 r = &query->querylist[i];
1154 /* Allocate new temp query list context */
1155 query->querylist = silc_realloc(query->querylist,
1156 sizeof(*query->querylist) *
1157 (query->querylist_count + 1));
1158 r = &query->querylist[query->querylist_count];
1159 query->querylist_count++;
1160 memset(r, 0, sizeof(*r));
1163 if (SILC_IS_LOCAL(client_entry))
1168 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1169 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1170 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1172 /* Add the client entry to be resolved */
1173 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1174 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1175 r->arg_lens[r->argc] = idp->len;
1176 r->arg_types[r->argc] = r->argc + 4;
1178 silc_buffer_free(idp);
1182 case SILC_COMMAND_WHOWAS:
1183 /* We must send WHOWAS command since it's the only the way of
1184 resolving clients that are not present in the network anymore. */
1185 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1186 1, query->nickname, strlen(query->nickname));
1187 if (silc_server_command_pending(server, query->querycmd, ident,
1188 silc_server_query_resolve_reply, query))
1189 query->queries_left++;
1194 /* Mark the entry as being resolved */
1195 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1196 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1197 client_entry->resolve_cmd_ident = ident;
1198 client_entry->updated = time(NULL);
1200 /* Save the queried ID, which we will reprocess after we get this and
1201 all other queries back. */
1202 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1203 (query->queries_count + 1));
1204 if (query->queries) {
1205 i = query->queries_count;
1206 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1207 query->queries[i].id_type = SILC_ID_CLIENT;
1208 query->queries[i].ident = ident;
1209 query->queries_count++;
1213 /* Reply callback called after one resolving has been completed. If
1214 all resolvings has been received then we will continue with sending
1215 the command reply to the original sender of the query. */
1217 void silc_server_query_resolve_reply(void *context, void *reply)
1219 SilcServerQuery query = context;
1220 SilcServer server = query->cmd->server;
1221 SilcServerCommandReplyContext cmdr = reply;
1222 SilcUInt16 ident = cmdr->ident;
1223 SilcStatus error = SILC_STATUS_OK;
1224 SilcServerQueryID id = NULL;
1225 SilcClientEntry client_entry;
1228 /* One less query left */
1229 query->queries_left--;
1231 silc_command_get_status(cmdr->payload, NULL, &error);
1232 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1233 query->queries_left, error));
1235 /* If no error then skip to other stuff */
1236 if (error == SILC_STATUS_OK)
1239 /* Error occurred during resolving */
1241 /* Find the resolved client ID */
1242 for (i = 0; i < query->queries_count; i++) {
1243 if (query->queries[i].ident != ident)
1246 id = &query->queries[i];
1248 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1250 /* If timeout occurred for local entry when resolving attributes
1251 mark that this client doesn't support attributes in WHOIS. This
1252 assures we won't send the request again to the client. */
1253 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1254 client_entry = silc_idlist_find_client_by_id(server->local_list,
1255 id->id, TRUE, NULL);
1256 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1257 silc_id_render(id->id, SILC_ID_CLIENT)));
1258 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1259 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1260 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1265 /* Remove the RESOLVING status from the client entry */
1266 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1267 client_entry = silc_idlist_find_client_by_id(server->local_list,
1268 id->id, TRUE, NULL);
1270 client_entry = silc_idlist_find_client_by_id(server->global_list,
1271 id->id, TRUE, NULL);
1273 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1280 /* If there are queries left then wait for them */
1281 if (query->queries_left)
1284 SILC_LOG_DEBUG(("Reprocess the query"));
1286 /* We have received all queries. Now re-search all information required
1287 to complete this query. Reason we cannot save the values found in
1288 the first search is that SilcClientEntry, SilcServerEntry and
1289 SilcChannelEntry pointers may become invalid while we were waiting
1290 for these resolvings. */
1291 silc_server_query_process(server, query, FALSE);
1294 /* Send the reply to the original query. If arguments are NULL then this
1295 sends only the errors that has occurred during the processing of the
1296 query. This sends the errors always after sending all the found
1297 information. The query is over after this function returns and the
1298 `query' will become invalid. This is called only after all informations
1299 has been resolved. This means that if something is not found or is
1300 incomplete in this function we were unable to resolve the information
1301 or it does not exist at all. */
1303 void silc_server_query_send_reply(SilcServer server,
1304 SilcServerQuery query,
1305 SilcClientEntry *clients,
1306 SilcUInt32 clients_count,
1307 SilcServerEntry *servers,
1308 SilcUInt32 servers_count,
1309 SilcChannelEntry *channels,
1310 SilcUInt32 channels_count)
1312 SilcServerCommandContext cmd = query->cmd;
1313 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1318 int i, k, valid_count;
1319 char nh[256], uh[256];
1320 bool sent_reply = FALSE;
1322 SILC_LOG_DEBUG(("Sending reply to query"));
1323 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1324 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1325 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1326 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1328 status = SILC_STATUS_OK;
1331 if (clients_count) {
1332 SilcClientEntry entry;
1333 SilcSocketConnection hsock;
1335 /* Mark all invalid entries */
1336 for (i = 0, valid_count = 0; i < clients_count; i++) {
1341 switch (query->querycmd) {
1342 case SILC_COMMAND_WHOIS:
1343 if (!entry->nickname || !entry->username || !entry->userinfo ||
1344 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1345 /* When querying by ID, every "unfound" entry must cause error */
1347 silc_server_query_add_error_id(server, query,
1348 SILC_STATUS_ERR_TIMEDOUT,
1349 entry->id, SILC_ID_CLIENT);
1355 case SILC_COMMAND_IDENTIFY:
1356 if (!entry->nickname ||
1357 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1358 /* When querying by ID, every "unfound" entry must cause error */
1360 silc_server_query_add_error_id(server, query,
1361 SILC_STATUS_ERR_TIMEDOUT,
1362 entry->id, SILC_ID_CLIENT);
1368 case SILC_COMMAND_WHOWAS:
1369 if (!entry->nickname || !entry->username ||
1370 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1379 /* Start processing found clients */
1380 status = SILC_STATUS_OK;
1381 if (valid_count > 1)
1382 status = SILC_STATUS_LIST_START;
1384 /* Now do the sending of valid entries */
1386 for (i = 0; i < clients_count && valid_count; i++) {
1392 status = SILC_STATUS_LIST_ITEM;
1393 if (valid_count > 1 && k == valid_count - 1
1394 && !servers_count && !channels_count && !query->errors_count)
1395 status = SILC_STATUS_LIST_END;
1396 if (query->reply_count && k - 1 == query->reply_count)
1397 status = SILC_STATUS_LIST_END;
1399 SILC_LOG_DEBUG(("%s: client %s",
1400 (status == SILC_STATUS_OK ? " OK" :
1401 status == SILC_STATUS_LIST_START ? "START" :
1402 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1403 status == SILC_STATUS_LIST_END ? " END" :
1404 " : "), entry->nickname));
1406 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1407 memset(uh, 0, sizeof(uh));
1408 memset(nh, 0, sizeof(nh));
1410 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1411 if (!strchr(entry->nickname, '@')) {
1412 silc_strncat(nh, sizeof(nh), "@", 1);
1413 if (entry->servername) {
1414 silc_strncat(nh, sizeof(nh), entry->servername,
1415 strlen(entry->servername));
1417 len = entry->router ? strlen(entry->router->server_name) :
1418 strlen(server->server_name);
1419 silc_strncat(nh, sizeof(nh), entry->router ?
1420 entry->router->server_name :
1421 server->server_name, len);
1425 switch (query->querycmd) {
1427 case SILC_COMMAND_WHOIS:
1429 unsigned char idle[4], mode[4];
1430 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1431 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1433 memset(fempty, 0, sizeof(fempty));
1434 memset(idle, 0, sizeof(idle));
1435 silc_strncat(uh, sizeof(uh), entry->username,
1436 strlen(entry->username));
1437 if (!strchr(entry->username, '@') && entry->connection) {
1438 hsock = entry->connection;
1439 silc_strncat(uh, sizeof(uh), "@", 1);
1440 len = strlen(hsock->hostname);
1441 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1444 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1446 silc_server_get_client_channel_list(server, entry, FALSE,
1447 FALSE, &umode_list);
1450 silc_server_get_client_channel_list(server, entry, TRUE,
1453 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1454 fingerprint = entry->data.fingerprint;
1458 SILC_PUT32_MSB(entry->mode, mode);
1459 if (entry->connection)
1460 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1462 /* If Requested Attribute were present, and we do not have the
1463 attributes we will reply to them on behalf of the client. */
1466 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1467 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1468 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1469 entry->attrs_len = len;
1470 silc_buffer_free(tmpattrs);
1472 attrs = entry->attrs;
1473 len = entry->attrs_len;
1476 /* Send command reply */
1477 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1478 status, 0, ident, 10,
1479 2, idp->data, idp->len,
1483 strlen(entry->userinfo),
1484 6, channels ? channels->data : NULL,
1485 channels ? channels->len : 0,
1489 fingerprint ? 20 : 0,
1490 10, umode_list ? umode_list->data :
1491 NULL, umode_list ? umode_list->len :
1496 /* For now we always delete Requested Attributes, unless the client
1497 is detached, in which case we don't want to reconstruct the
1498 same data everytime */
1499 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1500 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1501 silc_free(entry->attrs);
1502 entry->attrs = NULL;
1506 silc_buffer_free(channels);
1508 silc_buffer_free(umode_list);
1514 case SILC_COMMAND_IDENTIFY:
1515 if (!entry->username) {
1516 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1517 status, 0, ident, 2,
1518 2, idp->data, idp->len,
1522 silc_strncat(uh, sizeof(uh), entry->username,
1523 strlen(entry->username));
1524 if (!strchr(entry->username, '@') && entry->connection) {
1525 hsock = entry->connection;
1526 silc_strncat(uh, sizeof(uh), "@", 1);
1527 len = strlen(hsock->hostname);
1528 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1531 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1532 status, 0, ident, 3,
1533 2, idp->data, idp->len,
1540 case SILC_COMMAND_WHOWAS:
1541 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1542 if (!strchr(entry->username, '@'))
1543 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1545 /* Send command reply */
1546 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1547 status, 0, ident, 4,
1548 2, idp->data, idp->len,
1553 strlen(entry->userinfo) : 0);
1558 silc_buffer_free(idp);
1560 if (status == SILC_STATUS_LIST_END)
1566 /* Not one valid entry was found, send error. If nickname was used
1567 in query send error based on that, otherwise the query->errors
1568 already includes proper errors. */
1569 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1570 silc_server_query_add_error(server, query, 1, 1,
1571 SILC_STATUS_ERR_NO_SUCH_NICK);
1576 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1577 SilcServerEntry entry;
1579 if (status == SILC_STATUS_OK && servers_count > 1)
1580 status = SILC_STATUS_LIST_START;
1583 for (i = 0; i < servers_count; i++) {
1587 status = SILC_STATUS_LIST_ITEM;
1588 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1589 !query->errors_count)
1590 status = SILC_STATUS_LIST_END;
1591 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1592 !query->errors_count)
1593 status = SILC_STATUS_LIST_END;
1594 if (query->reply_count && k - 1 == query->reply_count)
1595 status = SILC_STATUS_LIST_END;
1597 SILC_LOG_DEBUG(("%s: server %s",
1598 (status == SILC_STATUS_OK ? " OK" :
1599 status == SILC_STATUS_LIST_START ? "START" :
1600 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1601 status == SILC_STATUS_LIST_END ? " END" :
1603 entry->server_name ? entry->server_name : ""));
1605 /* Send command reply */
1606 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1607 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1608 status, 0, ident, 2,
1609 2, idp->data, idp->len,
1610 3, entry->server_name,
1611 entry->server_name ?
1612 strlen(entry->server_name) : 0);
1613 silc_buffer_free(idp);
1616 if (status == SILC_STATUS_LIST_END)
1623 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1624 SilcChannelEntry entry;
1626 if (status == SILC_STATUS_OK && channels_count > 1)
1627 status = SILC_STATUS_LIST_START;
1630 for (i = 0; i < channels_count; i++) {
1631 entry = channels[i];
1634 status = SILC_STATUS_LIST_ITEM;
1635 if (channels_count == 1 && status != SILC_STATUS_OK &&
1636 !query->errors_count)
1637 status = SILC_STATUS_LIST_END;
1638 if (channels_count > 1 && k == channels_count - 1 &&
1639 !query->errors_count)
1640 status = SILC_STATUS_LIST_END;
1641 if (query->reply_count && k - 1 == query->reply_count)
1642 status = SILC_STATUS_LIST_END;
1644 SILC_LOG_DEBUG(("%s: channel %s",
1645 (status == SILC_STATUS_OK ? " OK" :
1646 status == SILC_STATUS_LIST_START ? "START" :
1647 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1648 status == SILC_STATUS_LIST_END ? " END" :
1650 entry->channel_name ? entry->channel_name : ""));
1652 /* Send command reply */
1653 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1654 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1655 status, 0, ident, 2,
1656 2, idp->data, idp->len,
1657 3, entry->channel_name,
1658 entry->channel_name ?
1659 strlen(entry->channel_name) : 0);
1660 silc_buffer_free(idp);
1663 if (status == SILC_STATUS_LIST_END)
1670 if (query->errors_count) {
1673 if (status == SILC_STATUS_OK && query->errors_count > 1)
1674 status = SILC_STATUS_LIST_START;
1677 for (i = 0; i < query->errors_count; i++) {
1680 /* Take error argument */
1681 if (query->errors[i].type == 1) {
1682 /* Take from sent arguments */
1684 tmp = silc_argument_get_arg_type(cmd->args,
1685 query->errors[i].index, &len);
1687 } else if (query->errors[i].type == 2) {
1692 } else if (!query->errors[i].id) {
1693 /* Take from query->ids */
1695 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1696 query->ids[query->errors[k].index].id_type);
1701 /* Take added ID. */
1702 idp = silc_id_payload_encode(query->errors[i].id,
1703 query->errors[k].id_type);
1710 status = SILC_STATUS_LIST_ITEM;
1711 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1712 status = SILC_STATUS_LIST_END;
1713 if (query->errors_count > 1 && k == query->errors_count - 1)
1714 status = SILC_STATUS_LIST_END;
1715 if (query->reply_count && k - 1 == query->reply_count)
1716 status = SILC_STATUS_LIST_END;
1718 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1719 (status == SILC_STATUS_OK ? " OK" :
1720 status == SILC_STATUS_LIST_START ? "START" :
1721 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1722 status == SILC_STATUS_LIST_END ? " END" :
1724 silc_get_status_message(query->errors[i].error),
1725 query->errors[i].error));
1727 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1728 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1730 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1731 (status == SILC_STATUS_OK ?
1732 query->errors[i].error : status),
1733 (status == SILC_STATUS_OK ?
1734 0 : query->errors[i].error), ident, 2,
1740 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1741 (status == SILC_STATUS_OK ?
1742 query->errors[i].error : status),
1743 (status == SILC_STATUS_OK ?
1744 0 : query->errors[i].error), ident, 1,
1747 silc_buffer_free(idp);
1750 if (status == SILC_STATUS_LIST_END)
1757 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1760 silc_server_query_free(query);
1763 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1764 of the client since we were unable to resolve them from the client.
1765 Either client does not support Requested Attributes or isn't replying
1766 to them like it should. */
1768 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1769 SilcServerQuery query,
1770 SilcClientEntry client_entry)
1772 SilcBuffer buffer = NULL;
1773 SilcAttribute attribute;
1774 SilcAttributePayload attr;
1775 SilcAttributeObjPk pk;
1776 SilcAttributeObjService service;
1778 unsigned char sign[2048 + 1];
1779 SilcUInt32 sign_len;
1781 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1783 /* Go through all requested attributes */
1784 silc_dlist_start(query->attrs);
1785 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1786 attribute = silc_attribute_get_attribute(attr);
1787 switch (attribute) {
1789 case SILC_ATTRIBUTE_SERVICE:
1790 /* Put SERVICE. Put only SILC service. */
1791 memset(&service, 0, sizeof(service));
1792 service.port = (server->config->server_info->primary ?
1793 server->config->server_info->primary->port : SILC_PORT);
1794 silc_strncat(service.address, sizeof(service.address),
1795 server->server_name, strlen(server->server_name));
1796 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1797 if (client_entry->connection)
1798 service.idle = time(NULL) - client_entry->data.last_receive;
1799 buffer = silc_attribute_payload_encode(buffer, attribute,
1800 SILC_ATTRIBUTE_FLAG_VALID,
1801 &service, sizeof(service));
1806 case SILC_ATTRIBUTE_STATUS_MOOD:
1807 /* Put STATUS_MOOD */
1808 buffer = silc_attribute_payload_encode(buffer, attribute,
1809 SILC_ATTRIBUTE_FLAG_VALID,
1811 SILC_ATTRIBUTE_MOOD_NORMAL,
1812 sizeof(SilcUInt32));
1817 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1818 /* Put STATUS_FREETEXT. We just tell in the message that we are
1819 replying on behalf of the client. */
1821 "This information was provided by the server on behalf of the user";
1822 buffer = silc_attribute_payload_encode(buffer, attribute,
1823 SILC_ATTRIBUTE_FLAG_VALID,
1829 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1830 /* Put PREFERRED_CONTACT */
1831 buffer = silc_attribute_payload_encode(buffer, attribute,
1832 SILC_ATTRIBUTE_FLAG_VALID,
1834 SILC_ATTRIBUTE_CONTACT_CHAT,
1835 sizeof(SilcUInt32));
1840 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1841 /* Put USER_PUBLIC_KEY */
1842 if (client_entry->data.public_key) {
1843 pk.type = "silc-rsa";
1844 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1846 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1847 SILC_ATTRIBUTE_FLAG_VALID :
1848 SILC_ATTRIBUTE_FLAG_INVALID,
1856 /* No public key available */
1857 buffer = silc_attribute_payload_encode(buffer, attribute,
1858 SILC_ATTRIBUTE_FLAG_INVALID,
1865 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1866 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1867 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1870 /* For other attributes we cannot reply so mark it invalid */
1871 buffer = silc_attribute_payload_encode(buffer, attribute,
1872 SILC_ATTRIBUTE_FLAG_INVALID,
1880 /* Always put our public key. This assures that we send at least
1881 something valid back always. */
1882 pk.type = "silc-rsa";
1883 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1884 buffer = silc_attribute_payload_encode(buffer,
1885 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1886 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1887 SILC_ATTRIBUTE_FLAG_INVALID,
1893 /* Finally compute the digital signature of all the data we provided
1894 as an indication that we provided rightfull information, and this
1895 also authenticates our public key. */
1896 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1897 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1898 buffer->data, buffer->len,
1902 pk.data_len = sign_len;
1904 silc_attribute_payload_encode(buffer,
1905 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1906 SILC_ATTRIBUTE_FLAG_VALID,
1915 /* Find client by the Client ID indicated by the `client_id', and if not
1916 found then query it by using WHOIS command. The client information
1917 is also resolved if the cached information is incomplete or if the
1918 `always_resolve' is set to TRUE. The indication whether requested
1919 client was being resolved is saved into `resolved'. If the client
1920 is not being resolved its entry is returned by this function. NULL
1921 is returned if client is resolved. */
1923 SilcClientEntry silc_server_query_client(SilcServer server,
1924 const SilcClientID *client_id,
1925 bool always_resolve,
1928 SilcClientEntry client;
1930 SILC_LOG_DEBUG(("Resolving client by client ID"));
1935 client = silc_idlist_find_client_by_id(server->local_list,
1936 (SilcClientID *)client_id,
1939 client = silc_idlist_find_client_by_id(server->global_list,
1940 (SilcClientID *)client_id,
1942 if (!client && server->server_type == SILC_ROUTER)
1946 if (!client && server->standalone)
1949 if (!client || !client->nickname || !client->username ||
1951 SilcBuffer buffer, idp;
1954 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1955 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1956 client->resolve_cmd_ident = ++server->cmd_ident;
1959 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1960 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1961 server->cmd_ident, 1,
1962 4, idp->data, idp->len);
1963 silc_server_packet_send(server, client ? client->router->connection :
1964 SILC_PRIMARY_ROUTE(server),
1965 SILC_PACKET_COMMAND, 0,
1966 buffer->data, buffer->len, FALSE);
1967 silc_buffer_free(idp);
1968 silc_buffer_free(buffer);