Fixed packet relaying.
[silc.git] / apps / silcd / packet_receive.c
index 9d4730612e5183ecd072b0263ec0b8bf1e56ac57..5d21089e91d35b03ade0f5acc148bf001c9627ca 100644 (file)
@@ -40,15 +40,17 @@ void silc_server_notify(SilcServer server,
   SilcChannelID *channel_id = NULL, *channel_id2;
   SilcClientID *client_id, *client_id2;
   SilcServerID *server_id;
-  SilcChannelEntry channel;
-  SilcClientEntry client;
-  SilcServerEntry server_entry;
+  SilcIdType id_type;
+  SilcChannelEntry channel = NULL;
+  SilcClientEntry client = NULL, client2 = NULL;
+  SilcServerEntry server_entry = NULL;
   SilcChannelClientEntry chl;
   SilcIDCacheEntry cache;
   SilcHashTableList htl;
-  uint32 mode;
+  SilcUInt32 mode;
   unsigned char *tmp;
-  uint32 tmp_len;
+  SilcUInt32 tmp_len;
+  bool local;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -71,11 +73,13 @@ void silc_server_notify(SilcServer server,
     if (dst_sock)
       /* Relay the packet */
       silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_receive, packet, TRUE);
+                              idata->hmac_send, idata->psn_send++,
+                              packet, TRUE);
   }
 
   /* Parse the Notify Payload */
-  payload = silc_notify_payload_parse(packet->buffer);
+  payload = silc_notify_payload_parse(packet->buffer->data,
+                                     packet->buffer->len);
   if (!payload)
     return;
 
