updates.
[silc.git] / apps / silcd / server.c
index 05323399eda32a43a8612d13898fbf6f42f15bef..86b0a3dc048bb11b5ff537dd8cbbd69855c388d9 100644 (file)
@@ -111,7 +111,7 @@ void silc_server_free(SilcServer server)
 
 int silc_server_init(SilcServer server)
 {
-  int *sock = NULL, sock_count = 0, i;
+  int *sock = NULL, sock_count, i;
   SilcServerID *id;
   SilcServerEntry id_entry;
   SilcIDListPurge purge;
@@ -181,10 +181,15 @@ int silc_server_init(SilcServer server)
 
     tmp = silc_net_create_server(server->config->listen_port->port,
                                 server->config->listen_port->listener_ip);
-    if (tmp < 0)
+
+    if (tmp < 0) {
+      SILC_LOG_ERROR(("Could not create server listener: %s on %d",
+                     server->config->listen_port->listener_ip,
+                     server->config->listen_port->port));
       goto err0;
+    }
 
-    sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+    sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1));
     sock[sock_count] = tmp;
     sock_count++;
     listen = listen->next;
@@ -218,11 +223,32 @@ int silc_server_init(SilcServer server)
     silc_net_set_socket_nonblock(sock[i]);
     server->sock = sock[i];
     
+    /* Add ourselves also to the socket table. The entry allocated above
+       is sent as argument for fast referencing in the future. */
+    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    server->sockets[sock[i]] = newsocket;
+    
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
+                                     &newsocket->ip)) {
+      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+         !newsocket->ip) {
+       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                       newsocket->hostname ? newsocket->hostname :
+                       newsocket->ip ? newsocket->ip : ""));
+       server->stat.conn_failures++;
+       goto err0;
+      }
+      if (!newsocket->hostname)
+       newsocket->hostname = strdup(newsocket->ip);
+    }
+    newsocket->port = silc_net_get_local_port(sock[i]);
+
     /* Create a Server ID for the server. */
-    silc_id_create_server_id(sock[i], server->rng, &id);
-    if (!id) {
+    silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+    if (!id)
       goto err0;
-    }
     
     server->id = id;
     server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
@@ -244,33 +270,10 @@ int silc_server_init(SilcServer server)
     }
     id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     
-    /* Add ourselves also to the socket table. The entry allocated above
-       is sent as argument for fast referencing in the future. */
-    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry, 
-                     &newsocket);
-
-    server->sockets[sock[i]] = newsocket;
-    
-    /* Perform name and address lookups to resolve the listenning address
-       and port. */
-    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
-                                    &newsocket->ip)) {
-      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
-         !newsocket->ip) {
-       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
-                       newsocket->hostname ? newsocket->hostname :
-                       newsocket->ip ? newsocket->ip : ""));
-       server->stat.conn_failures++;
-       goto err0;
-      }
-      if (!newsocket->hostname)
-       newsocket->hostname = strdup(newsocket->ip);
-    }
-    newsocket->port = silc_net_get_local_port(sock[i]);
-
     /* Put the allocated socket pointer also to the entry allocated above 
        for fast back-referencing to the socket list. */
-    id_entry->connection = (void *)server->sockets[sock[i]];
+    newsocket->user_data = (void *)id_entry;
+    id_entry->connection = (void *)newsocket;
     server->id_entry = id_entry;
   }
 
@@ -312,6 +315,7 @@ int silc_server_init(SilcServer server)
       if (ptr->backup_router) {
        server->server_type = SILC_BACKUP_ROUTER;
        server->backup_router = TRUE;
+       server->id_entry->server_type = SILC_BACKUP_ROUTER;
        break;
       }
       ptr = ptr->next;
@@ -351,19 +355,42 @@ int silc_server_init(SilcServer server)
   return FALSE;
 }
 
-/* Fork server to background and set gid+uid to non-root.
-   Silcd will not run as root, so trying to set either user or group to
-   root will cause silcd to exit. */
+/* Fork server to background and set gid+uid to non-root */
 
 void silc_server_daemonise(SilcServer server)
