silc_server_command_send_status_data(SilcServerCommandContext cmd,
SilcCommand command,
SilcCommandStatus status,
- unsigned int arg_type,
+ uint32 arg_type,
unsigned char *arg,
- unsigned int arg_len);
+ uint32 arg_len);
SILC_TASK_CALLBACK(silc_server_command_process_timeout);
/* Server command list. */
SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
- SILC_SERVER_CMD(restart, RESTART,
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(close, CLOSE,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
{ NULL, 0 },
};
#define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max) \
do { \
- unsigned int _argc = silc_argument_get_arg_num(cmd->args); \
+ uint32 _argc = silc_argument_get_arg_num(cmd->args); \
\
SILC_LOG_DEBUG(("Start")); \
\
void silc_server_command_pending(SilcServer server,
SilcCommand reply_cmd,
- unsigned short ident,
+ uint16 ident,
SilcServerPendingDestructor destructor,
SilcCommandCb callback,
void *context)
void silc_server_command_pending_del(SilcServer server,
SilcCommand reply_cmd,
- unsigned short ident)
+ uint16 ident)
{
SilcServerCommandPending *r;
int silc_server_command_pending_check(SilcServer server,
SilcServerCommandReplyContext ctx,
SilcCommand command,
- unsigned short ident)
+ uint16 ident)
{
SilcServerCommandPending *r;
silc_server_command_send_status_data(SilcServerCommandContext cmd,
SilcCommand command,
SilcCommandStatus status,
- unsigned int arg_type,
+ uint32 arg_type,
unsigned char *arg,
- unsigned int arg_len)
+ uint32 arg_len)
{
SilcBuffer buffer;
static int
silc_server_command_whois_parse(SilcServerCommandContext cmd,
SilcClientID ***client_id,
- unsigned int *client_id_count,
+ uint32 *client_id_count,
char **nickname,
char **server_name,
int *count,
SilcCommand command)
{
unsigned char *tmp;
- unsigned int len;
- unsigned int argc = silc_argument_get_arg_num(cmd->args);
+ uint32 len;
+ uint32 argc = silc_argument_get_arg_num(cmd->args);
int i, k;
/* If client ID is in the command it must be used instead of nickname */
static char
silc_server_command_whois_check(SilcServerCommandContext cmd,
SilcClientEntry *clients,
- unsigned int clients_count)
+ uint32 clients_count)
{
SilcServer server = cmd->server;
int i;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (!entry || entry->data.registered == FALSE)
+ continue;
+
if (!entry->nickname || !entry->username || !entry->userinfo) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
if (!entry->router)
continue;
static void
silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
- unsigned int clients_count)
+ uint32 clients_count,
+ int count)
{
SilcServer server = cmd->server;
char *tmp;
- int i, count = 0, len;
- SilcBuffer packet, idp;
+ int i, k, len;
+ SilcBuffer packet, idp, channels;
SilcClientEntry entry;
SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint16 ident = silc_command_get_ident(cmd->payload);
char nh[128], uh[128];
unsigned char idle[4], mode[4];
SilcSocketConnection hsock;
+ len = 0;
+ for (i = 0; i < clients_count; i++)
+ if (clients[i]->data.registered)
+ len++;
+
status = SILC_STATUS_OK;
- if (clients_count > 1)
+ if (len > 1)
status = SILC_STATUS_LIST_START;
- for (i = 0; i < clients_count; i++) {
+ for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->connection && entry->data.registered == FALSE) {
- if (clients_count == 1)
+ if (entry->data.registered == FALSE) {
+ if (clients_count == 1) {
+ 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_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
continue;
}
- if (count && i - 1 == count)
- break;
-
- if (clients_count > 2)
+ if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (clients_count > 1 && i == clients_count - 1)
+ if (clients_count > 1 && k == clients_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)
strncat(nh, entry->nickname, strlen(entry->nickname));
if (!strchr(entry->nickname, '@')) {
strncat(nh, "@", 1);
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- strncat(nh, entry->router ? entry->router->server_name :
- server->server_name, len);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
}
strncat(uh, entry->username, strlen(entry->username));
len = strlen(hsock->hostname);
strncat(uh, hsock->hostname, len);
}
+
+ channels = silc_server_get_client_channel_list(server, entry);
+ SILC_PUT32_MSB(entry->mode, mode);
+
if (entry->connection) {
SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
}
- SILC_PUT32_MSB(entry->mode, mode);
-
- 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);
+ 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);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
silc_buffer_free(packet);
silc_buffer_free(idp);
+ if (channels)
+ silc_buffer_free(channels);
+
+ k++;
}
}
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
+ uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
/* Protocol dictates that we must always send the received WHOIS request
if (server->server_type == SILC_SERVER && !cmd->pending &&
!server->standalone) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count);
}
/* Check global list as well */
- if (!clients) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
}
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
}
+ } else {
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count);
}
if (!clients) {
}
/* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count);
+ silc_server_command_whois_send_reply(cmd, clients, clients_count,
+ count);
out:
if (client_id_count) {
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
+ uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
/* Parse the whois request */
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count);
}
/* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
+ if (server->server_type == SILC_ROUTER) {
if (client_id_count) {
/* Check all Client ID's received in the command packet */
for (i = 0; i < client_id_count; i++) {
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count);
}
}
}
/* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count);
+ silc_server_command_whois_send_reply(cmd, clients, clients_count,
+ count);
out:
if (client_id_count) {
int *count)
{
unsigned char *tmp;
- unsigned int len;
+ uint32 len;
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
if (!tmp) {
return TRUE;
}
+static char
+silc_server_command_whowas_check(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;
+ int i;
+ SilcClientEntry entry;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ if (!entry->nickname || !entry->username) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ if (!entry->router)
+ continue;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command */
+ silc_server_packet_send(server, entry->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_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);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
static void
silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
- unsigned int clients_count)
+ uint32 clients_count)
{
SilcServer server = cmd->server;
char *tmp;
SilcBuffer packet, idp;
SilcClientEntry entry = NULL;
SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint16 ident = silc_command_get_ident(cmd->payload);
char found = FALSE;
+ char nh[256], uh[256];
status = SILC_STATUS_OK;
if (clients_count > 1)
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
- {
- char nh[256], uh[256];
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
len = entry->router ? strlen(entry->router->server_name) :
strlen(server->server_name);
strncat(nh, entry->router ? entry->router->server_name :
server->server_name, len);
}
+ }
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- strcat(uh, "*private*");
- }
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ strcat(uh, "*private*");
+ }
+ if (entry->userinfo)
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
status, ident, 4,
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));
+
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL;
+ uint32 clients_count = 0;
int ret = 0;
/* Protocol dictates that we must always send the received WHOWAS request
if (server->server_type == SILC_SERVER &&
!cmd->pending && !server->standalone) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
silc_command_get_ident(cmd->payload),
silc_server_command_destructor,
- silc_server_command_whois,
+ silc_server_command_whowas,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
return 0;
/* Get all clients matching that nickname from local list */
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
/* Check global list as well */
- if (!clients) {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- }
+ if (!silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
- if (!clients) {
- /* Such client(s) really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
+ if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
+ ret = -1;
goto out;
}
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL;
+ uint32 clients_count = 0;
int ret = 0;
/* Parse the whowas request */
/* Process the command request. Let's search for the requested client and
send reply to the requesting server. */
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
/* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
+ if (server->server_type == SILC_ROUTER) {
+ if (!silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
}
if (!clients) {
static char
silc_server_command_identify_check(SilcServerCommandContext cmd,
SilcClientEntry *clients,
- unsigned int clients_count)
+ uint32 clients_count)
{
SilcServer server = cmd->server;
int i;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (!entry || entry->data.registered == FALSE)
+ continue;
+
if (!entry->nickname) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
if (!entry->router)
continue;
static void
silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
- unsigned int clients_count)
+ uint32 clients_count,
+ int count)
{
SilcServer server = cmd->server;
char *tmp;
- int i, count = 0, len;
+ int i, k, len;
SilcBuffer packet, idp;
SilcClientEntry entry;
SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char nh[256], uh[256];
+ SilcSocketConnection hsock;
+
+ len = 0;
+ for (i = 0; i < clients_count; i++)
+ if (clients[i]->data.registered)
+ len++;
status = SILC_STATUS_OK;
- if (clients_count > 1)
+ if (len > 1)
status = SILC_STATUS_LIST_START;
- for (i = 0; i < clients_count; i++) {
+ for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->connection && entry->data.registered == FALSE) {
- if (clients_count == 1)
+ if (entry->data.registered == FALSE) {
+ 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_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
continue;
}
- if (count && i - 1 == count)
- break;
-
- if (clients_count > 2)
+ if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (clients_count > 1 && i == clients_count - 1)
+ if (clients_count > 1 && k == clients_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
/* Send IDENTIFY reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
- /* XXX */
- {
- char nh[256], uh[256];
- SilcSocketConnection hsock;
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
len = entry->router ? strlen(entry->router->server_name) :
strlen(server->server_name);
strncat(nh, entry->router ? entry->router->server_name :
server->server_name, len);
}
+ }
- if (!entry->username) {
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 2,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh));
- } else {
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- hsock = (SilcSocketConnection)entry->connection;
- len = strlen(hsock->hostname);
- strncat(uh, hsock->hostname, len);
- }
-
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
+ if (!entry->username) {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh));
+ } else {
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = strlen(hsock->hostname);
+ strncat(uh, hsock->hostname, len);
}
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
}
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
}
}
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
+ uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
/* Protocol dictates that we must always send the received IDENTIFY request
if (server->server_type == SILC_SERVER &&
!cmd->pending && !server->standalone) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count);
}
/* Check global list as well */
- if (!clients) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
}
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
}
+ } else {
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count);
}
if (!clients) {
}
/* Send the command reply to the client */
- silc_server_command_identify_send_reply(cmd, clients, clients_count);
+ silc_server_command_identify_send_reply(cmd, clients, clients_count,
+ count);
out:
if (client_id_count) {
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
+ int count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
+ uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
/* Parse the IDENTIFY request */
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count);
}
/* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
+ if (server->server_type == SILC_ROUTER) {
if (client_id_count) {
/* Check all Client ID's received in the command packet */
for (i = 0; i < client_id_count; i++) {
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count);
}
}
}
/* Send the command reply */
- silc_server_command_identify_send_reply(cmd, clients, clients_count);
+ silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
out:
if (client_id_count) {
SilcBuffer packet, nidp, oidp;
SilcClientID *new_id;
char *nick;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint16 ident = silc_command_get_ident(cmd->payload);
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
silc_server_send_notify_nick_change(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, client->id,
- new_id, SILC_ID_CLIENT_LEN);
+ new_id);
/* Remove old cache entry */
- silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
- client->id);
+ silc_idcache_del_by_context(server->local_list->clients, client);
oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Free old ID */
- if (client->id) {
- memset(client->id, 0, SILC_ID_CLIENT_LEN);
+ if (client->id)
silc_free(client->id);
- }
/* Save the nickname as this client is our local client */
if (client->nickname)
/* Update client cache */
silc_idcache_add(server->local_list->clients, client->nickname,
- SILC_ID_CLIENT, client->id, (void *)client, TRUE, FALSE);
+ client->id, (void *)client, FALSE);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(list)
+/* Sends the LIST command reply */
+
+static void
+silc_server_command_list_send_reply(SilcServerCommandContext cmd,
+ SilcChannelEntry *lch,
+ uint32 lch_count,
+ SilcChannelEntry *gch,
+ uint32 gch_count)
{
+ int i;
+ SilcBuffer packet, idp;
+ SilcChannelEntry entry;
+ SilcCommandStatus status;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char *topic;
+ unsigned char usercount[4];
+ uint32 users;
+
+ 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++)
+ if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+ gch[i] = NULL;
+
+ status = SILC_STATUS_OK;
+ if ((lch_count + gch_count) > 1)
+ status = SILC_STATUS_LIST_START;
+
+ /* 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)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_list_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* 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);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ 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)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_list_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* 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);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
}
-/* Server side of TOPIC command. Sets topic for channel and/or returns
- current topic to client. */
+/* Server side of LIST command. This lists the channel of the requested
+ server. Secret channels are not listed. */
-SILC_SERVER_CMD_FUNC(topic)
+SILC_SERVER_CMD_FUNC(list)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SilcChannelID *channel_id;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- SilcBuffer packet, idp;
+ SilcChannelID *channel_id = NULL;
unsigned char *tmp;
- unsigned int argc, tmp_len;
- unsigned short ident = silc_command_get_ident(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
+ uint32 tmp_len;
+ SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
+ uint32 lch_count = 0, gch_count = 0;
- argc = silc_argument_get_arg_num(cmd->args);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ }
+
+ /* Get the channels from local list */
+ lchannels = silc_idlist_get_channels(server->local_list, channel_id,
+ &lch_count);
+
+ /* Get the channels from global list if we are router */
+ if (server->server_type == SILC_ROUTER)
+ gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+ &gch_count);
+
+ /* Send the reply */
+ silc_server_command_list_send_reply(cmd, lchannels, lch_count,
+ gchannels, gch_count);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of TOPIC command. Sets topic for channel and/or returns
+ current topic to client. */
+
+SILC_SERVER_CMD_FUNC(topic)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, idp;
+ unsigned char *tmp;
+ uint32 argc, tmp_len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
+
+ argc = silc_argument_get_arg_num(cmd->args);
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
}
channel_id = silc_id_payload_parse_id(tmp, tmp_len);
if (!channel_id) {
silc_server_send_notify_topic_set(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel, client->id,
- SILC_ID_CLIENT_LEN, channel->topic);
+ channel->topic);
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_command_free(cmd);
}
-/* Server side of INVITE command. Invites some client to join some channel. */
+/* Server side of INVITE command. Invites some client to join some channel.
+ This command is also used to manage the invite list of the channel. */
SILC_SERVER_CMD_FUNC(invite)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock, dest_sock;
+ SilcChannelClientEntry chl;
SilcClientEntry sender, dest;
- SilcClientID *dest_id;
+ SilcClientID *dest_id = NULL;
SilcChannelEntry channel;
- SilcChannelID *channel_id;
- SilcBuffer sidp;
- unsigned char *tmp;
- unsigned int len;
+ SilcChannelID *channel_id = NULL;
+ SilcIDListData idata;
+ SilcBuffer idp, idp2, packet;
+ unsigned char *tmp, *add, *del;
+ uint32 len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
-
- /* Get destination ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CLIENT_ID);
- goto out;
- }
- dest_id = silc_id_payload_parse_id(tmp, len);
- if (!dest_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CLIENT_ID);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- /* Check whether the channel exists */
+ /* Get the channel entry */
channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
/* Check whether the channel is invite-only channel. If yes then the
sender of this command must be at least channel operator. */
if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
- SilcChannelClientEntry chl;
-
silc_list_start(channel->user_list);
while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
if (chl->client == sender) {
}
}
- /* Find the connection data for the destination. If it is local we will
- send it directly otherwise we will send it to router for routing. */
- dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
- if (dest)
- dest_sock = (SilcSocketConnection)dest->connection;
- else
- dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
+ /* Get destination client ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (tmp) {
+ char invite[512];
- /* Check whether the requested client is already on the channel. */
- /* XXX if we are normal server we don't know about global clients on
- the channel thus we must request it (USERS command), check from
- local cache as well. */
- if (silc_server_client_on_channel(dest, channel)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_USER_ON_CHANNEL);
- goto out;
+ dest_id = silc_id_payload_parse_id(tmp, len);
+ if (!dest_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get the client entry */
+ dest = silc_server_get_client_resolve(server, dest_id);
+ if (!dest) {
+ if (server->server_type == SILC_ROUTER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ 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,
+ 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;
+ }
+
+ /* Check whether the requested client is already on the channel. */
+ if (silc_server_client_on_channel(dest, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_USER_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get route to the client */
+ dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+
+ memset(invite, 0, sizeof(invite));
+ strncat(invite, dest->nickname, strlen(dest->nickname));
+ strncat(invite, "!", 1);
+ strncat(invite, dest->username, strlen(dest->username));
+ if (!strchr(dest->username, '@')) {
+ strncat(invite, "@", 1);
+ strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ len = strlen(invite);
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (len +
+ strlen(channel->invite_list) + 2));
+ strncat(channel->invite_list, invite, len);
+ strncat(channel->invite_list, ",", 1);
+
+ /* Send notify to the client that is invited to the channel */
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
+ SILC_ID_CLIENT,
+ SILC_NOTIFY_TYPE_INVITE, 3,
+ idp->data, idp->len,
+ channel->channel_name,
+ strlen(channel->channel_name),
+ idp2->data, idp2->len);
+ silc_buffer_free(idp);
+ silc_buffer_free(idp2);
}
- sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+ /* Add the client to the invite list of the channel */
+ add = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (add) {
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (len +
+ strlen(channel->invite_list) + 2));
+ if (add[len - 1] == ',')
+ add[len - 1] = '\0';
+
+ strncat(channel->invite_list, add, len);
+ strncat(channel->invite_list, ",", 1);
+ }
- /* Send notify to the client that is invited to the channel */
- silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
- SILC_ID_CLIENT,
- SILC_NOTIFY_TYPE_INVITE, 2,
- sidp->data, sidp->len, tmp, len);
+ /* Get the invite to be removed and remove it from the list */
+ del = silc_argument_get_arg_type(cmd->args, 4, &len);
+ if (del && channel->invite_list) {
+ char *start, *end, *n;
- /* Send command reply */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_OK);
+ if (!strncmp(channel->invite_list, del,
+ strlen(channel->invite_list) - 1)) {
+ silc_free(channel->invite_list);
+ channel->invite_list = NULL;
+ } else {
+ start = strstr(channel->invite_list, del);
+ if (start && strlen(start) >= len) {
+ end = start + len;
+ n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
+ }
+ }
- silc_buffer_free(sidp);
+ /* Send notify to the primary router */
+ if (!server->standalone)
+ silc_server_send_notify_invite(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ sender->id, add, del);
+
+ /* Send command reply */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp, len,
+ 3, channel->invite_list,
+ channel->invite_list ?
+ strlen(channel->invite_list) :
+ 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
out:
+ if (dest_id)
+ silc_free(dest_id);
+ if (channel_id)
+ silc_free(channel_id);
silc_server_command_free(cmd);
}
SilcSocketConnection sock = cmd->sock;
QuitInternal q;
unsigned char *tmp = NULL;
- unsigned int len = 0;
+ uint32 len = 0;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
SilcClientEntry remote_client;
SilcClientID *client_id;
unsigned char *tmp, *comment;
- unsigned int tmp_len, tmp_len2;
+ uint32 tmp_len, tmp_len2;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
/* Send KILLED notify to primary route */
if (!server->standalone)
silc_server_send_notify_killed(server, server->router->connection, TRUE,
- remote_client->id, SILC_ID_CLIENT_LEN,
- comment);
+ remote_client->id, comment);
/* Send KILLED notify to the client directly */
silc_server_send_notify_killed(server, remote_client->connection ?
remote_client->connection :
remote_client->router->connection, FALSE,
- remote_client->id, SILC_ID_CLIENT_LEN,
- comment);
+ remote_client->id, comment);
/* Remove the client from all channels. This generates new keys to the
channels as well. */
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcBuffer packet, idp;
- char info_string[256], *dest_server;
+ unsigned char *tmp;
+ uint32 tmp_len;
+ char *dest_server, *server_info = NULL, *server_name;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ SilcServerEntry entry = NULL;
+ SilcServerID *server_id = NULL;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 0, 2);
/* Get server name */
dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (!dest_server) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- goto out;
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp) {
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SERVER_ID);
+ goto out;
+ }
}
- if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+ if (server_id) {
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, NULL);
+ if (!entry && server->server_type == SILC_ROUTER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+ }
+ }
+
+ if ((!dest_server && !server_id) ||
+ (dest_server && !cmd->pending &&
+ !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
/* Send our reply */
+ char info_string[256];
+
memset(info_string, 0, sizeof(info_string));
snprintf(info_string, sizeof(info_string),
"location: %s server: %s admin: %s <%s>",
server->config->admin_info->admin_name,
server->config->admin_info->admin_email);
- idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
-
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, 0, 2,
- 2, idp->data, idp->len,
- 3, info_string,
- strlen(info_string));
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
+ server_info = info_string;
+ entry = server->id_entry;
} else {
- /* Send this command to the requested server */
+ /* Check whether we have this server cached */
+ if (!entry && dest_server) {
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, NULL);
+ }
+ }
- if (server->server_type == SILC_SERVER && !server->standalone) {
+ if (!cmd->pending &&
+ server->server_type == SILC_ROUTER && entry && !entry->server_info) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->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_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;
}
- if (server->server_type == SILC_ROUTER) {
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ 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);
+
+ 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_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;
}
}
-
+
+ if (server_id)
+ silc_free(server_id);
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ if (!server_info)
+ server_info = entry->server_info;
+ server_name = entry->server_name;
+
+ /* Send the reply */
+ 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));
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
out:
silc_server_command_free(cmd);
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcServerID *id;
- unsigned int len;
+ uint32 len;
unsigned char *tmp;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
if (!id)
goto out;
- if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+ if (SILC_ID_SERVER_COMPARE(id, server->id)) {
/* Send our reply */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
SILC_STATUS_OK);
SilcChannelEntry channel,
SilcClientID *client_id,
int created,
- unsigned int umode)
+ uint32 umode)
{
SilcSocketConnection sock = cmd->sock;
unsigned char *tmp;
- unsigned int tmp_len, user_count;
+ uint32 tmp_len, user_count;
unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
SilcClientEntry client;
SilcChannelClientEntry chl;
- SilcBuffer reply, chidp, clidp, keyp, user_list, mode_list;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char check[512];
SILC_LOG_DEBUG(("Start"));
if (!channel)
return;
- /* 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);
+ /* Get the client entry */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ client = (SilcClientEntry)sock->user_data;
+ } else {
+ client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ NULL);
+ if (!client)
+ goto out;
}
-
+
/*
* Check channel modes
*/
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ strncat(check, client->nickname, strlen(client->nickname));
+ if (!strchr(client->nickname, '@')) {
+ strncat(check, "@", 1);
+ strncat(check, server->server_name, strlen(server->server_name));
+ }
+ 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 invite list if channel is invite-only channel */
- if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
- if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
- /* Invite list is specified. Check whether client is invited in the
- list. If not, then check whether it has been invited otherwise. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (!channel->invite_list) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_INVITED);
+ goto out;
+ }
- } else {
- /* XXX client must be invited to be able to join the channel */
+ if (!silc_string_match(channel->invite_list, check)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_INVITED);
+ goto out;
}
}
- /* Check ban list if set */
- if (channel->mode & SILC_CHANNEL_MODE_BAN) {
-
+ /* 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && channel->ban_list) {
+ if (silc_string_match(channel->ban_list, check)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
+ 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 the channel passphrase if set. */
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
- if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
- strlen(channel->mode_data.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;
/* Check user count limit if set. */
if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
if (silc_list_count(channel->user_list) + 1 >
- channel->mode_data.user_limit) {
+ 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.
*/
- /* Get the client entry */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
- client = (SilcClientEntry)sock->user_data;
- } else {
- client = silc_idlist_find_client_by_id(server->local_list, client_id,
- NULL);
- if (!client) {
- /* XXX actually this is useless since router finds always cell's
- local clients from its local lists. */
- client = silc_idlist_find_client_by_id(server->global_list, client_id,
- NULL);
- if (!client)
- goto out;
- }
- }
-
/* Check whether the client already is on the channel */
if (silc_server_client_on_channel(client, channel)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
/* Send the channel key. This is broadcasted to the channel but is not
sent to the client who is joining to the channel. */
- silc_server_send_channel_key(server, NULL, channel,
- server->server_type == SILC_ROUTER ?
- FALSE : !server->standalone);
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
/* Join the client to the channel by adding it to channel's user list.
Add also the channel to client entry's channels list for fast cross-
SILC_PUT32_MSB(channel->mode, mode);
SILC_PUT32_MSB(created, tmp2);
SILC_PUT32_MSB(user_count, tmp3);
- tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
- silc_free(tmp);
- if (!channel->topic) {
- reply =
- silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, ident, 9,
- 2, channel->channel_name,
- strlen(channel->channel_name),
- 3, chidp->data, chidp->len,
- 4, clidp->data, clidp->len,
- 5, mode, 4,
- 6, tmp2, 4,
- 7, keyp->data, keyp->len,
- 12, tmp3, 4,
- 13, user_list->data, user_list->len,
- 14, mode_list->data,
- mode_list->len);
- } else {
- reply =
- silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, ident, 10,
- 2, channel->channel_name,
- strlen(channel->channel_name),
- 3, chidp->data, chidp->len,
- 4, clidp->data, clidp->len,
- 5, mode, 4,
- 6, tmp2, 4,
- 7, keyp->data, keyp->len,
- 10, channel->topic,
- strlen(channel->topic),
- 12, tmp3, 4,
- 13, user_list->data, user_list->len,
- 14, mode_list->data,
- mode_list->len);
- }
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ channel->key_len / 8, channel->key);
+ silc_free(tmp);
+ }
+
+ reply =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
+ SILC_STATUS_OK, ident, 13,
+ 2, channel->channel_name,
+ strlen(channel->channel_name),
+ 3, chidp->data, chidp->len,
+ 4, clidp->data, clidp->len,
+ 5, mode, 4,
+ 6, tmp2, 4,
+ 7, keyp ? keyp->data : NULL,
+ keyp ? keyp->len : 0,
+ 8, channel->ban_list,
+ channel->ban_list ?
+ strlen(channel->ban_list) : 0,
+ 9, channel->invite_list,
+ channel->invite_list ?
+ strlen(channel->invite_list) : 0,
+ 10, channel->topic,
+ channel->topic ?
+ strlen(channel->topic) : 0,
+ 11, channel->hmac->hmac->name,
+ strlen(channel->hmac->hmac->name),
+ 12, tmp3, 4,
+ 13, user_list->data, user_list->len,
+ 14, mode_list->data,
+ mode_list->len);
/* Send command reply */
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
if (!server->standalone)
silc_server_send_notify_join(server, server->router->connection,
server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel, client->id,
- SILC_ID_CLIENT_LEN);
+ TRUE : FALSE, channel, client->id);
}
silc_buffer_free(reply);
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- int tmp_len;
+ uint32 tmp_len;
char *tmp, *channel_name = NULL, *cipher, *hmac;
SilcChannelEntry channel;
- unsigned int umode = 0;
+ uint32 umode = 0;
int created = FALSE;
SilcClientID *client_id;
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)) {
+ 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;
}
}
- if (!channel) {
+ if (!channel || !channel->id) {
/* Channel not found */
/* If we are standalone server we don't have a router, we just create
if (server->standalone) {
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);
+ goto out;
+ }
+
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
or joins the client to it). */
if (server->server_type == SILC_SERVER) {
SilcBuffer tmpbuf;
- unsigned short old_ident;
+ uint16 old_ident;
old_ident = silc_command_get_ident(cmd->payload);
silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
/* Channel really does not exist, create it */
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);
+ goto out;
+ }
+
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
}
/* Channel really does not exist, create it */
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);
+ goto out;
+ }
+
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
}
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- char *motd;
- int motd_len;
+ SilcBuffer packet, idp;
+ char *motd, *dest_server;
+ uint32 motd_len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
- /* XXX show currently only our motd */
+ /* Get server name */
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (!dest_server) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
+ if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+ /* Send our MOTD */
+
+ idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
- /* Send motd */
- motd = silc_file_read(server->config->motd->motd_file, &motd_len);
- if (!motd)
+ if (server->config && server->config->motd &&
+ server->config->motd->motd_file) {
+ /* Send motd */
+ motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+ if (!motd)
+ goto out;
+
+ motd[motd_len] = 0;
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ 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,
+ SILC_STATUS_OK, ident, 1,
+ 2, idp, idp->len);
+ }
- motd[motd_len] = 0;
- silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
- SILC_STATUS_OK,
- 2, motd, motd_len);
- goto out;
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
} else {
- /* No motd */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
- SILC_STATUS_OK);
+ SilcServerEntry entry;
+
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, NULL);
+ }
+
+ if (server->server_type == SILC_ROUTER && !cmd->pending &&
+ entry && !entry->motd) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->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_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;
+ }
+
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ 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);
+
+ 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_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;
+ }
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ 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);
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
}
out:
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcBuffer packet;
unsigned char *tmp_mask;
- unsigned int mask;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint32 mask;
+ uint16 ident = silc_command_get_ident(cmd->payload);
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
*/
if (mask & SILC_UMODE_SERVER_OPERATOR) {
- /* Cannot operator mode */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
- SILC_STATUS_ERR_PERM_DENIED);
- goto out;
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) {
+ /* Cannot operator mode */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_PERM_DENIED);
+ goto out;
+ }
} else {
if (client->mode & SILC_UMODE_SERVER_OPERATOR)
/* Remove the server operator rights */
}
if (mask & SILC_UMODE_ROUTER_OPERATOR) {
- /* Cannot operator mode */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
- SILC_STATUS_ERR_PERM_DENIED);
- goto out;
+ if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ /* Cannot operator mode */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_PERM_DENIED);
+ goto out;
+ }
} else {
if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
/* Remove the router operator rights */
client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
}
+ if (mask & SILC_UMODE_GONE) {
+ client->mode |= SILC_UMODE_GONE;
+ } else {
+ if (client->mode & SILC_UMODE_GONE)
+ /* Remove the gone status */
+ client->mode &= ~SILC_UMODE_GONE;
+ }
+
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
+
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
SILC_STATUS_OK, ident, 1,
int silc_server_check_cmode_rights(SilcChannelEntry channel,
SilcChannelClientEntry client,
- unsigned int mode)
+ uint32 mode)
{
int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
}
}
+ if (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)
+ return FALSE;
+ }
+ }
+
return TRUE;
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcIDListData idata = (SilcIDListData)client;
SilcChannelID *channel_id;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcBuffer packet, cidp;
unsigned char *tmp, *tmp_id, *tmp_mask;
- unsigned int argc, mode_mask, tmp_len, tmp_len2;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ char *cipher = NULL, *hmac = NULL;
+ uint32 mode_mask, tmp_len, tmp_len2;
+ uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_LOG_DEBUG(("Start"));
-
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 8) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
/* Get Channel ID */
tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
/* Channel uses private keys to protect traffic. Client(s) has set the
key locally they want to use, server does not know that key. */
- /* Nothing interesting to do here now */
+ /* Nothing interesting to do here */
} else {
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
/* The mode is removed and we need to generate and distribute
new channel key. Clients are not using private channel keys
anymore after this. */
- /* XXX Duplicated code, make own function for this!! LEAVE uses this
- as well */
-
/* Re-generate channel key */
silc_server_create_channel_key(server, channel, 0);
- /* Encode channel key payload to be distributed on the channel */
- packet =
- silc_channel_key_payload_encode(tmp_len2, tmp_id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
-
- /* If we are normal server then we will send it to our router. If we
- are router we will send it to all local servers that has clients on
- the channel */
- if (server->server_type == SILC_SERVER) {
- if (!server->standalone)
- silc_server_packet_send(server,
- cmd->server->router->connection,
- SILC_PACKET_CHANNEL_KEY, 0, packet->data,
- packet->len, TRUE);
- } else {
-
- }
-
- /* Send to locally connected clients on the channel */
- silc_server_packet_send_local_channel(server, channel,
- SILC_PACKET_CHANNEL_KEY, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
+ /* 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 = channel->hmac->hmac->name;
}
}
if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
/* User limit is set on channel */
- unsigned int user_limit;
+ uint32 user_limit;
/* Get user limit */
tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
}
} else {
SILC_GET32_MSB(user_limit, tmp);
- channel->mode_data.user_limit = user_limit;
+ channel->user_limit = user_limit;
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
/* User limit mode is unset. Remove user limit */
- channel->mode_data.user_limit = 0;
+ channel->user_limit = 0;
}
if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
}
/* Save the passphrase */
- channel->mode_data.passphrase = strdup(tmp);
+ channel->passphrase = strdup(tmp);
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
/* Passphrase mode is unset. remove the passphrase */
- if (channel->mode_data.passphrase) {
- silc_free(channel->mode_data.passphrase);
- channel->mode_data.passphrase = NULL;
+ if (channel->passphrase) {
+ silc_free(channel->passphrase);
+ channel->passphrase = NULL;
}
}
}
- if (mode_mask & SILC_CHANNEL_MODE_BAN) {
- if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
- /* Ban list is specified for channel */
+ if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
+ /* Cipher to use protect the traffic */
- /* Get ban list */
- tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
- if (!tmp) {
+ /* Get cipher */
+ cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ if (!cipher) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- /* XXX check that channel founder is not banned */
+ /* Delete old cipher and allocate the new one */
+ silc_cipher_free(channel->channel_key);
+ if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
- /* Save the ban list */
- channel->mode_data.ban_list = strdup(tmp);
+ /* Re-generate channel key */
+ silc_server_create_channel_key(server, channel, 0);
+
+ /* 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);
}
} else {
- if (channel->mode & SILC_CHANNEL_MODE_BAN) {
- /* Ban mode is unset. Remove the entire ban list */
- if (channel->mode_data.ban_list) {
- silc_free(channel->mode_data.ban_list);
- channel->mode_data.ban_list = NULL;
- }
- }
- }
-
- if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
- if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
- /* Invite list is specified for channel */
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ /* Cipher mode is unset. Remove the cipher and revert back to
+ default cipher */
+ cipher = channel->cipher;
- /* Get invite list */
- tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
- if (!tmp) {
+ /* Delete old cipher and allocate default one */
+ silc_cipher_free(channel->channel_key);
+ if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc",
+ &channel->channel_key)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
- /* Save the invite linst */
- channel->mode_data.invite_list = strdup(tmp);
- }
- } else {
- if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
- /* Invite list mode is unset. Remove the entire invite list */
- if (channel->mode_data.invite_list) {
- silc_free(channel->mode_data.invite_list);
- channel->mode_data.invite_list = NULL;
- }
+ /* Re-generate channel key */
+ silc_server_create_channel_key(server, channel, 0);
+
+ /* 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);
}
}
- if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
- if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
- /* Cipher to use protect the traffic */
- unsigned int key_len;
+ if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
+ /* HMAC to use protect the traffic */
+ unsigned char hash[32];
- /* Get cipher */
- tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
- if (!tmp) {
+ /* Get hmac */
+ hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
+ if (!hmac) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- /* XXX Duplicated code, make own function for this!! */
-
- /* Delete old cipher and allocate the new one */
- silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(tmp, &channel->channel_key)) {
+ /* Delete old hmac and allocate the new one */
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
goto out;
}
- key_len = silc_cipher_get_key_len(channel->channel_key) / 8;
- /* Re-generate channel key */
- silc_server_create_channel_key(server, channel, key_len);
-
- /* Encode channel key payload to be distributed on the channel */
- packet =
- silc_channel_key_payload_encode(tmp_len2, tmp_id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
-
- /* If we are normal server then we will send it to our router. If we
- are router we will send it to all local servers that has clients on
- the channel */
- if (server->server_type == SILC_SERVER) {
- if (!server->standalone)
- silc_server_packet_send(server,
- cmd->server->router->connection,
- SILC_PACKET_CHANNEL_KEY, 0, packet->data,
- packet->len, TRUE);
- } else {
-
- }
-
- /* Send to locally connected clients on the channel */
- silc_server_packet_send_local_channel(server, channel,
- SILC_PACKET_CHANNEL_KEY, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
+ /* 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_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(channel->hmac->hash));
+ memset(hash, 0, sizeof(hash));
}
} else {
- if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
- /* Cipher mode is unset. Remove the cipher and revert back to
- default cipher */
-
- if (channel->mode_data.cipher) {
- silc_free(channel->mode_data.cipher);
- channel->mode_data.cipher = NULL;
- channel->mode_data.key_len = 0;
+ if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
+ /* Hmac mode is unset. Remove the hmac and revert back to
+ default hmac */
+ unsigned char hash[32];
+ hmac = channel->hmac_name;
+
+ /* Delete old hmac and allocate default one */
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL,
+ &channel->hmac)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
}
- /* Generate new cipher and key for the channel */
+ /* 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_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(channel->hmac->hash));
+ memset(hash, 0, sizeof(hash));
+ }
+ }
- /* XXX Duplicated code, make own function for this!! */
+ if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ /* Set the founder authentication */
+ SilcAuthPayload auth;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
- /* Delete old cipher and allocate default one */
- silc_cipher_free(channel->channel_key);
- if (!channel->cipher)
- silc_cipher_alloc("aes-256-cbc", &channel->channel_key);
- else {
- if (!silc_cipher_alloc(channel->cipher, &channel->channel_key)) {
+ auth = silc_auth_payload_parse(tmp, tmp_len);
+ if (!auth) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- }
- /* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
-
- /* Encode channel key payload to be distributed on the channel */
- packet =
- silc_channel_key_payload_encode(tmp_len2, tmp_id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
-
- /* If we are normal server then we will send it to our router. If we
- are router we will send it to all local servers that has clients on
- the channel */
- if (server->server_type == SILC_SERVER) {
- if (!server->standalone)
- silc_server_packet_send(server,
- cmd->server->router->connection,
- SILC_PACKET_CHANNEL_KEY, 0, packet->data,
- packet->len, TRUE);
- } else {
+ /* Save the public key */
+ tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
+ silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+ silc_free(tmp);
+ channel->founder_method = silc_auth_get_method(auth);
+
+ if (channel->founder_method == SILC_AUTH_PASSWORD) {
+ tmp = silc_auth_get_data(auth, &tmp_len);
+ channel->founder_passwd =
+ silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
+ memcpy(channel->founder_passwd, tmp, tmp_len);
+ channel->founder_passwd_len = tmp_len;
+ }
+
+ silc_auth_payload_free(auth);
+ }
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ if (channel->founder_passwd) {
+ silc_free(channel->founder_passwd);
+ channel->founder_passwd = NULL;
+ }
}
-
- /* Send to locally connected clients on the channel */
- silc_server_packet_send_local_channel(server, channel,
- SILC_PACKET_CHANNEL_KEY, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
}
}
/* 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, 2,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
cidp->data, cidp->len,
- tmp_mask, tmp_len);
+ tmp_mask, 4,
+ cipher, cipher ? strlen(cipher) : 0,
+ hmac, hmac ? strlen(hmac) : 0);
/* Set CMODE notify type to network */
if (!server->standalone)
silc_server_send_notify_cmode(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
- mode_mask, client->id, SILC_ID_CLIENT_LEN);
+ mode_mask, client->id, SILC_ID_CLIENT,
+ cipher, hmac);
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcIDListData idata = (SilcIDListData)client;
SilcChannelID *channel_id;
SilcClientID *client_id;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcBuffer packet, idp;
unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
- unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
+ uint32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
int notify = FALSE;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
/* Get Channel ID */
tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
silc_list_start(channel->user_list);
while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
if (chl->client == client) {
- if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
- goto out;
- }
-
sender_mask = chl->mode;
break;
}
client_id, NULL);
}
- /* Check whether target client is on the channel */
- if (!silc_server_client_on_channel(target_client, channel)) {
+ if (target_client != client &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
goto out;
}
- /* Get entry to the channel user list */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
- if (chl->client == target_client)
- break;
+ /* Check whether target client is on the channel */
+ if (target_client != client) {
+ if (!silc_server_client_on_channel(target_client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ if (chl->client == target_client)
+ break;
+ }
/*
* Change the mode
}
if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
- /* Cannot promote anyone to channel founder */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU);
- goto out;
+ /* The client tries to claim the founder rights. */
+ unsigned char *tmp_auth;
+ uint32 tmp_auth_len, auth_len;
+ void *auth;
+
+ if (target_client != client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+ !channel->founder_key) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+
+ tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
+ if (!tmp_auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ (void *)channel->founder_passwd : (void *)channel->founder_key);
+ auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ channel->founder_passwd_len : 0);
+
+ if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
+ channel->founder_method, auth, auth_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+ notify = TRUE;
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
if (target_client == client) {
if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
/* Promote to operator */
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+ if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
notify = TRUE;
}
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+ if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
/* Demote to normal user */
chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
notify = TRUE;
}
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
/* Send notify to channel, notify only if mode was actually changed. */
if (notify) {
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
target_mask, client->id,
- SILC_ID_CLIENT_LEN,
- target_client->id,
- SILC_ID_CLIENT_LEN);
+ SILC_ID_CLIENT,
+ target_client->id);
}
/* Send command reply to sender */
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcBuffer idp;
- unsigned int tmp_len;
+ uint32 tmp_len;
unsigned char *tmp, *comment;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
silc_server_send_notify_kicked(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
- target_client->id, SILC_ID_CLIENT_LEN,
- comment);
+ target_client->id, comment);
- /* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
-
- /* Send the channel key to the channel. The key of course is not sent
- to the client who was kicked off the channel. */
- silc_server_send_channel_key(server, target_client->connection, channel,
- server->server_type == SILC_ROUTER ?
- FALSE : !server->standalone);
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ /* Re-generate channel key */
+ silc_server_create_channel_key(server, channel, 0);
+
+ /* Send the channel key to the channel. The key of course is not sent
+ to the client who was kicked off the channel. */
+ silc_server_send_channel_key(server, target_client->connection, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
out:
silc_server_command_free(cmd);
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
unsigned char *username, *auth;
- unsigned int tmp_len;
+ uint32 tmp_len;
SilcServerConfigSectionAdminConnection *admin;
SilcIDListData idata = (SilcIDListData)client;
/* Client is now server operator */
client->mode |= SILC_UMODE_SERVER_OPERATOR;
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
+
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
SILC_STATUS_OK);
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
unsigned char *username, *auth;
- unsigned int tmp_len;
+ uint32 tmp_len;
SilcServerConfigSectionAdminConnection *admin;
SilcIDListData idata = (SilcIDListData)client;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+ if (server->server_type == SILC_SERVER)
+ goto out;
+
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
/* Client is now router operator */
client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
+
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
SILC_STATUS_OK);
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
unsigned char *tmp, *host;
- unsigned int tmp_len;
- unsigned int port = SILC_PORT;
+ uint32 tmp_len;
+ uint32 port = SILC_PORT;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
/* Get port */
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
+ if (tmp)
SILC_GET32_MSB(port, tmp);
- }
/* Create the connection. It is done with timeout and is async. */
silc_server_create_connection(server, host, port);
silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(restart)
+/* Server side of command BAN. This is used to manage the ban list of the
+ channel. To add clients and remove clients from the ban list. */
+
+SILC_SERVER_CMD_FUNC(ban)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcBuffer packet;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcChannelID *channel_id = NULL;
+ unsigned char *id, *add, *del;
+ uint32 id_len, tmp_len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
+
+ /* Get Channel ID */
+ id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+ if (id) {
+ channel_id = silc_id_payload_parse_id(id, id_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ }
+
+ /* Get channel entry. The server must know about the channel since the
+ client is expected to be on the channel. */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check whether this client is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ if (chl->client == client)
+ break;
+
+ /* The client must be at least channel operator. */
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /* Get the new ban and add it to the ban list */
+ add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (add) {
+ if (!channel->ban_list)
+ channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
+ else
+ channel->ban_list = silc_realloc(channel->ban_list,
+ sizeof(*channel->ban_list) *
+ (tmp_len +
+ strlen(channel->ban_list) + 2));
+ if (add[tmp_len - 1] == ',')
+ add[tmp_len - 1] = '\0';
+
+ strncat(channel->ban_list, add, tmp_len);
+ strncat(channel->ban_list, ",", 1);
+ }
+
+ /* Get the ban to be removed and remove it from the list */
+ del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (del && channel->ban_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
+ silc_free(channel->ban_list);
+ channel->ban_list = NULL;
+ } else {
+ start = strstr(channel->ban_list, del);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->ban_list, start - channel->ban_list);
+ strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) -
+ end) - 1);
+ silc_free(channel->ban_list);
+ channel->ban_list = n;
+ }
+ }
+ }
+
+ /* Send the BAN notify type to our primary router. */
+ if (!server->standalone && (add || del))
+ silc_server_send_notify_ban(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ 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);
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+
+ out:
+ if (channel_id)
+ silc_free(channel_id);
+ silc_server_command_free(cmd);
}
/* Server side command of CLOSE. Closes connection to a specified server. */
SilcServerEntry server_entry;
SilcSocketConnection sock;
unsigned char *tmp;
- unsigned int tmp_len;
+ uint32 tmp_len;
unsigned char *name;
- unsigned int port = SILC_PORT;
+ uint32 port = SILC_PORT;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
/* Get port */
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
+ if (tmp)
SILC_GET32_MSB(port, tmp);
- }
server_entry = silc_idlist_find_server_by_conn(server->local_list,
name, port, NULL);
SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock;
SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
- SilcChannelID *id;
+ SilcChannelID *id = NULL;
SilcChannelEntry channel;
- SilcBuffer packet;
- unsigned int i, len;
+ uint32 len;
unsigned char *tmp;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
if (!server->standalone)
silc_server_send_notify_leave(server, server->router->connection,
server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel, id_entry->id,
- SILC_ID_CLIENT_LEN);
+ TRUE : FALSE, channel, id_entry->id);
- /* Remove client from channel */
- i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
- TRUE);
silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
SILC_STATUS_OK);
- /* If the channel does not exist anymore we won't send anything */
- if (!i)
+ /* Remove client from channel */
+ if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
+ TRUE))
+ /* If the channel does not exist anymore we won't send anything */
goto out;
- /* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
-
- /* Encode channel key payload to be distributed on the channel */
- packet =
- silc_channel_key_payload_encode(len, tmp,
- strlen(channel->channel_key->cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
-
- /* If we are normal server then we will send it to our router. If we
- are router we will send it to all local servers that has clients on
- the channel */
- if (server->server_type == SILC_SERVER) {
- if (!server->standalone)
- silc_server_packet_send(server,
- cmd->server->router->connection,
- SILC_PACKET_CHANNEL_KEY, 0, packet->data,
- packet->len, FALSE);
- } else {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ /* Re-generate channel key */
+ silc_server_create_channel_key(server, channel, 0);
+ /* Send the channel key */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
}
- /* Send to locally connected clients on the channel */
- silc_server_packet_send_local_channel(server, channel,
- SILC_PACKET_CHANNEL_KEY, 0,
- packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_free(id);
-
out:
+ if (id)
+ silc_free(id);
silc_server_command_free(cmd);
}
SilcChannelID *id;
SilcBuffer packet;
unsigned char *channel_id;
- unsigned int channel_id_len;
+ uint32 channel_id_len;
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
unsigned char lc[4];
- unsigned int list_count = 0;
- unsigned short ident = silc_command_get_ident(cmd->payload);
+ uint32 list_count = 0;
+ uint16 ident = silc_command_get_ident(cmd->payload);
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
out:
silc_server_command_free(cmd);
}
+
+/* Server side of command GETKEY. This fetches the client's public key
+ from the server where to the client is connected. */
+
+SILC_SERVER_CMD_FUNC(getkey)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcBuffer packet;
+ SilcClientEntry client;
+ SilcServerEntry server_entry;
+ SilcClientID *client_id = NULL;
+ SilcServerID *server_id = NULL;
+ SilcIDPayload idp = NULL;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ unsigned char *tmp;
+ uint32 tmp_len;
+ SilcBuffer pk;
+ SilcIdType id_type;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ idp = silc_id_payload_parse_data(tmp, tmp_len);
+ if (!idp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
+ client_id = silc_id_payload_get_id(idp);
+
+ /* If the client is not found from local list there is no chance it
+ would be locally connected client so send the command further. */
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, NULL);
+
+ if ((!client && !cmd->pending && !server->standalone) ||
+ (client && !client->connection)) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+ SilcSocketConnection dest_sock;
+
+ dest_sock = silc_server_get_client_route(server, NULL, 0,
+ client_id, NULL);
+ if (!dest_sock)
+ goto out;
+
+ 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);
+
+ silc_server_packet_send(server, dest_sock,
+ 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_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;
+ }
+
+ if (!client && cmd->pending) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ /* The client is locally connected, just get the public key and
+ send it back. */
+ tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+
+ } else if (id_type == SILC_ID_SERVER) {
+ server_id = silc_id_payload_get_id(idp);
+
+ /* If the server is not found from local list there is no chance it
+ would be locally connected server so send the command further. */
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, NULL);
+
+ if ((!server_entry && !cmd->pending && !server->standalone) ||
+ (server_entry && !server_entry->connection)) {
+ 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);
+
+ 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_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;
+ }
+
+ if (!server_entry && cmd->pending) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
+ goto out;
+ }
+
+ /* The client is locally connected, just get the public key and
+ send it back. */
+ tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ } else {
+ goto out;
+ }
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp, tmp_len,
+ 3, pk->data, pk->len);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(pk);
+
+ out:
+ if (idp)
+ silc_id_payload_free(idp);
+ silc_free(client_id);
+ silc_free(server_id);
+ silc_server_command_free(cmd);
+}