SilcCommand command)
{
SilcIDListData idata = (SilcIDListData)sock->user_data;
- if (idata->registered)
+
+ if (!idata)
+ return FALSE;
+
+ 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;
-
- 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
uint16 ident = silc_command_get_ident(cmd->payload);
char nh[256], uh[256];
unsigned char idle[4], mode[4];
+ unsigned char *fingerprint;
SilcSocketConnection hsock;
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,
}
channels = silc_server_get_client_channel_list(server, entry);
+
+ if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
+ fingerprint = entry->data.fingerprint;
+ else
+ fingerprint = NULL;
SILC_PUT32_MSB(entry->mode, mode);
SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
}
- if (channels)
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, ident, 7,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo),
- 6, channels->data,
- channels->len,
- 7, mode, 4,
- 8, idle, 4);
- else
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, ident, 6,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo),
- 7, mode, 4,
- 8, idle, 4);
-
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+ status, ident, 8,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ strlen(entry->userinfo),
+ 6, channels ? channels->data : NULL,
+ channels ? channels->len : 0,
+ 7, mode, 4,
+ 8, idle, 4,
+ 9, fingerprint,
+ fingerprint ? 20 : 0);
+
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send WHOIS command to our router */
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
check_global = TRUE;
- else if (server->server_type == SILC_ROUTER)
+ else if (server->server_type != SILC_SERVER)
check_global = TRUE;
/* Parse the whois request */
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(nick);
+ silc_free(server_name);
return ret;
}
}
/* 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)
continue;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send WHOWAS command */
/* 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;
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send WHOWAS command to our router */
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
check_global = TRUE;
- else if (server->server_type == SILC_ROUTER)
+ else if (server->server_type != SILC_SERVER)
check_global = TRUE;
/* Parse the whowas request */
goto out;
}
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- !silc_server_command_whowas_check(cmd, clients, clients_count)) {
+ if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
ret = -1;
goto out;
}
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;
}
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
check_global = TRUE;
- else if (server->server_type == SILC_ROUTER)
+ else if (server->server_type != SILC_SERVER)
check_global = TRUE;
/* If ID Payload is in the command it must be used instead of names */
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,
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,
+ entry = silc_idlist_find_server_by_name(server->global_list,
tmp, TRUE, NULL);
if (entry) {
*servers = silc_realloc(*servers, sizeof(**servers) *
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,
+ entry = silc_idlist_find_channel_by_name(server->global_list,
tmp, NULL);
if (entry) {
*channels = silc_realloc(*channels, sizeof(**channels) *
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);
}
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send IDENTIFY command to our router */
static int silc_server_command_bad_chars(char *nick)
{
- if (strchr(nick, '\\')) return TRUE;
- if (strchr(nick, '\"')) return TRUE;
- if (strchr(nick, '´')) return TRUE;
- if (strchr(nick, '`')) return TRUE;
- if (strchr(nick, '\'')) return TRUE;
- if (strchr(nick, '*')) return TRUE;
- if (strchr(nick, '/')) return TRUE;
- if (strchr(nick, '@')) return TRUE;
+ int i;
+
+ for (i = 0; i < strlen(nick); i++) {
+ if (!isascii(nick[i]))
+ return TRUE;
+ if (nick[i] <= 32) return TRUE;
+ if (nick[i] == ' ') return TRUE;
+ if (nick[i] == '\\') return TRUE;
+ if (nick[i] == '\"') return TRUE;
+ if (nick[i] == '*') return TRUE;
+ if (nick[i] == '?') return TRUE;
+ if (nick[i] == ',') return TRUE;
+ if (nick[i] == '@') return TRUE;
+ if (nick[i] == ':') return TRUE;
+ if (nick[i] == '/') return TRUE;
+ if (nick[i] == '[') return TRUE;
+ if (nick[i] == '[') return TRUE;
+ if (nick[i] == '(') return TRUE;
+ if (nick[i] == ')') return TRUE;
+ if (nick[i] == '{') return TRUE;
+ if (nick[i] == '}') return TRUE;
+ if (nick[i] == '<') return TRUE;
+ if (nick[i] == '>') return TRUE;
+ }
return FALSE;
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcServer server = cmd->server;
- SilcBuffer packet, nidp, oidp;
+ SilcBuffer packet, nidp, oidp = NULL;
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';
+
+ /* Check for same nickname */
+ if (!strcmp(client->nickname, nick)) {
+ nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ goto send_reply;
+ }
/* 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
oidp->data, oidp->len,
nidp->data, nidp->len);
+ send_reply:
/* Send the new Client ID as reply command back to client */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
SILC_STATUS_OK, ident, 1,
silc_buffer_free(packet);
silc_buffer_free(nidp);
- silc_buffer_free(oidp);
+ if (oidp)
+ silc_buffer_free(oidp);
out:
silc_server_command_free(cmd);
if (i >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (i == lch_count - 1 && gch_count)
- break;
- if (lch_count > 1 && i == lch_count - 1)
+ if (lch_count > 1 && i == lch_count - 1 && !gch_count)
status = SILC_STATUS_LIST_END;
idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
uint32 lch_count = 0, gch_count = 0;
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
+
+ /* If we are normal server, send the command to router, since we
+ want to know all channels in the network. */
+ if (!cmd->pending && server->server_type == SILC_SERVER &&
+ !server->standalone) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_LIST,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_list,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
+ }
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
lchannels = silc_idlist_get_channels(server->local_list, channel_id,
&lch_count);
- /* Get the channels from global list if we are router */
- if (server->server_type == SILC_ROUTER)
- gchannels = silc_idlist_get_channels(server->global_list, channel_id,
- &gch_count);
+ /* Get the channels from global list */
+ gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+ &gch_count);
/* Send the reply */
silc_server_command_list_send_reply(cmd, lchannels, lch_count,
}
/* Set the topic for channel */
- if (channel->topic)
- silc_free(channel->topic);
+ silc_free(channel->topic);
channel->topic = strdup(tmp);
/* Send TOPIC_SET notify type to the network */
/* Get the client entry */
dest = silc_server_get_client_resolve(server, dest_id);
if (!dest) {
- if (server->server_type == SILC_ROUTER) {
+ if (server->server_type != SILC_SERVER) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
goto out;
silc_buffer_free(packet);
out:
- if (dest_id)
- silc_free(dest_id);
- if (channel_id)
- silc_free(channel_id);
+ silc_free(dest_id);
+ silc_free(channel_id);
silc_server_command_free(cmd);
}
/* 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 (!entry) {
entry = silc_idlist_find_server_by_id(server->global_list,
server_id, TRUE, NULL);
- if (!entry && server->server_type == SILC_ROUTER) {
+ if (!entry && server->server_type != SILC_SERVER) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
SILC_STATUS_ERR_NO_SUCH_SERVER);
goto out;
}
/* Some buggy servers has sent request to router about themselves. */
- if (server->server_type == SILC_ROUTER && cmd->sock->user_data == entry)
+ if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
goto out;
if ((!dest_server && !server_id && !entry) || (entry &&
}
if (!cmd->pending &&
- server->server_type == SILC_ROUTER && entry && !entry->server_info) {
+ server->server_type != SILC_SERVER && entry && !entry->server_info) {
/* Send to the server */
SilcBuffer tmpbuf;
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, entry->connection,
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, server->router->connection,
}
}
- if (server_id)
- silc_free(server_id);
+ silc_free(server_id);
if (!entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
SilcServerCommandContext cmd,
SilcChannelEntry channel,
SilcClientID *client_id,
- int created,
+ bool created,
+ bool create_key,
uint32 umode)
{
SilcSocketConnection sock = cmd->sock;
username and/or hostname is in the ban list the access to the
channel is denied. */
if (channel->ban_list) {
- if (silc_string_match(channel->ban_list, check) ||
+ if (!channel->ban_list ||
+ silc_string_match(channel->ban_list, check) ||
silc_string_match(channel->ban_list, check2)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
/* Check the channel passphrase if set. */
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
- if (!passphrase || memcmp(channel->passphrase, passphrase,
- strlen(channel->passphrase))) {
+ if (!passphrase || !channel->passphrase ||
+ memcmp(channel->passphrase, passphrase,
+ strlen(channel->passphrase))) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_PASSWORD);
goto out;
}
/* Generate new channel key as protocol dictates */
- if ((!created && silc_hash_table_count(channel->user_list) > 0) ||
- !channel->channel_key)
+ if (create_key) {
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. */
- if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
- silc_server_send_channel_key(server, NULL, channel,
- server->server_type == SILC_ROUTER ?
- FALSE : !server->standalone);
+ /* Send the channel key. This is broadcasted to the channel but is not
+ sent to the client who is joining to the channel. */
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
/* Join the client to the channel by adding it to channel's user list.
Add also the channel to client entry's channels list for fast cross-
10, channel->topic,
channel->topic ?
strlen(channel->topic) : 0,
- 11, channel->hmac->hmac->name,
- strlen(channel->hmac->hmac->name),
+ 11, silc_hmac_get_name(channel->hmac),
+ strlen(silc_hmac_get_name(channel->
+ hmac)),
12, tmp3, 4,
13, user_list->data, user_list->len,
14, mode_list->data,
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
reply->data, reply->len, FALSE);
- if (!cmd->pending) {
- /* Send JOIN notify to locally connected clients on the channel */
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 2,
- clidp->data, clidp->len,
- chidp->data, chidp->len);
+ /* Send JOIN notify to locally connected clients on the channel. If
+ we are normal server then router will send or have sent JOIN notify
+ already. However since we've added the client already to our channel
+ we'll ignore it (in packet_receive.c) so we must send it here. If
+ we are router then this will send it to local clients and local
+ servers. */
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_JOIN, 2,
+ clidp->data, clidp->len,
+ chidp->data, chidp->len);
+ if (!cmd->pending) {
/* Send JOIN notify packet to our primary router */
if (!server->standalone)
silc_server_send_notify_join(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel, client->id);
+
+ if (keyp)
+ /* Distribute the channel key to all backup routers. */
+ silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
+ keyp->data, keyp->len, FALSE, TRUE);
}
silc_buffer_free(reply);
silc_buffer_free(mode_list);
out:
- if (passphrase)
- silc_free(passphrase);
+ silc_free(passphrase);
}
/* Server side of command JOIN. Joins client into requested channel. If
char *tmp, *channel_name = NULL, *cipher, *hmac;
SilcChannelEntry channel;
uint32 umode = 0;
- int created = FALSE;
+ bool created = FALSE, create_key = TRUE;
SilcClientID *client_id;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
}
}
- if (!channel || !channel->id) {
+ if (!channel || channel->disabled) {
/* Channel not found */
/* If we are standalone server we don't have a router, we just create
hmac, channel_name, TRUE);
if (!channel) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
-
+
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
-
+ create_key = FALSE;
+
} else {
/* The channel does not exist on our server. If we are normal server
we will send JOIN command to our router which will handle the
joining procedure (either creates the channel if it doesn't exist
or joins the client to it). */
- if (server->server_type == SILC_SERVER) {
+ if (server->server_type != SILC_ROUTER) {
SilcBuffer tmpbuf;
uint16 old_ident;
goto out;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send JOIN command to our router */
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
+ create_key = FALSE;
}
}
}
if (!channel) {
/* Channel not found */
- /* If the command came from router and/or we are normal server then
+ /* If the command came from router and we are normal server then
something went wrong with the joining as the channel was not found.
We can't do anything else but ignore this. */
if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
- server->server_type == SILC_SERVER)
+ server->server_type != SILC_ROUTER)
goto out;
/* We are router and the channel does not seem exist so we will check
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
+ create_key = FALSE;
}
}
}
- /* If the channel does not have global users and is also empty it means the
- channel was created globally (by our router) and the client will be the
- channel founder and operator. */
- if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
- umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
- created = TRUE; /* Created globally by our router */
+ /* Check whether the channel was created by our router */
+ if (cmd->pending && context2) {
+ SilcServerCommandReplyContext reply =
+ (SilcServerCommandReplyContext)context2;
+ if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
+ tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
+ SILC_GET32_MSB(created, tmp);
+ create_key = FALSE; /* Router returned the key already */
+ }
}
+ /* If the channel does not have global users and is also empty the client
+ will be the channel founder and operator. */
+ if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
/* Join to the channel */
silc_server_command_join_channel(server, cmd, channel, client_id,
- created, umode);
+ created, create_key, umode);
silc_free(client_id);
if (server->config && server->config->motd &&
server->config->motd->motd_file) {
/* Send motd */
- motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+ motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
if (!motd)
goto out;
dest_server, TRUE, NULL);
}
- if (server->server_type == SILC_ROUTER && !cmd->pending &&
+ if (server->server_type != SILC_SERVER && !cmd->pending &&
entry && !entry->motd) {
/* Send to the server */
SilcBuffer tmpbuf;
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, entry->connection,
uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, server->router->connection,
modes are available automatically for channel operator. */
if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
- if (is_op && !is_fo)
- return FALSE;
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ if (is_op && !is_fo)
+ return FALSE;
} else {
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
if (is_op && !is_fo)
}
if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
- if (is_op && !is_fo)
- return FALSE;
+ if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+ if (is_op && !is_fo)
+ return FALSE;
} else {
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
if (is_op && !is_fo)
}
if (mode & SILC_CHANNEL_MODE_CIPHER) {
- if (is_op && !is_fo)
- return FALSE;
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+ if (is_op && !is_fo)
+ return FALSE;
} else {
if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
if (is_op && !is_fo)
}
if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
- if (is_op && !is_fo)
- return FALSE;
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH))
+ if (is_op && !is_fo)
+ return FALSE;
} else {
if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
if (is_op && !is_fo)
FALSE : !server->standalone);
cipher = channel->channel_key->cipher->name;
- hmac = channel->hmac->hmac->name;
+ hmac = (char *)silc_hmac_get_name(channel->hmac);
}
}
if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
/* Cipher to use protect the traffic */
+ SilcCipher newkey, oldkey;
/* Get cipher */
cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
}
/* Delete old cipher and allocate the new one */
- silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+ if (!silc_cipher_alloc(cipher, &newkey)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
+ oldkey = channel->channel_key;
+ channel->channel_key = newkey;
+
/* Re-generate channel key */
- if (!silc_server_create_channel_key(server, channel, 0))
+ if (!silc_server_create_channel_key(server, channel, 0)) {
+ /* We don't have new key, revert to old one */
+ channel->channel_key = oldkey;
goto out;
-
+ }
+
+ /* Remove old channel key for good */
+ silc_cipher_free(oldkey);
+
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
silc_server_send_channel_key(server, NULL, channel,
if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
/* Cipher mode is unset. Remove the cipher and revert back to
default cipher */
+ SilcCipher newkey, oldkey;
cipher = channel->cipher;
/* Delete old cipher and allocate default one */
- silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc",
- &channel->channel_key)) {
+ if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
+ oldkey = channel->channel_key;
+ channel->channel_key = newkey;
+
/* Re-generate channel key */
- if (!silc_server_create_channel_key(server, channel, 0))
+ if (!silc_server_create_channel_key(server, channel, 0)) {
+ /* We don't have new key, revert to old one */
+ channel->channel_key = oldkey;
goto out;
+ }
+ /* Remove old channel key for good */
+ silc_cipher_free(oldkey);
+
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
silc_server_send_channel_key(server, NULL, channel,
if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
/* HMAC to use protect the traffic */
unsigned char hash[32];
+ SilcHmac newhmac;
/* Get hmac */
hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
}
/* Delete old hmac and allocate the new one */
- silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
+ if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
+ silc_hmac_free(channel->hmac);
+ channel->hmac = newhmac;
+
/* Set the HMAC key out of current channel key. The client must do
this locally. */
- silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
- hash);
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ channel->key_len / 8, hash);
silc_hmac_set_key(channel->hmac, hash,
- silc_hash_len(channel->hmac->hash));
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
/* Hmac mode is unset. Remove the hmac and revert back to
default hmac */
+ SilcHmac newhmac;
unsigned char hash[32];
hmac = channel->hmac_name;
/* Delete old hmac and allocate default one */
silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL,
- &channel->hmac)) {
+ if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
+ silc_hmac_free(channel->hmac);
+ channel->hmac = newhmac;
+
/* Set the HMAC key out of current channel key. The client must do
this locally. */
- silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ channel->key_len / 8,
hash);
silc_hmac_set_key(channel->hmac, hash,
- silc_hash_len(channel->hmac->hash));
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
}
}
}
if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
- /* The client tries to claim the founder rights. */
- unsigned char *tmp_auth;
- uint32 tmp_auth_len, auth_len;
- void *auth;
-
- if (target_client != client) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU);
- goto out;
- }
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ /* The client tries to claim the founder rights. */
+ unsigned char *tmp_auth;
+ uint32 tmp_auth_len, auth_len;
+ void *auth;
+
+ if (target_client != client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
- if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
- !channel->founder_key) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU);
- goto out;
- }
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+ !channel->founder_key || !idata->public_key ||
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ idata->public_key)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
- tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
- if (!tmp_auth) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
+ tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
+ if (!tmp_auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
- auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
- (void *)channel->founder_passwd : (void *)channel->founder_key);
- auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
- channel->founder_passwd_len : 0);
-
- if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
- channel->founder_method, auth, auth_len,
- idata->hash, client->id, SILC_ID_CLIENT)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_AUTH_FAILED);
- goto out;
+ auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ (void *)channel->founder_passwd : (void *)channel->founder_key);
+ auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ channel->founder_passwd_len : 0);
+
+ if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
+ channel->founder_method, auth, auth_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+ notify = TRUE;
}
-
- sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
- notify = TRUE;
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
if (target_client == client) {
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- if (server->server_type == SILC_SERVER) {
+ if (server->server_type != SILC_ROUTER) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
SILC_STATUS_ERR_AUTH_FAILED);
goto out;
silc_buffer_free(packet);
out:
- if (channel_id)
- silc_free(channel_id);
+ silc_free(channel_id);
silc_server_command_free(cmd);
}
server_entry = silc_idlist_find_server_by_conn(server->local_list,
name, port, FALSE, NULL);
+ if (!server_entry)
+ server_entry = silc_idlist_find_server_by_conn(server->global_list,
+ name, port, FALSE, NULL);
if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
SILC_STATUS_ERR_NO_SERVER_ID);
/* Close the connection to the server */
sock = (SilcSocketConnection)server_entry->connection;
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock);
+
+ /* If we shutdown primary router connection manually then don't trigger
+ any reconnect or backup router connections, by setting the router
+ to NULL here. */
+ if (server->router == server_entry) {
+ server->id_entry->router = NULL;
+ server->router = NULL;
+ server->standalone = TRUE;
+ }
+ silc_server_free_sock_user_data(server, sock);
silc_server_close_connection(server, sock);
out:
}
out:
- if (id)
- silc_free(id);
+ silc_free(id);
silc_server_command_free(cmd);
}
channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
- if (!channel) {
- if (server->server_type == SILC_SERVER && !server->standalone &&
+ if (!channel || channel->disabled) {
+ if (server->server_type != SILC_ROUTER && !server->standalone &&
!cmd->pending) {
SilcBuffer tmpbuf;
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
/* Send USERS command */
}
}
- /* 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 */
silc_buffer_free(packet);
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
- if (id)
- silc_free(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"));
client_id, TRUE, NULL);
if ((!client && !cmd->pending && !server->standalone) ||
- (client && !client->connection && !cmd->pending &&
- !server->standalone) ||
- (client && !client->data.public_key && !cmd->pending &&
- !server->standalone)) {
+ (client && !client->connection && !cmd->pending) ||
+ (client && !client->data.public_key && !cmd->pending)) {
SilcBuffer tmpbuf;
uint16 old_ident;
SilcSocketConnection dest_sock;
goto out;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, dest_sock,
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);
server_entry = silc_idlist_find_server_by_id(server->global_list,
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;
old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(cmd->payload);
silc_server_packet_send(server, server->router->connection,
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)