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 server->config->dynamic_server &&
400 !silc_server_num_sockets_by_remote(server, query->nick_server,
401 query->nick_server, 706, type)) {
402 SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
403 query->nick_server, 706));
404 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
405 706, silc_server_query_connected,
407 query->dynamic_retry = TRUE;
408 query->resolved = FALSE;
412 SILC_LOG_DEBUG(("Sending error to original query"));
415 server->stat.commands_sent++;
417 /* Send the same command reply payload which contains the error */
418 silc_command_set_command(cmdr->payload, query->querycmd);
419 silc_command_set_ident(cmdr->payload,
420 silc_command_get_ident(query->cmd->payload));
421 buffer = silc_command_payload_encode_payload(cmdr->payload);
422 silc_server_packet_send(server, query->cmd->sock,
423 SILC_PACKET_COMMAND_REPLY, 0,
424 buffer->data, silc_buffer_len(buffer));
425 silc_buffer_free(buffer);
426 silc_server_query_free(query);
430 /* Continue with parsing */
431 silc_server_query_parse(server, query, FALSE);
434 /* Parse the command query and start processing the queries in detail. */
436 SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
439 SilcServerCommandContext cmd = query->cmd;
440 SilcIDListData idata = silc_packet_get_context(cmd->sock);
442 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
446 SILC_LOG_DEBUG(("Parsing %s query",
447 silc_get_command_name(query->querycmd)));
452 switch (query->querycmd) {
454 case SILC_COMMAND_WHOIS:
455 /* Get requested attributes if set */
456 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
457 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
458 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
460 /* When Requested Attributes is present we will assure that this
461 client cannot execute the WHOIS command too fast. This would be
462 same as having SILC_CF_LAG_STRICT. */
463 if (idata && idata->conn_type == SILC_CONN_CLIENT)
464 ((SilcClientEntry)idata)->fast_command = 6;
467 /* Get Client IDs if present. Take IDs always instead of nickname. */
468 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
472 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
473 if (!tmp && !query->attrs) {
474 /* No nickname, no ids and no attributes - send error */
475 silc_server_query_send_error(server, query,
476 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
477 silc_server_query_free(query);
481 /* Get the nickname@server string and parse it */
482 if (tmp && ((tmp_len > 128) ||
483 !silc_parse_userfqdn(tmp, query->nickname,
484 sizeof(query->nickname),
486 sizeof(query->nick_server)))) {
487 silc_server_query_send_error(server, query,
488 SILC_STATUS_ERR_BAD_NICKNAME, 0);
489 silc_server_query_free(query);
495 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
496 SILC_STRING_UTF8, 128, &tmp_len);
498 silc_server_query_send_error(server, query,
499 SILC_STATUS_ERR_BAD_NICKNAME, 0);
500 silc_server_query_free(query);
503 memset(query->nickname, 0, sizeof(query->nickname));
504 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
509 /* Parse the IDs included in the query */
510 query->ids = silc_calloc(argc, sizeof(*query->ids));
512 for (i = 0; i < argc; i++) {
513 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
517 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
518 id.type != SILC_ID_CLIENT) {
519 silc_server_query_add_error(server, query, 1, i + 4,
520 SILC_STATUS_ERR_BAD_CLIENT_ID);
524 /* Normal server must check whether this ID exist, and if not then
525 send the query to router, unless done so already */
526 if (server->server_type == SILC_SERVER && !query->resolved) {
527 if (!silc_idlist_find_client_by_id(server->local_list,
528 &id.u.client_id, TRUE, NULL)) {
529 if (idata->conn_type != SILC_CONN_CLIENT ||
530 !silc_idlist_find_client_by_id(server->global_list,
531 &id.u.client_id, TRUE, NULL)) {
532 silc_server_query_send_router(server, query);
533 for (i = 0; i < query->ids_count; i++)
534 silc_free(query->ids[i].id);
535 silc_free(query->ids);
537 query->ids_count = 0;
543 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
545 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
550 /* Get the max count of reply messages allowed */
551 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
552 if (tmp && tmp_len == sizeof(SilcUInt32))
553 SILC_GET32_MSB(query->reply_count, tmp);
556 case SILC_COMMAND_WHOWAS:
558 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
560 silc_server_query_send_error(server, query,
561 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
562 silc_server_query_free(query);
566 /* Get the nickname@server string and parse it */
568 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
569 query->nick_server, sizeof(query->nick_server))) {
570 silc_server_query_send_error(server, query,
571 SILC_STATUS_ERR_BAD_NICKNAME, 0);
572 silc_server_query_free(query);
577 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
578 SILC_STRING_UTF8, 128, &tmp_len);
580 silc_server_query_send_error(server, query,
581 SILC_STATUS_ERR_BAD_NICKNAME, 0);
582 silc_server_query_free(query);
585 memset(query->nickname, 0, sizeof(query->nickname));
586 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
589 /* Get the max count of reply messages allowed */
590 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
591 if (tmp && tmp_len == sizeof(SilcUInt32))
592 SILC_GET32_MSB(query->reply_count, tmp);
595 case SILC_COMMAND_IDENTIFY:
596 /* Get IDs if present. Take IDs always instead of names. */
597 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
600 /* Try get nickname */
601 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
603 /* Get the nickname@server string and parse it */
605 !silc_parse_userfqdn(tmp, query->nickname,
606 sizeof(query->nickname),
608 sizeof(query->nick_server)))
609 silc_server_query_add_error(server, query, 1, 1,
610 SILC_STATUS_ERR_BAD_NICKNAME);
613 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
614 SILC_STRING_UTF8, 128, &tmp_len);
616 silc_server_query_send_error(server, query,
617 SILC_STATUS_ERR_BAD_NICKNAME, 0);
618 silc_server_query_free(query);
621 memset(query->nickname, 0, sizeof(query->nickname));
622 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
626 /* Try get server name */
627 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
629 /* Check server name */
630 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
633 silc_server_query_send_error(server, query,
634 SILC_STATUS_ERR_BAD_SERVER, 0);
635 silc_server_query_free(query);
638 query->server_name = tmp;
641 /* Get channel name */
642 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
643 if (tmp && tmp_len <= 256) {
644 /* Check channel name */
645 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
648 silc_server_query_send_error(server, query,
649 SILC_STATUS_ERR_BAD_CHANNEL, 0);
650 silc_server_query_free(query);
653 query->channel_name = tmp;
656 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
657 silc_server_query_send_error(server, query,
658 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
659 silc_server_query_free(query);
664 /* Parse the IDs included in the query */
665 query->ids = silc_calloc(argc, sizeof(*query->ids));
667 for (i = 0; i < argc; i++) {
668 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
672 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
673 silc_server_query_add_error(server, query, 1, i + 5,
674 SILC_STATUS_ERR_BAD_CLIENT_ID);
678 /* Normal server must check whether this ID exist, and if not then
679 send the query to router, unless done so already */
680 if (server->server_type == SILC_SERVER && !query->resolved) {
681 if (id.type == SILC_ID_CLIENT) {
682 if (!silc_idlist_find_client_by_id(server->local_list,
683 &id.u.client_id, TRUE, NULL)) {
684 if (idata->conn_type != SILC_CONN_CLIENT ||
685 !silc_idlist_find_client_by_id(server->global_list,
686 &id.u.client_id, TRUE,
688 silc_server_query_send_router(server, query);
689 for (i = 0; i < query->ids_count; i++)
690 silc_free(query->ids[i].id);
691 silc_free(query->ids);
693 query->ids_count = 0;
698 /* For now all other ID's except Client ID's are explicitly
699 sent to router for resolving. */
700 silc_server_query_send_router(server, query);
701 for (i = 0; i < query->ids_count; i++)
702 silc_free(query->ids[i].id);
703 silc_free(query->ids);
705 query->ids_count = 0;
710 if (id.type == SILC_ID_CLIENT)
711 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
713 if (id.type == SILC_ID_SERVER)
714 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
716 if (id.type == SILC_ID_CHANNEL)
717 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
719 query->ids[query->ids_count].id_type = id.type;
724 /* Get the max count of reply messages allowed */
725 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
726 if (tmp && tmp_len == sizeof(SilcUInt32))
727 SILC_GET32_MSB(query->reply_count, tmp);
731 query->parsed = TRUE;
734 if (!parse_only && query->nickname) {
735 switch (query->querycmd) {
736 case SILC_COMMAND_WHOIS:
737 case SILC_COMMAND_IDENTIFY:
738 /* Check server name. If we are open server and don't yet have
739 connection to remote router, create it now. */
740 if (query->nick_server[0] && server->config->dynamic_server &&
742 /* If primary router is specified, use that. Otherwise connect
743 to the server in nick@server string. */
744 SilcServerConfigRouter *router;
745 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
746 SILC_CONN_SERVER : SILC_CONN_ROUTER);
748 router = silc_server_config_get_primary_router(server);
749 if (router && server->standalone) {
750 /* Create connection to primary router */
751 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
752 router->host, router->port));
753 query->dynamic_prim = TRUE;
754 silc_server_create_connection(server, FALSE, TRUE,
755 router->host, router->port,
756 silc_server_query_connected, query);
758 } else if (!silc_server_num_sockets_by_remote(server,
762 /* Create connection and handle the query after connection */
763 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
764 query->nick_server, 706));
765 silc_server_create_connection(server, FALSE, TRUE,
766 query->nick_server, 706,
767 silc_server_query_connected, query);
774 /* Start processing the query information */
776 silc_server_query_process(server, query, TRUE);
781 /* Context for holding clients searched by public key. */
783 SilcClientEntry **clients;
784 SilcUInt32 *clients_count;
786 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
788 /* SKR find callbcak */
790 static void silc_server_query_skr_callback(SilcSKR skr,
792 SilcSKRStatus status,
796 SilcServerPublicKeyUser uc = context;
800 SILC_LOG_DEBUG(("Found %d keys", silc_dlist_count(keys)));
801 (*uc->clients) = silc_realloc((*uc->clients),
802 sizeof((**uc->clients)) *
803 ((*uc->clients_count) +
804 silc_dlist_count(keys)));
806 silc_dlist_start(keys);
807 while ((key = silc_dlist_get(keys)))
808 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
811 silc_dlist_uninit(keys);
814 silc_skr_find_free(find);
817 /* If clients are set, limit the found clients using the attributes in
818 the query. If clients are not set, try to find some clients using
821 void silc_server_query_check_attributes(SilcServer server,
822 SilcServerQuery query,
823 SilcClientEntry **clients,
824 SilcUInt32 *clients_count) {
825 SilcClientEntry entry;
826 SilcAttributePayload attr;
827 SilcAttribute attribute;
828 SilcAttributeObjPk pk;
829 SilcPublicKey publickey, cmp_pubkey;
831 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
834 /* If no clients were found, we only check the attributes
835 if the user wasn't searching for nickname/ids */
838 if (query->nickname[0] || query->ids_count)
842 silc_dlist_start(query->attrs);
843 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
844 attribute = silc_attribute_get_attribute(attr);
847 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
848 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
850 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
853 if (!strcmp(pk.type, "silc-rsa"))
854 type = SILC_PKCS_SILC;
855 else if (!strcmp(pk.type, "ssh-rsa"))
856 type = SILC_PKCS_SSH2;
857 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
858 type = SILC_PKCS_X509V3;
859 else if (!strcmp(pk.type, "pgp-sign-rsa"))
860 type = SILC_PKCS_OPENPGP;
864 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
870 search_pubkey = TRUE;
872 /* If no clients were set on calling this function, we just search
873 for clients, otherwise we try to limit the clients. */
875 SilcServerPublicKeyUserStruct usercontext;
878 usercontext.clients = clients;
879 usercontext.clients_count = clients_count;
880 usercontext.found = FALSE;
882 find = silc_skr_find_alloc();
886 silc_skr_find_set_public_key(find, publickey);
887 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
888 silc_skr_find(server->repository, server->schedule,
889 find, silc_server_query_skr_callback, &usercontext);
891 if (usercontext.found == TRUE)
894 for (i = 0; i < *clients_count; i++) {
895 entry = (*clients)[i];
897 if (!entry->data.public_key)
900 if (silc_server_get_public_key_by_client(server, entry,
902 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
908 (*clients)[i] = NULL;
913 silc_pkcs_public_key_free(publickey);
918 if (!found && !query->nickname[0] && !query->ids)
919 silc_server_query_add_error(server, query, 2, 0,
921 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
922 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
925 /* Processes the parsed query. This does the actual finding of the
926 queried information and prepares for sending reply to the original
927 sender of the query command. */
929 void silc_server_query_process(SilcServer server, SilcServerQuery query,
932 SilcServerCommandContext cmd = query->cmd;
933 SilcIDListData idata = silc_packet_get_context(cmd->sock);
934 SilcBool check_global = FALSE;
936 SilcClientEntry *clients = NULL, client_entry;
937 SilcChannelEntry *channels = NULL;
938 SilcServerEntry *servers = NULL;
939 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
943 silc_server_query_free(query);
947 SILC_LOG_DEBUG(("Processing %s query",
948 silc_get_command_name(query->querycmd)));
950 /* Check global lists if query is coming from client or we are not
951 normal server (we know global information). */
952 if (idata->conn_type == SILC_CONN_CLIENT)
954 else if (server->server_type != SILC_SERVER)
957 if (query->nickname[0]) {
958 /* Get all clients matching nickname from local list */
959 if (!silc_idlist_get_clients_by_hash(server->local_list,
961 query->nick_server[0] ?
962 query->nick_server : NULL,
964 &clients, &clients_count))
965 silc_idlist_get_clients_by_nickname(server->local_list,
967 query->nick_server[0] ?
968 query->nick_server : NULL,
969 &clients, &clients_count);
971 /* Check global list as well */
973 if (!silc_idlist_get_clients_by_hash(server->global_list,
975 query->nick_server[0] ?
976 query->nick_server : NULL,
978 &clients, &clients_count))
979 silc_idlist_get_clients_by_nickname(server->global_list,
981 query->nick_server[0] ?
982 query->nick_server : NULL,
983 &clients, &clients_count);
987 silc_server_query_add_error(server, query, 1, 1,
988 SILC_STATUS_ERR_NO_SUCH_NICK);
991 if (query->server_name) {
992 /* Find server by name */
993 entry = silc_idlist_find_server_by_name(server->local_list,
994 query->server_name, TRUE, NULL);
995 if (!entry && check_global)
996 entry = silc_idlist_find_server_by_name(server->global_list,
997 query->server_name, TRUE, NULL);
999 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
1000 servers[servers_count++] = (SilcServerEntry)entry;
1004 silc_server_query_add_error(server, query, 1, 2,
1005 SILC_STATUS_ERR_NO_SUCH_SERVER);
1008 if (query->channel_name) {
1009 /* Find channel by name */
1010 entry = silc_idlist_find_channel_by_name(server->local_list,
1011 query->channel_name, NULL);
1012 if (!entry && check_global)
1013 entry = silc_idlist_find_channel_by_name(server->global_list,
1014 query->channel_name, NULL);
1016 channels = silc_realloc(channels, sizeof(*channels) *
1017 (channels_count + 1));
1018 channels[channels_count++] = (SilcChannelEntry)entry;
1022 silc_server_query_add_error(server, query, 1, 3,
1023 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1026 if (query->ids_count) {
1027 /* Find entries by the queried IDs */
1028 for (i = 0; i < query->ids_count; i++) {
1029 void *id = query->ids[i].id;
1033 switch (query->ids[i].id_type) {
1035 case SILC_ID_CLIENT:
1036 /* Get client entry */
1037 entry = silc_idlist_find_client_by_id(server->local_list,
1039 if (!entry && check_global)
1040 entry = silc_idlist_find_client_by_id(server->global_list,
1043 silc_server_query_add_error(server, query, 0, i,
1044 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1048 clients = silc_realloc(clients, sizeof(*clients) *
1049 (clients_count + 1));
1050 clients[clients_count++] = (SilcClientEntry)entry;
1053 case SILC_ID_SERVER:
1054 /* Get server entry */
1055 entry = silc_idlist_find_server_by_id(server->local_list,
1057 if (!entry && check_global)
1058 entry = silc_idlist_find_server_by_id(server->global_list,
1061 silc_server_query_add_error(server, query, 0, i,
1062 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1066 servers = silc_realloc(servers, sizeof(*servers) *
1067 (servers_count + 1));
1068 servers[servers_count++] = (SilcServerEntry)entry;
1071 case SILC_ID_CHANNEL:
1072 /* Get channel entry */
1073 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1074 if (!entry && check_global)
1075 entry = silc_idlist_find_channel_by_id(server->global_list, id,
1078 silc_server_query_add_error(server, query, 0, i,
1079 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1083 channels = silc_realloc(channels, sizeof(*channels) *
1084 (channels_count + 1));
1085 channels[channels_count++] = (SilcChannelEntry)entry;
1094 /* Check the attributes to narrow down the search by using them. */
1096 silc_server_query_check_attributes(server, query, &clients,
1099 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1100 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1101 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1103 /* If nothing was found, then just send the errors */
1104 if (!clients && !channels && !servers) {
1105 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1109 /* If caller does not want us to resolve anything (has resolved already)
1110 then just continue with sending the reply */
1112 silc_server_query_send_reply(server, query, clients, clients_count,
1113 servers, servers_count, channels,
1117 silc_free(channels);
1121 /* Now process all found information and if necessary do some more
1123 switch (query->querycmd) {
1125 case SILC_COMMAND_WHOIS:
1126 for (i = 0; i < clients_count; i++) {
1127 client_entry = clients[i];
1129 /* Check if cannot query this anyway, so take next one */
1130 if (!client_entry ||
1131 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1134 /* If Requested Attributes is set then we always resolve the client
1135 information, if not then check whether the entry is complete or not
1136 and decide whether we need to resolve or not. */
1137 if (!query->attrs) {
1139 /* Even if nickname and stuff are present, we may need to resolve
1141 if (client_entry->nickname && client_entry->username &&
1142 client_entry->userinfo) {
1143 /* Check if cannot query this anyway, so take next one */
1144 if (!client_entry->router)
1147 /* If we are router, client is local to us, or client is on channel
1148 we do not need to resolve the client information. */
1149 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1150 || silc_hash_table_count(client_entry->channels) ||
1156 /* Remove the NOATTR status periodically */
1157 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1158 client_entry->updated + 600 < time(NULL))
1159 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1161 /* When requested attributes is present and local client is detached
1162 we cannot send the command to the client, we'll reply on behalf of
1163 the client instead. */
1164 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1165 (client_entry->mode & SILC_UMODE_DETACHED ||
1166 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1169 /* If attributes are present in query, and in the entry and we have
1170 done resolvings already we don't need to resolve anymore */
1171 if (query->resolved && query->attrs && client_entry->attrs)
1174 /* Resolve the detailed client information. If client is local we
1175 know that attributes were present and we will resolve directly
1176 from the client. Otherwise resolve from client's owner. */
1177 silc_server_query_resolve(server, query,
1178 (SILC_IS_LOCAL(client_entry) ?
1179 client_entry->connection :
1180 client_entry->router->connection),
1185 case SILC_COMMAND_WHOWAS:
1186 for (i = 0; i < clients_count; i++) {
1187 client_entry = clients[i];
1189 /* Check if cannot query this anyway, so take next one */
1190 if (!client_entry || !client_entry->router ||
1191 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1194 /* If both nickname and username are present no resolving is needed */
1195 if (client_entry->nickname && client_entry->username)
1198 /* Resolve the detailed client information */
1199 silc_server_query_resolve(server, query,
1200 client_entry->router->connection,
1205 case SILC_COMMAND_IDENTIFY:
1206 for (i = 0; i < clients_count; i++) {
1207 client_entry = clients[i];
1209 /* Check if cannot query this anyway, so take next one */
1210 if (!client_entry || !client_entry->router ||
1211 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1214 /* Even if nickname is present, we may need to resolve the entry */
1215 if (client_entry->nickname) {
1217 /* If we are router, client is local to us, or client is on channel
1218 we do not need to resolve the client information. */
1219 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1220 || silc_hash_table_count(client_entry->channels) ||
1225 /* Resolve the detailed client information */
1226 silc_server_query_resolve(server, query,
1227 client_entry->router->connection,
1233 if (!query->queries_count)
1234 /* If we didn't have to do any resolving, continue with sending the
1235 command reply to the original sender. */
1236 silc_server_query_send_reply(server, query, clients, clients_count,
1237 servers, servers_count, channels,
1240 /* Now actually send the resolvings we gathered earlier */
1241 silc_server_query_resolve(server, query, NULL, NULL);
1245 silc_free(channels);
1248 /* Resolve the detailed information for the `client_entry'. Only client
1249 information needs to be resolved for being incomplete. Each incomplete
1250 client entry calls this function to do the resolving. */
1252 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1253 SilcPacketStream sock,
1254 SilcClientEntry client_entry)
1256 SilcServerCommandContext cmd = query->cmd;
1257 SilcServerQueryList r = NULL;
1264 if (!sock && client_entry)
1267 /* If arguments are NULL we will now actually send the resolvings
1268 that earlier has been gathered by calling this function. */
1269 if (!sock && !client_entry) {
1272 SILC_LOG_DEBUG(("Sending the resolvings"));
1274 /* WHOWAS resolving has been done at the same time this function
1275 was called to add the resolving for WHOWAS, so just return. */
1276 if (query->querycmd == SILC_COMMAND_WHOWAS)
1279 for (i = 0; i < query->querylist_count; i++) {
1280 r = &query->querylist[i];
1282 /* If Requested Attributes were present put them to this resolving */
1283 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1285 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1286 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1287 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1289 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1291 r->arg[r->argc] = silc_memdup(tmp, len);
1292 r->arg_lens[r->argc] = len;
1293 r->arg_types[r->argc] = 3;
1298 server->stat.commands_sent++;
1300 /* Send WHOIS command */
1301 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1302 r->argc, r->arg, r->arg_lens,
1303 r->arg_types, r->ident);
1304 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1305 res_cmd->data, silc_buffer_len(res_cmd));
1306 silc_buffer_free(res_cmd);
1308 /* Reprocess this packet after received reply */
1309 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1311 silc_server_query_resolve_reply,
1313 query->queries_left++;
1316 /* Cleanup this temporary context */
1317 for (i = 0; i < query->querylist_count; i++) {
1319 for (k = 0; k < query->querylist[i].argc; k++)
1320 silc_free(query->querylist[i].arg[k]);
1321 silc_free(query->querylist[i].arg);
1322 silc_free(query->querylist[i].arg_lens);
1323 silc_free(query->querylist[i].arg_types);
1325 silc_free(query->querylist);
1326 query->querylist = NULL;
1327 query->querylist_count = 0;
1331 SILC_LOG_DEBUG(("Resolving client information"));
1333 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1334 /* The entry is being resolved by some other external query already.
1335 Attach to that query instead of resolving again. */
1336 ident = client_entry->resolve_cmd_ident;
1337 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1338 silc_server_query_resolve_reply, query))
1339 query->queries_left++;
1341 /* This entry will be resolved */
1342 ident = ++server->cmd_ident;
1344 switch (query->querycmd) {
1346 case SILC_COMMAND_WHOIS:
1347 case SILC_COMMAND_IDENTIFY:
1348 /* Take existing query context if exist for this connection */
1349 for (i = 0; i < query->querylist_count; i++)
1350 if (query->querylist[i].sock == sock) {
1351 r = &query->querylist[i];
1356 /* Allocate new temp query list context */
1357 query->querylist = silc_realloc(query->querylist,
1358 sizeof(*query->querylist) *
1359 (query->querylist_count + 1));
1360 r = &query->querylist[query->querylist_count];
1361 query->querylist_count++;
1362 memset(r, 0, sizeof(*r));
1365 if (SILC_IS_LOCAL(client_entry))
1370 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1371 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1372 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1374 /* Add the client entry to be resolved */
1375 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1376 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1377 r->arg_lens[r->argc] = silc_buffer_len(idp);
1378 r->arg_types[r->argc] = r->argc + 4;
1380 silc_buffer_free(idp);
1384 case SILC_COMMAND_WHOWAS:
1385 /* We must send WHOWAS command since it's the only the way of
1386 resolving clients that are not present in the network anymore. */
1387 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1388 1, query->nickname, strlen(query->nickname));
1389 if (silc_server_command_pending(server, query->querycmd, ident,
1390 silc_server_query_resolve_reply, query))
1391 query->queries_left++;
1396 /* Mark the entry as being resolved */
1397 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1398 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1399 client_entry->resolve_cmd_ident = ident;
1400 client_entry->updated = time(NULL);
1402 /* Save the queried ID, which we will reprocess after we get this and
1403 all other queries back. */
1404 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1405 (query->queries_count + 1));
1406 if (query->queries) {
1407 i = query->queries_count;
1408 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1409 query->queries[i].id_type = SILC_ID_CLIENT;
1410 query->queries[i].ident = ident;
1411 query->queries_count++;
1415 /* Reply callback called after one resolving has been completed. If
1416 all resolvings has been received then we will continue with sending
1417 the command reply to the original sender of the query. */
1419 void silc_server_query_resolve_reply(void *context, void *reply)
1421 SilcServerQuery query = context;
1422 SilcServer server = query->cmd->server;
1423 SilcServerCommandReplyContext cmdr = reply;
1424 SilcUInt16 ident = cmdr->ident;
1425 SilcStatus error = SILC_STATUS_OK;
1426 SilcServerQueryID id = NULL;
1427 SilcClientEntry client_entry;
1430 /* One less query left */
1431 query->queries_left--;
1433 silc_command_get_status(cmdr->payload, NULL, &error);
1434 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1435 query->queries_left, error));
1437 /* If no error then skip to other stuff */
1438 if (error == SILC_STATUS_OK)
1441 /* Error occurred during resolving */
1443 /* Find the resolved client ID */
1444 for (i = 0; i < query->queries_count; i++) {
1445 if (query->queries[i].ident != ident)
1448 id = &query->queries[i];
1450 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1452 /* If timeout occurred for local entry when resolving attributes
1453 mark that this client doesn't support attributes in WHOIS. This
1454 assures we won't send the request again to the client. */
1455 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1456 client_entry = silc_idlist_find_client_by_id(server->local_list,
1457 id->id, TRUE, NULL);
1458 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1459 silc_id_render(id->id, SILC_ID_CLIENT)));
1460 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1461 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1462 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1467 /* Remove the RESOLVING status from the client entry */
1468 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1469 client_entry = silc_idlist_find_client_by_id(server->local_list,
1470 id->id, TRUE, NULL);
1472 client_entry = silc_idlist_find_client_by_id(server->global_list,
1473 id->id, TRUE, NULL);
1475 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1482 /* If there are queries left then wait for them */
1483 if (query->queries_left)
1486 SILC_LOG_DEBUG(("Reprocess the query"));
1488 /* If the original command caller has gone away, just stop. */
1489 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1490 SILC_LOG_DEBUG(("Original command caller vanished"));
1491 silc_server_query_free(query);
1495 /* We have received all queries. Now re-search all information required
1496 to complete this query. Reason we cannot save the values found in
1497 the first search is that SilcClientEntry, SilcServerEntry and
1498 SilcChannelEntry pointers may become invalid while we were waiting
1499 for these resolvings. */
1500 silc_server_query_process(server, query, FALSE);
1503 /* Send the reply to the original query. If arguments are NULL then this
1504 sends only the errors that has occurred during the processing of the
1505 query. This sends the errors always after sending all the found
1506 information. The query is over after this function returns and the
1507 `query' will become invalid. This is called only after all informations
1508 has been resolved. This means that if something is not found or is
1509 incomplete in this function we were unable to resolve the information
1510 or it does not exist at all. */
1512 void silc_server_query_send_reply(SilcServer server,
1513 SilcServerQuery query,
1514 SilcClientEntry *clients,
1515 SilcUInt32 clients_count,
1516 SilcServerEntry *servers,
1517 SilcUInt32 servers_count,
1518 SilcChannelEntry *channels,
1519 SilcUInt32 channels_count)
1521 SilcServerCommandContext cmd = query->cmd;
1522 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1523 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1529 int i, k, valid_count;
1530 char nh[384], uh[384];
1531 SilcBool sent_reply = FALSE;
1533 SILC_LOG_DEBUG(("Sending reply to query"));
1534 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1535 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1536 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1537 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1539 status = SILC_STATUS_OK;
1542 if (clients_count) {
1543 SilcClientEntry entry;
1544 SilcPacketStream hsock;
1546 /* Mark all invalid entries */
1547 for (i = 0, valid_count = 0; i < clients_count; i++) {
1552 switch (query->querycmd) {
1553 case SILC_COMMAND_WHOIS:
1554 if (!entry->nickname || !entry->username || !entry->userinfo ||
1555 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1556 /* When querying by ID, every "unfound" entry must cause error */
1558 silc_server_query_add_error_id(server, query,
1559 SILC_STATUS_ERR_TIMEDOUT,
1560 entry->id, SILC_ID_CLIENT);
1566 case SILC_COMMAND_IDENTIFY:
1567 if (!entry->nickname ||
1568 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1569 /* When querying by ID, every "unfound" entry must cause error */
1571 silc_server_query_add_error_id(server, query,
1572 SILC_STATUS_ERR_TIMEDOUT,
1573 entry->id, SILC_ID_CLIENT);
1579 case SILC_COMMAND_WHOWAS:
1580 if (!entry->nickname || !entry->username ||
1581 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1590 /* Start processing found clients */
1591 status = SILC_STATUS_OK;
1592 if (valid_count > 1)
1593 status = SILC_STATUS_LIST_START;
1595 /* Now do the sending of valid entries */
1597 for (i = 0; i < clients_count && valid_count; i++) {
1603 status = SILC_STATUS_LIST_ITEM;
1604 if (valid_count > 1 && k == valid_count - 1
1605 && !servers_count && !channels_count && !query->errors_count)
1606 status = SILC_STATUS_LIST_END;
1607 if (query->reply_count && k - 1 == query->reply_count)
1608 status = SILC_STATUS_LIST_END;
1610 SILC_LOG_DEBUG(("%s: client %s",
1611 (status == SILC_STATUS_OK ? " OK" :
1612 status == SILC_STATUS_LIST_START ? "START" :
1613 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1614 status == SILC_STATUS_LIST_END ? " END" :
1615 " : "), entry->nickname));
1617 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1618 memset(nh, 0, sizeof(nh));
1620 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1621 if (!strchr(entry->nickname, '@')) {
1622 silc_strncat(nh, sizeof(nh), "@", 1);
1623 if (entry->servername) {
1624 silc_strncat(nh, sizeof(nh), entry->servername,
1625 strlen(entry->servername));
1627 len = entry->router ? strlen(entry->router->server_name) :
1628 strlen(server->server_name);
1629 silc_strncat(nh, sizeof(nh), entry->router ?
1630 entry->router->server_name :
1631 server->server_name, len);
1635 switch (query->querycmd) {
1637 case SILC_COMMAND_WHOIS:
1639 unsigned char idle[4], mode[4];
1640 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1641 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1643 memset(fempty, 0, sizeof(fempty));
1644 memset(idle, 0, sizeof(idle));
1645 memset(uh, 0, sizeof(uh));
1647 silc_strncat(uh, sizeof(uh), entry->username,
1648 strlen(entry->username));
1649 if (!strchr(entry->username, '@') && entry->connection) {
1650 hsock = entry->connection;
1651 silc_strncat(uh, sizeof(uh), "@", 1);
1652 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1653 NULL, (const char **)&tmp2, NULL, NULL);
1654 silc_strncat(uh, sizeof(uh), tmp2, strlen(tmp2));
1657 if (idata->conn_type == SILC_CONN_CLIENT)
1659 silc_server_get_client_channel_list(server, entry, FALSE,
1660 FALSE, &umode_list);
1663 silc_server_get_client_channel_list(server, entry, TRUE,
1666 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1667 fingerprint = entry->data.fingerprint;
1671 SILC_PUT32_MSB(entry->mode, mode);
1672 if (entry->connection)
1673 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1675 /* If Requested Attribute were present, and we do not have the
1676 attributes we will reply to them on behalf of the client. */
1679 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1680 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1681 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1682 entry->attrs_len = len;
1683 silc_buffer_free(tmpattrs);
1685 attrs = entry->attrs;
1686 len = entry->attrs_len;
1689 /* Send command reply */
1690 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1691 status, 0, ident, 10,
1692 2, idp->data, silc_buffer_len(idp),
1696 strlen(entry->userinfo),
1697 6, channels ? channels->data : NULL,
1698 channels ? silc_buffer_len(channels)
1703 fingerprint ? 20 : 0,
1704 10, umode_list ? umode_list->data :
1706 silc_buffer_len(umode_list) :
1711 /* For now we always delete Requested Attributes, unless the client
1712 is detached, in which case we don't want to reconstruct the
1713 same data everytime */
1714 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1715 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1716 silc_free(entry->attrs);
1717 entry->attrs = NULL;
1721 silc_buffer_free(channels);
1723 silc_buffer_free(umode_list);
1729 case SILC_COMMAND_IDENTIFY:
1730 if (!entry->username) {
1731 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1732 status, 0, ident, 2,
1733 2, idp->data, silc_buffer_len(idp),
1737 memset(uh, 0, sizeof(uh));
1738 silc_strncat(uh, sizeof(uh), entry->username,
1739 strlen(entry->username));
1740 if (!strchr(entry->username, '@') && entry->connection) {
1741 hsock = entry->connection;
1742 silc_strncat(uh, sizeof(uh), "@", 1);
1743 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1744 NULL, (const char **)&tmp2,
1746 silc_strncat(uh, sizeof(uh), tmp2, strlen(tmp2));
1749 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1750 status, 0, ident, 3,
1751 2, idp->data, silc_buffer_len(idp),
1758 case SILC_COMMAND_WHOWAS:
1759 memset(uh, 0, sizeof(uh));
1760 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1761 if (!strchr(entry->username, '@'))
1762 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1764 /* Send command reply */
1765 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1766 status, 0, ident, 4,
1767 2, idp->data, silc_buffer_len(idp),
1772 strlen(entry->userinfo) : 0);
1777 silc_buffer_free(idp);
1779 if (status == SILC_STATUS_LIST_END)
1785 /* Not one valid entry was found, send error. If nickname was used
1786 in query send error based on that, otherwise the query->errors
1787 already includes proper errors. */
1788 if (query->nickname[0] || (!query->ids && query->attrs))
1789 silc_server_query_add_error(server, query, 1, 1,
1790 SILC_STATUS_ERR_NO_SUCH_NICK);
1792 /* Make sure some error is sent */
1793 if (!query->errors_count && !servers_count && !channels_count)
1794 silc_server_query_add_error(server, query, 2, 0,
1795 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1800 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1801 SilcServerEntry entry;
1803 if (status == SILC_STATUS_OK && servers_count > 1)
1804 status = SILC_STATUS_LIST_START;
1807 for (i = 0; i < servers_count; i++) {
1811 status = SILC_STATUS_LIST_ITEM;
1812 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1813 !query->errors_count)
1814 status = SILC_STATUS_LIST_END;
1815 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1816 !query->errors_count)
1817 status = SILC_STATUS_LIST_END;
1818 if (query->reply_count && k - 1 == query->reply_count)
1819 status = SILC_STATUS_LIST_END;
1821 SILC_LOG_DEBUG(("%s: server %s",
1822 (status == SILC_STATUS_OK ? " OK" :
1823 status == SILC_STATUS_LIST_START ? "START" :
1824 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1825 status == SILC_STATUS_LIST_END ? " END" :
1827 entry->server_name ? entry->server_name : ""));
1829 /* Send command reply */
1830 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1831 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1832 status, 0, ident, 2,
1833 2, idp->data, silc_buffer_len(idp),
1834 3, entry->server_name,
1835 entry->server_name ?
1836 strlen(entry->server_name) : 0);
1837 silc_buffer_free(idp);
1840 if (status == SILC_STATUS_LIST_END)
1847 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1848 SilcChannelEntry entry;
1850 if (status == SILC_STATUS_OK && channels_count > 1)
1851 status = SILC_STATUS_LIST_START;
1854 for (i = 0; i < channels_count; i++) {
1855 entry = channels[i];
1858 status = SILC_STATUS_LIST_ITEM;
1859 if (channels_count == 1 && status != SILC_STATUS_OK &&
1860 !query->errors_count)
1861 status = SILC_STATUS_LIST_END;
1862 if (channels_count > 1 && k == channels_count - 1 &&
1863 !query->errors_count)
1864 status = SILC_STATUS_LIST_END;
1865 if (query->reply_count && k - 1 == query->reply_count)
1866 status = SILC_STATUS_LIST_END;
1868 SILC_LOG_DEBUG(("%s: channel %s",
1869 (status == SILC_STATUS_OK ? " OK" :
1870 status == SILC_STATUS_LIST_START ? "START" :
1871 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1872 status == SILC_STATUS_LIST_END ? " END" :
1874 entry->channel_name ? entry->channel_name : ""));
1876 /* Send command reply */
1877 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1878 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1879 status, 0, ident, 2,
1880 2, idp->data, silc_buffer_len(idp),
1881 3, entry->channel_name,
1882 entry->channel_name ?
1883 strlen(entry->channel_name) : 0);
1884 silc_buffer_free(idp);
1887 if (status == SILC_STATUS_LIST_END)
1894 if (query->errors_count) {
1897 if (status == SILC_STATUS_OK && query->errors_count > 1)
1898 status = SILC_STATUS_LIST_START;
1901 for (i = 0; i < query->errors_count; i++) {
1904 /* Take error argument */
1905 if (query->errors[i].type == 1) {
1906 /* Take from sent arguments */
1908 tmp = silc_argument_get_arg_type(cmd->args,
1909 query->errors[i].index, &len);
1911 } else if (query->errors[i].type == 2) {
1916 } else if (!query->errors[i].id) {
1917 /* Take from query->ids */
1919 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1920 query->ids[query->errors[k].index].id_type);
1922 len = silc_buffer_len(idp);
1925 /* Take added ID. */
1926 idp = silc_id_payload_encode(query->errors[i].id,
1927 query->errors[k].id_type);
1929 len = silc_buffer_len(idp);
1934 status = SILC_STATUS_LIST_ITEM;
1935 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1936 status = SILC_STATUS_LIST_END;
1937 if (query->errors_count > 1 && k == query->errors_count - 1)
1938 status = SILC_STATUS_LIST_END;
1939 if (query->reply_count && k - 1 == query->reply_count)
1940 status = SILC_STATUS_LIST_END;
1942 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1943 (status == SILC_STATUS_OK ? " OK" :
1944 status == SILC_STATUS_LIST_START ? "START" :
1945 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1946 status == SILC_STATUS_LIST_END ? " END" :
1948 silc_get_status_message(query->errors[i].error),
1949 query->errors[i].error));
1951 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1952 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1954 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1955 (status == SILC_STATUS_OK ?
1956 query->errors[i].error : status),
1957 (status == SILC_STATUS_OK ?
1958 0 : query->errors[i].error), ident, 2,
1964 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1965 (status == SILC_STATUS_OK ?
1966 query->errors[i].error : status),
1967 (status == SILC_STATUS_OK ?
1968 0 : query->errors[i].error), ident, 1,
1971 silc_buffer_free(idp);
1974 if (status == SILC_STATUS_LIST_END)
1981 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1984 silc_server_query_free(query);
1987 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1988 of the client since we were unable to resolve them from the client.
1989 Either client does not support Requested Attributes or isn't replying
1990 to them like it should. */
1992 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1993 SilcServerQuery query,
1994 SilcClientEntry client_entry)
1996 SilcBuffer buffer = NULL;
1997 SilcAttribute attribute;
1998 SilcAttributePayload attr;
1999 SilcAttributeObjPk pk;
2000 SilcAttributeObjService service;
2002 unsigned char sign[2048 + 1];
2003 SilcUInt32 sign_len;
2005 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
2007 /* Go through all requested attributes */
2008 silc_dlist_start(query->attrs);
2009 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
2010 attribute = silc_attribute_get_attribute(attr);
2011 switch (attribute) {
2013 case SILC_ATTRIBUTE_SERVICE:
2014 /* Put SERVICE. Put only SILC service. */
2015 memset(&service, 0, sizeof(service));
2016 service.port = (server->config->server_info->primary ?
2017 server->config->server_info->primary->port : SILC_PORT);
2018 silc_strncat(service.address, sizeof(service.address),
2019 server->server_name, strlen(server->server_name));
2020 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2021 if (client_entry->connection)
2022 service.idle = time(NULL) - client_entry->data.last_receive;
2023 buffer = silc_attribute_payload_encode(buffer, attribute,
2024 SILC_ATTRIBUTE_FLAG_VALID,
2025 &service, sizeof(service));
2030 case SILC_ATTRIBUTE_STATUS_MOOD:
2031 /* Put STATUS_MOOD */
2032 buffer = silc_attribute_payload_encode(buffer, attribute,
2033 SILC_ATTRIBUTE_FLAG_VALID,
2035 SILC_ATTRIBUTE_MOOD_NORMAL,
2036 sizeof(SilcUInt32));
2041 case SILC_ATTRIBUTE_STATUS_FREETEXT:
2042 /* Put STATUS_FREETEXT. We just tell in the message that we are
2043 replying on behalf of the client. */
2045 "This information was provided by the server on behalf of the user";
2046 buffer = silc_attribute_payload_encode(buffer, attribute,
2047 SILC_ATTRIBUTE_FLAG_VALID,
2053 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2054 /* Put PREFERRED_CONTACT */
2055 buffer = silc_attribute_payload_encode(buffer, attribute,
2056 SILC_ATTRIBUTE_FLAG_VALID,
2058 SILC_ATTRIBUTE_CONTACT_CHAT,
2059 sizeof(SilcUInt32));
2064 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2065 /* Put USER_PUBLIC_KEY */
2066 if (client_entry->data.public_key) {
2067 pk.type = "silc-rsa";
2068 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2070 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2071 SILC_ATTRIBUTE_FLAG_VALID :
2072 SILC_ATTRIBUTE_FLAG_INVALID,
2080 /* No public key available */
2081 buffer = silc_attribute_payload_encode(buffer, attribute,
2082 SILC_ATTRIBUTE_FLAG_INVALID,
2089 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2090 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2091 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2094 /* For other attributes we cannot reply so mark it invalid */
2095 buffer = silc_attribute_payload_encode(buffer, attribute,
2096 SILC_ATTRIBUTE_FLAG_INVALID,
2104 /* Always put our public key. This assures that we send at least
2105 something valid back always. */
2106 pk.type = "silc-rsa";
2107 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2108 buffer = silc_attribute_payload_encode(buffer,
2109 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2110 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2111 SILC_ATTRIBUTE_FLAG_INVALID,
2117 /* Finally compute the digital signature of all the data we provided
2118 as an indication that we provided rightfull information, and this
2119 also authenticates our public key. */
2120 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2122 silc_pkcs_sign(server->private_key, buffer->data,
2123 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2124 TRUE, server->sha1hash)) {
2127 pk.data_len = sign_len;
2129 silc_attribute_payload_encode(buffer,
2130 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2131 SILC_ATTRIBUTE_FLAG_VALID,
2140 /* Find client by the Client ID indicated by the `client_id', and if not
2141 found then query it by using WHOIS command. The client information
2142 is also resolved if the cached information is incomplete or if the
2143 `always_resolve' is set to TRUE. The indication whether requested
2144 client was being resolved is saved into `resolved'. If the client
2145 is not being resolved its entry is returned by this function. NULL
2146 is returned if client is resolved. */
2148 SilcClientEntry silc_server_query_client(SilcServer server,
2149 const SilcClientID *client_id,
2150 SilcBool always_resolve,
2153 SilcClientEntry client;
2155 SILC_LOG_DEBUG(("Resolving client by client ID"));
2160 client = silc_idlist_find_client_by_id(server->local_list,
2161 (SilcClientID *)client_id,
2164 client = silc_idlist_find_client_by_id(server->global_list,
2165 (SilcClientID *)client_id,
2167 if (!client && server->server_type == SILC_ROUTER)
2171 if (!client && server->standalone)
2174 if (!client || !client->nickname || !client->username ||
2176 SilcBuffer buffer, idp;
2179 server->stat.commands_sent++;
2182 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2183 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2184 client->resolve_cmd_ident = ++server->cmd_ident;
2187 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2188 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2189 server->cmd_ident, 1,
2191 silc_buffer_len(idp));
2192 silc_server_packet_send(server,
2193 client && client->router ? client->router->connection :
2194 SILC_PRIMARY_ROUTE(server),
2195 SILC_PACKET_COMMAND, 0,
2196 buffer->data, silc_buffer_len(buffer));
2197 silc_buffer_free(idp);
2198 silc_buffer_free(buffer);