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
82 void silc_server_query_free(SilcServerQuery query);
83 void silc_server_query_send_error(SilcServer server,
84 SilcServerQuery query,
85 SilcStatus error, ...);
86 void silc_server_query_add_error(SilcServer server,
87 SilcServerQuery query,
91 void silc_server_query_add_error_id(SilcServer server,
92 SilcServerQuery query,
94 void *id, SilcIdType id_type);
95 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
96 void silc_server_query_send_router_reply(void *context, void *reply);
97 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
98 void silc_server_query_process(SilcServer server, SilcServerQuery query,
100 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
101 SilcPacketStream sock,
102 SilcClientEntry client_entry);
103 void silc_server_query_resolve_reply(void *context, void *reply);
104 void silc_server_query_send_reply(SilcServer server,
105 SilcServerQuery query,
106 SilcClientEntry *clients,
107 SilcUInt32 clients_count,
108 SilcServerEntry *servers,
109 SilcUInt32 servers_count,
110 SilcChannelEntry *channels,
111 SilcUInt32 channels_count);
112 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
113 SilcServerQuery query,
114 SilcClientEntry client_entry);
116 /* Free the query context structure and all allocated resources. */
118 void silc_server_query_free(SilcServerQuery query)
122 silc_server_command_free(query->cmd);
124 for (i = 0; i < query->queries_count; i++)
125 silc_free(query->queries[i].id);
126 silc_free(query->queries);
128 silc_free(query->server_name);
129 silc_free(query->channel_name);
131 for (i = 0; i < query->ids_count; i++)
132 silc_free(query->ids[i].id);
133 silc_free(query->ids);
136 silc_attribute_payload_list_free(query->attrs);
138 for (i = 0; i < query->errors_count; i++)
139 silc_free(query->errors[i].id);
140 silc_free(query->errors);
142 memset(query, 'F', sizeof(*query));
146 /* Send error reply indicated by the `error' to the original sender of
149 void silc_server_query_send_error(SilcServer server,
150 SilcServerQuery query,
151 SilcStatus error, ...)
154 unsigned char *data = NULL;
155 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
158 data_type = va_arg(va, SilcUInt32);
161 data = va_arg(va, unsigned char *);
162 data_len = va_arg(va, SilcUInt32);
165 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
167 /* Send the command reply with error */
168 silc_server_send_command_reply(server, query->cmd->sock,
169 query->querycmd, error, 0,
170 silc_command_get_ident(query->cmd->payload),
171 argc, data_type, data, data_len);
175 /* Add error to error list. Multiple errors may occur during the query
176 processing and this function can be used to add one error. The
177 `index' is the index to the command context which includes the argument
178 which caused the error, or it is the index to query->ids, depending
179 on value of `type'. If `type' is 0 the index is to query->ids, if
180 it is 1 it is index to the command context arguments, and if it is
181 2 the index is ignored and no argument is included in the error. */
183 void silc_server_query_add_error(SilcServer server,
184 SilcServerQuery query,
189 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
190 (query->errors_count + 1));
193 query->errors[query->errors_count].index = index;
194 query->errors[query->errors_count].type = type;
195 query->errors[query->errors_count].error = error;
196 query->errors[query->errors_count].id = NULL;
197 query->errors[query->errors_count].id_type = 0;
198 query->errors_count++;
201 /* Same as silc_server_query_add_error but adds the ID data to be used
202 with error sending with this error type. */
204 void silc_server_query_add_error_id(SilcServer server,
205 SilcServerQuery query,
207 void *id, SilcIdType id_type)
209 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
210 (query->errors_count + 1));
213 query->errors[query->errors_count].index = 0;
214 query->errors[query->errors_count].type = 0;
215 query->errors[query->errors_count].error = error;
216 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
217 query->errors[query->errors_count].id_type = id_type;
218 query->errors_count++;
221 /* Processes query as command. The `query' is the command that is
222 being processed indicated by the `cmd'. The `query' can be one of
223 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
224 SILC_COMMAND_IDENTIFY. This function handles the reply sending
225 to the entity who sent this query to us automatically. Returns
226 TRUE if the query is being processed or FALSE on error. */
228 SilcBool silc_server_query_command(SilcServer server,
229 SilcCommand querycmd,
230 SilcServerCommandContext cmd,
233 SilcServerQuery query;
235 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
238 query = silc_calloc(1, sizeof(*query));
239 query->querycmd = querycmd;
240 query->cmd = silc_server_command_dup(cmd);
241 query->router = SILC_PRIMARY_ROUTE(server);
247 case SILC_COMMAND_WHOIS:
248 /* If we are normal server and query contains nickname OR query
249 doesn't contain nickname or ids BUT attributes, send it to the
251 if (server->server_type != SILC_ROUTER && !server->standalone &&
252 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
253 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
254 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
255 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
256 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
257 silc_server_query_send_router(server, query);
262 case SILC_COMMAND_WHOWAS:
263 /* WHOWAS query is always sent to router if we are normal server */
264 if (server->server_type == SILC_SERVER && !server->standalone &&
265 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
266 silc_server_query_send_router(server, query);
271 case SILC_COMMAND_IDENTIFY:
272 /* If we are normal server and query does not contain IDs, send it
273 directly to router (it contains nickname, server name or channel
275 if (server->server_type == SILC_SERVER && !server->standalone &&
276 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
277 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
278 silc_server_query_send_router(server, query);
284 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
285 silc_server_query_free(query);
289 /* Now parse the request */
290 silc_server_query_parse(server, query);
295 /* Remote server connected callback. */
297 void silc_server_query_connected(SilcServer server,
298 SilcServerEntry server_entry,
301 SilcServerQuery query = context;
304 /* Connecting failed */
306 if (query->dynamic_prim /* && @serv != prim.host.name */ &&
307 !silc_server_num_sockets_by_remote(server, query->nick_server,
308 query->nick_server, 706)) {
309 /* Connection attempt to primary router failed, now try to the one
310 specified in nick@server. */
311 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
312 706, silc_server_query_connected,
314 query->dynamic_prim = FALSE;
318 /* Process the query after failed connect. This will send error back
319 because such nick was not found. */
320 SILC_LOG_DEBUG(("Process query, connecting failed"));
321 silc_server_query_process(server, query, TRUE);
325 /* Reprocess the query */
326 SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
327 server_entry->server_name));
328 query->router = server_entry->data.sconn->sock;
329 silc_server_query_command(server, query->querycmd, query->cmd, query);
332 /* Send the received query to our primary router since we could not
333 handle the query directly. We will reprocess the query after our
334 router replies back. */
336 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
339 SilcUInt16 old_ident;
341 SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
345 server->stat.commands_sent++;
347 /* Send WHOIS command to our router */
348 old_ident = silc_command_get_ident(query->cmd->payload);
349 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
350 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
351 silc_server_packet_send(server, query->router,
352 SILC_PACKET_COMMAND, 0,
353 tmpbuf->data, silc_buffer_len(tmpbuf));
354 silc_command_set_ident(query->cmd->payload, old_ident);
355 silc_buffer_free(tmpbuf);
357 query->resolved = TRUE;
359 /* Continue parsing the query after received reply from router */
360 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
361 silc_server_query_send_router_reply, query);
364 /* Reply callback called after primary router has replied to our initial
365 sending of the query to it. We will proceed the query in this function. */
367 void silc_server_query_send_router_reply(void *context, void *reply)
369 SilcServerQuery query = context;
370 SilcServer server = query->cmd->server;
371 SilcServerCommandReplyContext cmdr = reply;
373 SILC_LOG_DEBUG(("Received reply from router to query"));
375 /* If the original command caller has gone away, just stop. */
376 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
377 SILC_LOG_DEBUG(("Original command caller vanished"));
378 silc_server_query_free(query);
382 /* Check if router sent error reply */
383 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
386 /* If this was nick@server query, retry to @serv if the primary router
388 if (query->nick_server[0] && !query->dynamic_retry &&
389 !silc_server_num_sockets_by_remote(server, query->nick_server,
390 query->nick_server, 706)) {
391 SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
392 query->nick_server, 706));
393 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
394 706, silc_server_query_connected,
396 query->dynamic_retry = TRUE;
397 query->resolved = FALSE;
401 SILC_LOG_DEBUG(("Sending error to original query"));
404 server->stat.commands_sent++;
406 /* Send the same command reply payload which contains the error */
407 silc_command_set_command(cmdr->payload, query->querycmd);
408 silc_command_set_ident(cmdr->payload,
409 silc_command_get_ident(query->cmd->payload));
410 buffer = silc_command_payload_encode_payload(cmdr->payload);
411 silc_server_packet_send(server, query->cmd->sock,
412 SILC_PACKET_COMMAND_REPLY, 0,
413 buffer->data, silc_buffer_len(buffer));
414 silc_buffer_free(buffer);
415 silc_server_query_free(query);
419 /* Continue with parsing */
420 silc_server_query_parse(server, query);
423 /* Parse the command query and start processing the queries in detail. */
425 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
427 SilcServerCommandContext cmd = query->cmd;
428 SilcIDListData idata = silc_packet_get_context(cmd->sock);
430 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
434 SILC_LOG_DEBUG(("Parsing %s query",
435 silc_get_command_name(query->querycmd)));
437 switch (query->querycmd) {
439 case SILC_COMMAND_WHOIS:
440 /* Get requested attributes if set */
441 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
442 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
443 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
445 /* When Requested Attributes is present we will assure that this
446 client cannot execute the WHOIS command too fast. This would be
447 same as having SILC_CF_LAG_STRICT. */
448 if (idata && idata->conn_type == SILC_CONN_CLIENT)
449 ((SilcClientEntry)idata)->fast_command = 6;
452 /* Get Client IDs if present. Take IDs always instead of nickname. */
453 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
457 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
458 if (!tmp && !query->attrs) {
459 /* No nickname, no ids and no attributes - send error */
460 silc_server_query_send_error(server, query,
461 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
462 silc_server_query_free(query);
466 /* Get the nickname@server string and parse it */
467 if (tmp && ((tmp_len > 128) ||
468 !silc_parse_userfqdn(tmp, query->nickname,
469 sizeof(query->nickname),
471 sizeof(query->nick_server)))) {
472 silc_server_query_send_error(server, query,
473 SILC_STATUS_ERR_BAD_NICKNAME, 0);
474 silc_server_query_free(query);
480 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
481 SILC_STRING_UTF8, 128, &tmp_len);
483 silc_server_query_send_error(server, query,
484 SILC_STATUS_ERR_BAD_NICKNAME, 0);
485 silc_server_query_free(query);
488 memset(query->nickname, 0, sizeof(query->nickname));
489 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
493 /* Check server name. If we are open server and don't yet have
494 connection to remote router, create it now. */
495 if (query->nick_server[0] && server->config->open_server &&
497 /* If primary router is specified, use that. Otherwise connect
498 to the server in nick@server string. */
499 SilcServerConfigRouter *router;
501 router = silc_server_config_get_primary_router(server);
502 if (router && server->standalone) {
503 /* Create connection to primary router */
504 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
505 router->host, router->port));
506 query->dynamic_prim = TRUE;
507 silc_server_create_connection(server, FALSE, TRUE,
508 router->host, router->port,
509 silc_server_query_connected, query);
511 } else if (!silc_server_num_sockets_by_remote(server,
515 /* Create connection and handle the query after connection */
516 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
517 query->nick_server, 706));
518 silc_server_create_connection(server, FALSE, TRUE,
519 query->nick_server, 706,
520 silc_server_query_connected, query);
526 /* Parse the IDs included in the query */
527 query->ids = silc_calloc(argc, sizeof(*query->ids));
529 for (i = 0; i < argc; i++) {
530 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
534 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
535 id.type != SILC_ID_CLIENT) {
536 silc_server_query_add_error(server, query, 1, i + 4,
537 SILC_STATUS_ERR_BAD_CLIENT_ID);
541 /* Normal server must check whether this ID exist, and if not then
542 send the query to router, unless done so already */
543 if (server->server_type == SILC_SERVER && !query->resolved) {
544 if (!silc_idlist_find_client_by_id(server->local_list,
545 &id.u.client_id, TRUE, NULL)) {
546 if (idata->conn_type != SILC_CONN_CLIENT ||
547 !silc_idlist_find_client_by_id(server->global_list,
548 &id.u.client_id, TRUE, NULL)) {
549 silc_server_query_send_router(server, query);
550 for (i = 0; i < query->ids_count; i++)
551 silc_free(query->ids[i].id);
552 silc_free(query->ids);
554 query->ids_count = 0;
560 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
562 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
567 /* Get the max count of reply messages allowed */
568 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
569 if (tmp && tmp_len == sizeof(SilcUInt32))
570 SILC_GET32_MSB(query->reply_count, tmp);
573 case SILC_COMMAND_WHOWAS:
575 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
577 silc_server_query_send_error(server, query,
578 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
579 silc_server_query_free(query);
583 /* Get the nickname@server string and parse it */
585 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
586 query->nick_server, sizeof(query->nick_server))) {
587 silc_server_query_send_error(server, query,
588 SILC_STATUS_ERR_BAD_NICKNAME, 0);
589 silc_server_query_free(query);
594 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
595 SILC_STRING_UTF8, 128, &tmp_len);
597 silc_server_query_send_error(server, query,
598 SILC_STATUS_ERR_BAD_NICKNAME, 0);
599 silc_server_query_free(query);
602 memset(query->nickname, 0, sizeof(query->nickname));
603 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
606 /* Get the max count of reply messages allowed */
607 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
608 if (tmp && tmp_len == sizeof(SilcUInt32))
609 SILC_GET32_MSB(query->reply_count, tmp);
612 case SILC_COMMAND_IDENTIFY:
613 /* Get IDs if present. Take IDs always instead of names. */
614 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
617 /* Try get nickname */
618 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
620 /* Get the nickname@server string and parse it */
622 !silc_parse_userfqdn(tmp, query->nickname,
623 sizeof(query->nickname),
625 sizeof(query->nick_server)))
626 silc_server_query_add_error(server, query, 1, 1,
627 SILC_STATUS_ERR_BAD_NICKNAME);
630 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
631 SILC_STRING_UTF8, 128, &tmp_len);
633 silc_server_query_send_error(server, query,
634 SILC_STATUS_ERR_BAD_NICKNAME, 0);
635 silc_server_query_free(query);
638 memset(query->nickname, 0, sizeof(query->nickname));
639 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
643 /* Try get server name */
644 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
646 /* Check server name */
647 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
650 silc_server_query_send_error(server, query,
651 SILC_STATUS_ERR_BAD_SERVER, 0);
652 silc_server_query_free(query);
655 query->server_name = tmp;
658 /* Get channel name */
659 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
660 if (tmp && tmp_len <= 256) {
661 /* Check channel name */
662 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
665 silc_server_query_send_error(server, query,
666 SILC_STATUS_ERR_BAD_CHANNEL, 0);
667 silc_server_query_free(query);
670 query->channel_name = tmp;
673 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
674 silc_server_query_send_error(server, query,
675 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
676 silc_server_query_free(query);
680 /* Check server name. If we are open server and don't yet have
681 connection to remote router, create it now. */
682 if (query->nick_server[0] && server->config->open_server &&
684 /* If primary router is specified, use that. Otherwise connect
685 to the server in nick@server string. */
686 SilcServerConfigRouter *router;
688 router = silc_server_config_get_primary_router(server);
689 if (router && server->standalone) {
690 /* Create connection to primary router */
691 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
692 router->host, router->port));
693 query->dynamic_prim = TRUE;
694 silc_server_create_connection(server, FALSE, TRUE,
695 router->host, router->port,
696 silc_server_query_connected, query);
698 } else if (!silc_server_num_sockets_by_remote(server,
702 /* Create connection and handle the query after connection */
703 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
704 query->nick_server, 706));
705 silc_server_create_connection(server, FALSE, TRUE,
706 query->nick_server, 706,
707 silc_server_query_connected, query);
713 /* Parse the IDs included in the query */
714 query->ids = silc_calloc(argc, sizeof(*query->ids));
716 for (i = 0; i < argc; i++) {
717 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
721 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
722 silc_server_query_add_error(server, query, 1, i + 5,
723 SILC_STATUS_ERR_BAD_CLIENT_ID);
727 /* Normal server must check whether this ID exist, and if not then
728 send the query to router, unless done so already */
729 if (server->server_type == SILC_SERVER && !query->resolved) {
730 if (id.type == SILC_ID_CLIENT) {
731 if (!silc_idlist_find_client_by_id(server->local_list,
732 &id.u.client_id, TRUE, NULL)) {
733 if (idata->conn_type != SILC_CONN_CLIENT ||
734 !silc_idlist_find_client_by_id(server->global_list,
735 &id.u.client_id, TRUE,
737 silc_server_query_send_router(server, query);
738 for (i = 0; i < query->ids_count; i++)
739 silc_free(query->ids[i].id);
740 silc_free(query->ids);
742 query->ids_count = 0;
747 /* For now all other ID's except Client ID's are explicitly
748 sent to router for resolving. */
749 silc_server_query_send_router(server, query);
750 for (i = 0; i < query->ids_count; i++)
751 silc_free(query->ids[i].id);
752 silc_free(query->ids);
754 query->ids_count = 0;
759 if (id.type == SILC_ID_CLIENT)
760 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
762 if (id.type == SILC_ID_SERVER)
763 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
765 if (id.type == SILC_ID_CHANNEL)
766 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
768 query->ids[query->ids_count].id_type = id.type;
773 /* Get the max count of reply messages allowed */
774 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
775 if (tmp && tmp_len == sizeof(SilcUInt32))
776 SILC_GET32_MSB(query->reply_count, tmp);
780 /* Start processing the query information */
781 silc_server_query_process(server, query, TRUE);
784 /* Context for holding clients searched by public key. */
786 SilcClientEntry **clients;
787 SilcUInt32 *clients_count;
789 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
791 /* SKR find callbcak */
793 static void silc_server_query_skr_callback(SilcSKR skr,
795 SilcSKRStatus status,
799 SilcServerPublicKeyUser uc = context;
803 (*uc->clients) = silc_realloc((*uc->clients),
804 sizeof((**uc->clients)) *
805 ((*uc->clients_count) +
806 silc_dlist_count(keys)));
808 silc_dlist_start(keys);
809 while ((key = silc_dlist_get(keys)))
810 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
813 silc_dlist_uninit(keys);
816 silc_skr_find_free(find);
819 /* If clients are set, limit the found clients using the attributes in
820 the query. If clients are not set, try to find some clients using
823 void silc_server_query_check_attributes(SilcServer server,
824 SilcServerQuery query,
825 SilcClientEntry **clients,
826 SilcUInt32 *clients_count) {
827 SilcClientEntry entry;
828 SilcAttributePayload attr;
829 SilcAttribute attribute;
830 SilcAttributeObjPk pk;
831 SilcPublicKey publickey, cmp_pubkey;
833 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
836 /* If no clients were found, we only check the attributes
837 if the user wasn't searching for nickname/ids */
840 if (query->nickname[0] || query->ids_count)
844 silc_dlist_start(query->attrs);
845 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
846 attribute = silc_attribute_get_attribute(attr);
849 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
850 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
852 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
855 if (!strcmp(pk.type, "silc-rsa"))
856 type = SILC_PKCS_SILC;
857 else if (!strcmp(pk.type, "ssh-rsa"))
858 type = SILC_PKCS_SSH2;
859 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
860 type = SILC_PKCS_X509V3;
861 else if (!strcmp(pk.type, "pgp-sign-rsa"))
862 type = SILC_PKCS_OPENPGP;
866 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
872 search_pubkey = TRUE;
874 /* If no clients were set on calling this function, we just search
875 for clients, otherwise we try to limit the clients. */
877 SilcServerPublicKeyUserStruct usercontext;
880 usercontext.clients = clients;
881 usercontext.clients_count = clients_count;
882 usercontext.found = FALSE;
884 find = silc_skr_find_alloc();
888 silc_skr_find_set_public_key(find, publickey);
889 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
890 silc_skr_find(server->repository, server->schedule,
891 find, silc_server_query_skr_callback, &usercontext);
893 if (usercontext.found == TRUE)
896 for (i = 0; i < *clients_count; i++) {
897 entry = (*clients)[i];
899 if (!entry->data.public_key)
902 if (silc_server_get_public_key_by_client(server, entry,
904 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
910 (*clients)[i] = NULL;
915 silc_pkcs_public_key_free(publickey);
920 if (!found && !query->nickname[0] && !query->ids)
921 silc_server_query_add_error(server, query, 2, 0,
923 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
924 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
927 /* Processes the parsed query. This does the actual finding of the
928 queried information and prepares for sending reply to the original
929 sender of the query command. */
931 void silc_server_query_process(SilcServer server, SilcServerQuery query,
934 SilcServerCommandContext cmd = query->cmd;
935 SilcIDListData idata = silc_packet_get_context(cmd->sock);
936 SilcBool check_global = FALSE;
938 SilcClientEntry *clients = NULL, client_entry;
939 SilcChannelEntry *channels = NULL;
940 SilcServerEntry *servers = NULL;
941 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
944 SILC_LOG_DEBUG(("Processing %s query",
945 silc_get_command_name(query->querycmd)));
947 /* Check global lists if query is coming from client or we are not
948 normal server (we know global information). */
949 if (idata->conn_type == SILC_CONN_CLIENT)
951 else if (server->server_type != SILC_SERVER)
954 if (query->nickname[0]) {
955 /* Get all clients matching nickname from local list */
956 if (!silc_idlist_get_clients_by_hash(server->local_list,
958 query->nick_server[0] ?
959 query->nick_server : NULL,
961 &clients, &clients_count))
962 silc_idlist_get_clients_by_nickname(server->local_list,
964 query->nick_server[0] ?
965 query->nick_server : NULL,
966 &clients, &clients_count);
968 /* Check global list as well */
970 if (!silc_idlist_get_clients_by_hash(server->global_list,
972 query->nick_server[0] ?
973 query->nick_server : NULL,
975 &clients, &clients_count))
976 silc_idlist_get_clients_by_nickname(server->global_list,
978 query->nick_server[0] ?
979 query->nick_server : NULL,
980 &clients, &clients_count);
984 silc_server_query_add_error(server, query, 1, 1,
985 SILC_STATUS_ERR_NO_SUCH_NICK);
988 if (query->server_name) {
989 /* Find server by name */
990 entry = silc_idlist_find_server_by_name(server->local_list,
991 query->server_name, TRUE, NULL);
992 if (!entry && check_global)
993 entry = silc_idlist_find_server_by_name(server->global_list,
994 query->server_name, TRUE, NULL);
996 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
997 servers[servers_count++] = (SilcServerEntry)entry;
1001 silc_server_query_add_error(server, query, 1, 2,
1002 SILC_STATUS_ERR_NO_SUCH_SERVER);
1005 if (query->channel_name) {
1006 /* Find channel by name */
1007 entry = silc_idlist_find_channel_by_name(server->local_list,
1008 query->channel_name, NULL);
1009 if (!entry && check_global)
1010 entry = silc_idlist_find_channel_by_name(server->global_list,
1011 query->channel_name, NULL);
1013 channels = silc_realloc(channels, sizeof(*channels) *
1014 (channels_count + 1));
1015 channels[channels_count++] = (SilcChannelEntry)entry;
1019 silc_server_query_add_error(server, query, 1, 3,
1020 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1023 if (query->ids_count) {
1024 /* Find entries by the queried IDs */
1025 for (i = 0; i < query->ids_count; i++) {
1026 void *id = query->ids[i].id;
1030 switch (query->ids[i].id_type) {
1032 case SILC_ID_CLIENT:
1033 /* Get client entry */
1034 entry = silc_idlist_find_client_by_id(server->local_list,
1036 if (!entry && check_global)
1037 entry = silc_idlist_find_client_by_id(server->global_list,
1040 silc_server_query_add_error(server, query, 0, i,
1041 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1045 clients = silc_realloc(clients, sizeof(*clients) *
1046 (clients_count + 1));
1047 clients[clients_count++] = (SilcClientEntry)entry;
1050 case SILC_ID_SERVER:
1051 /* Get server entry */
1052 entry = silc_idlist_find_server_by_id(server->local_list,
1054 if (!entry && check_global)
1055 entry = silc_idlist_find_server_by_id(server->global_list,
1058 silc_server_query_add_error(server, query, 0, i,
1059 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1063 servers = silc_realloc(servers, sizeof(*servers) *
1064 (servers_count + 1));
1065 servers[servers_count++] = (SilcServerEntry)entry;
1068 case SILC_ID_CHANNEL:
1069 /* Get channel entry */
1070 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1071 if (!entry && check_global)
1072 entry = silc_idlist_find_channel_by_id(server->global_list, id,
1075 silc_server_query_add_error(server, query, 0, i,
1076 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1080 channels = silc_realloc(channels, sizeof(*channels) *
1081 (channels_count + 1));
1082 channels[channels_count++] = (SilcChannelEntry)entry;
1091 /* Check the attributes to narrow down the search by using them. */
1093 silc_server_query_check_attributes(server, query, &clients,
1096 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1097 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1098 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1100 /* If nothing was found, then just send the errors */
1101 if (!clients && !channels && !servers) {
1102 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1106 /* If caller does not want us to resolve anything (has resolved already)
1107 then just continue with sending the reply */
1109 silc_server_query_send_reply(server, query, clients, clients_count,
1110 servers, servers_count, channels,
1114 silc_free(channels);
1118 /* Now process all found information and if necessary do some more
1120 switch (query->querycmd) {
1122 case SILC_COMMAND_WHOIS:
1123 for (i = 0; i < clients_count; i++) {
1124 client_entry = clients[i];
1126 /* Check if cannot query this anyway, so take next one */
1127 if (!client_entry ||
1128 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1131 /* If Requested Attributes is set then we always resolve the client
1132 information, if not then check whether the entry is complete or not
1133 and decide whether we need to resolve or not. */
1134 if (!query->attrs) {
1136 /* Even if nickname and stuff are present, we may need to resolve
1138 if (client_entry->nickname && client_entry->username &&
1139 client_entry->userinfo) {
1140 /* Check if cannot query this anyway, so take next one */
1141 if (!client_entry->router)
1144 /* If we are router, client is local to us, or client is on channel
1145 we do not need to resolve the client information. */
1146 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1147 || silc_hash_table_count(client_entry->channels) ||
1153 /* Remove the NOATTR status periodically */
1154 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1155 client_entry->updated + 600 < time(NULL))
1156 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1158 /* When requested attributes is present and local client is detached
1159 we cannot send the command to the client, we'll reply on behalf of
1160 the client instead. */
1161 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1162 (client_entry->mode & SILC_UMODE_DETACHED ||
1163 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1166 /* If attributes are present in query, and in the entry and we have
1167 done resolvings already we don't need to resolve anymore */
1168 if (query->resolved && query->attrs && client_entry->attrs)
1171 /* Resolve the detailed client information. If client is local we
1172 know that attributes were present and we will resolve directly
1173 from the client. Otherwise resolve from client's owner. */
1174 silc_server_query_resolve(server, query,
1175 (SILC_IS_LOCAL(client_entry) ?
1176 client_entry->connection :
1177 client_entry->router->connection),
1182 case SILC_COMMAND_WHOWAS:
1183 for (i = 0; i < clients_count; i++) {
1184 client_entry = clients[i];
1186 /* Check if cannot query this anyway, so take next one */
1187 if (!client_entry || !client_entry->router ||
1188 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1191 /* If both nickname and username are present no resolving is needed */
1192 if (client_entry->nickname && client_entry->username)
1195 /* Resolve the detailed client information */
1196 silc_server_query_resolve(server, query,
1197 client_entry->router->connection,
1202 case SILC_COMMAND_IDENTIFY:
1203 for (i = 0; i < clients_count; i++) {
1204 client_entry = clients[i];
1206 /* Check if cannot query this anyway, so take next one */
1207 if (!client_entry || !client_entry->router ||
1208 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1211 /* Even if nickname is present, we may need to resolve the entry */
1212 if (client_entry->nickname) {
1214 /* If we are router, client is local to us, or client is on channel
1215 we do not need to resolve the client information. */
1216 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1217 || silc_hash_table_count(client_entry->channels) ||
1222 /* Resolve the detailed client information */
1223 silc_server_query_resolve(server, query,
1224 client_entry->router->connection,
1230 if (!query->queries_count)
1231 /* If we didn't have to do any resolving, continue with sending the
1232 command reply to the original sender. */
1233 silc_server_query_send_reply(server, query, clients, clients_count,
1234 servers, servers_count, channels,
1237 /* Now actually send the resolvings we gathered earlier */
1238 silc_server_query_resolve(server, query, NULL, NULL);
1242 silc_free(channels);
1245 /* Resolve the detailed information for the `client_entry'. Only client
1246 information needs to be resolved for being incomplete. Each incomplete
1247 client entry calls this function to do the resolving. */
1249 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1250 SilcPacketStream sock,
1251 SilcClientEntry client_entry)
1253 SilcServerCommandContext cmd = query->cmd;
1254 SilcServerQueryList r = NULL;
1261 if (!sock && client_entry)
1264 /* If arguments are NULL we will now actually send the resolvings
1265 that earlier has been gathered by calling this function. */
1266 if (!sock && !client_entry) {
1269 SILC_LOG_DEBUG(("Sending the resolvings"));
1271 /* WHOWAS resolving has been done at the same time this function
1272 was called to add the resolving for WHOWAS, so just return. */
1273 if (query->querycmd == SILC_COMMAND_WHOWAS)
1276 for (i = 0; i < query->querylist_count; i++) {
1277 r = &query->querylist[i];
1279 /* If Requested Attributes were present put them to this resolving */
1280 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1282 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1283 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1284 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1286 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1288 r->arg[r->argc] = silc_memdup(tmp, len);
1289 r->arg_lens[r->argc] = len;
1290 r->arg_types[r->argc] = 3;
1295 server->stat.commands_sent++;
1297 /* Send WHOIS command */
1298 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1299 r->argc, r->arg, r->arg_lens,
1300 r->arg_types, r->ident);
1301 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1302 res_cmd->data, silc_buffer_len(res_cmd));
1303 silc_buffer_free(res_cmd);
1305 /* Reprocess this packet after received reply */
1306 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1308 silc_server_query_resolve_reply,
1310 query->queries_left++;
1313 /* Cleanup this temporary context */
1314 for (i = 0; i < query->querylist_count; i++) {
1316 for (k = 0; k < query->querylist[i].argc; k++)
1317 silc_free(query->querylist[i].arg[k]);
1318 silc_free(query->querylist[i].arg);
1319 silc_free(query->querylist[i].arg_lens);
1320 silc_free(query->querylist[i].arg_types);
1322 silc_free(query->querylist);
1323 query->querylist = NULL;
1324 query->querylist_count = 0;
1328 SILC_LOG_DEBUG(("Resolving client information"));
1330 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1331 /* The entry is being resolved by some other external query already.
1332 Attach to that query instead of resolving again. */
1333 ident = client_entry->resolve_cmd_ident;
1334 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1335 silc_server_query_resolve_reply, query))
1336 query->queries_left++;
1338 /* This entry will be resolved */
1339 ident = ++server->cmd_ident;
1341 switch (query->querycmd) {
1343 case SILC_COMMAND_WHOIS:
1344 case SILC_COMMAND_IDENTIFY:
1345 /* Take existing query context if exist for this connection */
1346 for (i = 0; i < query->querylist_count; i++)
1347 if (query->querylist[i].sock == sock) {
1348 r = &query->querylist[i];
1353 /* Allocate new temp query list context */
1354 query->querylist = silc_realloc(query->querylist,
1355 sizeof(*query->querylist) *
1356 (query->querylist_count + 1));
1357 r = &query->querylist[query->querylist_count];
1358 query->querylist_count++;
1359 memset(r, 0, sizeof(*r));
1362 if (SILC_IS_LOCAL(client_entry))
1367 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1368 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1369 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1371 /* Add the client entry to be resolved */
1372 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1373 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1374 r->arg_lens[r->argc] = silc_buffer_len(idp);
1375 r->arg_types[r->argc] = r->argc + 4;
1377 silc_buffer_free(idp);
1381 case SILC_COMMAND_WHOWAS:
1382 /* We must send WHOWAS command since it's the only the way of
1383 resolving clients that are not present in the network anymore. */
1384 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1385 1, query->nickname, strlen(query->nickname));
1386 if (silc_server_command_pending(server, query->querycmd, ident,
1387 silc_server_query_resolve_reply, query))
1388 query->queries_left++;
1393 /* Mark the entry as being resolved */
1394 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1395 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1396 client_entry->resolve_cmd_ident = ident;
1397 client_entry->updated = time(NULL);
1399 /* Save the queried ID, which we will reprocess after we get this and
1400 all other queries back. */
1401 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1402 (query->queries_count + 1));
1403 if (query->queries) {
1404 i = query->queries_count;
1405 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1406 query->queries[i].id_type = SILC_ID_CLIENT;
1407 query->queries[i].ident = ident;
1408 query->queries_count++;
1412 /* Reply callback called after one resolving has been completed. If
1413 all resolvings has been received then we will continue with sending
1414 the command reply to the original sender of the query. */
1416 void silc_server_query_resolve_reply(void *context, void *reply)
1418 SilcServerQuery query = context;
1419 SilcServer server = query->cmd->server;
1420 SilcServerCommandReplyContext cmdr = reply;
1421 SilcUInt16 ident = cmdr->ident;
1422 SilcStatus error = SILC_STATUS_OK;
1423 SilcServerQueryID id = NULL;
1424 SilcClientEntry client_entry;
1427 /* One less query left */
1428 query->queries_left--;
1430 silc_command_get_status(cmdr->payload, NULL, &error);
1431 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1432 query->queries_left, error));
1434 /* If no error then skip to other stuff */
1435 if (error == SILC_STATUS_OK)
1438 /* Error occurred during resolving */
1440 /* Find the resolved client ID */
1441 for (i = 0; i < query->queries_count; i++) {
1442 if (query->queries[i].ident != ident)
1445 id = &query->queries[i];
1447 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1449 /* If timeout occurred for local entry when resolving attributes
1450 mark that this client doesn't support attributes in WHOIS. This
1451 assures we won't send the request again to the client. */
1452 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1453 client_entry = silc_idlist_find_client_by_id(server->local_list,
1454 id->id, TRUE, NULL);
1455 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1456 silc_id_render(id->id, SILC_ID_CLIENT)));
1457 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1458 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1459 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1464 /* Remove the RESOLVING status from the client entry */
1465 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1466 client_entry = silc_idlist_find_client_by_id(server->local_list,
1467 id->id, TRUE, NULL);
1469 client_entry = silc_idlist_find_client_by_id(server->global_list,
1470 id->id, TRUE, NULL);
1472 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1479 /* If there are queries left then wait for them */
1480 if (query->queries_left)
1483 SILC_LOG_DEBUG(("Reprocess the query"));
1485 /* If the original command caller has gone away, just stop. */
1486 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1487 SILC_LOG_DEBUG(("Original command caller vanished"));
1488 silc_server_query_free(query);
1492 /* We have received all queries. Now re-search all information required
1493 to complete this query. Reason we cannot save the values found in
1494 the first search is that SilcClientEntry, SilcServerEntry and
1495 SilcChannelEntry pointers may become invalid while we were waiting
1496 for these resolvings. */
1497 silc_server_query_process(server, query, FALSE);
1500 /* Send the reply to the original query. If arguments are NULL then this
1501 sends only the errors that has occurred during the processing of the
1502 query. This sends the errors always after sending all the found
1503 information. The query is over after this function returns and the
1504 `query' will become invalid. This is called only after all informations
1505 has been resolved. This means that if something is not found or is
1506 incomplete in this function we were unable to resolve the information
1507 or it does not exist at all. */
1509 void silc_server_query_send_reply(SilcServer server,
1510 SilcServerQuery query,
1511 SilcClientEntry *clients,
1512 SilcUInt32 clients_count,
1513 SilcServerEntry *servers,
1514 SilcUInt32 servers_count,
1515 SilcChannelEntry *channels,
1516 SilcUInt32 channels_count)
1518 SilcServerCommandContext cmd = query->cmd;
1519 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1520 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1525 int i, k, valid_count;
1526 char nh[384], uh[384];
1527 SilcBool sent_reply = FALSE;
1529 SILC_LOG_DEBUG(("Sending reply to query"));
1530 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1531 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1532 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1533 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1535 status = SILC_STATUS_OK;
1538 if (clients_count) {
1539 SilcClientEntry entry;
1540 SilcPacketStream hsock;
1542 /* Mark all invalid entries */
1543 for (i = 0, valid_count = 0; i < clients_count; i++) {
1548 switch (query->querycmd) {
1549 case SILC_COMMAND_WHOIS:
1550 if (!entry->nickname || !entry->username || !entry->userinfo ||
1551 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1552 /* When querying by ID, every "unfound" entry must cause error */
1554 silc_server_query_add_error_id(server, query,
1555 SILC_STATUS_ERR_TIMEDOUT,
1556 entry->id, SILC_ID_CLIENT);
1562 case SILC_COMMAND_IDENTIFY:
1563 if (!entry->nickname ||
1564 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1565 /* When querying by ID, every "unfound" entry must cause error */
1567 silc_server_query_add_error_id(server, query,
1568 SILC_STATUS_ERR_TIMEDOUT,
1569 entry->id, SILC_ID_CLIENT);
1575 case SILC_COMMAND_WHOWAS:
1576 if (!entry->nickname || !entry->username ||
1577 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1586 /* Start processing found clients */
1587 status = SILC_STATUS_OK;
1588 if (valid_count > 1)
1589 status = SILC_STATUS_LIST_START;
1591 /* Now do the sending of valid entries */
1593 for (i = 0; i < clients_count && valid_count; i++) {
1599 status = SILC_STATUS_LIST_ITEM;
1600 if (valid_count > 1 && k == valid_count - 1
1601 && !servers_count && !channels_count && !query->errors_count)
1602 status = SILC_STATUS_LIST_END;
1603 if (query->reply_count && k - 1 == query->reply_count)
1604 status = SILC_STATUS_LIST_END;
1606 SILC_LOG_DEBUG(("%s: client %s",
1607 (status == SILC_STATUS_OK ? " OK" :
1608 status == SILC_STATUS_LIST_START ? "START" :
1609 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1610 status == SILC_STATUS_LIST_END ? " END" :
1611 " : "), entry->nickname));
1613 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1614 memset(nh, 0, sizeof(nh));
1616 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1617 if (!strchr(entry->nickname, '@')) {
1618 silc_strncat(nh, sizeof(nh), "@", 1);
1619 if (entry->servername) {
1620 silc_strncat(nh, sizeof(nh), entry->servername,
1621 strlen(entry->servername));
1623 len = entry->router ? strlen(entry->router->server_name) :
1624 strlen(server->server_name);
1625 silc_strncat(nh, sizeof(nh), entry->router ?
1626 entry->router->server_name :
1627 server->server_name, len);
1631 switch (query->querycmd) {
1633 case SILC_COMMAND_WHOIS:
1635 unsigned char idle[4], mode[4];
1636 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1637 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1639 memset(fempty, 0, sizeof(fempty));
1640 memset(idle, 0, sizeof(idle));
1641 memset(uh, 0, sizeof(uh));
1643 silc_strncat(uh, sizeof(uh), entry->username,
1644 strlen(entry->username));
1645 if (!strchr(entry->username, '@') && entry->connection) {
1646 hsock = entry->connection;
1647 silc_strncat(uh, sizeof(uh), "@", 1);
1648 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1649 NULL, (const char **)&tmp, NULL, NULL);
1650 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1653 if (idata->conn_type == SILC_CONN_CLIENT)
1655 silc_server_get_client_channel_list(server, entry, FALSE,
1656 FALSE, &umode_list);
1659 silc_server_get_client_channel_list(server, entry, TRUE,
1662 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1663 fingerprint = entry->data.fingerprint;
1667 SILC_PUT32_MSB(entry->mode, mode);
1668 if (entry->connection)
1669 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1671 /* If Requested Attribute were present, and we do not have the
1672 attributes we will reply to them on behalf of the client. */
1675 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1676 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1677 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1678 entry->attrs_len = len;
1679 silc_buffer_free(tmpattrs);
1681 attrs = entry->attrs;
1682 len = entry->attrs_len;
1685 /* Send command reply */
1686 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1687 status, 0, ident, 10,
1688 2, idp->data, silc_buffer_len(idp),
1692 strlen(entry->userinfo),
1693 6, channels ? channels->data : NULL,
1694 channels ? silc_buffer_len(channels)
1699 fingerprint ? 20 : 0,
1700 10, umode_list ? umode_list->data :
1702 silc_buffer_len(umode_list) :
1707 /* For now we always delete Requested Attributes, unless the client
1708 is detached, in which case we don't want to reconstruct the
1709 same data everytime */
1710 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1711 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1712 silc_free(entry->attrs);
1713 entry->attrs = NULL;
1717 silc_buffer_free(channels);
1719 silc_buffer_free(umode_list);
1725 case SILC_COMMAND_IDENTIFY:
1726 if (!entry->username) {
1727 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1728 status, 0, ident, 2,
1729 2, idp->data, silc_buffer_len(idp),
1733 memset(uh, 0, sizeof(uh));
1734 silc_strncat(uh, sizeof(uh), entry->username,
1735 strlen(entry->username));
1736 if (!strchr(entry->username, '@') && entry->connection) {
1737 hsock = entry->connection;
1738 silc_strncat(uh, sizeof(uh), "@", 1);
1739 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1740 NULL, (const char **)&tmp,
1742 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1745 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1746 status, 0, ident, 3,
1747 2, idp->data, silc_buffer_len(idp),
1754 case SILC_COMMAND_WHOWAS:
1755 memset(uh, 0, sizeof(uh));
1756 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1757 if (!strchr(entry->username, '@'))
1758 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1760 /* Send command reply */
1761 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1762 status, 0, ident, 4,
1763 2, idp->data, silc_buffer_len(idp),
1768 strlen(entry->userinfo) : 0);
1773 silc_buffer_free(idp);
1775 if (status == SILC_STATUS_LIST_END)
1781 /* Not one valid entry was found, send error. If nickname was used
1782 in query send error based on that, otherwise the query->errors
1783 already includes proper errors. */
1784 if (query->nickname[0] || (!query->ids && query->attrs))
1785 silc_server_query_add_error(server, query, 1, 1,
1786 SILC_STATUS_ERR_NO_SUCH_NICK);
1788 /* Make sure some error is sent */
1789 if (!query->errors_count && !servers_count && !channels_count)
1790 silc_server_query_add_error(server, query, 2, 0,
1791 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1796 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1797 SilcServerEntry entry;
1799 if (status == SILC_STATUS_OK && servers_count > 1)
1800 status = SILC_STATUS_LIST_START;
1803 for (i = 0; i < servers_count; i++) {
1807 status = SILC_STATUS_LIST_ITEM;
1808 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1809 !query->errors_count)
1810 status = SILC_STATUS_LIST_END;
1811 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1812 !query->errors_count)
1813 status = SILC_STATUS_LIST_END;
1814 if (query->reply_count && k - 1 == query->reply_count)
1815 status = SILC_STATUS_LIST_END;
1817 SILC_LOG_DEBUG(("%s: server %s",
1818 (status == SILC_STATUS_OK ? " OK" :
1819 status == SILC_STATUS_LIST_START ? "START" :
1820 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1821 status == SILC_STATUS_LIST_END ? " END" :
1823 entry->server_name ? entry->server_name : ""));
1825 /* Send command reply */
1826 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1827 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1828 status, 0, ident, 2,
1829 2, idp->data, silc_buffer_len(idp),
1830 3, entry->server_name,
1831 entry->server_name ?
1832 strlen(entry->server_name) : 0);
1833 silc_buffer_free(idp);
1836 if (status == SILC_STATUS_LIST_END)
1843 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1844 SilcChannelEntry entry;
1846 if (status == SILC_STATUS_OK && channels_count > 1)
1847 status = SILC_STATUS_LIST_START;
1850 for (i = 0; i < channels_count; i++) {
1851 entry = channels[i];
1854 status = SILC_STATUS_LIST_ITEM;
1855 if (channels_count == 1 && status != SILC_STATUS_OK &&
1856 !query->errors_count)
1857 status = SILC_STATUS_LIST_END;
1858 if (channels_count > 1 && k == channels_count - 1 &&
1859 !query->errors_count)
1860 status = SILC_STATUS_LIST_END;
1861 if (query->reply_count && k - 1 == query->reply_count)
1862 status = SILC_STATUS_LIST_END;
1864 SILC_LOG_DEBUG(("%s: channel %s",
1865 (status == SILC_STATUS_OK ? " OK" :
1866 status == SILC_STATUS_LIST_START ? "START" :
1867 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1868 status == SILC_STATUS_LIST_END ? " END" :
1870 entry->channel_name ? entry->channel_name : ""));
1872 /* Send command reply */
1873 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1874 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1875 status, 0, ident, 2,
1876 2, idp->data, silc_buffer_len(idp),
1877 3, entry->channel_name,
1878 entry->channel_name ?
1879 strlen(entry->channel_name) : 0);
1880 silc_buffer_free(idp);
1883 if (status == SILC_STATUS_LIST_END)
1890 if (query->errors_count) {
1893 if (status == SILC_STATUS_OK && query->errors_count > 1)
1894 status = SILC_STATUS_LIST_START;
1897 for (i = 0; i < query->errors_count; i++) {
1900 /* Take error argument */
1901 if (query->errors[i].type == 1) {
1902 /* Take from sent arguments */
1904 tmp = silc_argument_get_arg_type(cmd->args,
1905 query->errors[i].index, &len);
1907 } else if (query->errors[i].type == 2) {
1912 } else if (!query->errors[i].id) {
1913 /* Take from query->ids */
1915 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1916 query->ids[query->errors[k].index].id_type);
1918 len = silc_buffer_len(idp);
1921 /* Take added ID. */
1922 idp = silc_id_payload_encode(query->errors[i].id,
1923 query->errors[k].id_type);
1925 len = silc_buffer_len(idp);
1930 status = SILC_STATUS_LIST_ITEM;
1931 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1932 status = SILC_STATUS_LIST_END;
1933 if (query->errors_count > 1 && k == query->errors_count - 1)
1934 status = SILC_STATUS_LIST_END;
1935 if (query->reply_count && k - 1 == query->reply_count)
1936 status = SILC_STATUS_LIST_END;
1938 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1939 (status == SILC_STATUS_OK ? " OK" :
1940 status == SILC_STATUS_LIST_START ? "START" :
1941 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1942 status == SILC_STATUS_LIST_END ? " END" :
1944 silc_get_status_message(query->errors[i].error),
1945 query->errors[i].error));
1947 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1948 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
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, 2,
1960 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1961 (status == SILC_STATUS_OK ?
1962 query->errors[i].error : status),
1963 (status == SILC_STATUS_OK ?
1964 0 : query->errors[i].error), ident, 1,
1967 silc_buffer_free(idp);
1970 if (status == SILC_STATUS_LIST_END)
1977 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1980 silc_server_query_free(query);
1983 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1984 of the client since we were unable to resolve them from the client.
1985 Either client does not support Requested Attributes or isn't replying
1986 to them like it should. */
1988 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1989 SilcServerQuery query,
1990 SilcClientEntry client_entry)
1992 SilcBuffer buffer = NULL;
1993 SilcAttribute attribute;
1994 SilcAttributePayload attr;
1995 SilcAttributeObjPk pk;
1996 SilcAttributeObjService service;
1998 unsigned char sign[2048 + 1];
1999 SilcUInt32 sign_len;
2001 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
2003 /* Go through all requested attributes */
2004 silc_dlist_start(query->attrs);
2005 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
2006 attribute = silc_attribute_get_attribute(attr);
2007 switch (attribute) {
2009 case SILC_ATTRIBUTE_SERVICE:
2010 /* Put SERVICE. Put only SILC service. */
2011 memset(&service, 0, sizeof(service));
2012 service.port = (server->config->server_info->primary ?
2013 server->config->server_info->primary->port : SILC_PORT);
2014 silc_strncat(service.address, sizeof(service.address),
2015 server->server_name, strlen(server->server_name));
2016 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2017 if (client_entry->connection)
2018 service.idle = time(NULL) - client_entry->data.last_receive;
2019 buffer = silc_attribute_payload_encode(buffer, attribute,
2020 SILC_ATTRIBUTE_FLAG_VALID,
2021 &service, sizeof(service));
2026 case SILC_ATTRIBUTE_STATUS_MOOD:
2027 /* Put STATUS_MOOD */
2028 buffer = silc_attribute_payload_encode(buffer, attribute,
2029 SILC_ATTRIBUTE_FLAG_VALID,
2031 SILC_ATTRIBUTE_MOOD_NORMAL,
2032 sizeof(SilcUInt32));
2037 case SILC_ATTRIBUTE_STATUS_FREETEXT:
2038 /* Put STATUS_FREETEXT. We just tell in the message that we are
2039 replying on behalf of the client. */
2041 "This information was provided by the server on behalf of the user";
2042 buffer = silc_attribute_payload_encode(buffer, attribute,
2043 SILC_ATTRIBUTE_FLAG_VALID,
2049 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2050 /* Put PREFERRED_CONTACT */
2051 buffer = silc_attribute_payload_encode(buffer, attribute,
2052 SILC_ATTRIBUTE_FLAG_VALID,
2054 SILC_ATTRIBUTE_CONTACT_CHAT,
2055 sizeof(SilcUInt32));
2060 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2061 /* Put USER_PUBLIC_KEY */
2062 if (client_entry->data.public_key) {
2063 pk.type = "silc-rsa";
2064 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2066 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2067 SILC_ATTRIBUTE_FLAG_VALID :
2068 SILC_ATTRIBUTE_FLAG_INVALID,
2076 /* No public key available */
2077 buffer = silc_attribute_payload_encode(buffer, attribute,
2078 SILC_ATTRIBUTE_FLAG_INVALID,
2085 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2086 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2087 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2090 /* For other attributes we cannot reply so mark it invalid */
2091 buffer = silc_attribute_payload_encode(buffer, attribute,
2092 SILC_ATTRIBUTE_FLAG_INVALID,
2100 /* Always put our public key. This assures that we send at least
2101 something valid back always. */
2102 pk.type = "silc-rsa";
2103 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2104 buffer = silc_attribute_payload_encode(buffer,
2105 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2106 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2107 SILC_ATTRIBUTE_FLAG_INVALID,
2113 /* Finally compute the digital signature of all the data we provided
2114 as an indication that we provided rightfull information, and this
2115 also authenticates our public key. */
2116 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2118 silc_pkcs_sign(server->private_key, buffer->data,
2119 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2120 TRUE, server->sha1hash)) {
2123 pk.data_len = sign_len;
2125 silc_attribute_payload_encode(buffer,
2126 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2127 SILC_ATTRIBUTE_FLAG_VALID,
2136 /* Find client by the Client ID indicated by the `client_id', and if not
2137 found then query it by using WHOIS command. The client information
2138 is also resolved if the cached information is incomplete or if the
2139 `always_resolve' is set to TRUE. The indication whether requested
2140 client was being resolved is saved into `resolved'. If the client
2141 is not being resolved its entry is returned by this function. NULL
2142 is returned if client is resolved. */
2144 SilcClientEntry silc_server_query_client(SilcServer server,
2145 const SilcClientID *client_id,
2146 SilcBool always_resolve,
2149 SilcClientEntry client;
2151 SILC_LOG_DEBUG(("Resolving client by client ID"));
2156 client = silc_idlist_find_client_by_id(server->local_list,
2157 (SilcClientID *)client_id,
2160 client = silc_idlist_find_client_by_id(server->global_list,
2161 (SilcClientID *)client_id,
2163 if (!client && server->server_type == SILC_ROUTER)
2167 if (!client && server->standalone)
2170 if (!client || !client->nickname || !client->username ||
2172 SilcBuffer buffer, idp;
2175 server->stat.commands_sent++;
2178 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2179 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2180 client->resolve_cmd_ident = ++server->cmd_ident;
2183 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2184 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2185 server->cmd_ident, 1,
2187 silc_buffer_len(idp));
2188 silc_server_packet_send(server, client ? client->router->connection :
2189 SILC_PRIMARY_ROUTE(server),
2190 SILC_PACKET_COMMAND, 0,
2191 buffer->data, silc_buffer_len(buffer));
2192 silc_buffer_free(idp);
2193 silc_buffer_free(buffer);