@@ -135,7 +139,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
@@ -156,7 +160,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -178,7 +182,7 @@ void silc_server_notify(SilcServer server,
        client = 
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
                                 silc_id_dup(client_id, SILC_ID_CLIENT), 
-                                sock->user_data, NULL);
+                                sock->user_data, NULL, 0);
        if (!client) {
          SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
          silc_free(client_id);
@@ -194,8 +198,10 @@ void silc_server_notify(SilcServer server,
       break;
 
     /* Do not add client to channel if it is there already */
-    if (silc_server_client_on_channel(client, channel))
+    if (silc_server_client_on_channel(client, channel, NULL)) {
+      SILC_LOG_DEBUG(("Client already on channel"));
       break;
+    }
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -207,6 +213,8 @@ void silc_server_notify(SilcServer server,
       /* The channel is global now */
       channel->global_users = TRUE;
 
+    SILC_LOG_DEBUG(("Joining to channel %s", channel->channel_name));
+
     /* JOIN the global client to the channel (local clients (if router 
        created the channel) is joined in the pending JOIN command). */
     chl = silc_calloc(1, sizeof(*chl));
@@ -221,6 +229,7 @@ void silc_server_notify(SilcServer server,
     silc_hash_table_add(channel->user_list, client, chl);
     silc_hash_table_add(client->channels, channel, chl);
     silc_free(client_id);
+    channel->user_count++;
 
     break;
 
@@ -255,7 +264,7 @@ void silc_server_notify(SilcServer server,
       silc_free(channel_id);
       goto out;
     }
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id) {
       silc_free(channel_id);
       goto out;
@@ -276,7 +285,7 @@ void silc_server_notify(SilcServer server,
     silc_free(client_id);
 
     /* Check if on channel */
-    if (!silc_server_client_on_channel(client, channel))
+    if (!silc_server_client_on_channel(client, channel, NULL))
       break;
 
     /* Send the leave notify to channel */
@@ -298,7 +307,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -320,14 +329,18 @@ void silc_server_notify(SilcServer server,
     if (tmp_len > 128)
       tmp = NULL;
 
+    /* Update statistics */
+    server->stat.clients--;
+    if (server->server_type == SILC_ROUTER)
+      server->stat.cell_clients--;
+    SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-    server->stat.clients--;
-    if (server->server_type == SILC_ROUTER)
-      server->stat.cell_clients--;
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -337,6 +350,34 @@ void silc_server_notify(SilcServer server,
 
     SILC_LOG_DEBUG(("TOPIC SET notify"));
 
+    /* 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, NULL);
+    if (!client_id)
+      goto out;
+
+    /* Get client entry */
+    client = silc_idlist_find_client_by_id(server->global_list, 
+                                          client_id, TRUE, &cache);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->local_list, 
+                                            client_id, TRUE, &cache);
+      if (!client) {
+       silc_free(client_id);
+       goto out;
+      }
+    }
+    silc_free(client_id);
+
+    /* Get the topic */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp) {
+      silc_free(channel_id);
+      goto out;
+    }
+
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -356,17 +397,21 @@ void silc_server_notify(SilcServer server,
       }
     }
 
-    /* Get the topic */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
+    if (channel->topic && !strcmp(channel->topic, tmp))
+      goto out;
+
+    /* Get user's channel entry and check that topic set is allowed. */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
+       channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+      SILC_LOG_DEBUG(("Topic change is not allowed"));
       goto out;
     }
 
-    if (channel->topic)
-      silc_free(channel->topic);
-    channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
-    memcpy(channel->topic, tmp, tmp_len);
+    /* Change the topic */
+    silc_free(channel->topic);
+    channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -388,7 +433,7 @@ void silc_server_notify(SilcServer server,
       id = silc_argument_get_arg_type(args, 1, &tmp_len);
       if (!id)
        goto out;
-      client_id = silc_id_payload_parse_id(id, tmp_len);
+      client_id = silc_id_payload_parse_id(id, tmp_len, NULL);
       if (!client_id)
        goto out;
       
@@ -396,7 +441,7 @@ void silc_server_notify(SilcServer server,
       id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
       if (!id2)
        goto out;
-      client_id2 = silc_id_payload_parse_id(id2, tmp_len);
+      client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
       if (!client_id2)
        goto out;
       
@@ -440,6 +485,29 @@ void silc_server_notify(SilcServer server,
     
     SILC_LOG_DEBUG(("CMODE CHANGE notify"));
       
+    /* 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, &id_type);
+    if (!client_id)
+      goto out;
+
+    /* Get client entry */
+    if (id_type == SILC_ID_CLIENT) {
+      client = silc_idlist_find_client_by_id(server->global_list, 
+                                            client_id, TRUE, &cache);
+      if (!client) {
+       client = silc_idlist_find_client_by_id(server->local_list, 
+                                              client_id, TRUE, &cache);
+       if (!client) {
+         silc_free(client_id);
+         goto out;
+       }
+      }
+      silc_free(client_id);
+    }
+
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -458,20 +526,28 @@ void silc_server_notify(SilcServer server,
        goto out;
       }
     }
+    silc_free(channel_id);
 
     /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
+    if (!tmp)
       goto out;
-    }
-
     SILC_GET32_MSB(mode, tmp);
 
     /* Check if mode changed */
     if (channel->mode == mode)
       break;
 
+    /* Get user's channel entry and check that mode change is allowed */
+    if (client) {
+      if (!silc_server_client_on_channel(client, channel, &chl))
+       goto out;
+      if (!silc_server_check_cmode_rights(server, channel, chl, mode)) {
+       SILC_LOG_DEBUG(("CMODE change is not allowed"));
+       goto out;
+      }
+    }
+
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
@@ -494,7 +570,6 @@ void silc_server_notify(SilcServer server,
 
     /* Change mode */
     channel->mode = mode;
-    silc_free(channel_id);
 
     /* Get the hmac */
     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
@@ -508,13 +583,21 @@ void silc_server_notify(SilcServer server,
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
 
+    /* Get the passphrase */
+    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+    if (tmp) {
+      silc_free(channel->passphrase);
+      channel->passphrase = strdup(tmp);
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -527,6 +610,29 @@ void silc_server_notify(SilcServer server,
       
       SILC_LOG_DEBUG(("CUMODE CHANGE notify"));
       
+      /* 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, &id_type);
+      if (!client_id)
+       goto out;
+
+      /* Get client entry */
+      if (id_type == SILC_ID_CLIENT) {
+       client = silc_idlist_find_client_by_id(server->global_list, 
+                                              client_id, TRUE, &cache);
+       if (!client) {
+         client = silc_idlist_find_client_by_id(server->local_list, 
+                                                client_id, TRUE, &cache);
+         if (!client) {
+           silc_free(client_id);
+           goto out;
+         }
+       }
+       silc_free(client_id);
+      }
+
       if (!channel_id) {
        channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                    packet->dst_id_type);
@@ -559,23 +665,47 @@ void silc_server_notify(SilcServer server,
       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
       if (!tmp)
        goto out;
-      client_id = silc_id_payload_parse_id(tmp, tmp_len);
+      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
       if (!client_id)
        goto out;
       
       /* Get client entry */
-      client = silc_idlist_find_client_by_id(server->global_list, 
-                                            client_id, TRUE, NULL);
-      if (!client) {
-       client = silc_idlist_find_client_by_id(server->local_list, 
-                                              client_id, TRUE, NULL);
-       if (!client) {
+      client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                             client_id, TRUE, NULL);
+      if (!client2) {
+       client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
          silc_free(client_id);
          goto out;
        }
       }
       silc_free(client_id);
 
+      if (client) {
+       /* Check that sender is on channel */
+       if (!silc_server_client_on_channel(client, channel, &chl))
+         goto out;
+       
+       if (client != client2) {
+         /* Sender must be operator */
+         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
+           goto out;
+         }
+
+         /* Check that target is on channel */
+         if (!silc_server_client_on_channel(client2, channel, &chl))
+           goto out;
+
+         /* If target is founder mode change is not allowed. */
+         if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
+           goto out;
+         }
+       }
+      }
+
       /* Get entry to the channel user list */
       silc_hash_table_list(channel->user_list, &htl);
       while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
@@ -596,10 +726,10 @@ void silc_server_notify(SilcServer server,
 
          mode &= ~SILC_CHANNEL_UMODE_CHANFO;
          silc_server_send_notify_cumode(server, sock, FALSE, channel, mode,
-                                        client->id, SILC_ID_CLIENT,
-                                        client->id);
+                                        client2->id, SILC_ID_CLIENT,
+                                        client2->id);
          
-         idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+         idp = silc_id_payload_encode(client2->id, SILC_ID_CLIENT);
          SILC_PUT32_MSB(mode, cumode);
          silc_server_send_notify_to_channel(server, sock, channel, FALSE, 
                                             SILC_NOTIFY_TYPE_CUMODE_CHANGE,
@@ -613,16 +743,19 @@ void silc_server_notify(SilcServer server,
          if (chl2) {
            chl2->mode = mode;
            silc_free(channel_id);
+           silc_hash_table_list_reset(&htl);
            goto out;
          }
        }
        
-       if (chl->client == client) {
+       if (chl->client == client2) {
          if (chl->mode == mode) {
            notify_sent = TRUE;
            break;
          }
 
+         SILC_LOG_DEBUG(("Changing the channel user mode"));
+
          /* Change the mode */
          chl->mode = mode;
          if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
@@ -631,6 +764,7 @@ void silc_server_notify(SilcServer server,
          chl2 = chl;
        }
       }
+      silc_hash_table_list_reset(&htl);
       
       /* Send the same notify to the channel */
       if (!notify_sent)
@@ -654,7 +788,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
@@ -671,8 +805,38 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(channel_id);
 
-    /* Get the added invite */
+    /* Get client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (!tmp)
+      goto out;
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+    if (!client_id)
+      goto out;
+
+    /* Get client entry */
+    client = silc_idlist_find_client_by_id(server->global_list, 
+                                          client_id, TRUE, &cache);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->local_list, 
+                                            client_id, TRUE, &cache);
+      if (!client) {
+       silc_free(client_id);
+       goto out;
+      }
+    }
+    silc_free(client_id);
+
+    /* Get user's channel entry and check that inviting is allowed. */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
+       channel->mode & SILC_CHANNEL_MODE_INVITE) {
+      SILC_LOG_DEBUG(("Inviting is not allowed"));
+      goto out;
+    }
+
+    /* Get the added invite */
+    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
     if (tmp) {
       if (!channel->invite_list)
        channel->invite_list = silc_calloc(tmp_len + 2, 
@@ -691,7 +855,7 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get the deleted invite */
-    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
     if (tmp && channel->invite_list) {
       char *start, *end, *n;
       
@@ -730,15 +894,15 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
     /* Get the channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->local_list, 
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->global_list, 
                                               channel_id, NULL);
       if (!channel) {
        silc_free(channel_id);
@@ -755,7 +919,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id2 = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id2 = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id2)
       goto out;
 
@@ -765,9 +929,9 @@ void silc_server_notify(SilcServer server,
                    silc_id_render(channel_id2, SILC_ID_CHANNEL)));
 
     /* Replace the Channel ID */
-    if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
+    if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
                                        channel_id2))
-      if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+      if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
                                          channel_id2)) {
        silc_free(channel_id2);
        channel_id2 = NULL;
@@ -775,7 +939,14 @@ void silc_server_notify(SilcServer server,
 
     if (channel_id2) {
       SilcBuffer users = NULL, users_modes = NULL;
-      
+
+      /* Re-announce this channel which ID was changed. */
+      silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
+                                  channel->id, 
+                                  silc_id_get_len(channel->id, 
+                                                  SILC_ID_CHANNEL),
+                                  channel->mode);
+
       /* Re-announce our clients on the channel as the ID has changed now */
       silc_server_announce_get_channel_users(server, channel, &users,
                                             &users_modes);
@@ -795,6 +966,15 @@ void silc_server_notify(SilcServer server,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
+
+      /* Re-announce channel's topic */
+      if (channel->topic) {
+       silc_server_send_notify_topic_set(server, sock,
+                                         server->server_type == SILC_ROUTER ?
+                                         TRUE : FALSE, channel, 
+                                         channel->id, SILC_ID_CHANNEL,
+                                         channel->topic);
+      }
     }
 
     silc_free(channel_id);
@@ -812,17 +992,68 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    server_id = silc_id_payload_parse_id(tmp, tmp_len);
+    server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!server_id)
       goto out;
 
     /* Get server entry */
     server_entry = silc_idlist_find_server_by_id(server->global_list, 
                                                 server_id, TRUE, NULL);
+    local = TRUE;
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->local_list, 
                                                   server_id, TRUE, NULL);
+      local = TRUE;
       if (!server_entry) {
+       /* If we are normal server then we might not have the server. Check
+          whether router was kind enough to send the list of all clients
+          that actually was to be removed. Remove them if the list is
+          available. */
+       if (server->server_type != SILC_ROUTER &&
+           silc_argument_get_arg_num(args) > 1) {
+         int i;
+
+         for (i = 1; i < silc_argument_get_arg_num(args); i++) {
+           /* Get Client ID */
+           tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
+           if (!tmp)
+             continue;
+           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+           if (!client_id)
+             continue;
+
+           /* Get client entry */
+           client = silc_idlist_find_client_by_id(server->global_list, 
+                                                  client_id, TRUE, &cache);
+           local = TRUE;
+           if (!client) {
+             client = silc_idlist_find_client_by_id(server->local_list, 
+                                                    client_id, TRUE, &cache);
+             local = FALSE;
+             if (!client) {
+               silc_free(client_id);
+               continue;
+             }
+           }
+           silc_free(client_id);
+
+           /* Update statistics */
+           server->stat.clients--;
+           if (server->server_type == SILC_ROUTER)
+             server->stat.cell_clients--;
+           SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+           SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+           /* Remove the client from all channels. */
+           silc_server_remove_from_channels(server, NULL, client, 
+                                            TRUE, NULL, FALSE);
+
+           /* Remove the client */
+           silc_idlist_del_client(local ? server->local_list :
+                                  server->global_list, client);
+         }
+       }
+
        silc_free(server_id);
        goto out;
       }
@@ -834,8 +1065,8 @@ void silc_server_notify(SilcServer server,
     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);
+    silc_idlist_del_server(local ? server->local_list :
+                          server->global_list, server_entry);
 
     /* XXX update statistics */
 
@@ -872,7 +1103,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -887,6 +1118,43 @@ void silc_server_notify(SilcServer server,
        goto out;
       }
     }
+    silc_free(client_id);
+
+    /* If target is founder they cannot be kicked */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
+      goto out;
+    
+    /* Get kicker. In protocol version 1.0 this is not mandatory argument
+       so we check it only if it is provided. */
+    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (tmp) {
+      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+      if (!client_id)
+       goto out;
+
+      /* If the the client is not in local list we check global list */
+      client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                             client_id, TRUE, NULL);
+      if (!client2) {
+       client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
+         silc_free(client_id);
+         goto out;
+       }
+      }
+      silc_free(client_id);
+
+      /* Kicker must be operator on channel */
+      if (!silc_server_client_on_channel(client2, channel, &chl))
+       goto out;
+      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+       SILC_LOG_DEBUG(("Kicking is not allowed"));
+       goto out;
+      }
+    }
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -904,7 +1172,7 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on channels
        */
       unsigned char *id;
