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 */
311 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
312 SILC_CONN_SERVER : SILC_CONN_ROUTER);
314 if (query->dynamic_prim /* && @serv != prim.host.name */ &&
315 !silc_server_num_sockets_by_remote(server, query->nick_server,
316 query->nick_server, 706, type)) {
317 /* Connection attempt to primary router failed, now try to the one
318 specified in nick@server. */
319 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
320 706, silc_server_query_connected,
322 query->dynamic_prim = FALSE;
326 /* Process the query after failed connect. This will send error back
327 because such nick was not found. */
328 SILC_LOG_DEBUG(("Process query, connecting failed"));
329 silc_server_query_process(server, query, TRUE);
333 /* Reprocess the query */
334 SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
335 server_entry->server_name));
336 query->router = server_entry->data.sconn->sock;
337 silc_server_query_command(server, query->querycmd, query->cmd, query);
340 /* Send the received query to our primary router since we could not
341 handle the query directly. We will reprocess the query after our
342 router replies back. */
344 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
347 SilcUInt16 old_ident;
349 SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
353 server->stat.commands_sent++;
355 /* Send WHOIS command to our router */
356 old_ident = silc_command_get_ident(query->cmd->payload);
357 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
358 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
359 silc_server_packet_send(server, query->router,
360 SILC_PACKET_COMMAND, 0,
361 tmpbuf->data, silc_buffer_len(tmpbuf));
362 silc_command_set_ident(query->cmd->payload, old_ident);
363 silc_buffer_free(tmpbuf);
365 query->resolved = TRUE;
367 /* Continue parsing the query after received reply from router */
368 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
369 silc_server_query_send_router_reply, query);
372 /* Reply callback called after primary router has replied to our initial
373 sending of the query to it. We will proceed the query in this function. */
375 void silc_server_query_send_router_reply(void *context, void *reply)
377 SilcServerQuery query = context;
378 SilcServer server = query->cmd->server;
379 SilcServerCommandReplyContext cmdr = reply;
381 SILC_LOG_DEBUG(("Received reply from router to query"));
383 /* If the original command caller has gone away, just stop. */
384 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
385 SILC_LOG_DEBUG(("Original command caller vanished"));
386 silc_server_query_free(query);
390 /* Check if router sent error reply */
391 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
393 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
394 SILC_CONN_SERVER : SILC_CONN_ROUTER);
396 /* If this was nick@server query, retry to @serv if the primary router
398 if (query->nick_server[0] && !query->dynamic_retry &&
399 !silc_server_num_sockets_by_remote(server, query->nick_server,
400 query->nick_server, 1334, type)) {
401 SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
402 query->nick_server, 706));
403 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
404 1334, silc_server_query_connected,
406 query->dynamic_retry = TRUE;
407 query->resolved = FALSE;
411 SILC_LOG_DEBUG(("Sending error to original query"));
414 server->stat.commands_sent++;
416 /* Send the same command reply payload which contains the error */
417 silc_command_set_command(cmdr->payload, query->querycmd);
418 silc_command_set_ident(cmdr->payload,
419 silc_command_get_ident(query->cmd->payload));
420 buffer = silc_command_payload_encode_payload(cmdr->payload);
421 silc_server_packet_send(server, query->cmd->sock,
422 SILC_PACKET_COMMAND_REPLY, 0,
423 buffer->data, silc_buffer_len(buffer));
424 silc_buffer_free(buffer);
425 silc_server_query_free(query);
429 /* Continue with parsing */
430 silc_server_query_parse(server, query, FALSE);
433 /* Parse the command query and start processing the queries in detail. */
435 SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
438 SilcServerCommandContext cmd = query->cmd;
439 SilcIDListData idata = silc_packet_get_context(cmd->sock);
441 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
445 SILC_LOG_DEBUG(("Parsing %s query",
446 silc_get_command_name(query->querycmd)));
451 switch (query->querycmd) {
453 case SILC_COMMAND_WHOIS:
454 /* Get requested attributes if set */
455 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
456 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
457 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
459 /* When Requested Attributes is present we will assure that this
460 client cannot execute the WHOIS command too fast. This would be
461 same as having SILC_CF_LAG_STRICT. */
462 if (idata && idata->conn_type == SILC_CONN_CLIENT)
463 ((SilcClientEntry)idata)->fast_command = 6;
466 /* Get Client IDs if present. Take IDs always instead of nickname. */
467 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
471 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
472 if (!tmp && !query->attrs) {
473 /* No nickname, no ids and no attributes - send error */
474 silc_server_query_send_error(server, query,
475 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
476 silc_server_query_free(query);
480 /* Get the nickname@server string and parse it */
481 if (tmp && ((tmp_len > 128) ||
482 !silc_parse_userfqdn(tmp, query->nickname,
483 sizeof(query->nickname),
485 sizeof(query->nick_server)))) {
486 silc_server_query_send_error(server, query,
487 SILC_STATUS_ERR_BAD_NICKNAME, 0);
488 silc_server_query_free(query);
494 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
495 SILC_STRING_UTF8, 128, &tmp_len);
497 silc_server_query_send_error(server, query,
498 SILC_STATUS_ERR_BAD_NICKNAME, 0);
499 silc_server_query_free(query);
502 memset(query->nickname, 0, sizeof(query->nickname));
503 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
508 /* Parse the IDs included in the query */
509 query->ids = silc_calloc(argc, sizeof(*query->ids));
511 for (i = 0; i < argc; i++) {
512 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
516 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
517 id.type != SILC_ID_CLIENT) {
518 silc_server_query_add_error(server, query, 1, i + 4,
519 SILC_STATUS_ERR_BAD_CLIENT_ID);
523 /* Normal server must check whether this ID exist, and if not then
524 send the query to router, unless done so already */
525 if (server->server_type == SILC_SERVER && !query->resolved) {
526 if (!silc_idlist_find_client_by_id(server->local_list,
527 &id.u.client_id, TRUE, NULL)) {
528 if (idata->conn_type != SILC_CONN_CLIENT ||
529 !silc_idlist_find_client_by_id(server->global_list,
530 &id.u.client_id, TRUE, NULL)) {
531 silc_server_query_send_router(server, query);
532 for (i = 0; i < query->ids_count; i++)
533 silc_free(query->ids[i].id);
534 silc_free(query->ids);
536 query->ids_count = 0;
542 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
544 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
549 /* Get the max count of reply messages allowed */
550 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
551 if (tmp && tmp_len == sizeof(SilcUInt32))
552 SILC_GET32_MSB(query->reply_count, tmp);
555 case SILC_COMMAND_WHOWAS:
557 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
559 silc_server_query_send_error(server, query,
560 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
561 silc_server_query_free(query);
565 /* Get the nickname@server string and parse it */
567 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
568 query->nick_server, sizeof(query->nick_server))) {
569 silc_server_query_send_error(server, query,
570 SILC_STATUS_ERR_BAD_NICKNAME, 0);
571 silc_server_query_free(query);
576 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
577 SILC_STRING_UTF8, 128, &tmp_len);
579 silc_server_query_send_error(server, query,
580 SILC_STATUS_ERR_BAD_NICKNAME, 0);
581 silc_server_query_free(query);
584 memset(query->nickname, 0, sizeof(query->nickname));
585 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
588 /* Get the max count of reply messages allowed */
589 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
590 if (tmp && tmp_len == sizeof(SilcUInt32))
591 SILC_GET32_MSB(query->reply_count, tmp);
594 case SILC_COMMAND_IDENTIFY:
595 /* Get IDs if present. Take IDs always instead of names. */
596 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
599 /* Try get nickname */
600 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
602 /* Get the nickname@server string and parse it */
604 !silc_parse_userfqdn(tmp, query->nickname,
605 sizeof(query->nickname),
607 sizeof(query->nick_server)))
608 silc_server_query_add_error(server, query, 1, 1,
609 SILC_STATUS_ERR_BAD_NICKNAME);
612 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
613 SILC_STRING_UTF8, 128, &tmp_len);
615 silc_server_query_send_error(server, query,
616 SILC_STATUS_ERR_BAD_NICKNAME, 0);
617 silc_server_query_free(query);
620 memset(query->nickname, 0, sizeof(query->nickname));
621 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
625 /* Try get server name */
626 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
628 /* Check server name */
629 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
632 silc_server_query_send_error(server, query,
633 SILC_STATUS_ERR_BAD_SERVER, 0);
634 silc_server_query_free(query);
637 query->server_name = tmp;
640 /* Get channel name */
641 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
642 if (tmp && tmp_len <= 256) {
643 /* Check channel name */
644 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
647 silc_server_query_send_error(server, query,
648 SILC_STATUS_ERR_BAD_CHANNEL, 0);
649 silc_server_query_free(query);
652 query->channel_name = tmp;
655 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
656 silc_server_query_send_error(server, query,
657 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
658 silc_server_query_free(query);
663 /* Parse the IDs included in the query */
664 query->ids = silc_calloc(argc, sizeof(*query->ids));
666 for (i = 0; i < argc; i++) {
667 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
671 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
672 silc_server_query_add_error(server, query, 1, i + 5,
673 SILC_STATUS_ERR_BAD_CLIENT_ID);
677 /* Normal server must check whether this ID exist, and if not then
678 send the query to router, unless done so already */
679 if (server->server_type == SILC_SERVER && !query->resolved) {
680 if (id.type == SILC_ID_CLIENT) {
681 if (!silc_idlist_find_client_by_id(server->local_list,
682 &id.u.client_id, TRUE, NULL)) {
683 if (idata->conn_type != SILC_CONN_CLIENT ||
684 !silc_idlist_find_client_by_id(server->global_list,
685 &id.u.client_id, TRUE,
687 silc_server_query_send_router(server, query);
688 for (i = 0; i < query->ids_count; i++)
689 silc_free(query->ids[i].id);
690 silc_free(query->ids);
692 query->ids_count = 0;
697 /* For now all other ID's except Client ID's are explicitly
698 sent to router for resolving. */
699 silc_server_query_send_router(server, query);
700 for (i = 0; i < query->ids_count; i++)
701 silc_free(query->ids[i].id);
702 silc_free(query->ids);
704 query->ids_count = 0;
709 if (id.type == SILC_ID_CLIENT)
710 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
712 if (id.type == SILC_ID_SERVER)
713 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
715 if (id.type == SILC_ID_CHANNEL)
716 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
718 query->ids[query->ids_count].id_type = id.type;
723 /* Get the max count of reply messages allowed */
724 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
725 if (tmp && tmp_len == sizeof(SilcUInt32))
726 SILC_GET32_MSB(query->reply_count, tmp);
730 query->parsed = TRUE;
733 if (!parse_only && query->nickname) {
734 switch (query->querycmd) {
735 case SILC_COMMAND_WHOIS:
736 case SILC_COMMAND_IDENTIFY:
737 /* Check server name. If we are open server and don't yet have
738 connection to remote router, create it now. */
739 if (query->nick_server[0] && server->config->dynamic_server &&
741 /* If primary router is specified, use that. Otherwise connect
742 to the server in nick@server string. */
743 SilcServerConfigRouter *router;
744 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
745 SILC_CONN_SERVER : SILC_CONN_ROUTER);
747 router = silc_server_config_get_primary_router(server);
748 if (router && server->standalone) {
749 /* Create connection to primary router */
750 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
751 router->host, router->port));
752 query->dynamic_prim = TRUE;
753 silc_server_create_connection(server, FALSE, TRUE,
754 router->host, router->port,
755 silc_server_query_connected, query);
757 } else if (!silc_server_num_sockets_by_remote(server,
761 /* Create connection and handle the query after connection */
762 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
763 query->nick_server, 706));
764 silc_server_create_connection(server, FALSE, TRUE,
765 query->nick_server, 706,
766 silc_server_query_connected, query);
773 /* Start processing the query information */
775 silc_server_query_process(server, query, TRUE);
780 /* Context for holding clients searched by public key. */
782 SilcClientEntry **clients;
783 SilcUInt32 *clients_count;
785 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
787 /* SKR find callbcak */
789 static void silc_server_query_skr_callback(SilcSKR skr,
791 SilcSKRStatus status,
795 SilcServerPublicKeyUser uc = context;
799 (*uc->clients) = silc_realloc((*uc->clients),
800 sizeof((**uc->clients)) *
801 ((*uc->clients_count) +
802 silc_dlist_count(keys)));
804 silc_dlist_start(keys);
805 while ((key = silc_dlist_get(keys)))
806 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
809 silc_dlist_uninit(keys);
812 silc_skr_find_free(find);
815 /* If clients are set, limit the found clients using the attributes in
816 the query. If clients are not set, try to find some clients using
819 void silc_server_query_check_attributes(SilcServer server,
820 SilcServerQuery query,
821 SilcClientEntry **clients,
822 SilcUInt32 *clients_count) {
823 SilcClientEntry entry;
824 SilcAttributePayload attr;
825 SilcAttribute attribute;
826 SilcAttributeObjPk pk;
827 SilcPublicKey publickey, cmp_pubkey;
829 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
832 /* If no clients were found, we only check the attributes
833 if the user wasn't searching for nickname/ids */
836 if (query->nickname[0] || query->ids_count)
840 silc_dlist_start(query->attrs);
841 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
842 attribute = silc_attribute_get_attribute(attr);
845 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
846 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
848 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
851 if (!strcmp(pk.type, "silc-rsa"))
852 type = SILC_PKCS_SILC;
853 else if (!strcmp(pk.type, "ssh-rsa"))
854 type = SILC_PKCS_SSH2;
855 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
856 type = SILC_PKCS_X509V3;
857 else if (!strcmp(pk.type, "pgp-sign-rsa"))
858 type = SILC_PKCS_OPENPGP;
862 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
868 search_pubkey = TRUE;
870 /* If no clients were set on calling this function, we just search
871 for clients, otherwise we try to limit the clients. */
873 SilcServerPublicKeyUserStruct usercontext;
876 usercontext.clients = clients;
877 usercontext.clients_count = clients_count;
878 usercontext.found = FALSE;
880 find = silc_skr_find_alloc();
884 silc_skr_find_set_public_key(find, publickey);
885 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
886 silc_skr_find(server->repository, server->schedule,
887 find, silc_server_query_skr_callback, &usercontext);
889 if (usercontext.found == TRUE)
892 for (i = 0; i < *clients_count; i++) {
893 entry = (*clients)[i];
895 if (!entry->data.public_key)
898 if (silc_server_get_public_key_by_client(server, entry,
900 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
906 (*clients)[i] = NULL;
911 silc_pkcs_public_key_free(publickey);
916 if (!found && !query->nickname[0] && !query->ids)
917 silc_server_query_add_error(server, query, 2, 0,
919 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
920 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
923 /* Processes the parsed query. This does the actual finding of the
924 queried information and prepares for sending reply to the original
925 sender of the query command. */
927 void silc_server_query_process(SilcServer server, SilcServerQuery query,
930 SilcServerCommandContext cmd = query->cmd;
931 SilcIDListData idata = silc_packet_get_context(cmd->sock);
932 SilcBool check_global = FALSE;
934 SilcClientEntry *clients = NULL, client_entry;
935 SilcChannelEntry *channels = NULL;
936 SilcServerEntry *servers = NULL;
937 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
940 SILC_LOG_DEBUG(("Processing %s query",
941 silc_get_command_name(query->querycmd)));
943 /* Check global lists if query is coming from client or we are not
944 normal server (we know global information). */
945 if (idata->conn_type == SILC_CONN_CLIENT)
947 else if (server->server_type != SILC_SERVER)
950 if (query->nickname[0]) {
951 /* Get all clients matching nickname from local list */
952 if (!silc_idlist_get_clients_by_hash(server->local_list,
954 query->nick_server[0] ?
955 query->nick_server : NULL,
957 &clients, &clients_count))
958 silc_idlist_get_clients_by_nickname(server->local_list,
960 query->nick_server[0] ?
961 query->nick_server : NULL,
962 &clients, &clients_count);
964 /* Check global list as well */
966 if (!silc_idlist_get_clients_by_hash(server->global_list,
968 query->nick_server[0] ?
969 query->nick_server : NULL,
971 &clients, &clients_count))
972 silc_idlist_get_clients_by_nickname(server->global_list,
974 query->nick_server[0] ?
975 query->nick_server : NULL,
976 &clients, &clients_count);
980 silc_server_query_add_error(server, query, 1, 1,
981 SILC_STATUS_ERR_NO_SUCH_NICK);
984 if (query->server_name) {
985 /* Find server by name */
986 entry = silc_idlist_find_server_by_name(server->local_list,
987 query->server_name, TRUE, NULL);
988 if (!entry && check_global)
989 entry = silc_idlist_find_server_by_name(server->global_list,
990 query->server_name, TRUE, NULL);
992 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
993 servers[servers_count++] = (SilcServerEntry)entry;
997 silc_server_query_add_error(server, query, 1, 2,
998 SILC_STATUS_ERR_NO_SUCH_SERVER);
1001 if (query->channel_name) {
1002 /* Find channel by name */
1003 entry = silc_idlist_find_channel_by_name(server->local_list,
1004 query->channel_name, NULL);
1005 if (!entry && check_global)
1006 entry = silc_idlist_find_channel_by_name(server->global_list,
1007 query->channel_name, NULL);
1009 channels = silc_realloc(channels, sizeof(*channels) *
1010 (channels_count + 1));
1011 channels[channels_count++] = (SilcChannelEntry)entry;
1015 silc_server_query_add_error(server, query, 1, 3,
1016 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1019 if (query->ids_count) {
1020 /* Find entries by the queried IDs */
1021 for (i = 0; i < query->ids_count; i++) {
1022 void *id = query->ids[i].id;
1026 switch (query->ids[i].id_type) {
1028 case SILC_ID_CLIENT:
1029 /* Get client entry */
1030 entry = silc_idlist_find_client_by_id(server->local_list,
1032 if (!entry && check_global)
1033 entry = silc_idlist_find_client_by_id(server->global_list,
1036 silc_server_query_add_error(server, query, 0, i,
1037 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1041 clients = silc_realloc(clients, sizeof(*clients) *
1042 (clients_count + 1));
1043 clients[clients_count++] = (SilcClientEntry)entry;
1046 case SILC_ID_SERVER:
1047 /* Get server entry */
1048 entry = silc_idlist_find_server_by_id(server->local_list,
1050 if (!entry && check_global)
1051 entry = silc_idlist_find_server_by_id(server->global_list,
1054 silc_server_query_add_error(server, query, 0, i,
1055 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1059 servers = silc_realloc(servers, sizeof(*servers) *
1060 (servers_count + 1));
1061 servers[servers_count++] = (SilcServerEntry)entry;
1064 case SILC_ID_CHANNEL:
1065 /* Get channel entry */
1066 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1067 if (!entry && check_global)
1068 entry = silc_idlist_find_channel_by_id(server->global_list, id,
1071 silc_server_query_add_error(server, query, 0, i,
1072 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1076 channels = silc_realloc(channels, sizeof(*channels) *
1077 (channels_count + 1));
1078 channels[channels_count++] = (SilcChannelEntry)entry;
1087 /* Check the attributes to narrow down the search by using them. */
1089 silc_server_query_check_attributes(server, query, &clients,
1092 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1093 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1094 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1096 /* If nothing was found, then just send the errors */
1097 if (!clients && !channels && !servers) {
1098 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1102 /* If caller does not want us to resolve anything (has resolved already)
1103 then just continue with sending the reply */
1105 silc_server_query_send_reply(server, query, clients, clients_count,
1106 servers, servers_count, channels,
1110 silc_free(channels);
1114 /* Now process all found information and if necessary do some more
1116 switch (query->querycmd) {
1118 case SILC_COMMAND_WHOIS:
1119 for (i = 0; i < clients_count; i++) {
1120 client_entry = clients[i];
1122 /* Check if cannot query this anyway, so take next one */
1123 if (!client_entry ||
1124 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1127 /* If Requested Attributes is set then we always resolve the client
1128 information, if not then check whether the entry is complete or not
1129 and decide whether we need to resolve or not. */
1130 if (!query->attrs) {
1132 /* Even if nickname and stuff are present, we may need to resolve
1134 if (client_entry->nickname && client_entry->username &&
1135 client_entry->userinfo) {
1136 /* Check if cannot query this anyway, so take next one */
1137 if (!client_entry->router)
1140 /* If we are router, client is local to us, or client is on channel
1141 we do not need to resolve the client information. */
1142 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1143 || silc_hash_table_count(client_entry->channels) ||
1149 /* Remove the NOATTR status periodically */
1150 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1151 client_entry->updated + 600 < time(NULL))
1152 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1154 /* When requested attributes is present and local client is detached
1155 we cannot send the command to the client, we'll reply on behalf of
1156 the client instead. */
1157 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1158 (client_entry->mode & SILC_UMODE_DETACHED ||
1159 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1162 /* If attributes are present in query, and in the entry and we have
1163 done resolvings already we don't need to resolve anymore */
1164 if (query->resolved && query->attrs && client_entry->attrs)
1167 /* Resolve the detailed client information. If client is local we
1168 know that attributes were present and we will resolve directly
1169 from the client. Otherwise resolve from client's owner. */
1170 silc_server_query_resolve(server, query,
1171 (SILC_IS_LOCAL(client_entry) ?
1172 client_entry->connection :
1173 client_entry->router->connection),
1178 case SILC_COMMAND_WHOWAS:
1179 for (i = 0; i < clients_count; i++) {
1180 client_entry = clients[i];
1182 /* Check if cannot query this anyway, so take next one */
1183 if (!client_entry || !client_entry->router ||
1184 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1187 /* If both nickname and username are present no resolving is needed */
1188 if (client_entry->nickname && client_entry->username)
1191 /* Resolve the detailed client information */
1192 silc_server_query_resolve(server, query,
1193 client_entry->router->connection,
1198 case SILC_COMMAND_IDENTIFY:
1199 for (i = 0; i < clients_count; i++) {
1200 client_entry = clients[i];
1202 /* Check if cannot query this anyway, so take next one */
1203 if (!client_entry || !client_entry->router ||
1204 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1207 /* Even if nickname is present, we may need to resolve the entry */
1208 if (client_entry->nickname) {
1210 /* If we are router, client is local to us, or client is on channel
1211 we do not need to resolve the client information. */
1212 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1213 || silc_hash_table_count(client_entry->channels) ||
1218 /* Resolve the detailed client information */
1219 silc_server_query_resolve(server, query,
1220 client_entry->router->connection,
1226 if (!query->queries_count)
1227 /* If we didn't have to do any resolving, continue with sending the
1228 command reply to the original sender. */
1229 silc_server_query_send_reply(server, query, clients, clients_count,
1230 servers, servers_count, channels,
1233 /* Now actually send the resolvings we gathered earlier */
1234 silc_server_query_resolve(server, query, NULL, NULL);
1238 silc_free(channels);
1241 /* Resolve the detailed information for the `client_entry'. Only client
1242 information needs to be resolved for being incomplete. Each incomplete
1243 client entry calls this function to do the resolving. */
1245 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1246 SilcPacketStream sock,
1247 SilcClientEntry client_entry)
1249 SilcServerCommandContext cmd = query->cmd;
1250 SilcServerQueryList r = NULL;
1257 if (!sock && client_entry)
1260 /* If arguments are NULL we will now actually send the resolvings
1261 that earlier has been gathered by calling this function. */
1262 if (!sock && !client_entry) {
1265 SILC_LOG_DEBUG(("Sending the resolvings"));
1267 /* WHOWAS resolving has been done at the same time this function
1268 was called to add the resolving for WHOWAS, so just return. */
1269 if (query->querycmd == SILC_COMMAND_WHOWAS)
1272 for (i = 0; i < query->querylist_count; i++) {
1273 r = &query->querylist[i];
1275 /* If Requested Attributes were present put them to this resolving */
1276 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1278 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1279 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1280 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1282 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1284 r->arg[r->argc] = silc_memdup(tmp, len);
1285 r->arg_lens[r->argc] = len;
1286 r->arg_types[r->argc] = 3;
1291 server->stat.commands_sent++;
1293 /* Send WHOIS command */
1294 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1295 r->argc, r->arg, r->arg_lens,
1296 r->arg_types, r->ident);
1297 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1298 res_cmd->data, silc_buffer_len(res_cmd));
1299 silc_buffer_free(res_cmd);
1301 /* Reprocess this packet after received reply */
1302 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1304 silc_server_query_resolve_reply,
1306 query->queries_left++;
1309 /* Cleanup this temporary context */
1310 for (i = 0; i < query->querylist_count; i++) {
1312 for (k = 0; k < query->querylist[i].argc; k++)
1313 silc_free(query->querylist[i].arg[k]);
1314 silc_free(query->querylist[i].arg);
1315 silc_free(query->querylist[i].arg_lens);
1316 silc_free(query->querylist[i].arg_types);
1318 silc_free(query->querylist);
1319 query->querylist = NULL;
1320 query->querylist_count = 0;
1324 SILC_LOG_DEBUG(("Resolving client information"));
1326 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1327 /* The entry is being resolved by some other external query already.
1328 Attach to that query instead of resolving again. */
1329 ident = client_entry->resolve_cmd_ident;
1330 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1331 silc_server_query_resolve_reply, query))
1332 query->queries_left++;
1334 /* This entry will be resolved */
1335 ident = ++server->cmd_ident;
1337 switch (query->querycmd) {
1339 case SILC_COMMAND_WHOIS:
1340 case SILC_COMMAND_IDENTIFY:
1341 /* Take existing query context if exist for this connection */
1342 for (i = 0; i < query->querylist_count; i++)
1343 if (query->querylist[i].sock == sock) {
1344 r = &query->querylist[i];
1349 /* Allocate new temp query list context */
1350 query->querylist = silc_realloc(query->querylist,
1351 sizeof(*query->querylist) *
1352 (query->querylist_count + 1));
1353 r = &query->querylist[query->querylist_count];
1354 query->querylist_count++;
1355 memset(r, 0, sizeof(*r));
1358 if (SILC_IS_LOCAL(client_entry))
1363 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1364 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1365 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1367 /* Add the client entry to be resolved */
1368 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1369 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1370 r->arg_lens[r->argc] = silc_buffer_len(idp);
1371 r->arg_types[r->argc] = r->argc + 4;
1373 silc_buffer_free(idp);
1377 case SILC_COMMAND_WHOWAS:
1378 /* We must send WHOWAS command since it's the only the way of
1379 resolving clients that are not present in the network anymore. */
1380 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1381 1, query->nickname, strlen(query->nickname));
1382 if (silc_server_command_pending(server, query->querycmd, ident,
1383 silc_server_query_resolve_reply, query))
1384 query->queries_left++;
1389 /* Mark the entry as being resolved */
1390 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1391 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1392 client_entry->resolve_cmd_ident = ident;
1393 client_entry->updated = time(NULL);
1395 /* Save the queried ID, which we will reprocess after we get this and
1396 all other queries back. */
1397 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1398 (query->queries_count + 1));
1399 if (query->queries) {
1400 i = query->queries_count;
1401 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1402 query->queries[i].id_type = SILC_ID_CLIENT;
1403 query->queries[i].ident = ident;
1404 query->queries_count++;
1408 /* Reply callback called after one resolving has been completed. If
1409 all resolvings has been received then we will continue with sending
1410 the command reply to the original sender of the query. */
1412 void silc_server_query_resolve_reply(void *context, void *reply)
1414 SilcServerQuery query = context;
1415 SilcServer server = query->cmd->server;
1416 SilcServerCommandReplyContext cmdr = reply;
1417 SilcUInt16 ident = cmdr->ident;
1418 SilcStatus error = SILC_STATUS_OK;
1419 SilcServerQueryID id = NULL;
1420 SilcClientEntry client_entry;
1423 /* One less query left */
1424 query->queries_left--;
1426 silc_command_get_status(cmdr->payload, NULL, &error);
1427 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1428 query->queries_left, error));
1430 /* If no error then skip to other stuff */
1431 if (error == SILC_STATUS_OK)
1434 /* Error occurred during resolving */
1436 /* Find the resolved client ID */
1437 for (i = 0; i < query->queries_count; i++) {
1438 if (query->queries[i].ident != ident)
1441 id = &query->queries[i];
1443 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1445 /* If timeout occurred for local entry when resolving attributes
1446 mark that this client doesn't support attributes in WHOIS. This
1447 assures we won't send the request again to the client. */
1448 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1449 client_entry = silc_idlist_find_client_by_id(server->local_list,
1450 id->id, TRUE, NULL);
1451 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1452 silc_id_render(id->id, SILC_ID_CLIENT)));
1453 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1454 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1455 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1460 /* Remove the RESOLVING status from the client entry */
1461 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1462 client_entry = silc_idlist_find_client_by_id(server->local_list,
1463 id->id, TRUE, NULL);
1465 client_entry = silc_idlist_find_client_by_id(server->global_list,
1466 id->id, TRUE, NULL);
1468 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1475 /* If there are queries left then wait for them */
1476 if (query->queries_left)
1479 SILC_LOG_DEBUG(("Reprocess the query"));
1481 /* If the original command caller has gone away, just stop. */
1482 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1483 SILC_LOG_DEBUG(("Original command caller vanished"));
1484 silc_server_query_free(query);
1488 /* We have received all queries. Now re-search all information required
1489 to complete this query. Reason we cannot save the values found in
1490 the first search is that SilcClientEntry, SilcServerEntry and
1491 SilcChannelEntry pointers may become invalid while we were waiting
1492 for these resolvings. */
1493 silc_server_query_process(server, query, FALSE);
1496 /* Send the reply to the original query. If arguments are NULL then this
1497 sends only the errors that has occurred during the processing of the
1498 query. This sends the errors always after sending all the found
1499 information. The query is over after this function returns and the
1500 `query' will become invalid. This is called only after all informations
1501 has been resolved. This means that if something is not found or is
1502 incomplete in this function we were unable to resolve the information
1503 or it does not exist at all. */
1505 void silc_server_query_send_reply(SilcServer server,
1506 SilcServerQuery query,
1507 SilcClientEntry *clients,
1508 SilcUInt32 clients_count,
1509 SilcServerEntry *servers,
1510 SilcUInt32 servers_count,
1511 SilcChannelEntry *channels,
1512 SilcUInt32 channels_count)
1514 SilcServerCommandContext cmd = query->cmd;
1515 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1516 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1521 int i, k, valid_count;
1522 char nh[384], uh[384];
1523 SilcBool sent_reply = FALSE;
1525 SILC_LOG_DEBUG(("Sending reply to query"));
1526 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1527 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1528 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1529 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1531 status = SILC_STATUS_OK;
1534 if (clients_count) {
1535 SilcClientEntry entry;
1536 SilcPacketStream hsock;
1538 /* Mark all invalid entries */
1539 for (i = 0, valid_count = 0; i < clients_count; i++) {
1544 switch (query->querycmd) {
1545 case SILC_COMMAND_WHOIS:
1546 if (!entry->nickname || !entry->username || !entry->userinfo ||
1547 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1548 /* When querying by ID, every "unfound" entry must cause error */
1550 silc_server_query_add_error_id(server, query,
1551 SILC_STATUS_ERR_TIMEDOUT,
1552 entry->id, SILC_ID_CLIENT);
1558 case SILC_COMMAND_IDENTIFY:
1559 if (!entry->nickname ||
1560 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1561 /* When querying by ID, every "unfound" entry must cause error */
1563 silc_server_query_add_error_id(server, query,
1564 SILC_STATUS_ERR_TIMEDOUT,
1565 entry->id, SILC_ID_CLIENT);
1571 case SILC_COMMAND_WHOWAS:
1572 if (!entry->nickname || !entry->username ||
1573 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1582 /* Start processing found clients */
1583 status = SILC_STATUS_OK;
1584 if (valid_count > 1)
1585 status = SILC_STATUS_LIST_START;
1587 /* Now do the sending of valid entries */
1589 for (i = 0; i < clients_count && valid_count; i++) {
1595 status = SILC_STATUS_LIST_ITEM;
1596 if (valid_count > 1 && k == valid_count - 1
1597 && !servers_count && !channels_count && !query->errors_count)
1598 status = SILC_STATUS_LIST_END;
1599 if (query->reply_count && k - 1 == query->reply_count)
1600 status = SILC_STATUS_LIST_END;
1602 SILC_LOG_DEBUG(("%s: client %s",
1603 (status == SILC_STATUS_OK ? " OK" :
1604 status == SILC_STATUS_LIST_START ? "START" :
1605 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1606 status == SILC_STATUS_LIST_END ? " END" :
1607 " : "), entry->nickname));
1609 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1610 memset(nh, 0, sizeof(nh));
1612 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1613 if (!strchr(entry->nickname, '@')) {
1614 silc_strncat(nh, sizeof(nh), "@", 1);
1615 if (entry->servername) {
1616 silc_strncat(nh, sizeof(nh), entry->servername,
1617 strlen(entry->servername));
1619 len = entry->router ? strlen(entry->router->server_name) :
1620 strlen(server->server_name);
1621 silc_strncat(nh, sizeof(nh), entry->router ?
1622 entry->router->server_name :
1623 server->server_name, len);
1627 switch (query->querycmd) {
1629 case SILC_COMMAND_WHOIS:
1631 unsigned char idle[4], mode[4];
1632 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1633 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1635 memset(fempty, 0, sizeof(fempty));
1636 memset(idle, 0, sizeof(idle));
1637 memset(uh, 0, sizeof(uh));
1639 silc_strncat(uh, sizeof(uh), entry->username,
1640 strlen(entry->username));
1641 if (!strchr(entry->username, '@') && entry->connection) {
1642 hsock = entry->connection;
1643 silc_strncat(uh, sizeof(uh), "@", 1);
1644 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1645 NULL, (const char **)&tmp, NULL, NULL);
1646 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1649 if (idata->conn_type == SILC_CONN_CLIENT)
1651 silc_server_get_client_channel_list(server, entry, FALSE,
1652 FALSE, &umode_list);
1655 silc_server_get_client_channel_list(server, entry, TRUE,
1658 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1659 fingerprint = entry->data.fingerprint;
1663 SILC_PUT32_MSB(entry->mode, mode);
1664 if (entry->connection)
1665 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1667 /* If Requested Attribute were present, and we do not have the
1668 attributes we will reply to them on behalf of the client. */
1671 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1672 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1673 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1674 entry->attrs_len = len;
1675 silc_buffer_free(tmpattrs);
1677 attrs = entry->attrs;
1678 len = entry->attrs_len;
1681 /* Send command reply */
1682 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1683 status, 0, ident, 10,
1684 2, idp->data, silc_buffer_len(idp),
1688 strlen(entry->userinfo),
1689 6, channels ? channels->data : NULL,
1690 channels ? silc_buffer_len(channels)
1695 fingerprint ? 20 : 0,
1696 10, umode_list ? umode_list->data :
1698 silc_buffer_len(umode_list) :
1703 /* For now we always delete Requested Attributes, unless the client
1704 is detached, in which case we don't want to reconstruct the
1705 same data everytime */
1706 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1707 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1708 silc_free(entry->attrs);
1709 entry->attrs = NULL;
1713 silc_buffer_free(channels);
1715 silc_buffer_free(umode_list);
1721 case SILC_COMMAND_IDENTIFY:
1722 if (!entry->username) {
1723 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1724 status, 0, ident, 2,
1725 2, idp->data, silc_buffer_len(idp),
1729 memset(uh, 0, sizeof(uh));
1730 silc_strncat(uh, sizeof(uh), entry->username,
1731 strlen(entry->username));
1732 if (!strchr(entry->username, '@') && entry->connection) {
1733 hsock = entry->connection;
1734 silc_strncat(uh, sizeof(uh), "@", 1);
1735 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1736 NULL, (const char **)&tmp,
1738 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1741 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1742 status, 0, ident, 3,
1743 2, idp->data, silc_buffer_len(idp),
1750 case SILC_COMMAND_WHOWAS:
1751 memset(uh, 0, sizeof(uh));
1752 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1753 if (!strchr(entry->username, '@'))
1754 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1756 /* Send command reply */
1757 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1758 status, 0, ident, 4,
1759 2, idp->data, silc_buffer_len(idp),
1764 strlen(entry->userinfo) : 0);
1769 silc_buffer_free(idp);
1771 if (status == SILC_STATUS_LIST_END)
1777 /* Not one valid entry was found, send error. If nickname was used
1778 in query send error based on that, otherwise the query->errors
1779 already includes proper errors. */
1780 if (query->nickname[0] || (!query->ids && query->attrs))
1781 silc_server_query_add_error(server, query, 1, 1,
1782 SILC_STATUS_ERR_NO_SUCH_NICK);
1784 /* Make sure some error is sent */
1785 if (!query->errors_count && !servers_count && !channels_count)
1786 silc_server_query_add_error(server, query, 2, 0,
1787 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1792 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1793 SilcServerEntry entry;
1795 if (status == SILC_STATUS_OK && servers_count > 1)
1796 status = SILC_STATUS_LIST_START;
1799 for (i = 0; i < servers_count; i++) {
1803 status = SILC_STATUS_LIST_ITEM;
1804 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1805 !query->errors_count)
1806 status = SILC_STATUS_LIST_END;
1807 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1808 !query->errors_count)
1809 status = SILC_STATUS_LIST_END;
1810 if (query->reply_count && k - 1 == query->reply_count)
1811 status = SILC_STATUS_LIST_END;
1813 SILC_LOG_DEBUG(("%s: server %s",
1814 (status == SILC_STATUS_OK ? " OK" :
1815 status == SILC_STATUS_LIST_START ? "START" :
1816 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1817 status == SILC_STATUS_LIST_END ? " END" :
1819 entry->server_name ? entry->server_name : ""));
1821 /* Send command reply */
1822 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1823 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1824 status, 0, ident, 2,
1825 2, idp->data, silc_buffer_len(idp),
1826 3, entry->server_name,
1827 entry->server_name ?
1828 strlen(entry->server_name) : 0);
1829 silc_buffer_free(idp);
1832 if (status == SILC_STATUS_LIST_END)
1839 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1840 SilcChannelEntry entry;
1842 if (status == SILC_STATUS_OK && channels_count > 1)
1843 status = SILC_STATUS_LIST_START;
1846 for (i = 0; i < channels_count; i++) {
1847 entry = channels[i];
1850 status = SILC_STATUS_LIST_ITEM;
1851 if (channels_count == 1 && status != SILC_STATUS_OK &&
1852 !query->errors_count)
1853 status = SILC_STATUS_LIST_END;
1854 if (channels_count > 1 && k == channels_count - 1 &&
1855 !query->errors_count)
1856 status = SILC_STATUS_LIST_END;
1857 if (query->reply_count && k - 1 == query->reply_count)
1858 status = SILC_STATUS_LIST_END;
1860 SILC_LOG_DEBUG(("%s: channel %s",
1861 (status == SILC_STATUS_OK ? " OK" :
1862 status == SILC_STATUS_LIST_START ? "START" :
1863 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1864 status == SILC_STATUS_LIST_END ? " END" :
1866 entry->channel_name ? entry->channel_name : ""));
1868 /* Send command reply */
1869 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1870 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1871 status, 0, ident, 2,
1872 2, idp->data, silc_buffer_len(idp),
1873 3, entry->channel_name,
1874 entry->channel_name ?
1875 strlen(entry->channel_name) : 0);
1876 silc_buffer_free(idp);
1879 if (status == SILC_STATUS_LIST_END)
1886 if (query->errors_count) {
1889 if (status == SILC_STATUS_OK && query->errors_count > 1)
1890 status = SILC_STATUS_LIST_START;
1893 for (i = 0; i < query->errors_count; i++) {
1896 /* Take error argument */
1897 if (query->errors[i].type == 1) {
1898 /* Take from sent arguments */
1900 tmp = silc_argument_get_arg_type(cmd->args,
1901 query->errors[i].index, &len);
1903 } else if (query->errors[i].type == 2) {
1908 } else if (!query->errors[i].id) {
1909 /* Take from query->ids */
1911 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1912 query->ids[query->errors[k].index].id_type);
1914 len = silc_buffer_len(idp);
1917 /* Take added ID. */
1918 idp = silc_id_payload_encode(query->errors[i].id,
1919 query->errors[k].id_type);
1921 len = silc_buffer_len(idp);
1926 status = SILC_STATUS_LIST_ITEM;
1927 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1928 status = SILC_STATUS_LIST_END;
1929 if (query->errors_count > 1 && k == query->errors_count - 1)
1930 status = SILC_STATUS_LIST_END;
1931 if (query->reply_count && k - 1 == query->reply_count)
1932 status = SILC_STATUS_LIST_END;
1934 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1935 (status == SILC_STATUS_OK ? " OK" :
1936 status == SILC_STATUS_LIST_START ? "START" :
1937 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1938 status == SILC_STATUS_LIST_END ? " END" :
1940 silc_get_status_message(query->errors[i].error),
1941 query->errors[i].error));
1943 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1944 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1946 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1947 (status == SILC_STATUS_OK ?
1948 query->errors[i].error : status),
1949 (status == SILC_STATUS_OK ?
1950 0 : query->errors[i].error), ident, 2,
1956 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1957 (status == SILC_STATUS_OK ?
1958 query->errors[i].error : status),
1959 (status == SILC_STATUS_OK ?
1960 0 : query->errors[i].error), ident, 1,
1963 silc_buffer_free(idp);
1966 if (status == SILC_STATUS_LIST_END)
1973 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1976 silc_server_query_free(query);
1979 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1980 of the client since we were unable to resolve them from the client.
1981 Either client does not support Requested Attributes or isn't replying
1982 to them like it should. */
1984 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1985 SilcServerQuery query,
1986 SilcClientEntry client_entry)
1988 SilcBuffer buffer = NULL;
1989 SilcAttribute attribute;
1990 SilcAttributePayload attr;
1991 SilcAttributeObjPk pk;
1992 SilcAttributeObjService service;
1994 unsigned char sign[2048 + 1];
1995 SilcUInt32 sign_len;
1997 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1999 /* Go through all requested attributes */
2000 silc_dlist_start(query->attrs);
2001 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
2002 attribute = silc_attribute_get_attribute(attr);
2003 switch (attribute) {
2005 case SILC_ATTRIBUTE_SERVICE:
2006 /* Put SERVICE. Put only SILC service. */
2007 memset(&service, 0, sizeof(service));
2008 service.port = (server->config->server_info->primary ?
2009 server->config->server_info->primary->port : SILC_PORT);
2010 silc_strncat(service.address, sizeof(service.address),
2011 server->server_name, strlen(server->server_name));
2012 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2013 if (client_entry->connection)
2014 service.idle = time(NULL) - client_entry->data.last_receive;
2015 buffer = silc_attribute_payload_encode(buffer, attribute,
2016 SILC_ATTRIBUTE_FLAG_VALID,
2017 &service, sizeof(service));
2022 case SILC_ATTRIBUTE_STATUS_MOOD:
2023 /* Put STATUS_MOOD */
2024 buffer = silc_attribute_payload_encode(buffer, attribute,
2025 SILC_ATTRIBUTE_FLAG_VALID,
2027 SILC_ATTRIBUTE_MOOD_NORMAL,
2028 sizeof(SilcUInt32));
2033 case SILC_ATTRIBUTE_STATUS_FREETEXT:
2034 /* Put STATUS_FREETEXT. We just tell in the message that we are
2035 replying on behalf of the client. */
2037 "This information was provided by the server on behalf of the user";
2038 buffer = silc_attribute_payload_encode(buffer, attribute,
2039 SILC_ATTRIBUTE_FLAG_VALID,
2045 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2046 /* Put PREFERRED_CONTACT */
2047 buffer = silc_attribute_payload_encode(buffer, attribute,
2048 SILC_ATTRIBUTE_FLAG_VALID,
2050 SILC_ATTRIBUTE_CONTACT_CHAT,
2051 sizeof(SilcUInt32));
2056 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2057 /* Put USER_PUBLIC_KEY */
2058 if (client_entry->data.public_key) {
2059 pk.type = "silc-rsa";
2060 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2062 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2063 SILC_ATTRIBUTE_FLAG_VALID :
2064 SILC_ATTRIBUTE_FLAG_INVALID,
2072 /* No public key available */
2073 buffer = silc_attribute_payload_encode(buffer, attribute,
2074 SILC_ATTRIBUTE_FLAG_INVALID,
2081 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2082 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2083 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2086 /* For other attributes we cannot reply so mark it invalid */
2087 buffer = silc_attribute_payload_encode(buffer, attribute,
2088 SILC_ATTRIBUTE_FLAG_INVALID,
2096 /* Always put our public key. This assures that we send at least
2097 something valid back always. */
2098 pk.type = "silc-rsa";
2099 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2100 buffer = silc_attribute_payload_encode(buffer,
2101 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2102 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2103 SILC_ATTRIBUTE_FLAG_INVALID,
2109 /* Finally compute the digital signature of all the data we provided
2110 as an indication that we provided rightfull information, and this
2111 also authenticates our public key. */
2112 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2114 silc_pkcs_sign(server->private_key, buffer->data,
2115 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2116 TRUE, server->sha1hash)) {
2119 pk.data_len = sign_len;
2121 silc_attribute_payload_encode(buffer,
2122 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2123 SILC_ATTRIBUTE_FLAG_VALID,
2132 /* Find client by the Client ID indicated by the `client_id', and if not
2133 found then query it by using WHOIS command. The client information
2134 is also resolved if the cached information is incomplete or if the
2135 `always_resolve' is set to TRUE. The indication whether requested
2136 client was being resolved is saved into `resolved'. If the client
2137 is not being resolved its entry is returned by this function. NULL
2138 is returned if client is resolved. */
2140 SilcClientEntry silc_server_query_client(SilcServer server,
2141 const SilcClientID *client_id,
2142 SilcBool always_resolve,
2145 SilcClientEntry client;
2147 SILC_LOG_DEBUG(("Resolving client by client ID"));
2152 client = silc_idlist_find_client_by_id(server->local_list,
2153 (SilcClientID *)client_id,
2156 client = silc_idlist_find_client_by_id(server->global_list,
2157 (SilcClientID *)client_id,
2159 if (!client && server->server_type == SILC_ROUTER)
2163 if (!client && server->standalone)
2166 if (!client || !client->nickname || !client->username ||
2168 SilcBuffer buffer, idp;
2171 server->stat.commands_sent++;
2174 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2175 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2176 client->resolve_cmd_ident = ++server->cmd_ident;
2179 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2180 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2181 server->cmd_ident, 1,
2183 silc_buffer_len(idp));
2184 silc_server_packet_send(server, client ? client->router->connection :
2185 SILC_PRIMARY_ROUTE(server),
2186 SILC_PACKET_COMMAND, 0,
2187 buffer->data, silc_buffer_len(buffer));
2188 silc_buffer_free(idp);
2189 silc_buffer_free(buffer);