updates, check CHANGES
authorPekka Riikonen <priikone@silcnet.org>
Mon, 27 Nov 2000 21:20:07 +0000 (21:20 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 27 Nov 2000 21:20:07 +0000 (21:20 +0000)
CHANGES
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/server.c
apps/silcd/server.h

diff --git a/CHANGES b/CHANGES
index 05bea0178d4e7c389caad4584eb167ac8259e38c..9b91d8af760de9d1f936da91353d63a55b211c50 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,34 @@
+Mon Nov 27 21:39:40 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * 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 <priikone@poseidon.pspt.fi>
 
        * Splitted server.[ch] finally.  Created now packet_send.[ch] and
index 51d238aedb2d8ff1fb9e82b084ee5c1590bd068f..e69dcd6684d9f215e61fa90f82d0954eb1fef5ed 100644 (file)
@@ -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
index 64d099fd277df0f207c64aee985d21a02e21377f..514b289f238c73cd47fc6714b4a024cf98c08159 100644 (file)
@@ -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:
index 65a60a72853c874efd1ac21d473322609a72b5b7..a69671d46df7c57bd7e3ecd003e63cf8e688eeea 100644 (file)
@@ -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:
index 3b72d89a77679f52819af78be81954aa71f7651d..661b16d5c04607a9e39cbf3ea8ba3fe9b004fe35 100644 (file)
@@ -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);
+}
index 760095ce60f8f48ee31b6d98a183645c4be9fd0e..4a81510543cc562ec353f9e993ca8f42c411b871 100644 (file)
@@ -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
index b9336a86005434595008ff7d7ee939134526b0c1..1b71f80adc19afd97c936e1a8a819c30841cd88c 100644 (file)
@@ -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));
+}
index 7df7c010e6fc15be36fe90ec36fc5aa7cfec4173..dd952162e571b40f0704b49f3509c4773b71c4ab 100644 (file)
@@ -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