-      uint32 id_len;
+      SilcUInt32 id_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -912,7 +1180,7 @@ void silc_server_notify(SilcServer server,
       id = silc_argument_get_arg_type(args, 1, &id_len);
       if (!id)
        goto out;
-      client_id = silc_id_payload_parse_id(id, id_len);
+      client_id = silc_id_payload_parse_id(id, id_len, NULL);
       if (!client_id)
        goto out;
 
@@ -964,12 +1232,12 @@ void silc_server_notify(SilcServer server,
      */
 
     SILC_LOG_DEBUG(("UMODE_CHANGE notify"));
-      
+
     /* 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);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -990,9 +1258,16 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
+    SILC_GET32_MSB(mode, tmp);
 
-    /* Save the mode */
-    SILC_GET32_MSB(client->mode, tmp);
+    /* Check that mode changing is allowed. */
+    if (!silc_server_check_umode_rights(server, client, mode)) {
+      SILC_LOG_DEBUG(("UMODE change is not allowed"));
+      goto out;
+    }
+
+    /* Change the mode */
+    client->mode = mode;
 
     break;
 
@@ -1007,7 +1282,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
     
@@ -1044,7 +1319,7 @@ void silc_server_notify(SilcServer server,
     if (tmp && channel->ban_list) {
       char *start, *end, *n;
       
-      if (!strcmp(channel->ban_list, tmp)) {
+      if (!strncmp(channel->ban_list, tmp, strlen(channel->ban_list) - 1)) {
        silc_free(channel->ban_list);
        channel->ban_list = NULL;
       } else {
@@ -1060,7 +1335,6 @@ void silc_server_notify(SilcServer server,
        }
       }
     }
-
     break;
 
     /* Ignore rest of the notify types for now */
@@ -1081,7 +1355,7 @@ void silc_server_notify_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  uint16 len;
+  SilcUInt16 len;
 
   SILC_LOG_DEBUG(("Processing Notify List"));
 
@@ -1144,21 +1418,45 @@ void silc_server_private_message(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
-      packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  if (!packet->dst_id)
+      packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id)
     return;
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
                                          packet->dst_id_len, NULL, &idata);
-  if (!dst_sock)
+  if (!dst_sock) {
+    /* Send IDENTIFY command reply with error status to indicate that
+       such destination ID does not exist or is invalid */
+    SilcBuffer idp = silc_id_payload_encode_data(packet->dst_id,
+                                                packet->dst_id_len,
+                                                packet->dst_id_type);
+    if (!idp)
+      return;
+
+    if (packet->src_id_type == SILC_ID_CLIENT) {
+      SilcClientID *client_id = silc_id_str2id(packet->src_id,
+                                              packet->src_id_len,
+                                              packet->src_id_type);
+      silc_server_send_dest_command_reply(server, sock, 
+                                         client_id, SILC_ID_CLIENT,
+                                         SILC_COMMAND_IDENTIFY,
+                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
+                                         0, 1, 2, idp->data, idp->len);
+      silc_free(client_id);
+    } else {
+      silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
+                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
+                                    0, 1, 2, idp->data, idp->len);
+    }
+
+    silc_buffer_free(idp);
     return;
+  }
 
   /* Send the private message */
   silc_server_send_private_message(server, dst_sock, idata->send_key,
-                                  idata->hmac_send, packet);
+                                  idata->hmac_send, idata->psn_send++,
+                                  packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -1190,7 +1488,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++, packet, FALSE);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -1232,7 +1530,7 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_SERVER) {
     /* For now this must be for us */
-    if (memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+    if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
       return;
     }
@@ -1243,19 +1541,23 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
     /* Relay the packet to the client */
+    const SilcBufferStruct p;
     
     dst_sock = (SilcSocketConnection)client->connection;
+    idata = (SilcIDListData)client;
+    
     silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                     + packet->dst_id_len + packet->padlen);
