SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
+ SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(connect, CONNECT,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
- SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+ 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 | 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(close, CLOSE,
SILC_CF_OPER),
SILC_SERVER_CMD(silcoper, SILCOPER,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
- SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
{ NULL, 0 },
/* Internal context to hold data when executed command with timeout. */
typedef struct {
- SilcServer server;
- SilcSocketConnection sock;
- SilcPacketContext *packet;
+ SilcServerCommandContext ctx;
+ SilcServerCommand *cmd;
} *SilcServerCommandTimeout;
/* Timeout callback to process commands with timeout for client. Client's
SILC_TASK_CALLBACK(silc_server_command_process_timeout)
{
SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
- SilcServerCommandContext ctx;
- SilcServerCommand *cmd;
- SilcClientEntry client = (SilcClientEntry)timeout->sock->user_data;
+ SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
/* Update access time */
client->last_command = time(NULL);
+ if (!(timeout->cmd->flags & SILC_CF_REG))
+ timeout->cmd->cb(timeout->ctx);
+ else if (silc_server_is_registered(timeout->ctx->server,
+ timeout->ctx->sock,
+ timeout->ctx,
+ timeout->cmd->cmd))
+ timeout->cmd->cb(timeout->ctx);
+
+ silc_free(timeout);
+}
+
+/* Processes received command packet. */
+
+void silc_server_command_process(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcServerCommandContext ctx;
+ SilcServerCommand *cmd;
+
/* Allocate command context. This must be free'd by the
command routine receiving it. */
ctx = silc_server_command_alloc();
- ctx->server = timeout->server;
- ctx->sock = timeout->sock;
- ctx->packet = timeout->packet;
-
+ ctx->server = server;
+ ctx->sock = silc_socket_dup(sock);
+ ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
+
/* Parse the command payload in the packet */
- ctx->payload = silc_command_payload_parse(ctx->packet->buffer);
+ ctx->payload = silc_command_payload_parse(packet->buffer);
if (!ctx->payload) {
SILC_LOG_ERROR(("Bad command payload, packet dropped"));
- silc_buffer_free(ctx->packet->buffer);
+ silc_buffer_free(packet->buffer);
+ silc_packet_context_free(packet);
silc_socket_free(ctx->sock);
- silc_packet_context_free(ctx->packet);
silc_free(ctx);
- silc_free(timeout);
return;
}
ctx->args = silc_command_get_args(ctx->payload);
- /* Execute command. If this fails the packet is dropped. */
+ /* Get the command */
for (cmd = silc_command_list; cmd->cb; cmd++)
- if (cmd->cmd == silc_command_get(ctx->payload)) {
-
- if (!(cmd->flags & SILC_CF_REG)) {
- cmd->cb(ctx);
- break;
- }
-
- if (silc_server_is_registered(ctx->server, ctx->sock, ctx, cmd->cmd)) {
- cmd->cb(ctx);
- break;
- }
- }
+ if (cmd->cmd == silc_command_get(ctx->payload))
+ break;
if (cmd == NULL) {
SILC_LOG_ERROR(("Unknown command, packet dropped"));
silc_server_command_free(ctx);
- silc_free(timeout);
return;
}
- silc_free(timeout);
-}
-
-/* Processes received command packet. */
-
-void silc_server_command_process(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcServerCommandContext ctx;
- SilcServerCommand *cmd;
-
/* Execute client's commands always with timeout. Normally they are
executed with zero (0) timeout but if client is sending command more
frequently than once in 2 seconds, then the timeout may be 0 to 2
if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
SilcClientEntry client = (SilcClientEntry)sock->user_data;
SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
+ int fast;
+
+ timeout->ctx = ctx;
+ timeout->cmd = cmd;
- timeout->server = server;
- timeout->sock = silc_socket_dup(sock);
- timeout->packet = silc_packet_context_dup(packet);
+ if (client->last_command && (time(NULL) - client->last_command) < 2) {
+ client->fast_command++;
+ fast = FALSE;
+ } else {
+ client->fast_command = ((client->fast_command - 1) <= 0 ? 0 :
+ client->fast_command--);
+ fast = TRUE;
+ }
- if (client->last_command && (time(NULL) - client->last_command) < 2)
+ if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
+ (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
silc_task_register(server->timeout_queue, sock->sock,
silc_server_command_process_timeout,
(void *)timeout,
return;
}
- /* Allocate command context. This must be free'd by the
- command routine receiving it. */
- ctx = silc_server_command_alloc();
- ctx->server = server;
- ctx->sock = silc_socket_dup(sock);
- ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
-
- /* Parse the command payload in the packet */
- ctx->payload = silc_command_payload_parse(packet->buffer);
- if (!ctx->payload) {
- SILC_LOG_ERROR(("Bad command payload, packet dropped"));
- silc_buffer_free(packet->buffer);
- silc_packet_context_free(packet);
- silc_socket_free(ctx->sock);
- silc_free(ctx);
- return;
- }
- ctx->args = silc_command_get_args(ctx->payload);
-
- /* Execute command. If this fails the packet is dropped. */
- for (cmd = silc_command_list; cmd->cb; cmd++)
- if (cmd->cmd == silc_command_get(ctx->payload)) {
+ /* Execute for server */
- if (!(cmd->flags & SILC_CF_REG)) {
- cmd->cb(ctx);
- break;
- }
-
- if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
- cmd->cb(ctx);
- break;
- }
- }
-
- if (cmd == NULL) {
- SILC_LOG_ERROR(("Unknown command, packet dropped"));
- silc_server_command_free(ctx);
- return;
- }
+ if (!(cmd->flags & SILC_CF_REG))
+ cmd->cb(ctx);
+ else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
+ cmd->cb(ctx);
}
/* Allocate Command Context */
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->connection && entry->data.registered == FALSE) {
+ if (clients_count == 1)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ continue;
+ }
+
if (count && i - 1 == count)
break;
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];
unsigned char idle[4];
silc_server_command_free(cmd);
}
+/******************************************************************************
+
+ WHOWAS Functions
+
+******************************************************************************/
+
+static int
+silc_server_command_whowas_parse(SilcServerCommandContext cmd,
+ char **nickname,
+ char **server_name,
+ int *count)
+{
+ unsigned char *tmp;
+ unsigned int len;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+
+ /* Get the nickname@server string and parse it. */
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ *nickname = silc_calloc(len + 1, sizeof(char));
+ memcpy(*nickname, tmp, len);
+ *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ *nickname = strdup(tmp);
+ }
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
+
+ return TRUE;
+}
+
+static void
+silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ unsigned int clients_count)
+{
+ SilcServer server = cmd->server;
+ char *tmp;
+ int i, count = 0, len;
+ SilcBuffer packet, idp;
+ SilcClientEntry entry = NULL;
+ SilcCommandStatus status;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+ char found = FALSE;
+
+ status = SILC_STATUS_OK;
+ if (clients_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ /* We will take only clients that are not valid anymore. They are the
+ ones that are not registered anymore but still have a ID. They
+ have disconnected us, and thus valid for WHOWAS. */
+ if (entry->data.registered == TRUE)
+ continue;
+ if (entry->id == NULL)
+ continue;
+
+ if (count && i - 1 == count)
+ break;
+
+ found = TRUE;
+
+ if (clients_count > 2)
+ status = SILC_STATUS_LIST_ITEM;
+
+ if (clients_count > 1 && i == clients_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username)
+ continue;
+
+ /* Send WHOWAS reply */
+ 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));
+
+ 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);
+ }
+
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ strcat(uh, "*private*");
+ }
+
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ strlen(entry->userinfo));
+ }
+
+ 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 (found == FALSE && entry)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+}
+
+static int
+silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL;
+ int ret = 0;
+
+ /* Protocol dictates that we must always send the received WHOWAS request
+ to our router if we are normal server, so let's do it now unless we
+ are standalone. We will not send any replies to the client until we
+ have received reply from the router. */
+ if (server->server_type == SILC_SERVER &&
+ !cmd->pending && !server->standalone) {
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ ret = -1;
+ goto out;
+ }
+
+ /* We are ready to process the command request. Let's search for the
+ requested client and send reply to the requesting client. */
+
+ /* Parse the whowas request */
+ if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
+ 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);
+
+ /* 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 (!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));
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whowas_send_reply(cmd, clients, clients_count);
+
+ out:
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+static int
+silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL;
+ int ret = 0;
+
+ /* Parse the whowas request */
+ if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
+ return 0;
+
+ /* 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 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 (!clients) {
+ /* Such a client 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));
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whowas_send_reply(cmd, clients, clients_count);
+
+ out:
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+/* Server side of command WHOWAS. */
+
SILC_SERVER_CMD_FUNC(whowas)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret = 0;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ ret = silc_server_command_whowas_from_client(cmd);
+ else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
+ (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
+ ret = silc_server_command_whowas_from_server(cmd);
+
+ if (!ret)
+ silc_server_command_free(cmd);
}
/******************************************************************************
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->connection && entry->data.registered == FALSE) {
+ if (clients_count == 1)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ continue;
+ }
+
if (count && i - 1 == count)
break;
/* Update client cache */
silc_idcache_add(server->local_list->clients, client->nickname,
- SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+ SILC_ID_CLIENT, client->id, (void *)client, TRUE, FALSE);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send NICK_CHANGE notify to the client's channels */
- silc_server_send_notify_on_channels(server, client,
+ silc_server_send_notify_on_channels(server, NULL, client,
SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
oidp->data, oidp->len,
nidp->data, nidp->len);
silc_server_command_free(cmd);
}
+/* Server side of command KILL. This command is used by router operator
+ to remove an client from the SILC Network temporarily. */
+
SILC_SERVER_CMD_FUNC(kill)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcClientEntry remote_client;
+ SilcClientID *client_id;
+ unsigned char *tmp, *comment;
+ unsigned int tmp_len;
+ SilcBuffer idp;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ if (server->server_type != SILC_ROUTER)
+ goto out;
+
+ /* Check whether client has the permissions. */
+ if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
+ goto out;
+ }
+
+ /* Get the client ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get the client entry */
+ remote_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, NULL);
+ if (!remote_client) {
+ remote_client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, NULL);
+ if (!remote_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+ }
+
+ /* Get comment */
+ comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_OK);
+
+ /* Send KILLED notify to the channels. It is not sent to the client
+ as it will be sent differently destined directly to the client and not
+ to the channel. */
+ idp = silc_id_payload_encode(remote_client->id, SILC_ID_CLIENT);
+ silc_server_send_notify_on_channels(server, remote_client->connection,
+ remote_client, SILC_NOTIFY_TYPE_KILLED,
+ comment ? 2 : 1,
+ idp->data, idp->len,
+ comment, comment ? strlen(comment) : 0);
+ silc_buffer_free(idp);
+
+ /* Remove the client from all channels. This generates new keys to the
+ channels as well. */
+ silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
+ NULL, TRUE);
+
+ /* 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);
+
+ /* Send KILLED notify to primary route */
+ if (!server->standalone)
+ silc_server_send_notify_killed(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE,
+ remote_client->id, SILC_ID_CLIENT_LEN,
+ comment);
+
+ out:
+ silc_server_command_free(cmd);
}
/* Server side of command INFO. This sends information about us to
silc_buffer_free(idp);
/* Remove the client from the channel. If the channel does not exist
- after removing the client then the client kicked itself of the channel
+ after removing the client then the client kicked itself off the channel
and we don't have to send anything after that. */
if (!silc_server_remove_from_one_channel(server, NULL, channel,
target_client, FALSE))
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 joined the channel. */
+ 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);
silc_server_command_free(cmd);
}
+/* Server side of OPER command. Client uses this comand to obtain server
+ operator privileges to this server/router. */
+
SILC_SERVER_CMD_FUNC(oper)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *username, *auth;
+ unsigned int tmp_len;
+ SilcServerConfigSectionAdminConnection *admin;
+ SilcIDListData idata = (SilcIDListData)client;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Get the username */
+ username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the admin configuration */
+ admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+ username, client->nickname);
+ if (!admin) {
+ admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+ username, client->nickname);
+ if (!admin) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+ }
+
+ /* Get the authentication payload */
+ auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Verify the authentication data */
+ if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth,
+ admin->auth_data, admin->auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ /* Client is now server operator */
+ client->mode |= SILC_UMODE_SERVER_OPERATOR;
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
+/* Server side of SILCOPER command. Client uses this comand to obtain router
+ operator privileges to this router. */
+
SILC_SERVER_CMD_FUNC(silcoper)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *username, *auth;
+ unsigned int tmp_len;
+ SilcServerConfigSectionAdminConnection *admin;
+ SilcIDListData idata = (SilcIDListData)client;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Get the username */
+ username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the admin configuration */
+ admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+ username, client->nickname);
+ if (!admin) {
+ admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+ username, client->nickname);
+ if (!admin) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+ }
+
+ /* Get the authentication payload */
+ auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Verify the authentication data */
+ if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth,
+ admin->auth_data, admin->auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ /* Client is now router operator */
+ client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
/* Server side command of CONNECT. Connects us to the specified remote
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- unsigned char *tmp;
+ unsigned char *tmp, *host;
unsigned int tmp_len;
unsigned int port = SILC_PORT;
}
/* Get the remote server */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
+ host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!host) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
SILC_GET32_MSB(port, tmp);
/* Create the connection. It is done with timeout and is async. */
- silc_server_create_connection(server, tmp, port);
+ silc_server_create_connection(server, host, port);
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcServerEntry server_entry;
+ SilcSocketConnection sock;
unsigned char *tmp;
unsigned int tmp_len;
unsigned char *name;
goto out;
}
- /* Close the connection to the server */
- silc_server_free_sock_user_data(server, server_entry->connection);
- silc_server_disconnect_remote(server, server_entry->connection,
- "Server closed connection: "
- "Closed by operator");
-
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
SILC_STATUS_OK);
+ /* Close the connection to the server */
+ sock = (SilcSocketConnection)server_entry->connection;
+ silc_server_free_sock_user_data(server, sock);
+ silc_server_close_connection(server, sock);
+
out:
silc_server_command_free(cmd);
}
goto out;
}
- /* Then, gracefully, or not, bring the server down. */
- silc_server_stop(server);
-
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
SILC_STATUS_OK);
+ /* Then, gracefully, or not, bring the server down. */
+ silc_server_stop(server);
+ exit(0);
+
out:
silc_server_command_free(cmd);
}