Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2003 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#include "serverincludes.h"
#include "server_internal.h"
-/* Received notify packet. Server can receive notify packets from router.
+/* Received notify packet. Server can receive notify packets from router.
Server then relays the notify messages to clients if needed. */
void silc_server_notify(SilcServer server,
SilcClientEntry client = NULL, client2 = NULL;
SilcServerEntry server_entry = NULL;
SilcChannelClientEntry chl;
- SilcIDCacheEntry cache;
+ SilcIDCacheEntry cache = NULL;
SilcHashTableList htl;
SilcUInt32 mode;
unsigned char *tmp;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, NULL,
+ packet->dst_id_len, NULL,
&idata, NULL);
if (dst_sock)
/* Relay the packet */
if (!channel_id)
goto out;
- silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server),
- packet->type, packet->flags |
- SILC_PACKET_FLAG_BROADCAST,
+ silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server),
+ packet->type, packet->flags |
+ SILC_PACKET_FLAG_BROADCAST,
channel_id, SILC_ID_CHANNEL,
- packet->buffer->data,
+ packet->buffer->data,
packet->buffer->len, FALSE);
- silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data,
+ silc_server_backup_send_dest(server, sock->user_data,
packet->type, packet->flags,
channel_id, SILC_ID_CHANNEL,
- packet->buffer->data, packet->buffer->len,
+ packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
} else {
/* Packet is destined to client or server */
- silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+ silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data, packet->buffer->len,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len,
FALSE);
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ silc_server_backup_send(server, sock->user_data,
packet->type, packet->flags,
- packet->buffer->data, packet->buffer->len,
+ packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
}
}
switch(type) {
case SILC_NOTIFY_TYPE_JOIN:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
SILC_LOG_DEBUG(("JOIN notify"));
+ if (channel_id)
+ silc_free(channel_id);
+
/* Get Channel ID */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
if (!tmp)
goto out;
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
/* If the the client is not in local list we check global list (ie. the
channel will be global channel) and if it does not exist then create
entry for the client. */
- client = silc_idlist_find_client_by_id(server->global_list,
- client_id, server->server_type,
- NULL);
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, server->server_type,
+ &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, server->server_type,
- NULL);
+ &cache);
if (!client) {
/* If router did not find the client the it is bogus */
- if (server->server_type != SILC_SERVER)
+ if (server->server_type != SILC_SERVER) {
+ silc_free(client_id);
goto out;
+ }
- client =
+ client =
silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
- silc_id_dup(client_id, SILC_ID_CLIENT),
+ silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL, 0);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
}
}
+ silc_free(client_id);
/* Do not process the notify if the client is not registered */
if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
/* Do not add client to channel if it is there already */
if (silc_server_client_on_channel(client, channel, NULL)) {
- SILC_LOG_DEBUG(("Client already on channel"));
+ SILC_LOG_DEBUG(("Client already on channel %s",
+ channel->channel_name));
break;
}
/* Send to channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
- if (server->server_type != SILC_ROUTER &&
+ if (server->server_type != SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_ROUTER)
/* The channel is global now */
channel->global_users = TRUE;
SILC_LOG_DEBUG(("Joining to channel %s", channel->channel_name));
- /* JOIN the global client to the channel (local clients (if router
+ /* JOIN the global client to the channel (local clients (if router
created the channel) is joined in the pending JOIN command). */
chl = silc_calloc(1, sizeof(*chl));
chl->client = client;
silc_hash_table_add(channel->user_list, client, chl);
silc_hash_table_add(client->channels, channel, chl);
- silc_free(client_id);
channel->user_count++;
channel->disabled = FALSE;
+ /* Make sure we don't expire clients that are on channel */
+ if (cache)
+ cache->expire = 0;
+
/* Update statistics */
if (server->server_type == SILC_ROUTER) {
if (sock->type != SILC_SOCKET_TYPE_ROUTER)
break;
case SILC_NOTIFY_TYPE_LEAVE:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
SILC_LOG_DEBUG(("LEAVE notify"));
}
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
- if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
}
/* Get client entry */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client) {
silc_free(client_id);
}
}
silc_free(client_id);
+ silc_free(channel_id);
/* Check if on channel */
if (!silc_server_client_on_channel(client, channel, NULL))
break;
/* Send the leave notify to channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
/* Remove the user from channel */
break;
case SILC_NOTIFY_TYPE_SIGNOFF:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
SILC_LOG_DEBUG(("SIGNOFF notify"));
goto out;
/* Get client entry */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
silc_schedule_task_del_by_context(server->schedule, client);
/* Remove the client from all channels. */
- silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
+ silc_server_remove_from_channels(server, NULL, client, TRUE,
+ tmp, FALSE, FALSE);
/* Check if anyone is watching this nickname */
if (server->server_type == SILC_ROUTER)
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
/* Get client entry */
if (id_type == SILC_ID_CLIENT) {
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
}
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
goto out;
}
}
+ silc_free(channel_id);
if (channel->topic && !strcmp(channel->topic, tmp)) {
SILC_LOG_DEBUG(("Topic is already set and same"));
channel->topic = strdup(tmp);
/* Send the same notify to the channel */
- silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
- silc_free(channel_id);
break;
case SILC_NOTIFY_TYPE_NICK_CHANGE:
{
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
unsigned char *id, *id2;
SilcUInt32 nickname_len;
SILC_LOG_DEBUG(("NICK CHANGE notify"));
-
+
/* Get old client ID */
id = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!id)
client_id = silc_id_payload_parse_id(id, tmp_len, NULL);
if (!client_id)
goto out;
-
+
/* Get new client ID */
id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
if (!id2)
goto out;
client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
- if (!client_id2)
+ if (!client_id2) {
+ silc_free(client_id);
goto out;
-
- SILC_LOG_DEBUG(("Old Client ID id(%s)",
+ }
+
+ SILC_LOG_DEBUG(("Old Client ID id(%s)",
silc_id_render(client_id, SILC_ID_CLIENT)));
- SILC_LOG_DEBUG(("New Client ID id(%s)",
+ SILC_LOG_DEBUG(("New Client ID id(%s)",
silc_id_render(client_id2, SILC_ID_CLIENT)));
/* From protocol version 1.1 we also get the new nickname */
client_id2, nickname);
if (!client)
client = silc_idlist_replace_client_id(server,
- server->local_list, client_id,
+ server->local_list, client_id,
client_id2, nickname);
if (client) {
}
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
/* Get client entry */
if (id_type == SILC_ID_CLIENT) {
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
goto out;
}
}
- silc_free(client_id);
}
+ silc_free(client_id);
if (!channel_id) {
channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
}
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
SILC_ID_SERVER, channel->cipher,
channel->hmac_name,
channel->passphrase,
- channel->founder_key);
+ channel->founder_key, NULL);
}
/* If we received same mode from our primary check whether founder
if (server->server_type == SILC_SERVER &&
sock == SILC_PRIMARY_ROUTE(server) &&
mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
- SILC_LOG_DEBUG(("Founder public key received from primary router"));
+ SILC_LOG_DEBUG(("Founder public key received from router"));
tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
if (!tmp)
break;
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
- silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+ silc_pkcs_public_key_payload_decode(tmp, tmp_len,
+ &channel->founder_key);
+ }
+
+ /* Check also for channel public key list */
+ if (server->server_type == SILC_SERVER &&
+ sock == SILC_PRIMARY_ROUTE(server) &&
+ mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+ SilcBuffer chpklist;
+ SilcBuffer sidp;
+ unsigned char mask[4];
+
+ SILC_LOG_DEBUG(("Channel public key list received from router"));
+ tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+ if (!tmp)
+ break;
+
+ /* Set the router's list, and send the notify to channel too so that
+ channel gets the list */
+ silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+ chpklist = silc_server_get_channel_pk_list(server, channel,
+ FALSE, FALSE);
+ if (!chpklist)
+ break;
+ sidp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+ SILC_PUT32_MSB(channel->mode, mask);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+ sidp->data, sidp->len,
+ mask, 4,
+ channel->cipher,
+ channel->cipher ?
+ strlen(channel->cipher) : 0,
+ channel->hmac_name,
+ channel->hmac_name ?
+ strlen(channel->hmac_name) : 0,
+ channel->passphrase,
+ channel->passphrase ?
+ strlen(channel->passphrase) : 0,
+ NULL, 0,
+ chpklist->data, chpklist->len);
+ silc_buffer_free(sidp);
+ silc_buffer_free(chpklist);
+ goto out;
}
break;
SILC_ID_SERVER, channel->cipher,
channel->hmac_name,
channel->passphrase,
- channel->founder_key);
+ channel->founder_key, NULL);
goto out;
}
} else {
SILC_ID_SERVER, channel->cipher,
channel->hmac_name,
channel->passphrase,
- channel->founder_key);
+ channel->founder_key, NULL);
goto out;
}
SILC_ID_SERVER, channel->cipher,
channel->hmac_name,
channel->passphrase,
- channel->founder_key);
+ channel->founder_key, NULL);
silc_hash_table_list_reset(&htl);
goto out;
}
/* Re-generate channel key */
if (!silc_server_create_channel_key(server, channel, 0))
goto out;
-
+
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
- silc_server_send_channel_key(server, NULL, channel,
- server->server_type == SILC_ROUTER ?
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
}
/* Set the HMAC key out of current channel key. The client must do
this locally. */
- silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
channel->key_len / 8, hash);
- silc_hmac_set_key(channel->hmac, hash,
+ silc_hmac_set_key(channel->hmac, hash,
silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
}
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
- silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
-
- if (!channel->founder_key ||
- (client && client->data.public_key &&
- server->server_type == SILC_ROUTER &&
- !silc_pkcs_public_key_compare(channel->founder_key,
- client->data.public_key))) {
- /* A really buggy server isn't checking public keys correctly.
- It's not possible that the mode setter and founder wouldn't
- have same public key. */
+ if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len,
+ &channel->founder_key)) {
SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
-
mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
silc_server_send_notify_cmode(server, sock, FALSE, channel,
mode, server->id, SILC_ID_SERVER,
- channel->cipher,
+ channel->cipher,
channel->hmac_name,
- channel->passphrase, NULL);
+ channel->passphrase, NULL, NULL);
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
- } else if (client && !client->data.public_key) {
- client->data.public_key =
- silc_pkcs_public_key_copy(channel->founder_key);
}
}
mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
silc_server_send_notify_cmode(server, sock, FALSE, channel,
mode, server->id, SILC_ID_SERVER,
- channel->cipher,
+ channel->cipher,
channel->hmac_name,
- channel->passphrase, NULL);
+ channel->passphrase, NULL, NULL);
+ }
+
+ /* Process channel public key(s). */
+ tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+ if (tmp && mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+ SilcStatus ret =
+ silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+
+ /* If list was set already we will enforce the same list to server. */
+ if (ret == SILC_STATUS_ERR_OPERATION_ALLOWED) {
+ SilcBuffer chpklist = silc_server_get_channel_pk_list(server, channel,
+ TRUE, FALSE);
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ mode, server->id, SILC_ID_SERVER,
+ channel->cipher,
+ channel->hmac_name,
+ channel->passphrase, NULL,
+ chpklist);
+ silc_buffer_free(chpklist);
+ }
}
/* Send the same notify to the channel */
- silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
/* Change mode */
channel->mode = mode;
+ /* Cleanup if some modes are removed */
+
if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) &&
channel->founder_key) {
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
}
+ if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) &&
+ channel->channel_pubkeys) {
+ silc_hash_table_free(channel->channel_pubkeys);
+ channel->channel_pubkeys = NULL;
+ }
+
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
{
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
SilcChannelClientEntry chl2 = NULL;
/* Get client entry */
if (id_type == SILC_ID_CLIENT) {
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
goto out;
}
}
- silc_free(client_id);
}
+ silc_free(client_id);
if (!channel_id) {
channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
}
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
silc_free(channel_id);
goto out;
}
-
+
SILC_GET32_MSB(mode, tmp);
-
+
/* Get target client */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
if (!tmp)
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!client_id)
goto out;
-
+
/* Get client entry */
- client2 = silc_idlist_find_client_by_id(server->global_list,
+ client2 = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
if (!client2) {
- client2 = silc_idlist_find_client_by_id(server->local_list,
+ client2 = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client2) {
silc_free(client_id);
/* Check that sender is on channel */
if (!silc_server_client_on_channel(client, channel, &chl))
goto out;
-
+
if (client != client2 && server->server_type == SILC_ROUTER) {
/* Sender must be operator */
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
break;
}
+ /* Check whether to give founder rights to this user or not. The
+ problem here is that we get only the public key of the client,
+ but no authentication data. We must assume that server has
+ already authenticated the user (and thus we must trust the
+ server). */
if (mode & SILC_CHANNEL_UMODE_CHANFO &&
!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
server->server_type == SILC_ROUTER &&
/* If channel doesn't have founder auth mode then it's impossible
that someone would be getting founder rights with CUMODE command.
In that case there already either is founder or there isn't
- founder at all on the channel. */
+ founder at all on the channel (valid only when 'client' is
+ valid). */
if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
/* Force the mode to not have founder mode */
chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
/* Get the founder of the channel and if found then this client
cannot be the founder since there already is one. */
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl2))
if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
- /* If the founder on the channel is not the one whom has set
- the founder mode, then it's possible that this CUMODE_CHANGE
- is correct. Due to netsplits it's possible that this
- situation happens. */
- if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
- (channel->founder_key && chl2->client->data.public_key &&
- silc_pkcs_public_key_compare(
- channel->founder_key,
- chl2->client->data.public_key))) {
- chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel,
- chl, mode);
- notify_sent = TRUE;
- }
+ chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel,
+ chl, mode);
+ notify_sent = TRUE;
break;
}
silc_hash_table_list_reset(&htl);
if (channel->founder_key) {
/* Get public key that must be present in notify */
tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len,
- &founder_key)) {
+ if (!tmp || !silc_pkcs_public_key_payload_decode(tmp, tmp_len,
+ &founder_key)) {
chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
silc_server_force_cumode_change(server, sock, channel, chl, mode);
notify_sent = TRUE;
/* Now match the public key we have cached and public key sent.
They must match. */
- if (client && client->data.public_key &&
- !silc_pkcs_public_key_compare(channel->founder_key,
- client->data.public_key)) {
- chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
- notify_sent = TRUE;
- break;
- }
if (!silc_pkcs_public_key_compare(channel->founder_key,
founder_key)) {
chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
}
/* There cannot be anyone else as founder on the channel now. This
- client is definitely the founder due to this authentication */
+ client is definitely the founder due to this 'authentication'.
+ We trust the server did the actual authentication earlier. */
silc_hash_table_list(channel->user_list, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
/* Send the same notify to the channel */
if (!notify_sent)
- silc_server_packet_send_to_channel(server, NULL, channel,
- packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, NULL, channel,
+ packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
-
+
silc_free(channel_id);
break;
}
goto out;
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
}
silc_free(channel_id);
+#if 0 /* These aren't actually used anywhere or needed, since this
+ notify is for handling the invite list (direct invite
+ goes to client and is not handled here at all). */
+
/* Get client ID */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
if (!tmp)
goto out;
/* Get client entry */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
silc_free(client_id);
/* Get user's channel entry and check that inviting is allowed. */
- if (!silc_server_client_on_channel(client, channel, &chl))
- goto out;
- if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
- SILC_LOG_DEBUG(("Inviting is not allowed"));
- goto out;
+ if (server->server_type == SILC_ROUTER) {
+ if (!silc_server_client_on_channel(client, channel, &chl))
+ goto out;
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ SILC_LOG_DEBUG(("Inviting is not allowed"));
+ goto out;
+ }
}
+#endif
- /* Get the added invite */
+ /* Get the invite action */
tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (tmp) {
- if (!channel->invite_list)
- channel->invite_list = silc_calloc(tmp_len + 2,
- sizeof(*channel->invite_list));
- else
- channel->invite_list = silc_realloc(channel->invite_list,
- sizeof(*channel->invite_list) *
- (tmp_len +
- strlen(channel->invite_list) +
- 2));
- if (tmp[tmp_len - 1] == ',')
- tmp[tmp_len - 1] = '\0';
-
- strncat(channel->invite_list, tmp, tmp_len);
- strncat(channel->invite_list, ",", 1);
- }
-
- /* Get the deleted invite */
- tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
- if (tmp && channel->invite_list) {
- char *start, *end, *n;
-
- if (!strncmp(channel->invite_list, tmp,
- strlen(channel->invite_list) - 1)) {
- silc_free(channel->invite_list);
- channel->invite_list = NULL;
- } else {
- start = strstr(channel->invite_list, tmp);
- if (start && strlen(start) >= tmp_len) {
- end = start + tmp_len;
- n = silc_calloc(strlen(channel->invite_list) - tmp_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;
- }
- }
+ if (tmp && tmp_len == 1) {
+ SilcUInt8 action = (SilcUInt8)tmp[0];
+ SilcUInt16 iargc = 0;
+ SilcArgumentPayload iargs;
+
+ /* Get invite list */
+ tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+ if (!tmp || tmp_len < 2)
+ goto out;
+
+ /* Parse the arguments to see they are constructed correctly */
+ SILC_GET16_MSB(iargc, tmp);
+ iargs = silc_argument_payload_parse(tmp + 2, tmp_len - 2, iargc);
+ if (!iargs)
+ goto out;
+
+ if (action != 0x01 && !channel->invite_list)
+ channel->invite_list =
+ silc_hash_table_alloc(0, silc_hash_ptr,
+ NULL, NULL, NULL,
+ silc_server_inviteban_destruct, channel, TRUE);
+
+ /* Proces the invite action */
+ silc_server_inviteban_process(server, channel->invite_list, action,
+ iargs);
+ silc_argument_payload_free(iargs);
+
+ /* If we are router we must send this notify to our local servers on
+ the channel. Normal server does nothing. The notify is not
+ sent to clients. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_packet_send_to_channel(server, sock, channel,
+ packet->type, FALSE, FALSE,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
}
break;
goto out;
/* Get the channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ 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 = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
}
/* Send the notify to the channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
/* Get the new Channel ID */
if (!channel_id2)
goto out;
- SILC_LOG_DEBUG(("Old Channel ID id(%s)",
+ SILC_LOG_DEBUG(("Old Channel ID id(%s)",
silc_id_render(channel_id, SILC_ID_CHANNEL)));
- SILC_LOG_DEBUG(("New Channel ID id(%s)",
+ SILC_LOG_DEBUG(("New Channel ID id(%s)",
silc_id_render(channel_id2, SILC_ID_CHANNEL)));
/* Replace the Channel ID */
/* Re-announce this channel which ID was changed. */
silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
- channel->id,
- silc_id_get_len(channel->id,
+ channel->id,
+ silc_id_get_len(channel->id,
SILC_ID_CHANNEL),
channel->mode);
silc_server_packet_send_dest(server, sock,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel->id, SILC_ID_CHANNEL,
- users_modes->data,
+ users_modes->data,
users_modes->len, FALSE);
silc_buffer_free(users_modes);
}
if (channel->topic) {
silc_server_send_notify_topic_set(server, sock,
server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
+ TRUE : FALSE, channel,
server->id, SILC_ID_SERVER,
channel->topic);
}
break;
case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
- /*
+ /*
* Remove the server entry and all clients that this server owns.
*/
SILC_LOG_DEBUG(("SERVER SIGNOFF notify"));
+ /* Backup router shouldn't accept SERVER_SIGNOFF's from normal routers
+ when the backup isn't acting as primary router. */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER &&
+ server->backup_router && server->server_type == SILC_BACKUP_ROUTER)
+ return;
+
/* Get Server ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
if (!server_id)
goto out;
+ /* If the ID is mine, this notify is not allowed. */
+ if (SILC_ID_SERVER_COMPARE(server_id, server->id)) {
+ SILC_LOG_DEBUG(("Ignoring my own ID for SERVER_SIGNOFF"));
+ break;
+ }
+
/* Get server entry */
- server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
server_id, TRUE, NULL);
- local = TRUE;
+ local = FALSE;
if (!server_entry) {
- server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
server_id, TRUE, NULL);
local = TRUE;
if (!server_entry) {
continue;
/* Get client entry */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
- local = TRUE;
+ local = FALSE;
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
- local = FALSE;
+ local = TRUE;
if (!client) {
silc_free(client_id);
continue;
SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
/* Remove the client from all channels. */
- silc_server_remove_from_channels(server, NULL, client,
- TRUE, NULL, FALSE);
+ silc_server_remove_from_channels(server, NULL, client,
+ TRUE, NULL, FALSE, FALSE);
/* Check if anyone is watching this nickname */
if (server->server_type == SILC_ROUTER)
silc_server_del_from_watcher_list(server, client);
/* Remove the client */
+ silc_idlist_del_data(client);
silc_idlist_del_client(local ? server->local_list :
server->global_list, client);
}
}
silc_free(server_id);
- /* Sending SERVER_SIGNOFF is not right way to signoff local connection */
- if (SILC_IS_LOCAL(server_entry))
+ /* For local entrys SERVER_SIGNOFF is processed only on backup router.
+ It is possible that router sends server signoff for a server. If
+ backup router has it as local connection it will be closed. */
+ if (SILC_IS_LOCAL(server_entry)) {
+ if (server->server_type == SILC_BACKUP_ROUTER) {
+ sock = server_entry->connection;
+ SILC_LOG_DEBUG(("Closing connection %s after SERVER_SIGNOFF",
+ sock->hostname));
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ SILC_SET_DISCONNECTING(sock);
+ silc_server_close_connection(server, sock);
+ }
+
break;
+ }
+
+ /* Remove all servers that are originated from this server, and
+ remove the clients of those servers too. */
+ silc_server_remove_servers_by_server(server, server_entry, TRUE);
- /* Free all client entries that this server owns as they will
- become invalid now as well. */
- silc_server_remove_clients_by_server(server, server_entry, TRUE);
+ /* Remove the clients that this server owns as they will become
+ invalid now too. */
+ silc_server_remove_clients_by_server(server, server_entry->router,
+ server_entry, TRUE);
silc_server_backup_del(server, server_entry);
/* Remove the server entry */
break;
case SILC_NOTIFY_TYPE_KICKED:
- /*
+ /*
* Distribute the notify to local clients on the channel
*/
-
+
SILC_LOG_DEBUG(("KICKED notify"));
-
+
if (!channel_id) {
channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
packet->dst_id_type);
}
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
goto out;
/* If the the client is not in local list we check global list */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client) {
silc_free(client_id);
goto out;
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
goto out;
-
- /* From protocol version 1.1 we get the kicker's ID as well. */
+
+ /* Get the kicker's Client ID */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (tmp) {
- client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
- if (!client_id)
- goto out;
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- /* If the the client is not in local list we check global list */
- client2 = silc_idlist_find_client_by_id(server->global_list,
+ /* If the the client is not in local list we check global list */
+ client2 = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client2) {
+ client2 = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client2) {
- client2 = silc_idlist_find_client_by_id(server->local_list,
- client_id, TRUE, NULL);
- if (!client2) {
- silc_free(client_id);
- goto out;
- }
- }
- silc_free(client_id);
-
- /* Kicker must be operator on channel */
- if (!silc_server_client_on_channel(client2, channel, &chl))
- goto out;
- if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
- SILC_LOG_DEBUG(("Kicking is not allowed"));
+ silc_free(client_id);
goto out;
}
}
+ silc_free(client_id);
+
+ /* Kicker must be operator on channel */
+ if (!silc_server_client_on_channel(client2, channel, &chl))
+ goto out;
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ SILC_LOG_DEBUG(("Kicking is not allowed"));
+ goto out;
+ }
/* Send to channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, TRUE, packet->buffer->data,
packet->buffer->len, FALSE);
+ /* Remove the client from channel's invite list */
+ if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+ SilcBuffer ab;
+ SilcArgumentPayload iargs;
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ ab = silc_argument_payload_encode_one(NULL, tmp, tmp_len, 3);
+ iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+ silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
+ silc_buffer_free(ab);
+ silc_argument_payload_free(iargs);
+ }
+
/* Remove the client from channel */
silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
case SILC_NOTIFY_TYPE_KILLED:
{
- /*
+ /*
* Distribute the notify to local clients on channels
*/
unsigned char *id, *comment;
SilcUInt32 id_len, comment_len;
-
+
SILC_LOG_DEBUG(("KILLED notify"));
-
+
/* Get client ID */
id = silc_argument_get_arg_type(args, 1, &id_len);
if (!id)
goto out;
/* If the the client is not in local list we check global list */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
if (comment_len > 128)
comment_len = 127;
- /* From protocol version 1.1 we get the killer's ID as well. */
+ /* Get the killer's Client ID */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (tmp) {
- client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
- if (!client_id)
- goto out;
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!client_id)
+ goto out;
- if (id_type == SILC_ID_CLIENT) {
- /* If the the client is not in local list we check global list */
- client2 = silc_idlist_find_client_by_id(server->global_list,
+ if (id_type == SILC_ID_CLIENT) {
+ /* If the the client is not in local list we check global list */
+ client2 = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client2) {
+ client2 = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client2) {
- client2 = silc_idlist_find_client_by_id(server->local_list,
- client_id, TRUE, NULL);
- if (!client2) {
- silc_free(client_id);
- goto out;
- }
- }
- silc_free(client_id);
-
- /* Killer must be router operator */
- if (server->server_type != SILC_SERVER &&
- !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
- SILC_LOG_DEBUG(("Killing is not allowed"));
+ silc_free(client_id);
goto out;
}
}
+ silc_free(client_id);
+
+ /* Killer must be router operator */
+ if (server->server_type != SILC_SERVER &&
+ !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ SILC_LOG_DEBUG(("Killing is not allowed"));
+ goto out;
+ }
}
/* Send the notify to local clients on the channels except to the
tmp, tmp_len);
/* Remove the client from all channels */
- silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
- FALSE);
+ silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
+ FALSE, TRUE);
/* Check if anyone is watching this nickname */
silc_server_check_watcher_list(server, client, NULL,
goto out;
/* Get client entry */
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
if (!client) {
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client) {
silc_free(client_id);
server->stat.detached--;
}
}
+ SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
/* Change the mode */
client->mode = mode;
*/
SILC_LOG_DEBUG(("BAN notify"));
-
+
/* Get Channel ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!channel_id)
goto out;
-
+
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
SILC_LOG_DEBUG(("Notify for unknown channel"));
}
silc_free(channel_id);
- /* Get the new ban and add it to the ban list */
+ /* Get the ban action */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp) {
- 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));
- strncat(channel->ban_list, tmp, tmp_len);
- strncat(channel->ban_list, ",", 1);
- }
+ if (tmp && tmp_len == 1) {
+ SilcUInt8 action = (SilcUInt8)tmp[0];
+ SilcUInt16 iargc = 0;
+ SilcArgumentPayload iargs;
- /* Get the ban to be removed and remove it from the list */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (tmp && channel->ban_list) {
- char *start, *end, *n;
-
- if (!strncmp(channel->ban_list, tmp, strlen(channel->ban_list) - 1)) {
- silc_free(channel->ban_list);
- channel->ban_list = NULL;
- } else {
- start = strstr(channel->ban_list, tmp);
- 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;
- }
- }
+ /* Get ban list */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp || tmp_len < 2)
+ goto out;
+
+ /* Parse the arguments to see they are constructed correctly */
+ SILC_GET16_MSB(iargc, tmp);
+ iargs = silc_argument_payload_parse(tmp + 2, tmp_len - 2, iargc);
+ if (!iargs)
+ goto out;
+
+ if (action != 0x01 && !channel->ban_list)
+ channel->ban_list =
+ silc_hash_table_alloc(0, silc_hash_ptr,
+ NULL, NULL, NULL,
+ silc_server_inviteban_destruct, channel, TRUE);
+
+ /* Proces the ban action */
+ silc_server_inviteban_process(server, channel->ban_list, action,
+ iargs);
+ silc_argument_payload_free(iargs);
+
+ /* If we are router we must send this notify to our local servers on
+ the channel. Normal server does nothing. The notify is not
+ sent to clients. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_packet_send_to_channel(server, sock, channel,
+ packet->type, FALSE, FALSE,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
}
break;
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!client_id)
goto out;
- client = silc_idlist_find_client_by_id(server->global_list,
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, FALSE, NULL);
if (client) {
- silc_server_remove_from_channels(server, NULL, client, TRUE,
- NULL, TRUE);
+ silc_server_remove_from_channels(server, NULL, client, TRUE,
+ NULL, TRUE, FALSE);
+ silc_idlist_del_data(client);
silc_idlist_del_client(server->global_list, client);
}
silc_free(client_id);
silc_free(new);
}
-/* Received private message. This resolves the destination of the message
+/* Received private message. This resolves the destination of the message
and sends the packet. This is used by both server and router. If the
destination is our locally connected client this sends the packet to
the client. This may also send the message for further routing if
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, NULL,
+ packet->dst_id_len, NULL,
&idata, &client);
if (!dst_sock) {
SilcBuffer idp;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, NULL,
+ packet->dst_id_len, NULL,
&idata, NULL);
if (!dst_sock)
return;
}
/* Processes incoming command reply packet. The command reply packet may
- be destined to one of our clients or it may directly for us. We will
+ be destined to one of our clients or it may directly for us. We will
call the command reply routine after processing the packet. */
void silc_server_command_reply(SilcServer server,
SILC_LOG_DEBUG(("Start"));
- /* Source must be server or router */
- if (packet->src_id_type != SILC_ID_SERVER &&
- sock->type != SILC_SOCKET_TYPE_ROUTER)
- return;
-
if (packet->dst_id_type == SILC_ID_CHANNEL)
return;
if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
/* Relay the packet to the client */
const SilcBufferStruct p;
-
+
dst_sock = (SilcSocketConnection)client->connection;
idata = (SilcIDListData)client;
-
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ packet->dst_id_len + packet->padlen);
if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len,
idata->hmac_send, (const SilcBuffer)&p)) {
return;
}
silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-
+
/* Encrypt packet */
silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
(SilcBuffer)&p, buffer->len);
-
+
/* Send the packet */
silc_server_packet_send_real(server, dst_sock, TRUE);
SILC_NOTIFY_TYPE_ERROR, 2,
&error, 1, idp->data, idp->len);
}
-
+
silc_buffer_free(idp);
goto out;
}
/* See that this client is on the channel. If the original sender is
not client (as it can be server as well) we don't do the check. */
- sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
packet->src_id_type);
if (!sender_id)
goto out;
if (packet->src_id_type == SILC_ID_CLIENT) {
- sender_entry = silc_idlist_find_client_by_id(server->local_list,
+ sender_entry = silc_idlist_find_client_by_id(server->local_list,
sender_id, TRUE, NULL);
if (!sender_entry) {
local = FALSE;
- sender_entry = silc_idlist_find_client_by_id(server->global_list,
+ sender_entry = silc_idlist_find_client_by_id(server->global_list,
sender_id, TRUE, NULL);
}
- if (!sender_entry || !silc_server_client_on_channel(sender_entry,
+ if (!sender_entry || !silc_server_client_on_channel(sender_entry,
channel, &chl)) {
SILC_LOG_DEBUG(("Client not on channel"));
goto out;
/* If channel is moderated check that client is allowed to send
messages. */
- if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
SILC_LOG_DEBUG(("Channel is silenced from normal users"));
goto out;
}
- if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
SILC_LOG_DEBUG(("Channel is silenced from operators"));
goto out;
}
- /* If the packet is coming from router, but the client entry is local
- entry to us then some router is rerouting this to us and it is not
+ /* If the packet is coming from router, but the client entry is local
+ entry to us then some router is rerouting this to us and it is not
allowed. When the client is local to us it means that we've routed
this packet to network, and now someone is routing it back to us. */
if (server->server_type == SILC_ROUTER &&
SilcChannelEntry channel;
if (packet->src_id_type != SILC_ID_SERVER ||
- (server->server_type == SILC_ROUTER &&
+ (server->server_type == SILC_ROUTER && !server->backup_router &&
sock->type == SILC_SOCKET_TYPE_ROUTER))
return;
/* Save the channel key */
channel = silc_server_save_channel_key(server, buffer, NULL);
- if (!channel)
+ if (!channel) {
+ SILC_LOG_ERROR(("Bad channel key from %s (%s)",
+ sock->hostname, sock->ip));
return;
+ }
/* Distribute the key to everybody who is on the channel. If we are router
we will also send it to locally connected servers. */
silc_server_send_channel_key(server, sock, channel, FALSE);
-
+
if (server->server_type != SILC_BACKUP_ROUTER) {
/* Distribute to local cell backup routers. */
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ silc_server_backup_send(server, sock->user_data,
SILC_PACKET_CHANNEL_KEY, 0,
buffer->data, buffer->len, FALSE, TRUE);
}
/* Remove the old cache entry. */
if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
+ /* Make sure this client hasn't registered already */
+ if (idata->status & SILC_IDLIST_STATUS_REGISTERED) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_OPERATION_ALLOWED,
+ "Too many registrations");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ return NULL;
+ }
+
/* Parse incoming packet */
ret = silc_buffer_unformat(buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&username,
+ SILC_STR_UI16_NSTRING_ALLOC(&username,
&username_len),
SILC_STR_UI16_STRING_ALLOC(&realname),
SILC_STR_END);
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
hostname = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
- if (strcmp(sock->hostname, sock->ip) &&
+ if (strcmp(sock->hostname, sock->ip) &&
strcmp(sock->hostname, hostname)) {
silc_free(username);
silc_free(hostname);
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
-
+
pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
if (pident) {
phostname = strdup(pident->host);
silc_pkcs_free_identifier(pident);
}
- if (!strcmp(sock->hostname, sock->ip) &&
+ if (!strcmp(sock->hostname, sock->ip) &&
phostname && strcmp(phostname, hostname)) {
silc_free(username);
silc_free(hostname);
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
-
+
silc_free(phostname);
} else {
/* The hostname is not present, add it. */
#if 0
if (strcmp(sock->hostname, sock->ip)) {
#endif
- newusername = silc_calloc(strlen(username) +
+ newusername = silc_calloc(strlen(username) +
strlen(sock->hostname) + 2,
sizeof(*newusername));
strncat(newusername, username, strlen(username));
username = newusername;
#if 0
} else {
- SilcPublicKeyIdentifier pident =
+ SilcPublicKeyIdentifier pident =
silc_pkcs_decode_identifier(client->data.public_key->identifier);
-
+
if (pident) {
- newusername = silc_calloc(strlen(username) +
+ newusername = silc_calloc(strlen(username) +
strlen(pident->host) + 2,
sizeof(*newusername));
strncat(newusername, username, strlen(username));
}
/* Create Client ID */
- while (!silc_id_create_client_id(server, server->id, server->rng,
+ while (!silc_id_create_client_id(server, server->id, server->rng,
server->md5hash, nickname, &client_id)) {
nickfail++;
if (nickfail > 9) {
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_NICKNAME, NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
}
+ /* If client marked as anonymous, scramble the username and hostname */
+ if (client->mode & SILC_UMODE_ANONYMOUS) {
+ char *scramble;
+
+ if (strlen(username) >= 2) {
+ username[0] = silc_rng_get_byte_fast(server->rng);
+ username[1] = silc_rng_get_byte_fast(server->rng);
+ }
+
+ scramble = silc_hash_babbleprint(server->sha1hash, username,
+ strlen(username));
+ scramble[5] = '@';
+ scramble[11] = '.';
+ memcpy(&scramble[16], ".silc", 5);
+ scramble[21] = '\0';
+ silc_free(username);
+ username = scramble;
+ }
+
/* Update client entry */
idata->status |= SILC_IDLIST_STATUS_REGISTERED;
client->nickname = nickname;
client->username = username;
- client->userinfo = realname ? realname : strdup(" ");
+ client->userinfo = realname ? realname : strdup(username);
client->id = client_id;
id_len = silc_id_get_len(client_id, SILC_ID_CLIENT);
/* Distribute to backup routers */
if (server->server_type == SILC_ROUTER) {
SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+ silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
idp->data, idp->len, FALSE, TRUE);
silc_buffer_free(idp);
}
/* Create new server. This processes received New Server packet and
saves the received Server ID. The server is our locally connected
- server thus we save all the information and save it to local list.
+ server thus we save all the information and save it to local list.
This funtion can be used by both normal server and router server.
If normal server uses this it means that its router has connected
to the server. If router uses this it means that one of the cell's
/* Remove the old cache entry */
if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
- if (!silc_idcache_del_by_context(server->global_list->servers,
+ if (!silc_idcache_del_by_context(server->global_list->servers,
new_server)) {
SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
"network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
"server" : "router")));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
local = FALSE;
}
+ /* Make sure this server hasn't registered already */
+ if (idata->status & SILC_IDLIST_STATUS_REGISTERED) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_OPERATION_ALLOWED,
+ "Too many registrations");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ return NULL;
+ }
+
/* Parse the incoming packet */
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
- SILC_STR_UI16_NSTRING_ALLOC(&server_name,
+ SILC_STR_UI16_NSTRING_ALLOC(&server_name,
&name_len),
SILC_STR_END);
if (ret == -1) {
silc_free(id_string);
silc_free(server_name);
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
if (id_len > buffer->len) {
silc_free(id_string);
silc_free(server_name);
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
if (!server_id) {
silc_free(id_string);
silc_free(server_name);
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
NULL);
if (sock->user_data)
if (!silc_id_is_valid_server_id(server, server_id, sock)) {
SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
sock->ip, sock->hostname));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
}
/* Check that we do not have this ID already */
- server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
server_id, TRUE, NULL);
if (server_entry) {
- silc_idcache_del_by_context(server->local_list->servers, server_entry);
+ if (SILC_IS_LOCAL(server_entry)) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_OPERATION_ALLOWED,
+ "Too many registrations");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ return NULL;
+ } else {
+ silc_idcache_del_by_context(server->local_list->servers, server_entry);
+ }
} else {
- server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
server_id, TRUE, NULL);
- if (server_entry)
- silc_idcache_del_by_context(server->global_list->servers, server_entry);
+ if (server_entry) {
+ if (SILC_IS_LOCAL(server_entry)) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_OPERATION_ALLOWED,
+ "Too many registrations");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ return NULL;
+ } else {
+ silc_idcache_del_by_context(server->global_list->servers,
+ server_entry);
+ }
+ }
}
/* Update server entry */
idata->status |= SILC_IDLIST_STATUS_REGISTERED;
new_server->server_name = server_name;
new_server->id = server_id;
-
+
SILC_LOG_DEBUG(("New server id(%s)",
silc_id_render(server_id, SILC_ID_SERVER)));
/* Add again the entry to the ID cache. */
- silc_idcache_add(local ? server->local_list->servers :
- server->global_list->servers, server_name, server_id,
+ silc_idcache_add(local ? server->local_list->servers :
+ server->global_list->servers, server_name, server_id,
new_server, 0, NULL);
/* Distribute the information about new server in the SILC network
if (server->server_type == SILC_ROUTER && !server->standalone &&
SILC_PRIMARY_ROUTE(server) != sock)
silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
- TRUE, new_server->id, SILC_ID_SERVER,
+ TRUE, new_server->id, SILC_ID_SERVER,
silc_id_get_len(server_id, SILC_ID_SERVER));
if (server->server_type == SILC_ROUTER) {
/* Distribute to backup routers */
SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
- silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+ silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
idp->data, idp->len, FALSE, TRUE);
silc_buffer_free(idp);
protocol has been completed. */
if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
silc_server_backup_replaced_get(server, server_id, NULL)) {
- /* Send packet to the server indicating that it cannot use this
+ /* Send packet to the router indicating that it cannot use this
connection as it has been replaced by backup router. */
- SilcBuffer packet = silc_buffer_alloc(2);
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_REPLACED),
- SILC_STR_UI_CHAR(0),
- SILC_STR_END);
- silc_server_packet_send(server, sock,
- SILC_PACKET_RESUME_ROUTER, 0,
- packet->data, packet->len, TRUE);
- silc_buffer_free(packet);
+ SILC_LOG_DEBUG(("Remote router has been replaced by backup router, "
+ "disabling its connection"));
+
+ silc_server_backup_send_replaced(server, sock);
/* Mark the router disabled. The data sent earlier will go but nothing
- after this does not go to this connection. */
+ after this goes to this connection. */
idata->status |= SILC_IDLIST_STATUS_DISABLED;
} else {
/* If it is router announce our stuff to it. */
- if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
server->server_type == SILC_ROUTER) {
silc_server_announce_servers(server, FALSE, 0, sock);
silc_server_announce_clients(server, 0, sock);
silc_server_announce_channels(server, 0, sock);
}
+ /* Announce our information to backup router */
+ if (new_server->server_type == SILC_BACKUP_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ server->server_type == SILC_ROUTER) {
+ silc_server_announce_servers(server, TRUE, 0, sock);
+ silc_server_announce_clients(server, 0, sock);
+ silc_server_announce_channels(server, 0, sock);
+ }
+
+ /* If backup router, mark it as one of ours. This server is considered
+ to be backup router after this setting. */
+ if (new_server->server_type == SILC_BACKUP_ROUTER) {
+ SilcServerConfigRouter *backup;
+ backup = silc_server_config_find_backup_conn(server, sock->ip);
+ if (!backup)
+ backup = silc_server_config_find_backup_conn(server, sock->hostname);
+ if (backup) {
+ /* Add as our backup router */
+ silc_server_backup_add(server, new_server, backup->backup_replace_ip,
+ backup->backup_replace_port,
+ backup->backup_local);
+ }
+ }
+
/* By default the servers connected to backup router are disabled
until backup router has become the primary */
if (server->server_type == SILC_BACKUP_ROUTER &&
/* Processes incoming New ID packet. New ID Payload is used to distribute
information about newly registered clients and servers. */
-static void silc_server_new_id_real(SilcServer server,
+static void silc_server_new_id_real(SilcServer server,
SilcSocketConnection sock,
SilcPacketContext *packet,
int broadcast)
/* If the sender is backup router and ID is server (and we are not
backup router) then switch the entry to global list. */
- if (server_entry->server_type == SILC_BACKUP_ROUTER &&
- id_type == SILC_ID_SERVER &&
+ if (server_entry->server_type == SILC_BACKUP_ROUTER &&
+ id_type == SILC_ID_SERVER &&
server->id_entry->server_type != SILC_BACKUP_ROUTER) {
id_list = server->global_list;
router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock;
SilcClientEntry entry;
/* Check that we do not have this client already */
- entry = silc_idlist_find_client_by_id(server->global_list,
- id, server->server_type,
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ id, server->server_type,
NULL);
if (!entry)
- entry = silc_idlist_find_client_by_id(server->local_list,
+ entry = silc_idlist_find_client_by_id(server->local_list,
id, server->server_type,
NULL);
if (entry) {
silc_id_render(id, SILC_ID_CLIENT),
sock->type == SILC_SOCKET_TYPE_SERVER ?
"Server" : "Router", sock->hostname));
-
+
/* As a router we keep information of all global information in our
global list. Cell wide information however is kept in the local
list. */
- entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
id, router, NULL, 0);
if (!entry) {
SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
SILC_LOG_DEBUG(("Ignoring sender's own ID"));
break;
}
-
+
/* Check that we do not have this server already */
- entry = silc_idlist_find_server_by_id(server->global_list,
- id, server->server_type,
+ entry = silc_idlist_find_server_by_id(server->global_list,
+ id, server->server_type,
NULL);
if (!entry)
- entry = silc_idlist_find_server_by_id(server->local_list,
+ entry = silc_idlist_find_server_by_id(server->local_list,
id, server->server_type,
NULL);
if (entry) {
silc_id_render(id, SILC_ID_SERVER),
sock->type == SILC_SOCKET_TYPE_SERVER ?
"Server" : "Router", sock->hostname));
-
- /* As a router we keep information of all global information in our
+
+ /* As a router we keep information of all global information in our
global list. Cell wide information however is kept in the local
list. */
- entry = silc_idlist_add_server(id_list, NULL, 0, id, router,
+ entry = silc_idlist_add_server(id_list, NULL, 0, id, router,
router_sock);
if (!entry) {
SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
goto out;
}
entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
-
+
if (sock->type == SILC_SOCKET_TYPE_SERVER)
server->stat.cell_servers++;
server->stat.servers++;
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- packet->type,
+ packet->type,
packet->flags | SILC_PACKET_FLAG_BROADCAST,
buffer->data, buffer->len, FALSE);
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ silc_server_backup_send(server, sock->user_data,
packet->type, packet->flags,
- packet->buffer->data, packet->buffer->len,
+ packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
}
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- packet->type,
+ packet->type,
packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data,
+ packet->buffer->data,
packet->buffer->len, FALSE);
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ silc_server_backup_send(server, sock->user_data,
packet->type, packet->flags,
- packet->buffer->data, packet->buffer->len,
+ packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
}
data buffer, which we will here now fetch from the original buffer. */
new_id = silc_packet_context_alloc();
new_id->type = SILC_PACKET_NEW_ID;
- new_id->flags = packet->flags;
+ new_id->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
new_id->src_id = packet->src_id;
new_id->src_id_len = packet->src_id_len;
new_id->src_id_type = packet->src_id_type;
silc_free(new_id);
}
-/* Received New Channel packet. Information about new channels in the
+/* Received New Channel packet. Information about new channels in the
network are distributed using this packet. Save the information about
the new channel. This usually comes from router but also normal server
can send this to notify channels it has when it connects to us. */
char *channel_name;
SilcUInt32 name_len;
unsigned char *id;
- SilcUInt32 id_len;
+ SilcUInt32 id_len, cipher_len;
SilcServerEntry server_entry;
SilcChannelEntry channel;
+ const char *cipher;
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
packet->src_id_type != SILC_ID_SERVER ||
packet->buffer->len);
if (!payload)
return;
-
+
/* Get the channel ID */
channel_id = silc_channel_get_id_parse(payload);
if (!channel_id) {
server_entry = (SilcServerEntry)sock->user_data;
if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
- /* Add the channel to global list as it is coming from router. It
+ /* Add the channel to global list as it is coming from router. It
cannot be our own channel as it is coming from router. */
/* Check that we don't already have this channel */
- channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
if (!channel)
- channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel = silc_idlist_find_channel_by_name(server->global_list,
channel_name, NULL);
if (!channel) {
SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
- silc_id_render(channel_id, SILC_ID_CHANNEL),
+ silc_id_render(channel_id, SILC_ID_CHANNEL),
sock->hostname));
-
- channel =
- silc_idlist_add_channel(server->global_list, strdup(channel_name),
+
+ channel =
+ silc_idlist_add_channel(server->global_list, strdup(channel_name),
0, channel_id, sock->user_data, NULL, NULL, 0);
- if (!channel)
+ if (!channel) {
+ silc_channel_payload_free(payload);
+ silc_free(channel_id);
return;
- channel->disabled = TRUE;
+ }
+ channel->disabled = TRUE; /* Disabled until someone JOINs */
server->stat.channels++;
if (server->server_type == SILC_ROUTER)
SilcBuffer chk;
SILC_LOG_DEBUG(("Channel id(%s) from [Server] %s",
- silc_id_render(channel_id, SILC_ID_CHANNEL),
+ silc_id_render(channel_id, SILC_ID_CHANNEL),
sock->hostname));
/* Check that we don't already have this channel */
- channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
if (!channel)
- channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel = silc_idlist_find_channel_by_name(server->global_list,
channel_name, NULL);
/* If the channel does not exist, then create it. This creates a new
!SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
SilcChannelID *tmp;
SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
-
if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
- silc_server_send_notify_channel_change(server, sock, FALSE,
+ silc_server_send_notify_channel_change(server, sock, FALSE,
channel_id, tmp);
+ silc_channel_payload_free(payload);
silc_free(channel_id);
- channel_id = tmp;
+ silc_free(tmp);
}
+
+ /* Wait that server re-announces this channel */
+ return;
}
/* Create the channel with the provided Channel ID */
silc_free(channel_id);
return;
}
- channel->disabled = TRUE;
- channel->mode = silc_channel_get_mode(payload);
+ channel->disabled = TRUE; /* Disabled until someone JOINs */
+
+#if 0 /* We assume that CMODE_CHANGE notify is sent to us after this. */
+
+ /* XXX Dunno if this is supposed to be set in any server type. If set
+ here the CMODE_CHANGE that may follow sets mode that we already
+ have, and we may loose data from the CMODE_CHANGE notify. */
+ if (server_entry->server_type != SILC_BACKUP_ROUTER)
+ channel->mode = silc_channel_get_mode(payload);
+#endif
/* Send the new channel key to the server */
id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ cipher = silc_cipher_get_name(channel->channel_key);
+ cipher_len = strlen(cipher);
chk = silc_channel_key_payload_encode(id_len, id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8,
+ cipher_len, cipher,
+ channel->key_len / 8,
channel->key);
- silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
chk->data, chk->len, FALSE);
silc_buffer_free(chk);
+ silc_free(id);
} else {
/* The channel exist by that name, check whether the ID's match.
If they don't then we'll force the server to use the ID we have.
/* They don't match, send CHANNEL_CHANGE notify to the server to
force the ID change. */
SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
- silc_server_send_notify_channel_change(server, sock, FALSE,
+ silc_server_send_notify_channel_change(server, sock, FALSE,
channel_id, channel->id);
+ silc_channel_payload_free(payload);
+ silc_free(channel_id);
/* Wait that server re-announces this channel */
return;
/* Create new key for the channel and send it to the server and
everybody else possibly on the channel. */
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
- if (!silc_server_create_channel_key(server, channel, 0))
- return;
-
- /* Send to the channel */
- silc_server_send_channel_key(server, sock, channel, FALSE);
- id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
+ if (silc_hash_table_count(channel->user_list)) {
+ if (!silc_server_create_channel_key(server, channel, 0)) {
+ silc_channel_payload_free(payload);
+ silc_free(channel_id);
+ return;
+ }
+
+ /* Send to the channel */
+ silc_server_send_channel_key(server, sock, channel, FALSE);
+ }
/* Send to the server */
+ id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ cipher = silc_cipher_get_name(channel->channel_key);
+ cipher_len = strlen(cipher);
chk = silc_channel_key_payload_encode(id_len, id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->
- cipher->name,
- channel->key_len / 8,
+ cipher_len, cipher,
+ channel->key_len / 8,
channel->key);
- silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
chk->data, chk->len, FALSE);
silc_buffer_free(chk);
silc_free(id);
silc_free(channel_id);
- /* Update statistics */
- server->stat.channels++;
- server->stat.cell_channels++;
-
/* Since the channel is coming from server and we also know about it
then send the JOIN notify to the server so that it see's our
users on the channel "joining" the channel. */
silc_server_packet_send_dest(server, sock,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel->id, SILC_ID_CHANNEL,
- users_modes->data,
+ users_modes->data,
users_modes->len, FALSE);
silc_buffer_free(users_modes);
}
if (channel->topic) {
silc_server_send_notify_topic_set(server, sock,
server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
+ TRUE : FALSE, channel,
server->id, SILC_ID_SERVER,
channel->topic);
}
}
}
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. Broadcast
+ this list packet instead of multiple New Channel packets. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New Channel packet"));
+ silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
+ silc_server_backup_send(server, sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+
silc_channel_payload_free(payload);
}
server->server_type == SILC_SERVER)
return;
- /* If the sender of this packet is server and we are router we need to
- broadcast this packet to other routers in the network. Broadcast
- this list packet instead of multiple New Channel packets. */
- if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER &&
- !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
- SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
- silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data,
- packet->buffer->len, FALSE);
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
- packet->type, packet->flags,
- packet->buffer->data, packet->buffer->len,
- FALSE, TRUE);
- }
-
/* Make copy of the original packet context, except for the actual
data buffer, which we will here now fetch from the original buffer. */
new = silc_packet_context_alloc();
new->type = SILC_PACKET_NEW_CHANNEL;
- new->flags = packet->flags;
+ new->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
new->src_id = packet->src_id;
new->src_id_len = packet->src_id_len;
new->src_id_type = packet->src_id_type;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, NULL,
+ packet->dst_id_len, NULL,
&idata, NULL);
if (!dst_sock)
return;
SilcServerRekeyInternalContext *proto_ctx;
SilcIDListData idata = (SilcIDListData)sock->user_data;
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Received rekey request"));
+
+ /* If we have other protocol executing we have no other choice but to
+ not execute rekey. XXX This is very bad thing. Let's hope this
+ doesn't happen often. */
+ if (sock->protocol) {
+ SILC_LOG_WARNING(("Cannot execute REKEY protocol because other protocol "
+ "is executing at the same time"));
+ return;
+ }
/* Allocate internal protocol context. This is sent as context
to the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
- proto_ctx->sock = sock;
+ proto_ctx->sock = silc_socket_dup(sock);
proto_ctx->responder = TRUE;
proto_ctx->pfs = idata->rekey->pfs;
-
+
/* Perform rekey protocol. Will call the final callback after the
protocol is over. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
&protocol, proto_ctx, silc_server_rekey_final);
sock->protocol = protocol;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, NULL,
+ packet->dst_id_len, NULL,
&idata, NULL);
if (!dst_sock)
return;
if (reply && silc_command_get(reply->payload) == SILC_COMMAND_WHOIS) {
/* Get entry to the client, and resolve it if we don't have it. */
- client = silc_idlist_find_client_by_id(server->local_list,
+ client = silc_idlist_find_client_by_id(server->local_list,
r->data, TRUE, NULL);
if (!client) {
client = silc_idlist_find_client_by_id(server->global_list,
silc_server_free_sock_user_data(server, sock, NULL);
goto out;
}
+
+ client->data.status |= SILC_IDLIST_STATUS_RESUME_RES;
}
/* Reprocess the packet */
{
SilcBuffer buffer = packet->buffer, buf;
SilcIDListData idata;
+ SilcIDCacheEntry id_cache = NULL;
SilcClientEntry detached_client;
SilcClientID *client_id = NULL;
unsigned char *id_string, *auth = NULL;
SilcHashTableList htl;
SilcChannelClientEntry chl;
SilcServerResumeResolve r;
+ const char *cipher;
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING(&id_string, &id_len),
idata = (SilcIDListData)client;
/* Get entry to the client, and resolve it if we don't have it. */
- detached_client = silc_server_get_client_resolve(server, client_id, FALSE,
- &resolved);
+ detached_client = silc_server_query_client(server, client_id, FALSE,
+ &resolved);
if (!detached_client) {
if (resolved) {
/* The client info is being resolved. Reprocess this packet after
resolve = TRUE;
if (!detached_client->nickname)
resolve = TRUE;
+ if (detached_client->data.status & SILC_IDLIST_STATUS_RESUME_RES)
+ resolve = FALSE;
if (resolve) {
if (server->server_type == SILC_SERVER && !server->standalone) {
/* The client info is being resolved. Reprocess this packet after
receiving the reply to the query. */
SILC_LOG_DEBUG(("Resolving client info"));
- silc_server_get_client_resolve(server, client_id, TRUE, NULL);
+ silc_server_query_client(server, client_id, TRUE, NULL);
r = silc_calloc(1, sizeof(*r));
if (!r)
return;
/* We must retrieve the detached client's public key by sending
GETKEY command. Reprocess this packet after receiving the key */
SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- SilcSocketConnection dest_sock =
+ SilcSocketConnection dest_sock =
silc_server_get_client_route(server, NULL, 0, client_id, NULL, NULL);
SILC_LOG_DEBUG(("Resolving client public key"));
- silc_server_send_command(server, dest_sock ? dest_sock :
+ silc_server_send_command(server, dest_sock ? dest_sock :
SILC_PRIMARY_ROUTE(server),
SILC_COMMAND_GETKEY, ++server->cmd_ident,
1, 1, idp->data, idp->len);
if (!idata->hash ||
!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
detached_client->data.public_key, 0,
- idata->hash, detached_client->id,
+ idata->hash, detached_client->id,
SILC_ID_CLIENT)) {
SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
"closing connection", sock->hostname, sock->ip));
silc_idlist_add_data(detached_client, idata);
detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+ detached_client->data.status |= SILC_IDLIST_STATUS_LOCAL;
+ detached_client->data.status &= ~SILC_IDLIST_STATUS_RESUME_RES;
detached_client->mode &= ~SILC_UMODE_DETACHED;
server->stat.my_detached--;
/* Send to primary router */
silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_RESUME_CLIENT, 0,
+ SILC_PACKET_RESUME_CLIENT, 0,
buf->data, buf->len, TRUE);
+ silc_server_backup_send(server, detached_client->router,
+ SILC_PACKET_RESUME_CLIENT, 0,
+ buf->data, buf->len, TRUE, TRUE);
/* As router we must deliver this packet directly to the original
server whom this client was earlier. */
if (server->server_type == SILC_ROUTER && detached_client->router &&
detached_client->router->server_type != SILC_ROUTER)
silc_server_packet_send(server, detached_client->router->connection,
- SILC_PACKET_RESUME_CLIENT, 0,
+ SILC_PACKET_RESUME_CLIENT, 0,
buf->data, buf->len, TRUE);
silc_buffer_free(buf);
server->stat.clients--;
if (server->stat.cell_clients)
server->stat.cell_clients--;
+ silc_server_remove_from_channels(server, NULL, client, FALSE,
+ NULL, FALSE, FALSE);
silc_server_del_from_watcher_list(server, client);
- silc_idlist_del_client(server->local_list, client);
+ if (!silc_idlist_del_client(server->local_list, client))
+ silc_idlist_del_client(server->global_list, client);
client = detached_client;
+ silc_free(client->servername);
+ client->servername = strdup(server->server_name);
/* If the ID is not based in our ID then change it */
if (!SILC_ID_COMPARE(client->id, server->id, server->id->ip.data_len)) {
silc_free(client_id);
- while (!silc_id_create_client_id(server, server->id, server->rng,
- server->md5hash, client->nickname,
+ while (!silc_id_create_client_id(server, server->id, server->rng,
+ server->md5hash, client->nickname,
&client_id)) {
nickfail++;
if (nickfail > 9) {
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_NICKNAME, NULL);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
return;
}
- snprintf(&client->nickname[strlen(client->nickname) - 1], 1,
+ snprintf(&client->nickname[strlen(client->nickname) - 1], 1,
"%d", nickfail);
}
nick_change = TRUE;
silc_hash_table_list(client->channels, &htl);
while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
channel = chl->channel;
- SILC_LOG_DEBUG(("Resolving users for %s channel",
+ SILC_LOG_DEBUG(("Resolving users for %s channel",
channel->channel_name));
if (channel->disabled || !channel->users_resolved) {
silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
SilcBuffer oidp, nidp;
oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
nidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- silc_server_send_notify_on_channels(server, NULL, client,
+ silc_server_send_notify_on_channels(server, NULL, client,
SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
- oidp->data, oidp->len,
+ oidp->data, oidp->len,
nidp->data, nidp->len,
- client->nickname,
+ client->nickname,
strlen(client->nickname));
silc_buffer_free(oidp);
silc_buffer_free(nidp);
}
id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- keyp =
+ cipher = silc_cipher_get_name(channel->channel_key);
+ keyp =
silc_channel_key_payload_encode(silc_id_get_len(channel->id,
- SILC_ID_CHANNEL),
+ SILC_ID_CHANNEL),
id_string,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
+ strlen(cipher), cipher,
channel->key_len / 8, channel->key);
silc_free(id_string);
- /* Send the key packet to client */
- silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ /* Send the channel key to the client */
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
keyp->data, keyp->len, FALSE);
- if (created && server->server_type == SILC_SERVER)
- silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_CHANNEL_KEY, 0,
- keyp->data, keyp->len, FALSE);
+ /* Distribute the channel key to channel */
+ if (created) {
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
+ keyp->data, keyp->len, FALSE, TRUE);
+ }
silc_buffer_free(keyp);
}
}
/* Get entry to the client, and resolve it if we don't have it. */
- detached_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, TRUE, NULL);
+ detached_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE,
+ &id_cache);
if (!detached_client) {
detached_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, TRUE, NULL);
+ client_id, TRUE,
+ &id_cache);
if (!detached_client) {
SILC_LOG_DEBUG(("Resuming client is unknown"));
silc_free(client_id);
return;
}
+ SILC_LOG_DEBUG(("Resuming detached client"));
+
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
+ silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
+ silc_server_backup_send(server, sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+
/* Client is detached, and now it is resumed. Remove the detached
mode and mark that it is resumed. */
+ silc_idlist_del_data(detached_client);
detached_client->mode &= ~SILC_UMODE_DETACHED;
detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+ detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+ id_cache->expire = 0;
+
+ silc_schedule_task_del_by_context(server->schedule, detached_client);
/* Get the new owner of the resumed client */
server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
}
/* Get server entry */
- server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
server_id, TRUE, NULL);
- local = TRUE;
+ local = FALSE;
if (!server_entry) {
- server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
server_id, TRUE, NULL);
- local = FALSE;
+ local = TRUE;
if (!server_entry) {
silc_free(server_id);
silc_free(client_id);
}
if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER &&
server_entry->server_type == SILC_ROUTER)
local = FALSE;
- SILC_LOG_DEBUG(("Resuming detached client"));
-
/* Change the client to correct list. */
if (!silc_idcache_del_by_context(server->local_list->clients,
detached_client))
silc_idcache_del_by_context(server->global_list->clients,
detached_client);
- silc_idcache_add(local && server->server_type == SILC_ROUTER ?
- server->local_list->clients :
- server->global_list->clients,
+ silc_idcache_add(local && server->server_type == SILC_ROUTER ?
+ server->local_list->clients :
+ server->global_list->clients,
detached_client->nickname,
detached_client->id, detached_client, FALSE, NULL);
- detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
- /* Change the owner of the client if needed */
- if (detached_client->router != server_entry)
- detached_client->router = server_entry;
+ /* Change the owner of the client */
+ detached_client->router = server_entry;
/* Update channel information regarding global clients on channel. */
- if (server->server_type == SILC_SERVER) {
+ if (server->server_type != SILC_ROUTER) {
silc_hash_table_list(detached_client->channels, &htl);
while (silc_hash_table_get(&htl, NULL, (void **)&chl))
- chl->channel->global_users =
+ chl->channel->global_users =
silc_server_channel_has_global(chl->channel);
silc_hash_table_list_reset(&htl);
}
- silc_schedule_task_del_by_context(server->schedule, detached_client);
-
- /* If the sender of this packet is server and we are router we need to
- broadcast this packet to other routers in the network. */
- if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER &&
- !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
- SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
- silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
- silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
- packet->type, packet->flags,
- packet->buffer->data, packet->buffer->len,
- FALSE, TRUE);
- }
-
silc_free(server_id);
}