+{
+  int i;
+
+  i = fork ();
+
+  if (i) {
+    if (i > 0) {
+      if (geteuid())
+        SILC_LOG_DEBUG(("Server started as user"));
+      else
+        SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+
+      SILC_LOG_DEBUG(("Forking SILC server to background"));
+      exit(0);
+    } else {
+      SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+      exit(1);
+    }
+  }
+  setsid();
+}
+
+/* Drop root privligies. If this cannot be done, die. */
+
+void silc_server_drop(SilcServer server)
 {
   /* Are we executing silcd as root or a regular user? */
-  if (geteuid()==0) {
-    
+  if (!geteuid()) {
+
     struct passwd *pw;
     struct group *gr;
     char *user, *group;
-    
+
     if (!server->config->identity || !server->config->identity->user || 
        !server->config->identity->group) {
       fprintf(stderr, "Error:"
@@ -373,11 +400,11 @@ void silc_server_daemonise(SilcServer server)
        "\tthe server as non-root user.\n");
       exit(1);
     }
-    
+
     /* Get the values given for user and group in configuration file */
     user=server->config->identity->user;
     group=server->config->identity->group;
-    
+
     /* Check whether the user/group information is text */ 
     if (atoi(user)!=0 || atoi(group)!=0) {
       SILC_LOG_DEBUG(("Invalid user and/or group information"));
@@ -386,27 +413,24 @@ void silc_server_daemonise(SilcServer server)
       fprintf(stderr, "Please assign them as names, not numbers\n");
       exit(1);
     }
-    
+
     /* Catch the nasty incident of string "0" returning 0 from atoi */
     if (strcmp("0", user)==0 || strcmp("0", group)==0) {
       SILC_LOG_DEBUG(("User and/or group configured to 0. Unacceptable"));
       fprintf(stderr, "User and/or group configured to 0. Exiting\n");
       exit(1);
     }
-    
-    pw=getpwnam(user);
-    gr=getgrnam(group);
 
-    if (!pw) {
+    if (!(pw=getpwnam(user))) {
       fprintf(stderr, "No such user %s found\n", user);
       exit(1);
     }
 
-    if (!gr) {
+    if (!(gr=getgrnam(group))) {
       fprintf(stderr, "No such group %s found\n", group);
       exit(1);
     }
-    
+
     /* Check whether user and/or group is set to root. If yes, exit
        immediately. Otherwise, setgid and setuid server to user.group */
     if (gr->gr_gid==0 || pw->pw_uid==0) {
@@ -417,16 +441,8 @@ void silc_server_daemonise(SilcServer server)
        "\tthe server as non-root user.\n");
       exit(1);
     } else {
-      /* Fork server to background, making it a daemon */
-      if (fork()) {
-        SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
-        SILC_LOG_DEBUG(("Forking SILC server to background"));
-        exit(0);
-      } 
-      setsid();
-      
       SILC_LOG_DEBUG(("Changing to group %s", group));
-      if(setgid(gr->gr_gid)==0) {
+      if (setgid(gr->gr_gid)==0) {
         SILC_LOG_DEBUG(("Setgid to %s", group));
       } else {
         SILC_LOG_DEBUG(("Setgid to %s failed", group));
@@ -434,8 +450,21 @@ void silc_server_daemonise(SilcServer server)
                 group);
         exit(1);
       }
-      SILC_LOG_DEBUG(("Changing to user nobody"));
-      if(setuid(pw->pw_uid)==0) {
+#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
+      if (setgroups(0, NULL)!=0) {
+        SILC_LOG_DEBUG(("Setgroups to NULL failed"));
+        fprintf(stderr, "Tried to setgroups NULL but failed. Exiting\n");
+        exit(1);
+      }
+      if (initgroups(user, gr->gr_gid)!=0) {
+        SILC_LOG_DEBUG(("Initgroups to user %s (gid=%d) failed", user, gr->gr_gid));
+        fprintf(stderr, "Tried to initgroups %s (gid=%d) but no such user. Exiting\n",
+                user, gr->gr_gid);
+        exit(1);
+      }
+#endif
+      SILC_LOG_DEBUG(("Changing to user %s", user));
+      if (setuid(pw->pw_uid)==0) {
         SILC_LOG_DEBUG(("Setuid to %s", user));
       } else {
         SILC_LOG_DEBUG(("Setuid to %s failed", user));
@@ -444,14 +473,6 @@ void silc_server_daemonise(SilcServer server)
         exit(1);
       }
     }
-  } else {
-    /* Fork server to background, making it a daemon */
-    if (fork()) {
-      SILC_LOG_DEBUG(("Server started as user")); 
-      SILC_LOG_DEBUG(("Forking SILC server to background"));
-      exit(0);
-    }
-    setsid();
   }
 }
 
@@ -659,7 +680,11 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       sconn->remote_host = strdup(ptr->host);
       sconn->remote_port = ptr->port;
       sconn->backup = ptr->backup_router;
-      
+      if (sconn->backup) {
+       sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
+       sconn->backup_replace_port = ptr->backup_replace_port;
+      }
+
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
@@ -717,7 +742,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   /* We now have the key material as the result of the key exchange
      protocol. Take the key material into use. Free the raw key material
      as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+  if (!silc_server_protocol_ke_set_keys(server, ctx->ske, 
+                                       ctx->sock, ctx->keymat,
                                        ctx->ske->prop->cipher,
                                        ctx->ske->prop->pkcs,
                                        ctx->ske->prop->hash,
@@ -872,8 +898,24 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 
   SILC_LOG_INFO(("Connected to router %s", sock->hostname));
 
-  /* Add the connected router to local server list */
-  id_entry = silc_idlist_add_server(server->local_list, strdup(sock->hostname),
+  /* Check that we do not have this ID already */
+  id_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                          ctx->dest_id, TRUE, NULL);
+  if (id_entry) {
+    silc_idcache_del_by_context(server->local_list->servers, id_entry);
+  } else {
+    id_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                            ctx->dest_id, TRUE, NULL);
+    if (id_entry) 
+      silc_idcache_del_by_context(server->global_list->servers, id_entry);
+  }
+
+  SILC_LOG_DEBUG(("New server id(%s)",
+                 silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
+
+  /* Add the connected router to global server list */
+  id_entry = silc_idlist_add_server(server->global_list, 
+                                   strdup(sock->hostname),
                                    SILC_ROUTER, ctx->dest_id, NULL, sock);
   if (!id_entry) {
     silc_free(ctx->dest_id);
@@ -924,7 +966,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     }
   } else {
     /* Add this server to be our backup router */
-    silc_server_backup_add(server, id_entry, FALSE);
+    silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
+                          sconn->backup_replace_port, FALSE);
   }
 
   sock->protocol = NULL;
@@ -938,6 +981,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   /* Free the temporary connection data context */
   if (sconn) {
     silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
   }
 
@@ -1156,7 +1200,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   /* We now have the key material as the result of the key exchange
      protocol. Take the key material into use. Free the raw key material
      as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+  if (!silc_server_protocol_ke_set_keys(server, ctx->ske, 
+                                       ctx->sock, ctx->keymat,
                                        ctx->ske->prop->cipher,
                                        ctx->ske->prop->pkcs,
                                        ctx->ske->prop->hash,
@@ -1248,8 +1293,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    if (sock)
-      sock->protocol = NULL;
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
@@ -1315,11 +1358,18 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         server. We mark ourselves as router for this server if we really
         are router. */
       new_server = 
-       silc_idlist_add_server(server->local_list, NULL,
-                              ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                              SILC_SERVER : SILC_ROUTER, NULL, 
-                              ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                              server->id_entry : NULL, sock);
+       silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+                               server->local_list : (conn->backup_router ?
+                                                     server->local_list :
+                                                     server->global_list)),
+                              NULL,
+                              (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+                               SILC_SERVER : SILC_ROUTER), 
+                              NULL, 
+                              (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+                               server->id_entry : (conn->backup_router ? 
+                                                   server->id_entry : NULL)),
+                              sock);
       if (!new_server) {
        SILC_LOG_ERROR(("Could not add new server to cache"));
        silc_free(sock->user_data);
@@ -1342,22 +1392,15 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* If the incoming connection is router and marked as backup router
         then add it to be one of our backups */
       if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && conn->backup_router) {
-       silc_server_backup_add(server, new_server, conn->backup_local);
+       silc_server_backup_add(server, new_server, conn->backup_replace_ip,
+                              conn->backup_replace_port, conn->backup_local);
 
        /* Change it back to SERVER type since that's what it really is. */
-       if (conn->backup_local) {
+       if (conn->backup_local)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
-         new_server->server_type = SILC_BACKUP_ROUTER;
-       }
-      }
 
