SilcCommand command)
{
SilcIDListData idata = (SilcIDListData)sock->user_data;
- if (idata->registered)
+ if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
return TRUE;
silc_server_command_send_status_reply(cmd, command,
if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
(client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_command_process_timeout,
(void *)timeout,
2 - (time(NULL) - client->last_command), 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
else
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_command_process_timeout,
(void *)timeout,
0, 1,
/* Add new pending command to be executed when reply to a command has been
received. The `reply_cmd' is the command that will call the `callback'
- with `context' when reply has been received. If `ident' is non-zero
+ with `context' when reply has been received. It can be SILC_COMMAND_NONE
+ to match any command with the `ident'. If `ident' is non-zero
the `callback' will be executed when received reply with command
identifier `ident'. */
/* Checks for pending commands and marks callbacks to be called from
the command reply function. Returns TRUE if there were pending command. */
-int silc_server_command_pending_check(SilcServer server,
- SilcServerCommandReplyContext ctx,
- SilcCommand command,
- uint16 ident)
+SilcServerCommandPendingCallbacks
+silc_server_command_pending_check(SilcServer server,
+ SilcServerCommandReplyContext ctx,
+ SilcCommand command,
+ uint16 ident,
+ uint32 *callbacks_count)
{
SilcServerCommandPending *r;
+ SilcServerCommandPendingCallbacks callbacks = NULL;
+ int i = 0;
silc_dlist_start(server->pending_commands);
while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
- if (r->reply_cmd == command && r->ident == ident) {
- ctx->context = r->context;
- ctx->callback = r->callback;
- ctx->destructor = r->destructor;
+ if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
+ && r->ident == ident) {
+ callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+ callbacks[i].context = r->context;
+ callbacks[i].callback = r->callback;
+ callbacks[i].destructor = r->destructor;
ctx->ident = ident;
- return TRUE;
+ i++;
}
}
- return FALSE;
+ *callbacks_count = i;
+ return callbacks;
}
/* Destructor function for pending callbacks. This is called when using
return FALSE;
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmdr->args, 1, NULL));
- if (status != SILC_STATUS_OK) {
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_START &&
+ status != SILC_STATUS_LIST_ITEM &&
+ status != SILC_STATUS_LIST_END) {
/* Send the error message */
silc_server_command_send_status_reply(cmd, command, status);
return TRUE;
/* No ID, get the nickname@server string and parse it. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
if (tmp) {
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- *nickname = silc_calloc(len + 1, sizeof(char));
- memcpy(*nickname, tmp, len);
- *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
- } else {
- *nickname = strdup(tmp);
- }
+ silc_parse_userfqdn(tmp, nickname, server_name);
} else {
silc_server_command_send_status_reply(cmd, command,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
}
}
}
-
- /* Command includes ID, use that */
}
/* Get the max count of reply messages allowed */
return TRUE;
}
-static char
+/* Resolve context used by both WHOIS and IDENTIFY commands */
+typedef struct {
+ SilcServerEntry router;
+ uint16 ident;
+ unsigned char **res_argv;
+ uint32 *res_argv_lens;
+ uint32 *res_argv_types;
+ uint32 res_argc;
+} *SilcServerResolveContext;
+
+static bool
silc_server_command_whois_check(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count)
{
SilcServer server = cmd->server;
- int i;
SilcClientEntry entry;
+ SilcServerResolveContext resolve = NULL, r = NULL;
+ uint32 resolve_count = 0;
+ int i, k;
+ bool no_res = TRUE;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (!entry || entry->data.registered == FALSE)
+ if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+ !entry->router)
continue;
- if (!entry->nickname || !entry->username || !entry->userinfo) {
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- if (!entry->router)
- continue;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+ /* We need to resolve this entry since it is not complete */
- /* Send WHOIS command */
- silc_server_packet_send(server, entry->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply */
- silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- silc_command_get_ident(cmd->payload),
+ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* The entry is being resolved (and we are not the resolver) so attach
+ to the command reply and we're done with this one. */
+ silc_server_command_pending(server, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
silc_server_command_destructor,
- silc_server_command_whois,
+ silc_server_command_whois,
silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
+ no_res = FALSE;
+ } else {
+ if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* We've resolved this and it still is not ready. We'll return
+ and are that this will be handled again after it is resolved. */
+ for (i = 0; i < resolve_count; i++) {
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ }
+ silc_free(resolve);
+ return FALSE;
+ } else {
+ /* We'll resolve this client */
+ SilcBuffer idp;
+
+ r = NULL;
+ for (k = 0; k < resolve_count; k++) {
+ if (resolve[k].router == entry->router) {
+ r = &resolve[k];
+ break;
+ }
+ }
- silc_buffer_free(tmpbuf);
- return FALSE;
+ if (!r) {
+ resolve = silc_realloc(resolve, sizeof(*resolve) *
+ (resolve_count + 1));
+ r = &resolve[resolve_count];
+ memset(r, 0, sizeof(*r));
+ r->router = entry->router;
+ r->ident = ++server->cmd_ident;
+ resolve_count++;
+ }
+
+ r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+ (r->res_argc + 1));
+ r->res_argv_lens = silc_realloc(r->res_argv_lens,
+ sizeof(*r->res_argv_lens) *
+ (r->res_argc + 1));
+ r->res_argv_types = silc_realloc(r->res_argv_types,
+ sizeof(*r->res_argv_types) *
+ (r->res_argc + 1));
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ r->res_argv[r->res_argc] = silc_calloc(idp->len,
+ sizeof(**r->res_argv));
+ memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+ r->res_argv_lens[r->res_argc] = idp->len;
+ r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argc++;
+ silc_buffer_free(idp);
+
+ entry->resolve_cmd_ident = r->ident;
+ entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ }
}
}
- return TRUE;
+ /* Do the resolving */
+ for (i = 0; i < resolve_count; i++) {
+ SilcBuffer res_cmd;
+
+ r = &resolve[i];
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ r->res_argc, r->res_argv,
+ r->res_argv_lens,
+ r->res_argv_types,
+ r->ident);
+ silc_server_packet_send(server, r->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ res_cmd->data, res_cmd->len, FALSE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ r->ident,
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_buffer_free(res_cmd);
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ no_res = FALSE;
+ }
+ silc_free(resolve);
+
+ return no_res;
}
static void
len = 0;
for (i = 0; i < clients_count; i++)
- if (clients[i]->data.registered)
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
len++;
+ if (len == 0 && clients_count) {
+ entry = clients[0];
+ if (entry->nickname) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
+
+ return;
+ }
+
status = SILC_STATUS_OK;
if (len > 1)
status = SILC_STATUS_LIST_START;
for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->data.registered == FALSE) {
+ if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
if (clients_count == 1) {
if (entry->nickname) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
}
static int
-silc_server_command_whois_from_client(SilcServerCommandContext cmd)
+silc_server_command_whois_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
SilcClientID **client_id = NULL;
uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
+ bool check_global = FALSE;
/* Protocol dictates that we must always send the received WHOIS request
to our router if we are normal server, so let's do it now unless we
are standalone. We will not send any replies to the client until we
have received reply from the router. */
- if (server->server_type == SILC_SERVER && !cmd->pending &&
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
!server->standalone) {
SilcBuffer tmpbuf;
uint16 old_ident;
/* We are ready to process the command request. Let's search for the
requested client and send reply to the requesting client. */
- /* Parse the whois request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_WHOIS))
- return 0;
-
- /* Get all clients matching that ID or nickname from local list */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* Check global list as well */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- if (!clients) {
- /* Such client(s) really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Router always finds the client entry if it exists in the SILC network.
- However, it might be incomplete entry and does not include all the
- mandatory fields that WHOIS command reply requires. Check for these and
- make query from the server who owns the client if some fields are
- missing. */
- if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count,
- count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_whois_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_count = 0;
- int i, ret = 0;
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
/* Parse the whois request */
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
SILC_COMMAND_WHOIS))
return 0;
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
+ /* Get all clients matching that ID or nickname from local list */
if (client_id_count) {
/* Check all Client ID's received in the command packet */
for (i = 0; i < client_id_count; i++) {
entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
+ client_id[i], TRUE, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], TRUE, NULL);
if (entry) {
clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
silc_idlist_get_clients_by_nickname(server->local_list,
nick, server_name,
&clients, &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (server->server_type == SILC_ROUTER) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
+ if (check_global) {
if (!silc_idlist_get_clients_by_hash(server->global_list,
nick, server->md5hash,
&clients, &clients_count))
&clients, &clients_count);
}
}
-
+
if (!clients) {
- /* Such a client really does not exist in the SILC network. */
+ /* Such client(s) really does not exist in the SILC network. */
if (!client_id_count) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
SILC_STATUS_ERR_NO_SUCH_NICK,
goto out;
}
- /* Send the command reply to the client */
+ /* Send the command reply */
silc_server_command_whois_send_reply(cmd, clients, clients_count,
count);
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whois_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_whois_from_server(cmd);
+ ret = silc_server_command_whois_process(cmd);
if (!ret)
silc_server_command_free(cmd);
}
/* Get the nickname@server string and parse it. */
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- *nickname = silc_calloc(len + 1, sizeof(char));
- memcpy(*nickname, tmp, len);
- *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
- } else {
- *nickname = strdup(tmp);
- }
+ silc_parse_userfqdn(tmp, nickname, server_name);
+
/* Get the max count of reply messages allowed */
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
if (tmp)
/* We will take only clients that are not valid anymore. They are the
ones that are not registered anymore but still have a ID. They
have disconnected us, and thus valid for WHOWAS. */
- if (entry->data.registered == TRUE)
+ if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
continue;
if (entry->id == NULL)
continue;
}
static int
-silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
+silc_server_command_whowas_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
SilcClientEntry *clients = NULL;
uint32 clients_count = 0;
int ret = 0;
+ bool check_global = FALSE;
/* Protocol dictates that we must always send the received WHOWAS request
to our router if we are normal server, so let's do it now unless we
are standalone. We will not send any replies to the client until we
have received reply from the router. */
- if (server->server_type == SILC_SERVER && !cmd->pending &&
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
!server->standalone) {
SilcBuffer tmpbuf;
uint16 old_ident;
/* We are ready to process the command request. Let's search for the
requested client and send reply to the requesting client. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
+
/* Parse the whowas request */
if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
return 0;
&clients, &clients_count);
/* Check global list as well */
- if (!silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count))
- silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count);
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- goto out;
- }
-
- if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whowas_send_reply(cmd, clients, clients_count);
-
- out:
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL;
- uint32 clients_count = 0;
- int ret = 0;
-
- /* Parse the whowas request */
- if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
- return 0;
-
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
- if (!silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count))
- silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count);
-
- /* If we are router we will check our global list as well. */
- if (server->server_type == SILC_ROUTER) {
+ if (check_global) {
if (!silc_idlist_get_clients_by_nickname(server->global_list,
nick, server_name,
&clients, &clients_count))
nick, server->md5hash,
&clients, &clients_count);
}
-
+
if (!clients) {
/* Such a client really does not exist in the SILC network. */
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
goto out;
}
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ !silc_server_command_whowas_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
+ }
+
/* Send the command reply to the client */
silc_server_command_whowas_send_reply(cmd, clients, clients_count);
out:
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
+ silc_free(clients);
+ silc_free(nick);
+ silc_free(server_name);
return ret;
}
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whowas_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_whowas_from_server(cmd);
+ ret = silc_server_command_whowas_process(cmd);
if (!ret)
silc_server_command_free(cmd);
******************************************************************************/
-/* Checks that all mandatory fields are present. If not then send WHOIS
- request to the server who owns the client. We use WHOIS because we want
- to get as much information as possible at once. */
-
-static char
-silc_server_command_identify_check(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- uint32 clients_count)
+static bool
+silc_server_command_identify_parse(SilcServerCommandContext cmd,
+ SilcClientEntry **clients,
+ uint32 *clients_count,
+ SilcServerEntry **servers,
+ uint32 *servers_count,
+ SilcChannelEntry **channels,
+ uint32 *channels_count,
+ uint32 *count)
{
SilcServer server = cmd->server;
+ unsigned char *tmp;
+ uint32 len;
+ uint32 argc = silc_argument_get_arg_num(cmd->args);
+ SilcIDPayload idp;
+ bool check_global = FALSE;
+ void *entry;
int i;
+ bool error = FALSE;
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
+
+ /* If ID Payload is in the command it must be used instead of names */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
+ if (!tmp) {
+ /* No ID, get the names. */
+
+ /* Try to get nickname@server. */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ char *nick = NULL;
+ char *nick_server = NULL;
+
+ silc_parse_userfqdn(tmp, &nick, &nick_server);
+
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, nick_server,
+ clients, clients_count);
+ if (check_global) {
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, nick_server,
+ clients, clients_count);
+ }
+
+ silc_free(nick);
+ silc_free(nick_server);
+
+ if (!(*clients)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
+
+ /* Try to get server name */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ tmp, TRUE, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ tmp, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = entry;
+ }
+
+ if (!(*servers)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
+
+ /* Try to get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_channel_by_name(server->local_list,
+ tmp, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_channel_by_name(server->local_list,
+ tmp, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = entry;
+ }
+
+ if (!(*channels)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
+
+ if (!(*clients) && !(*servers) && !(*channels)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+ } else {
+ /* Command includes ID, we must use that. Also check whether the command
+ has more than one ID set - take them all. */
+
+ /* Take all ID's from the command packet */
+ for (i = 0; i < argc; i++) {
+ void *id;
+
+ tmp = silc_argument_get_arg_type(cmd->args, i + 5, &len);
+ if (!tmp)
+ continue;
+
+ idp = silc_id_payload_parse_data(tmp, len);
+ if (!idp) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+
+ id = silc_id_payload_get_id(idp);
+
+ switch (silc_id_payload_get_type(idp)) {
+
+ case SILC_ID_CLIENT:
+ entry = (void *)silc_idlist_find_client_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_client_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *clients = silc_realloc(*clients, sizeof(**clients) *
+ (*clients_count + 1));
+ (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+
+ break;
+
+ case SILC_ID_SERVER:
+ entry = (void *)silc_idlist_find_server_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_server_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ entry = (void *)silc_idlist_find_channel_by_id(server->local_list,
+ id, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_channel_by_id(server->global_list,
+ id, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ break;
+ }
+
+ silc_free(id);
+ }
+ }
+
+ if (error) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return FALSE;
+ }
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
+
+ return TRUE;
+}
+
+/* Checks that all mandatory fields in client entry are present. If not
+ then send WHOIS request to the server who owns the client. We use
+ WHOIS because we want to get as much information as possible at once. */
+
+static bool
+silc_server_command_identify_check_client(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;
SilcClientEntry entry;
+ SilcServerResolveContext resolve = NULL, r = NULL;
+ uint32 resolve_count = 0;
+ int i, k;
+ bool no_res = TRUE;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (!entry || entry->data.registered == FALSE)
+ if (!entry || entry->nickname ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+ !entry->router)
continue;
- if (!entry->nickname) {
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- if (!entry->router)
- continue;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOIS request. We send WHOIS since we're doing the requesting
- now anyway so make it a good one. */
- silc_server_packet_send(server, entry->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply */
- silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- silc_command_get_ident(cmd->payload),
+ /* We need to resolve this entry since it is not complete */
+
+ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* The entry is being resolved (and we are not the resolver) so attach
+ to the command reply and we're done with this one. */
+ silc_server_command_pending(server, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
silc_server_command_destructor,
silc_server_command_identify,
silc_server_command_dup(cmd));
+ no_res = FALSE;
+ } else {
+ if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* We've resolved this and it still is not ready. We'll return
+ and are that this will be handled again after it is resolved. */
+ for (i = 0; i < resolve_count; i++) {
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ }
+ silc_free(resolve);
+ return FALSE;
+ } else {
+ /* We'll resolve this client */
+ SilcBuffer idp;
+
+ r = NULL;
+ for (k = 0; k < resolve_count; k++) {
+ if (resolve[k].router == entry->router) {
+ r = &resolve[k];
+ break;
+ }
+ }
- cmd->pending = TRUE;
-
- /* Put old data back to the Command Payload we just changed */
- silc_command_set_ident(cmd->payload, old_ident);
- silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
+ if (!r) {
+ resolve = silc_realloc(resolve, sizeof(*resolve) *
+ (resolve_count + 1));
+ r = &resolve[resolve_count];
+ memset(r, 0, sizeof(*r));
+ r->router = entry->router;
+ r->ident = ++server->cmd_ident;
+ resolve_count++;
+ }
- silc_buffer_free(tmpbuf);
- return FALSE;
+ r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+ (r->res_argc + 1));
+ r->res_argv_lens = silc_realloc(r->res_argv_lens,
+ sizeof(*r->res_argv_lens) *
+ (r->res_argc + 1));
+ r->res_argv_types = silc_realloc(r->res_argv_types,
+ sizeof(*r->res_argv_types) *
+ (r->res_argc + 1));
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ r->res_argv[r->res_argc] = silc_calloc(idp->len,
+ sizeof(**r->res_argv));
+ memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+ r->res_argv_lens[r->res_argc] = idp->len;
+ r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argc++;
+ silc_buffer_free(idp);
+
+ entry->resolve_cmd_ident = r->ident;
+ entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ }
}
}
- return TRUE;
+ /* Do the resolving */
+ for (i = 0; i < resolve_count; i++) {
+ SilcBuffer res_cmd;
+
+ r = &resolve[i];
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ r->res_argc, r->res_argv,
+ r->res_argv_lens,
+ r->res_argv_types,
+ r->ident);
+ silc_server_packet_send(server, r->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ res_cmd->data, res_cmd->len, FALSE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ r->ident,
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_buffer_free(res_cmd);
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ no_res = FALSE;
+ }
+ silc_free(resolve);
+
+ return no_res;
}
static void
silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count,
+ SilcServerEntry *servers,
+ uint32 servers_count,
+ SilcChannelEntry *channels,
+ uint32 channels_count,
int count)
{
SilcServer server = cmd->server;
- char *tmp;
int i, k, len;
SilcBuffer packet, idp;
- SilcClientEntry entry;
SilcCommandStatus status;
uint16 ident = silc_command_get_ident(cmd->payload);
char nh[256], uh[256];
SilcSocketConnection hsock;
- len = 0;
- for (i = 0; i < clients_count; i++)
- if (clients[i]->data.registered)
- len++;
-
status = SILC_STATUS_OK;
- if (len > 1)
- status = SILC_STATUS_LIST_START;
- for (i = 0, k = 0; i < clients_count; i++) {
- entry = clients[i];
+ if (clients) {
+ SilcClientEntry entry;
- if (entry->data.registered == FALSE) {
- if (clients_count == 1) {
+ len = 0;
+ for (i = 0; i < clients_count; i++)
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ len++;
+
+ if (len == 0 && clients_count) {
+ entry = clients[0];
+ if (entry->nickname) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ } else {
SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2, idp->data, idp->len);
silc_buffer_free(idp);
}
- continue;
+
+ return;
}
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
+ if (len > 1)
+ status = SILC_STATUS_LIST_START;
- if (clients_count > 1 && k == clients_count - 1)
- status = SILC_STATUS_LIST_END;
+ for (i = 0, k = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (clients_count == 1) {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
+ continue;
+ }
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (clients_count > 1 && k == clients_count - 1
+ && !servers_count && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
+ }
+
+ if (!entry->username) {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh));
+ } else {
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = strlen(hsock->hostname);
+ strncat(uh, hsock->hostname, len);
+ }
+
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
+ }
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
+ }
- if (count && k - 1 == count)
- status = SILC_STATUS_LIST_END;
+ status = (status == SILC_STATUS_LIST_ITEM ?
+ SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
- if (count && k - 1 > count)
- break;
+ if (servers) {
+ SilcServerEntry entry;
- /* Send IDENTIFY reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
+ if (status == SILC_STATUS_OK && servers_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < servers_count; i++) {
+ entry = servers[i];
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
- if (entry->servername) {
- strncat(nh, entry->servername, strlen(entry->servername));
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (servers_count > 1 && k == servers_count - 1 && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ if (entry->server_name) {
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->server_name,
+ strlen(entry->server_name));
} else {
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- strncat(nh, entry->router ? entry->router->server_name :
- server->server_name, len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 1,
+ 2, idp->data, idp->len);
}
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
}
+ }
+
+ status = (status == SILC_STATUS_LIST_ITEM ?
+ SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
+
+ if (channels) {
+ SilcChannelEntry entry;
+
+ if (status == SILC_STATUS_OK && channels_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < channels_count; i++) {
+ entry = channels[i];
- if (!entry->username) {
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 2,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh));
- } else {
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- hsock = (SilcSocketConnection)entry->connection;
- len = strlen(hsock->hostname);
- strncat(uh, hsock->hostname, len);
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (channels_count > 1 && k == channels_count - 1)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+ if (entry->channel_name) {
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name));
+ } else {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 1,
+ 2, idp->data, idp->len);
}
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
- }
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
-
- k++;
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
}
}
static int
-silc_server_command_identify_from_client(SilcServerCommandContext cmd)
+silc_server_command_identify_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_count = 0;
- int i, ret = 0;
+ uint32 count = 0;
+ int ret = 0;
+ SilcClientEntry *clients = NULL;
+ SilcServerEntry *servers = NULL;
+ SilcChannelEntry *channels = NULL;
+ uint32 clients_count = 0, servers_count = 0, channels_count = 0;
/* Protocol dictates that we must always send the received IDENTIFY request
to our router if we are normal server, so let's do it now unless we
are standalone. We will not send any replies to the client until we
have received reply from the router. */
- if (server->server_type == SILC_SERVER &&
- !cmd->pending && !server->standalone) {
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
SilcBuffer tmpbuf;
uint16 old_ident;
requested client and send reply to the requesting client. */
/* Parse the IDENTIFY request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_IDENTIFY))
+ if (!silc_server_command_identify_parse(cmd,
+ &clients, &clients_count,
+ &servers, &servers_count,
+ &channels, &channels_count,
+ &count))
return 0;
- /* Get all clients matching that ID or nickname from local list */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* Check global list as well */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
+ if (clients && !silc_server_command_identify_check_client(cmd, clients,
+ clients_count)) {
ret = -1;
goto out;
}
/* Send the command reply to the client */
- silc_server_command_identify_send_reply(cmd, clients, clients_count,
+ silc_server_command_identify_send_reply(cmd,
+ clients, clients_count,
+ servers, servers_count,
+ channels, channels_count,
count);
out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_identify_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_count = 0;
- int i, ret = 0;
-
- /* Parse the IDENTIFY request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_IDENTIFY))
- return 0;
-
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (server->server_type == SILC_ROUTER) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count);
- }
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Check that all mandatory fields are present and request those data
- from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply */
- silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
+ silc_free(clients);
+ silc_free(servers);
+ silc_free(channels);
return ret;
}
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_identify_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) |
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_identify_from_server(cmd);
+ ret = silc_server_command_identify_process(cmd);
if (!ret)
silc_server_command_free(cmd);
SilcClientID *new_id;
char *nick;
uint16 ident = silc_command_get_ident(cmd->payload);
+ int nickfail = 0;
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
}
if (strlen(nick) > 128)
- nick[127] = '\0';
+ nick[128] = '\0';
/* Create new Client ID */
- silc_id_create_client_id(cmd->server->id, cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id);
+ while (!silc_id_create_client_id(cmd->server, cmd->server->id,
+ cmd->server->rng,
+ cmd->server->md5hash, nick,
+ &new_id)) {
+ nickfail++;
+ snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
+ }
/* Send notify about nickname change to our router. We send the new
ID and ask to replace it with the old one. If we are router the
FALSE : TRUE, client->id,
new_id);
+ oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
/* Remove old cache entry */
silc_idcache_del_by_context(server->local_list->clients, client);
- oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
/* Free old ID */
- if (client->id)
- silc_free(client->id);
+ silc_free(client->id);
/* Save the nickname as this client is our local client */
- if (client->nickname)
- silc_free(client->nickname);
+ silc_free(client->nickname);
client->nickname = strdup(nick);
client->id = new_id;
q->signoff = tmp ? strdup(tmp) : NULL;
/* We quit the connection with little timeout */
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_command_quit_cb, (void *)q,
0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Get the client entry */
remote_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!remote_client) {
remote_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!remote_client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
}
}
- if (remote_client->data.registered == FALSE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
-
/* Get comment */
comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
if (tmp_len2 > 128)
/* Remove the client entry, If it is locally connected then we will also
disconnect the client here */
- if (remote_client->data.registered && remote_client->connection) {
+ if (remote_client->connection) {
/* Remove locally conneted client */
SilcSocketConnection sock = remote_client->connection;
silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
if (server_id) {
/* Check whether we have this server cached */
entry = silc_idlist_find_server_by_id(server->local_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_id(server->global_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!entry && server->server_type == SILC_ROUTER) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
SILC_STATUS_ERR_NO_SUCH_SERVER);
}
}
- if ((!dest_server && !server_id) ||
+ /* Some buggy servers has sent request to router about themselves. */
+ if (server->server_type == SILC_ROUTER && cmd->sock->user_data == entry)
+ goto out;
+
+ if ((!dest_server && !server_id && !entry) || (entry &&
+ entry == server->id_entry) ||
(dest_server && !cmd->pending &&
!strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
/* Send our reply */
/* Check whether we have this server cached */
if (!entry && dest_server) {
entry = silc_idlist_find_server_by_name(server->global_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_name(server->local_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
}
}
/* Generate new channel key as protocol dictates */
if ((!created && silc_hash_table_count(channel->user_list) > 0) ||
!channel->channel_key)
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This is broadcasted to the channel but is not
sent to the client who is joining to the channel. */
/* Check whether we have this server cached */
entry = silc_idlist_find_server_by_name(server->global_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_name(server->local_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
}
if (server->server_type == SILC_ROUTER && !cmd->pending &&
anymore after this. */
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
}
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
/* Delete old cipher and allocate default one */
silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc",
+ if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
&channel->channel_key)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
}
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
/* Delete old hmac and allocate default one */
silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL,
+ if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL,
&channel->hmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
memcpy(channel->founder_passwd, tmp, tmp_len);
channel->founder_passwd_len = tmp_len;
+ } else {
+ /* Verify the payload before setting the mode */
+ if (!silc_auth_verify(auth, channel->founder_method,
+ channel->founder_key, 0, idata->hash,
+ client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
}
silc_auth_payload_free(auth);
/* Get target client's entry */
target_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!target_client) {
target_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
}
if (target_client != client &&
/* Get target client's entry */
target_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!target_client) {
target_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
}
/* Check that the target client is not channel founder. Channel founder
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key to the channel. The key of course is not sent
to the client who was kicked off the channel. */
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
- if (server->server_type == SILC_SERVER)
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ if (server->server_type == SILC_SERVER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
goto out;
+ }
/* Get the username */
username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
SILC_GET32_MSB(port, tmp);
server_entry = silc_idlist_find_server_by_conn(server->local_list,
- name, port, NULL);
+ name, port, FALSE, NULL);
if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
SILC_STATUS_ERR_NO_SERVER_ID);
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key */
silc_server_send_channel_key(server, NULL, channel,
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcChannelEntry channel;
- SilcChannelID *id;
- SilcBuffer packet;
+ SilcChannelID *id = NULL;
+ SilcBuffer packet, idp;
unsigned char *channel_id;
uint32 channel_id_len;
SilcBuffer client_id_list;
unsigned char lc[4];
uint32 list_count = 0;
uint16 ident = silc_command_get_ident(cmd->payload);
+ char *channel_name;
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 1);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
/* Get Channel ID */
channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
- if (!channel_id) {
+
+ /* Get channel name */
+ channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
+
+ if (!channel_id && !channel_name) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- id = silc_id_payload_parse_id(channel_id, channel_id_len);
- if (!id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
+
+ if (channel_id) {
+ id = silc_id_payload_parse_id(channel_id, channel_id_len);
+ if (!id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
}
/* If we are server and we don't know about this channel we will send
the command to our router. If we know about the channel then we also
have the list of users already. */
- channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+ if (id)
+ channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+ else
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
+
if (!channel) {
if (server->server_type == SILC_SERVER && !server->standalone &&
!cmd->pending) {
return;
}
- /* We are router and we will check the global list as well. */
- channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ /* Check the global list as well. */
+ if (id)
+ channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ else
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
if (!channel) {
/* Channel really does not exist */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
}
}
+ /* If the channel is private or secret do not send anything, unless the
+ user requesting this command is on the channel. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
+ && !silc_server_client_on_channel(cmd->sock->user_data, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ } else {
+ if (channel->mode &
+ (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
/* Get the users list */
silc_server_get_users_on_channel(server, channel, &client_id_list,
&client_mode_list, &list_count);
SILC_PUT32_MSB(list_count, lc);
/* Send reply */
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
SILC_STATUS_OK, ident, 4,
- 2, channel_id, channel_id_len,
+ 2, idp->data, idp->len,
3, lc, 4,
4, client_id_list->data,
client_id_list->len,
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
+ silc_buffer_free(idp);
silc_buffer_free(packet);
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
- silc_free(id);
+ if (id)
+ silc_free(id);
out:
silc_server_command_free(cmd);
SilcServerID *server_id = NULL;
SilcIDPayload idp = NULL;
uint16 ident = silc_command_get_ident(cmd->payload);
- unsigned char *tmp;
- uint32 tmp_len;
- SilcBuffer pk;
+ unsigned char *tmp, *pkdata;
+ uint32 tmp_len, pklen;
+ SilcBuffer pk = NULL;
SilcIdType id_type;
SILC_LOG_DEBUG(("Start"));
/* If the client is not found from local list there is no chance it
would be locally connected client so send the command further. */
client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!client)
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if ((!client && !cmd->pending && !server->standalone) ||
(client && !client->connection && !cmd->pending &&
return;
}
- if (!client && cmd->pending) {
+ if (!client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
goto out;
}
/* The client is locally connected, just get the public key and
- send it back. */
- tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
- pk = silc_buffer_alloc(4 + tmp_len);
- silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
- silc_buffer_format(pk,
- SILC_STR_UI_SHORT(tmp_len),
- SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
- SILC_STR_UI_XNSTRING(tmp, tmp_len),
- SILC_STR_END);
- silc_free(tmp);
-
+ send it back. If they key does not exist then do not send it,
+ send just OK reply */
+ if (!client->data.public_key) {
+ pkdata = NULL;
+ pklen = 0;
+ } else {
+ tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ pkdata = pk->data;
+ pklen = pk->len;
+ }
} else if (id_type == SILC_ID_SERVER) {
server_id = silc_id_payload_get_id(idp);
/* If the server is not found from local list there is no chance it
would be locally connected server so send the command further. */
server_entry = silc_idlist_find_server_by_id(server->local_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!server_entry)
server_entry = silc_idlist_find_server_by_id(server->global_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
- if ((!server_entry && !cmd->pending && !server->standalone) ||
- (server_entry && !server_entry->connection && !cmd->pending &&
- !server->standalone) ||
- (server_entry && !server_entry->data.public_key && !cmd->pending &&
- !server->standalone)) {
+ if (server_entry != server->id_entry &&
+ ((!server_entry && !cmd->pending && !server->standalone) ||
+ (server_entry && !server_entry->connection && !cmd->pending &&
+ !server->standalone) ||
+ (server_entry && !server_entry->data.public_key && !cmd->pending &&
+ !server->standalone))) {
SilcBuffer tmpbuf;
uint16 old_ident;
return;
}
- if (!server_entry && cmd->pending) {
+ if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
goto out;
}
- /* The client is locally connected, just get the public key and
- send it back. */
- tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
- pk = silc_buffer_alloc(4 + tmp_len);
- silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
- silc_buffer_format(pk,
- SILC_STR_UI_SHORT(tmp_len),
- SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
- SILC_STR_UI_XNSTRING(tmp, tmp_len),
- SILC_STR_END);
- silc_free(tmp);
+ /* If they key does not exist then do not send it, send just OK reply */
+ if (!server_entry->data.public_key) {
+ pkdata = NULL;
+ pklen = 0;
+ } else {
+ tmp = silc_pkcs_public_key_encode(server_entry->data.public_key,
+ &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ pkdata = pk->data;
+ pklen = pk->len;
+ }
} else {
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
- SILC_STATUS_OK, ident, 2,
+ SILC_STATUS_OK, ident,
+ pkdata ? 2 : 1,
2, tmp, tmp_len,
- 3, pk->data, pk->len);
+ 3, pkdata, pklen);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
- silc_buffer_free(pk);
+
+ if (pk)
+ silc_buffer_free(pk);
out:
if (idp)