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,
/* 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
/* 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);
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;
+ /* We need to resolve this entry since it is not complete */
- 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);
-
- /* 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,
/* 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], NULL);
+ client_id[i], TRUE, NULL);
if (entry) {
clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
}
/* 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;
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;
}
char *nick = NULL;
char *nick_server = NULL;
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- nick = silc_calloc(len + 1, sizeof(char));
- memcpy(nick, tmp, len);
- nick_server = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(nick_server, tmp + len + 1, strlen(tmp) - len - 1);
- } else {
- nick = strdup(tmp);
- }
+ silc_parse_userfqdn(tmp, &nick, &nick_server);
if (!silc_idlist_get_clients_by_hash(server->local_list,
nick, server->md5hash,
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
if (tmp) {
entry = silc_idlist_find_server_by_name(server->local_list,
- tmp, NULL);
+ tmp, TRUE, NULL);
if (!entry && check_global)
entry = silc_idlist_find_server_by_name(server->local_list,
- tmp, NULL);
+ tmp, TRUE, NULL);
if (entry) {
*servers = silc_realloc(*servers, sizeof(**servers) *
(*servers_count + 1));
case SILC_ID_CLIENT:
entry = (void *)silc_idlist_find_client_by_id(server->local_list,
- id, NULL);
+ id, TRUE, NULL);
if (!entry && check_global)
entry = (void *)silc_idlist_find_client_by_id(server->global_list,
- id, NULL);
+ id, TRUE, NULL);
if (entry) {
*clients = silc_realloc(*clients, sizeof(**clients) *
(*clients_count + 1));
case SILC_ID_SERVER:
entry = (void *)silc_idlist_find_server_by_id(server->local_list,
- id, NULL);
+ id, TRUE, NULL);
if (!entry && check_global)
entry = (void *)silc_idlist_find_server_by_id(server->global_list,
- id, NULL);
+ id, TRUE, NULL);
if (entry) {
*servers = silc_realloc(*servers, sizeof(**servers) *
(*servers_count + 1));
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
+static bool
silc_server_command_identify_check_client(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->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
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_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);
+ }
+
+ return;
+ }
+
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) {
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,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2, idp->data, idp->len);
silc_buffer_free(idp);
}
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;
/* 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);
}
}
+ /* 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 &&
/* 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);
/* 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_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,
}
}
- /* If the channel is private or secret do not send anything */
- 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;
+ /* 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 */
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)