SilcCommand command,
SilcCommandStatus status,
uint32 arg_type,
- unsigned char *arg,
+ const unsigned char *arg,
uint32 arg_len);
static bool
silc_server_command_pending_error_check(SilcServerCommandContext cmd,
ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
/* Parse the command payload in the packet */
- ctx->payload = silc_command_payload_parse(packet->buffer);
+ ctx->payload = silc_command_payload_parse(packet->buffer->data,
+ packet->buffer->len);
if (!ctx->payload) {
SILC_LOG_ERROR(("Bad command payload, packet dropped"));
silc_buffer_free(packet->buffer);
SilcCommand command,
SilcCommandStatus status,
uint32 arg_type,
- unsigned char *arg,
+ const unsigned char *arg,
uint32 arg_len)
{
SilcBuffer buffer;
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);
+ SilcBuffer buffer;
+
+ /* Send the same command reply payload */
+ silc_command_set_ident(cmdr->payload,
+ silc_command_get_ident(cmd->payload));
+ buffer = silc_command_payload_encode_payload(cmdr->payload);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ buffer->data, buffer->len, FALSE);
+ silc_buffer_free(buffer);
return TRUE;
}
for (i = 0; i < clients_count; i++) {
entry = clients[i];
-
- if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
- !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
- !entry->router)
+ if (!entry)
continue;
+ if ((entry->nickname && entry->username && entry->userinfo) ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (!entry->router)
+ continue;
+
+ /* If we are normal server, and we've not resolved this client from
+ router and it is global client, we'll check whether it is on some
+ channel. If not then we cannot be sure about its validity, and
+ we'll resolve it from router. */
+ if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+ entry->connection || silc_hash_table_count(entry->channels))
+ continue;
+ }
+
/* We need to resolve this entry since it is not complete */
if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count,
- int count)
+ int count,
+ const char *nickname,
+ SilcClientID **client_ids)
{
SilcServer server = cmd->server;
char *tmp;
- int i, k, len;
+ int i, k, len, valid_count;
SilcBuffer packet, idp, channels;
SilcClientEntry entry;
SilcCommandStatus status;
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++)
+ /* Process only valid clients and ignore those that are not registered. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- len++;
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
- if (len == 0 && clients_count) {
- entry = clients[0];
- if (entry->nickname) {
+ if (!valid_count) {
+ /* No valid clients found, send error reply */
+ if (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);
+ 3, nickname, strlen(nickname));
+ } else if (client_ids && client_ids[0]) {
+ SilcBuffer idp = silc_id_payload_encode(client_ids[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);
}
-
return;
}
- status = SILC_STATUS_OK;
- if (len > 1)
+ /* Start processing found clients. */
+ if (valid_count > 1)
status = SILC_STATUS_LIST_START;
+ else
+ status = SILC_STATUS_OK;
for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
+ if (!entry)
+ continue;
- 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,
- 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);
- }
- }
+#if 1
+ /* XXX REMOVE */
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username || !entry->userinfo) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+ "|| !entry->userinfo) triggered: should have not!"));
continue;
}
+#endif
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && k == clients_count - 1)
+ if (valid_count > 1 && k == valid_count - 1)
status = SILC_STATUS_LIST_END;
-
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
- if (count && k - 1 > count)
- break;
-
- /* Sanity check, however these should never fail. However, as
- this sanity check has been added here they have failed. */
- if (!entry->nickname || !entry->username || !entry->userinfo)
- continue;
-
/* Send WHOIS reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
}
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);
}
}
+static void
+silc_server_command_whois_send_router(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ 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);
+
+ /* Send WHOIS command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ 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_WHOIS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+}
+
static int
silc_server_command_whois_process(SilcServerCommandContext cmd)
{
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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !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));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOIS command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- 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_WHOIS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_whois,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
+ /* 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;
- silc_buffer_free(tmpbuf);
+ /* Send the WHOIS request to the router only if it included nickname.
+ Since nicknames can be expanded into many clients we need to send it
+ to router. If the WHOIS included only client ID's we will check them
+ first locally since we just might have them. */
+ if (nick && !client_id_count && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_whois_send_router(cmd);
ret = -1;
goto out;
}
- /* 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_SERVER)
check_global = TRUE;
- /* 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 */
clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
clients[clients_count++] = entry;
+ } else {
+ /* If we are normal server and did not send the request first to router
+ do it now, since we do not have the Client ID information. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_whois_send_router(cmd);
+ ret = -1;
+ goto out;
+ }
}
}
} else {
+ /* Find by nickname */
if (!silc_idlist_get_clients_by_hash(server->local_list,
nick, server->md5hash,
&clients, &clients_count))
}
if (!clients) {
+ /* If we are normal server and did not send the request first to router
+ do it now, since we do not have the information. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_whois_send_router(cmd);
+ ret = -1;
+ goto out;
+ }
+
/* 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,
/* Send the command reply */
silc_server_command_whois_send_reply(cmd, clients, clients_count,
- count);
+ count, nick, client_id);
out:
if (client_id_count) {
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.status & SILC_IDLIST_STATUS_REGISTERED)
- continue;
- if (entry->id == NULL)
+ if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED || !entry->id)
continue;
if (count && i - 1 == count)
if (clients_count > 2)
status = SILC_STATUS_LIST_ITEM;
-
if (clients_count > 1 && i == clients_count - 1)
status = SILC_STATUS_LIST_END;
/* Sanity check, however these should never fail. However, as
this sanity check has been added here they have failed. */
- if (!entry->nickname || !entry->username)
+ if (!entry->nickname || !entry->username || !entry->userinfo) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+ "|| !entry->userinfo) triggered: should have not!"));
+ continue;
+ }
+
+#if 1
+ /* XXX REMOVE */
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username) "
+ "triggered: should have not!"));
continue;
+ }
+#endif
/* Send WHOWAS 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));
strcat(uh, "*private*");
}
- if (entry->userinfo)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo));
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
-
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ entry->userinfo ?
+ strlen(entry->userinfo) : 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 WHOWAS command to our router */
******************************************************************************/
-static bool
+static void
+silc_server_command_identify_send_router(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ 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);
+
+ /* Send IDENTIFY command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ 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_IDENTIFY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+}
+
+static int
silc_server_command_identify_parse(SilcServerCommandContext cmd,
SilcClientEntry **clients,
uint32 *clients_count,
if (!tmp) {
/* No ID, get the names. */
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ return -1;
+ }
+
/* Try to get nickname@server. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
if (tmp) {
silc_free(nick_server);
if (!(*clients)) {
+ /* the nickname does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_NICK,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
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) *
}
if (!(*servers)) {
+ /* the server does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_SERVER,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
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) *
}
if (!(*channels)) {
+ /* The channel does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CHANNEL,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
if (!(*clients) && !(*servers) && !(*channels)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return FALSE;
+ return 0;
}
} else {
/* Command includes ID, we must use that. Also check whether the command
if (!tmp)
continue;
- idp = silc_id_payload_parse_data(tmp, len);
+ idp = silc_id_payload_parse(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;
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return 0;
}
id = silc_id_payload_get_id(idp);
(*clients_count + 1));
(*clients)[(*clients_count)++] = (SilcClientEntry)entry;
} else {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, tmp, len);
- error = TRUE;
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
(*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;
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
(*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;
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
}
else
*count = 0;
- return TRUE;
+ return 1;
}
/* Checks that all mandatory fields in client entry are present. If not
for (i = 0; i < clients_count; i++) {
entry = clients[i];
-
- if (!entry || entry->nickname ||
- !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
- !entry->router)
+ if (!entry)
continue;
+ if (entry->nickname ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (!entry->router)
+ continue;
+
+ /* If we are normal server, and we've not resolved this client from
+ router and it is global client, we'll check whether it is on some
+ channel. If not then we cannot be sure about its validity, and
+ we'll resolve it from router. */
+ if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+ entry->connection || silc_hash_table_count(entry->channels))
+ continue;
+ }
+
/* We need to resolve this entry since it is not complete */
if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
int count)
{
SilcServer server = cmd->server;
- int i, k, len;
+ int i, k, len, valid_count;
SilcBuffer packet, idp;
SilcCommandStatus status;
uint16 ident = silc_command_get_ident(cmd->payload);
if (clients) {
SilcClientEntry entry;
- len = 0;
- for (i = 0; i < clients_count; i++)
+ /* Process only valid entries. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- len++;
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
+
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
- if (len == 0 && clients_count) {
- entry = clients[0];
- if (entry->nickname) {
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ 3, tmp, strlen(tmp));
} else {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, (uint32 *)&len);
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);
+ 2, tmp, len);
}
-
return;
}
- if (len > 1)
+ /* Process all valid client entries and send command replies */
+
+ if (valid_count > 1)
status = SILC_STATUS_LIST_START;
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);
- }
+ if (!entry)
continue;
- }
-
+
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (clients_count > 1 && k == clients_count - 1
+ if (valid_count > 1 && k == valid_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);
server->server_name, len);
}
}
-
+
if (!entry->username) {
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
status, ident, 2,
}
}
- status = (status == SILC_STATUS_LIST_ITEM ?
- SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
if (servers) {
SilcServerEntry entry;
/* 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 {
- 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, 2,
+ 2, idp->data, idp->len,
+ 3, entry->server_name,
+ entry->server_name ?
+ strlen(entry->server_name) : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
}
}
- status = (status == SILC_STATUS_LIST_ITEM ?
- SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
if (channels) {
SilcChannelEntry entry;
/* 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, 2,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ entry->channel_name ?
+ strlen(entry->channel_name): 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
static int
silc_server_command_identify_process(SilcServerCommandContext cmd)
{
- SilcServer server = cmd->server;
uint32 count = 0;
int ret = 0;
SilcClientEntry *clients = 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !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));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send IDENTIFY command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- 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_IDENTIFY,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_identify,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- ret = -1;
- goto out;
- }
-
- /* We are ready to process the command request. Let's search for the
- requested client and send reply to the requesting client. */
-
/* Parse the IDENTIFY request */
- if (!silc_server_command_identify_parse(cmd,
- &clients, &clients_count,
- &servers, &servers_count,
- &channels, &channels_count,
- &count))
- return 0;
+ ret = silc_server_command_identify_parse(cmd,
+ &clients, &clients_count,
+ &servers, &servers_count,
+ &channels, &channels_count,
+ &count);
+ if (ret < 1)
+ return ret;
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
silc_free(clients);
silc_free(servers);
silc_free(channels);
-
return ret;
}
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;
}
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);
if (strlen(nick) > 128)
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 */
while (!silc_id_create_client_id(cmd->server, cmd->server->id,
cmd->server->rng,
/* Update client cache */
silc_idcache_add(server->local_list->clients, client->nickname,
- client->id, (void *)client, FALSE);
+ client->id, (void *)client, 0, NULL);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
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);
/* Local list */
for (i = 0; i < lch_count; i++) {
entry = lch[i];
-
if (!entry)
continue;
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 (i >= 1 && i == lch_count - 1 && !gch_count)
status = SILC_STATUS_LIST_END;
idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
}
/* Send the reply */
- if (topic)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, strlen(topic),
- 5, usercount, 4);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 5, usercount, 4);
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, topic ? strlen(topic) : 0,
+ 5, usercount, 4);
silc_server_packet_send(cmd->server, cmd->sock,
SILC_PACKET_COMMAND_REPLY, 0, packet->data,
packet->len, FALSE);
silc_buffer_free(idp);
}
- status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
-
/* Global list */
for (i = 0; i < gch_count; i++) {
entry = gch[i];
-
if (!entry)
continue;
if (i >= 1)
status = SILC_STATUS_LIST_ITEM;
-
- if (gch_count > 1 && i == lch_count - 1)
+ if (i >= 1 && i == gch_count - 1)
status = SILC_STATUS_LIST_END;
idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
}
/* Send the reply */
- if (topic)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, strlen(topic),
- 5, usercount, 4);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 5, usercount, 4);
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, topic ? strlen(topic) : 0,
+ 5, usercount, 4);
silc_server_packet_send(cmd->server, cmd->sock,
SILC_PACKET_COMMAND_REPLY, 0, packet->data,
packet->len, FALSE);
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_SERVER)
- 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,
gchannels, gch_count);
+ silc_free(lchannels);
+ silc_free(gchannels);
+
out:
silc_server_command_free(cmd);
}
if (!server->standalone)
silc_server_send_notify_topic_set(server, server->router->connection,
server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel, client->id,
+ TRUE : FALSE, channel,
+ client->id, SILC_ID_CLIENT,
channel->topic);
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send notify about topic change to all clients on the channel */
- silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
SILC_NOTIFY_TYPE_TOPIC_SET, 2,
idp->data, idp->len,
channel->topic, strlen(channel->topic));
/* Send the topic to client as reply packet */
idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- if (channel->topic)
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
- SILC_STATUS_OK, ident, 2,
- 2, idp->data, idp->len,
- 3, channel->topic,
- strlen(channel->topic));
- else
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
- SILC_STATUS_OK, ident, 1,
- 2, idp->data, idp->len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp->data, idp->len,
+ 3, channel->topic,
+ channel->topic ?
+ strlen(channel->topic) : 0);
silc_server_packet_send(cmd->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);
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,
server_name = entry->server_name;
/* Send the reply */
- if (server_info)
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, ident, 3,
- 2, idp->data, idp->len,
- 3, server_name,
- strlen(server_name),
- 4, server_info,
- strlen(server_info));
- else
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, ident, 2,
- 2, idp->data, idp->len,
- 3, server_name,
- strlen(server_name));
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+ SILC_STATUS_OK, ident, 3,
+ 2, idp->data, idp->len,
+ 3, server_name,
+ strlen(server_name),
+ 4, server_info,
+ server_info ?
+ strlen(server_info) : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
SilcClientID *client_id,
bool created,
bool create_key,
- uint32 umode)
+ uint32 umode,
+ const unsigned char *auth,
+ uint32 auth_len)
{
SilcSocketConnection sock = cmd->sock;
unsigned char *tmp;
SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
uint16 ident = silc_command_get_ident(cmd->payload);
char check[512], check2[512];
+ bool founder = FALSE;
SILC_LOG_DEBUG(("Start"));
}
/*
- * Check channel modes
+ * Check founder auth payload if provided. If client can gain founder
+ * privileges it can override various conditions on joining the channel,
+ * and can have directly the founder mode set on the channel.
*/
-
- memset(check, 0, sizeof(check));
- memset(check2, 0, sizeof(check2));
- strncat(check, client->nickname, strlen(client->nickname));
- strncat(check, "!", 1);
- strncat(check, client->username, strlen(client->username));
- if (!strchr(client->username, '@')) {
- strncat(check, "@", 1);
- strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ SilcIDListData idata = (SilcIDListData)client;
+
+ if (channel->founder_key && idata->public_key &&
+ silc_pkcs_public_key_compare(channel->founder_key,
+ idata->public_key)) {
+ void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ (void *)channel->founder_passwd :
+ (void *)channel->founder_key);
+ uint32 auth_data_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ channel->founder_passwd_len : 0);
+
+ /* Check whether the client is to become founder */
+ if (silc_auth_verify_data(auth, auth_len, channel->founder_method,
+ auth_data, auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ founder = TRUE;
+ }
+ }
}
- strncat(check2, client->nickname, strlen(client->nickname));
- if (!strchr(client->nickname, '@')) {
- strncat(check2, "@", 1);
- strncat(check2, server->server_name, strlen(server->server_name));
- }
- strncat(check2, "!", 1);
- strncat(check2, client->username, strlen(client->username));
- if (!strchr(client->username, '@')) {
- strncat(check2, "@", 1);
- strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
- }
+ /*
+ * Check channel modes
+ */
- /* Check invite list if channel is invite-only channel */
- if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
- if (!channel->invite_list ||
- (!silc_string_match(channel->invite_list, check) &&
- !silc_string_match(channel->invite_list, check2))) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_INVITED);
- goto out;
+ if (!umode) {
+ memset(check, 0, sizeof(check));
+ memset(check2, 0, sizeof(check2));
+ strncat(check, client->nickname, strlen(client->nickname));
+ strncat(check, "!", 1);
+ strncat(check, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check, "@", 1);
+ strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
}
- }
- /* Check ban list if it exists. If the client's nickname, server,
- 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) ||
- silc_string_match(channel->ban_list, check2)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
- goto out;
+ strncat(check2, client->nickname, strlen(client->nickname));
+ if (!strchr(client->nickname, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, server->server_name, strlen(server->server_name));
+ }
+ strncat(check2, "!", 1);
+ strncat(check2, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ /* Check invite list if channel is invite-only channel */
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (!channel->invite_list ||
+ (!silc_string_match(channel->invite_list, check) &&
+ !silc_string_match(channel->invite_list, check2))) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_INVITED);
+ goto out;
+ }
}
- }
- /* Get passphrase */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
- if (tmp) {
- passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
- memcpy(passphrase, tmp, tmp_len);
+ /* Check ban list if it exists. If the client's nickname, server,
+ username and/or hostname is in the ban list the access to the
+ channel is denied. */
+ if (channel->ban_list) {
+ 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);
+ goto out;
+ }
+ }
+
+ /* Check user count limit if set. */
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+ if (silc_hash_table_count(channel->user_list) + 1 >
+ channel->user_limit) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_CHANNEL_IS_FULL);
+ goto out;
+ }
+ }
}
-
+
/* Check the channel passphrase if set. */
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
- if (!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;
+ /* Get passphrase */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (tmp) {
+ passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+ memcpy(passphrase, tmp, tmp_len);
}
- }
-
- /* Check user count limit if set. */
- if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
- if (silc_hash_table_count(channel->user_list) + 1 >
- channel->user_limit) {
+
+ if (!passphrase || !channel->passphrase ||
+ memcmp(channel->passphrase, passphrase,
+ strlen(channel->passphrase))) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_CHANNEL_IS_FULL);
+ SILC_STATUS_ERR_BAD_PASSWORD);
goto out;
}
}
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,
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_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_JOIN, 2,
clidp->data, clidp->len,
chidp->data, chidp->len);
/* 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);
+
+ /* If client became founder by providing correct founder auth data
+ notify the mode change to the channel. */
+ if (founder) {
+ SILC_PUT32_MSB(chl->mode, mode);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ clidp->data, clidp->len,
+ mode, 4, clidp->data, clidp->len);
+
+ /* Set CUMODE notify type to network */
+ if (!server->standalone)
+ silc_server_send_notify_cumode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ chl->mode, client->id, SILC_ID_CLIENT,
+ client->id);
+ }
}
silc_buffer_free(reply);
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- uint32 tmp_len;
+ unsigned char *auth;
+ uint32 tmp_len, auth_len;
char *tmp, *channel_name = NULL, *cipher, *hmac;
SilcChannelEntry channel;
uint32 umode = 0;
bool created = FALSE, create_key = TRUE;
SilcClientID *client_id;
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
/* Get channel name */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
goto out;
}
- /* Get cipher and hmac name */
+ /* Get cipher, hmac name and auth payload */
cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
/* See if the channel exists */
channel = silc_idlist_find_channel_by_name(server->local_list,
}
}
- 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
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 */
/* Join to the channel */
silc_server_command_join_channel(server, cmd, channel, client_id,
- created, create_key, umode);
+ created, create_key, umode,
+ auth, auth_len);
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;
SILC_STATUS_OK, ident, 2,
2, idp, idp->len,
3, motd, motd_len);
- goto out;
} else {
/* No motd */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
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,
}
idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
-
- if (entry->motd)
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
- SILC_STATUS_OK, ident, 2,
- 2, idp, idp->len,
- 3, entry->motd,
- strlen(entry->motd));
- else
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
- SILC_STATUS_OK, ident, 1,
- 2, idp, idp->len);
-
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp, idp->len,
+ 3, entry->motd,
+ entry->motd ?
+ strlen(entry->motd) : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
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)
SilcChannelClientEntry chl;
SilcBuffer packet, cidp;
unsigned char *tmp, *tmp_id, *tmp_mask;
- char *cipher = NULL, *hmac = NULL;
+ char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
uint32 mode_mask, tmp_len, tmp_len2;
uint16 ident = silc_command_get_ident(cmd->payload);
FALSE : !server->standalone);
cipher = channel->channel_key->cipher->name;
- hmac = channel->hmac->hmac->name;
+ hmac = (char *)silc_hmac_get_name(channel->hmac);
}
}
}
/* Save the passphrase */
- channel->passphrase = strdup(tmp);
+ passphrase = channel->passphrase = strdup(tmp);
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
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 : SILC_DEFAULT_CIPHER,
- &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 : SILC_DEFAULT_HMAC, 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));
}
}
/* Finally, set the mode */
channel->mode = mode_mask;
- /* Send CMODE_CHANGE notify */
+ /* Send CMODE_CHANGE notify. */
cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
cidp->data, cidp->len,
tmp_mask, 4,
cipher, cipher ? strlen(cipher) : 0,
- hmac, hmac ? strlen(hmac) : 0);
+ hmac, hmac ? strlen(hmac) : 0,
+ passphrase, passphrase ?
+ strlen(passphrase) : 0);
/* Set CMODE notify type to network */
if (!server->standalone)
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
mode_mask, client->id, SILC_ID_CLIENT,
- cipher, hmac);
+ cipher, hmac, passphrase);
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
silc_buffer_free(packet);
silc_free(channel_id);
- silc_free(cidp);
+ silc_buffer_free(cidp);
out:
silc_server_command_free(cmd);
}
if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
- !channel->founder_key) {
+ !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;
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 ?
/* Send notify to channel, notify only if mode was actually changed. */
if (notify) {
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
idp->data, idp->len,
tmp_mask, 4,
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcBuffer idp;
- uint32 tmp_len;
- unsigned char *tmp, *comment;
+ uint32 tmp_len, target_idp_len;
+ unsigned char *tmp, *comment, *target_idp;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
}
/* Get target Client ID */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (!tmp) {
+ target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
+ if (!target_idp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
SILC_STATUS_ERR_NO_CLIENT_ID);
goto out;
}
- client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ client_id = silc_id_payload_parse_id(target_idp, target_idp_len);
if (!client_id) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
SILC_STATUS_ERR_NO_CLIENT_ID);
SILC_STATUS_OK);
/* Send KICKED notify to local clients on the channel */
- idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_KICKED,
- comment ? 2 : 1,
- idp->data, idp->len,
- comment, comment ? strlen(comment) : 0);
+ SILC_NOTIFY_TYPE_KICKED, 3,
+ target_idp, target_idp_len,
+ comment, comment ? strlen(comment) : 0,
+ idp->data, idp->len);
silc_buffer_free(idp);
/* Remove the client from the channel. If the channel does not exist
TRUE : FALSE, channel, add, del);
/* Send the reply back to the client */
- if (channel->ban_list)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
- SILC_STATUS_OK, ident, 2,
- 2, id, id_len,
- 3, channel->ban_list,
- strlen(channel->ban_list) - 1);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
- SILC_STATUS_OK, ident, 1,
- 2, id, id_len);
-
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
+ SILC_STATUS_OK, ident, 2,
+ 2, id, id_len,
+ 3, channel->ban_list,
+ channel->ban_list ?
+ strlen(channel->ban_list) - 1 : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
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);
channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
- if (!channel) {
+ 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 */
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- idp = silc_id_payload_parse_data(tmp, tmp_len);
+ idp = silc_id_payload_parse(tmp, tmp_len);
if (!idp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
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,
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,