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));
243 query->querycmd = querycmd;
244 query->cmd = silc_server_command_dup(cmd);
245 query->router = SILC_PRIMARY_ROUTE(server);
251 case SILC_COMMAND_WHOIS:
252 /* If we are normal server and query contains nickname OR query
253 doesn't contain nickname or ids BUT attributes, send it to the
255 if (server->server_type != SILC_ROUTER && !server->standalone &&
256 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
257 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
258 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
259 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
260 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
261 if (!silc_server_query_parse(server, query, TRUE))
263 silc_server_query_send_router(server, query);
268 case SILC_COMMAND_WHOWAS:
269 /* WHOWAS query is always sent to router if we are normal server */
270 if (server->server_type == SILC_SERVER && !server->standalone &&
271 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
272 silc_server_query_send_router(server, query);
277 case SILC_COMMAND_IDENTIFY:
278 /* If we are normal server and query does not contain IDs, send it
279 directly to router (it contains nickname, server name or channel
281 if (server->server_type == SILC_SERVER && !server->standalone &&
282 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
283 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
284 if (!silc_server_query_parse(server, query, TRUE))
286 silc_server_query_send_router(server, query);
292 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
293 silc_server_query_free(query);
297 /* Now parse the request */
298 silc_server_query_parse(server, query, FALSE);
303 /* Remote server connected callback. */
305 void silc_server_query_connected(SilcServer server,
306 SilcServerEntry server_entry,
309 SilcServerQuery query = context;
312 /* Connecting failed */
313 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
314 SILC_CONN_SERVER : SILC_CONN_ROUTER);
316 if (query->dynamic_prim /* && @serv != prim.host.name */ &&
317 !silc_server_num_sockets_by_remote(server, query->nick_server,
318 query->nick_server, 706, type)) {
319 /* Connection attempt to primary router failed, now try to the one
320 specified in nick@server. */
321 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
322 706, silc_server_query_connected,
324 query->dynamic_prim = FALSE;
328 /* Process the query after failed connect. This will send error back
329 because such nick was not found. */
330 SILC_LOG_DEBUG(("Process query, connecting failed"));
331 silc_server_query_process(server, query, TRUE);
335 /* Reprocess the query */
336 SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
337 server_entry->server_name));
338 query->router = server_entry->data.sconn->sock;
339 silc_server_query_command(server, query->querycmd, query->cmd, query);
342 /* Send the received query to our primary router since we could not
343 handle the query directly. We will reprocess the query after our
344 router replies back. */
346 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
349 SilcUInt16 old_ident;
351 SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
355 server->stat.commands_sent++;
357 /* Send WHOIS command to our router */
358 old_ident = silc_command_get_ident(query->cmd->payload);
359 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
360 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
361 silc_server_packet_send(server, query->router,
362 SILC_PACKET_COMMAND, 0,
363 tmpbuf->data, silc_buffer_len(tmpbuf));
364 silc_command_set_ident(query->cmd->payload, old_ident);
365 silc_buffer_free(tmpbuf);
367 query->resolved = TRUE;
369 /* Continue parsing the query after received reply from router */
370 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
371 silc_server_query_send_router_reply, query);
374 /* Reply callback called after primary router has replied to our initial
375 sending of the query to it. We will proceed the query in this function. */
377 void silc_server_query_send_router_reply(void *context, void *reply)
379 SilcServerQuery query = context;
380 SilcServer server = query->cmd->server;
381 SilcServerCommandReplyContext cmdr = reply;
383 SILC_LOG_DEBUG(("Received reply from router to query"));
385 /* If the original command caller has gone away, just stop. */
386 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
387 SILC_LOG_DEBUG(("Original command caller vanished"));
388 silc_server_query_free(query);
392 /* Check if router sent error reply */
393 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
395 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
396 SILC_CONN_SERVER : SILC_CONN_ROUTER);
398 /* If this was nick@server query, retry to @serv if the primary router
400 if (query->nick_server[0] && !query->dynamic_retry &&
401 server->config->dynamic_server &&
402 !silc_server_num_sockets_by_remote(server, query->nick_server,
403 query->nick_server, 706, type)) {
404 SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
405 query->nick_server, 706));
406 silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
407 706, silc_server_query_connected,
409 query->dynamic_retry = TRUE;
410 query->resolved = FALSE;
414 SILC_LOG_DEBUG(("Sending error to original query"));
417 server->stat.commands_sent++;
419 /* Send the same command reply payload which contains the error */
420 silc_command_set_command(cmdr->payload, query->querycmd);
421 silc_command_set_ident(cmdr->payload,
422 silc_command_get_ident(query->cmd->payload));
423 buffer = silc_command_payload_encode_payload(cmdr->payload);
424 silc_server_packet_send(server, query->cmd->sock,
425 SILC_PACKET_COMMAND_REPLY, 0,
426 buffer->data, silc_buffer_len(buffer));
427 silc_buffer_free(buffer);
428 silc_server_query_free(query);
432 /* Continue with parsing */
433 silc_server_query_parse(server, query, FALSE);
436 /* Parse the command query and start processing the queries in detail. */
438 SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
441 SilcServerCommandContext cmd = query->cmd;
442 SilcIDListData idata = silc_packet_get_context(cmd->sock);
444 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
448 SILC_LOG_DEBUG(("Parsing %s query",
449 silc_get_command_name(query->querycmd)));
454 switch (query->querycmd) {
456 case SILC_COMMAND_WHOIS:
457 /* Get requested attributes if set */
458 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
459 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
460 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
462 /* When Requested Attributes is present we will assure that this
463 client cannot execute the WHOIS command too fast. This would be
464 same as having SILC_CF_LAG_STRICT. */
465 if (idata && idata->conn_type == SILC_CONN_CLIENT)
466 ((SilcClientEntry)idata)->fast_command = 6;
469 /* Get Client IDs if present. Take IDs always instead of nickname. */
470 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
474 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
475 if (!tmp && !query->attrs) {
476 /* No nickname, no ids and no attributes - send error */
477 silc_server_query_send_error(server, query,
478 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
479 silc_server_query_free(query);
483 /* Get the nickname@server string and parse it */
484 if (tmp && ((tmp_len > 128) ||
485 !silc_parse_userfqdn(tmp, query->nickname,
486 sizeof(query->nickname),
488 sizeof(query->nick_server)))) {
489 silc_server_query_send_error(server, query,
490 SILC_STATUS_ERR_BAD_NICKNAME, 0);
491 silc_server_query_free(query);
497 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
498 SILC_STRING_UTF8, 128, &tmp_len);
500 silc_server_query_send_error(server, query,
501 SILC_STATUS_ERR_BAD_NICKNAME, 0);
502 silc_server_query_free(query);
505 memset(query->nickname, 0, sizeof(query->nickname));
506 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
511 /* Parse the IDs included in the query */
512 query->ids = silc_calloc(argc, sizeof(*query->ids));
516 for (i = 0; i < argc; i++) {
517 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
521 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
522 id.type != SILC_ID_CLIENT) {
523 silc_server_query_add_error(server, query, 1, i + 4,
524 SILC_STATUS_ERR_BAD_CLIENT_ID);
528 /* Normal server must check whether this ID exist, and if not then
529 send the query to router, unless done so already */
530 if (server->server_type == SILC_SERVER && !query->resolved) {
531 if (!silc_idlist_find_client_by_id(server->local_list,
532 &id.u.client_id, TRUE, NULL)) {
533 if (idata->conn_type != SILC_CONN_CLIENT ||
534 !silc_idlist_find_client_by_id(server->global_list,
535 &id.u.client_id, TRUE, NULL)) {
536 silc_server_query_send_router(server, query);
537 for (i = 0; i < query->ids_count; i++)
538 silc_free(query->ids[i].id);
539 silc_free(query->ids);
541 query->ids_count = 0;
547 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
549 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
554 /* Get the max count of reply messages allowed */
555 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
556 if (tmp && tmp_len == sizeof(SilcUInt32))
557 SILC_GET32_MSB(query->reply_count, tmp);
560 case SILC_COMMAND_WHOWAS:
562 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
564 silc_server_query_send_error(server, query,
565 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
566 silc_server_query_free(query);
570 /* Get the nickname@server string and parse it */
572 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
573 query->nick_server, sizeof(query->nick_server))) {
574 silc_server_query_send_error(server, query,
575 SILC_STATUS_ERR_BAD_NICKNAME, 0);
576 silc_server_query_free(query);
581 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
582 SILC_STRING_UTF8, 128, &tmp_len);
584 silc_server_query_send_error(server, query,
585 SILC_STATUS_ERR_BAD_NICKNAME, 0);
586 silc_server_query_free(query);
589 memset(query->nickname, 0, sizeof(query->nickname));
590 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
593 /* Get the max count of reply messages allowed */
594 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
595 if (tmp && tmp_len == sizeof(SilcUInt32))
596 SILC_GET32_MSB(query->reply_count, tmp);
599 case SILC_COMMAND_IDENTIFY:
600 /* Get IDs if present. Take IDs always instead of names. */
601 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
604 /* Try get nickname */
605 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
607 /* Get the nickname@server string and parse it */
609 !silc_parse_userfqdn(tmp, query->nickname,
610 sizeof(query->nickname),
612 sizeof(query->nick_server)))
613 silc_server_query_add_error(server, query, 1, 1,
614 SILC_STATUS_ERR_BAD_NICKNAME);
617 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
618 SILC_STRING_UTF8, 128, &tmp_len);
620 silc_server_query_send_error(server, query,
621 SILC_STATUS_ERR_BAD_NICKNAME, 0);
622 silc_server_query_free(query);
625 memset(query->nickname, 0, sizeof(query->nickname));
626 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
630 /* Try get server name */
631 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
633 /* Check server name */
634 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
637 silc_server_query_send_error(server, query,
638 SILC_STATUS_ERR_BAD_SERVER, 0);
639 silc_server_query_free(query);
642 query->server_name = tmp;
645 /* Get channel name */
646 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
647 if (tmp && tmp_len <= 256) {
648 /* Check channel name */
649 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
652 silc_server_query_send_error(server, query,
653 SILC_STATUS_ERR_BAD_CHANNEL, 0);
654 silc_server_query_free(query);
657 query->channel_name = tmp;
660 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
661 silc_server_query_send_error(server, query,
662 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
663 silc_server_query_free(query);
668 /* Parse the IDs included in the query */
669 query->ids = silc_calloc(argc, sizeof(*query->ids));
673 for (i = 0; i < argc; i++) {
674 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
678 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
679 silc_server_query_add_error(server, query, 1, i + 5,
680 SILC_STATUS_ERR_BAD_CLIENT_ID);
684 /* Normal server must check whether this ID exist, and if not then
685 send the query to router, unless done so already */
686 if (server->server_type == SILC_SERVER && !query->resolved) {
687 if (id.type == SILC_ID_CLIENT) {
688 if (!silc_idlist_find_client_by_id(server->local_list,
689 &id.u.client_id, TRUE, NULL)) {
690 if (idata->conn_type != SILC_CONN_CLIENT ||
691 !silc_idlist_find_client_by_id(server->global_list,
692 &id.u.client_id, TRUE,
694 silc_server_query_send_router(server, query);
695 for (i = 0; i < query->ids_count; i++)
696 silc_free(query->ids[i].id);
697 silc_free(query->ids);
699 query->ids_count = 0;
704 /* For now all other ID's except Client ID's are explicitly
705 sent to router for resolving. */
706 silc_server_query_send_router(server, query);
707 for (i = 0; i < query->ids_count; i++)
708 silc_free(query->ids[i].id);
709 silc_free(query->ids);
711 query->ids_count = 0;
716 if (id.type == SILC_ID_CLIENT)
717 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
719 if (id.type == SILC_ID_SERVER)
720 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
722 if (id.type == SILC_ID_CHANNEL)
723 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
725 query->ids[query->ids_count].id_type = id.type;
730 /* Get the max count of reply messages allowed */
731 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
732 if (tmp && tmp_len == sizeof(SilcUInt32))
733 SILC_GET32_MSB(query->reply_count, tmp);
737 query->parsed = TRUE;
740 if (!parse_only && query->nickname) {
741 switch (query->querycmd) {
742 case SILC_COMMAND_WHOIS:
743 case SILC_COMMAND_IDENTIFY:
744 /* Check server name. If we are open server and don't yet have
745 connection to remote router, create it now. */
746 if (query->nick_server[0] && server->config->dynamic_server &&
748 /* If primary router is specified, use that. Otherwise connect
749 to the server in nick@server string. */
750 SilcServerConfigRouter *router;
751 SilcConnectionType type = (server->server_type == SILC_ROUTER ?
752 SILC_CONN_SERVER : SILC_CONN_ROUTER);
754 router = silc_server_config_get_primary_router(server);
755 if (router && server->standalone) {
756 /* Create connection to primary router */
757 SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
758 router->host, router->port));
759 query->dynamic_prim = TRUE;
760 silc_server_create_connection(server, FALSE, TRUE,
761 router->host, router->port,
762 silc_server_query_connected, query);
764 } else if (!silc_server_num_sockets_by_remote(server,
768 /* Create connection and handle the query after connection */
769 SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
770 query->nick_server, 706));
771 silc_server_create_connection(server, FALSE, TRUE,
772 query->nick_server, 706,
773 silc_server_query_connected, query);
780 /* Start processing the query information */
782 silc_server_query_process(server, query, TRUE);
787 /* Context for holding clients searched by public key. */
789 SilcClientEntry **clients;
790 SilcUInt32 *clients_count;
792 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
794 /* SKR find callbcak */
796 static void silc_server_query_skr_callback(SilcSKR skr,
798 SilcSKRStatus status,
802 SilcServerPublicKeyUser uc = context;
806 SILC_LOG_DEBUG(("Found %d keys", silc_dlist_count(keys)));
807 (*uc->clients) = silc_realloc((*uc->clients),
808 sizeof((**uc->clients)) *
809 ((*uc->clients_count) +
810 silc_dlist_count(keys)));
812 silc_dlist_start(keys);
813 while ((key = silc_dlist_get(keys)))
814 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
817 silc_dlist_uninit(keys);
820 silc_skr_find_free(find);
823 /* If clients are set, limit the found clients using the attributes in
824 the query. If clients are not set, try to find some clients using
827 void silc_server_query_check_attributes(SilcServer server,
828 SilcServerQuery query,
829 SilcClientEntry **clients,
830 SilcUInt32 *clients_count) {
831 SilcClientEntry entry;
832 SilcAttributePayload attr;
833 SilcAttribute attribute;
834 SilcAttributeObjPk pk;
835 SilcPublicKey publickey, cmp_pubkey;
837 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
840 /* If no clients were found, we only check the attributes
841 if the user wasn't searching for nickname/ids */
844 if (query->nickname[0] || query->ids_count)
848 silc_dlist_start(query->attrs);
849 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
850 attribute = silc_attribute_get_attribute(attr);
853 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
854 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
856 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
859 if (!strcmp(pk.type, "silc-rsa"))
860 type = SILC_PKCS_SILC;
861 else if (!strcmp(pk.type, "ssh-rsa"))
862 type = SILC_PKCS_SSH2;
863 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
864 type = SILC_PKCS_X509V3;
865 else if (!strcmp(pk.type, "pgp-sign-rsa"))
866 type = SILC_PKCS_OPENPGP;
870 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
876 search_pubkey = TRUE;
878 /* If no clients were set on calling this function, we just search
879 for clients, otherwise we try to limit the clients. */
881 SilcServerPublicKeyUserStruct usercontext;
884 usercontext.clients = clients;
885 usercontext.clients_count = clients_count;
886 usercontext.found = FALSE;
888 find = silc_skr_find_alloc();
892 silc_skr_find_set_public_key(find, publickey);
893 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
894 silc_skr_find(server->repository, server->schedule,
895 find, silc_server_query_skr_callback, &usercontext);
897 if (usercontext.found == TRUE)
900 for (i = 0; i < *clients_count; i++) {
901 entry = (*clients)[i];
903 if (!entry->data.public_key)
906 if (silc_server_get_public_key_by_client(server, entry,
908 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
914 (*clients)[i] = NULL;
919 silc_pkcs_public_key_free(publickey);
924 if (!found && !query->nickname[0] && !query->ids)
925 silc_server_query_add_error(server, query, 2, 0,
927 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
928 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
931 /* Processes the parsed query. This does the actual finding of the
932 queried information and prepares for sending reply to the original
933 sender of the query command. */
935 void silc_server_query_process(SilcServer server, SilcServerQuery query,
938 SilcServerCommandContext cmd = query->cmd;
939 SilcIDListData idata = silc_packet_get_context(cmd->sock);
940 SilcBool check_global = FALSE;
942 SilcClientEntry *clients = NULL, client_entry;
943 SilcChannelEntry *channels = NULL;
944 SilcServerEntry *servers = NULL;
945 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
949 silc_server_query_free(query);
953 SILC_LOG_DEBUG(("Processing %s query",
954 silc_get_command_name(query->querycmd)));
956 /* Check global lists if query is coming from client or we are not
957 normal server (we know global information). */
958 if (idata->conn_type == SILC_CONN_CLIENT)
960 else if (server->server_type != SILC_SERVER)
963 if (query->nickname[0]) {
964 /* Get all clients matching nickname from local list */
965 if (!silc_idlist_get_clients_by_hash(server->local_list,
967 query->nick_server[0] ?
968 query->nick_server : NULL,
970 &clients, &clients_count))
971 silc_idlist_get_clients_by_nickname(server->local_list,
973 query->nick_server[0] ?
974 query->nick_server : NULL,
975 &clients, &clients_count);
977 /* Check global list as well */
979 if (!silc_idlist_get_clients_by_hash(server->global_list,
981 query->nick_server[0] ?
982 query->nick_server : NULL,
984 &clients, &clients_count))
985 silc_idlist_get_clients_by_nickname(server->global_list,
987 query->nick_server[0] ?
988 query->nick_server : NULL,
989 &clients, &clients_count);
993 silc_server_query_add_error(server, query, 1, 1,
994 SILC_STATUS_ERR_NO_SUCH_NICK);
997 if (query->server_name) {
998 /* Find server by name */
999 entry = silc_idlist_find_server_by_name(server->local_list,
1000 query->server_name, TRUE, NULL);
1001 if (!entry && check_global)
1002 entry = silc_idlist_find_server_by_name(server->global_list,
1003 query->server_name, TRUE, NULL);
1005 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
1006 servers[servers_count++] = (SilcServerEntry)entry;
1010 silc_server_query_add_error(server, query, 1, 2,
1011 SILC_STATUS_ERR_NO_SUCH_SERVER);
1014 if (query->channel_name) {
1015 /* Find channel by name */
1016 entry = silc_idlist_find_channel_by_name(server->local_list,
1017 query->channel_name, NULL);
1018 if (!entry && check_global)
1019 entry = silc_idlist_find_channel_by_name(server->global_list,
1020 query->channel_name, NULL);
1022 channels = silc_realloc(channels, sizeof(*channels) *
1023 (channels_count + 1));
1024 channels[channels_count++] = (SilcChannelEntry)entry;
1028 silc_server_query_add_error(server, query, 1, 3,
1029 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1032 if (query->ids_count) {
1033 /* Find entries by the queried IDs */
1034 for (i = 0; i < query->ids_count; i++) {
1035 void *id = query->ids[i].id;
1039 switch (query->ids[i].id_type) {
1041 case SILC_ID_CLIENT:
1042 /* Get client entry */
1043 entry = silc_idlist_find_client_by_id(server->local_list,
1045 if (!entry && check_global)
1046 entry = silc_idlist_find_client_by_id(server->global_list,
1049 silc_server_query_add_error(server, query, 0, i,
1050 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1054 clients = silc_realloc(clients, sizeof(*clients) *
1055 (clients_count + 1));
1056 clients[clients_count++] = (SilcClientEntry)entry;
1059 case SILC_ID_SERVER:
1060 /* Get server entry */
1061 entry = silc_idlist_find_server_by_id(server->local_list,
1063 if (!entry && check_global)
1064 entry = silc_idlist_find_server_by_id(server->global_list,
1067 silc_server_query_add_error(server, query, 0, i,
1068 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1072 servers = silc_realloc(servers, sizeof(*servers) *
1073 (servers_count + 1));
1074 servers[servers_count++] = (SilcServerEntry)entry;
1077 case SILC_ID_CHANNEL:
1078 /* Get channel entry */
1079 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1080 if (!entry && check_global)
1081 entry = silc_idlist_find_channel_by_id(server->global_list, id,
1084 silc_server_query_add_error(server, query, 0, i,
1085 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1089 channels = silc_realloc(channels, sizeof(*channels) *
1090 (channels_count + 1));
1091 channels[channels_count++] = (SilcChannelEntry)entry;
1100 /* Check the attributes to narrow down the search by using them. */
1102 silc_server_query_check_attributes(server, query, &clients,
1105 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1106 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1107 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1109 /* If nothing was found, then just send the errors */
1110 if (!clients && !channels && !servers) {
1111 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1115 /* If caller does not want us to resolve anything (has resolved already)
1116 then just continue with sending the reply */
1118 silc_server_query_send_reply(server, query, clients, clients_count,
1119 servers, servers_count, channels,
1123 silc_free(channels);
1127 /* Now process all found information and if necessary do some more
1129 switch (query->querycmd) {
1131 case SILC_COMMAND_WHOIS:
1132 for (i = 0; i < clients_count; i++) {
1133 client_entry = clients[i];
1135 /* Check if cannot query this anyway, so take next one */
1136 if (!client_entry ||
1137 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1140 /* If Requested Attributes is set then we always resolve the client
1141 information, if not then check whether the entry is complete or not
1142 and decide whether we need to resolve or not. */
1143 if (!query->attrs) {
1145 /* Even if nickname and stuff are present, we may need to resolve
1147 if (client_entry->nickname && client_entry->username &&
1148 client_entry->userinfo) {
1149 /* Check if cannot query this anyway, so take next one */
1150 if (!client_entry->router)
1153 /* If we are router, client is local to us, or client is on channel
1154 we do not need to resolve the client information. */
1155 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1156 || silc_hash_table_count(client_entry->channels) ||
1162 /* Remove the NOATTR status periodically */
1163 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1164 client_entry->updated + 600 < time(NULL))
1165 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1167 /* When requested attributes is present and local client is detached
1168 we cannot send the command to the client, we'll reply on behalf of
1169 the client instead. */
1170 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1171 (client_entry->mode & SILC_UMODE_DETACHED ||
1172 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1175 /* If attributes are present in query, and in the entry and we have
1176 done resolvings already we don't need to resolve anymore */
1177 if (query->resolved && query->attrs && client_entry->attrs)
1180 /* Resolve the detailed client information. If client is local we
1181 know that attributes were present and we will resolve directly
1182 from the client. Otherwise resolve from client's owner. */
1183 silc_server_query_resolve(server, query,
1184 (SILC_IS_LOCAL(client_entry) ?
1185 client_entry->connection :
1186 client_entry->router->connection),
1191 case SILC_COMMAND_WHOWAS:
1192 for (i = 0; i < clients_count; i++) {
1193 client_entry = clients[i];
1195 /* Check if cannot query this anyway, so take next one */
1196 if (!client_entry || !client_entry->router ||
1197 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1200 /* If both nickname and username are present no resolving is needed */
1201 if (client_entry->nickname && client_entry->username)
1204 /* Resolve the detailed client information */
1205 silc_server_query_resolve(server, query,
1206 client_entry->router->connection,
1211 case SILC_COMMAND_IDENTIFY:
1212 for (i = 0; i < clients_count; i++) {
1213 client_entry = clients[i];
1215 /* Check if cannot query this anyway, so take next one */
1216 if (!client_entry || !client_entry->router ||
1217 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1220 /* Even if nickname is present, we may need to resolve the entry */
1221 if (client_entry->nickname) {
1223 /* If we are router, client is local to us, or client is on channel
1224 we do not need to resolve the client information. */
1225 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1226 || silc_hash_table_count(client_entry->channels) ||
1231 /* Resolve the detailed client information */
1232 silc_server_query_resolve(server, query,
1233 client_entry->router->connection,
1239 if (!query->queries_count)
1240 /* If we didn't have to do any resolving, continue with sending the
1241 command reply to the original sender. */
1242 silc_server_query_send_reply(server, query, clients, clients_count,
1243 servers, servers_count, channels,
1246 /* Now actually send the resolvings we gathered earlier */
1247 silc_server_query_resolve(server, query, NULL, NULL);
1251 silc_free(channels);
1254 /* Resolve the detailed information for the `client_entry'. Only client
1255 information needs to be resolved for being incomplete. Each incomplete
1256 client entry calls this function to do the resolving. */
1258 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1259 SilcPacketStream sock,
1260 SilcClientEntry client_entry)
1262 SilcServerCommandContext cmd = query->cmd;
1263 SilcServerQueryList r = NULL;
1270 if (!sock && client_entry)
1273 /* If arguments are NULL we will now actually send the resolvings
1274 that earlier has been gathered by calling this function. */
1275 if (!sock && !client_entry) {
1278 SILC_LOG_DEBUG(("Sending the resolvings"));
1280 /* WHOWAS resolving has been done at the same time this function
1281 was called to add the resolving for WHOWAS, so just return. */
1282 if (query->querycmd == SILC_COMMAND_WHOWAS)
1285 for (i = 0; i < query->querylist_count; i++) {
1286 r = &query->querylist[i];
1288 /* If Requested Attributes were present put them to this resolving */
1289 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1291 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1292 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1293 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1295 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1297 r->arg[r->argc] = silc_memdup(tmp, len);
1298 r->arg_lens[r->argc] = len;
1299 r->arg_types[r->argc] = 3;
1304 server->stat.commands_sent++;
1306 /* Send WHOIS command */
1307 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1308 r->argc, r->arg, r->arg_lens,
1309 r->arg_types, r->ident);
1310 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1311 res_cmd->data, silc_buffer_len(res_cmd));
1312 silc_buffer_free(res_cmd);
1314 /* Reprocess this packet after received reply */
1315 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1317 silc_server_query_resolve_reply,
1319 query->queries_left++;
1322 /* Cleanup this temporary context */
1323 for (i = 0; i < query->querylist_count; i++) {
1325 for (k = 0; k < query->querylist[i].argc; k++)
1326 silc_free(query->querylist[i].arg[k]);
1327 silc_free(query->querylist[i].arg);
1328 silc_free(query->querylist[i].arg_lens);
1329 silc_free(query->querylist[i].arg_types);
1331 silc_free(query->querylist);
1332 query->querylist = NULL;
1333 query->querylist_count = 0;
1337 SILC_LOG_DEBUG(("Resolving client information"));
1339 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1340 /* The entry is being resolved by some other external query already.
1341 Attach to that query instead of resolving again. */
1342 ident = client_entry->resolve_cmd_ident;
1343 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1344 silc_server_query_resolve_reply, query))
1345 query->queries_left++;
1347 /* This entry will be resolved */
1348 ident = ++server->cmd_ident;
1350 switch (query->querycmd) {
1352 case SILC_COMMAND_WHOIS:
1353 case SILC_COMMAND_IDENTIFY:
1354 /* Take existing query context if exist for this connection */
1355 for (i = 0; i < query->querylist_count; i++)
1356 if (query->querylist[i].sock == sock) {
1357 r = &query->querylist[i];
1362 /* Allocate new temp query list context */
1363 query->querylist = silc_realloc(query->querylist,
1364 sizeof(*query->querylist) *
1365 (query->querylist_count + 1));
1366 r = &query->querylist[query->querylist_count];
1367 query->querylist_count++;
1368 memset(r, 0, sizeof(*r));
1371 if (SILC_IS_LOCAL(client_entry))
1376 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1377 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1378 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1380 /* Add the client entry to be resolved */
1381 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1382 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1383 r->arg_lens[r->argc] = silc_buffer_len(idp);
1384 r->arg_types[r->argc] = r->argc + 4;
1386 silc_buffer_free(idp);
1390 case SILC_COMMAND_WHOWAS:
1391 /* We must send WHOWAS command since it's the only the way of
1392 resolving clients that are not present in the network anymore. */
1393 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1394 1, query->nickname, strlen(query->nickname));
1395 if (silc_server_command_pending(server, query->querycmd, ident,
1396 silc_server_query_resolve_reply, query))
1397 query->queries_left++;
1402 /* Mark the entry as being resolved */
1403 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1404 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1405 client_entry->resolve_cmd_ident = ident;
1406 client_entry->updated = time(NULL);
1408 /* Save the queried ID, which we will reprocess after we get this and
1409 all other queries back. */
1410 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1411 (query->queries_count + 1));
1412 if (query->queries) {
1413 i = query->queries_count;
1414 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1415 query->queries[i].id_type = SILC_ID_CLIENT;
1416 query->queries[i].ident = ident;
1417 query->queries_count++;
1421 /* Reply callback called after one resolving has been completed. If
1422 all resolvings has been received then we will continue with sending
1423 the command reply to the original sender of the query. */
1425 void silc_server_query_resolve_reply(void *context, void *reply)
1427 SilcServerQuery query = context;
1428 SilcServer server = query->cmd->server;
1429 SilcServerCommandReplyContext cmdr = reply;
1430 SilcUInt16 ident = cmdr->ident;
1431 SilcStatus error = SILC_STATUS_OK;
1432 SilcServerQueryID id = NULL;
1433 SilcClientEntry client_entry;
1436 /* One less query left */
1437 query->queries_left--;
1439 silc_command_get_status(cmdr->payload, NULL, &error);
1440 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1441 query->queries_left, error));
1443 /* If no error then skip to other stuff */
1444 if (error == SILC_STATUS_OK)
1447 /* Error occurred during resolving */
1449 /* Find the resolved client ID */
1450 for (i = 0; i < query->queries_count; i++) {
1451 if (query->queries[i].ident != ident)
1454 id = &query->queries[i];
1456 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1458 /* If timeout occurred for local entry when resolving attributes
1459 mark that this client doesn't support attributes in WHOIS. This
1460 assures we won't send the request again to the client. */
1461 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1462 client_entry = silc_idlist_find_client_by_id(server->local_list,
1463 id->id, TRUE, NULL);
1464 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1465 silc_id_render(id->id, SILC_ID_CLIENT)));
1466 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1467 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1468 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1473 /* Remove the RESOLVING status from the client entry */
1474 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1475 client_entry = silc_idlist_find_client_by_id(server->local_list,
1476 id->id, TRUE, NULL);
1478 client_entry = silc_idlist_find_client_by_id(server->global_list,
1479 id->id, TRUE, NULL);
1481 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1488 /* If there are queries left then wait for them */
1489 if (query->queries_left)
1492 SILC_LOG_DEBUG(("Reprocess the query"));
1494 /* If the original command caller has gone away, just stop. */
1495 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1496 SILC_LOG_DEBUG(("Original command caller vanished"));
1497 silc_server_query_free(query);
1501 /* We have received all queries. Now re-search all information required
1502 to complete this query. Reason we cannot save the values found in
1503 the first search is that SilcClientEntry, SilcServerEntry and
1504 SilcChannelEntry pointers may become invalid while we were waiting
1505 for these resolvings. */
1506 silc_server_query_process(server, query, FALSE);
1509 /* Send the reply to the original query. If arguments are NULL then this
1510 sends only the errors that has occurred during the processing of the
1511 query. This sends the errors always after sending all the found
1512 information. The query is over after this function returns and the
1513 `query' will become invalid. This is called only after all informations
1514 has been resolved. This means that if something is not found or is
1515 incomplete in this function we were unable to resolve the information
1516 or it does not exist at all. */
1518 void silc_server_query_send_reply(SilcServer server,
1519 SilcServerQuery query,
1520 SilcClientEntry *clients,
1521 SilcUInt32 clients_count,
1522 SilcServerEntry *servers,
1523 SilcUInt32 servers_count,
1524 SilcChannelEntry *channels,
1525 SilcUInt32 channels_count)
1527 SilcServerCommandContext cmd = query->cmd;
1528 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1529 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1535 int i, k, valid_count;
1536 char nh[384], uh[384];
1537 SilcBool sent_reply = FALSE;
1539 SILC_LOG_DEBUG(("Sending reply to query"));
1540 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1541 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1542 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1543 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1545 status = SILC_STATUS_OK;
1548 if (clients_count) {
1549 SilcClientEntry entry;
1550 SilcPacketStream hsock;
1552 /* Mark all invalid entries */
1553 for (i = 0, valid_count = 0; i < clients_count; i++) {
1558 switch (query->querycmd) {
1559 case SILC_COMMAND_WHOIS:
1560 if (!entry->nickname || !entry->username || !entry->userinfo ||
1561 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1562 /* When querying by ID, every "unfound" entry must cause error */
1564 silc_server_query_add_error_id(server, query,
1565 SILC_STATUS_ERR_TIMEDOUT,
1566 entry->id, SILC_ID_CLIENT);
1572 case SILC_COMMAND_IDENTIFY:
1573 if (!entry->nickname ||
1574 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1575 /* When querying by ID, every "unfound" entry must cause error */
1577 silc_server_query_add_error_id(server, query,
1578 SILC_STATUS_ERR_TIMEDOUT,
1579 entry->id, SILC_ID_CLIENT);
1585 case SILC_COMMAND_WHOWAS:
1586 if (!entry->nickname || !entry->username ||
1587 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1596 /* Start processing found clients */
1597 status = SILC_STATUS_OK;
1598 if (valid_count > 1)
1599 status = SILC_STATUS_LIST_START;
1601 /* Now do the sending of valid entries */
1603 for (i = 0; i < clients_count && valid_count; i++) {
1609 status = SILC_STATUS_LIST_ITEM;
1610 if (valid_count > 1 && k == valid_count - 1
1611 && !servers_count && !channels_count && !query->errors_count)
1612 status = SILC_STATUS_LIST_END;
1613 if (query->reply_count && k - 1 == query->reply_count)
1614 status = SILC_STATUS_LIST_END;
1616 SILC_LOG_DEBUG(("%s: client %s",
1617 (status == SILC_STATUS_OK ? " OK" :
1618 status == SILC_STATUS_LIST_START ? "START" :
1619 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1620 status == SILC_STATUS_LIST_END ? " END" :
1621 " : "), entry->nickname));
1623 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1624 memset(nh, 0, sizeof(nh));
1626 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1627 if (!strchr(entry->nickname, '@')) {
1628 silc_strncat(nh, sizeof(nh), "@", 1);
1629 if (entry->servername) {
1630 silc_strncat(nh, sizeof(nh), entry->servername,
1631 strlen(entry->servername));
1633 len = entry->router ? strlen(entry->router->server_name) :
1634 strlen(server->server_name);
1635 silc_strncat(nh, sizeof(nh), entry->router ?
1636 entry->router->server_name :
1637 server->server_name, len);
1641 switch (query->querycmd) {
1643 case SILC_COMMAND_WHOIS:
1645 unsigned char idle[4], mode[4];
1646 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1647 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1649 memset(fempty, 0, sizeof(fempty));
1650 memset(idle, 0, sizeof(idle));
1651 memset(uh, 0, sizeof(uh));
1653 silc_strncat(uh, sizeof(uh), entry->username,
1654 strlen(entry->username));
1655 if (!strchr(entry->username, '@') && entry->connection) {
1656 hsock = entry->connection;
1657 silc_strncat(uh, sizeof(uh), "@", 1);
1658 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1659 NULL, (const char **)&tmp2, NULL, NULL);
1660 silc_strncat(uh, sizeof(uh), tmp2, strlen(tmp2));
1663 if (idata->conn_type == SILC_CONN_CLIENT)
1665 silc_server_get_client_channel_list(server, entry, FALSE,
1666 FALSE, &umode_list);
1669 silc_server_get_client_channel_list(server, entry, TRUE,
1672 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1673 fingerprint = entry->data.fingerprint;
1677 SILC_PUT32_MSB(entry->mode, mode);
1678 if (entry->connection)
1679 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1681 /* If Requested Attribute were present, and we do not have the
1682 attributes we will reply to them on behalf of the client. */
1685 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1686 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1687 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1688 entry->attrs_len = len;
1689 silc_buffer_free(tmpattrs);
1691 attrs = entry->attrs;
1692 len = entry->attrs_len;
1695 /* Send command reply */
1696 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1697 status, 0, ident, 10,
1698 2, idp->data, silc_buffer_len(idp),
1702 strlen(entry->userinfo),
1703 6, channels ? channels->data : NULL,
1704 channels ? silc_buffer_len(channels)
1709 fingerprint ? 20 : 0,
1710 10, umode_list ? umode_list->data :
1712 silc_buffer_len(umode_list) :
1717 /* For now we always delete Requested Attributes, unless the client
1718 is detached, in which case we don't want to reconstruct the
1719 same data everytime */
1720 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1721 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1722 silc_free(entry->attrs);
1723 entry->attrs = NULL;
1727 silc_buffer_free(channels);
1729 silc_buffer_free(umode_list);
1735 case SILC_COMMAND_IDENTIFY:
1736 if (!entry->username) {
1737 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1738 status, 0, ident, 2,
1739 2, idp->data, silc_buffer_len(idp),
1743 memset(uh, 0, sizeof(uh));
1744 silc_strncat(uh, sizeof(uh), entry->username,
1745 strlen(entry->username));
1746 if (!strchr(entry->username, '@') && entry->connection) {
1747 hsock = entry->connection;
1748 silc_strncat(uh, sizeof(uh), "@", 1);
1749 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1750 NULL, (const char **)&tmp2,
1752 silc_strncat(uh, sizeof(uh), tmp2, strlen(tmp2));
1755 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1756 status, 0, ident, 3,
1757 2, idp->data, silc_buffer_len(idp),
1764 case SILC_COMMAND_WHOWAS:
1765 memset(uh, 0, sizeof(uh));
1766 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1767 if (!strchr(entry->username, '@'))
1768 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1770 /* Send command reply */
1771 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1772 status, 0, ident, 4,
1773 2, idp->data, silc_buffer_len(idp),
1778 strlen(entry->userinfo) : 0);
1783 silc_buffer_free(idp);
1785 if (status == SILC_STATUS_LIST_END)
1791 /* Not one valid entry was found, send error. If nickname was used
1792 in query send error based on that, otherwise the query->errors
1793 already includes proper errors. */
1794 if (query->nickname[0] || (!query->ids && query->attrs))
1795 silc_server_query_add_error(server, query, 1, 1,
1796 SILC_STATUS_ERR_NO_SUCH_NICK);
1798 /* Make sure some error is sent */
1799 if (!query->errors_count && !servers_count && !channels_count)
1800 silc_server_query_add_error(server, query, 2, 0,
1801 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1806 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1807 SilcServerEntry entry;
1809 if (status == SILC_STATUS_OK && servers_count > 1)
1810 status = SILC_STATUS_LIST_START;
1813 for (i = 0; i < servers_count; i++) {
1817 status = SILC_STATUS_LIST_ITEM;
1818 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1819 !query->errors_count)
1820 status = SILC_STATUS_LIST_END;
1821 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1822 !query->errors_count)
1823 status = SILC_STATUS_LIST_END;
1824 if (query->reply_count && k - 1 == query->reply_count)
1825 status = SILC_STATUS_LIST_END;
1827 SILC_LOG_DEBUG(("%s: server %s",
1828 (status == SILC_STATUS_OK ? " OK" :
1829 status == SILC_STATUS_LIST_START ? "START" :
1830 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1831 status == SILC_STATUS_LIST_END ? " END" :
1833 entry->server_name ? entry->server_name : ""));
1835 /* Send command reply */
1836 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1837 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1838 status, 0, ident, 2,
1839 2, idp->data, silc_buffer_len(idp),
1840 3, entry->server_name,
1841 entry->server_name ?
1842 strlen(entry->server_name) : 0);
1843 silc_buffer_free(idp);
1846 if (status == SILC_STATUS_LIST_END)
1853 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1854 SilcChannelEntry entry;
1856 if (status == SILC_STATUS_OK && channels_count > 1)
1857 status = SILC_STATUS_LIST_START;
1860 for (i = 0; i < channels_count; i++) {
1861 entry = channels[i];
1864 status = SILC_STATUS_LIST_ITEM;
1865 if (channels_count == 1 && status != SILC_STATUS_OK &&
1866 !query->errors_count)
1867 status = SILC_STATUS_LIST_END;
1868 if (channels_count > 1 && k == channels_count - 1 &&
1869 !query->errors_count)
1870 status = SILC_STATUS_LIST_END;
1871 if (query->reply_count && k - 1 == query->reply_count)
1872 status = SILC_STATUS_LIST_END;
1874 SILC_LOG_DEBUG(("%s: channel %s",
1875 (status == SILC_STATUS_OK ? " OK" :
1876 status == SILC_STATUS_LIST_START ? "START" :
1877 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1878 status == SILC_STATUS_LIST_END ? " END" :
1880 entry->channel_name ? entry->channel_name : ""));
1882 /* Send command reply */
1883 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1884 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1885 status, 0, ident, 2,
1886 2, idp->data, silc_buffer_len(idp),
1887 3, entry->channel_name,
1888 entry->channel_name ?
1889 strlen(entry->channel_name) : 0);
1890 silc_buffer_free(idp);
1893 if (status == SILC_STATUS_LIST_END)
1900 if (query->errors_count) {
1903 if (status == SILC_STATUS_OK && query->errors_count > 1)
1904 status = SILC_STATUS_LIST_START;
1907 for (i = 0; i < query->errors_count; i++) {
1910 /* Take error argument */
1911 if (query->errors[i].type == 1) {
1912 /* Take from sent arguments */
1914 tmp = silc_argument_get_arg_type(cmd->args,
1915 query->errors[i].index, &len);
1917 } else if (query->errors[i].type == 2) {
1922 } else if (!query->errors[i].id) {
1923 /* Take from query->ids */
1925 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1926 query->ids[query->errors[k].index].id_type);
1928 len = silc_buffer_len(idp);
1931 /* Take added ID. */
1932 idp = silc_id_payload_encode(query->errors[i].id,
1933 query->errors[k].id_type);
1935 len = silc_buffer_len(idp);
1940 status = SILC_STATUS_LIST_ITEM;
1941 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1942 status = SILC_STATUS_LIST_END;
1943 if (query->errors_count > 1 && k == query->errors_count - 1)
1944 status = SILC_STATUS_LIST_END;
1945 if (query->reply_count && k - 1 == query->reply_count)
1946 status = SILC_STATUS_LIST_END;
1948 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1949 (status == SILC_STATUS_OK ? " OK" :
1950 status == SILC_STATUS_LIST_START ? "START" :
1951 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1952 status == SILC_STATUS_LIST_END ? " END" :
1954 silc_get_status_message(query->errors[i].error),
1955 query->errors[i].error));
1957 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1958 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1960 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1961 (status == SILC_STATUS_OK ?
1962 query->errors[i].error : status),
1963 (status == SILC_STATUS_OK ?
1964 0 : query->errors[i].error), ident, 2,
1970 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1971 (status == SILC_STATUS_OK ?
1972 query->errors[i].error : status),
1973 (status == SILC_STATUS_OK ?
1974 0 : query->errors[i].error), ident, 1,
1977 silc_buffer_free(idp);
1980 if (status == SILC_STATUS_LIST_END)
1987 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1990 silc_server_query_free(query);
1993 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1994 of the client since we were unable to resolve them from the client.
1995 Either client does not support Requested Attributes or isn't replying
1996 to them like it should. */
1998 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1999 SilcServerQuery query,
2000 SilcClientEntry client_entry)
2002 SilcBuffer buffer = NULL;
2003 SilcAttribute attribute;
2004 SilcAttributePayload attr;
2005 SilcAttributeObjPk pk;
2006 SilcAttributeObjService service;
2008 unsigned char sign[65536 + 1];
2009 SilcUInt32 sign_len;
2011 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
2013 /* Go through all requested attributes */
2014 silc_dlist_start(query->attrs);
2015 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
2016 attribute = silc_attribute_get_attribute(attr);
2017 switch (attribute) {
2019 case SILC_ATTRIBUTE_SERVICE:
2020 /* Put SERVICE. Put only SILC service. */
2021 memset(&service, 0, sizeof(service));
2022 service.port = (server->config->server_info->primary ?
2023 server->config->server_info->primary->port : SILC_PORT);
2024 silc_strncat(service.address, sizeof(service.address),
2025 server->server_name, strlen(server->server_name));
2026 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2027 if (client_entry->connection)
2028 service.idle = time(NULL) - client_entry->data.last_receive;
2029 buffer = silc_attribute_payload_encode(buffer, attribute,
2030 SILC_ATTRIBUTE_FLAG_VALID,
2031 &service, sizeof(service));
2036 case SILC_ATTRIBUTE_STATUS_MOOD:
2037 /* Put STATUS_MOOD */
2038 buffer = silc_attribute_payload_encode(buffer, attribute,
2039 SILC_ATTRIBUTE_FLAG_VALID,
2041 SILC_ATTRIBUTE_MOOD_NORMAL,
2042 sizeof(SilcUInt32));
2047 case SILC_ATTRIBUTE_STATUS_FREETEXT:
2048 /* Put STATUS_FREETEXT. We just tell in the message that we are
2049 replying on behalf of the client. */
2051 "This information was provided by the server on behalf of the user";
2052 buffer = silc_attribute_payload_encode(buffer, attribute,
2053 SILC_ATTRIBUTE_FLAG_VALID,
2059 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2060 /* Put PREFERRED_CONTACT */
2061 buffer = silc_attribute_payload_encode(buffer, attribute,
2062 SILC_ATTRIBUTE_FLAG_VALID,
2064 SILC_ATTRIBUTE_CONTACT_CHAT,
2065 sizeof(SilcUInt32));
2070 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2071 /* Put USER_PUBLIC_KEY */
2072 if (client_entry->data.public_key) {
2073 pk.type = "silc-rsa";
2074 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2076 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2077 SILC_ATTRIBUTE_FLAG_VALID :
2078 SILC_ATTRIBUTE_FLAG_INVALID,
2086 /* No public key available */
2087 buffer = silc_attribute_payload_encode(buffer, attribute,
2088 SILC_ATTRIBUTE_FLAG_INVALID,
2095 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2096 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2097 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2100 /* For other attributes we cannot reply so mark it invalid */
2101 buffer = silc_attribute_payload_encode(buffer, attribute,
2102 SILC_ATTRIBUTE_FLAG_INVALID,
2110 /* Always put our public key. This assures that we send at least
2111 something valid back always. */
2112 pk.type = "silc-rsa";
2113 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2114 buffer = silc_attribute_payload_encode(buffer,
2115 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2116 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2117 SILC_ATTRIBUTE_FLAG_INVALID,
2123 /* Finally compute the digital signature of all the data we provided
2124 as an indication that we provided rightfull information, and this
2125 also authenticates our public key. */
2126 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2128 silc_pkcs_sign(server->private_key, buffer->data,
2129 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2130 TRUE, server->sha1hash)) {
2133 pk.data_len = sign_len;
2135 silc_attribute_payload_encode(buffer,
2136 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2137 SILC_ATTRIBUTE_FLAG_VALID,
2146 /* Find client by the Client ID indicated by the `client_id', and if not
2147 found then query it by using WHOIS command. The client information
2148 is also resolved if the cached information is incomplete or if the
2149 `always_resolve' is set to TRUE. The indication whether requested
2150 client was being resolved is saved into `resolved'. If the client
2151 is not being resolved its entry is returned by this function. NULL
2152 is returned if client is resolved. */
2154 SilcClientEntry silc_server_query_client(SilcServer server,
2155 const SilcClientID *client_id,
2156 SilcBool always_resolve,
2159 SilcClientEntry client;
2161 SILC_LOG_DEBUG(("Resolving client by client ID"));
2166 client = silc_idlist_find_client_by_id(server->local_list,
2167 (SilcClientID *)client_id,
2170 client = silc_idlist_find_client_by_id(server->global_list,
2171 (SilcClientID *)client_id,
2173 if (!client && server->server_type == SILC_ROUTER)
2177 if (!client && server->standalone)
2180 if (!client || !client->nickname || !client->username ||
2182 SilcBuffer buffer, idp;
2185 server->stat.commands_sent++;
2188 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2189 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2190 client->resolve_cmd_ident = ++server->cmd_ident;
2193 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2194 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2195 server->cmd_ident, 1,
2197 silc_buffer_len(idp));
2198 silc_server_packet_send(server,
2199 client && client->router ? client->router->connection :
2200 SILC_PRIMARY_ROUTE(server),
2201 SILC_PACKET_COMMAND, 0,
2202 buffer->data, silc_buffer_len(buffer));
2203 silc_buffer_free(idp);
2204 silc_buffer_free(buffer);