Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2009 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
SilcBuffer tmpreply;
int i;
- SILC_LOG_DEBUG(("Timeout pending command"));
+ SILC_LOG_DEBUG(("Timeout pending command %p", reply));
/* Allocate temporary and bogus command reply context */
cmdr = silc_calloc(1, sizeof(*cmdr));
SilcBuffer list, tmp2;
SilcBufferStruct alist;
unsigned char *tmp, *atype = NULL;
- SilcUInt32 len, type, len2;
+ SilcUInt32 len, len2, ttype;
+ void *type;
SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
silc_hash_table_list(channel->invite_list, &htl);
while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
- if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
+ if (SILC_PTR_TO_32(type) == 3 && !memcmp(tmp2->data, tmp, len)) {
tmp = NULL;
break;
}
silc_hash_table_list(channel->invite_list, &htl);
while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data,
- silc_buffer_len(tmp2), type);
+ silc_buffer_len(tmp2),
+ SILC_PTR_TO_32(type));
silc_hash_table_list_reset(&htl);
}
/* Send invite list back only if the list was modified, or no arguments
was given. */
- type = 0;
+ ttype = 0;
argc = silc_argument_get_arg_num(cmd->args);
if (argc == 1)
- type = 1;
+ ttype = 1;
if (silc_argument_get_arg_type(cmd->args, 3, &len))
- type = 1;
+ ttype = 1;
/* Send command reply */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INVITE,
SILC_STATUS_OK, 0, ident, 2,
2, tmp, len,
- 3, type && list ?
+ 3, ttype && list ?
list->data : NULL,
- type && list ? silc_buffer_len(list) : 0);
+ ttype && list ? silc_buffer_len(list) : 0);
silc_buffer_free(list);
out:
/* Do normal signoff for the destination client */
sock = remote_client->connection;
+
+ if (sock)
+ silc_packet_stream_ref(sock);
+
silc_server_remove_from_channels(server, NULL, remote_client,
TRUE, (char *)"Killed", TRUE, TRUE);
- silc_server_free_client_data(server, NULL, remote_client, TRUE,
- comment ? comment :
- (unsigned char *)"Killed");
- if (sock)
+ silc_server_free_sock_user_data(server, sock, comment ? comment :
+ (unsigned char *)"Killed");
+ if (sock) {
+ silc_packet_set_context(sock, NULL);
silc_server_close_connection(server, sock);
+ silc_packet_stream_unref(sock);
+ }
} else {
/* Router operator killing */
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->server_info->location,
- server->config->server_info->server_type,
- server->config->server_info->admin,
- server->config->server_info->email);
+ silc_snprintf(info_string, sizeof(info_string),
+ "location: %s server: %s admin: %s <%s> version: %s",
+ server->config->server_info->location,
+ server->config->server_info->server_type,
+ server->config->server_info->admin,
+ server->config->server_info->email,
+ silc_dist_version);
server_info = info_string;
entry = server->id_entry;
SilcBuffer user_list, mode_list, invite_list, ban_list;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
char check[512], check2[512];
+ void *plen;
SilcBool founder = FALSE;
SilcBool resolve;
SilcBuffer fkey = NULL, chpklist = NULL;
SILC_STR_END);
silc_hash_table_list(channel->invite_list, &htl);
- while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
+ while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
invite_list = silc_argument_payload_encode_one(invite_list,
reply->data,
- silc_buffer_len(reply), tmp_len);
+ silc_buffer_len(reply),
+ SILC_PTR_TO_32(plen));
silc_hash_table_list_reset(&htl);
}
SILC_STR_END);
silc_hash_table_list(channel->ban_list, &htl);
- while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
+ while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
ban_list = silc_argument_payload_encode_one(ban_list,
reply->data,
- silc_buffer_len(reply), tmp_len);
+ silc_buffer_len(reply),
+ SILC_PTR_TO_32(plen));
silc_hash_table_list_reset(&htl);
}
/* Server side of command JOIN. Joins client into requested channel. If
the channel does not exist it will be created. */
-/* Ways of creating channel with dynamic connections:
-
- 1. If channels are not local (no local_channels in silcd.conf) then
- /join silc, will create connection to default router if it is
- specified in the silcd.conf. If it isn't, it creates local channel.
-
- 2. If channels are not local then /join silc@silcnet.org, will create
- connection to default if it is specified in the silcd.conf and if it
- isn't or join fails it creates connection to silcnet.org and sends
- the JOIN command to that server/router.
+void silc_server_command_join_connected(SilcServer server,
+ SilcServerEntry server_entry,
+ void *context)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- 3. If channels are local (local_channels set in silcd.conf) then
- /join silc, will create local channel. No connections are created
- to anywhere.
+ if (!server_entry) {
+ SilcUInt32 tmp_len;
+ unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ char serv[256 + 1];
- 4. If channels are local then /join silc@silcnet.org will create
- connection to default router if it is specified in the silcd.conf and
- if it isn't, or join fails it creates connection to silcnet.org and
- send the JOIN command to that server/router.
+ SILC_LOG_DEBUG(("Connecting to router failed"));
+ silc_parse_userfqdn(tmp, NULL, 0, serv, sizeof(serv));
- 5. If we create connection to a remote that already has a channel that
- we also have as a local channel, should we merge those channels?
- Should I announce my local channels when I connect to router? Should
- I keep local channels local, unless I say /join localch@silcnet.org
- in which case the local channel 'localch' becomes global?
+ if (serv[0]) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
+ 2, serv, strlen(serv));
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
+ 2, tmp, tmp_len);
+ }
+ silc_server_command_free(cmd);
+ return;
+ }
- 6. After we have connection established to router, depending on the
- local_channels setting /join silc will join locally or globally.
- /join silc@silcnet.org would always join globally.
-*/
+ /* Reprocess command */
+ SILC_LOG_DEBUG(("Reprocess JOIN after connecting to router"));
+ silc_server_command_join(cmd, NULL);
+}
SILC_SERVER_CMD_FUNC(join)
{
}
/* Parse server name from the channel name */
- silc_parse_userfqdn(channel_name, parsed, sizeof(parsed), serv,
+ silc_parse_userfqdn(tmp, parsed, sizeof(parsed), serv,
sizeof(serv));
channel_name = parsed;
+ if (server->config->dynamic_server) {
+ /* If server name is not specified but local channels is FALSE then the
+ channel will be global, based on our router name. */
+ if (!serv[0] && !server->config->local_channels) {
+ if (!server->standalone) {
+ silc_snprintf(serv, sizeof(serv), server->router->server_name);
+ } else {
+ SilcServerConfigRouter *router;
+ router = silc_server_config_get_primary_router(server);
+ if (router) {
+ /* Create connection to primary router */
+ SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
+ router->host, router->port));
+ silc_server_create_connection(server, FALSE, TRUE,
+ router->host, router->port,
+ silc_server_command_join_connected,
+ cmd);
+ return;
+ }
+ }
+ }
+
+ /* If server name is ours, ignore it. */
+ if (serv[0] && silc_utf8_strcasecmp(serv, server->server_name))
+ memset(serv, 0, sizeof(serv));
+
+ /* Create connection */
+ if (serv[0] && server->standalone) {
+ SilcServerConfigRouter *router;
+ router = silc_server_config_get_primary_router(server);
+ if (router) {
+ /* Create connection to primary router */
+ SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
+ router->host, router->port));
+ silc_server_create_connection(server, FALSE, TRUE,
+ router->host, router->port,
+ silc_server_command_join_connected, cmd);
+ return;
+ }
+ }
+ }
+
/* Check for valid channel name. This is cached, the original is saved
in the channel context. */
channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
channel = silc_server_create_new_channel(server, server->id, cipher,
hmac, channel_name, TRUE);
if (!channel) {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
- 0, 2, cipher, strlen(cipher));
+ if (cipher) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, cipher, strlen(cipher));
+ } else if (hmac) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, hmac, strlen(hmac));
+ } else {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_RESOURCE_LIMIT,
+ 0);
+ }
goto out;
}
channel = silc_server_create_new_channel(server, server->id, cipher,
hmac, channel_name, TRUE);
if (!channel) {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
- 2, cipher, strlen(cipher));
+ if (cipher) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, cipher, strlen(cipher));
+ } else if (hmac) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, hmac, strlen(hmac));
+ } else {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_RESOURCE_LIMIT,
+ 0);
+ }
goto out;
}
channel = silc_server_create_new_channel(server, server->id, cipher,
hmac, channel_name, TRUE);
if (!channel) {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
- 2, cipher, strlen(cipher));
+ if (cipher) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, cipher, strlen(cipher));
+ } else if (hmac) {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+ 0, 2, hmac, strlen(hmac));
+ } else {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_RESOURCE_LIMIT,
+ 0);
+ }
goto out;
}
SilcServer server = cmd->server;
SilcClientEntry client = silc_packet_get_context(cmd->sock);
unsigned char *tmp_mask, m[4];
- SilcUInt32 mask = 0;
+ SilcUInt32 mask = 0, tmp_len;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
SilcBool set_mask = FALSE;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
/* Get the client's mode mask */
- tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (tmp_mask) {
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp_mask && tmp_len == 4) {
SILC_GET32_MSB(mask, tmp_mask);
set_mask = TRUE;
}
/* Get the channel mode mask */
tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp_mask) {
+ if (tmp_mask && tmp_len == 4) {
SILC_GET32_MSB(mode_mask, tmp_mask);
set_mask = TRUE;
}
SilcClientID *client_id = (SilcClientID *)q->sock;
SilcClientEntry client;
SilcPacketStream sock;
+ SilcIDListData idata;
+
client = silc_idlist_find_client_by_id(server->local_list, client_id,
TRUE, NULL);
if (client && client->connection) {
sock = client->connection;
+ SILC_LOG_DEBUG(("Detaching client %s",
+ silc_id_render(client->id, SILC_ID_CLIENT)));
+
+ /* Stop rekey for the client. */
+ silc_server_stop_rekey(server, client);
+
+ /* Abort any active protocol */
+ idata = silc_packet_get_context(sock);
+ if (idata && idata->sconn && idata->sconn->op) {
+ SILC_LOG_DEBUG(("Abort active protocol"));
+ silc_async_abort(idata->sconn->op, NULL, NULL);
+ idata->sconn->op = NULL;
+ }
+
/* Close the connection on our side */
client->router = NULL;
client->connection = NULL;
silc_server_close_connection(server, sock);
+
+ /* Mark the client as locally detached. */
+ client->local_detached = TRUE;
+
+ /*
+ * Decrement the user count; we'll increment it if the user resumes on our
+ * server.
+ */
+ SILC_VERIFY(&server->stat.my_clients > 0);
+ server->stat.my_clients--;
}
silc_free(client_id);
pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
while (pk) {
- if (!silc_public_key_payload_decode(pk, pk_len, &public_key))
+ if (!silc_public_key_payload_decode(pk, pk_len, &public_key)) {
+ pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
continue;
+ }
if (type == 0x03)
type = 0x00;
username = silc_identifier_check(username, tmp_len, SILC_STRING_UTF8, 128,
&tmp_len);
if (!username) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
SILC_STATUS_ERR_BAD_USERNAME,
0);
goto out;
}
if (!result) {
/* Authentication failed */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
SILC_STATUS_ERR_AUTH_FAILED, 0);
goto out;
}
SilcUInt32 id_len, len, len2;
SilcArgumentPayload args;
SilcHashTableList htl;
- SilcUInt32 type;
+ void *type;
SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
SilcBufferStruct blist;
silc_hash_table_list(channel->ban_list, &htl);
while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data,
- silc_buffer_len(tmp2), type);
+ silc_buffer_len(tmp2),
+ SILC_PTR_TO_32(type));
silc_hash_table_list_reset(&htl);
}