-#if 0
-      /* If the incoming connection is normal server and marked as backup
-        server then it will use us as backup router. We'll disable the
-        connection until it is allowed to be used. */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && conn->backup_router)
-       SILC_SET_DISABLED(sock);
-#endif
+       new_server->server_type = SILC_BACKUP_ROUTER;
+      }
 
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
@@ -1425,6 +1468,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   int ret;
 
   if (!sock)
@@ -1481,11 +1525,11 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     if (ret == -1)
       SILC_LOG_ERROR(("Error receiving packet from connection "
-                     "%s:%d [%s]", sock->hostname, sock->port,  
+                     "%s:%d [%s] %s", sock->hostname, sock->port,  
                      (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                      "Router")));
+                      "Router"), strerror(errno)));
     return;
   }    
 
@@ -1525,46 +1569,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   if (idata) {
     cipher = idata->receive_key;
     hmac = idata->hmac_receive;
+    sequence = idata->psn_receive;
   }
  
   /* Process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  silc_packet_receive_process(sock, cipher, hmac, silc_server_packet_parse, 
-                             server);
-}
-
-/* Callback function that the silc_packet_decrypt will call to make the
-   decision whether the packet is normal or special packet. We will 
-   return TRUE if it is normal and FALSE if it is special */
-
-static int silc_server_packet_decrypt_check(SilcPacketType packet_type,
-                                           SilcBuffer buffer,
-                                           SilcPacketContext *packet,
-                                           void *context)
-{
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcServer server = (SilcServer)parse_ctx->context;
-
-  /* Packet is normal packet, if: 
-
-     1) packet is private message packet and does not have private key set
-     2) is other packet than channel message packet
-     3) is channel message packet and remote is router and we are router 
-
-     all other packets are special packets 
-  */
-
-  if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
-      (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
-    return FALSE;
-
-  if (packet_type != SILC_PACKET_CHANNEL_MESSAGE || 
-      (packet_type == SILC_PACKET_CHANNEL_MESSAGE &&
-       parse_ctx->sock->type == SILC_SOCKET_TYPE_ROUTER &&
-       server->server_type == SILC_ROUTER))
-    return TRUE;
-
-  return FALSE;
+  silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                             TRUE : FALSE, cipher, hmac, sequence, 
+                             silc_server_packet_parse, server);
 }
   
 /* Parses whole packet, received earlier. */
