updates.
[silc.git] / apps / silcd / packet_receive.c
index 65ceb85dfb77001d369aa8439338658b2406b077..50111068f314d9ca3448a3675b2cd8dc566835ec 100644 (file)
@@ -45,9 +45,9 @@ void silc_server_notify(SilcServer server,
   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"));
 
@@ -70,7 +70,7 @@ void silc_server_notify(SilcServer server,
     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
@@ -272,17 +272,11 @@ void silc_server_notify(SilcServer server,
     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:
@@ -782,7 +776,7 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on channels
        */
       unsigned char *id;
-      unsigned int id_len;
+      uint32 id_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -960,7 +954,7 @@ void silc_server_notify_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  unsigned short len;
+  uint16 len;
 
   SILC_LOG_DEBUG(("Processing New Notify List"));
 
@@ -1037,7 +1031,7 @@ void silc_server_private_message(SilcServer 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
@@ -1069,7 +1063,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* 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
@@ -1133,7 +1127,7 @@ void silc_server_command_reply(SilcServer server,
     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 */
@@ -1154,6 +1148,7 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelClientEntry chl;
   SilcChannelID *id = NULL;
   void *sender = NULL;
+  void *sender_entry = NULL;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
@@ -1184,12 +1179,13 @@ void silc_server_channel_message(SilcServer server,
                          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"));
@@ -1197,41 +1193,10 @@ void silc_server_channel_message(SilcServer server,
     }
   }
 
-  /* 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;
-    unsigned int iv_len, i;
-    unsigned short 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);
 
@@ -1296,6 +1261,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   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;
   }
 
@@ -1309,6 +1276,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_free(username);
     if (realname)
       silc_free(realname);
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                  "Incomplete client information");
     return NULL;
   }
 
@@ -1434,7 +1403,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   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"));
@@ -1568,8 +1537,25 @@ static void silc_server_new_id_real(SilcServer server,
   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:
@@ -1603,11 +1589,17 @@ static void silc_server_new_id_real(SilcServer server,
     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);
@@ -1647,7 +1639,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
 {
   SilcPacketContext *new_id;
   SilcBuffer idp;
-  unsigned short id_len;
+  uint16 id_len;
 
   SILC_LOG_DEBUG(("Processing New ID List"));
 
@@ -1715,10 +1707,10 @@ void silc_server_new_channel(SilcServer server,
   SilcChannelPayload payload;
   SilcChannelID *channel_id;
   char *channel_name;
-  unsigned int name_len;
+  uint32 name_len;
   unsigned char *id;
-  unsigned int id_len;
-  unsigned int mode;
+  uint32 id_len;
+  uint32 mode;
 
   SILC_LOG_DEBUG(("Processing New Channel"));
 
@@ -1882,7 +1874,7 @@ void silc_server_new_channel_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  unsigned short len1, len2;
+  uint16 len1, len2;
 
   SILC_LOG_DEBUG(("Processing New Channel List"));
 
@@ -1973,7 +1965,7 @@ void silc_server_key_agreement(SilcServer server,
 
   /* 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
@@ -1989,7 +1981,7 @@ void silc_server_connection_auth_request(SilcServer server,
                                         SilcPacketContext *packet)
 {
   SilcServerConfigSectionClientConnection *client = NULL;
-  unsigned short conn_type;
+  uint16 conn_type;
   int ret;
   SilcAuthMethod auth_meth;
 
@@ -2026,3 +2018,35 @@ void silc_server_connection_auth_request(SilcServer server,
                                           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);
+}