-    
-    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
-    idata = (SilcIDListData)client;
+    if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len,
+                                  idata->hmac_send, (const SilcBuffer)&p)) {
+      SILC_LOG_ERROR(("Cannot send packet"));
+      return;
+    }
+    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
     
     /* Encrypt packet */
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf, 
-                       buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+                       (SilcBuffer)&p, buffer->len);
     
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, TRUE);
@@ -1273,8 +1575,9 @@ void silc_server_channel_message(SilcServer server,
 {
   SilcChannelEntry channel = NULL;
   SilcChannelID *id = NULL;
-  void *sender = NULL;
-  void *sender_entry = NULL;
+  void *sender_id = NULL;
+  SilcClientEntry sender_entry = NULL;
+  bool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
@@ -1299,35 +1602,45 @@ void silc_server_channel_message(SilcServer server,
 
   /* See that this client is on the channel. If the original sender is
      not client (as it can be server as well) we don't do the check. */
-  sender = silc_id_str2id(packet->src_id, packet->src_id_len, 
-                         packet->src_id_type);
-  if (!sender)
+  sender_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
+                            packet->src_id_type);
+  if (!sender_id)
     goto out;
   if (packet->src_id_type == SILC_ID_CLIENT) {
     sender_entry = silc_idlist_find_client_by_id(server->local_list, 
-                                                sender, TRUE, NULL);
-    if (!sender_entry)
+                                                sender_id, TRUE, NULL);
+    if (!sender_entry) {
+      local = FALSE;
       sender_entry = silc_idlist_find_client_by_id(server->global_list, 
-                                                  sender, TRUE, NULL);
+                                                  sender_id, TRUE, NULL);
+    }
     if (!sender_entry || !silc_server_client_on_channel(sender_entry, 
-                                                       channel)) {
+                                                       channel, NULL)) {
       SILC_LOG_DEBUG(("Client not on channel"));
       goto out;
     }