@@ -1580,34 +1592,18 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Decrypt the received packet */
-  ret = silc_packet_decrypt(idata ? idata->receive_key : NULL, 
-                           idata ? idata->hmac_receive : NULL, 
-                           packet->buffer, packet,
-                           silc_server_packet_decrypt_check, parse_ctx);
-  if (ret < 0) {
-    SILC_LOG_WARNING(("Packet decryption failed for connection "
-                     "%s:%d [%s]", sock->hostname, sock->port,  
-                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
-                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
-                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                      "Router")));
-    goto out;
-  }
-
-  if (ret == 0) {
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet);
-  } else {
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet);
-  }
+  /* Parse the packet */
+  if (parse_ctx->normal)
+    ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
+  else
+    ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
 
   /* If entry is disabled ignore what we got. */
   if (ret != SILC_PACKET_RESUME_ROUTER &&
-      idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+      idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+    SILC_LOG_DEBUG(("Connection is disabled"));
     goto out;
+  }
 
   if (ret == SILC_PACKET_NONE)
     goto out;
@@ -1674,10 +1670,42 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 /* Parser callback called by silc_packet_receive_process. This merely
    registers timeout that will handle the actual parsing when appropriate. */
 
-void silc_server_packet_parse(SilcPacketParserContext *parser_context)
+bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
+                             void *context)
 {
-  SilcServer server = (SilcServer)parser_context->context;
+  SilcServer server = (SilcServer)context;
   SilcSocketConnection sock = parser_context->sock;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+  if (idata)
+    idata->psn_receive = parser_context->packet->sequence + 1;
+
+  /* If protocol for this connection is key exchange or rekey then we'll
+     process all packets synchronously, since there might be packets in
+     queue that we are not able to decrypt without first processing the
+     packets before them. */
+  if ((parser_context->packet->type == SILC_PACKET_REKEY ||
+       parser_context->packet->type == SILC_PACKET_REKEY_DONE) ||
+      (sock->protocol && sock->protocol->protocol && 
+       (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) {
+    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+                                 parser_context);
+
+    /* Reprocess data since we'll return FALSE here.  This is because
+       the idata->receive_key might have become valid in the last packet
+       and we want to call this processor with valid cipher. */
+    if (idata)
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                 TRUE : FALSE, idata->receive_key, 
+                                 idata->hmac_receive, idata->psn_receive, 
+                                 silc_server_packet_parse, server);
+    else
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                 TRUE : FALSE, NULL, NULL, 0, 
+                                 silc_server_packet_parse, server);
+    return FALSE;
+  }
 
   switch (sock->type) {
   case SILC_SOCKET_TYPE_UNKNOWN:
@@ -1691,16 +1719,15 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
-    /* Packets from servers are parsed as soon as possible */
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_packet_parse_real,
-                          (void *)parser_context, 0, 1,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
+    /* Packets from servers are parsed immediately */
+    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+                                 parser_context);
     break;
   default:
