SilcArgumentPayload args;
SilcChannelID *channel_id, *channel_id2;
SilcClientID *client_id, *client_id2;
+ SilcServerID *server_id;
SilcChannelEntry channel;
SilcClientEntry client;
+ SilcServerEntry server_entry;
SilcChannelClientEntry chl;
SilcIDCacheEntry cache;
- unsigned int mode;
+ uint32 mode;
unsigned char *tmp;
- unsigned int tmp_len;
+ uint32 tmp_len;
SILC_LOG_DEBUG(("Start"));
SILC_GET32_MSB(mode, tmp);
+ /* 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->mode & SILC_CHANNEL_MODE_PRIVKEY &&
+ !(mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ /* Re-generate channel key */
+ silc_server_create_channel_key(server, channel, 0);
+
+ /* Send the channel key. This sends it to our local clients and if
+ we are normal server to our router as well. */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+
/* Change mode */
channel->mode = mode;
silc_free(channel_id);
SILC_LOG_DEBUG(("CHANNEL CHANGE"));
+ if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+ break;
+
/* Get the old Channel ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
if (!channel_id2)
goto out;
+ 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_id_render(channel_id2, SILC_ID_CHANNEL)));
+
/* Replace the Channel ID */
if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
channel_id2))
- silc_idlist_replace_channel_id(server->local_list, channel_id,
- channel_id2);
+ if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+ channel_id2)) {
+ silc_free(channel_id2);
+ channel_id2 = NULL;
+ }
+
+ if (channel_id2) {
+ SilcBuffer users = NULL;
+
+ /* Re-announce our clients on the channel as the ID has changed now */
+ silc_server_announce_get_channel_users(server, channel, &users);
+ if (users) {
+ silc_buffer_push(users, users->data - users->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users->data, users->len, FALSE);
+ silc_buffer_free(users);
+ }
+ }
silc_free(channel_id);
- silc_free(channel_id2);
break;
case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
- SILC_LOG_DEBUG(("SERVER SIGNOFF notify (not-impl XXX)"));
+ /*
+ * Remove the server entry and all clients that this server owns.
+ */
+
+ SILC_LOG_DEBUG(("SERVER SIGNOFF notify"));
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id)
+ goto out;
+
+ /* Get server entry */
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, NULL);
+ if (!server_entry) {
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, NULL);
+ if (!server_entry) {
+ silc_free(server_id);
+ goto out;
+ }
+ }
+ 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);
+
+ /* Remove the server entry */
+ if (!silc_idlist_del_server(server->global_list, server_entry))
+ silc_idlist_del_server(server->local_list, server_entry);
+
+ /* XXX update statistics */
+
break;
case SILC_NOTIFY_TYPE_KICKED:
* Distribute the notify to local clients on channels
*/
unsigned char *id;
- unsigned int id_len;
+ uint32 id_len;
SILC_LOG_DEBUG(("KILLED notify"));
{
SilcPacketContext *new;
SilcBuffer buffer;
- unsigned short len;
+ uint16 len;
SILC_LOG_DEBUG(("Processing New Notify List"));
sock->type == SILC_SOCKET_TYPE_ROUTER &&
!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
SilcBuffer chp;
- unsigned int iv_len, i, data_len;
+ uint32 iv_len, i;
+ uint16 data_len, flags;
iv_len = silc_cipher_get_block_len(channel->channel_key);
if (channel->iv[0] == '\0')
silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
/* Encode new payload. This encrypts it also. */
- SILC_GET16_MSB(data_len, packet->buffer->data);
- chp = silc_channel_message_payload_encode(data_len,
- packet->buffer->data + 2,
+ SILC_GET16_MSB(flags, packet->buffer->data);
+ SILC_GET16_MSB(data_len, packet->buffer->data + 2);
+ chp = silc_channel_message_payload_encode(flags, data_len,
+ packet->buffer->data + 4,
iv_len, channel->iv,
channel->channel_key,
- channel->hmac, server->rng);
+ channel->hmac);
silc_buffer_put(packet->buffer, chp->data, chp->len);
silc_buffer_free(chp);
}
SilcBuffer buffer = packet->buffer;
SilcChannelEntry channel;
- if (packet->src_id_type != SILC_ID_SERVER)
+ if (packet->src_id_type != SILC_ID_SERVER ||
+ (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER))
return;
/* Save the channel key */
cache->id = (void *)client_id;
cache->type = SILC_ID_CLIENT;
cache->data = username;
+ cache->data_len = strlen(username);
silc_idcache_sort_by_data(server->local_list->clients);
/* Notify our router about new client on the SILC network */
SilcServerID *server_id;
SilcIDListData idata;
unsigned char *server_name, *id_string;
- unsigned short id_len, name_len;
+ uint16 id_len, name_len;
int ret;
SILC_LOG_DEBUG(("Creating new server"));
cache->id = (void *)server_id;
cache->type = SILC_ID_SERVER;
cache->data = server_name;
+ cache->data_len = strlen(server_name);
silc_idcache_sort_by_data(server->local_list->servers);
/* Distribute the information about new server in the SILC network
{
SilcPacketContext *new_id;
SilcBuffer idp;
- unsigned short id_len;
+ uint16 id_len;
SILC_LOG_DEBUG(("Processing New ID List"));
SilcChannelPayload payload;
SilcChannelID *channel_id;
char *channel_name;
- unsigned int name_len;
+ uint32 name_len;
unsigned char *id;
- unsigned int id_len;
+ uint32 id_len;
+ uint32 mode;
SILC_LOG_DEBUG(("Processing New Channel"));
/* 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;
+
+ if (!channel->id)
+ channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
/* They don't match, send CHANNEL_CHANGE notify to the server to
SILC_ID_CHANNEL_LEN);
}
+ /* If the mode is different from what we have then enforce the
+ mode change. */
+ mode = silc_channel_get_mode(payload);
+ if (channel->mode != mode) {
+ SILC_LOG_DEBUG(("Forcing the server to change channel mode"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER, SILC_ID_SERVER_LEN,
+ channel->cipher, channel->hmac_name);
+ }
+
/* Create new key for the channel and send it to the server and
everybody else possibly on the channel. */
- silc_server_create_channel_key(server, channel, 0);
-
- /* Send to the channel */
- silc_server_send_channel_key(server, sock, channel, FALSE);
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ silc_server_create_channel_key(server, channel, 0);
+
+ /* 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_CHANNEL_LEN;
+
+ /* Send to the server */
+ chk = silc_channel_key_payload_encode(id_len, id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->
+ cipher->name,
+ 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);
+ }
- /* Send to the server */
- chk = silc_channel_key_payload_encode(id_len, id,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- 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(channel_id);
/* 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. */
- /* XXX TODO **/
+ silc_server_announce_get_channel_users(server, channel, &users);
+ if (users) {
+ silc_buffer_push(users, users->data - users->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users->data, users->len, FALSE);
+ silc_buffer_free(users);
+ }
}
}
+
+ silc_channel_payload_free(payload);
}
/* Received New Channel List packet, list of New Channel List payloads inside
{
SilcPacketContext *new;
SilcBuffer buffer;
- unsigned short len1, len2;
+ uint16 len1, len2;
SILC_LOG_DEBUG(("Processing New Channel List"));
SilcPacketContext *packet)
{
SilcServerConfigSectionClientConnection *client = NULL;
- unsigned short conn_type;
+ uint16 conn_type;
int ret;
SilcAuthMethod auth_meth;
conn_type,
auth_meth);
}
+
+/* Received REKEY packet. The sender of the packet wants to regenerate
+ its session keys. This starts the REKEY protocol. */
+
+void silc_server_rekey(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* 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->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,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ sock->protocol = protocol;
+
+ if (proto_ctx->pfs == FALSE)
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol, sock->sock, 0, 0);
+}