if (dst_sock)
/* Relay the packet */
silc_server_relay_packet(server, dst_sock, idata->send_key,
- idata->hmac, packet, TRUE);
+ idata->hmac_receive, packet, TRUE);
}
/* If we are router and this packet is not already broadcast packet
if (tmp_len > 128)
tmp = NULL;
- /* Remove the client from all channels */
- silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, TRUE);
+ /* Remove the client from all channels. */
+ silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
client->data.registered = FALSE;
cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-
-#if 0
- /* Remove the client entry */
- if (!silc_idlist_del_client(server->global_list, client))
- silc_idlist_del_client(server->local_list, client);
-#endif
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
/* Get entry to the channel user list */
silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ SilcChannelClientEntry chl2 = NULL;
+
+ /* If the mode is channel founder and we already find a client
+ to have that mode on the channel we will enforce the sender
+ to change the channel founder mode away. There can be only one
+ channel founder on the channel. */
+ if (server->server_type == SILC_ROUTER &&
+ mode & SILC_CHANNEL_UMODE_CHANFO &&
+ chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ silc_server_send_notify_cumode(server, sock, FALSE, channel,
+ (mode & (~SILC_CHANNEL_UMODE_CHANFO)),
+ server->id, SILC_ID_SERVER,
+ SILC_ID_SERVER_LEN,
+ client->id, SILC_ID_CLIENT_LEN);
+ silc_free(channel_id);
+
+ /* Change the mode back if we changed it */
+ if (chl2)
+ chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ goto out;
+ }
+
if (chl->client == client) {
/* Change the mode */
chl->mode = mode;
- break;
+ if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+ break;
+
+ chl2 = chl;
}
+ }
/* Send the same notify to the channel */
silc_server_packet_send_to_channel(server, sock, channel, packet->type,
}
if (channel_id2) {
- SilcBuffer users = NULL;
+ SilcBuffer users = NULL, users_modes = NULL;
/* 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, &users,
+ &users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users_modes->data, users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
}
silc_free(channel_id);
SilcBuffer buffer;
uint16 len;
- SILC_LOG_DEBUG(("Processing New Notify List"));
+ SILC_LOG_DEBUG(("Processing Notify List"));
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
packet->src_id_type != SILC_ID_SERVER)
/* Send the private message */
silc_server_send_private_message(server, dst_sock, idata->send_key,
- idata->hmac, packet);
+ idata->hmac_send, packet);
}
/* Received private message key packet.. This packet is never for us. It is to
/* Relay the packet */
silc_server_relay_packet(server, dst_sock, idata->send_key,
- idata->hmac, packet, FALSE);
+ idata->hmac_send, packet, FALSE);
}
/* Processes incoming command reply packet. The command reply packet may
idata = (SilcIDListData)client;
/* Encrypt packet */
- silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf,
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf,
buffer->len);
/* Send the packet */
SilcChannelClientEntry chl;
SilcChannelID *id = NULL;
void *sender = NULL;
+ void *sender_entry = NULL;
SILC_LOG_DEBUG(("Processing channel message"));
packet->src_id_type);
if (!sender)
goto out;
- if (sock->type != SILC_SOCKET_TYPE_ROUTER &&
- packet->src_id_type == SILC_ID_CLIENT) {
+ if (packet->src_id_type == SILC_ID_CLIENT) {
silc_list_start(channel->user_list);
while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+ if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) {
+ sender_entry = chl->client;
break;
+ }
}
if (chl == SILC_LIST_END) {
SILC_LOG_DEBUG(("Client not on channel"));
}
}
- /* If we are router and the packet came from router and private key
- has not been set for the channel then we must encrypt the packet
- as it was decrypted with the session key shared between us and the
- router which sent it. This is so, because cells does not share the
- same channel key */
- if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_ROUTER &&
- !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
- SilcBuffer chp;
- uint32 iv_len, i;
- uint16 data_len, flags;
-
- iv_len = silc_cipher_get_block_len(channel->channel_key);
- if (channel->iv[0] == '\0')
- for (i = 0; i < iv_len; i++) channel->iv[i] =
- silc_rng_get_byte(server->rng);
- else
- silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
-
- /* Encode new payload. This encrypts it also. */
- 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);
- silc_buffer_put(packet->buffer, chp->data, chp->len);
- silc_buffer_free(chp);
- }
-
/* Distribute the packet to our local clients. This will send the
packet for further routing as well, if needed. */
silc_server_packet_relay_to_channel(server, sock, channel, sender,
- packet->src_id_type,
+ packet->src_id_type, sender_entry,
packet->buffer->data,
packet->buffer->len, FALSE);
if (!silc_idcache_find_by_context(server->local_list->clients,
sock->user_data, &cache)) {
SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Unknown client");
return NULL;
}
silc_free(username);
if (realname)
silc_free(realname);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Incomplete client information");
return NULL;
}
else
id_list = server->global_list;
- router_sock = sock;
- router = sock->user_data;
+ /* If the packet is coming from server then use the sender as the
+ origin of the the packet. If it came from router then check the real
+ sender of the packet and use that as the origin. */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+ router_sock = sock;
+ router = sock->user_data;
+ } else {
+ void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ router = silc_idlist_find_server_by_id(server->global_list,
+ sender_id, NULL);
+ if (!router)
+ router = silc_idlist_find_server_by_id(server->local_list,
+ sender_id, NULL);
+ silc_free(sender_id);
+ if (!router)
+ goto out;
+ router_sock = sock;
+ }
switch(id_type) {
case SILC_ID_CLIENT:
break;
case SILC_ID_SERVER:
+ /* If the ID is mine, ignore it. */
+ if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+ SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
+ break;
+ }
+
SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
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 global
list. Cell wide information however is kept in the local list. */
silc_idlist_add_server(id_list, NULL, 0, id, router, router_sock);
/* 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;
+ SilcBuffer users = NULL, users_modes = NULL;
if (!channel->id)
channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
/* 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, &users,
+ &users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users_modes->data, users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
}
}
/* Relay the packet */
silc_server_relay_packet(server, dst_sock, idata->send_key,
- idata->hmac, packet, FALSE);
+ idata->hmac_send, packet, FALSE);
}
/* Received connection auth request packet that is used during connection
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);
+}