5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005, 2007 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 SilcPacketStream 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[128 + 1]; /* Queried nickname, normalized */
55 char nick_server[128 + 1]; /* 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 SilcPacketStream router; /* Router to send our query */
65 SilcServerCommandContext cmd; /* Command context for query */
66 SilcServerQueryList querylist; /* Temporary query list context */
67 SilcServerQueryID queries; /* Ongoing queries */
68 SilcServerQueryError errors; /* Query errors */
69 SilcUInt16 querylist_count; /* Number of query lists */
70 SilcUInt16 queries_count; /* Number of ongoing queries */
71 SilcUInt16 queries_left; /* Number of ongoing queries left */
72 SilcUInt16 errors_count; /* number of errors */
73 unsigned int querycmd : 7; /* Query command (SilcCommand) */
74 unsigned int resolved : 1; /* TRUE if normal server has resolved
75 information from router */
76 unsigned int dynamic_prim : 1; /* Dynamic connection attempt to primary */
77 unsigned int dynamic_retry : 1; /* Primary returned error, send to
79 unsigned int parsed : 1; /* Set when query is parsed */
83 void silc_server_query_free(SilcServerQuery query);
84 void silc_server_query_send_error(SilcServer server,
85 SilcServerQuery query,
86 SilcStatus error, ...);
87 void silc_server_query_add_error(SilcServer server,
88 SilcServerQuery query,
92 void silc_server_query_add_error_id(SilcServer server,
93 SilcServerQuery query,
95 void *id, SilcIdType id_type);
96 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
97 void silc_server_query_send_router_reply(void *context, void *reply);
98 SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
100 void silc_server_query_process(SilcServer server, SilcServerQuery query,
102 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
103 SilcPacketStream sock,
104 SilcClientEntry client_entry);
105 void silc_server_query_resolve_reply(void *context, void *reply);
106 void silc_server_query_send_reply(SilcServer server,
107 SilcServerQuery query,
108 SilcClientEntry *clients,
109 SilcUInt32 clients_count,
110 SilcServerEntry *servers,
111 SilcUInt32 servers_count,
112 SilcChannelEntry *channels,
113 SilcUInt32 channels_count);
114 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
115 SilcServerQuery query,
116 SilcClientEntry client_entry);
118 /* Free the query context structure and all allocated resources. */
120 void silc_server_query_free(SilcServerQuery query)
124 silc_server_command_free(query->cmd);
126 for (i = 0; i < query->queries_count; i++)
127 silc_free(query->queries[i].id);
128 silc_free(query->queries);
130 silc_free(query->server_name);
131 silc_free(query->channel_name);
133 for (i = 0; i < query->ids_count; i++)
134 silc_free(query->ids[i].id);
135 silc_free(query->ids);
138 silc_attribute_payload_list_free(query->attrs);
140 for (i = 0; i < query->errors_count; i++)
141 silc_free(query->errors[i].id);
142 silc_free(query->errors);
144 memset(query, 'F', sizeof(*query));
148 /* Send error reply indicated by the `error' to the original sender of
151 void silc_server_query_send_error(SilcServer server,
152 SilcServerQuery query,
153 SilcStatus error, ...)
156 unsigned char *data = NULL;
157 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
160 data_type = va_arg(va, SilcUInt32);
163 data = va_arg(va, unsigned char *);
164 data_len = va_arg(va, SilcUInt32);
167 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
169 /* Send the command reply with error */
170 silc_server_send_command_reply(server, query->cmd->sock,
171 query->querycmd, error, 0,
172 silc_command_get_ident(query->cmd->payload),
173 argc, data_type, data, data_len);
177 /* Add error to error list. Multiple errors may occur during the query
178 processing and this function can be used to add one error. The
179 `index' is the index to the command context which includes the argument
180 which caused the error, or it is the index to query->ids, depending
181 on value of `type'. If `type' is 0 the index is to query->ids, if
182 it is 1 it is index to the command context arguments, and if it is
183 2 the index is ignored and no argument is included in the error. */
185 void silc_server_query_add_error(SilcServer server,
186 SilcServerQuery query,
191 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
192 (query->errors_count + 1));
195 query->errors[query->errors_count].index = index;
196 query->errors[query->errors_count].type = type;
197 query->errors[query->errors_count].error = error;
198 query->errors[query->errors_count].id = NULL;
199 query->errors[query->errors_count].id_type = 0;
200 query->errors_count++;
203 /* Same as silc_server_query_add_error but adds the ID data to be used
204 with error sending with this error type. */
206 void silc_server_query_add_error_id(SilcServer server,
207 SilcServerQuery query,
209 void *id, SilcIdType id_type)
211 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
212 (query->errors_count + 1));
215 query->errors[query->errors_count].index = 0;
216 query->errors[query->errors_count].type = 0;
217 query->errors[query->errors_count].error = error;
218 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
219 query->errors[query->errors_count].id_type = id_type;
220 query->errors_count++;
223 /* Processes query as command. The `query' is the command that is
224 being processed indicated by the `cmd'. The `query' can be one of
225 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
226 SILC_COMMAND_IDENTIFY. This function handles the reply sending
227 to the entity who sent this query to us automatically. Returns
228 TRUE if the query is being processed or FALSE on error. */
230 SilcBool silc_server_query_command(SilcServer server,
231 SilcCommand querycmd,
232 SilcServerCommandContext cmd,
235 SilcServerQuery query;
237 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
240 query = silc_calloc(1, sizeof(*query));
241 query->querycmd = querycmd;
242 query->cmd = silc_server_command_dup(cmd);
243 query->router = SILC_PRIMARY_ROUTE(server);
249 case SILC_COMMAND_WHOIS:
250 /* If we are normal server and query contains nickname OR query
251 doesn't contain nickname or ids BUT attributes, send it to the
253 if (server->server_type != SILC_ROUTER && !server->standalone &&
254 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
255 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
256 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
257 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
258 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
259 if (!silc_server_query_parse(server, query, TRUE))
261 silc_server_query_send_router(server, query);
266 case SILC_COMMAND_WHOWAS:
267 /* WHOWAS query is always sent to router if we are normal server */
268 if (server->server_type == SILC_SERVER && !server->standalone &&
269 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
270 silc_server_query_send_router(server, query);
275 case SILC_COMMAND_IDENTIFY:
276 /* If we are normal server and query does not contain IDs, send it
277 directly to router (it contains nickname, server name or channel
279 if (server->server_type == SILC_SERVER && !server->standalone &&
280 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
281 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
282 if (!silc_server_query_parse(server, query, TRUE))
284 silc_server_query_send_router(server, query);
290 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
291 silc_server_query_free(query);
295 /* Now parse the request */
296 silc_server_query_parse(server, query, FALSE);
301 /* Remote server connected callback. */
303 void silc_server_query_connected(SilcServer server,
304 SilcServerEntry server_entry,
307 SilcServerQuery query = context;
310 /* Connecting failed */
312 if (query->dynamic_prim /* && @serv != prim.host.name */ &&
313 !silc_server_num_sockets_by_remote(server, query->nick_server,
314 query->nick_server, 706)) {
315 /* Connection attempt to primary router failed, now try to the one
316 specified in nick@server. */
317 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
318 706, silc_server_query_connected,
320 query->dynamic_prim = FALSE;
324 /* Process the query after failed connect. This will send error back
325 because such nick was not found. */
326 SILC_LOG_DEBUG(("Process query, connecting failed"));
327 silc_server_query_process(server, query, TRUE);
331 /* Reprocess the query */
332 SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
333 server_entry->server_name));
334 query->router = server_entry->data.sconn->sock;
335 silc_server_query_command(server, query->querycmd, query->cmd, query);
338 /* Send the received query to our primary router since we could not
339 handle the query directly. We will reprocess the query after our
340 router replies back. */
342 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
345 SilcUInt16 old_ident;
347 SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
351 server->stat.commands_sent++;
353 /* Send WHOIS command to our router */
354 old_ident = silc_command_get_ident(query->cmd->payload);
355 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
356 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
357 silc_server_packet_send(server, query->router,
358 SILC_PACKET_COMMAND, 0,
359 tmpbuf->data, silc_buffer_len(tmpbuf));
360 silc_command_set_ident(query->cmd->payload, old_ident);
361 silc_buffer_free(tmpbuf);
363 query->resolved = TRUE;
365 /* Continue parsing the query after received reply from router */
366 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
367 silc_server_query_send_router_reply, query);
370 /* Reply callback called after primary router has replied to our initial
371 sending of the query to it. We will proceed the query in this function. */
373 void silc_server_query_send_router_reply(void *context, void *reply)
375 SilcServerQuery query = context;
376 SilcServer server = query->cmd->server;
377 SilcServerCommandReplyContext cmdr = reply;
379 SILC_LOG_DEBUG(("Received reply from router to query"));
381 /* If the original command caller has gone away, just stop. */
382 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
383 SILC_LOG_DEBUG(("Original command caller vanished"));
384 silc_server_query_free(query);
388 /* Check if router sent error reply */
389 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
392 /* If this was nick@server query, retry to @serv if the primary router
394 if (query->nick_server[0] && !query->dynamic_retry &&
395 !silc_server_num_sockets_by_remote(server, query->nick_server,
396 query->nick_server, 1334)) {
397 SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
398 query->nick_server, 706));
399 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
400 1334, silc_server_query_connected,
402 query->dynamic_retry = TRUE;
403 query->resolved = FALSE;
407 SILC_LOG_DEBUG(("Sending error to original query"));
410 server->stat.commands_sent++;
412 /* Send the same command reply payload which contains the error */
413 silc_command_set_command(cmdr->payload, query->querycmd);
414 silc_command_set_ident(cmdr->payload,
415 silc_command_get_ident(query->cmd->payload));
416 buffer = silc_command_payload_encode_payload(cmdr->payload);
417 silc_server_packet_send(server, query->cmd->sock,
418 SILC_PACKET_COMMAND_REPLY, 0,
419 buffer->data, silc_buffer_len(buffer));
420 silc_buffer_free(buffer);
421 silc_server_query_free(query);
425 /* Continue with parsing */
426 silc_server_query_parse(server, query, FALSE);
429 /* Parse the command query and start processing the queries in detail. */
431 SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
434 SilcServerCommandContext cmd = query->cmd;
435 SilcIDListData idata = silc_packet_get_context(cmd->sock);
437 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
441 SILC_LOG_DEBUG(("Parsing %s query",
442 silc_get_command_name(query->querycmd)));
447 switch (query->querycmd) {
449 case SILC_COMMAND_WHOIS:
450 /* Get requested attributes if set */
451 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
452 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
453 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
455 /* When Requested Attributes is present we will assure that this
456 client cannot execute the WHOIS command too fast. This would be
457 same as having SILC_CF_LAG_STRICT. */
458 if (idata && idata->conn_type == SILC_CONN_CLIENT)
459 ((SilcClientEntry)idata)->fast_command = 6;
462 /* Get Client IDs if present. Take IDs always instead of nickname. */
463 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
467 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
468 if (!tmp && !query->attrs) {
469 /* No nickname, no ids and no attributes - send error */
470 silc_server_query_send_error(server, query,
471 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
472 silc_server_query_free(query);
476 /* Get the nickname@server string and parse it */
477 if (tmp && ((tmp_len > 128) ||
478 !silc_parse_userfqdn(tmp, query->nickname,
479 sizeof(query->nickname),
481 sizeof(query->nick_server)))) {
482 silc_server_query_send_error(server, query,
483 SILC_STATUS_ERR_BAD_NICKNAME, 0);
484 silc_server_query_free(query);
490 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
491 SILC_STRING_UTF8, 128, &tmp_len);
493 silc_server_query_send_error(server, query,
494 SILC_STATUS_ERR_BAD_NICKNAME, 0);
495 silc_server_query_free(query);
498 memset(query->nickname, 0, sizeof(query->nickname));
499 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
504 /* Parse the IDs included in the query */
505 query->ids = silc_calloc(argc, sizeof(*query->ids));
507 for (i = 0; i < argc; i++) {
508 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
512 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
513 id.type != SILC_ID_CLIENT) {
514 silc_server_query_add_error(server, query, 1, i + 4,
515 SILC_STATUS_ERR_BAD_CLIENT_ID);
519 /* Normal server must check whether this ID exist, and if not then
520 send the query to router, unless done so already */
521 if (server->server_type == SILC_SERVER && !query->resolved) {
522 if (!silc_idlist_find_client_by_id(server->local_list,
523 &id.u.client_id, TRUE, NULL)) {
524 if (idata->conn_type != SILC_CONN_CLIENT ||
525 !silc_idlist_find_client_by_id(server->global_list,
526 &id.u.client_id, TRUE, NULL)) {
527 silc_server_query_send_router(server, query);
528 for (i = 0; i < query->ids_count; i++)
529 silc_free(query->ids[i].id);
530 silc_free(query->ids);
532 query->ids_count = 0;
538 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
540 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
545 /* Get the max count of reply messages allowed */
546 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
547 if (tmp && tmp_len == sizeof(SilcUInt32))
548 SILC_GET32_MSB(query->reply_count, tmp);
551 case SILC_COMMAND_WHOWAS:
553 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
555 silc_server_query_send_error(server, query,
556 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
557 silc_server_query_free(query);
561 /* Get the nickname@server string and parse it */
563 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
564 query->nick_server, sizeof(query->nick_server))) {
565 silc_server_query_send_error(server, query,
566 SILC_STATUS_ERR_BAD_NICKNAME, 0);
567 silc_server_query_free(query);
572 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
573 SILC_STRING_UTF8, 128, &tmp_len);
575 silc_server_query_send_error(server, query,
576 SILC_STATUS_ERR_BAD_NICKNAME, 0);
577 silc_server_query_free(query);
580 memset(query->nickname, 0, sizeof(query->nickname));
581 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
584 /* Get the max count of reply messages allowed */
585 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
586 if (tmp && tmp_len == sizeof(SilcUInt32))
587 SILC_GET32_MSB(query->reply_count, tmp);
590 case SILC_COMMAND_IDENTIFY:
591 /* Get IDs if present. Take IDs always instead of names. */
592 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
595 /* Try get nickname */
596 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
598 /* Get the nickname@server string and parse it */
600 !silc_parse_userfqdn(tmp, query->nickname,
601 sizeof(query->nickname),
603 sizeof(query->nick_server)))
604 silc_server_query_add_error(server, query, 1, 1,
605 SILC_STATUS_ERR_BAD_NICKNAME);
608 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
609 SILC_STRING_UTF8, 128, &tmp_len);
611 silc_server_query_send_error(server, query,
612 SILC_STATUS_ERR_BAD_NICKNAME, 0);
613 silc_server_query_free(query);
616 memset(query->nickname, 0, sizeof(query->nickname));
617 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
621 /* Try get server name */
622 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
624 /* Check server name */
625 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
628 silc_server_query_send_error(server, query,
629 SILC_STATUS_ERR_BAD_SERVER, 0);
630 silc_server_query_free(query);
633 query->server_name = tmp;
636 /* Get channel name */
637 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
638 if (tmp && tmp_len <= 256) {
639 /* Check channel name */
640 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
643 silc_server_query_send_error(server, query,
644 SILC_STATUS_ERR_BAD_CHANNEL, 0);
645 silc_server_query_free(query);
648 query->channel_name = tmp;
651 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
652 silc_server_query_send_error(server, query,
653 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
654 silc_server_query_free(query);
659 /* Parse the IDs included in the query */
660 query->ids = silc_calloc(argc, sizeof(*query->ids));
662 for (i = 0; i < argc; i++) {
663 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
667 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
668 silc_server_query_add_error(server, query, 1, i + 5,
669 SILC_STATUS_ERR_BAD_CLIENT_ID);
673 /* Normal server must check whether this ID exist, and if not then
674 send the query to router, unless done so already */
675 if (server->server_type == SILC_SERVER && !query->resolved) {
676 if (id.type == SILC_ID_CLIENT) {
677 if (!silc_idlist_find_client_by_id(server->local_list,
678 &id.u.client_id, TRUE, NULL)) {
679 if (idata->conn_type != SILC_CONN_CLIENT ||
680 !silc_idlist_find_client_by_id(server->global_list,
681 &id.u.client_id, TRUE,
683 silc_server_query_send_router(server, query);
684 for (i = 0; i < query->ids_count; i++)
685 silc_free(query->ids[i].id);
686 silc_free(query->ids);
688 query->ids_count = 0;
693 /* For now all other ID's except Client ID's are explicitly
694 sent to router for resolving. */
695 silc_server_query_send_router(server, query);
696 for (i = 0; i < query->ids_count; i++)
697 silc_free(query->ids[i].id);
698 silc_free(query->ids);
700 query->ids_count = 0;
705 if (id.type == SILC_ID_CLIENT)
706 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
708 if (id.type == SILC_ID_SERVER)
709 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
711 if (id.type == SILC_ID_CHANNEL)
712 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
714 query->ids[query->ids_count].id_type = id.type;
719 /* Get the max count of reply messages allowed */
720 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
721 if (tmp && tmp_len == sizeof(SilcUInt32))
722 SILC_GET32_MSB(query->reply_count, tmp);
726 query->parsed = TRUE;
729 if (!parse_only && query->nickname) {
730 switch (query->querycmd) {
731 case SILC_COMMAND_WHOIS:
732 case SILC_COMMAND_IDENTIFY:
733 /* Check server name. If we are open server and don't yet have
734 connection to remote router, create it now. */
735 if (query->nick_server[0] && server->config->dynamic_server &&
737 /* If primary router is specified, use that. Otherwise connect
738 to the server in nick@server string. */
739 SilcServerConfigRouter *router;
741 router = silc_server_config_get_primary_router(server);
742 if (router && server->standalone) {
743 /* Create connection to primary router */
744 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
745 router->host, router->port));
746 query->dynamic_prim = TRUE;
747 silc_server_create_connection(server, FALSE, TRUE,
748 router->host, router->port,
749 silc_server_query_connected, query);
751 } else if (!silc_server_num_sockets_by_remote(server,
755 /* Create connection and handle the query after connection */
756 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
757 query->nick_server, 706));
758 silc_server_create_connection(server, FALSE, TRUE,
759 query->nick_server, 706,
760 silc_server_query_connected, query);
767 /* Start processing the query information */
769 silc_server_query_process(server, query, TRUE);
774 /* Context for holding clients searched by public key. */
776 SilcClientEntry **clients;
777 SilcUInt32 *clients_count;
779 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
781 /* SKR find callbcak */
783 static void silc_server_query_skr_callback(SilcSKR skr,
785 SilcSKRStatus status,
789 SilcServerPublicKeyUser uc = context;
793 (*uc->clients) = silc_realloc((*uc->clients),
794 sizeof((**uc->clients)) *
795 ((*uc->clients_count) +
796 silc_dlist_count(keys)));
798 silc_dlist_start(keys);
799 while ((key = silc_dlist_get(keys)))
800 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
803 silc_dlist_uninit(keys);
806 silc_skr_find_free(find);
809 /* If clients are set, limit the found clients using the attributes in
810 the query. If clients are not set, try to find some clients using
813 void silc_server_query_check_attributes(SilcServer server,
814 SilcServerQuery query,
815 SilcClientEntry **clients,
816 SilcUInt32 *clients_count) {
817 SilcClientEntry entry;
818 SilcAttributePayload attr;
819 SilcAttribute attribute;
820 SilcAttributeObjPk pk;
821 SilcPublicKey publickey, cmp_pubkey;
823 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
826 /* If no clients were found, we only check the attributes
827 if the user wasn't searching for nickname/ids */
830 if (query->nickname[0] || query->ids_count)
834 silc_dlist_start(query->attrs);
835 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
836 attribute = silc_attribute_get_attribute(attr);
839 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
840 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
842 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
845 if (!strcmp(pk.type, "silc-rsa"))
846 type = SILC_PKCS_SILC;
847 else if (!strcmp(pk.type, "ssh-rsa"))
848 type = SILC_PKCS_SSH2;
849 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
850 type = SILC_PKCS_X509V3;
851 else if (!strcmp(pk.type, "pgp-sign-rsa"))
852 type = SILC_PKCS_OPENPGP;
856 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
862 search_pubkey = TRUE;
864 /* If no clients were set on calling this function, we just search
865 for clients, otherwise we try to limit the clients. */
867 SilcServerPublicKeyUserStruct usercontext;
870 usercontext.clients = clients;
871 usercontext.clients_count = clients_count;
872 usercontext.found = FALSE;
874 find = silc_skr_find_alloc();
878 silc_skr_find_set_public_key(find, publickey);
879 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
880 silc_skr_find(server->repository, server->schedule,
881 find, silc_server_query_skr_callback, &usercontext);
883 if (usercontext.found == TRUE)
886 for (i = 0; i < *clients_count; i++) {
887 entry = (*clients)[i];
889 if (!entry->data.public_key)
892 if (silc_server_get_public_key_by_client(server, entry,
894 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
900 (*clients)[i] = NULL;
905 silc_pkcs_public_key_free(publickey);
910 if (!found && !query->nickname[0] && !query->ids)
911 silc_server_query_add_error(server, query, 2, 0,
913 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
914 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
917 /* Processes the parsed query. This does the actual finding of the
918 queried information and prepares for sending reply to the original
919 sender of the query command. */
921 void silc_server_query_process(SilcServer server, SilcServerQuery query,
924 SilcServerCommandContext cmd = query->cmd;
925 SilcIDListData idata = silc_packet_get_context(cmd->sock);
926 SilcBool check_global = FALSE;
928 SilcClientEntry *clients = NULL, client_entry;
929 SilcChannelEntry *channels = NULL;
930 SilcServerEntry *servers = NULL;
931 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
934 SILC_LOG_DEBUG(("Processing %s query",
935 silc_get_command_name(query->querycmd)));
937 /* Check global lists if query is coming from client or we are not
938 normal server (we know global information). */
939 if (idata->conn_type == SILC_CONN_CLIENT)
941 else if (server->server_type != SILC_SERVER)
944 if (query->nickname[0]) {
945 /* Get all clients matching nickname from local list */
946 if (!silc_idlist_get_clients_by_hash(server->local_list,
948 query->nick_server[0] ?
949 query->nick_server : NULL,
951 &clients, &clients_count))
952 silc_idlist_get_clients_by_nickname(server->local_list,
954 query->nick_server[0] ?
955 query->nick_server : NULL,
956 &clients, &clients_count);
958 /* Check global list as well */
960 if (!silc_idlist_get_clients_by_hash(server->global_list,
962 query->nick_server[0] ?
963 query->nick_server : NULL,
965 &clients, &clients_count))
966 silc_idlist_get_clients_by_nickname(server->global_list,
968 query->nick_server[0] ?
969 query->nick_server : NULL,
970 &clients, &clients_count);
974 silc_server_query_add_error(server, query, 1, 1,
975 SILC_STATUS_ERR_NO_SUCH_NICK);
978 if (query->server_name) {
979 /* Find server by name */
980 entry = silc_idlist_find_server_by_name(server->local_list,
981 query->server_name, TRUE, NULL);
982 if (!entry && check_global)
983 entry = silc_idlist_find_server_by_name(server->global_list,
984 query->server_name, TRUE, NULL);
986 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
987 servers[servers_count++] = (SilcServerEntry)entry;
991 silc_server_query_add_error(server, query, 1, 2,
992 SILC_STATUS_ERR_NO_SUCH_SERVER);
995 if (query->channel_name) {
996 /* Find channel by name */
997 entry = silc_idlist_find_channel_by_name(server->local_list,
998 query->channel_name, NULL);
999 if (!entry && check_global)
1000 entry = silc_idlist_find_channel_by_name(server->global_list,
1001 query->channel_name, NULL);
1003 channels = silc_realloc(channels, sizeof(*channels) *
1004 (channels_count + 1));
1005 channels[channels_count++] = (SilcChannelEntry)entry;
1009 silc_server_query_add_error(server, query, 1, 3,
1010 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1013 if (query->ids_count) {
1014 /* Find entries by the queried IDs */
1015 for (i = 0; i < query->ids_count; i++) {
1016 void *id = query->ids[i].id;
1020 switch (query->ids[i].id_type) {
1022 case SILC_ID_CLIENT:
1023 /* Get client entry */
1024 entry = silc_idlist_find_client_by_id(server->local_list,
1026 if (!entry && check_global)
1027 entry = silc_idlist_find_client_by_id(server->global_list,
1030 silc_server_query_add_error(server, query, 0, i,
1031 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1035 clients = silc_realloc(clients, sizeof(*clients) *
1036 (clients_count + 1));
1037 clients[clients_count++] = (SilcClientEntry)entry;
1040 case SILC_ID_SERVER:
1041 /* Get server entry */
1042 entry = silc_idlist_find_server_by_id(server->local_list,
1044 if (!entry && check_global)
1045 entry = silc_idlist_find_server_by_id(server->global_list,
1048 silc_server_query_add_error(server, query, 0, i,
1049 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1053 servers = silc_realloc(servers, sizeof(*servers) *
1054 (servers_count + 1));
1055 servers[servers_count++] = (SilcServerEntry)entry;
1058 case SILC_ID_CHANNEL:
1059 /* Get channel entry */
1060 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1061 if (!entry && check_global)
1062 entry = silc_idlist_find_channel_by_id(server->global_list, id,
1065 silc_server_query_add_error(server, query, 0, i,
1066 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1070 channels = silc_realloc(channels, sizeof(*channels) *
1071 (channels_count + 1));
1072 channels[channels_count++] = (SilcChannelEntry)entry;
1081 /* Check the attributes to narrow down the search by using them. */
1083 silc_server_query_check_attributes(server, query, &clients,
1086 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1087 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1088 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1090 /* If nothing was found, then just send the errors */
1091 if (!clients && !channels && !servers) {
1092 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1096 /* If caller does not want us to resolve anything (has resolved already)
1097 then just continue with sending the reply */
1099 silc_server_query_send_reply(server, query, clients, clients_count,
1100 servers, servers_count, channels,
1104 silc_free(channels);
1108 /* Now process all found information and if necessary do some more
1110 switch (query->querycmd) {
1112 case SILC_COMMAND_WHOIS:
1113 for (i = 0; i < clients_count; i++) {
1114 client_entry = clients[i];
1116 /* Check if cannot query this anyway, so take next one */
1117 if (!client_entry ||
1118 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1121 /* If Requested Attributes is set then we always resolve the client
1122 information, if not then check whether the entry is complete or not
1123 and decide whether we need to resolve or not. */
1124 if (!query->attrs) {
1126 /* Even if nickname and stuff are present, we may need to resolve
1128 if (client_entry->nickname && client_entry->username &&
1129 client_entry->userinfo) {
1130 /* Check if cannot query this anyway, so take next one */
1131 if (!client_entry->router)
1134 /* If we are router, client is local to us, or client is on channel
1135 we do not need to resolve the client information. */
1136 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1137 || silc_hash_table_count(client_entry->channels) ||
1143 /* Remove the NOATTR status periodically */
1144 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1145 client_entry->updated + 600 < time(NULL))
1146 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1148 /* When requested attributes is present and local client is detached
1149 we cannot send the command to the client, we'll reply on behalf of
1150 the client instead. */
1151 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1152 (client_entry->mode & SILC_UMODE_DETACHED ||
1153 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1156 /* If attributes are present in query, and in the entry and we have
1157 done resolvings already we don't need to resolve anymore */
1158 if (query->resolved && query->attrs && client_entry->attrs)
1161 /* Resolve the detailed client information. If client is local we
1162 know that attributes were present and we will resolve directly
1163 from the client. Otherwise resolve from client's owner. */
1164 silc_server_query_resolve(server, query,
1165 (SILC_IS_LOCAL(client_entry) ?
1166 client_entry->connection :
1167 client_entry->router->connection),
1172 case SILC_COMMAND_WHOWAS:
1173 for (i = 0; i < clients_count; i++) {
1174 client_entry = clients[i];
1176 /* Check if cannot query this anyway, so take next one */
1177 if (!client_entry || !client_entry->router ||
1178 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1181 /* If both nickname and username are present no resolving is needed */
1182 if (client_entry->nickname && client_entry->username)
1185 /* Resolve the detailed client information */
1186 silc_server_query_resolve(server, query,
1187 client_entry->router->connection,
1192 case SILC_COMMAND_IDENTIFY:
1193 for (i = 0; i < clients_count; i++) {
1194 client_entry = clients[i];
1196 /* Check if cannot query this anyway, so take next one */
1197 if (!client_entry || !client_entry->router ||
1198 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1201 /* Even if nickname is present, we may need to resolve the entry */
1202 if (client_entry->nickname) {
1204 /* If we are router, client is local to us, or client is on channel
1205 we do not need to resolve the client information. */
1206 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1207 || silc_hash_table_count(client_entry->channels) ||
1212 /* Resolve the detailed client information */
1213 silc_server_query_resolve(server, query,
1214 client_entry->router->connection,
1220 if (!query->queries_count)
1221 /* If we didn't have to do any resolving, continue with sending the
1222 command reply to the original sender. */
1223 silc_server_query_send_reply(server, query, clients, clients_count,
1224 servers, servers_count, channels,
1227 /* Now actually send the resolvings we gathered earlier */
1228 silc_server_query_resolve(server, query, NULL, NULL);
1232 silc_free(channels);
1235 /* Resolve the detailed information for the `client_entry'. Only client
1236 information needs to be resolved for being incomplete. Each incomplete
1237 client entry calls this function to do the resolving. */
1239 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1240 SilcPacketStream sock,
1241 SilcClientEntry client_entry)
1243 SilcServerCommandContext cmd = query->cmd;
1244 SilcServerQueryList r = NULL;
1251 if (!sock && client_entry)
1254 /* If arguments are NULL we will now actually send the resolvings
1255 that earlier has been gathered by calling this function. */
1256 if (!sock && !client_entry) {
1259 SILC_LOG_DEBUG(("Sending the resolvings"));
1261 /* WHOWAS resolving has been done at the same time this function
1262 was called to add the resolving for WHOWAS, so just return. */
1263 if (query->querycmd == SILC_COMMAND_WHOWAS)
1266 for (i = 0; i < query->querylist_count; i++) {
1267 r = &query->querylist[i];
1269 /* If Requested Attributes were present put them to this resolving */
1270 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1272 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1273 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1274 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1276 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1278 r->arg[r->argc] = silc_memdup(tmp, len);
1279 r->arg_lens[r->argc] = len;
1280 r->arg_types[r->argc] = 3;
1285 server->stat.commands_sent++;
1287 /* Send WHOIS command */
1288 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1289 r->argc, r->arg, r->arg_lens,
1290 r->arg_types, r->ident);
1291 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1292 res_cmd->data, silc_buffer_len(res_cmd));
1293 silc_buffer_free(res_cmd);
1295 /* Reprocess this packet after received reply */
1296 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1298 silc_server_query_resolve_reply,
1300 query->queries_left++;
1303 /* Cleanup this temporary context */
1304 for (i = 0; i < query->querylist_count; i++) {
1306 for (k = 0; k < query->querylist[i].argc; k++)
1307 silc_free(query->querylist[i].arg[k]);
1308 silc_free(query->querylist[i].arg);
1309 silc_free(query->querylist[i].arg_lens);
1310 silc_free(query->querylist[i].arg_types);
1312 silc_free(query->querylist);
1313 query->querylist = NULL;
1314 query->querylist_count = 0;
1318 SILC_LOG_DEBUG(("Resolving client information"));
1320 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1321 /* The entry is being resolved by some other external query already.
1322 Attach to that query instead of resolving again. */
1323 ident = client_entry->resolve_cmd_ident;
1324 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1325 silc_server_query_resolve_reply, query))
1326 query->queries_left++;
1328 /* This entry will be resolved */
1329 ident = ++server->cmd_ident;
1331 switch (query->querycmd) {
1333 case SILC_COMMAND_WHOIS:
1334 case SILC_COMMAND_IDENTIFY:
1335 /* Take existing query context if exist for this connection */
1336 for (i = 0; i < query->querylist_count; i++)
1337 if (query->querylist[i].sock == sock) {
1338 r = &query->querylist[i];
1343 /* Allocate new temp query list context */
1344 query->querylist = silc_realloc(query->querylist,
1345 sizeof(*query->querylist) *
1346 (query->querylist_count + 1));
1347 r = &query->querylist[query->querylist_count];
1348 query->querylist_count++;
1349 memset(r, 0, sizeof(*r));
1352 if (SILC_IS_LOCAL(client_entry))
1357 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1358 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1359 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1361 /* Add the client entry to be resolved */
1362 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1363 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1364 r->arg_lens[r->argc] = silc_buffer_len(idp);
1365 r->arg_types[r->argc] = r->argc + 4;
1367 silc_buffer_free(idp);
1371 case SILC_COMMAND_WHOWAS:
1372 /* We must send WHOWAS command since it's the only the way of
1373 resolving clients that are not present in the network anymore. */
1374 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1375 1, query->nickname, strlen(query->nickname));
1376 if (silc_server_command_pending(server, query->querycmd, ident,
1377 silc_server_query_resolve_reply, query))
1378 query->queries_left++;
1383 /* Mark the entry as being resolved */
1384 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1385 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1386 client_entry->resolve_cmd_ident = ident;
1387 client_entry->updated = time(NULL);
1389 /* Save the queried ID, which we will reprocess after we get this and
1390 all other queries back. */
1391 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1392 (query->queries_count + 1));
1393 if (query->queries) {
1394 i = query->queries_count;
1395 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1396 query->queries[i].id_type = SILC_ID_CLIENT;
1397 query->queries[i].ident = ident;
1398 query->queries_count++;
1402 /* Reply callback called after one resolving has been completed. If
1403 all resolvings has been received then we will continue with sending
1404 the command reply to the original sender of the query. */
1406 void silc_server_query_resolve_reply(void *context, void *reply)
1408 SilcServerQuery query = context;
1409 SilcServer server = query->cmd->server;
1410 SilcServerCommandReplyContext cmdr = reply;
1411 SilcUInt16 ident = cmdr->ident;
1412 SilcStatus error = SILC_STATUS_OK;
1413 SilcServerQueryID id = NULL;
1414 SilcClientEntry client_entry;
1417 /* One less query left */
1418 query->queries_left--;
1420 silc_command_get_status(cmdr->payload, NULL, &error);
1421 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1422 query->queries_left, error));
1424 /* If no error then skip to other stuff */
1425 if (error == SILC_STATUS_OK)
1428 /* Error occurred during resolving */
1430 /* Find the resolved client ID */
1431 for (i = 0; i < query->queries_count; i++) {
1432 if (query->queries[i].ident != ident)
1435 id = &query->queries[i];
1437 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1439 /* If timeout occurred for local entry when resolving attributes
1440 mark that this client doesn't support attributes in WHOIS. This
1441 assures we won't send the request again to the client. */
1442 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1443 client_entry = silc_idlist_find_client_by_id(server->local_list,
1444 id->id, TRUE, NULL);
1445 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1446 silc_id_render(id->id, SILC_ID_CLIENT)));
1447 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1448 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1449 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1454 /* Remove the RESOLVING status from the client entry */
1455 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1456 client_entry = silc_idlist_find_client_by_id(server->local_list,
1457 id->id, TRUE, NULL);
1459 client_entry = silc_idlist_find_client_by_id(server->global_list,
1460 id->id, TRUE, NULL);
1462 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1469 /* If there are queries left then wait for them */
1470 if (query->queries_left)
1473 SILC_LOG_DEBUG(("Reprocess the query"));
1475 /* If the original command caller has gone away, just stop. */
1476 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1477 SILC_LOG_DEBUG(("Original command caller vanished"));
1478 silc_server_query_free(query);
1482 /* We have received all queries. Now re-search all information required
1483 to complete this query. Reason we cannot save the values found in
1484 the first search is that SilcClientEntry, SilcServerEntry and
1485 SilcChannelEntry pointers may become invalid while we were waiting
1486 for these resolvings. */
1487 silc_server_query_process(server, query, FALSE);
1490 /* Send the reply to the original query. If arguments are NULL then this
1491 sends only the errors that has occurred during the processing of the
1492 query. This sends the errors always after sending all the found
1493 information. The query is over after this function returns and the
1494 `query' will become invalid. This is called only after all informations
1495 has been resolved. This means that if something is not found or is
1496 incomplete in this function we were unable to resolve the information
1497 or it does not exist at all. */
1499 void silc_server_query_send_reply(SilcServer server,
1500 SilcServerQuery query,
1501 SilcClientEntry *clients,
1502 SilcUInt32 clients_count,
1503 SilcServerEntry *servers,
1504 SilcUInt32 servers_count,
1505 SilcChannelEntry *channels,
1506 SilcUInt32 channels_count)
1508 SilcServerCommandContext cmd = query->cmd;
1509 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1510 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1515 int i, k, valid_count;
1516 char nh[384], uh[384];
1517 SilcBool sent_reply = FALSE;
1519 SILC_LOG_DEBUG(("Sending reply to query"));
1520 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1521 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1522 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1523 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1525 status = SILC_STATUS_OK;
1528 if (clients_count) {
1529 SilcClientEntry entry;
1530 SilcPacketStream hsock;
1532 /* Mark all invalid entries */
1533 for (i = 0, valid_count = 0; i < clients_count; i++) {
1538 switch (query->querycmd) {
1539 case SILC_COMMAND_WHOIS:
1540 if (!entry->nickname || !entry->username || !entry->userinfo ||
1541 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1542 /* When querying by ID, every "unfound" entry must cause error */
1544 silc_server_query_add_error_id(server, query,
1545 SILC_STATUS_ERR_TIMEDOUT,
1546 entry->id, SILC_ID_CLIENT);
1552 case SILC_COMMAND_IDENTIFY:
1553 if (!entry->nickname ||
1554 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1555 /* When querying by ID, every "unfound" entry must cause error */
1557 silc_server_query_add_error_id(server, query,
1558 SILC_STATUS_ERR_TIMEDOUT,
1559 entry->id, SILC_ID_CLIENT);
1565 case SILC_COMMAND_WHOWAS:
1566 if (!entry->nickname || !entry->username ||
1567 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1576 /* Start processing found clients */
1577 status = SILC_STATUS_OK;
1578 if (valid_count > 1)
1579 status = SILC_STATUS_LIST_START;
1581 /* Now do the sending of valid entries */
1583 for (i = 0; i < clients_count && valid_count; i++) {
1589 status = SILC_STATUS_LIST_ITEM;
1590 if (valid_count > 1 && k == valid_count - 1
1591 && !servers_count && !channels_count && !query->errors_count)
1592 status = SILC_STATUS_LIST_END;
1593 if (query->reply_count && k - 1 == query->reply_count)
1594 status = SILC_STATUS_LIST_END;
1596 SILC_LOG_DEBUG(("%s: client %s",
1597 (status == SILC_STATUS_OK ? " OK" :
1598 status == SILC_STATUS_LIST_START ? "START" :
1599 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1600 status == SILC_STATUS_LIST_END ? " END" :
1601 " : "), entry->nickname));
1603 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1604 memset(nh, 0, sizeof(nh));
1606 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1607 if (!strchr(entry->nickname, '@')) {
1608 silc_strncat(nh, sizeof(nh), "@", 1);
1609 if (entry->servername) {
1610 silc_strncat(nh, sizeof(nh), entry->servername,
1611 strlen(entry->servername));
1613 len = entry->router ? strlen(entry->router->server_name) :
1614 strlen(server->server_name);
1615 silc_strncat(nh, sizeof(nh), entry->router ?
1616 entry->router->server_name :
1617 server->server_name, len);
1621 switch (query->querycmd) {
1623 case SILC_COMMAND_WHOIS:
1625 unsigned char idle[4], mode[4];
1626 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1627 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1629 memset(fempty, 0, sizeof(fempty));
1630 memset(idle, 0, sizeof(idle));
1631 memset(uh, 0, sizeof(uh));
1633 silc_strncat(uh, sizeof(uh), entry->username,
1634 strlen(entry->username));
1635 if (!strchr(entry->username, '@') && entry->connection) {
1636 hsock = entry->connection;
1637 silc_strncat(uh, sizeof(uh), "@", 1);
1638 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1639 NULL, (const char **)&tmp, NULL, NULL);
1640 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1643 if (idata->conn_type == SILC_CONN_CLIENT)
1645 silc_server_get_client_channel_list(server, entry, FALSE,
1646 FALSE, &umode_list);
1649 silc_server_get_client_channel_list(server, entry, TRUE,
1652 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1653 fingerprint = entry->data.fingerprint;
1657 SILC_PUT32_MSB(entry->mode, mode);
1658 if (entry->connection)
1659 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1661 /* If Requested Attribute were present, and we do not have the
1662 attributes we will reply to them on behalf of the client. */
1665 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1666 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1667 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1668 entry->attrs_len = len;
1669 silc_buffer_free(tmpattrs);
1671 attrs = entry->attrs;
1672 len = entry->attrs_len;
1675 /* Send command reply */
1676 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1677 status, 0, ident, 10,
1678 2, idp->data, silc_buffer_len(idp),
1682 strlen(entry->userinfo),
1683 6, channels ? channels->data : NULL,
1684 channels ? silc_buffer_len(channels)
1689 fingerprint ? 20 : 0,
1690 10, umode_list ? umode_list->data :
1692 silc_buffer_len(umode_list) :
1697 /* For now we always delete Requested Attributes, unless the client
1698 is detached, in which case we don't want to reconstruct the
1699 same data everytime */
1700 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1701 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1702 silc_free(entry->attrs);
1703 entry->attrs = NULL;
1707 silc_buffer_free(channels);
1709 silc_buffer_free(umode_list);
1715 case SILC_COMMAND_IDENTIFY:
1716 if (!entry->username) {
1717 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1718 status, 0, ident, 2,
1719 2, idp->data, silc_buffer_len(idp),
1723 memset(uh, 0, sizeof(uh));
1724 silc_strncat(uh, sizeof(uh), entry->username,
1725 strlen(entry->username));
1726 if (!strchr(entry->username, '@') && entry->connection) {
1727 hsock = entry->connection;
1728 silc_strncat(uh, sizeof(uh), "@", 1);
1729 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1730 NULL, (const char **)&tmp,
1732 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1735 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1736 status, 0, ident, 3,
1737 2, idp->data, silc_buffer_len(idp),
1744 case SILC_COMMAND_WHOWAS:
1745 memset(uh, 0, sizeof(uh));
1746 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1747 if (!strchr(entry->username, '@'))
1748 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1750 /* Send command reply */
1751 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1752 status, 0, ident, 4,
1753 2, idp->data, silc_buffer_len(idp),
1758 strlen(entry->userinfo) : 0);
1763 silc_buffer_free(idp);
1765 if (status == SILC_STATUS_LIST_END)
1771 /* Not one valid entry was found, send error. If nickname was used
1772 in query send error based on that, otherwise the query->errors
1773 already includes proper errors. */
1774 if (query->nickname[0] || (!query->ids && query->attrs))
1775 silc_server_query_add_error(server, query, 1, 1,
1776 SILC_STATUS_ERR_NO_SUCH_NICK);
1778 /* Make sure some error is sent */
1779 if (!query->errors_count && !servers_count && !channels_count)
1780 silc_server_query_add_error(server, query, 2, 0,
1781 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1786 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1787 SilcServerEntry entry;
1789 if (status == SILC_STATUS_OK && servers_count > 1)
1790 status = SILC_STATUS_LIST_START;
1793 for (i = 0; i < servers_count; i++) {
1797 status = SILC_STATUS_LIST_ITEM;
1798 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1799 !query->errors_count)
1800 status = SILC_STATUS_LIST_END;
1801 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1802 !query->errors_count)
1803 status = SILC_STATUS_LIST_END;
1804 if (query->reply_count && k - 1 == query->reply_count)
1805 status = SILC_STATUS_LIST_END;
1807 SILC_LOG_DEBUG(("%s: server %s",
1808 (status == SILC_STATUS_OK ? " OK" :
1809 status == SILC_STATUS_LIST_START ? "START" :
1810 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1811 status == SILC_STATUS_LIST_END ? " END" :
1813 entry->server_name ? entry->server_name : ""));
1815 /* Send command reply */
1816 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1817 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1818 status, 0, ident, 2,
1819 2, idp->data, silc_buffer_len(idp),
1820 3, entry->server_name,
1821 entry->server_name ?
1822 strlen(entry->server_name) : 0);
1823 silc_buffer_free(idp);
1826 if (status == SILC_STATUS_LIST_END)
1833 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1834 SilcChannelEntry entry;
1836 if (status == SILC_STATUS_OK && channels_count > 1)
1837 status = SILC_STATUS_LIST_START;
1840 for (i = 0; i < channels_count; i++) {
1841 entry = channels[i];
1844 status = SILC_STATUS_LIST_ITEM;
1845 if (channels_count == 1 && status != SILC_STATUS_OK &&
1846 !query->errors_count)
1847 status = SILC_STATUS_LIST_END;
1848 if (channels_count > 1 && k == channels_count - 1 &&
1849 !query->errors_count)
1850 status = SILC_STATUS_LIST_END;
1851 if (query->reply_count && k - 1 == query->reply_count)
1852 status = SILC_STATUS_LIST_END;
1854 SILC_LOG_DEBUG(("%s: channel %s",
1855 (status == SILC_STATUS_OK ? " OK" :
1856 status == SILC_STATUS_LIST_START ? "START" :
1857 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1858 status == SILC_STATUS_LIST_END ? " END" :
1860 entry->channel_name ? entry->channel_name : ""));
1862 /* Send command reply */
1863 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1864 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1865 status, 0, ident, 2,
1866 2, idp->data, silc_buffer_len(idp),
1867 3, entry->channel_name,
1868 entry->channel_name ?
1869 strlen(entry->channel_name) : 0);
1870 silc_buffer_free(idp);
1873 if (status == SILC_STATUS_LIST_END)
1880 if (query->errors_count) {
1883 if (status == SILC_STATUS_OK && query->errors_count > 1)
1884 status = SILC_STATUS_LIST_START;
1887 for (i = 0; i < query->errors_count; i++) {
1890 /* Take error argument */
1891 if (query->errors[i].type == 1) {
1892 /* Take from sent arguments */
1894 tmp = silc_argument_get_arg_type(cmd->args,
1895 query->errors[i].index, &len);
1897 } else if (query->errors[i].type == 2) {
1902 } else if (!query->errors[i].id) {
1903 /* Take from query->ids */
1905 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1906 query->ids[query->errors[k].index].id_type);
1908 len = silc_buffer_len(idp);
1911 /* Take added ID. */
1912 idp = silc_id_payload_encode(query->errors[i].id,
1913 query->errors[k].id_type);
1915 len = silc_buffer_len(idp);
1920 status = SILC_STATUS_LIST_ITEM;
1921 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1922 status = SILC_STATUS_LIST_END;
1923 if (query->errors_count > 1 && k == query->errors_count - 1)
1924 status = SILC_STATUS_LIST_END;
1925 if (query->reply_count && k - 1 == query->reply_count)
1926 status = SILC_STATUS_LIST_END;
1928 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1929 (status == SILC_STATUS_OK ? " OK" :
1930 status == SILC_STATUS_LIST_START ? "START" :
1931 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1932 status == SILC_STATUS_LIST_END ? " END" :
1934 silc_get_status_message(query->errors[i].error),
1935 query->errors[i].error));
1937 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1938 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1940 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1941 (status == SILC_STATUS_OK ?
1942 query->errors[i].error : status),
1943 (status == SILC_STATUS_OK ?
1944 0 : query->errors[i].error), ident, 2,
1950 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1951 (status == SILC_STATUS_OK ?
1952 query->errors[i].error : status),
1953 (status == SILC_STATUS_OK ?
1954 0 : query->errors[i].error), ident, 1,
1957 silc_buffer_free(idp);
1960 if (status == SILC_STATUS_LIST_END)
1967 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1970 silc_server_query_free(query);
1973 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1974 of the client since we were unable to resolve them from the client.
1975 Either client does not support Requested Attributes or isn't replying
1976 to them like it should. */
1978 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1979 SilcServerQuery query,
1980 SilcClientEntry client_entry)
1982 SilcBuffer buffer = NULL;
1983 SilcAttribute attribute;
1984 SilcAttributePayload attr;
1985 SilcAttributeObjPk pk;
1986 SilcAttributeObjService service;
1988 unsigned char sign[2048 + 1];
1989 SilcUInt32 sign_len;
1991 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1993 /* Go through all requested attributes */
1994 silc_dlist_start(query->attrs);
1995 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1996 attribute = silc_attribute_get_attribute(attr);
1997 switch (attribute) {
1999 case SILC_ATTRIBUTE_SERVICE:
2000 /* Put SERVICE. Put only SILC service. */
2001 memset(&service, 0, sizeof(service));
2002 service.port = (server->config->server_info->primary ?
2003 server->config->server_info->primary->port : SILC_PORT);
2004 silc_strncat(service.address, sizeof(service.address),
2005 server->server_name, strlen(server->server_name));
2006 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2007 if (client_entry->connection)
2008 service.idle = time(NULL) - client_entry->data.last_receive;
2009 buffer = silc_attribute_payload_encode(buffer, attribute,
2010 SILC_ATTRIBUTE_FLAG_VALID,
2011 &service, sizeof(service));
2016 case SILC_ATTRIBUTE_STATUS_MOOD:
2017 /* Put STATUS_MOOD */
2018 buffer = silc_attribute_payload_encode(buffer, attribute,
2019 SILC_ATTRIBUTE_FLAG_VALID,
2021 SILC_ATTRIBUTE_MOOD_NORMAL,
2022 sizeof(SilcUInt32));
2027 case SILC_ATTRIBUTE_STATUS_FREETEXT:
2028 /* Put STATUS_FREETEXT. We just tell in the message that we are
2029 replying on behalf of the client. */
2031 "This information was provided by the server on behalf of the user";
2032 buffer = silc_attribute_payload_encode(buffer, attribute,
2033 SILC_ATTRIBUTE_FLAG_VALID,
2039 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2040 /* Put PREFERRED_CONTACT */
2041 buffer = silc_attribute_payload_encode(buffer, attribute,
2042 SILC_ATTRIBUTE_FLAG_VALID,
2044 SILC_ATTRIBUTE_CONTACT_CHAT,
2045 sizeof(SilcUInt32));
2050 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2051 /* Put USER_PUBLIC_KEY */
2052 if (client_entry->data.public_key) {
2053 pk.type = "silc-rsa";
2054 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2056 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2057 SILC_ATTRIBUTE_FLAG_VALID :
2058 SILC_ATTRIBUTE_FLAG_INVALID,
2066 /* No public key available */
2067 buffer = silc_attribute_payload_encode(buffer, attribute,
2068 SILC_ATTRIBUTE_FLAG_INVALID,
2075 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2076 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2077 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2080 /* For other attributes we cannot reply so mark it invalid */
2081 buffer = silc_attribute_payload_encode(buffer, attribute,
2082 SILC_ATTRIBUTE_FLAG_INVALID,
2090 /* Always put our public key. This assures that we send at least
2091 something valid back always. */
2092 pk.type = "silc-rsa";
2093 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2094 buffer = silc_attribute_payload_encode(buffer,
2095 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2096 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2097 SILC_ATTRIBUTE_FLAG_INVALID,
2103 /* Finally compute the digital signature of all the data we provided
2104 as an indication that we provided rightfull information, and this
2105 also authenticates our public key. */
2106 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2108 silc_pkcs_sign(server->private_key, buffer->data,
2109 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2110 TRUE, server->sha1hash)) {
2113 pk.data_len = sign_len;
2115 silc_attribute_payload_encode(buffer,
2116 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2117 SILC_ATTRIBUTE_FLAG_VALID,
2126 /* Find client by the Client ID indicated by the `client_id', and if not
2127 found then query it by using WHOIS command. The client information
2128 is also resolved if the cached information is incomplete or if the
2129 `always_resolve' is set to TRUE. The indication whether requested
2130 client was being resolved is saved into `resolved'. If the client
2131 is not being resolved its entry is returned by this function. NULL
2132 is returned if client is resolved. */
2134 SilcClientEntry silc_server_query_client(SilcServer server,
2135 const SilcClientID *client_id,
2136 SilcBool always_resolve,
2139 SilcClientEntry client;
2141 SILC_LOG_DEBUG(("Resolving client by client ID"));
2146 client = silc_idlist_find_client_by_id(server->local_list,
2147 (SilcClientID *)client_id,
2150 client = silc_idlist_find_client_by_id(server->global_list,
2151 (SilcClientID *)client_id,
2153 if (!client && server->server_type == SILC_ROUTER)
2157 if (!client && server->standalone)
2160 if (!client || !client->nickname || !client->username ||
2162 SilcBuffer buffer, idp;
2165 server->stat.commands_sent++;
2168 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2169 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2170 client->resolve_cmd_ident = ++server->cmd_ident;
2173 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2174 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2175 server->cmd_ident, 1,
2177 silc_buffer_len(idp));
2178 silc_server_packet_send(server, client ? client->router->connection :
2179 SILC_PRIMARY_ROUTE(server),
2180 SILC_PACKET_COMMAND, 0,
2181 buffer->data, silc_buffer_len(buffer));
2182 silc_buffer_free(idp);
2183 silc_buffer_free(buffer);