/*
- server_query.c
+ server_query.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 Pekka Riikonen
+ 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
#include "server_internal.h"
typedef struct {
- SilcSocketConnection sock; /* Connection of this query */
+ SilcPacketStream sock; /* Connection of this query */
unsigned char **arg; /* Query argument */
SilcUInt32 *arg_lens; /* Query argument lengths */
SilcUInt32 *arg_types; /* Query argument types */
typedef struct {
void *id; /* ID */
SilcIdType id_type; /* ID type */
- SilcUInt16 index; /* Index to IDs */
- unsigned int from_cmd : 1; /* TRUE if `index' is from command args,
- otherwise from query->ids */
+ 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; /* Queried nickname */
- char *nick_server; /* Queried nickname's server */
- char *server_name; /* Queried server name */
- char *channel_name; /* Queried channel name */
+ 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 */
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
+ 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,
- bool from_cmd,
+ SilcUInt32 type,
SilcUInt32 index,
SilcStatus error);
void silc_server_query_add_error_id(SilcServer server,
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);
-void silc_server_query_parse(SilcServer server, SilcServerQuery query);
+SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query,
+ SilcBool parse_only);
void silc_server_query_process(SilcServer server, SilcServerQuery query,
- bool resolve);
+ SilcBool resolve);
void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcClientEntry client_entry);
void silc_server_query_resolve_reply(void *context, void *reply);
void silc_server_query_send_reply(SilcServer server,
silc_free(query->queries[i].id);
silc_free(query->queries);
- silc_free(query->nickname);
- silc_free(query->nick_server);
silc_free(query->server_name);
silc_free(query->channel_name);
/* Send the command reply with error */
silc_server_send_command_reply(server, query->cmd->sock,
- query->querycmd, error, 0,
+ query->querycmd, error, 0,
silc_command_get_ident(query->cmd->payload),
argc, data_type, data, data_len);
va_end(va);
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 `from_cmd'. */
+ 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,
- bool from_cmd,
+ SilcUInt32 type,
SilcUInt32 index,
SilcStatus error)
{
if (!query->errors)
return;
query->errors[query->errors_count].index = index;
- query->errors[query->errors_count].from_cmd = from_cmd;
+ 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;
if (!query->errors)
return;
query->errors[query->errors_count].index = 0;
- query->errors[query->errors_count].from_cmd = FALSE;
+ 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;
to the entity who sent this query to us automatically. Returns
TRUE if the query is being processed or FALSE on error. */
-bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
- SilcServerCommandContext cmd)
+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)));
- query = silc_calloc(1, sizeof(*query));
- query->querycmd = querycmd;
- query->cmd = silc_server_command_dup(cmd);
+ 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, send it
- directly to router. */
- if (server->server_type == SILC_SERVER && !server->standalone &&
+ /* 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, 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;
}
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;
}
}
/* Now parse the request */
- silc_server_query_parse(server, query);
+ 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. */
SilcBuffer tmpbuf;
SilcUInt16 old_ident;
- SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
+ 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,
- SILC_PRIMARY_ROUTE(server),
+ silc_server_packet_send(server, query->router,
SILC_PACKET_COMMAND, 0,
- tmpbuf->data, tmpbuf->len, TRUE);
+ tmpbuf->data, silc_buffer_len(tmpbuf));
silc_command_set_ident(query->cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
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, buffer->len, FALSE);
+ 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);
+ silc_server_query_parse(server, query, FALSE);
}
/* Parse the command query and start processing the queries in detail. */
-void silc_server_query_parse(SilcServer server, SilcServerQuery query)
+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);
- void *id;
- SilcIdType id_type;
+ 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) {
+ 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;
+ return FALSE;
}
/* Get the nickname@server string and parse it */
- if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+ 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;
+ 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 {
if (!tmp)
continue;
- id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
- if (!id || id_type != SILC_ID_CLIENT) {
- silc_server_query_add_error(server, query, TRUE, i + 4,
+ 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;
}
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, TRUE, NULL)) {
- if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+ &id.u.client_id, TRUE, NULL)) {
+ if (idata->conn_type != SILC_CONN_CLIENT ||
!silc_idlist_find_client_by_id(server->global_list,
- id, TRUE, NULL)) {
+ &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;
- silc_free(id);
- return;
+ return FALSE;
}
}
}
- query->ids[query->ids_count].id = id;
+ 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++;
}
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
if (tmp && tmp_len == sizeof(SilcUInt32))
SILC_GET32_MSB(query->reply_count, tmp);
-
- /* Get requested attributes if set */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
- if (tmp && 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- cmd->sock->user_data)
- ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
- }
- break;
+ break;
case SILC_COMMAND_WHOWAS:
/* Get nickname */
silc_server_query_send_error(server, query,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
silc_server_query_free(query);
- return;
+ return FALSE;
}
/* Get the nickname@server string and parse it */
if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+ !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;
+ 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) {
/* Get the nickname@server string and parse it */
if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
- silc_server_query_add_error(server, query, TRUE, 1,
+ !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)
- query->server_name = silc_memdup(tmp, 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)
- query->channel_name = silc_memdup(tmp, 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 && !query->server_name && !query->channel_name) {
+ 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;
+ return FALSE;
}
} else {
if (!tmp)
continue;
- id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
- if (!id) {
- silc_server_query_add_error(server, query, TRUE, i + 5,
+ 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 (id.type == SILC_ID_CLIENT) {
if (!silc_idlist_find_client_by_id(server->local_list,
- id, TRUE, NULL)) {
- if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+ &id.u.client_id, TRUE, NULL)) {
+ if (idata->conn_type != SILC_CONN_CLIENT ||
!silc_idlist_find_client_by_id(server->global_list,
- id, TRUE, NULL)) {
+ &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;
- silc_free(id);
- return;
+ return FALSE;
}
}
} else {
silc_free(query->ids);
query->ids = NULL;
query->ids_count = 0;
- silc_free(id);
- return;
+ return FALSE;
}
}
- query->ids[query->ids_count].id = id;
- query->ids[query->ids_count].id_type = id_type;
+ 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++;
}
}
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 */
- silc_server_query_process(server, query, TRUE);
+ 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
sender of the query command. */
void silc_server_query_process(SilcServer server, SilcServerQuery query,
- bool resolve)
+ SilcBool resolve)
{
SilcServerCommandContext cmd = query->cmd;
- bool check_global = FALSE;
+ SilcIDListData idata = silc_packet_get_context(cmd->sock);
+ SilcBool check_global = FALSE;
void *entry;
SilcClientEntry *clients = NULL, client_entry;
SilcChannelEntry *channels = NULL;
/* Check global lists if query is coming from client or we are not
normal server (we know global information). */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ if (idata->conn_type == SILC_CONN_CLIENT)
check_global = TRUE;
else if (server->server_type != SILC_SERVER)
check_global = TRUE;
- if (query->nickname) {
+ if (query->nickname[0]) {
/* Get all clients matching nickname from local list */
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- query->nickname, server->md5hash,
+ 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,
+ silc_idlist_get_clients_by_nickname(server->local_list,
query->nickname,
- query->nick_server,
+ 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, server->md5hash,
+ 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,
+ silc_idlist_get_clients_by_nickname(server->global_list,
query->nickname,
- query->nick_server,
+ query->nick_server[0] ?
+ query->nick_server : NULL,
&clients, &clients_count);
}
if (!clients)
- silc_server_query_add_error(server, query, TRUE, 1,
+ silc_server_query_add_error(server, query, 1, 1,
SILC_STATUS_ERR_NO_SUCH_NICK);
}
}
if (!servers)
- silc_server_query_add_error(server, query, TRUE, 2,
+ silc_server_query_add_error(server, query, 1, 2,
SILC_STATUS_ERR_NO_SUCH_SERVER);
}
}
if (!channels)
- silc_server_query_add_error(server, query, TRUE, 3,
+ silc_server_query_add_error(server, query, 1, 3,
SILC_STATUS_ERR_NO_SUCH_CHANNEL);
}
entry = silc_idlist_find_client_by_id(server->global_list,
id, TRUE, NULL);
if (!entry) {
- silc_server_query_add_error(server, query, FALSE, i,
+ silc_server_query_add_error(server, query, 0, i,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
continue;
}
entry = silc_idlist_find_server_by_id(server->global_list,
id, TRUE, NULL);
if (!entry) {
- silc_server_query_add_error(server, query, FALSE, i,
+ silc_server_query_add_error(server, query, 0, i,
SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
continue;
}
entry = silc_idlist_find_channel_by_id(server->global_list, id,
NULL);
if (!entry) {
- silc_server_query_add_error(server, query, FALSE, i,
+ silc_server_query_add_error(server, query, 0, i,
SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
continue;
}
}
}
+ /* 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);
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. */
client entry calls this function to do the resolving. */
void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcClientEntry client_entry)
{
SilcServerCommandContext cmd = query->cmd;
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, res_cmd->len, FALSE);
+ res_cmd->data, silc_buffer_len(res_cmd));
silc_buffer_free(res_cmd);
/* Reprocess this packet after received reply */
if (!r) {
/* Allocate new temp query list context */
query->querylist = silc_realloc(query->querylist,
- sizeof(*query->querylist) *
+ sizeof(*query->querylist) *
(query->querylist_count + 1));
r = &query->querylist[query->querylist_count];
query->querylist_count++;
/* 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, idp->len);
- r->arg_lens[r->argc] = idp->len;
+ 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);
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
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[256], uh[256];
- bool sent_reply = FALSE;
+ 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;
- SilcSocketConnection hsock;
+ 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 ||
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (valid_count > 1 && k == valid_count - 1
+ 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)
" : "), entry->nickname));
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- memset(uh, 0, sizeof(uh));
memset(nh, 0, sizeof(nh));
silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
server->server_name, len);
}
}
-
+
switch (query->querycmd) {
-
+
case SILC_COMMAND_WHOIS:
{
unsigned char idle[4], mode[4];
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);
- len = strlen(hsock->hostname);
- silc_strncat(uh, sizeof(uh), hsock->hostname, len);
+ 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ if (idata->conn_type == SILC_CONN_CLIENT)
channels =
- silc_server_get_client_channel_list(server, entry, FALSE,
+ silc_server_get_client_channel_list(server, entry, FALSE,
FALSE, &umode_list);
else
channels =
- silc_server_get_client_channel_list(server, entry, TRUE,
+ silc_server_get_client_channel_list(server, entry, TRUE,
TRUE, &umode_list);
if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
if (query->attrs) {
if (!entry->attrs && SILC_IS_LOCAL(entry)) {
tmpattrs = silc_server_query_reply_attrs(server, query, entry);
- entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
- entry->attrs_len = tmpattrs->len;
+ entry->attrs = silc_buffer_steal(tmpattrs, &len);
+ entry->attrs_len = len;
silc_buffer_free(tmpattrs);
}
attrs = entry->attrs;
/* Send command reply */
silc_server_send_command_reply(server, cmd->sock, query->querycmd,
status, 0, ident, 10,
- 2, idp->data, idp->len,
+ 2, idp->data, silc_buffer_len(idp),
3, nh, strlen(nh),
4, uh, strlen(uh),
- 5, entry->userinfo,
+ 5, entry->userinfo,
strlen(entry->userinfo),
6, channels ? channels->data : NULL,
- channels ? channels->len : 0,
+ 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 ? umode_list->len :
+ NULL, umode_list ?
+ silc_buffer_len(umode_list) :
0, 11, attrs, len);
sent_reply = TRUE;
if (!entry->username) {
silc_server_send_command_reply(server, cmd->sock, query->querycmd,
status, 0, ident, 2,
- 2, idp->data, idp->len,
+ 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);
- len = strlen(hsock->hostname);
- silc_strncat(uh, sizeof(uh), hsock->hostname, len);
+ 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, idp->len,
+ 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);
+ 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, idp->len,
+ 2, idp->data, silc_buffer_len(idp),
3, nh, strlen(nh),
4, uh, strlen(uh),
- 5, entry->userinfo,
- entry->userinfo ?
+ 5, entry->userinfo,
+ entry->userinfo ?
strlen(entry->userinfo) : 0);
sent_reply = TRUE;
break;
/* 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)
- silc_server_query_add_error(server, query, TRUE, 1,
+ 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);
}
}
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" :
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, idp->len,
- 3, entry->server_name,
- entry->server_name ?
+ 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++;
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" :
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, idp->len,
- 3, entry->channel_name,
- entry->channel_name ?
+ 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++;
idp = NULL;
/* Take error argument */
- if (query->errors[i].from_cmd) {
+ 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);
- if (query->errors[i].index == 1)
- type = 3; /* Nickname */
- else
- type = 2; /* ID */
+ 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 = idp->len;
+ 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 = idp->len;
+ 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_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 ?
(status == SILC_STATUS_OK ?
0 : query->errors[i].error), ident, 1,
type, tmp, len);
+
silc_buffer_free(idp);
sent_reply = TRUE;
SilcAttributeObjPk pk;
SilcAttributeObjService service;
unsigned char *tmp;
- unsigned char sign[2048];
+ unsigned char sign[2048 + 1];
SilcUInt32 sign_len;
SILC_LOG_DEBUG(("Constructing Requested Attributes"));
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));
case SILC_ATTRIBUTE_STATUS_FREETEXT:
/* Put STATUS_FREETEXT. We just tell in the message that we are
replying on behalf of the client. */
- tmp =
+ tmp =
"This information was provided by the server on behalf of the user";
buffer = silc_attribute_payload_encode(buffer, attribute,
SILC_ATTRIBUTE_FLAG_VALID,
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,
/* 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_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
- silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
- buffer->data, buffer->len,
- sign, &sign_len)) {
+ 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;
SilcClientEntry silc_server_query_client(SilcServer server,
const SilcClientID *client_id,
- bool always_resolve,
- bool *resolved)
+ SilcBool always_resolve,
+ SilcBool *resolved)
{
SilcClientEntry client;
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;
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, idp->len);
+ 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, buffer->len, FALSE);
+ buffer->data, silc_buffer_len(buffer));
silc_buffer_free(idp);
silc_buffer_free(buffer);