+++ /dev/null
-/*
-
- server_query.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 2005, 2007 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "serverincludes.h"
-#include "server_internal.h"
-
-typedef struct {
- SilcPacketStream sock; /* Connection of this query */
- unsigned char **arg; /* Query argument */
- SilcUInt32 *arg_lens; /* Query argument lengths */
- SilcUInt32 *arg_types; /* Query argument types */
- SilcUInt32 argc; /* Number of query arguments */
- SilcUInt32 timeout; /* Max timeout for query to complete */
- SilcUInt16 ident; /* Query command identifier */
-} *SilcServerQueryList;
-
-/* Represents an SILC ID */
-typedef struct {
- void *id; /* ID */
- SilcIdType id_type; /* ID type */
- SilcUInt16 ident; /* Command identifier */
-} *SilcServerQueryID;
-
-/* Represents one error occurred during query */
-typedef struct {
- void *id; /* ID */
- SilcIdType id_type; /* ID type */
- unsigned int index : 15; /* Index to IDs */
- unsigned int type : 2; /* 0 = take from query->ids, 1 = take
- from args, 2 = no args in error. */
- unsigned int error : 7; /* The actual error (SilcStatus) */
-} *SilcServerQueryError;
-
-/* Query session context */
-typedef struct {
- /* Queried data */
- char nickname[128 + 1]; /* Queried nickname, normalized */
- char nick_server[128 + 1]; /* Queried nickname's server */
- char *server_name; /* Queried server name, normalized */
- char *channel_name; /* Queried channel name, normalized */
- SilcServerQueryID ids; /* Queried IDs */
- SilcUInt32 ids_count; /* number of queried IDs */
- SilcUInt32 reply_count; /* Requested reply count */
- SilcDList attrs; /* Requested Attributes in WHOIS */
-
- /* Query session data */
- SilcPacketStream router; /* Router to send our query */
- SilcServerCommandContext cmd; /* Command context for query */
- SilcServerQueryList querylist; /* Temporary query list context */
- SilcServerQueryID queries; /* Ongoing queries */
- SilcServerQueryError errors; /* Query errors */
- SilcUInt16 querylist_count; /* Number of query lists */
- SilcUInt16 queries_count; /* Number of ongoing queries */
- SilcUInt16 queries_left; /* Number of ongoing queries left */
- SilcUInt16 errors_count; /* number of errors */
- unsigned int querycmd : 7; /* Query command (SilcCommand) */
- unsigned int resolved : 1; /* TRUE if normal server has resolved
- information from router */
- unsigned int dynamic_prim : 1; /* Dynamic connection attempt to primary */
- unsigned int dynamic_retry : 1; /* Primary returned error, send to
- nick@serv server. */
- unsigned int parsed : 1; /* Set when query is parsed */
-} *SilcServerQuery;
-
-
-void silc_server_query_free(SilcServerQuery query);
-void silc_server_query_send_error(SilcServer server,
- SilcServerQuery query,
- SilcStatus error, ...);
-void silc_server_query_add_error(SilcServer server,
- SilcServerQuery query,
- SilcUInt32 type,
- SilcUInt32 index,
- SilcStatus error);
-void silc_server_query_add_error_id(SilcServer server,
- SilcServerQuery query,
- SilcStatus error,
- void *id, SilcIdType id_type);
-void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
-void silc_server_query_send_router_reply(void *context, void *reply);
-SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
- SilcBool parse_only);
-void silc_server_query_process(SilcServer server, SilcServerQuery query,
- SilcBool resolve);
-void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
- SilcPacketStream sock,
- SilcClientEntry client_entry);
-void silc_server_query_resolve_reply(void *context, void *reply);
-void silc_server_query_send_reply(SilcServer server,
- SilcServerQuery query,
- SilcClientEntry *clients,
- SilcUInt32 clients_count,
- SilcServerEntry *servers,
- SilcUInt32 servers_count,
- SilcChannelEntry *channels,
- SilcUInt32 channels_count);
-SilcBuffer silc_server_query_reply_attrs(SilcServer server,
- SilcServerQuery query,
- SilcClientEntry client_entry);
-
-/* Free the query context structure and all allocated resources. */
-
-void silc_server_query_free(SilcServerQuery query)
-{
- int i;
-
- silc_server_command_free(query->cmd);
-
- for (i = 0; i < query->queries_count; i++)
- silc_free(query->queries[i].id);
- silc_free(query->queries);
-
- silc_free(query->server_name);
- silc_free(query->channel_name);
-
- for (i = 0; i < query->ids_count; i++)
- silc_free(query->ids[i].id);
- silc_free(query->ids);
-
- if (query->attrs)
- silc_attribute_payload_list_free(query->attrs);
-
- for (i = 0; i < query->errors_count; i++)
- silc_free(query->errors[i].id);
- silc_free(query->errors);
-
- memset(query, 'F', sizeof(*query));
- silc_free(query);
-}
-
-/* Send error reply indicated by the `error' to the original sender of
- the query. */
-
-void silc_server_query_send_error(SilcServer server,
- SilcServerQuery query,
- SilcStatus error, ...)
-{
- va_list va;
- unsigned char *data = NULL;
- SilcUInt32 data_len = 0, data_type = 0, argc = 0;
-
- va_start(va, error);
- data_type = va_arg(va, SilcUInt32);
- if (data_type) {
- argc = 1;
- data = va_arg(va, unsigned char *);
- data_len = va_arg(va, SilcUInt32);
- }
-
- SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
-
- /* Send the command reply with error */
- silc_server_send_command_reply(server, query->cmd->sock,
- query->querycmd, error, 0,
- silc_command_get_ident(query->cmd->payload),
- argc, data_type, data, data_len);
- va_end(va);
-}
-
-/* Add error to error list. Multiple errors may occur during the query
- processing and this function can be used to add one error. The
- `index' is the index to the command context which includes the argument
- which caused the error, or it is the index to query->ids, depending
- on value of `type'. If `type' is 0 the index is to query->ids, if
- it is 1 it is index to the command context arguments, and if it is
- 2 the index is ignored and no argument is included in the error. */
-
-void silc_server_query_add_error(SilcServer server,
- SilcServerQuery query,
- SilcUInt32 type,
- SilcUInt32 index,
- SilcStatus error)
-{
- query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
- (query->errors_count + 1));
- if (!query->errors)
- return;
- query->errors[query->errors_count].index = index;
- query->errors[query->errors_count].type = type;
- query->errors[query->errors_count].error = error;
- query->errors[query->errors_count].id = NULL;
- query->errors[query->errors_count].id_type = 0;
- query->errors_count++;
-}
-
-/* Same as silc_server_query_add_error but adds the ID data to be used
- with error sending with this error type. */
-
-void silc_server_query_add_error_id(SilcServer server,
- SilcServerQuery query,
- SilcStatus error,
- void *id, SilcIdType id_type)
-{
- query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
- (query->errors_count + 1));
- if (!query->errors)
- return;
- query->errors[query->errors_count].index = 0;
- query->errors[query->errors_count].type = 0;
- query->errors[query->errors_count].error = error;
- query->errors[query->errors_count].id = silc_id_dup(id, id_type);
- query->errors[query->errors_count].id_type = id_type;
- query->errors_count++;
-}
-
-/* Processes query as command. The `query' is the command that is
- being processed indicated by the `cmd'. The `query' can be one of
- the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
- SILC_COMMAND_IDENTIFY. This function handles the reply sending
- to the entity who sent this query to us automatically. Returns
- TRUE if the query is being processed or FALSE on error. */
-
-SilcBool silc_server_query_command(SilcServer server,
- SilcCommand querycmd,
- SilcServerCommandContext cmd,
- void *old_query)
-{
- SilcServerQuery query;
-
- SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
-
- if (!old_query) {
- query = silc_calloc(1, sizeof(*query));
- query->querycmd = querycmd;
- query->cmd = silc_server_command_dup(cmd);
- query->router = SILC_PRIMARY_ROUTE(server);
- } else
- query = old_query;
-
- switch (querycmd) {
-
- case SILC_COMMAND_WHOIS:
- /* If we are normal server and query contains nickname OR query
- doesn't contain nickname or ids BUT attributes, send it to the
- router */
- if (server->server_type != SILC_ROUTER && !server->standalone &&
- cmd->sock != SILC_PRIMARY_ROUTE(server) &&
- (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
- (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
- !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
- silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
- if (!silc_server_query_parse(server, query, TRUE))
- return FALSE;
- silc_server_query_send_router(server, query);
- return TRUE;
- }
- break;
-
- case SILC_COMMAND_WHOWAS:
- /* WHOWAS query is always sent to router if we are normal server */
- if (server->server_type == SILC_SERVER && !server->standalone &&
- cmd->sock != SILC_PRIMARY_ROUTE(server)) {
- silc_server_query_send_router(server, query);
- return TRUE;
- }
- break;
-
- case SILC_COMMAND_IDENTIFY:
- /* If we are normal server and query does not contain IDs, send it
- directly to router (it contains nickname, server name or channel
- name). */
- if (server->server_type == SILC_SERVER && !server->standalone &&
- cmd->sock != SILC_PRIMARY_ROUTE(server) &&
- !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
- if (!silc_server_query_parse(server, query, TRUE))
- return FALSE;
- silc_server_query_send_router(server, query);
- return TRUE;
- }
- break;
-
- default:
- SILC_LOG_ERROR(("Bad query using %d command", querycmd));
- silc_server_query_free(query);
- return FALSE;
- }
-
- /* Now parse the request */
- silc_server_query_parse(server, query, FALSE);
-
- return TRUE;
-}
-
-/* Remote server connected callback. */
-
-void silc_server_query_connected(SilcServer server,
- SilcServerEntry server_entry,
- void *context)
-{
- SilcServerQuery query = context;
-
- if (!server_entry) {
- /* Connecting failed */
- SilcConnectionType type = (server->server_type == SILC_ROUTER ?
- SILC_CONN_SERVER : SILC_CONN_ROUTER);
-
- if (query->dynamic_prim /* && @serv != prim.host.name */ &&
- !silc_server_num_sockets_by_remote(server, query->nick_server,
- query->nick_server, 706, type)) {
- /* Connection attempt to primary router failed, now try to the one
- specified in nick@server. */
- silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
- 706, silc_server_query_connected,
- query);
- query->dynamic_prim = FALSE;
- return;
- }
-
- /* Process the query after failed connect. This will send error back
- because such nick was not found. */
- SILC_LOG_DEBUG(("Process query, connecting failed"));
- silc_server_query_process(server, query, TRUE);
- return;
- }
-
- /* Reprocess the query */
- SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
- server_entry->server_name));
- query->router = server_entry->data.sconn->sock;
- silc_server_query_command(server, query->querycmd, query->cmd, query);
-}
-
-/* Send the received query to our primary router since we could not
- handle the query directly. We will reprocess the query after our
- router replies back. */
-
-void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
-{
- SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
-
- SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
- query->router));
-
- /* Statistics */
- server->stat.commands_sent++;
-
- /* Send WHOIS command to our router */
- old_ident = silc_command_get_ident(query->cmd->payload);
- silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
- silc_server_packet_send(server, query->router,
- SILC_PACKET_COMMAND, 0,
- tmpbuf->data, silc_buffer_len(tmpbuf));
- silc_command_set_ident(query->cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
-
- query->resolved = TRUE;
-
- /* Continue parsing the query after received reply from router */
- silc_server_command_pending(server, query->querycmd, server->cmd_ident,
- silc_server_query_send_router_reply, query);
-}
-
-/* Reply callback called after primary router has replied to our initial
- sending of the query to it. We will proceed the query in this function. */
-
-void silc_server_query_send_router_reply(void *context, void *reply)
-{
- SilcServerQuery query = context;
- SilcServer server = query->cmd->server;
- SilcServerCommandReplyContext cmdr = reply;
-
- SILC_LOG_DEBUG(("Received reply from router to query"));
-
- /* If the original command caller has gone away, just stop. */
- if (!silc_packet_stream_is_valid(query->cmd->sock)) {
- SILC_LOG_DEBUG(("Original command caller vanished"));
- silc_server_query_free(query);
- return;
- }
-
- /* Check if router sent error reply */
- if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
- SilcBuffer buffer;
- SilcConnectionType type = (server->server_type == SILC_ROUTER ?
- SILC_CONN_SERVER : SILC_CONN_ROUTER);
-
- /* If this was nick@server query, retry to @serv if the primary router
- returned error. */
- if (query->nick_server[0] && !query->dynamic_retry &&
- !silc_server_num_sockets_by_remote(server, query->nick_server,
- query->nick_server, 1334, type)) {
- SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
- query->nick_server, 706));
- silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
- 1334, silc_server_query_connected,
- query);
- query->dynamic_retry = TRUE;
- query->resolved = FALSE;
- return;
- }
-
- SILC_LOG_DEBUG(("Sending error to original query"));
-
- /* Statistics */
- server->stat.commands_sent++;
-
- /* Send the same command reply payload which contains the error */
- silc_command_set_command(cmdr->payload, query->querycmd);
- silc_command_set_ident(cmdr->payload,
- silc_command_get_ident(query->cmd->payload));
- buffer = silc_command_payload_encode_payload(cmdr->payload);
- silc_server_packet_send(server, query->cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- buffer->data, silc_buffer_len(buffer));
- silc_buffer_free(buffer);
- silc_server_query_free(query);
- return;
- }
-
- /* Continue with parsing */
- silc_server_query_parse(server, query, FALSE);
-}
-
-/* Parse the command query and start processing the queries in detail. */
-
-SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
- SilcBool parse_only)
-{
- SilcServerCommandContext cmd = query->cmd;
- SilcIDListData idata = silc_packet_get_context(cmd->sock);
- unsigned char *tmp;
- SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
- SilcID id;
- int i;
-
- SILC_LOG_DEBUG(("Parsing %s query",
- silc_get_command_name(query->querycmd)));
-
- if (query->parsed)
- goto parsed;
-
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- /* Get requested attributes if set */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
- if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
- query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
-
- /* When Requested Attributes is present we will assure that this
- client cannot execute the WHOIS command too fast. This would be
- same as having SILC_CF_LAG_STRICT. */
- if (idata && idata->conn_type == SILC_CONN_CLIENT)
- ((SilcClientEntry)idata)->fast_command = 6;
- }
-
- /* Get Client IDs if present. Take IDs always instead of nickname. */
- tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
- if (!tmp) {
-
- /* Get nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp && !query->attrs) {
- /* No nickname, no ids and no attributes - send error */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- silc_server_query_free(query);
- return FALSE;
- }
-
- /* Get the nickname@server string and parse it */
- if (tmp && ((tmp_len > 128) ||
- !silc_parse_userfqdn(tmp, query->nickname,
- sizeof(query->nickname),
- query->nick_server,
- sizeof(query->nick_server)))) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_server_query_free(query);
- return FALSE;
- }
-
- /* Check nickname */
- if (tmp) {
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_server_query_free(query);
- return FALSE;
- }
- memset(query->nickname, 0, sizeof(query->nickname));
- silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
- silc_free(tmp);
- }
-
- } else {
- /* Parse the IDs included in the query */
- query->ids = silc_calloc(argc, sizeof(*query->ids));
-
- for (i = 0; i < argc; i++) {
- tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
- if (!tmp)
- continue;
-
- if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
- id.type != SILC_ID_CLIENT) {
- silc_server_query_add_error(server, query, 1, i + 4,
- SILC_STATUS_ERR_BAD_CLIENT_ID);
- continue;
- }
-
- /* Normal server must check whether this ID exist, and if not then
- send the query to router, unless done so already */
- if (server->server_type == SILC_SERVER && !query->resolved) {
- if (!silc_idlist_find_client_by_id(server->local_list,
- &id.u.client_id, TRUE, NULL)) {
- if (idata->conn_type != SILC_CONN_CLIENT ||
- !silc_idlist_find_client_by_id(server->global_list,
- &id.u.client_id, TRUE, NULL)) {
- silc_server_query_send_router(server, query);
- for (i = 0; i < query->ids_count; i++)
- silc_free(query->ids[i].id);
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- return FALSE;
- }
- }
- }
-
- query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
- SILC_ID_CLIENT);
- query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
- query->ids_count++;
- }
- }
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break;
-
- case SILC_COMMAND_WHOWAS:
- /* Get nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- silc_server_query_free(query);
- return FALSE;
- }
-
- /* Get the nickname@server string and parse it */
- if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
- query->nick_server, sizeof(query->nick_server))) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_server_query_free(query);
- return FALSE;
- }
-
- /* Check nickname */
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_server_query_free(query);
- return FALSE;
- }
- memset(query->nickname, 0, sizeof(query->nickname));
- silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
- silc_free(tmp);
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break;
-
- case SILC_COMMAND_IDENTIFY:
- /* Get IDs if present. Take IDs always instead of names. */
- tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
- if (!tmp) {
-
- /* Try get nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (tmp) {
- /* Get the nickname@server string and parse it */
- if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, query->nickname,
- sizeof(query->nickname),
- query->nick_server,
- sizeof(query->nick_server)))
- silc_server_query_add_error(server, query, 1, 1,
- SILC_STATUS_ERR_BAD_NICKNAME);
-
- /* Check nickname */
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_server_query_free(query);
- return FALSE;
- }
- memset(query->nickname, 0, sizeof(query->nickname));
- silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
- silc_free(tmp);
- }
-
- /* Try get server name */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
- /* Check server name */
- tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
- 256, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_SERVER, 0);
- silc_server_query_free(query);
- return FALSE;
- }
- query->server_name = tmp;
- }
-
- /* Get channel name */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
- if (tmp && tmp_len <= 256) {
- /* Check channel name */
- tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
- 256, &tmp_len);
- if (!tmp) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_CHANNEL, 0);
- silc_server_query_free(query);
- return FALSE;
- }
- query->channel_name = tmp;
- }
-
- if (!query->nickname[0] && !query->server_name && !query->channel_name) {
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- silc_server_query_free(query);
- return FALSE;
- }
-
- } else {
- /* Parse the IDs included in the query */
- query->ids = silc_calloc(argc, sizeof(*query->ids));
-
- for (i = 0; i < argc; i++) {
- tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
- if (!tmp)
- continue;
-
- if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
- silc_server_query_add_error(server, query, 1, i + 5,
- SILC_STATUS_ERR_BAD_CLIENT_ID);
- continue;
- }
-
- /* Normal server must check whether this ID exist, and if not then
- send the query to router, unless done so already */
- if (server->server_type == SILC_SERVER && !query->resolved) {
- if (id.type == SILC_ID_CLIENT) {
- if (!silc_idlist_find_client_by_id(server->local_list,
- &id.u.client_id, TRUE, NULL)) {
- if (idata->conn_type != SILC_CONN_CLIENT ||
- !silc_idlist_find_client_by_id(server->global_list,
- &id.u.client_id, TRUE,
- NULL)) {
- silc_server_query_send_router(server, query);
- for (i = 0; i < query->ids_count; i++)
- silc_free(query->ids[i].id);
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- return FALSE;
- }
- }
- } else {
- /* For now all other ID's except Client ID's are explicitly
- sent to router for resolving. */
- silc_server_query_send_router(server, query);
- for (i = 0; i < query->ids_count; i++)
- silc_free(query->ids[i].id);
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- return FALSE;
- }
- }
-
- if (id.type == SILC_ID_CLIENT)
- query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
- SILC_ID_CLIENT);
- if (id.type == SILC_ID_SERVER)
- query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
- SILC_ID_SERVER);
- if (id.type == SILC_ID_CHANNEL)
- query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
- SILC_ID_CHANNEL);
- query->ids[query->ids_count].id_type = id.type;
- query->ids_count++;
- }
- }
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break;
- }
-
- query->parsed = TRUE;
-
- parsed:
- if (!parse_only && query->nickname) {
- switch (query->querycmd) {
- case SILC_COMMAND_WHOIS:
- case SILC_COMMAND_IDENTIFY:
- /* Check server name. If we are open server and don't yet have
- connection to remote router, create it now. */
- if (query->nick_server[0] && server->config->dynamic_server &&
- !query->resolved) {
- /* If primary router is specified, use that. Otherwise connect
- to the server in nick@server string. */
- SilcServerConfigRouter *router;
- SilcConnectionType type = (server->server_type == SILC_ROUTER ?
- SILC_CONN_SERVER : SILC_CONN_ROUTER);
-
- router = silc_server_config_get_primary_router(server);
- if (router && server->standalone) {
- /* Create connection to primary router */
- SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
- router->host, router->port));
- query->dynamic_prim = TRUE;
- silc_server_create_connection(server, FALSE, TRUE,
- router->host, router->port,
- silc_server_query_connected, query);
- return FALSE;
- } else if (!silc_server_num_sockets_by_remote(server,
- query->nick_server,
- query->nick_server,
- 706, type)) {
- /* Create connection and handle the query after connection */
- SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
- query->nick_server, 706));
- silc_server_create_connection(server, FALSE, TRUE,
- query->nick_server, 706,
- silc_server_query_connected, query);
- return FALSE;
- }
- }
- }
- }
-
- /* Start processing the query information */
- if (!parse_only)
- silc_server_query_process(server, query, TRUE);
-
- return TRUE;
-}
-
-/* Context for holding clients searched by public key. */
-typedef struct {
- SilcClientEntry **clients;
- SilcUInt32 *clients_count;
- SilcBool found;
-} *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
-
-/* SKR find callbcak */
-
-static void silc_server_query_skr_callback(SilcSKR skr,
- SilcSKRFind find,
- SilcSKRStatus status,
- SilcDList keys,
- void *context)
-{
- SilcServerPublicKeyUser uc = context;
- SilcSKRKey key;
-
- if (keys) {
- (*uc->clients) = silc_realloc((*uc->clients),
- sizeof((**uc->clients)) *
- ((*uc->clients_count) +
- silc_dlist_count(keys)));
-
- silc_dlist_start(keys);
- while ((key = silc_dlist_get(keys)))
- (*uc->clients)[(*uc->clients_count)++] = key->key_context;
-
- uc->found = TRUE;
- silc_dlist_uninit(keys);
- }
-
- silc_skr_find_free(find);
-}
-
-/* If clients are set, limit the found clients using the attributes in
- the query. If clients are not set, try to find some clients using
- the attributes */
-
-void silc_server_query_check_attributes(SilcServer server,
- SilcServerQuery query,
- SilcClientEntry **clients,
- SilcUInt32 *clients_count) {
- SilcClientEntry entry;
- SilcAttributePayload attr;
- SilcAttribute attribute;
- SilcAttributeObjPk pk;
- SilcPublicKey publickey, cmp_pubkey;
- SilcPKCSType type;
- SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
- int i;
-
- /* If no clients were found, we only check the attributes
- if the user wasn't searching for nickname/ids */
- if (!(*clients)) {
- no_clients = TRUE;
- if (query->nickname[0] || query->ids_count)
- return;
- }
-
- silc_dlist_start(query->attrs);
- while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
- attribute = silc_attribute_get_attribute(attr);
- switch (attribute) {
-
- case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
- SILC_LOG_DEBUG(("Finding clients by public key attribute"));
-
- if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
- continue;
-
- if (!strcmp(pk.type, "silc-rsa"))
- type = SILC_PKCS_SILC;
- else if (!strcmp(pk.type, "ssh-rsa"))
- type = SILC_PKCS_SSH2;
- else if (!strcmp(pk.type, "x509v3-sign-rsa"))
- type = SILC_PKCS_X509V3;
- else if (!strcmp(pk.type, "pgp-sign-rsa"))
- type = SILC_PKCS_OPENPGP;
- else
- continue;
-
- if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
- &publickey)) {
- silc_free(pk.type);
- silc_free(pk.data);
- continue;
- }
- search_pubkey = TRUE;
-
- /* If no clients were set on calling this function, we just search
- for clients, otherwise we try to limit the clients. */
- if (no_clients) {
- SilcServerPublicKeyUserStruct usercontext;
- SilcSKRFind find;
-
- usercontext.clients = clients;
- usercontext.clients_count = clients_count;
- usercontext.found = FALSE;
-
- find = silc_skr_find_alloc();
- if (!find)
- continue;
-
- silc_skr_find_set_public_key(find, publickey);
- silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
- silc_skr_find(server->repository, server->schedule,
- find, silc_server_query_skr_callback, &usercontext);
-
- if (usercontext.found == TRUE)
- found = TRUE;
- } else {
- for (i = 0; i < *clients_count; i++) {
- entry = (*clients)[i];
-
- if (!entry->data.public_key)
- continue;
-
- if (silc_server_get_public_key_by_client(server, entry,
- &cmp_pubkey)) {
- if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
- found = TRUE;
- continue;
- }
- }
-
- (*clients)[i] = NULL;
- }
- }
- silc_free(pk.type);
- silc_free(pk.data);
- silc_pkcs_public_key_free(publickey);
- break;
- }
- }
-
- if (!found && !query->nickname[0] && !query->ids)
- silc_server_query_add_error(server, query, 2, 0,
- search_pubkey ?
- SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-}
-
-/* Processes the parsed query. This does the actual finding of the
- queried information and prepares for sending reply to the original
- sender of the query command. */
-
-void silc_server_query_process(SilcServer server, SilcServerQuery query,
- SilcBool resolve)
-{
- SilcServerCommandContext cmd = query->cmd;
- SilcIDListData idata = silc_packet_get_context(cmd->sock);
- SilcBool check_global = FALSE;
- void *entry;
- SilcClientEntry *clients = NULL, client_entry;
- SilcChannelEntry *channels = NULL;
- SilcServerEntry *servers = NULL;
- SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
- int i;
-
- SILC_LOG_DEBUG(("Processing %s query",
- silc_get_command_name(query->querycmd)));
-
- /* Check global lists if query is coming from client or we are not
- normal server (we know global information). */
- if (idata->conn_type == SILC_CONN_CLIENT)
- check_global = TRUE;
- else if (server->server_type != SILC_SERVER)
- check_global = TRUE;
-
- if (query->nickname[0]) {
- /* Get all clients matching nickname from local list */
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- query->nickname,
- query->nick_server[0] ?
- query->nick_server : NULL,
- server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- query->nickname,
- query->nick_server[0] ?
- query->nick_server : NULL,
- &clients, &clients_count);
-
- /* Check global list as well */
- if (check_global) {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- query->nickname,
- query->nick_server[0] ?
- query->nick_server : NULL,
- server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- query->nickname,
- query->nick_server[0] ?
- query->nick_server : NULL,
- &clients, &clients_count);
- }
-
- if (!clients)
- silc_server_query_add_error(server, query, 1, 1,
- SILC_STATUS_ERR_NO_SUCH_NICK);
- }
-
- if (query->server_name) {
- /* Find server by name */
- entry = silc_idlist_find_server_by_name(server->local_list,
- query->server_name, TRUE, NULL);
- if (!entry && check_global)
- entry = silc_idlist_find_server_by_name(server->global_list,
- query->server_name, TRUE, NULL);
- if (entry) {
- servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
- servers[servers_count++] = (SilcServerEntry)entry;
- }
-
- if (!servers)
- silc_server_query_add_error(server, query, 1, 2,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- }
-
- if (query->channel_name) {
- /* Find channel by name */
- entry = silc_idlist_find_channel_by_name(server->local_list,
- query->channel_name, NULL);
- if (!entry && check_global)
- entry = silc_idlist_find_channel_by_name(server->global_list,
- query->channel_name, NULL);
- if (entry) {
- channels = silc_realloc(channels, sizeof(*channels) *
- (channels_count + 1));
- channels[channels_count++] = (SilcChannelEntry)entry;
- }
-
- if (!channels)
- silc_server_query_add_error(server, query, 1, 3,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- }
-
- if (query->ids_count) {
- /* Find entries by the queried IDs */
- for (i = 0; i < query->ids_count; i++) {
- void *id = query->ids[i].id;
- if (!id)
- continue;
-
- switch (query->ids[i].id_type) {
-
- case SILC_ID_CLIENT:
- /* Get client entry */
- entry = silc_idlist_find_client_by_id(server->local_list,
- id, TRUE, NULL);
- if (!entry && check_global)
- entry = silc_idlist_find_client_by_id(server->global_list,
- id, TRUE, NULL);
- if (!entry) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- continue;
- }
-
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = (SilcClientEntry)entry;
- break;
-
- case SILC_ID_SERVER:
- /* Get server entry */
- entry = silc_idlist_find_server_by_id(server->local_list,
- id, TRUE, NULL);
- if (!entry && check_global)
- entry = silc_idlist_find_server_by_id(server->global_list,
- id, TRUE, NULL);
- if (!entry) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
- continue;
- }
-
- servers = silc_realloc(servers, sizeof(*servers) *
- (servers_count + 1));
- servers[servers_count++] = (SilcServerEntry)entry;
- break;
-
- case SILC_ID_CHANNEL:
- /* Get channel entry */
- entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
- if (!entry && check_global)
- entry = silc_idlist_find_channel_by_id(server->global_list, id,
- NULL);
- if (!entry) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
- continue;
- }
-
- channels = silc_realloc(channels, sizeof(*channels) *
- (channels_count + 1));
- channels[channels_count++] = (SilcChannelEntry)entry;
- break;
-
- default:
- break;
- }
- }
- }
-
- /* Check the attributes to narrow down the search by using them. */
- if (query->attrs)
- silc_server_query_check_attributes(server, query, &clients,
- &clients_count);
-
- SILC_LOG_DEBUG(("Querying %d clients", clients_count));
- SILC_LOG_DEBUG(("Querying %d servers", servers_count));
- SILC_LOG_DEBUG(("Querying %d channels", channels_count));
-
- /* If nothing was found, then just send the errors */
- if (!clients && !channels && !servers) {
- silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
- return;
- }
-
- /* If caller does not want us to resolve anything (has resolved already)
- then just continue with sending the reply */
- if (!resolve) {
- silc_server_query_send_reply(server, query, clients, clients_count,
- servers, servers_count, channels,
- channels_count);
- silc_free(clients);
- silc_free(servers);
- silc_free(channels);
- return;
- }
-
- /* Now process all found information and if necessary do some more
- resolving. */
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- for (i = 0; i < clients_count; i++) {
- client_entry = clients[i];
-
- /* Check if cannot query this anyway, so take next one */
- if (!client_entry ||
- !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
- continue;
-
- /* If Requested Attributes is set then we always resolve the client
- information, if not then check whether the entry is complete or not
- and decide whether we need to resolve or not. */
- if (!query->attrs) {
-
- /* Even if nickname and stuff are present, we may need to resolve
- the entry */
- if (client_entry->nickname && client_entry->username &&
- client_entry->userinfo) {
- /* Check if cannot query this anyway, so take next one */
- if (!client_entry->router)
- continue;
-
- /* If we are router, client is local to us, or client is on channel
- we do not need to resolve the client information. */
- if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
- || silc_hash_table_count(client_entry->channels) ||
- query->resolved)
- continue;
- }
- }
-
- /* Remove the NOATTR status periodically */
- if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
- client_entry->updated + 600 < time(NULL))
- client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
-
- /* When requested attributes is present and local client is detached
- we cannot send the command to the client, we'll reply on behalf of
- the client instead. */
- if (query->attrs && SILC_IS_LOCAL(client_entry) &&
- (client_entry->mode & SILC_UMODE_DETACHED ||
- client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
- continue;
-
- /* If attributes are present in query, and in the entry and we have
- done resolvings already we don't need to resolve anymore */
- if (query->resolved && query->attrs && client_entry->attrs)
- continue;
-
- /* Resolve the detailed client information. If client is local we
- know that attributes were present and we will resolve directly
- from the client. Otherwise resolve from client's owner. */
- silc_server_query_resolve(server, query,
- (SILC_IS_LOCAL(client_entry) ?
- client_entry->connection :
- client_entry->router->connection),
- client_entry);
- }
- break;
-
- case SILC_COMMAND_WHOWAS:
- for (i = 0; i < clients_count; i++) {
- client_entry = clients[i];
-
- /* Check if cannot query this anyway, so take next one */
- if (!client_entry || !client_entry->router ||
- client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
- continue;
-
- /* If both nickname and username are present no resolving is needed */
- if (client_entry->nickname && client_entry->username)
- continue;
-
- /* Resolve the detailed client information */
- silc_server_query_resolve(server, query,
- client_entry->router->connection,
- client_entry);
- }
- break;
-
- case SILC_COMMAND_IDENTIFY:
- for (i = 0; i < clients_count; i++) {
- client_entry = clients[i];
-
- /* Check if cannot query this anyway, so take next one */
- if (!client_entry || !client_entry->router ||
- !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
- continue;
-
- /* Even if nickname is present, we may need to resolve the entry */
- if (client_entry->nickname) {
-
- /* If we are router, client is local to us, or client is on channel
- we do not need to resolve the client information. */
- if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
- || silc_hash_table_count(client_entry->channels) ||
- query->resolved)
- continue;
- }
-
- /* Resolve the detailed client information */
- silc_server_query_resolve(server, query,
- client_entry->router->connection,
- client_entry);
- }
- break;
- }
-
- if (!query->queries_count)
- /* If we didn't have to do any resolving, continue with sending the
- command reply to the original sender. */
- silc_server_query_send_reply(server, query, clients, clients_count,
- servers, servers_count, channels,
- channels_count);
- else
- /* Now actually send the resolvings we gathered earlier */
- silc_server_query_resolve(server, query, NULL, NULL);
-
- silc_free(clients);
- silc_free(servers);
- silc_free(channels);
-}
-
-/* Resolve the detailed information for the `client_entry'. Only client
- information needs to be resolved for being incomplete. Each incomplete
- client entry calls this function to do the resolving. */
-
-void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
- SilcPacketStream sock,
- SilcClientEntry client_entry)
-{
- SilcServerCommandContext cmd = query->cmd;
- SilcServerQueryList r = NULL;
- SilcBuffer idp;
- unsigned char *tmp;
- SilcUInt32 len;
- SilcUInt16 ident;
- int i;
-
- if (!sock && client_entry)
- return;
-
- /* If arguments are NULL we will now actually send the resolvings
- that earlier has been gathered by calling this function. */
- if (!sock && !client_entry) {
- SilcBuffer res_cmd;
-
- SILC_LOG_DEBUG(("Sending the resolvings"));
-
- /* WHOWAS resolving has been done at the same time this function
- was called to add the resolving for WHOWAS, so just return. */
- if (query->querycmd == SILC_COMMAND_WHOWAS)
- return;
-
- for (i = 0; i < query->querylist_count; i++) {
- r = &query->querylist[i];
-
- /* If Requested Attributes were present put them to this resolving */
- if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
- len = r->argc + 1;
- r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
- r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
- r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
-
- tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
- if (tmp)
- r->arg[r->argc] = silc_memdup(tmp, len);
- r->arg_lens[r->argc] = len;
- r->arg_types[r->argc] = 3;
- r->argc++;
- }
-
- /* Statistics */
- server->stat.commands_sent++;
-
- /* Send WHOIS command */
- res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
- r->argc, r->arg, r->arg_lens,
- r->arg_types, r->ident);
- silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
- res_cmd->data, silc_buffer_len(res_cmd));
- silc_buffer_free(res_cmd);
-
- /* Reprocess this packet after received reply */
- if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
- r->ident,
- silc_server_query_resolve_reply,
- query, r->timeout))
- query->queries_left++;
- }
-
- /* Cleanup this temporary context */
- for (i = 0; i < query->querylist_count; i++) {
- int k;
- for (k = 0; k < query->querylist[i].argc; k++)
- silc_free(query->querylist[i].arg[k]);
- silc_free(query->querylist[i].arg);
- silc_free(query->querylist[i].arg_lens);
- silc_free(query->querylist[i].arg_types);
- }
- silc_free(query->querylist);
- query->querylist = NULL;
- query->querylist_count = 0;
- return;
- }
-
- SILC_LOG_DEBUG(("Resolving client information"));
-
- if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
- /* The entry is being resolved by some other external query already.
- Attach to that query instead of resolving again. */
- ident = client_entry->resolve_cmd_ident;
- if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
- silc_server_query_resolve_reply, query))
- query->queries_left++;
- } else {
- /* This entry will be resolved */
- ident = ++server->cmd_ident;
-
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- case SILC_COMMAND_IDENTIFY:
- /* Take existing query context if exist for this connection */
- for (i = 0; i < query->querylist_count; i++)
- if (query->querylist[i].sock == sock) {
- r = &query->querylist[i];
- break;
- }
-
- if (!r) {
- /* Allocate new temp query list context */
- query->querylist = silc_realloc(query->querylist,
- sizeof(*query->querylist) *
- (query->querylist_count + 1));
- r = &query->querylist[query->querylist_count];
- query->querylist_count++;
- memset(r, 0, sizeof(*r));
- r->sock = sock;
- r->ident = ident;
- if (SILC_IS_LOCAL(client_entry))
- r->timeout = 3;
- }
-
- len = r->argc + 1;
- r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
- r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
- r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
-
- /* Add the client entry to be resolved */
- idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
- r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
- r->arg_lens[r->argc] = silc_buffer_len(idp);
- r->arg_types[r->argc] = r->argc + 4;
- r->argc++;
- silc_buffer_free(idp);
-
- break;
-
- case SILC_COMMAND_WHOWAS:
- /* We must send WHOWAS command since it's the only the way of
- resolving clients that are not present in the network anymore. */
- silc_server_send_command(server, sock, query->querycmd, ident, 1,
- 1, query->nickname, strlen(query->nickname));
- if (silc_server_command_pending(server, query->querycmd, ident,
- silc_server_query_resolve_reply, query))
- query->queries_left++;
- break;
- }
- }
-
- /* Mark the entry as being resolved */
- client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
- client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
- client_entry->resolve_cmd_ident = ident;
- client_entry->updated = time(NULL);
-
- /* Save the queried ID, which we will reprocess after we get this and
- all other queries back. */
- query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
- (query->queries_count + 1));
- if (query->queries) {
- i = query->queries_count;
- query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
- query->queries[i].id_type = SILC_ID_CLIENT;
- query->queries[i].ident = ident;
- query->queries_count++;
- }
-}
-
-/* Reply callback called after one resolving has been completed. If
- all resolvings has been received then we will continue with sending
- the command reply to the original sender of the query. */
-
-void silc_server_query_resolve_reply(void *context, void *reply)
-{
- SilcServerQuery query = context;
- SilcServer server = query->cmd->server;
- SilcServerCommandReplyContext cmdr = reply;
- SilcUInt16 ident = cmdr->ident;
- SilcStatus error = SILC_STATUS_OK;
- SilcServerQueryID id = NULL;
- SilcClientEntry client_entry;
- int i;
-
- /* One less query left */
- query->queries_left--;
-
- silc_command_get_status(cmdr->payload, NULL, &error);
- SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
- query->queries_left, error));
-
- /* If no error then skip to other stuff */
- if (error == SILC_STATUS_OK)
- goto out;
-
- /* Error occurred during resolving */
-
- /* Find the resolved client ID */
- for (i = 0; i < query->queries_count; i++) {
- if (query->queries[i].ident != ident)
- continue;
-
- id = &query->queries[i];
-
- if (error == SILC_STATUS_ERR_TIMEDOUT) {
-
- /* If timeout occurred for local entry when resolving attributes
- mark that this client doesn't support attributes in WHOIS. This
- assures we won't send the request again to the client. */
- if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
- client_entry = silc_idlist_find_client_by_id(server->local_list,
- id->id, TRUE, NULL);
- SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
- silc_id_render(id->id, SILC_ID_CLIENT)));
- if (client_entry && SILC_IS_LOCAL(client_entry)) {
- client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
- client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
- continue;
- }
- }
-
- /* Remove the RESOLVING status from the client entry */
- if (query->querycmd != SILC_COMMAND_WHOWAS) {
- client_entry = silc_idlist_find_client_by_id(server->local_list,
- id->id, TRUE, NULL);
- if (!client_entry)
- client_entry = silc_idlist_find_client_by_id(server->global_list,
- id->id, TRUE, NULL);
- if (client_entry)
- client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
- }
- }
- }
-
- out:
-
- /* If there are queries left then wait for them */
- if (query->queries_left)
- return;
-
- SILC_LOG_DEBUG(("Reprocess the query"));
-
- /* If the original command caller has gone away, just stop. */
- if (!silc_packet_stream_is_valid(query->cmd->sock)) {
- SILC_LOG_DEBUG(("Original command caller vanished"));
- silc_server_query_free(query);
- return;
- }
-
- /* We have received all queries. Now re-search all information required
- to complete this query. Reason we cannot save the values found in
- the first search is that SilcClientEntry, SilcServerEntry and
- SilcChannelEntry pointers may become invalid while we were waiting
- for these resolvings. */
- silc_server_query_process(server, query, FALSE);
-}
-
-/* Send the reply to the original query. If arguments are NULL then this
- sends only the errors that has occurred during the processing of the
- query. This sends the errors always after sending all the found
- information. The query is over after this function returns and the
- `query' will become invalid. This is called only after all informations
- has been resolved. This means that if something is not found or is
- incomplete in this function we were unable to resolve the information
- or it does not exist at all. */
-
-void silc_server_query_send_reply(SilcServer server,
- SilcServerQuery query,
- SilcClientEntry *clients,
- SilcUInt32 clients_count,
- SilcServerEntry *servers,
- SilcUInt32 servers_count,
- SilcChannelEntry *channels,
- SilcUInt32 channels_count)
-{
- SilcServerCommandContext cmd = query->cmd;
- SilcIDListData idata = silc_packet_get_context(cmd->sock);
- SilcUInt16 ident = silc_command_get_ident(cmd->payload);
- SilcStatus status;
- unsigned char *tmp;
- SilcUInt32 len;
- SilcBuffer idp;
- int i, k, valid_count;
- char nh[384], uh[384];
- SilcBool sent_reply = FALSE;
-
- SILC_LOG_DEBUG(("Sending reply to query"));
- SILC_LOG_DEBUG(("Sending %d clients", clients_count));
- SILC_LOG_DEBUG(("Sending %d servers", servers_count));
- SILC_LOG_DEBUG(("Sending %d channels", channels_count));
- SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
-
- status = SILC_STATUS_OK;
-
- /* Send clients */
- if (clients_count) {
- SilcClientEntry entry;
- SilcPacketStream hsock;
-
- /* Mark all invalid entries */
- for (i = 0, valid_count = 0; i < clients_count; i++) {
- entry = clients[i];
- if (!entry)
- continue;
-
- switch (query->querycmd) {
- case SILC_COMMAND_WHOIS:
- if (!entry->nickname || !entry->username || !entry->userinfo ||
- !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- /* When querying by ID, every "unfound" entry must cause error */
- if (query->ids)
- silc_server_query_add_error_id(server, query,
- SILC_STATUS_ERR_TIMEDOUT,
- entry->id, SILC_ID_CLIENT);
- clients[i] = NULL;
- continue;
- }
- break;
-
- case SILC_COMMAND_IDENTIFY:
- if (!entry->nickname ||
- !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- /* When querying by ID, every "unfound" entry must cause error */
- if (query->ids)
- silc_server_query_add_error_id(server, query,
- SILC_STATUS_ERR_TIMEDOUT,
- entry->id, SILC_ID_CLIENT);
- clients[i] = NULL;
- continue;
- }
- break;
-
- case SILC_COMMAND_WHOWAS:
- if (!entry->nickname || !entry->username ||
- entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
- clients[i] = NULL;
- continue;
- }
- break;
- }
- valid_count++;
- }
-
- /* Start processing found clients */
- status = SILC_STATUS_OK;
- if (valid_count > 1)
- status = SILC_STATUS_LIST_START;
-
- /* Now do the sending of valid entries */
- k = 0;
- for (i = 0; i < clients_count && valid_count; i++) {
- entry = clients[i];
- if (!entry)
- continue;
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (valid_count > 1 && k == valid_count - 1
- && !servers_count && !channels_count && !query->errors_count)
- status = SILC_STATUS_LIST_END;
- if (query->reply_count && k - 1 == query->reply_count)
- status = SILC_STATUS_LIST_END;
-
- SILC_LOG_DEBUG(("%s: client %s",
- (status == SILC_STATUS_OK ? " OK" :
- status == SILC_STATUS_LIST_START ? "START" :
- status == SILC_STATUS_LIST_ITEM ? " ITEM" :
- status == SILC_STATUS_LIST_END ? " END" :
- " : "), entry->nickname));
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- memset(nh, 0, sizeof(nh));
-
- silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- silc_strncat(nh, sizeof(nh), "@", 1);
- if (entry->servername) {
- silc_strncat(nh, sizeof(nh), entry->servername,
- strlen(entry->servername));
- } else {
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- silc_strncat(nh, sizeof(nh), entry->router ?
- entry->router->server_name :
- server->server_name, len);
- }
- }
-
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- {
- unsigned char idle[4], mode[4];
- unsigned char *fingerprint, fempty[20], *attrs = NULL;
- SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
-
- memset(fempty, 0, sizeof(fempty));
- memset(idle, 0, sizeof(idle));
- memset(uh, 0, sizeof(uh));
-
- silc_strncat(uh, sizeof(uh), entry->username,
- strlen(entry->username));
- if (!strchr(entry->username, '@') && entry->connection) {
- hsock = entry->connection;
- silc_strncat(uh, sizeof(uh), "@", 1);
- silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
- NULL, (const char **)&tmp, NULL, NULL);
- silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
- }
-
- if (idata->conn_type == SILC_CONN_CLIENT)
- channels =
- silc_server_get_client_channel_list(server, entry, FALSE,
- FALSE, &umode_list);
- else
- channels =
- silc_server_get_client_channel_list(server, entry, TRUE,
- TRUE, &umode_list);
-
- if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
- fingerprint = entry->data.fingerprint;
- else
- fingerprint = NULL;
-
- SILC_PUT32_MSB(entry->mode, mode);
- if (entry->connection)
- SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
-
- /* If Requested Attribute were present, and we do not have the
- attributes we will reply to them on behalf of the client. */
- len = 0;
- if (query->attrs) {
- if (!entry->attrs && SILC_IS_LOCAL(entry)) {
- tmpattrs = silc_server_query_reply_attrs(server, query, entry);
- entry->attrs = silc_buffer_steal(tmpattrs, &len);
- entry->attrs_len = len;
- silc_buffer_free(tmpattrs);
- }
- attrs = entry->attrs;
- len = entry->attrs_len;
- }
-
- /* Send command reply */
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- status, 0, ident, 10,
- 2, idp->data, silc_buffer_len(idp),
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo),
- 6, channels ? channels->data : NULL,
- channels ? silc_buffer_len(channels)
- : 0,
- 7, mode, 4,
- 8, idle, 4,
- 9, fingerprint,
- fingerprint ? 20 : 0,
- 10, umode_list ? umode_list->data :
- NULL, umode_list ?
- silc_buffer_len(umode_list) :
- 0, 11, attrs, len);
-
- sent_reply = TRUE;
-
- /* For now we always delete Requested Attributes, unless the client
- is detached, in which case we don't want to reconstruct the
- same data everytime */
- if (!(entry->mode & SILC_UMODE_DETACHED) &&
- !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
- silc_free(entry->attrs);
- entry->attrs = NULL;
- }
-
- if (channels)
- silc_buffer_free(channels);
- if (umode_list) {
- silc_buffer_free(umode_list);
- umode_list = NULL;
- }
- }
- break;
-
- case SILC_COMMAND_IDENTIFY:
- if (!entry->username) {
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- status, 0, ident, 2,
- 2, idp->data, silc_buffer_len(idp),
- 3, nh, strlen(nh));
- sent_reply = TRUE;
- } else {
- memset(uh, 0, sizeof(uh));
- silc_strncat(uh, sizeof(uh), entry->username,
- strlen(entry->username));
- if (!strchr(entry->username, '@') && entry->connection) {
- hsock = entry->connection;
- silc_strncat(uh, sizeof(uh), "@", 1);
- silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
- NULL, (const char **)&tmp,
- NULL, NULL);
- silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
- }
-
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- status, 0, ident, 3,
- 2, idp->data, silc_buffer_len(idp),
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
- sent_reply = TRUE;
- }
- break;
-
- case SILC_COMMAND_WHOWAS:
- memset(uh, 0, sizeof(uh));
- silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@'))
- silc_strncat(uh, sizeof(uh), "@-private-", 10);
-
- /* Send command reply */
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- status, 0, ident, 4,
- 2, idp->data, silc_buffer_len(idp),
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- entry->userinfo ?
- strlen(entry->userinfo) : 0);
- sent_reply = TRUE;
- break;
- }
-
- silc_buffer_free(idp);
-
- if (status == SILC_STATUS_LIST_END)
- break;
- k++;
- }
-
- if (k == 0) {
- /* Not one valid entry was found, send error. If nickname was used
- in query send error based on that, otherwise the query->errors
- already includes proper errors. */
- if (query->nickname[0] || (!query->ids && query->attrs))
- silc_server_query_add_error(server, query, 1, 1,
- SILC_STATUS_ERR_NO_SUCH_NICK);
-
- /* Make sure some error is sent */
- if (!query->errors_count && !servers_count && !channels_count)
- silc_server_query_add_error(server, query, 2, 0,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- }
- }
-
- /* Send servers */
- if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
- SilcServerEntry entry;
-
- if (status == SILC_STATUS_OK && servers_count > 1)
- status = SILC_STATUS_LIST_START;
-
- k = 0;
- for (i = 0; i < servers_count; i++) {
- entry = servers[i];
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
- !query->errors_count)
- status = SILC_STATUS_LIST_END;
- if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
- !query->errors_count)
- status = SILC_STATUS_LIST_END;
- if (query->reply_count && k - 1 == query->reply_count)
- status = SILC_STATUS_LIST_END;
-
- SILC_LOG_DEBUG(("%s: server %s",
- (status == SILC_STATUS_OK ? " OK" :
- status == SILC_STATUS_LIST_START ? "START" :
- status == SILC_STATUS_LIST_ITEM ? " ITEM" :
- status == SILC_STATUS_LIST_END ? " END" :
- " : "),
- entry->server_name ? entry->server_name : ""));
-
- /* Send command reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
- silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
- status, 0, ident, 2,
- 2, idp->data, silc_buffer_len(idp),
- 3, entry->server_name,
- entry->server_name ?
- strlen(entry->server_name) : 0);
- silc_buffer_free(idp);
- sent_reply = TRUE;
-
- if (status == SILC_STATUS_LIST_END)
- break;
- k++;
- }
- }
-
- /* Send channels */
- if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
- SilcChannelEntry entry;
-
- if (status == SILC_STATUS_OK && channels_count > 1)
- status = SILC_STATUS_LIST_START;
-
- k = 0;
- for (i = 0; i < channels_count; i++) {
- entry = channels[i];
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (channels_count == 1 && status != SILC_STATUS_OK &&
- !query->errors_count)
- status = SILC_STATUS_LIST_END;
- if (channels_count > 1 && k == channels_count - 1 &&
- !query->errors_count)
- status = SILC_STATUS_LIST_END;
- if (query->reply_count && k - 1 == query->reply_count)
- status = SILC_STATUS_LIST_END;
-
- SILC_LOG_DEBUG(("%s: channel %s",
- (status == SILC_STATUS_OK ? " OK" :
- status == SILC_STATUS_LIST_START ? "START" :
- status == SILC_STATUS_LIST_ITEM ? " ITEM" :
- status == SILC_STATUS_LIST_END ? " END" :
- " : "),
- entry->channel_name ? entry->channel_name : ""));
-
- /* Send command reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
- silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
- status, 0, ident, 2,
- 2, idp->data, silc_buffer_len(idp),
- 3, entry->channel_name,
- entry->channel_name ?
- strlen(entry->channel_name) : 0);
- silc_buffer_free(idp);
- sent_reply = TRUE;
-
- if (status == SILC_STATUS_LIST_END)
- break;
- k++;
- }
- }
-
- /* Send errors */
- if (query->errors_count) {
- int type;
-
- if (status == SILC_STATUS_OK && query->errors_count > 1)
- status = SILC_STATUS_LIST_START;
-
- k = 0;
- for (i = 0; i < query->errors_count; i++) {
- idp = NULL;
-
- /* Take error argument */
- if (query->errors[i].type == 1) {
- /* Take from sent arguments */
- len = 0;
- tmp = silc_argument_get_arg_type(cmd->args,
- query->errors[i].index, &len);
- type = 2;
- } else if (query->errors[i].type == 2) {
- /* No argument */
- len = 0;
- tmp = NULL;
- type = 0;
- } else if (!query->errors[i].id) {
- /* Take from query->ids */
- idp =
- silc_id_payload_encode(query->ids[query->errors[i].index].id,
- query->ids[query->errors[k].index].id_type);
- tmp = idp->data;
- len = silc_buffer_len(idp);
- type = 2;
- } else {
- /* Take added ID. */
- idp = silc_id_payload_encode(query->errors[i].id,
- query->errors[k].id_type);
- tmp = idp->data;
- len = silc_buffer_len(idp);
- type = 2;
- }
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (query->errors_count == 1 && status != SILC_STATUS_OK)
- status = SILC_STATUS_LIST_END;
- if (query->errors_count > 1 && k == query->errors_count - 1)
- status = SILC_STATUS_LIST_END;
- if (query->reply_count && k - 1 == query->reply_count)
- status = SILC_STATUS_LIST_END;
-
- SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
- (status == SILC_STATUS_OK ? " OK" :
- status == SILC_STATUS_LIST_START ? "START" :
- status == SILC_STATUS_LIST_ITEM ? " ITEM" :
- status == SILC_STATUS_LIST_END ? " END" :
- " : "),
- silc_get_status_message(query->errors[i].error),
- query->errors[i].error));
-
-#if 1 /* XXX Backwards compatibility. Remove in 1.0. */
- if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
- /* Send error */
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- (status == SILC_STATUS_OK ?
- query->errors[i].error : status),
- (status == SILC_STATUS_OK ?
- 0 : query->errors[i].error), ident, 2,
- type, tmp, len,
- 3, tmp, len);
- else
-#endif
- /* Send error */
- silc_server_send_command_reply(server, cmd->sock, query->querycmd,
- (status == SILC_STATUS_OK ?
- query->errors[i].error : status),
- (status == SILC_STATUS_OK ?
- 0 : query->errors[i].error), ident, 1,
- type, tmp, len);
-
- silc_buffer_free(idp);
- sent_reply = TRUE;
-
- if (status == SILC_STATUS_LIST_END)
- break;
- k++;
- }
- }
-
- if (!sent_reply)
- SILC_LOG_ERROR(("BUG: Query did not send anything"));
-
- /* Cleanup */
- silc_server_query_free(query);
-}
-
-/* This routine is used to reply to Requested Attributes in WHOIS on behalf
- of the client since we were unable to resolve them from the client.
- Either client does not support Requested Attributes or isn't replying
- to them like it should. */
-
-SilcBuffer silc_server_query_reply_attrs(SilcServer server,
- SilcServerQuery query,
- SilcClientEntry client_entry)
-{
- SilcBuffer buffer = NULL;
- SilcAttribute attribute;
- SilcAttributePayload attr;
- SilcAttributeObjPk pk;
- SilcAttributeObjService service;
- unsigned char *tmp;
- unsigned char sign[2048 + 1];
- SilcUInt32 sign_len;
-
- SILC_LOG_DEBUG(("Constructing Requested Attributes"));
-
- /* Go through all requested attributes */
- silc_dlist_start(query->attrs);
- while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
- attribute = silc_attribute_get_attribute(attr);
- switch (attribute) {
-
- case SILC_ATTRIBUTE_SERVICE:
- /* Put SERVICE. Put only SILC service. */
- memset(&service, 0, sizeof(service));
- service.port = (server->config->server_info->primary ?
- server->config->server_info->primary->port : SILC_PORT);
- silc_strncat(service.address, sizeof(service.address),
- server->server_name, strlen(server->server_name));
- service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
- if (client_entry->connection)
- service.idle = time(NULL) - client_entry->data.last_receive;
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_VALID,
- &service, sizeof(service));
- if (!buffer)
- return NULL;
- break;
-
- case SILC_ATTRIBUTE_STATUS_MOOD:
- /* Put STATUS_MOOD */
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_VALID,
- (void *)
- SILC_ATTRIBUTE_MOOD_NORMAL,
- sizeof(SilcUInt32));
- if (!buffer)
- return NULL;
- break;
-
- case SILC_ATTRIBUTE_STATUS_FREETEXT:
- /* Put STATUS_FREETEXT. We just tell in the message that we are
- replying on behalf of the client. */
- tmp =
- "This information was provided by the server on behalf of the user";
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_VALID,
- tmp, strlen(tmp));
- if (!buffer)
- return NULL;
- break;
-
- case SILC_ATTRIBUTE_PREFERRED_CONTACT:
- /* Put PREFERRED_CONTACT */
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_VALID,
- (void *)
- SILC_ATTRIBUTE_CONTACT_CHAT,
- sizeof(SilcUInt32));
- if (!buffer)
- return NULL;
- break;
-
- case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
- /* Put USER_PUBLIC_KEY */
- if (client_entry->data.public_key) {
- pk.type = "silc-rsa";
- pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
- &pk.data_len);
- buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
- SILC_ATTRIBUTE_FLAG_VALID :
- SILC_ATTRIBUTE_FLAG_INVALID,
- &pk, sizeof(pk));
- silc_free(pk.data);
- if (!buffer)
- return NULL;
- break;
- }
-
- /* No public key available */
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_INVALID,
- NULL, 0);
- if (!buffer)
- return NULL;
- break;
-
- default:
- /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
- if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
- attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
- break;
-
- /* For other attributes we cannot reply so mark it invalid */
- buffer = silc_attribute_payload_encode(buffer, attribute,
- SILC_ATTRIBUTE_FLAG_INVALID,
- NULL, 0);
- if (!buffer)
- return NULL;
- break;
- }
- }
-
- /* Always put our public key. This assures that we send at least
- something valid back always. */
- pk.type = "silc-rsa";
- pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
- buffer = silc_attribute_payload_encode(buffer,
- SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
- pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
- SILC_ATTRIBUTE_FLAG_INVALID,
- &pk, sizeof(pk));
- silc_free(pk.data);
- if (!buffer)
- return NULL;
-
- /* Finally compute the digital signature of all the data we provided
- as an indication that we provided rightfull information, and this
- also authenticates our public key. */
- if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
- sizeof(sign) -1 &&
- silc_pkcs_sign(server->private_key, buffer->data,
- silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
- TRUE, server->sha1hash)) {
- pk.type = NULL;
- pk.data = sign;
- pk.data_len = sign_len;
- buffer =
- silc_attribute_payload_encode(buffer,
- SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
- SILC_ATTRIBUTE_FLAG_VALID,
- &pk, sizeof(pk));
- }
- if (!buffer)
- return NULL;
-
- return buffer;
-}
-
-/* Find client by the Client ID indicated by the `client_id', and if not
- found then query it by using WHOIS command. The client information
- is also resolved if the cached information is incomplete or if the
- `always_resolve' is set to TRUE. The indication whether requested
- client was being resolved is saved into `resolved'. If the client
- is not being resolved its entry is returned by this function. NULL
- is returned if client is resolved. */
-
-SilcClientEntry silc_server_query_client(SilcServer server,
- const SilcClientID *client_id,
- SilcBool always_resolve,
- SilcBool *resolved)
-{
- SilcClientEntry client;
-
- SILC_LOG_DEBUG(("Resolving client by client ID"));
-
- if (resolved)
- *resolved = FALSE;
-
- client = silc_idlist_find_client_by_id(server->local_list,
- (SilcClientID *)client_id,
- TRUE, NULL);
- if (!client) {
- client = silc_idlist_find_client_by_id(server->global_list,
- (SilcClientID *)client_id,
- TRUE, NULL);
- if (!client && server->server_type == SILC_ROUTER)
- return NULL;
- }
-
- if (!client && server->standalone)
- return NULL;
-
- if (!client || !client->nickname || !client->username ||
- always_resolve) {
- SilcBuffer buffer, idp;
-
- /* Statistics */
- server->stat.commands_sent++;
-
- if (client) {
- client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
- client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
- client->resolve_cmd_ident = ++server->cmd_ident;
- }
-
- idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
- server->cmd_ident, 1,
- 4, idp->data,
- silc_buffer_len(idp));
- silc_server_packet_send(server, client ? client->router->connection :
- SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_COMMAND, 0,
- buffer->data, silc_buffer_len(buffer));
- silc_buffer_free(idp);
- silc_buffer_free(buffer);
-
- if (resolved)
- *resolved = TRUE;
-
- return NULL;
- }
-
- return client;
-}