SilcClientEntry client = NULL, client2 = NULL;
SilcServerEntry server_entry = NULL;
SilcChannelClientEntry chl;
- SilcIDCacheEntry cache;
+ SilcIDCacheEntry cache = NULL;
SilcHashTableList htl;
SilcUInt32 mode;
unsigned char *tmp;
SilcUInt32 tmp_len;
bool local;
- SILC_LOG_DEBUG(("Start"));
-
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
- packet->src_id_type != SILC_ID_SERVER)
- return;
-
- if (!packet->dst_id)
+ packet->src_id_type != SILC_ID_SERVER || !packet->dst_id) {
+ SILC_LOG_DEBUG(("Bad notify packet received"));
return;
+ }
/* If the packet is destined directly to a client then relay the packet
before processing it. */
we will broadcast it. The sending socket really cannot be router or
the router is buggy. If this packet is coming from router then it must
have the broadcast flag set already and we won't do anything. */
- if (!server->standalone && server->server_type == SILC_ROUTER &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
if (!channel_id)
goto out;
- silc_server_packet_send_dest(server, server->router->connection,
- 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->len,
- FALSE);
- silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
+ silc_server_backup_send_dest(server, sock->user_data,
packet->type, packet->flags,
channel_id, SILC_ID_CHANNEL,
packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
} else {
/* Packet is destined to client or server */
- silc_server_packet_send(server, server->router->connection,
+ 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,
+ silc_server_backup_send(server, sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
*/
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)
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;
}
entry for the client. */
client = silc_idlist_find_client_by_id(server->global_list,
client_id, server->server_type,
- NULL);
+ &cache);
if (!client) {
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 =
silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
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;
}
chl->client = client;
chl->channel = channel;
- /* If this is the first one on the channel then it is the founder of
- the channel. */
- if (!silc_hash_table_count(channel->user_list))
- chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ if (server->server_type != SILC_ROUTER ||
+ sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ /* If this is the first one on the channel then it is the founder of
+ the channel. This is done on normal server and on router if this
+ notify is coming from router */
+ if (!silc_hash_table_count(channel->user_list)) {
+ SILC_LOG_DEBUG(("Client %s is founder on channel",
+ silc_id_render(chl->client->id, SILC_ID_CLIENT)));
+ chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ }
+ }
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)
+ server->stat.cell_chanclients++;
+ server->stat.chanclients++;
+ }
break;
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_free(client_id);
+ silc_free(channel_id);
/* Check if on channel */
if (!silc_server_client_on_channel(client, channel, NULL))
server->stat.cell_clients--;
SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+ 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_check_watcher_list(server, client, NULL,
SILC_NOTIFY_TYPE_SIGNOFF);
+ /* Remove this client from watcher list if it is */
+ silc_server_del_from_watcher_list(server, client);
+
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
break;
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
goto out;
- client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
if (!client_id)
goto out;
/* Get client entry */
- 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,
+ if (id_type == SILC_ID_CLIENT) {
+ client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, &cache);
if (!client) {
- silc_free(client_id);
- goto out;
+ 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);
/* Get the topic */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
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_free(channel_id);
- if (channel->topic && !strcmp(channel->topic, tmp))
+ if (channel->topic && !strcmp(channel->topic, tmp)) {
+ SILC_LOG_DEBUG(("Topic is already set and same"));
goto out;
+ }
- /* Get user's channel entry and check that topic set is allowed. */
- if (!silc_server_client_on_channel(client, channel, &chl))
- goto out;
- if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
- SILC_LOG_DEBUG(("Topic change is not allowed"));
- goto out;
+ if (client) {
+ /* Get user's channel entry and check that topic set is allowed. */
+ if (!silc_server_client_on_channel(client, channel, &chl))
+ goto out;
+ if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ SILC_LOG_DEBUG(("Topic change is not allowed"));
+ goto out;
+ }
}
/* Change the topic */
channel->topic = strdup(tmp);
/* Send the same notify to the channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
FALSE, packet->buffer->data,
packet->buffer->len, FALSE);
- silc_free(channel_id);
break;
case SILC_NOTIFY_TYPE_NICK_CHANGE:
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_id_render(client_id, SILC_ID_CLIENT)));
/*
* Distribute the notify to local clients on the channel
*/
-
+
SILC_LOG_DEBUG(("CMODE CHANGE notify"));
-
+
/* Get client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
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,
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);
/* Check if mode changed */
- if (channel->mode == mode)
+ if (channel->mode == mode) {
+ SILC_LOG_DEBUG(("Mode is changed already"));
+
+ /* If this mode change has founder mode then we'll enforce the
+ change so that the server gets the real founder public key */
+ if (server->server_type != SILC_SERVER &&
+ sock != SILC_PRIMARY_ROUTE(server) &&
+ mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && channel->founder_key) {
+ SILC_LOG_DEBUG(("Sending founder public key to server"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
+ }
+
+ /* If we received same mode from our primary check whether founder
+ mode and key in the notify is set. We update the founder key
+ here since we may have wrong one */
+ 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 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_payload_decode(tmp, tmp_len,
+ &channel->founder_key);
+ }
+
break;
+ }
/* Get user's channel entry and check that mode change is allowed */
if (client) {
goto out;
if (!silc_server_check_cmode_rights(server, channel, chl, mode)) {
SILC_LOG_DEBUG(("CMODE change is not allowed"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
+ goto out;
+ }
+ } else {
+ /* Assure that server is not removing founder mode from us */
+ if (server->server_type == SILC_ROUTER &&
+ sock != SILC_PRIMARY_ROUTE(server) &&
+ channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH &&
+ !(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
goto out;
}
- }
- /* Send the same notify to the channel */
- silc_server_packet_send_to_channel(server, sock, channel, packet->type,
- FALSE, packet->buffer->data,
- packet->buffer->len, FALSE);
+ /* If server is adding founder mode, check whether there is founder
+ on channel already and is not from this server */
+ if (server->server_type == SILC_ROUTER &&
+ sock != SILC_PRIMARY_ROUTE(server) &&
+ mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl))
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO &&
+ chl->client->router != sock->user_data) {
+ SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
+ silc_hash_table_list_reset(&htl);
+ goto out;
+ }
+ silc_hash_table_list_reset(&htl);
+ }
+ }
/* If the channel had private keys set and the mode was removed then
we must re-generate and re-distribute a new channel key */
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);
if (!channel->founder_key ||
(client && client->data.public_key &&
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
- } else if (!client->data.public_key) {
+ } else if (client && !client->data.public_key) {
client->data.public_key =
silc_pkcs_public_key_copy(channel->founder_key);
}
}
+ if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && !channel->founder_key &&
+ server->server_type == SILC_ROUTER) {
+ 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->hmac_name,
+ channel->passphrase, NULL);
+ }
+
+ /* Send the same notify to the channel */
+ silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
/* Change mode */
channel->mode = mode;
*/
SilcChannelClientEntry chl2 = NULL;
bool notify_sent = FALSE;
-
+
SILC_LOG_DEBUG(("CUMODE CHANGE notify"));
-
+
/* Get client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
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,
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;
}
if (!silc_server_client_on_channel(client, channel, &chl))
goto out;
- if (client != client2) {
+ if (client != client2 && server->server_type == SILC_ROUTER) {
/* Sender must be operator */
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
goto out;
}
- /* Check that target is on channel */
if (!silc_server_client_on_channel(client2, channel, &chl))
goto out;
}
}
+ /* Get target channel user entry */
+ if (!silc_server_client_on_channel(client2, channel, &chl))
+ goto out;
+
+ if (server->server_type == SILC_SERVER && chl->mode == mode) {
+ SILC_LOG_DEBUG(("Mode is changed already"));
+ break;
+ }
+
if (mode & SILC_CHANNEL_UMODE_CHANFO &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
- server->server_type == SILC_ROUTER) {
- /* Check whether this client is allowed to be channel founder on
- this channel. */
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+ server->server_type == SILC_ROUTER &&
+ sock != SILC_PRIMARY_ROUTE(server)) {
+ SilcPublicKey founder_key = NULL;
/* 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. */
- if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
/* Force the mode to not have founder mode */
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ 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(channel->user_list, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
- notify_sent = TRUE;
+ /* 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;
+ }
break;
}
silc_hash_table_list_reset(&htl);
if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
break;
- /* XXX Founder not found of the channel. Since the founder auth mode
+ /* Founder not found of the channel. Since the founder auth mode
is set on the channel now check whether this is the client that
- originally set the mode. If we don't have the public key it
- is resolved first.
- if (!silc_pkcs_public_key_compare(channel->founder_key,
- client->data.public_key))
- */
-
+ originally set the mode. */
+
+ 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_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;
+ break;
+ }
+
+ /* Now match the public key we have cached and public key sent.
+ They must match. */
+#if 0 /* The key may be other than the client's in 1.2 */
+ 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;
+ }
+#endif
+ if (!silc_pkcs_public_key_compare(channel->founder_key,
+ founder_key)) {
+ chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
+ }
+ }
+
+ /* There cannot be anyone else as founder on the channel now. This
+ client is definitely the founder due to this authentication */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+ if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, NULL, channel, chl2,
+ chl2->mode);
+ break;
+ }
+ silc_hash_table_list_reset(&htl);
+
+ if (founder_key)
+ silc_pkcs_public_key_free(founder_key);
+ }
+
+ if (server->server_type != SILC_SERVER && chl->mode == mode) {
+ SILC_LOG_DEBUG(("Mode is changed already"));
+ break;
}
- SILC_LOG_DEBUG(("Changing the channel user mode"));
+ SILC_LOG_DEBUG(("Changing %s channel user mode",
+ chl->client->nickname ? chl->client->nickname :
+ (unsigned char *)""));
/* Change the mode */
chl->mode = mode;
/* Send the same notify to the channel */
if (!notify_sent)
- silc_server_packet_send_to_channel(server, sock, channel,
- packet->type,
- FALSE, packet->buffer->data,
+ silc_server_packet_send_to_channel(server, NULL, channel,
+ packet->type,
+ FALSE, packet->buffer->data,
packet->buffer->len, FALSE);
silc_free(channel_id);
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;
}
channel = silc_idlist_find_channel_by_id(server->global_list,
channel_id, NULL);
if (!channel) {
+ SILC_LOG_DEBUG(("Notify for unknown channel"));
silc_free(channel_id);
goto out;
}
}
if (channel_id2) {
- SilcBuffer users = NULL, users_modes = NULL;
+ SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
/* Re-announce this channel which ID was changed. */
silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
channel->mode);
/* Re-announce our clients on the channel as the ID has changed now */
- silc_server_announce_get_channel_users(server, channel, &users,
+ silc_server_announce_get_channel_users(server, channel, &modes, &users,
&users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (modes) {
+ silc_buffer_push(modes, modes->data - modes->head);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ modes->data, modes->len, FALSE);
+ silc_buffer_free(modes);
+ }
if (users_modes) {
silc_buffer_push(users_modes, users_modes->data - users_modes->head);
silc_server_packet_send_dest(server, sock,
silc_server_send_notify_topic_set(server, sock,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
- channel->id, SILC_ID_CHANNEL,
+ server->id, SILC_ID_SERVER,
channel->topic);
}
}
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_id, TRUE, NULL);
- local = TRUE;
+ local = FALSE;
if (!server_entry) {
server_entry = silc_idlist_find_server_by_id(server->local_list,
server_id, TRUE, NULL);
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);
- /* 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);
+ /* Sending SERVER_SIGNOFF is not right way to signoff local connection */
+ if (SILC_IS_LOCAL(server_entry))
+ 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);
+
+ /* 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 */
silc_idlist_del_server(local ? server->local_list :
server->global_list, server_entry);
- /* XXX update statistics */
+ /* Update statistics */
+ if (server->server_type == SILC_ROUTER)
+ server->stat.servers--;
break;
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;
}
/* If the the client is not in local list we check global list */
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, TRUE, NULL);
+ client_id, TRUE, &cache);
if (!client) {
client = silc_idlist_find_client_by_id(server->local_list,
- client_id, TRUE, NULL);
+ client_id, TRUE, &cache);
if (!client) {
silc_free(client_id);
goto out;
silc_free(client_id);
/* Killer must be router operator */
- if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ if (server->server_type != SILC_SERVER &&
+ !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
SILC_LOG_DEBUG(("Killing is not allowed"));
goto out;
}
FALSE);
/* Check if anyone is watching this nickname */
- if (server->server_type == SILC_ROUTER)
- silc_server_check_watcher_list(server, client, NULL,
- SILC_NOTIFY_TYPE_KILLED);
+ silc_server_check_watcher_list(server, client, NULL,
+ SILC_NOTIFY_TYPE_KILLED);
+
+ /* Update statistics */
+ server->stat.clients--;
+ if (server->stat.cell_clients)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+ if (SILC_IS_LOCAL(client)) {
+ server->stat.my_clients--;
+ silc_schedule_task_del_by_context(server->schedule, client);
+ silc_idlist_del_data(client);
+ client->mode = 0;
+ }
+ client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+ cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
break;
}
goto out;
SILC_GET32_MSB(mode, tmp);
- /* Check that mode changing is allowed. */
- if (!silc_server_check_umode_rights(server, client, mode)) {
- SILC_LOG_DEBUG(("UMODE change is not allowed"));
- goto out;
- }
-
/* Remove internal resumed flag if client is marked detached now */
if (mode & SILC_UMODE_DETACHED)
client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
+ /* Update statistics */
+ if (server->server_type == SILC_ROUTER) {
+ if (mode & SILC_UMODE_GONE) {
+ if (!(client->mode & SILC_UMODE_GONE))
+ server->stat.aways++;
+ } else {
+ if (client->mode & SILC_UMODE_GONE)
+ server->stat.aways--;
+ }
+ if (mode & SILC_UMODE_DETACHED) {
+ if (!(client->mode & SILC_UMODE_DETACHED))
+ server->stat.detached++;
+ } else {
+ if (client->mode & SILC_UMODE_DETACHED)
+ 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;
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;
}
if (client) {
silc_server_remove_from_channels(server, NULL, client, TRUE,
NULL, TRUE);
+ silc_idlist_del_data(client);
silc_idlist_del_client(server->global_list, client);
}
silc_free(client_id);
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;
SILC_LOG_DEBUG(("Channel is silenced from operators"));
goto out;
}
+ if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
+ SILC_LOG_DEBUG(("Sender is quieted on the channel"));
+ 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
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;
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);
}
SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
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;
}
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_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_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_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;
}
if (nickfail > 9) {
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 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);
client_id, client, 0, NULL);
/* Notify our router about new client on the SILC network */
- if (!server->standalone)
- silc_server_send_new_id(server, (SilcSocketConnection)
- server->router->connection,
- server->server_type == SILC_ROUTER ? TRUE : FALSE,
- client->id, SILC_ID_CLIENT, id_len);
-
+ silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
+ SILC_BROADCAST(server), client->id,
+ SILC_ID_CLIENT, id_len);
+
+ /* 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, sock->user_data, SILC_PACKET_NEW_ID, 0,
+ idp->data, idp->len, FALSE, TRUE);
+ silc_buffer_free(idp);
+ }
+
/* Send the new client ID to the client. */
silc_server_send_new_id(server, sock, FALSE, client->id, SILC_ID_CLIENT,
silc_id_get_len(client->id, SILC_ID_CLIENT));
"server" : "router")));
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;
}
local = FALSE;
&name_len),
SILC_STR_END);
if (ret == -1) {
- if (id_string)
- silc_free(id_string);
- if (server_name)
- silc_free(server_name);
+ silc_free(id_string);
+ silc_free(server_name);
+ 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;
}
if (id_len > buffer->len) {
silc_free(id_string);
silc_free(server_name);
+ 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;
}
if (!server_id) {
silc_free(id_string);
silc_free(server_name);
+ 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(id_string);
sock->ip, sock->hostname));
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);
silc_free(server_name);
return NULL;
}
to our router. If we are normal server we won't send anything
since this connection must be our router connection. */
if (server->server_type == SILC_ROUTER && !server->standalone &&
- server->router->connection != sock)
- silc_server_send_new_id(server, server->router->connection,
+ SILC_PRIMARY_ROUTE(server) != sock)
+ silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
TRUE, new_server->id, SILC_ID_SERVER,
silc_id_get_len(server_id, SILC_ID_SERVER));
- if (server->server_type == SILC_ROUTER)
+ 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, sock->user_data, SILC_PACKET_NEW_ID, 0,
+ idp->data, idp->len, FALSE, TRUE);
+ silc_buffer_free(idp);
+
+ /* Statistics */
server->stat.cell_servers++;
+ }
/* Check whether this router connection has been replaced by an
backup router. If it has been then we'll disable the server and will
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 &&
+ sock->type == SILC_SOCKET_TYPE_SERVER)
+ idata->status |= SILC_IDLIST_STATUS_DISABLED;
}
return new_server;
id_type == SILC_ID_SERVER &&
server->id_entry->server_type != SILC_BACKUP_ROUTER) {
id_list = server->global_list;
- router_sock = server->router ? server->router->connection : sock;
+ router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock;
}
} else {
void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
/* 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 (broadcast && !server->standalone && server->server_type == SILC_ROUTER &&
+ if (broadcast && server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
- silc_server_packet_send(server, server->router->connection,
+ 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,
+ silc_server_backup_send(server, sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
FALSE, TRUE);
/* 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 ID packets. */
- if (!server->standalone && server->server_type == SILC_ROUTER &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
- silc_server_packet_send(server, server->router->connection,
+ 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->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);
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;
char *channel_name;
SilcUInt32 name_len;
unsigned char *id;
- SilcUInt32 id_len;
- SilcUInt32 mode;
+ SilcUInt32 id_len, cipher_len;
SilcServerEntry server_entry;
SilcChannelEntry channel;
-
- SILC_LOG_DEBUG(("Processing New Channel"));
+ const char *cipher;
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
packet->src_id_type != SILC_ID_SERVER ||
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; /* Disabled until someone JOINs */
server->stat.channels++;
if (server->server_type == SILC_ROUTER)
/* If the channel does not exist, then create it. This creates a new
key to the channel as well that we will send to the server. */
if (!channel) {
+ SILC_LOG_DEBUG(("Channel is new to us"));
+
/* The protocol says that the Channel ID's IP address must be based
on the router's IP address. Check whether the ID is based in our
IP and if it is not then create a new ID and enforce the server
!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,
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; /* Disabled until someone JOINs */
- /* Get the mode and set it to the channel */
- channel->mode = silc_channel_get_mode(payload);
+#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,
+ cipher_len, cipher,
channel->key_len / 8,
channel->key);
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.
We also create a new key for the channel. */
- SilcBuffer users = NULL, users_modes = NULL;
+ SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
+
+ SILC_LOG_DEBUG(("Channel already exists"));
if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
/* They don't match, send CHANNEL_CHANGE notify to the server to
SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
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;
}
+#if 0 /* We will announce our CMODE anyway for this channel, so no need
+ to check it (implicit enforce). */
+
/* If the mode is different from what we have then enforce the
mode change. */
mode = silc_channel_get_mode(payload);
channel->passphrase,
channel->founder_key);
}
+#endif
/* 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,
+ cipher_len, cipher,
channel->key_len / 8,
channel->key);
silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
/* 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_announce_get_channel_users(server, channel, &users,
+ silc_server_announce_get_channel_users(server, channel, &modes, &users,
&users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (modes) {
+ silc_buffer_push(modes, modes->data - modes->head);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ modes->data, modes->len, FALSE);
+ silc_buffer_free(modes);
+ }
if (users_modes) {
silc_buffer_push(users_modes, users_modes->data - users_modes->head);
silc_server_packet_send_dest(server, sock,
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,
+ 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->standalone && 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, server->router->connection,
- 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;
int ret;
SilcAuthMethod auth_meth = SILC_AUTH_NONE;
- SILC_LOG_DEBUG(("Start"));
-
- if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT)
+ if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT) {
+ SILC_LOG_DEBUG(("Request not from client"));
return;
+ }
/* Parse the payload */
ret = silc_buffer_unformat(packet->buffer,
auth_meth = SILC_AUTH_PUBLIC_KEY;
}
+ SILC_LOG_DEBUG(("Authentication method is [%s]",
+ (auth_meth == SILC_AUTH_NONE ? "None" :
+ auth_meth == SILC_AUTH_PASSWORD ? "Passphrase" :
+ "Digital signatures")));
+
/* Send it back to the client */
silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
}
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
goto out;
}
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
goto out;
}
}
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ 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;
-
- SILC_LOG_DEBUG(("Start"));
+ const char *cipher;
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING(&id_string, &id_len),
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
return;
}
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
r->server = server;
r->sock = silc_socket_dup(sock);
r->packet = silc_packet_context_dup(packet);
- r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+ r->data = client_id;
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
server->cmd_ident,
silc_server_command_resume_resolve, r);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
}
return;
}
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;
r->server = server;
r->sock = silc_socket_dup(sock);
r->packet = silc_packet_context_dup(packet);
- r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+ r->data = client_id;
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
server->cmd_ident,
silc_server_command_resume_resolve, r);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
return;
}
}
resolve it first. */
if (!detached_client->data.public_key) {
if (server->server_type == SILC_SERVER && server->standalone) {
+ SILC_LOG_ERROR(("Detached client's public key not present, "
+ "closing connection"));
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
} else {
/* We must retrieve the detached client's public key by sending
GETKEY command. Reprocess this packet after receiving the key */
SILC_LOG_DEBUG(("Resolving client public key"));
silc_server_send_command(server, dest_sock ? dest_sock :
- server->router->connection,
+ SILC_PRIMARY_ROUTE(server),
SILC_COMMAND_GETKEY, ++server->cmd_ident,
1, 1, idp->data, idp->len);
r = silc_calloc(1, sizeof(*r));
- if (!r)
+ if (!r) {
+ silc_free(client_id);
return;
+ }
r->server = server;
r->sock = silc_socket_dup(sock);
silc_buffer_free(idp);
}
+ silc_free(client_id);
return;
} else if (!silc_pkcs_public_key_compare(detached_client->data.public_key,
idata->public_key)) {
/* We require that the connection and resuming authentication data
must be using same key pair. */
+ SILC_LOG_ERROR(("Resuming attempted with wrong public key, "
+ "closing connection"));
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
return;
}
/* Verify the authentication payload. This has to be successful in
order to allow the resuming */
- if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+ 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,
SILC_ID_CLIENT)) {
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_free(client_id);
return;
}
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_RESUME_RES;
detached_client->mode &= ~SILC_UMODE_DETACHED;
+ server->stat.my_detached--;
/* Send the RESUME_CLIENT packet to our primary router so that others
know this client isn't detached anymore. */
SILC_STR_END);
/* Send to primary router */
- if (!server->standalone)
- silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_RESUME_CLIENT, 0,
- buf->data, buf->len, TRUE);
+ silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+ 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. */
server->stat.clients--;
if (server->stat.cell_clients)
server->stat.cell_clients--;
- silc_idlist_del_client(server->local_list, client);
+ silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, FALSE);
+ silc_server_del_from_watcher_list(server, 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,
&client_id)) {
if (nickfail > 9) {
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,
if (nick_change) {
/* Notify about Client ID change, nickname doesn't actually change. */
- if (!server->standalone)
- silc_server_send_notify_nick_change(server, server->router->connection,
- FALSE, client->id, client_id,
- client->nickname);
+ silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
+ SILC_BROADCAST(server),
+ client->id, client_id,
+ client->nickname);
}
/* Resolve users on those channels that client has joined but we
SILC_LOG_DEBUG(("Resolving users for %s channel",
channel->channel_name));
if (channel->disabled || !channel->users_resolved) {
- silc_server_send_command(server, server->router->connection,
+ silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
SILC_COMMAND_USERS, ++server->cmd_ident,
1, 2, channel->channel_name,
strlen(channel->channel_name));
}
id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ cipher = silc_cipher_get_name(channel->channel_key);
keyp =
silc_channel_key_payload_encode(silc_id_get_len(channel->id,
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 */
+ /* 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 &&
- !server->standalone)
- silc_server_packet_send(server, server->router->connection,
- 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);
}
SilcServerEntry server_entry;
SilcServerID *server_id;
- if (!client_id)
+ if (!client_id) {
+ SILC_LOG_DEBUG(("Malformed resuming packet"));
return;
+ }
/* 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);
+ client_id, TRUE,
+ &id_cache);
if (!detached_client) {
detached_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, TRUE, NULL);
- if (!detached_client)
+ client_id, TRUE,
+ &id_cache);
+ if (!detached_client) {
+ SILC_LOG_DEBUG(("Resuming client is unknown"));
+ silc_free(client_id);
return;
+ }
}
/* Check that the client has not been resumed already because it is
/* The client is clearly attempting to resume more than once and
perhaps playing around by resuming from several different places
at the same time. */
+ SILC_LOG_DEBUG(("Attempting to re-resume client, killing both"));
silc_server_kill_client(server, detached_client, NULL,
server->id, SILC_ID_SERVER);
+ silc_free(client_id);
return;
}
/* Check whether client is detached at all */
- if (!(detached_client->mode & SILC_UMODE_DETACHED))
+ if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
+ SILC_LOG_DEBUG(("Client is not detached"));
+ 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. */
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,
packet->src_id_type);
- if (!server_id)
+ if (!server_id) {
+ silc_free(client_id);
return;
+ }
/* Get server entry */
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_id, TRUE, NULL);
- local = FALSE;
+ local = TRUE;
if (!server_entry) {
silc_free(server_id);
+ silc_free(client_id);
return;
}
}
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);
- /* 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 =
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->standalone && 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, server->router->connection,
- 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);
}