+
+    /* If the packet is coming from router, but the client entry is local 
+       entry to us then some router is rerouting this to us and it is not 
+       allowed. When the client is local to us it means that we've routed
+       this packet to network, and now someone is routing it back to us. */
+    if (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER && local) {
+      SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
+      goto out;
+    }
   }
 
   /* 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,
+  silc_server_packet_relay_to_channel(server, sock, channel, sender_id,
                                      packet->src_id_type, sender_entry,
                                      packet->buffer->data,
                                      packet->buffer->len, FALSE);
 
  out:
-  if (sender)
-    silc_free(sender);
-  if (id)
-    silc_free(id);
+  silc_free(sender_id);
+  silc_free(id);
 }
 
 /* Received channel key packet. We distribute the key to all of our locally
@@ -1375,7 +1688,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcBuffer reply;
   SilcIDListData idata;
   char *username = NULL, *realname = NULL, *id_string;
-  uint32 id_len;
+  SilcUInt16 username_len;
+  SilcUInt32 id_len;
   int ret;
   char *hostname, *nickname;
   int nickfail = 0;
@@ -1389,24 +1703,25 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   client = (SilcClientEntry)sock->user_data;
   idata = (SilcIDListData)client;
 
-  /* Remove the old cache entry */
+  /* Remove the old cache entry. */
   if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
