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,
silc_server_command_send_status_reply(cmd, command,
SILC_STATUS_ERR_NOT_REGISTERED);
- silc_server_command_free(cmd);
return FALSE;
}
SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
+ if (!client) {
+ silc_server_command_free(timeout->ctx);
+ silc_free(timeout);
+ }
+
/* Update access time */
client->last_command = time(NULL);
timeout->ctx,
timeout->cmd->cmd))
timeout->cmd->cb(timeout->ctx, NULL);
+ else
+ silc_server_command_free(timeout->ctx);
silc_free(timeout);
}
silc_server_command_process_timeout,
(void *)timeout,
2 - (time(NULL) - client->last_command), 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
else
silc_schedule_task_add(server->schedule, sock->sock,
silc_server_command_process_timeout,
- (void *)timeout,
- 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ (void *)timeout, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
return;
}
cmd->cb(ctx, NULL);
else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
cmd->cb(ctx, NULL);
+ else
+ silc_server_command_free(ctx);
}
/* Allocate Command Context */
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'. */
+ identifier `ident'. If there already exists pending command for the
+ specified command, ident, callback and context this function has no
+ effect. */
-void silc_server_command_pending(SilcServer server,
+bool silc_server_command_pending(SilcServer server,
SilcCommand reply_cmd,
uint16 ident,
- SilcServerPendingDestructor destructor,
SilcCommandCb callback,
void *context)
{
SilcServerCommandPending *reply;
+ /* Check whether identical pending already exists for same command,
+ ident, callback and callback context. If it does then it would be
+ error to register it again. */
+ silc_dlist_start(server->pending_commands);
+ while ((reply = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
+ if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
+ reply->callback == callback && reply->context == context)
+ return FALSE;
+ }
+
reply = silc_calloc(1, sizeof(*reply));
reply->reply_cmd = reply_cmd;
reply->ident = ident;
reply->context = context;
reply->callback = callback;
- reply->destructor = destructor;
silc_dlist_add(server->pending_commands, reply);
+
+ return TRUE;
}
/* Deletes pending command by reply command type. */
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;
i++;
}
return callbacks;
}
-/* Destructor function for pending callbacks. This is called when using
- pending commands to free the context given for the pending command. */
-
-static void silc_server_command_destructor(void *context)
-{
- silc_server_command_free((SilcServerCommandContext)context);
-}
-
/* Sends simple status message as command reply packet */
static void
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;
}
(*client_id)[0] = silc_id_payload_parse_id(tmp, len);
if ((*client_id)[0] == NULL) {
silc_free(*client_id);
+ silc_server_command_send_status_reply(cmd, command,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
return FALSE;
}
*client_id_count = 1;
for (i = 0; i < *client_id_count; i++)
silc_free((*client_id)[i]);
silc_free(*client_id);
+ silc_server_command_send_status_reply(
+ cmd, command,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
return FALSE;
}
(*client_id_count)++;
int i, k;
bool no_res = TRUE;
+ SILC_LOG_DEBUG(("Start"));
+
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) {
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_dup(cmd));
no_res = 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_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;
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->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 (!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)
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);
}
}
+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_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, ++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);
+ /* 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) {
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
ret = silc_server_command_whois_process(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
+ silc_server_command_free(cmd);
}
/******************************************************************************
/* Reprocess this packet after received reply */
silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_whowas,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
-
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
{
SilcServer server = cmd->server;
char *tmp;
- int i, count = 0, len;
+ int i, k, count = 0, len;
SilcBuffer packet, idp;
SilcClientEntry entry = NULL;
SilcCommandStatus status;
uint16 ident = silc_command_get_ident(cmd->payload);
- char found = FALSE;
char nh[256], uh[256];
+ int valid_count;
status = SILC_STATUS_OK;
- if (clients_count > 1)
- status = SILC_STATUS_LIST_START;
+ /* Process only entries that are not registered anymore. */
+ valid_count = 0;
for (i = 0; i < clients_count; i++) {
- entry = clients[i];
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ clients[i] = NULL;
+ else
+ valid_count++;
+ }
- /* 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)
- continue;
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ return;
+ }
- if (count && i - 1 == count)
- break;
+ if (valid_count > 1)
+ status = SILC_STATUS_LIST_START;
- found = TRUE;
+ for (i = 0, k = 0; i < clients_count; i++) {
+ entry = clients[i];
+ if (!entry)
+ continue;
- if (clients_count > 2)
+ if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && i == 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)
- continue;
-
/* 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));
silc_buffer_free(packet);
silc_buffer_free(idp);
- }
- if (found == FALSE && entry)
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ k++;
+ }
}
static int
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_whowas,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
-
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
silc_free(clients);
silc_free(nick);
silc_free(server_name);
-
return ret;
}
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
ret = silc_server_command_whowas_process(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
+ silc_server_command_free(cmd);
}
/******************************************************************************
******************************************************************************/
-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_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;
}
}
}
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;
}
}
}
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
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) {
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;
/* 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;
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 (len == 0 && clients_count) {
- entry = clients[0];
- if (entry->nickname) {
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
+
+ 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;
}
}
- status = (status == SILC_STATUS_LIST_ITEM ?
- SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
if (channels) {
SilcChannelEntry entry;
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, ++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);
- 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;
+ ret = 0;
/* 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;
}
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
ret = silc_server_command_identify_process(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
-}
-
-/* Checks string for bad characters and returns TRUE if they are found. */
-
-static int silc_server_command_bad_chars(char *nick)
-{
- 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;
- }
-
- return FALSE;
+ silc_server_command_free(cmd);
}
/* Server side of command NICK. Sets nickname for user. Setting
SilcServer server = cmd->server;
SilcBuffer packet, nidp, oidp = NULL;
SilcClientID *new_id;
+ uint32 nick_len;
char *nick;
uint16 ident = silc_command_get_ident(cmd->payload);
int nickfail = 0;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
/* Check nickname */
- nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (silc_server_command_bad_chars(nick) == TRUE) {
+ nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
+ if (nick_len > 128)
+ nick[128] = '\0';
+ if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
SILC_STATUS_ERR_BAD_NICKNAME);
goto out;
}
- 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);
/* 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);
SilcChannelEntry *gch,
uint32 gch_count)
{
- int i;
+ int i, k;
SilcBuffer packet, idp;
SilcChannelEntry entry;
SilcCommandStatus status;
char *topic;
unsigned char usercount[4];
uint32 users;
+ int valid_lcount = 0, valid_rcount = 0;
- for (i = 0; i < lch_count; i++)
+ for (i = 0; i < lch_count; i++) {
if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
lch[i] = NULL;
- for (i = 0; i < gch_count; i++)
+ else
+ valid_lcount++;
+ }
+ for (i = 0; i < gch_count; i++) {
if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
gch[i] = NULL;
+ else
+ valid_rcount++;
+ }
status = SILC_STATUS_OK;
if ((lch_count + gch_count) > 1)
status = SILC_STATUS_LIST_START;
/* Local list */
- for (i = 0; i < lch_count; i++) {
+ for (i = 0, k = 0; i < lch_count; i++) {
entry = lch[i];
if (!entry)
continue;
- if (i >= 1)
+ if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (i >= 1 && i == lch_count - 1 && !gch_count)
+ if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
status = SILC_STATUS_LIST_END;
idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
packet->len, FALSE);
silc_buffer_free(packet);
silc_buffer_free(idp);
+ k++;
}
/* Global list */
- for (i = 0; i < gch_count; i++) {
+ for (i = 0, k = 0; i < gch_count; i++) {
entry = gch[i];
if (!entry)
continue;
- if (i >= 1)
+ if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (i >= 1 && i == gch_count - 1)
+ if (valid_rcount > 1 && k == valid_rcount - 1)
status = SILC_STATUS_LIST_END;
idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
packet->len, FALSE);
silc_buffer_free(packet);
silc_buffer_free(idp);
+ k++;
}
}
/* 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;
+ goto out;
}
/* Get Channel ID */
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, FALSE,
SILC_NOTIFY_TYPE_TOPIC_SET, 2,
idp->data, idp->len,
channel->topic, strlen(channel->topic));
tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
if (tmp) {
char invite[512];
+ bool resolve;
dest_id = silc_id_payload_parse_id(tmp, len);
if (!dest_id) {
}
/* Get the client entry */
- dest = silc_server_get_client_resolve(server, dest_id);
+ dest = silc_server_get_client_resolve(server, dest_id, &resolve);
if (!dest) {
- if (server->server_type != SILC_SERVER) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ if (server->server_type != SILC_SERVER || !resolve) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
goto out;
}
receiving the reply to the query. */
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
server->cmd_ident,
- silc_server_command_destructor,
silc_server_command_invite,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_free(channel_id);
silc_free(dest_id);
- return;
+ goto out;
}
/* Check whether the requested client is already on the channel. */
SilcClientID *client_id;
unsigned char *tmp, *comment;
uint32 tmp_len, tmp_len2;
+ bool local;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
/* Get the client entry */
remote_client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
+ local = TRUE;
if (!remote_client) {
remote_client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
+ local = FALSE;
if (!remote_client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
silc_server_close_connection(server, sock);
} else {
+ /* Update statistics */
+ if (remote_client->connection)
+ server->stat.my_clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
+
/* Remove remote client */
- if (!silc_idlist_del_client(server->global_list, remote_client))
- silc_idlist_del_client(server->local_list, remote_client);
+ silc_idlist_del_client(local ? server->local_list :
+ server->global_list, remote_client);
}
out:
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_INFO,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_info,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
if (!entry && !cmd->pending && !server->standalone) {
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_INFO,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_info,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
}
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;
+ bool resolve;
SILC_LOG_DEBUG(("Start"));
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
client = (SilcClientEntry)sock->user_data;
} else {
- client = silc_server_get_client_resolve(server, client_id);
+ client = silc_server_get_client_resolve(server, client_id, &resolve);
if (!client) {
if (cmd->pending)
goto out;
+ if (!resolve) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
/* The client info is being resolved. Reprocess this packet after
receiving the reply to the query. */
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- server->cmd_ident, NULL,
+ server->cmd_ident,
silc_server_command_join,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
- return;
+ goto out;
}
cmd->pending = FALSE;
}
/*
- * 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 (!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;
+ 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 (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) {
+ /* 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);
+ }
+
if (!passphrase || !channel->passphrase ||
- memcmp(channel->passphrase, passphrase,
- strlen(channel->passphrase))) {
+ memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_PASSWORD);
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;
- }
- }
-
/*
* Client is allowed to join to the channel. Make it happen.
*/
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);
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);
silc_buffer_free(clidp);
silc_buffer_free(chidp);
{
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);
}
channel_name = tmp;
- if (strlen(channel_name) > 256)
+ if (tmp_len > 256)
channel_name[255] = '\0';
- if (silc_server_command_bad_chars(channel_name) == TRUE) {
+ if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_CHANNEL);
goto out;
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,
channel_name, NULL);
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
- /* If this is coming from client the Client ID in the command packet must
- be same as the client's ID. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
- SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
- if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- }
+ SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+ client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
if (!channel || channel->disabled) {
/* Channel not found */
channel = silc_server_create_new_channel(server, server->id, cipher,
hmac, channel_name, TRUE);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_JOIN,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_join,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
- return;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
}
/* We are router and the channel does not seem exist so we will check
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 (silc_argument_get_arg_type(reply->args, 7, NULL))
+ create_key = FALSE; /* Router returned the key already */
}
+
+ if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
+ !silc_hash_table_count(channel->user_list))
+ created = TRUE;
}
/* If the channel does not have global users and is also empty the client
/* 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);
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_MOTD,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_motd,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
if (!entry && !cmd->pending && !server->standalone) {
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_MOTD,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_motd,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
if (!entry) {
goto out;
}
} else {
- if (client->mode & SILC_UMODE_SERVER_OPERATOR)
- /* Remove the server operator rights */
+ /* Remove the server operator rights */
+ if (client->mode & SILC_UMODE_SERVER_OPERATOR) {
client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
+ if (client->connection)
+ server->stat.my_server_ops--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.server_ops--;
+ }
}
if (mask & SILC_UMODE_ROUTER_OPERATOR) {
goto out;
}
} else {
- if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
- /* Remove the router operator rights */
+ /* Remove the router operator rights */
+ if (client->mode & SILC_UMODE_ROUTER_OPERATOR) {
client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
+ if (client->connection)
+ server->stat.my_router_ops--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.router_ops--;
+ }
}
if (mask & SILC_UMODE_GONE) {
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);
/* The mode is removed and we need to generate and distribute
new channel key. Clients are not using private channel keys
anymore after this. */
-
+
/* Re-generate channel key */
if (!silc_server_create_channel_key(server, channel, 0))
goto out;
-
+
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
silc_server_send_channel_key(server, NULL, channel,
server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
-
+
cipher = channel->channel_key->cipher->name;
hmac = (char *)silc_hmac_get_name(channel->hmac);
}
}
-
+
if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
/* User limit is set on channel */
uint32 user_limit;
}
/* Save the passphrase */
- channel->passphrase = strdup(tmp);
+ passphrase = channel->passphrase = strdup(tmp);
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
/* 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,
/* If the target client is founder, no one else can change their mode
but themselves. */
- if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU);
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
goto out;
}
/* 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,
silc_server_send_notify_kicked(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
- target_client->id, comment);
+ target_client->id, client->id, comment);
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
/* Client is now server operator */
client->mode |= SILC_UMODE_SERVER_OPERATOR;
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_server_ops++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.server_ops++;
+
/* Send UMODE change to primary router */
if (!server->standalone)
silc_server_send_notify_umode(server, server->router->connection, TRUE,
/* Client is now router operator */
client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_router_ops++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.router_ops++;
+
/* Send UMODE change to primary router */
if (!server->standalone)
silc_server_send_notify_umode(server, server->router->connection, TRUE,
}
/* Get entry to the channel user list */
- silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+ if (!silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
/* The client must be at least channel operator. */
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2, id, id_len,
3, channel->ban_list,
channel->ban_list ?
- strlen(channel->ban_list) - 1 : 0);
+ strlen(channel->ban_list) -1 : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
server->router = NULL;
server->standalone = TRUE;
}
- silc_server_free_sock_user_data(server, sock);
+ silc_server_free_sock_user_data(server, sock, NULL);
silc_server_close_connection(server, sock);
out:
/* Reprocess this packet after received reply */
silc_server_command_pending(server, SILC_COMMAND_USERS,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_users,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, ident);
-
silc_buffer_free(tmpbuf);
silc_free(id);
- return;
+ goto out;
}
/* Check the global list as well. */
uint32 tmp_len, pklen;
SilcBuffer pk = NULL;
SilcIdType id_type;
+ SilcPublicKey public_key;
SILC_LOG_DEBUG(("Start"));
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_GETKEY,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_getkey,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
-
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
if (!client) {
/* The client is locally connected, just get the public key and
send it back. If they key does not exist then do not send it,
send just OK reply */
- if (!client->data.public_key) {
+ public_key = client->data.public_key;
+ if (!public_key) {
pkdata = NULL;
pklen = 0;
} else {
- tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
pk = silc_buffer_alloc(4 + tmp_len);
silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
silc_buffer_format(pk,
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_GETKEY,
silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
silc_server_command_getkey,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
-
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- return;
+ goto out;
}
if (!server_entry) {
}
/* If they key does not exist then do not send it, send just OK reply */
- if (!server_entry->data.public_key) {
+ public_key = (!server_entry->data.public_key ?
+ (server_entry == server->id_entry ? server->public_key :
+ NULL) : server_entry->data.public_key);
+ if (!public_key) {
pkdata = NULL;
pklen = 0;
} else {
- tmp = silc_pkcs_public_key_encode(server_entry->data.public_key,
- &tmp_len);
+ tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
pk = silc_buffer_alloc(4 + tmp_len);
silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
silc_buffer_format(pk,