-    return;
+    return TRUE;
   }
+
+  return TRUE;
 }
 
 /* Parses the packet type and calls what ever routines the packet type
@@ -2115,7 +2142,11 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_FTP:
-    /* Ignored */
+    /* FTP packet */
+    SILC_LOG_DEBUG(("FTP packet"));
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_ftp(server, sock, packet);
     break;
 
   case SILC_PACKET_RESUME_ROUTER:
@@ -2163,6 +2194,9 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
+  if (!server->sockets[sock->sock])
+    return;
+
   SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
                   sock->port,
                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
@@ -2259,12 +2293,15 @@ void silc_server_free_client_data(SilcServer server,
      to the network before removing the client entry. */
   silc_server_packet_queue_purge(server, sock);
 
+  if (!client->id)
+    return;
+
   /* Send SIGNOFF notify to routers. */
   if (notify && !server->standalone && server->router)
     silc_server_send_notify_signoff(server, server->router->connection,
                                    server->server_type == SILC_SERVER ?
                                    FALSE : TRUE, client->id, signoff);
-
+    
   /* Remove client from all channels */
   if (notify)
     silc_server_remove_from_channels(server, NULL, client, 
@@ -2272,7 +2309,7 @@ void silc_server_free_client_data(SilcServer server,
   else
     silc_server_remove_from_channels(server, NULL, client, 
                                     FALSE, NULL, FALSE);
-
+    
   /* We will not delete the client entry right away. We will take it
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
@@ -2314,11 +2351,12 @@ void silc_server_free_sock_user_data(SilcServer server,
       SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
       SilcServerEntry backup_router = NULL;
 
+      if (user_data->id)
+       backup_router = silc_server_backup_get(server, user_data->id);
+
       /* If this was our primary router connection then we're lost to
         the outside world. */
       if (server->router == user_data) {
-       backup_router = silc_server_backup_get(server);
-
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
          silc_schedule_task_add(server->schedule, 0, 
@@ -2339,6 +2377,7 @@ void silc_server_free_sock_user_data(SilcServer server,
          server->id_entry->router = backup_router;
          server->router = backup_router;
          server->router_connect = time(0);
+         server->backup_primary = TRUE;
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
 
@@ -2353,6 +2392,15 @@ void silc_server_free_sock_user_data(SilcServer server,
          silc_server_backup_replaced_add(server, user_data->id, 
                                          backup_router);
        }
+      } else if (backup_router) {
+       SILC_LOG_INFO(("Enabling the use of backup router %s",
+                      backup_router->server_name));
+       SILC_LOG_DEBUG(("Enabling the use of backup router %s",
+                       backup_router->server_name));
+
+       /* Mark this connection as replaced */
+       silc_server_backup_replaced_add(server, user_data->id, 
+                                       backup_router);
       }
 
       if (!backup_router) {
@@ -2360,19 +2408,26 @@ void silc_server_free_sock_user_data(SilcServer server,
           become invalid now as well. */
        if (user_data->id)
          silc_server_remove_clients_by_server(server, user_data, TRUE);
+       if (server->server_type == SILC_SERVER)
+         silc_server_remove_channels_by_server(server, user_data);
       } else {
        /* Update the client entries of this server to the new backup
           router. This also removes the clients that *really* was owned
           by the primary router and went down with the router.  */
        silc_server_update_clients_by_server(server, user_data, backup_router,
                                             TRUE, TRUE);
+       silc_server_update_servers_by_server(server, user_data, backup_router);
+       if (server->server_type == SILC_SERVER)
+         silc_server_update_channels_by_server(server, user_data, 
+                                               backup_router);
       }
 
       /* Free the server entry */
       silc_server_backup_del(server, user_data);
       silc_server_backup_replaced_del(server, user_data);
       silc_idlist_del_data(user_data);
-      silc_idlist_del_server(server->local_list, user_data);
+      if (!silc_idlist_del_server(server->local_list, user_data))
+       silc_idlist_del_server(server->global_list, user_data);
       server->stat.my_servers--;
       server->stat.servers--;
       if (server->server_type == SILC_ROUTER)
@@ -2381,26 +2436,15 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (backup_router) {
        /* Announce all of our stuff that was created about 5 minutes ago.
           The backup router knows all the other stuff already. */
-       if (server->server_type == SILC_ROUTER)
-         silc_server_announce_servers(server, FALSE, 0,
-                                      server->router->connection);
-
-       /* Announce our clients and channels to the router */
-       silc_server_announce_clients(server, 0,
-                                    server->router->connection);
-       silc_server_announce_channels(server, 0,
-                                     server->router->connection);
-#if 0
        if (server->server_type == SILC_ROUTER)
          silc_server_announce_servers(server, FALSE, time(0) - 300,
-                                      server->router->connection);
+                                      backup_router->connection);
 
        /* Announce our clients and channels to the router */
        silc_server_announce_clients(server, time(0) - 300,
-                                    server->router->connection);
+                                    backup_router->connection);
        silc_server_announce_channels(server, time(0) - 300,
-                                     server->router->connection);
-#endif
+                                     backup_router->connection);
       }
       break;
     }
@@ -2462,9 +2506,10 @@ void silc_server_remove_from_channels(SilcServer server,
        silc_hash_table_count(channel->user_list) < 2) {
       if (channel->rekey)
        silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-      if (!silc_idlist_del_channel(server->local_list, channel))
-       silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
+      if (silc_idlist_del_channel(server->local_list, channel))
+       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -2501,7 +2546,7 @@ void silc_server_remove_from_channels(SilcServer server,
        SilcChannelClientEntry chl2;
        SilcHashTableList htl2;
 
-       channel->id = NULL;
+       channel->disabled = TRUE;
 
        silc_hash_table_list(channel->user_list, &htl2);
        while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
@@ -2513,9 +2558,10 @@ void silc_server_remove_from_channels(SilcServer server,
       }
 
       /* Remove the channel entry */
-      if (!silc_idlist_del_channel(server->local_list, channel))
-       silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
+      if (silc_idlist_del_channel(server->local_list, channel))
+       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -2580,10 +2626,11 @@ int silc_server_remove_from_one_channel(SilcServer server,
       silc_hash_table_count(channel->user_list) < 2) {
     if (channel->rekey)
       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-    if (!silc_idlist_del_channel(server->local_list, channel))
+    if (silc_idlist_del_channel(server->local_list, channel))
+      server->stat.my_channels--;
+    else 
       silc_idlist_del_channel(server->global_list, channel);
     silc_buffer_free(clidp);
-    server->stat.my_channels--;
     return FALSE;
   }
 
@@ -2619,7 +2666,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
       SilcChannelClientEntry chl2;
       SilcHashTableList htl2;
       
-      channel->id = NULL;
+      channel->disabled = TRUE;
       
       silc_hash_table_list(channel->user_list, &htl2);
       while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
@@ -2631,9 +2678,10 @@ int silc_server_remove_from_one_channel(SilcServer server,
     }
 
     /* Remove the channel entry */
-    if (!silc_idlist_del_channel(server->local_list, channel))
+    if (silc_idlist_del_channel(server->local_list, channel))
+      server->stat.my_channels--;
+    else 
       silc_idlist_del_channel(server->global_list, channel);
-    server->stat.my_channels--;
     return FALSE;
   }
 
@@ -2854,8 +2902,10 @@ bool silc_server_create_channel_key(SilcServer server,
   }
 
   if (!channel->channel_key)
-    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
+    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
+      channel->channel_key = NULL;
       return FALSE;
+    }
 
   if (key_len)
     len = key_len;
@@ -2885,8 +2935,9 @@ bool silc_server_create_channel_key(SilcServer server,
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, channel->key, len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
   if (server->server_type == SILC_ROUTER) {
@@ -2926,7 +2977,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode channel key payload */
-  payload = silc_channel_key_payload_parse(key_payload);
+  payload = silc_channel_key_payload_parse(key_payload->data,
+                                          key_payload->len);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload, dropped"));
     channel = NULL;
@@ -2975,6 +3027,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 
   /* Create new cipher */
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+    channel->channel_key = NULL;
     channel = NULL;
     goto out;
   }
@@ -2992,8 +3045,9 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
 
   memset(hash, 0, sizeof(hash));
   memset(tmp, 0, tmp_len);
@@ -3349,7 +3403,7 @@ void silc_server_announce_get_channels(SilcServer server,
        (*channel_ids)[i] = NULL;
        silc_server_announce_get_channel_users(server, channel,
                                               channel_users,
-                                              channel_users_modes[i]);
+                                              &(*channel_users_modes)[i]);
        (*channel_ids)[i] = channel->id;
        i++;
 
@@ -3390,11 +3444,12 @@ void silc_server_announce_channels(SilcServer server,
                                    &channel_ids, creation_time);
 
   /* Get channels and channel users in global list */
-  silc_server_announce_get_channels(server, server->global_list,
-                                   &channels, &channel_users,
-                                   &channel_users_modes,
-                                   &channel_users_modes_c,
-                                   &channel_ids, creation_time);
+  if (server->server_type != SILC_SERVER)
+    silc_server_announce_get_channels(server, server->global_list,
+                                     &channels, &channel_users,
+                                     &channel_users_modes,
+                                     &channel_users_modes_c,
+                                     &channel_ids, creation_time);
 
   if (channels) {
     silc_buffer_push(channels, channels->data - channels->head);