-    SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+    SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                  "Unknown client");
+                                  "You have not been authenticated");
     return NULL;
   }
 
   /* Parse incoming packet */
   ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI16_STRING_ALLOC(&username),
+                            SILC_STR_UI16_NSTRING_ALLOC(&username, 
+                                                        &username_len),
                             SILC_STR_UI16_STRING_ALLOC(&realname),
                             SILC_STR_END);
   if (ret == -1) {
-    if (username)
-      silc_free(username);
-    if (realname)
-      silc_free(realname);
+    silc_free(username);
+    silc_free(realname);
+    SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                   "connection", sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
@@ -1414,17 +1729,24 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   if (!username) {
     silc_free(username);
-    if (realname)
-      silc_free(realname);
+    silc_free(realname);
+    SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
+                   "connection", sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
   }
 
-  if (strlen(username) > 128)
-    username[127] = '\0';
+  if (username_len > 128)
+    username[128] = '\0';
 
-  nickname = strdup(username);
+  /* Check for bad characters for nickname, and modify the nickname if
+     it includes those. */
+  if (silc_server_name_bad_chars(username, username_len)) {
+    nickname = silc_server_name_modify_bad(username, username_len);
+  } else {
+    nickname = strdup(username);
+  }
 
   /* Make sanity checks for the hostname of the client. If the hostname
      is provided in the `username' check that it is the same than the
@@ -1436,15 +1758,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     int tlen = strcspn(username, "@");
     char *phostname = NULL;
 
-    hostname = silc_calloc((strlen(username) - tlen) + 1, sizeof(char));
-    memcpy(hostname, username + tlen + 1, strlen(username) - tlen - 1);
+    hostname = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
     if (strcmp(sock->hostname, sock->ip) && 
        strcmp(sock->hostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (realname)
-       silc_free(realname);
+      silc_free(realname);
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                     "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
@@ -1461,18 +1783,17 @@ SilcClientEntry silc_server_new_client(SilcServer server,
        phostname && strcmp(phostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (phostname)
-       silc_free(phostname);
-      if (realname)
-       silc_free(realname);
+      silc_free(phostname);
+      silc_free(realname);
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                     "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
       return NULL;
     }
     
-    if (phostname)
-      silc_free(phostname);
+    silc_free(phostname);
   } else {
     /* The hostname is not present, add it. */
     char *newusername;
@@ -1527,7 +1848,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Add the client again to the ID cache */
   silc_idcache_add(server->local_list->clients, client->nickname,
-                  client_id, client, FALSE);
+                  client_id, client, 0, NULL);
 
   /* Notify our router about new client on the SILC network */
   if (!server->standalone)
@@ -1556,8 +1877,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                           username));
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your host is %s, running version %s",
-                          server->config->server_info->server_name,
-                          server_version));
+                          server->server_name, server_version));
   if (server->server_type == SILC_ROUTER) {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients on %d servers in SILC "
@@ -1575,10 +1895,14 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                             server->stat.my_servers,
                             server->stat.my_routers));
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("%d server operators and %d router operators "
-                            "online",
-                            server->stat.my_server_ops,
-                            server->stat.my_router_ops));
+                           ("There are %d server operators and %d router "
+                            "operators online",
+                            server->stat.server_ops,
+                            server->stat.router_ops));
+    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                           ("I have %d operators online",
+                            server->stat.my_router_ops +
+                            server->stat.my_server_ops));
   } else {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("I have %d clients and %d channels formed",
@@ -1616,12 +1940,13 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                       SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcServerEntry new_server;
+  SilcServerEntry new_server, server_entry;
   SilcServerID *server_id;
   SilcIDListData idata;
   unsigned char *server_name, *id_string;
-  uint16 id_len, name_len;
+  SilcUInt16 id_len, name_len;
   int ret;
+  bool local = TRUE;
 
   SILC_LOG_DEBUG(("Creating new server"));
 
@@ -1634,7 +1959,18 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   idata = (SilcIDListData)new_server;
 
   /* Remove the old cache entry */
-  silc_idcache_del_by_context(server->local_list->servers, new_server);
+  if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
+    if (!silc_idcache_del_by_context(server->global_list->servers, 
+                                    new_server)) {
+      SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
+                    "network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
+                                "server" : "router")));
+      silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                   "You have not been authenticated");
+      return NULL;
+    }
+    local = FALSE;
+  }
 
   /* Parse the incoming packet */
   ret = silc_buffer_unformat(buffer,
@@ -1668,14 +2004,40 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   }
   silc_free(id_string);
 
