From c2c7077d20dc0ddb055b9128a5cc2e160ec50b89 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 27 Nov 2000 21:20:07 +0000 Subject: [PATCH] updates, check CHANGES --- CHANGES | 31 ++++ apps/silcd/command.c | 287 +++++++++++++++--------------------- apps/silcd/command_reply.c | 9 +- apps/silcd/packet_receive.c | 79 +++++++--- apps/silcd/packet_send.c | 52 +++++-- apps/silcd/packet_send.h | 4 + apps/silcd/server.c | 61 ++++++-- apps/silcd/server.h | 3 + 8 files changed, 313 insertions(+), 213 deletions(-) diff --git a/CHANGES b/CHANGES index 05bea017..9b91d8af 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,34 @@ +Mon Nov 27 21:39:40 EET 2000 Pekka Riikonen + + * Fixed a channel user mode bug when joining to a channel server gave + everybody channel founder rights, oops. + + * We mark ourselves as the router of the incoming server connection + if we are router ourselves. This way we can check in some packet + sending functions whether it is locally connected server. For + incoming router connections we put NULL. + + * For router sending packets locally means now always sending the + packet cell wide; to local clients and local servers. For normal + server sending packet locally means sending it to only local + clients. + + * Fixed the JOIN command to really work in router environment. If the + channel is created it is always created by the router. Router is + also responsible of making the initial joining to the channel, + sending JOIN notify to the sending server and distributing + NEW_CHANNEL and NEW_CHANNEL_USER packets. Hence, if the channel + does not exist server doesn't do anything else but forward the + command to the router which performs everything. + + * Added silc_server_send_channel_key function to send the Channel Key + payload. + + * Added silc_server_create_channel_key to create new channel key. The + channel key is now re-generated everytime someone joins or leaves + a channel, as protocol dictates. Note: channel->key_len is the + key length in bits. + Wed Nov 22 22:14:19 EET 2000 Pekka Riikonen * Splitted server.[ch] finally. Created now packet_send.[ch] and diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 51d238ae..e69dcd66 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -1224,11 +1224,11 @@ void silc_server_command_send_names(SilcServer server, has been either created or resolved from ID lists. This joins the sent client to the channel. */ -static void -silc_server_command_join_channel(SilcServer server, - SilcServerCommandContext cmd, - SilcChannelEntry channel, - unsigned int umode) +static void silc_server_command_join_channel(SilcServer server, + SilcServerCommandContext cmd, + SilcChannelEntry channel, + int created, + unsigned int umode) { SilcSocketConnection sock = cmd->sock; unsigned char *tmp; @@ -1236,7 +1236,7 @@ silc_server_command_join_channel(SilcServer server, unsigned char *passphrase = NULL, mode[4]; SilcClientEntry client; SilcChannelClientEntry chl; - SilcBuffer packet, idp; + SilcBuffer reply, chidp, clidp; if (!channel) return; @@ -1295,9 +1295,7 @@ silc_server_command_join_channel(SilcServer server, /* If the JOIN request was forwarded to us we will make a bit slower query to get the client pointer. Otherwise, we get the client pointer real easy. */ - if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) { - client = (SilcClientEntry)sock->user_data; - } else { + if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) { void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type); client = silc_idlist_find_client_by_id(server->local_list, id); if (!client) { @@ -1307,6 +1305,8 @@ silc_server_command_join_channel(SilcServer server, goto out; } silc_free(id); + } else { + client = (SilcClientEntry)sock->user_data; } /* Check whether the client already is on the channel */ @@ -1316,6 +1316,10 @@ silc_server_command_join_channel(SilcServer server, goto out; } + /* Generate new channel key as protocol dictates */ + if (!created) + silc_server_create_channel_key(server, channel, 0); + /* Join the client to the channel by adding it to channel's user list. Add also the channel to client entry's channels list for fast cross- referencing. */ @@ -1326,107 +1330,92 @@ silc_server_command_join_channel(SilcServer server, silc_list_add(channel->user_list, chl); silc_list_add(client->channels, chl); - /* Notify router about new user on channel. If we are normal server - we send it to our router, if we are router we send it to our - primary route. */ - if (!server->standalone) { - + /* Encode Client ID Payload of the original client who wants to join */ + clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + + /* Encode command reply packet */ + chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + SILC_PUT32_MSB(channel->mode, mode); + if (!channel->topic) { + reply = + silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, + SILC_STATUS_OK, 0, 3, + 2, channel->channel_name, + strlen(channel->channel_name), + 3, chidp->data, chidp->len, + 4, mode, 4); + } else { + reply = + silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, + SILC_STATUS_OK, 0, 4, + 2, channel->channel_name, + strlen(channel->channel_name), + 3, chidp->data, chidp->len, + 4, mode, 4, + 5, channel->topic, + strlen(channel->topic)); } + + if (server->server_type == SILC_ROUTER && + cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) { + /* We are router and server has forwarded this command to us. Send + all replys to the server. */ + void *tmpid; + + /* Send command reply destined to the original client */ + tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type); + silc_server_packet_send_dest(cmd->server, sock, + SILC_PACKET_COMMAND_REPLY, 0, + tmpid, cmd->packet->src_id_type, + reply->data, reply->len, FALSE); - /* Send command reply to the client. Client receives the Channe ID, - channel mode and possibly other information in this reply packet. */ - if (!cmd->pending) { - idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); - SILC_PUT32_MSB(channel->mode, mode); + /* Distribute new channel key to local cell and local clients. */ + silc_server_send_channel_key(server, sock, channel, TRUE); + + /* Distribute JOIN notify into the cell for everbody on the channel */ + silc_server_send_notify_to_channel(server, channel, FALSE, + SILC_NOTIFY_TYPE_JOIN, 1, + clidp->data, clidp->len); - if (!channel->topic) - packet = - silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, - SILC_STATUS_OK, 0, 3, - 2, channel->channel_name, - strlen(channel->channel_name), - 3, idp->data, idp->len, - 4, mode, 4); - else - packet = - silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, - SILC_STATUS_OK, 0, 4, - 2, channel->channel_name, - strlen(channel->channel_name), - 3, idp->data, idp->len, - 4, mode, 4, - 5, channel->topic, - strlen(channel->topic)); - - if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) { - void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type); - silc_server_packet_send_dest(cmd->server, cmd->sock, - SILC_PACKET_COMMAND_REPLY, 0, - id, cmd->packet->src_id_type, - packet->data, packet->len, FALSE); - silc_free(id); - } else - silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); + /* Broadcast NEW_CHANNEL_USER packet to primary route */ + silc_server_send_new_channel_user(server, server->router->connection, + TRUE, channel->id, SILC_ID_CHANNEL_LEN, + client->id, SILC_ID_CLIENT_LEN); - /* Send channel key to the client. Client cannot start transmitting - to the channel until we have sent the key. */ - tmp_len = strlen(channel->channel_key->cipher->name); - packet = - silc_channel_key_payload_encode(idp->len, idp->data, - 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, - packet->data, packet->len, FALSE); + silc_free(tmpid); + } else { + /* Client sent the command. Send all replies directly to the client. */ - silc_buffer_free(packet); - silc_buffer_free(idp); - } + /* Send command reply */ + silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, + reply->data, reply->len, FALSE); - /* Finally, send notify message to all clients on the channel about - new user on the channel. */ - if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) { - if (!cmd->pending) { - /* Send JOIN notify to clients */ - SilcBuffer clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); - silc_server_send_notify_to_channel(server, channel, FALSE, - SILC_NOTIFY_TYPE_JOIN, 1, - clidp->data, clidp->len); - silc_buffer_free(clidp); - - /* Send NEW_CHANNEL_USER packet to primary route */ - if (!server->standalone) - silc_server_send_new_channel_user(server, server->router->connection, - server->server_type == SILC_SERVER ? - FALSE : TRUE, - channel->id, SILC_ID_CHANNEL_LEN, - client->id, SILC_ID_CLIENT_LEN); - } else { - /* This is pending command request. Send the notify after we have - received the key for the channel from the router. */ - JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx)); - ctx->channel_name = channel->channel_name; - ctx->nickname = client->nickname; - ctx->username = client->username; - ctx->hostname = sock->hostname ? sock->hostname : sock->ip; - ctx->channel = channel; - ctx->server = server; - ctx->client = client; - silc_task_register(server->timeout_queue, sock->sock, - silc_server_command_join_notify, ctx, - 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); - goto out; - } + /* Send the channel key. Channel key is sent before any other packet + to the channel. */ + silc_server_send_channel_key(server, sock, channel, server->standalone ? + FALSE : TRUE); + + /* Send JOIN notify to locally connected clients on the channel */ + silc_server_send_notify_to_channel(server, channel, FALSE, + SILC_NOTIFY_TYPE_JOIN, 1, + clidp->data, clidp->len); + + /* Send NEW_CHANNEL_USER packet to our primary router */ + if (!server->standalone) + silc_server_send_new_channel_user(server, server->router->connection, + FALSE, + channel->id, SILC_ID_CHANNEL_LEN, + client->id, SILC_ID_CLIENT_LEN); /* Send NAMES command reply to the joined channel so the user sees who is currently on the channel. */ silc_server_command_send_names(server, sock, channel); } + silc_buffer_free(reply); + silc_buffer_free(clidp); + silc_buffer_free(chidp); + out: if (passphrase) silc_free(passphrase); @@ -1442,7 +1431,8 @@ SILC_SERVER_CMD_FUNC(join) int argc, tmp_len; char *tmp, *channel_name = NULL, *cipher = NULL; SilcChannelEntry channel; - unsigned int umode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO; + unsigned int umode = 0; + int created = FALSE; SILC_LOG_DEBUG(("Start")); @@ -1488,27 +1478,25 @@ SILC_SERVER_CMD_FUNC(join) if (server->standalone) { channel = silc_server_create_new_channel(server, server->id, cipher, channel_name); + umode |= SILC_CHANNEL_UMODE_CHANOP; + umode |= SILC_CHANNEL_UMODE_CHANFO; + created = TRUE; } else { - /* The channel does not exist on our server. We send JOIN command to - our router which will handle the joining procedure (either creates - the channel if it doesn't exist or joins the client to it) - if we - are normal server. */ + /* The channel does not exist on our server. If we are normal server + we will send JOIN command to our router which will handle the joining + procedure (either creates the channel if it doesn't exist or joins + the client to it). */ if (server->server_type == SILC_SERVER) { - SilcBuffer buffer = cmd->packet->buffer; - /* Forward the original JOIN command to the router */ - silc_buffer_push(buffer, buffer->data - buffer->head); + silc_buffer_push(cmd->packet->buffer, + cmd->packet->buffer->data - + cmd->packet->buffer->head); silc_server_packet_forward(server, (SilcSocketConnection) server->router->connection, - buffer->data, buffer->len, TRUE); - - /* Add the command to be pending. It will be re-executed after - router has replied back to us. */ - cmd->pending = TRUE; - silc_server_command_pending(server, SILC_COMMAND_JOIN, 0, - silc_server_command_join, context); - return; + cmd->packet->buffer->data, + cmd->packet->buffer->len, TRUE); + goto out; } /* We are router and the channel does not seem exist so we will check @@ -1521,12 +1509,13 @@ SILC_SERVER_CMD_FUNC(join) channel_name); umode |= SILC_CHANNEL_UMODE_CHANOP; umode |= SILC_CHANNEL_UMODE_CHANFO; + created = TRUE; } } } /* Join to the channel */ - silc_server_command_join_channel(server, cmd, channel, umode); + silc_server_command_join_channel(server, cmd, channel, created, umode); out: silc_server_command_free(cmd); @@ -1732,23 +1721,12 @@ SILC_SERVER_CMD_FUNC(cmode) /* The mode is removed and we need to generate and distribute new channel key. Clients are not using private channel keys anymore after this. */ - unsigned int key_len; - unsigned char channel_key[32]; /* XXX Duplicated code, make own function for this!! LEAVE uses this as well */ /* Re-generate channel key */ - key_len = channel->key_len / 8; - for (i = 0; i < key_len; i++) - channel_key[i] = silc_rng_get_byte(server->rng); - channel->channel_key->cipher->set_key(channel->channel_key->context, - channel_key, key_len); - memset(channel->key, 0, key_len); - silc_free(channel->key); - channel->key = silc_calloc(key_len, sizeof(*channel->key)); - memcpy(channel->key, channel_key, key_len); - memset(channel_key, 0, sizeof(channel_key)); + silc_server_create_channel_key(server, channel, 0); /* Encode channel key payload to be distributed on the channel */ packet = @@ -1756,7 +1734,7 @@ SILC_SERVER_CMD_FUNC(cmode) strlen(channel->channel_key-> cipher->name), channel->channel_key->cipher->name, - key_len, channel->key); + channel->key_len / 8, channel->key); /* If we are normal server then we will send it to our router. If we are router we will send it to all local servers that has clients on @@ -1882,7 +1860,6 @@ SILC_SERVER_CMD_FUNC(cmode) if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) { /* Cipher to use protect the traffic */ unsigned int key_len = 128; - unsigned char channel_key[32]; char *cp; /* Get cipher */ @@ -1905,20 +1882,12 @@ SILC_SERVER_CMD_FUNC(cmode) silc_cipher_free(channel->channel_key); silc_cipher_alloc(tmp, &channel->channel_key); - /* Re-generate channel key */ key_len /= 8; - if (key_len > sizeof(channel_key)) - key_len = sizeof(channel_key); - - for (i = 0; i < key_len; i++) - channel_key[i] = silc_rng_get_byte(server->rng); - channel->channel_key->cipher->set_key(channel->channel_key->context, - channel_key, key_len); - memset(channel->key, 0, key_len); - silc_free(channel->key); - channel->key = silc_calloc(key_len, sizeof(*channel->key)); - memcpy(channel->key, channel_key, key_len); - memset(channel_key, 0, sizeof(channel_key)); + if (key_len > 32) + key_len = 32; + + /* Re-generate channel key */ + silc_server_create_channel_key(server, channel, key_len); /* Encode channel key payload to be distributed on the channel */ packet = @@ -1926,7 +1895,7 @@ SILC_SERVER_CMD_FUNC(cmode) strlen(channel->channel_key-> cipher->name), channel->channel_key->cipher->name, - key_len, channel->key); + channel->key_len / 8, channel->key); /* If we are normal server then we will send it to our router. If we are router we will send it to all local servers that has clients on @@ -1951,8 +1920,6 @@ SILC_SERVER_CMD_FUNC(cmode) if (channel->mode & SILC_CHANNEL_MODE_CIPHER) { /* Cipher mode is unset. Remove the cipher and revert back to default cipher */ - unsigned int key_len; - unsigned char channel_key[32]; if (channel->mode_data.cipher) { silc_free(channel->mode_data.cipher); @@ -1972,16 +1939,7 @@ SILC_SERVER_CMD_FUNC(cmode) silc_cipher_alloc(channel->cipher, &channel->channel_key); /* Re-generate channel key */ - key_len = channel->key_len / 8; - for (i = 0; i < key_len; i++) - channel_key[i] = silc_rng_get_byte(server->rng); - channel->channel_key->cipher->set_key(channel->channel_key->context, - channel_key, key_len); - memset(channel->key, 0, key_len); - silc_free(channel->key); - channel->key = silc_calloc(key_len, sizeof(*channel->key)); - memcpy(channel->key, channel_key, key_len); - memset(channel_key, 0, sizeof(channel_key)); + silc_server_create_channel_key(server, channel, 0); /* Encode channel key payload to be distributed on the channel */ packet = @@ -1989,7 +1947,7 @@ SILC_SERVER_CMD_FUNC(cmode) strlen(channel->channel_key-> cipher->name), channel->channel_key->cipher->name, - key_len, channel->key); + channel->key_len / 8, channel->key); /* If we are normal server then we will send it to our router. If we are router we will send it to all local servers that has clients on @@ -2255,8 +2213,8 @@ SILC_SERVER_CMD_FUNC(leave) SilcChannelID *id; SilcChannelEntry channel; SilcBuffer packet; - unsigned int i, argc, key_len, len; - unsigned char *tmp, channel_key[32]; + unsigned int i, argc, len; + unsigned char *tmp; SILC_LOG_DEBUG(("Start")); @@ -2315,23 +2273,14 @@ SILC_SERVER_CMD_FUNC(leave) goto out; /* Re-generate channel key */ - key_len = channel->key_len / 8; - for (i = 0; i < key_len; i++) - channel_key[i] = silc_rng_get_byte(server->rng); - channel->channel_key->cipher->set_key(channel->channel_key->context, - channel_key, key_len); - memset(channel->key, 0, key_len); - silc_free(channel->key); - channel->key = silc_calloc(key_len, sizeof(*channel->key)); - memcpy(channel->key, channel_key, key_len); - memset(channel_key, 0, sizeof(channel_key)); + silc_server_create_channel_key(server, channel, 0); /* Encode channel key payload to be distributed on the channel */ packet = silc_channel_key_payload_encode(len, tmp, strlen(channel->channel_key->cipher->name), channel->channel_key->cipher->name, - key_len, channel->key); + channel->key_len / 8, channel->key); /* If we are normal server then we will send it to our router. If we are router we will send it to all local servers that has clients on diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 64d099fd..514b289f 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -271,6 +271,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join) channel_name = strdup(tmp); id = silc_id_payload_parse_id(id_string, len); + /* XXX We should check that we have sent JOIN command to the router + in the first place. Also should check that we don't have the channel + already in the cache. These checks must be made because of possible + buggy routers. */ + SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name, silc_id_render(id, SILC_ID_CHANNEL))); @@ -286,9 +291,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) //entry->global_users = TRUE; - /* Execute pending JOIN command so that the client who originally - wanted to join the channel will be joined after all. */ - SILC_LOG_DEBUG(("Re-executing JOIN command")); + /* Execute any pending commands */ SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN); out: diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 65a60a72..a69671d4 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -247,8 +247,6 @@ void silc_server_channel_message(SilcServer server, /* Received channel key packet. We distribute the key to all of our locally connected clients on the channel. */ -/* XXX Router must accept this packet and distribute the key to all its - server that has clients on the channel */ void silc_server_channel_key(SilcServer server, SilcSocketConnection sock, @@ -262,9 +260,9 @@ void silc_server_channel_key(SilcServer server, unsigned char *tmp; unsigned int tmp_len; char *cipher; + int exist = FALSE; - if (packet->src_id_type != SILC_ID_SERVER && - sock->type != SILC_SOCKET_TYPE_ROUTER) + if (packet->src_id_type != SILC_ID_SERVER) goto out; /* Decode channel key payload */ @@ -287,29 +285,43 @@ void silc_server_channel_key(SilcServer server, goto out; } - /* Save the key for us as well */ tmp = silc_channel_key_get_key(payload, &tmp_len); if (!tmp) goto out; + cipher = silc_channel_key_get_cipher(payload, NULL);; if (!cipher) goto out; - if (!silc_cipher_alloc(cipher, &channel->channel_key)) - goto out; - /* Distribute the key to all clients on the channel */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - silc_server_packet_send(server, chl->client->connection, - SILC_PACKET_CHANNEL_KEY, 0, - buffer->data, buffer->len, TRUE); + /* Remove old key if exists */ + if (channel->key) { + memset(channel->key, 0, channel->key_len); + silc_free(channel_key); + silc_cipher_free(channel->channel_key); + exist = TRUE; } + /* Create new cipher */ + if (!silc_cipher_alloc(cipher, &channel->channel_key)) + goto out; + + /* Save the key */ channel->key_len = tmp_len * 8; channel->key = silc_calloc(tmp_len, sizeof(unsigned char)); memcpy(channel->key, tmp, tmp_len); channel->channel_key->cipher->set_key(channel->channel_key->context, tmp, tmp_len); + + /* Distribute the key to everybody who is on the channel. If we are router + we will also send it to locally connected servers. If we are normal + server and old key did not exist then we don't use this function + as the client is not in our channel user list just yet. We send the + key after receiveing JOIN notify from router. */ + if (server->server_type == SILC_SERVER && exist) + silc_server_send_channel_key(server, channel, FALSE); + if (server->server_type == SILC_ROUTER) + silc_server_send_channel_key(server, channel, FALSE); + out: if (id) silc_free(id); @@ -581,8 +593,7 @@ SilcServerEntry silc_server_new_server(SilcServer server, } /* Processes incoming New ID packet. New ID Payload is used to distribute - information about newly registered clients, servers and created - channels. */ + information about newly registered clients and servers. */ void silc_server_new_id(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet) @@ -833,15 +844,23 @@ void silc_server_notify(SilcServer server, SilcNotifyPayload payload; SilcNotifyType type; SilcArgumentPayload args; + SilcClientID *client_id; + SilcChannelID *channel_id; + SilcClientEntry client; + SilcChannelEntry channel; + unsigned char *tmp; + unsigned int tmp_len; int i; + SILC_LOG_DEBUG(("Start")); + if (sock->type == SILC_SOCKET_TYPE_CLIENT || packet->src_id_type != SILC_ID_SERVER) return; - /* For now we expect that the we are normal server and that the + /* XXX: For now we expect that the we are normal server and that the sender is router. Server could send (protocol allows it) notify to - router but we don't support it yet. XXX! */ + router but we don't support it yet. */ if (server->server_type != SILC_SERVER && sock->type != SILC_SOCKET_TYPE_ROUTER) return; @@ -857,6 +876,32 @@ void silc_server_notify(SilcServer server, switch(type) { case SILC_NOTIFY_TYPE_JOIN: + { + /* Get Client ID */ + tmp = silc_argument_get_arg_type(args, 1, &tmp_len); + if (!tmp) + goto out; + + client_id = silc_id_payload_parse_id(tmp, tmp_len); + + /* Get client entry */ + client = silc_idlist_find_client_by_id(server->local_list, client_id); + if (!client) { + silc_free(client_id); + goto out; + } + + // channel_id = ; + + /* Get channel entry */ + channel = silc_idlist_find_channel_by_id(server->local_list, channel_id); + if (!channel) { + silc_free(client_id); + goto out; + } + + silc_free(client_id); + } break; case SILC_NOTIFY_TYPE_LEAVE: diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 3b72d89a..661b16d5 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -319,7 +319,7 @@ silc_server_packet_send_to_channel_real(SilcServer server, the channel. Usually this is used to send notify messages to the channel, things like notify about new user joining to the channel. If `route' is FALSE then the packet is sent only locally and will not - be routed anywhere. */ + be routed anywhere (for router locally means cell wide). */ void silc_server_packet_send_to_channel(SilcServer server, SilcChannelEntry channel, @@ -381,9 +381,10 @@ void silc_server_packet_send_to_channel(SilcServer server, client = chl->client; /* If client has router set it is not locally connected client and - we will route the message to the router set in the client. */ - if (route && client && client->router && - server->server_type == SILC_ROUTER) { + we will route the message to the router set in the client. Though, + send locally connected server in all cases. */ + if (server->server_type == SILC_ROUTER && client && client->router && + ((!route && client->router->router == server->id_entry) || route)) { int k; /* Check if we have sent the packet to this route already */ @@ -589,7 +590,6 @@ void silc_server_packet_send_local_channel(SilcServer server, unsigned int data_len, int force_send) { - SilcClientEntry client; SilcChannelClientEntry chl; SilcSocketConnection sock = NULL; @@ -598,13 +598,11 @@ void silc_server_packet_send_local_channel(SilcServer server, /* Send the message to clients on the channel's client list. */ silc_list_start(channel->user_list); while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - client = chl->client; - - if (client) { - sock = (SilcSocketConnection)client->connection; + if (chl->client) { + sock = (SilcSocketConnection)chl->client->connection; /* Send the packet to the client */ - silc_server_packet_send_dest(server, sock, type, flags, client->id, + silc_server_packet_send_dest(server, sock, type, flags, chl->client->id, SILC_ID_CLIENT, data, data_len, force_send); } @@ -1087,3 +1085,37 @@ void silc_server_send_new_channel_user(SilcServer server, silc_free(chid); silc_buffer_free(packet); } + +/* Send Channel Key payload to distribute the new channel key. Normal server + sends this to router when new client joins to existing channel. Router + sends this to the local server who forwarded join command in case where + the channel did not exist yet. Both normal and router servers uses this + also to send this to locally connected clients on the channel. This + must not be broadcasted packet. */ + +void silc_server_send_channel_key(SilcServer server, + SilcSocketConnection sock, + SilcChannelEntry channel, + unsigned char route) +{ + SilcBuffer packet; + unsigned char *chid; + unsigned int tmp_len; + + SILC_LOG_DEBUG(("Start")); + + chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL); + if (!chid) + return; + + /* Encode channel key packet */ + tmp_len = strlen(channel->channel_key->cipher->name); + packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len, + channel->channel_key->cipher->name, + channel->key_len / 8, channel->key); + + silc_server_packet_send_to_channel(server, channel, SILC_PACKET_CHANNEL_KEY, + route, packet->data, packet->len, FALSE); + silc_buffer_free(packet); + silc_free(chid); +} diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 760095ce..4a815105 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -129,5 +129,9 @@ void silc_server_send_new_channel_user(SilcServer server, unsigned int channel_id_len, void *client_id, unsigned int client_id_len); +void silc_server_send_channel_key(SilcServer server, + SilcSocketConnection sock, + SilcChannelEntry channel, + unsigned char route); #endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index b9336a86..1b71f80a 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -981,11 +981,14 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) /* Add the server into server cache. The server name and Server ID is updated after we have received NEW_SERVER packet from the - server. */ + server. We mark ourselves as router for this server if we really + are router. */ new_server = silc_idlist_add_server(server->local_list, NULL, sock->type == SILC_SOCKET_TYPE_SERVER ? - SILC_SERVER : SILC_ROUTER, NULL, NULL, sock); + SILC_SERVER : SILC_ROUTER, NULL, + sock->type == SILC_SOCKET_TYPE_SERVER ? + server->id_entry : NULL, sock); if (!new_server) { SILC_LOG_ERROR(("Could not add new server to cache")); silc_free(sock->user_data); @@ -1793,24 +1796,17 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, char *cipher, char *channel_name) { - int i, key_len; SilcChannelID *channel_id; SilcChannelEntry entry; SilcCipher key; - unsigned char channel_key[32]; SILC_LOG_DEBUG(("Creating new channel")); - /* Create channel key */ - for (i = 0; i < 32; i++) channel_key[i] = silc_rng_get_byte(server->rng); - if (!cipher) cipher = "twofish"; - /* Allocate keys */ - key_len = 16; + /* Allocate cipher */ silc_cipher_alloc(cipher, &key); - key->cipher->set_key(key->context, channel_key, key_len); channel_name = strdup(channel_name); @@ -1824,10 +1820,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, return NULL; } - entry->key = silc_calloc(key_len, sizeof(*entry->key)); - entry->key_len = key_len * 8; - memcpy(entry->key, channel_key, key_len); - memset(channel_key, 0, sizeof(channel_key)); + /* Now create the actual key material */ + silc_server_create_channel_key(server, entry, 16); /* Notify other routers about the new channel. We send the packet to our primary route. */ @@ -1838,3 +1832,42 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, return entry; } + +/* Generates new channel key. This is used to create the initial channel key + but also to re-generate new key for channel. If `key_len' is provided + it is the bytes of the key length. */ + +void silc_server_create_channel_key(SilcServer server, + SilcChannelEntry channel, + unsigned int key_len) +{ + int i; + unsigned char channel_key[32]; + unsigned int len; + + if (key_len) + len = key_len; + else if (channel->key_len) + len = channel->key_len / 8; + else + len = 32; + + /* Create channel key */ + for (i = 0; i < len; i++) channel_key[i] = silc_rng_get_byte(server->rng); + + /* Set the key */ + channel->channel_key->cipher->set_key(channel->channel_key->context, + channel_key, len); + + /* Remove old key if exists */ + if (channel->key) { + memset(channel->key, 0, channel->key_len); + silc_free(channel->key); + } + + /* Save the key */ + channel->key_len = len * 8; + channel->key = silc_calloc(len, sizeof(*channel->key)); + memcpy(channel->key, channel_key, len); + memset(channel_key, 0, sizeof(channel_key)); +} diff --git a/apps/silcd/server.h b/apps/silcd/server.h index 7df7c010..dd952162 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -104,5 +104,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, SilcServerID *router_id, char *cipher, char *channel_name); +void silc_server_create_channel_key(SilcServer server, + SilcChannelEntry channel, + unsigned int key_len); #endif -- 2.24.0