+  /* Check for valid server ID */
+  if (!silc_id_is_valid_server_id(server, server_id, sock)) {
+    SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
+                  sock->ip, sock->hostname));
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Your Server ID is not valid");
+    silc_free(server_name);
+    return NULL;
+  }
+
+  /* Check that we do not have this ID already */
+  server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                              server_id, TRUE, NULL);
+  if (server_entry) {
+    silc_idcache_del_by_context(server->local_list->servers, server_entry);
+  } else {
+    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                server_id, TRUE, NULL);
+    if (server_entry) 
+      silc_idcache_del_by_context(server->global_list->servers, server_entry);
+  }
+
   /* Update server entry */
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   new_server->server_name = server_name;
   new_server->id = server_id;
+  
+  SILC_LOG_DEBUG(("New server id(%s)",
+                 silc_id_render(server_id, SILC_ID_SERVER)));
 
   /* Add again the entry to the ID cache. */
-  silc_idcache_add(server->local_list->servers, server_name, server_id, 
-                  new_server, FALSE);
+  silc_idcache_add(local ? server->local_list->servers : 
+                  server->global_list->servers, server_name, server_id, 
+                  new_server, 0, NULL);
 
   /* Distribute the information about new server in the SILC network
      to our router. If we are normal server we won't send anything
@@ -1708,9 +2070,17 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                            packet->data, packet->len, TRUE);
     silc_buffer_free(packet);
 
-    /* Mark the server disabled. The data sent earlier will go but nothing
+    /* Mark the router disabled. The data sent earlier will go but nothing
        after this does not go to this connection. */
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
+  } else {
+    /* If it is router announce our stuff to it. */
+    if (sock->type == SILC_SOCKET_TYPE_ROUTER && 
+       server->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, FALSE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
   }
 
   return new_server;
@@ -1726,7 +2096,7 @@ static void silc_server_new_id_real(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer;
   SilcIDList id_list;
-  SilcServerEntry router;
+  SilcServerEntry router, server_entry;
   SilcSocketConnection router_sock;
   SilcIDPayload idp;
   SilcIdType id_type;
@@ -1739,31 +2109,38 @@ static void silc_server_new_id_real(SilcServer server,
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  idp = silc_id_payload_parse(buffer);
+  idp = silc_id_payload_parse(buffer->data, buffer->len);
   if (!idp)
     return;
 
   id_type = silc_id_payload_get_type(idp);
 
   /* Normal server cannot have other normal server connections */
-  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
+  server_entry = (SilcServerEntry)sock->user_data;
+  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER &&
+      server_entry->server_type == SILC_SERVER)
     goto out;
 
   id = silc_id_payload_get_id(idp);
   if (!id)
     goto out;
 
-  if (sock->type == SILC_SOCKET_TYPE_SERVER)
-    id_list = server->local_list;
-  else
-    id_list = server->global_list;
-
   /* 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) {
+    id_list = server->local_list;
     router_sock = sock;
     router = sock->user_data;
+
+    /* If the sender is backup router and ID is server (and we are not
+       backup router) then switch the entry to global list. */
+    if (server_entry->server_type == SILC_BACKUP_ROUTER && 
+       id_type == SILC_ID_SERVER && 
+       server->id_entry->server_type != SILC_BACKUP_ROUTER) {
+      id_list = server->global_list;
+      router_sock = server->router ? server->router->connection : sock;
+    }
   } else {
     void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                                     packet->src_id_type);
@@ -1773,11 +2150,13 @@ static void silc_server_new_id_real(SilcServer server,
       router = silc_idlist_find_server_by_id(server->local_list,
                                             sender_id, TRUE, NULL);
     silc_free(sender_id);
-    if (!router)
-      goto out;
     router_sock = sock;
+    id_list = server->global_list;
   }
 
+  if (!router)
+    goto out;
+
   switch(id_type) {
   case SILC_ID_CLIENT:
     {
@@ -1805,7 +2184,7 @@ static void silc_server_new_id_real(SilcServer server,
         global list. Cell wide information however is kept in the local
         list. */
       entry = silc_idlist_add_client(id_list, NULL, NULL, NULL, 
-                                    id, router, NULL);
+                                    id, router, NULL, 0);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
 
@@ -1921,7 +2300,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
 {
   SilcPacketContext *new_id;
   SilcBuffer idp;
-  uint16 id_len;
+  SilcUInt16 id_len;
 
   SILC_LOG_DEBUG(("Processing New ID List"));
 
@@ -1993,10 +2372,10 @@ void silc_server_new_channel(SilcServer server,
   SilcChannelPayload payload;
   SilcChannelID *channel_id;
   char *channel_name;
-  uint32 name_len;
+  SilcUInt32 name_len;
   unsigned char *id;
-  uint32 id_len;
-  uint32 mode;
+  SilcUInt32 id_len;
+  SilcUInt32 mode;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
 
@@ -2008,7 +2387,8 @@ void silc_server_new_channel(SilcServer server,
     return;
 
   /* Parse the channel payload */
-  payload = silc_channel_payload_parse(packet->buffer);
+  payload = silc_channel_payload_parse(packet->buffer->data,
+                                      packet->buffer->len);
   if (!payload)
     return;
     
@@ -2043,7 +2423,7 @@ void silc_server_new_channel(SilcServer server,
                      sock->hostname));
     
       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
-                             0, channel_id, sock->user_data, NULL, NULL);
+                             0, channel_id, sock->user_data, NULL, NULL, 0);
       server->stat.channels++;
     }
   } else {
@@ -2096,6 +2476,8 @@ void silc_server_new_channel(SilcServer server,
       channel->mode = silc_channel_get_mode(payload);
 
       /* Send the new channel key to the server */
+      id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+      id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
       chk = silc_channel_key_payload_encode(id_len, id,
                                            strlen(channel->channel_key->
                                                   cipher->name),
@@ -2112,9 +2494,6 @@ void silc_server_new_channel(SilcServer server,
         We also create a new key for the channel. */
       SilcBuffer users = NULL, users_modes = 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
           force the ID change. */
@@ -2131,7 +2510,8 @@ void silc_server_new_channel(SilcServer server,
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                      channel->mode, server->id,
                                      SILC_ID_SERVER,
-                                     channel->cipher, channel->hmac_name);
+                                     channel->cipher, channel->hmac_name,
+                                     channel->passphrase);
       }
 
       /* Create new key for the channel and send it to the server and
@@ -2144,8 +2524,8 @@ void silc_server_new_channel(SilcServer server,
        /* 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;
-       
+       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
        /* Send to the server */
        chk = silc_channel_key_payload_encode(id_len, id,
                                              strlen(channel->channel_key->
@@ -2198,7 +2578,7 @@ void silc_server_new_channel_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  uint16 len1, len2;
+  SilcUInt16 len1, len2;
 
   SILC_LOG_DEBUG(("Processing New Channel List"));
 
@@ -2293,7 +2673,8 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++,
+                          packet, FALSE);
 }
 
 /* Received connection auth request packet that is used during connection
@@ -2308,10 +2689,10 @@ void silc_server_connection_auth_request(SilcServer server,
                                         SilcSocketConnection sock,
                                         SilcPacketContext *packet)
 {
-  SilcServerConfigSectionClientConnection *client = NULL;
-  uint16 conn_type;
-  int ret, port;
-  SilcAuthMethod auth_meth;
+  SilcServerConfigClient *client = NULL;
+  SilcUInt16 conn_type;
+  int ret;
+  SilcAuthMethod auth_meth = SILC_AUTH_NONE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2331,21 +2712,21 @@ void silc_server_connection_auth_request(SilcServer server,
 
   /* Get the authentication method for the client */
   auth_meth = SILC_AUTH_NONE;
-  port = server->sockets[server->sock]->port; /* Listenning port */
-  client = silc_server_config_find_client_conn(server->config,
-                                              sock->ip,
-                                              port);
+  client = silc_server_config_find_client(server, sock->ip);
   if (!client)
-    client = silc_server_config_find_client_conn(server->config,
-                                                sock->hostname,
-                                                port);
-  if (client)
-    auth_meth = client->auth_meth;
-         
+    client = silc_server_config_find_client(server, sock->hostname);
+  if (client) {
+    if (client->passphrase) {
+      if (client->publickeys && !server->config->prefer_passphrase_auth)
+       auth_meth = SILC_AUTH_PUBLIC_KEY;
+      else
+       auth_meth = SILC_AUTH_PASSWORD;
+    } else if (client->publickeys)
+      auth_meth = SILC_AUTH_PUBLIC_KEY;
+  }
+
   /* Send it back to the client */
-  silc_server_send_connection_auth_request(server, sock,
-                                          conn_type,
-                                          auth_meth);
+  silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
 }
 
 /* Received REKEY packet. The sender of the packet wants to regenerate
@@ -2379,3 +2760,36 @@ void silc_server_rekey(SilcServer server,
     /* Run the protocol */
     silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
+
+/* Received file transger packet. This packet is never for us. It is to
+   the client in the packet's destination ID. Sending of this sort of packet
+   equals sending private message, ie. it is sent point to point from
+   one client to another. */
+
+void silc_server_ftp(SilcServer server,
+                    SilcSocketConnection sock,
+                    SilcPacketContext *packet)
+{
+  SilcSocketConnection dst_sock;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (packet->src_id_type != SILC_ID_CLIENT ||
+      packet->dst_id_type != SILC_ID_CLIENT)
+    return;
+
+  if (!packet->dst_id)
+    return;
+
+  /* Get the route to the client */
+  dst_sock = silc_server_get_client_route(server, packet->dst_id,
+                                         packet->dst_id_len, NULL, &idata);
+  if (!dst_sock)
+    return;
+
+  /* Relay the packet */
+  silc_server_relay_packet(server, dst_sock, idata->send_key,
+                          idata->hmac_send, idata->psn_send++,
+                          packet, FALSE);
+}