Integer type name change.
[silc.git] / apps / silcd / server.c
index 8f2c8d830cd75c049666776bd134a74e592c2b85..61b4c50dca6239703ae171a18615f6e65693a208 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
 */
 /*
  * This is the actual SILC server than handles everything relating to
- * servicing the SILC connections. This is also a SILC router as a router 
+ * servicing the SILC connections. This is also a SILC router as a router
  * is also normal server.
  */
 /* $Id$ */
@@ -93,8 +93,6 @@ void silc_server_free(SilcServer server)
     silc_dlist_uninit(server->sim);
 #endif
 
-    silc_free(server->params);
-
     if (server->pending_commands)
       silc_dlist_uninit(server->pending_commands);
 
@@ -104,55 +102,43 @@ void silc_server_free(SilcServer server)
 
 /* Initializes the entire SILC server. This is called always before running
    the server. This is called only once at the initialization of the program.
-   This binds the server to its listenning port. After this function returns 
-   one should call silc_server_run to start the server. This returns TRUE 
+   This binds the server to its listenning port. After this function returns
+   one should call silc_server_run to start the server. This returns TRUE
    when everything is ok to run the server. Configuration file must be
    read and parsed before calling this. */
 
 int silc_server_init(SilcServer server)
 {
-  int *sock = NULL, sock_count = 0, i;
+  int sock;
   SilcServerID *id;
   SilcServerEntry id_entry;
   SilcIDListPurge purge;
-  SilcServerConfigSectionListenPort *listen;
 
   SILC_LOG_DEBUG(("Initializing server"));
   assert(server);
   assert(server->config);
 
   /* Set public and private keys */
-  if (!server->config->server_keys ||
-      !server->config->server_keys->public_key || 
-      !server->config->server_keys->private_key) {
+  if (!server->config->server_info ||
+      !server->config->server_info->public_key ||
+      !server->config->server_info->private_key) {
     SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
     return FALSE;
   }
-  server->public_key = server->config->server_keys->public_key;
-  server->private_key = server->config->server_keys->private_key;
-
-  /* XXX After server is made as Silc Server Library this can be given
-     as argument, for now this is hard coded */
-  server->params = silc_calloc(1, sizeof(*server->params));
-  server->params->retry_count = SILC_SERVER_RETRY_COUNT;
-  server->params->retry_interval_min = SILC_SERVER_RETRY_INTERVAL_MIN;
-  server->params->retry_interval_max = SILC_SERVER_RETRY_INTERVAL_MAX;
-  server->params->retry_keep_trying = FALSE;
-  server->params->protocol_timeout = 60;
-  server->params->require_reverse_mapping = FALSE;
-
-  /* Set log files where log message should be saved. */
-  server->config->server = server;
-  silc_server_config_setlogfiles(server->config);
+  server->public_key = server->config->server_info->public_key;
+  server->private_key = server->config->server_info->private_key;
+
+  /* Set default to configuration parameters */
+  silc_server_config_set_defaults(server);
+
   /* Register all configured ciphers, PKCS and hash functions. */
-  if (!silc_server_config_register_ciphers(server->config))
+  if (!silc_server_config_register_ciphers(server))
     silc_cipher_register_default();
-  if (!silc_server_config_register_pkcs(server->config))
+  if (!silc_server_config_register_pkcs(server))
     silc_pkcs_register_default();
-  if (!silc_server_config_register_hashfuncs(server->config))
+  if (!silc_server_config_register_hashfuncs(server))
     silc_hash_register_default();
-  if (!silc_server_config_register_hmacs(server->config))
+  if (!silc_server_config_register_hmacs(server))
     silc_hmac_register_default();
 
   /* Initialize random number generator for the server. */
@@ -164,148 +150,138 @@ int silc_server_init(SilcServer server)
   silc_hash_alloc("md5", &server->md5hash);
   silc_hash_alloc("sha1", &server->sha1hash);
 
-  /* Initialize none cipher */
-  silc_cipher_alloc("none", &server->none_cipher);
-
   /* Allocate PKCS context for local public and private keys */
   silc_pkcs_alloc(server->public_key->name, &server->pkcs);
   silc_pkcs_public_key_set(server->pkcs, server->public_key);
   silc_pkcs_private_key_set(server->pkcs, server->private_key);
 
-  /* Create a listening server. Note that our server can listen on multiple
-     ports. All listeners are created here and now. */
-  sock_count = 0;
-  listen = server->config->listen_port;
-  while(listen) {
-    int tmp;
-
-    tmp = silc_net_create_server(server->config->listen_port->port,
-                                server->config->listen_port->listener_ip);
-    if (tmp < 0)
-      goto err0;
-
-    sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
-    sock[sock_count] = tmp;
-    sock_count++;
-    listen = listen->next;
+  /* Create a listening server */
+  sock = silc_net_create_server(server->config->server_info->port,
+                               server->config->server_info->server_ip);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
+                   server->config->server_info->server_ip,
+                   server->config->server_info->port));
+    goto err;
   }
 
   /* Initialize ID caches */
-  server->local_list->clients = 
+  server->local_list->clients =
     silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
   server->local_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
   server->local_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
-  /* These are allocated for normal server as well as these hold some 
-     global information that the server has fetched from its router. For 
+  /* These are allocated for normal server as well as these hold some
+     global information that the server has fetched from its router. For
      router these are used as they are supposed to be used on router. */
-  server->global_list->clients = 
+  server->global_list->clients =
     silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
   server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
   server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
-  /* Allocate the entire socket list that is used in server. Eventually 
-     all connections will have entry in this table (it is a table of 
-     pointers to the actual object that is allocated individually 
+  /* Allocate the entire socket list that is used in server. Eventually
+     all connections will have entry in this table (it is a table of
+     pointers to the actual object that is allocated individually
      later). */
-  server->sockets = silc_calloc(SILC_SERVER_MAX_CONNECTIONS,
+  server->sockets = silc_calloc(server->config->param.connections_max,
                                sizeof(*server->sockets));
 
-  for (i = 0; i < sock_count; i++) {
+  do {
     SilcSocketConnection newsocket = NULL;
 
     /* Set socket to non-blocking mode */
-    silc_net_set_socket_nonblock(sock[i]);
-    server->sock = sock[i];
-    
-    /* Create a Server ID for the server. */
-    silc_id_create_server_id(sock[i], server->rng, &id);
-    if (!id) {
-      goto err0;
+    silc_net_set_socket_nonblock(sock);
+    server->sock = sock;
+
+    /* 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, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    server->sockets[sock] = newsocket;
+
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
+                                     &newsocket->ip)) {
+      if ((server->config->require_reverse_lookup && !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 err;
+      }
+      if (!newsocket->hostname)
+       newsocket->hostname = strdup(newsocket->ip);
     }
-    
+    newsocket->port = silc_net_get_local_port(sock);
+
+    /* Create a Server ID for the server. */
+    silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+    if (!id)
+      goto err;
+
     server->id = id;
     server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
     server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
     server->id_type = SILC_ID_SERVER;
     server->server_name = server->config->server_info->server_name;
 
-    /* Add ourselves to the server list. We don't have a router yet 
-       beacuse we haven't established a route yet. It will be done later. 
+    /* Add ourselves to the server list. We don't have a router yet
+       beacuse we haven't established a route yet. It will be done later.
        For now, NULL is sent as router. This allocates new entry to
        the ID list. */
-    id_entry = 
+    id_entry =
       silc_idlist_add_server(server->local_list,
                             server->config->server_info->server_name,
                             server->server_type, server->id, NULL, NULL);
     if (!id_entry) {
       SILC_LOG_ERROR(("Could not add ourselves to cache"));
-      goto err0;
+      goto err;
     }
     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 
+    /* 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;
-  }
+  } while (0);
 
   /* Register protocols */
   silc_server_protocols_register();
 
   /* Initialize the scheduler. */
-  server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
+  server->schedule = silc_schedule_init(server->config->param.connections_max);
   if (!server->schedule)
-    goto err0;
-  
+    goto err;
+
   /* Add the first task to the scheduler. This is task that is executed by
      timeout. It expires as soon as the caller calls silc_server_run. This
      task performs authentication protocol and key exchange with our
      primary router. */
-  silc_schedule_task_add(server->schedule, sock[0], 
+  silc_schedule_task_add(server->schedule, sock,
                         silc_server_connect_to_router,
                         (void *)server, 0, 1,
                         SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
 
   /* Add listener task to the scheduler. This task receives new connections
-     to the server. This task remains on the queue until the end of the 
+     to the server. This task remains on the queue until the end of the
      program. */
-  silc_schedule_task_add(server->schedule, sock[0],
+  silc_schedule_task_add(server->schedule, sock,
                         silc_server_accept_new_connection,
-                        (void *)server, 0, 0, 
+                        (void *)server, 0, 0,
                         SILC_TASK_FD,
                         SILC_TASK_PRI_NORMAL);
   server->listenning = TRUE;
 
+  /* Send log file configuration */
+  silc_server_config_setlogfiles(server);
+
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
   if (server->config->servers) {
-    SilcServerConfigSectionServerConnection *ptr = server->config->servers;
+    SilcServerConfigServer *ptr = server->config->servers;
 
     server->server_type = SILC_ROUTER;
     while (ptr) {
@@ -326,18 +302,20 @@ int silc_server_init(SilcServer server)
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
   purge->schedule = server->schedule;
-  silc_schedule_task_add(purge->schedule, 0, 
+  purge->timeout = 600;
+  silc_schedule_task_add(purge->schedule, 0,
                         silc_idlist_purge,
-                        (void *)purge, 600, 0,
+                        (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
   purge->schedule = server->schedule;
-  silc_schedule_task_add(purge->schedule, 0, 
+  purge->timeout = 300;
+  silc_schedule_task_add(purge->schedule, 0,
                         silc_idlist_purge,
-                        (void *)purge, 300, 0,
+                        (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   SILC_LOG_DEBUG(("Server initialized"));
@@ -345,118 +323,115 @@ int silc_server_init(SilcServer server)
   /* We are done here, return succesfully */
   return TRUE;
 
- err0:
-  for (i = 0; i < sock_count; i++)
-    silc_net_close_server(sock[i]);
-
+ err:
+  silc_net_close_server(sock);
   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 */
 
 void silc_server_daemonise(SilcServer server)
+{
+  int i;
+
+  SILC_LOG_DEBUG(("Forking SILC server to background"));
+
+  i = fork();
+
+  if (i < 0) {
+    SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+    exit(1);
+  }
+  else if (i) {
+    if (geteuid())
+      SILC_LOG_DEBUG(("Server started as user"));
+    else
+      SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+    exit(0);
+  }
+  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:"
+
+    /* Get the values given for user and group in configuration file */
+    user = server->config->server_info->user;
+    group = server->config->server_info->group;
+
+    if (!user || !group) {
+      fprintf(stderr, "Error:" /* XXX update this error message */
        "\tSILC server must not be run as root.  For the security of your\n"
        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
        "\tuser account.  Modify the [Identity] configuration section to run\n"
        "\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"));
-      SILC_LOG_DEBUG(("User and/or group given as number"));
+
+    /* Check whether the user/group does not begin with a number */
+    if (isdigit(user[0]) || isdigit(group[0])) {
+      SILC_LOG_DEBUG(("User and/or group starts with a number"));
       fprintf(stderr, "Invalid user and/or group information\n");
       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) {
-      fprintf(stderr, "No such user %s found\n", user);
+    if (!(pw = getpwnam(user))) {
+      fprintf(stderr, "Error: No such user %s found.\n", user);
       exit(1);
     }
-
-    if (!gr) {
-      fprintf(stderr, "No such group %s found\n", group);
+    if (!(gr = getgrnam(group))) {
+      fprintf(stderr, "Error: 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) {
+    if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
       fprintf(stderr, "Error:"
        "\tSILC server must not be run as root.  For the security of your\n"
        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
        "\tuser account.  Modify the [Identity] configuration section to run\n"
        "\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) {
-        SILC_LOG_DEBUG(("Setgid to %s", group));
-      } else {
-        SILC_LOG_DEBUG(("Setgid to %s failed", group));
-        fprintf(stderr, "Tried to setgid %s but no such group. Exiting\n",
-                group);
-        exit(1);
-      }
-      SILC_LOG_DEBUG(("Changing to user nobody"));
-      if(setuid(pw->pw_uid)==0) {
-        SILC_LOG_DEBUG(("Setuid to %s", user));
-      } else {
-        SILC_LOG_DEBUG(("Setuid to %s failed", user));
-        fprintf(stderr, "Tried to setuid %s but no such user. Exiting\n",
-                user);
-        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);
+
+    SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
+    if (setgid(gr->gr_gid) != 0) {
+      fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
+             group, gr->gr_gid);
+      exit(1);
+    }
+#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
+    SILC_LOG_DEBUG(("Removing supplementary groups"));
+    if (setgroups(0, NULL) != 0) {
+      fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
+      exit(1);
+    }
+    SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
+    if (initgroups(user, gr->gr_gid) != 0) {
+      fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
+             "Exiting.\n", user, gr->gr_gid);
+      exit(1);
+    }
+#endif
+    SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
+    if (setuid(pw->pw_uid) != 0) {
+      fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
+              user, pw->pw_uid);
+      exit(1);
     }
-    setsid();
   }
 }
 
-/* The heart of the server. This runs the scheduler thus runs the server. 
+/* The heart of the server. This runs the scheduler thus runs the server.
    When this returns the server has been stopped and the program will
    be terminated. */
 
@@ -471,16 +446,19 @@ void silc_server_run(SilcServer server)
   silc_schedule(server->schedule);
 }
 
-/* Stops the SILC server. This function is used to shutdown the server. 
-   This is usually called after the scheduler has returned. After stopping 
+/* Stops the SILC server. This function is used to shutdown the server.
+   This is usually called after the scheduler has returned. After stopping
    the server one should call silc_server_free. */
 
 void silc_server_stop(SilcServer server)
 {
   SILC_LOG_DEBUG(("Stopping server"));
 
-  silc_schedule_stop(server->schedule);
-  silc_schedule_uninit(server->schedule);
+  if (server->schedule) {
+    silc_schedule_stop(server->schedule);
+    silc_schedule_uninit(server->schedule);
+    server->schedule = NULL;
+  }
 
   silc_server_protocols_unregister();
 
@@ -498,8 +476,13 @@ void silc_server_start_key_exchange(SilcServer server,
   SilcSocketConnection newsocket;
   SilcProtocol protocol;
   SilcServerKEInternalContext *proto_ctx;
+  SilcServerConfigRouter *conn = sconn->conn;
   void *context;
 
+  /* Cancel any possible retry timeouts */
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_connect_router);
+
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
@@ -523,7 +506,13 @@ void silc_server_start_key_exchange(SilcServer server,
   proto_ctx->sock = newsocket;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = FALSE;
-      
+
+  /* Set Key Exchange flags from configuration, but fall back to global
+     settings too. */
+  SILC_GET_SKE_FLAGS(conn, proto_ctx);
+  if (server->config->param.key_exchange_pfs)
+    proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
+
   /* Perform key exchange protocol. silc_server_connect_to_router_second
      will be called after the protocol is finished. */
   silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
@@ -535,21 +524,20 @@ void silc_server_start_key_exchange(SilcServer server,
      is not executed within set limit. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock, 
-                      silc_server_timeout_remote,
-                      server, server->params->protocol_timeout,
-                      server->params->protocol_timeout_usec,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+                          silc_server_timeout_remote,
+                          server, server->config->key_exchange_timeout, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 
   /* Register the connection for network input and output. This sets
      that scheduler will listen for incoming packets for this connection 
-     and sets that outgoing packets may be sent to this connection as 
+     and sets that outgoing packets may be sent to this connection as
      well. However, this doesn't set the scheduler for outgoing traffic,
      it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
      later when outgoing data is available. */
   context = (void *)server;
   SILC_REGISTER_CONNECTION_FOR_IO(sock);
-  
+
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
@@ -563,39 +551,42 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 {
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
+  SilcServerConfigConnParams *param = 
+    (sconn->param ? sconn->param : &server->config->param);
 
   SILC_LOG_INFO(("Retrying connecting to a router"));
 
   /* Calculate next timeout */
   if (sconn->retry_count >= 1) {
     sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
-    if (sconn->retry_timeout > SILC_SERVER_RETRY_INTERVAL_MAX)
-      sconn->retry_timeout = SILC_SERVER_RETRY_INTERVAL_MAX;
+    if (sconn->retry_timeout > param->reconnect_interval_max)
+      sconn->retry_timeout = param->reconnect_interval_max;
   } else {
-    sconn->retry_timeout = server->params->retry_interval_min;
+    sconn->retry_timeout = param->reconnect_interval;
   }
   sconn->retry_count++;
   sconn->retry_timeout = sconn->retry_timeout +
     silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
 
   /* If we've reached max retry count, give up. */
-  if (sconn->retry_count > server->params->retry_count && 
-      server->params->retry_keep_trying == FALSE) {
+  if (sconn->retry_count > param->reconnect_count &&
+      param->reconnect_keep_trying == FALSE) {
     SILC_LOG_ERROR(("Could not connect to router, giving up"));
+    silc_free(sconn->remote_host);
+    silc_free(sconn);
     return;
   }
 
   /* Wait one before retrying */
   silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
-                        context, sconn->retry_timeout, 
-                        server->params->retry_interval_min_usec,
+                        context, sconn->retry_timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* Generic routine to use connect to a router. */
 
 SILC_TASK_CALLBACK(silc_server_connect_router)
-{    
+{
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
   int sock;
@@ -604,18 +595,20 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                 (sconn->backup ? "backup router" : "router"), 
                 sconn->remote_host, sconn->remote_port));
 
-  server->router_connect = time(0);
+  server->router_connect = time(NULL);
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->listen_port->local_ip,
+  sock = silc_net_create_connection(server->config->server_info->server_ip,
                                    sconn->remote_port, 
                                    sconn->remote_host);
   if (sock < 0) {
-    SILC_LOG_ERROR(("Could not connect to router"));
-    silc_schedule_task_add(server->schedule, fd, 
-                          silc_server_connect_to_router_retry,
-                          context, 0, 1, SILC_TASK_TIMEOUT, 
-                          SILC_TASK_PRI_NORMAL);
+    SILC_LOG_ERROR(("Could not connect to router %s:%d",
+                   sconn->remote_host, sconn->remote_port));
+    if (!sconn->no_reconnect)
+      silc_schedule_task_add(server->schedule, fd,
+                            silc_server_connect_to_router_retry,
+                            context, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -632,7 +625,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
 {
   SilcServer server = (SilcServer)context;
   SilcServerConnection sconn;
-  SilcServerConfigSectionServerConnection *ptr;
+  SilcServerConfigRouter *ptr;
 
   SILC_LOG_DEBUG(("Connecting to router(s)"));
 
@@ -665,6 +658,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
        sconn->backup_replace_port = ptr->backup_replace_port;
       }
 
+      if (!server->router_conn && !sconn->backup)
+       server->router_conn = sconn;
+
+      sconn->conn = ptr;
+      sconn->param = ptr->param;
+
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
@@ -696,7 +695,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
   SilcSocketConnection sock = ctx->sock;
   SilcServerConnAuthInternalContext *proto_ctx;
-  SilcServerConfigSectionServerConnection *conn = NULL;
+  SilcServerConfigRouter *conn = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -722,7 +721,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,
@@ -758,15 +758,30 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
 
   /* Resolve the authentication method used in this connection. Check if 
      we find a match from user configured connections */
-  conn = silc_server_config_find_router_conn(server->config,
-                                            sock->hostname,
-                                            sock->port);
+  if (!sconn->conn)
+    conn = silc_server_config_find_router_conn(server, sock->hostname,
+                                              sock->port);
+  else
+    conn = sconn->conn;
+
   if (conn) {
     /* Match found. Use the configured authentication method */
-    proto_ctx->auth_meth = conn->auth_meth;
-    if (conn->auth_data) {
-      proto_ctx->auth_data = strdup(conn->auth_data);
-      proto_ctx->auth_data_len = strlen(conn->auth_data);
+    if (conn->passphrase) {
+      if (conn->publickey && !server->config->prefer_passphrase_auth) {
+       proto_ctx->auth_data = conn->publickey;
+       proto_ctx->auth_data_len = 0;
+       proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
+      } else {
+       proto_ctx->auth_data = strdup(conn->passphrase);
+       proto_ctx->auth_data_len = strlen(conn->passphrase);
+       proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
+      }
+    } else if (conn->publickey) {
+      proto_ctx->auth_data = conn->publickey;
+      proto_ctx->auth_data_len = 0;
+      proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
+    } else {
+      proto_ctx->auth_meth = SILC_AUTH_NONE;
     }
   } else {
     SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
@@ -802,14 +817,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
                      silc_server_connect_to_router_final);
 
   /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. Currently
-     this is 15 seconds and is hard coded limit (XXX). */
-  proto_ctx->timeout_task = 
-    silc_schedule_task_add(server->schedule, sock->sock, 
-                      silc_server_timeout_remote,
-                      (void *)server, 15, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+     this timelimit the connection will be terminated. */
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_timeout_remote,
+                          (void *)server, 
+                          server->config->conn_auth_timeout, 0, 
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 
   /* Run the protocol */
   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
@@ -821,7 +836,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
 SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx = 
+  SilcServerConnAuthInternalContext *ctx =
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
@@ -830,8 +845,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SilcBuffer packet;
   SilcServerHBContext hb_context;
   unsigned char *id_string;
-  uint32 id_len;
+  SilcUInt32 id_len;
   SilcIDListData idata;
+  SilcServerConfigConnParams *param;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -844,12 +860,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     goto out;
   }
 
-  /* Add a task to the queue. This task receives new connections to the 
+  /* Add a task to the queue. This task receives new connections to the
      server. This task remains on the queue until the end of the program. */
   if (!server->listenning && !sconn->backup) {
-    silc_schedule_task_add(server->schedule, server->sock, 
+    silc_schedule_task_add(server->schedule, server->sock,
                           silc_server_accept_new_connection,
-                          (void *)server, 0, 0, 
+                          (void *)server, 0, 0,
                           SILC_TASK_FD,
                           SILC_TASK_PRI_NORMAL);
     server->listenning = TRUE;
@@ -910,17 +926,18 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   idata = (SilcIDListData)sock->user_data;
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
 
+  param = (sconn->param ? sconn->param : &server->config->param);
+
   /* Perform keepalive. The `hb_context' will be freed automatically
-     when finally calling the silc_socket_free function. XXX hardcoded 
-     timeout!! */
+     when finally calling the silc_socket_free function. */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 600, hb_context,
+  silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
   /* Register re-key timeout */
-  idata->rekey->timeout = 3600; /* XXX hardcoded */
+  idata->rekey->timeout = param->key_exchange_rekey;
   idata->rekey->context = (void *)server;
   silc_schedule_task_add(server->schedule, sock->sock, 
                         silc_server_rekey_callback,
@@ -963,6 +980,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
   }
+  if (sconn == server->router_conn)
+    server->router_conn = NULL;
 
   /* Free the protocol object */
   if (sock->protocol == protocol)
@@ -972,6 +991,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_packet_context_free(ctx->packet);
   if (ctx->ske)
     silc_ske_free(ctx->ske);
+  if (ctx->auth_meth == SILC_AUTH_PASSWORD)
+    silc_free(ctx->auth_data);
   silc_free(ctx);
 }
 
@@ -986,15 +1007,17 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
 {
   SilcServer server = (SilcServer)context;
   SilcServerKEInternalContext *proto_ctx;
-  void *cconfig, *sconfig, *rconfig;
-  SilcServerConfigSectionDenyConnection *deny;
+  SilcServerConfigClient *cconfig = NULL;
+  SilcServerConfigServer *sconfig = NULL;
+  SilcServerConfigRouter *rconfig = NULL;
+  SilcServerConfigDeny *deny;
   int port;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Check whether we could resolve both IP and FQDN. */
   if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
-                   server->params->require_reverse_mapping)) {
+                   server->config->require_reverse_lookup)) {
     SILC_LOG_ERROR(("IP/DNS lookup failed %s",
                    sock->hostname ? sock->hostname :
                    sock->ip ? sock->ip : ""));
@@ -1018,16 +1041,15 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   port = server->sockets[server->sock]->port; /* Listenning port */
 
   /* Check whether this connection is denied to connect to us. */
-  deny = silc_server_config_denied_conn(server->config, sock->ip, port);
+  deny = silc_server_config_find_denied(server, sock->ip);
   if (!deny)
-    deny = silc_server_config_denied_conn(server->config, sock->hostname,
-                                         port);
+    deny = silc_server_config_find_denied(server, sock->hostname);
   if (deny) {
     /* The connection is denied */
     SILC_LOG_INFO(("Connection %s (%s) is denied", 
                    sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, deny->comment ?
-                                 deny->comment :
+    silc_server_disconnect_remote(server, sock, deny->reason ?
+                                 deny->reason :
                                  "Server closed connection: "
                                  "Connection refused");
     server->stat.conn_failures++;
@@ -1037,23 +1059,19 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   /* Check whether we have configred this sort of connection at all. We
      have to check all configurations since we don't know what type of
      connection this is. */
-  if (!(cconfig = silc_server_config_find_client_conn(server->config,
-                                                     sock->ip, port)))
-    cconfig = silc_server_config_find_client_conn(server->config,
-                                                 sock->hostname, 
-                                                 port);
-  if (!(sconfig = silc_server_config_find_server_conn(server->config,
-                                                    sock->ip, 
-                                                    port)))
-    sconfig = silc_server_config_find_server_conn(server->config,
-                                                 sock->hostname,
-                                                 port);
-  if (!(rconfig = silc_server_config_find_router_conn(server->config,
-                                                    sock->ip, port)))
-    rconfig = silc_server_config_find_router_conn(server->config,
-                                                 sock->hostname, 
-                                                 port);
+  if (!(cconfig = silc_server_config_find_client(server, sock->ip)))
+    cconfig = silc_server_config_find_client(server, sock->hostname);
+  if (!(sconfig = silc_server_config_find_server_conn(server, sock->ip)))
+    sconfig = silc_server_config_find_server_conn(server, sock->hostname);
+  if (server->server_type == SILC_ROUTER) {
+    if (!(rconfig = silc_server_config_find_router_conn(server, 
+                                                       sock->ip, port)))
+      rconfig = silc_server_config_find_router_conn(server, sock->hostname, 
+                                                   sock->port);
+  }
   if (!cconfig && !sconfig && !rconfig) {
+    SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname, 
+                  sock->ip));
     silc_server_disconnect_remote(server, sock, 
                                  "Server closed connection: "
                                  "Connection refused");
@@ -1074,6 +1092,15 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   proto_ctx->sconfig = sconfig;
   proto_ctx->rconfig = rconfig;
 
+  /* Take flags for key exchange. Since we do not know what type of connection
+     this is, we go through all found configuratios and use the global ones
+     as well. This will result always into strictest key exchange flags. */
+  SILC_GET_SKE_FLAGS(cconfig, proto_ctx);
+  SILC_GET_SKE_FLAGS(sconfig, proto_ctx);
+  SILC_GET_SKE_FLAGS(rconfig, proto_ctx);
+  if (server->config->param.key_exchange_pfs)
+    proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
+
   /* Prepare the connection for key exchange protocol. We allocate the
      protocol but will not start it yet. The connector will be the
      initiator of the protocol thus we will wait for initiation from 
@@ -1084,13 +1111,12 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                      silc_server_accept_new_connection_second);
 
   /* Register a timeout task that will be executed if the connector
-     will not start the key exchange protocol within 60 seconds. For
-     now, this is a hard coded limit. After 60 secs the connection will
-     be closed if the key exchange protocol has not been started. */
+     will not start the key exchange protocol within specified timeout
+     and the connection will be closed. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock->sock, 
                           silc_server_timeout_remote,
-                          context, 60, 0,
+                          context, server->config->key_exchange_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1115,12 +1141,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
     return;
   }
 
-  /* Check max connections */
-  if (sock > SILC_SERVER_MAX_CONNECTIONS) {
-    SILC_LOG_ERROR(("Refusing connection, server is full"));
+  /* Check for maximum allowed connections */
+  if (sock > server->config->param.connections_max) {
+    SILC_LOG_ERROR(("Refusing connection, server is full, try again later"));
     server->stat.conn_failures++;
     return;
-  }
+  }  
 
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
@@ -1179,7 +1205,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,
@@ -1233,12 +1260,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                      silc_server_accept_new_connection_final);
 
   /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. Currently
-     this is 60 seconds and is hard coded limit (XXX). */
+     this timelimit the connection will be terminated. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock->sock, 
                           silc_server_timeout_remote,
-                          (void *)server, 60, 0,
+                          (void *)server, 
+                          server->config->conn_auth_timeout, 0, 
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1256,7 +1283,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcSocketConnection sock = ctx->sock;
   SilcServerHBContext hb_context;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
-  void *id_entry = NULL;
+  void *id_entry;
+  SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
+  SilcUInt32 num_sockets;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1271,8 +1300,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: "
@@ -1283,10 +1310,36 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   entry->data.last_receive = time(NULL);
 
+  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip);
+
   switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
+      SilcServerConfigClient *conn = ctx->cconfig;
+      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
+
+      /* Check for maximum connections limit */
+      if (conn->param) {
+       if (conn->param->connections_max &&
+           server->stat.my_clients >= conn->param->connections_max) {
+         silc_server_disconnect_remote(server, sock, 
+                                       "Server closed connection: "
+                                       "Server is full, try again later");
+         server->stat.auth_failures++;
+         goto out;
+       }
+
+       max_per_host = conn->param->connections_max_per_host;
+      }
+
+      if (num_sockets > max_per_host) {
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Too many connections from your host");
+       server->stat.auth_failures++;
+       goto out;
+      }
 
       SILC_LOG_DEBUG(("Remote host is client"));
       SILC_LOG_INFO(("Connection from %s (%s) is client", sock->hostname,
@@ -1296,7 +1349,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         and other information is created after we have received NEW_CLIENT
         packet from client. */
       client = silc_idlist_add_client(server->local_list, 
-                                     NULL, NULL, NULL, NULL, NULL, sock);
+                                     NULL, NULL, NULL, NULL, NULL, sock, 0);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
@@ -1313,6 +1366,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (server->server_type == SILC_ROUTER)
        server->stat.cell_clients++;
 
+      /* Get connection parameters */
+      if (conn->param) {
+       if (conn->param->keepalive_secs)
+         hearbeat_timeout = conn->param->keepalive_secs;
+      }
+
       id_entry = (void *)client;
       break;
     }
@@ -1320,17 +1379,74 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_ROUTER:
     {
       SilcServerEntry new_server;
-      SilcServerConfigSectionServerConnection *conn = 
-       ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-       ctx->sconfig : ctx->rconfig;
+      bool initiator = FALSE;
+      bool backup_local = FALSE;
+      bool backup_router = FALSE;
+      char *backup_replace_ip = NULL;
+      SilcUInt16 backup_replace_port = 0;
+      SilcServerConfigServer *sconn = ctx->sconfig;
+      SilcServerConfigRouter *rconn = ctx->rconfig;
+      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
+
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && rconn) {
+       if (rconn->param) {
+         /* Check for maximum connections limit */
+         if (rconn->param->connections_max &&
+             server->stat.my_routers >= rconn->param->connections_max) {
+           silc_server_disconnect_remote(server, sock, 
+                                         "Server closed connection: "
+                                         "Server is full, try again later");
+           server->stat.auth_failures++;
+           goto out;
+         }
+         max_per_host = rconn->param->connections_max_per_host;
+
+         if (rconn->param->keepalive_secs)
+           hearbeat_timeout = rconn->param->keepalive_secs;
+       }
+
+       initiator = rconn->initiator;
+       backup_local = rconn->backup_local;
+       backup_router = rconn->backup_router;
+       backup_replace_ip = rconn->backup_replace_ip;
+       backup_replace_port = rconn->backup_replace_port;
+      }
+
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && sconn) {
+       if (sconn->param) {
+         /* Check for maximum connections limit */
+         if (sconn->param->connections_max &&
+             server->stat.my_servers >= sconn->param->connections_max) {
+           silc_server_disconnect_remote(server, sock, 
+                                         "Server closed connection: "
+                                         "Server is full, try again later");
+           server->stat.auth_failures++;
+           goto out;
+         }
+         max_per_host = sconn->param->connections_max_per_host;
+
+         if (sconn->param->keepalive_secs)
+           hearbeat_timeout = sconn->param->keepalive_secs;
+       }
+
+       backup_router = sconn->backup_router;
+      }
+
+      if (num_sockets > max_per_host) {
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Too many connections from your host");
+       server->stat.auth_failures++;
+       goto out;
+      }
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                     "server" : (conn->backup_router ? 
+                     "server" : (backup_router ? 
                                  "backup router" : "router")));
       SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
                     sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                    "server" : (conn->backup_router ? 
+                    "server" : (backup_router ? 
                                 "backup router" : "router")));
 
       /* Add the server into server cache. The server name and Server ID
@@ -1339,7 +1455,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         are router. */
       new_server = 
        silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->local_list : (conn->backup_router ?
+                               server->local_list : (backup_router ?
                                                      server->local_list :
                                                      server->global_list)),
                               NULL,
@@ -1347,7 +1463,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                SILC_SERVER : SILC_ROUTER), 
                               NULL, 
                               (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->id_entry : (conn->backup_router ? 
+                               server->id_entry : (backup_router ? 
                                                    server->id_entry : NULL)),
                               sock);
       if (!new_server) {
@@ -1371,12 +1487,12 @@ 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_replace_ip,
-                              conn->backup_replace_port, conn->backup_local);
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) {
+       silc_server_backup_add(server, new_server, backup_replace_ip,
+                              backup_replace_port, backup_local);
 
        /* Change it back to SERVER type since that's what it really is. */
-       if (conn->backup_local)
+       if (backup_local)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
 
        new_server->server_type = SILC_BACKUP_ROUTER;
@@ -1385,8 +1501,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
       if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
-       if (silc_server_config_is_primary_route(server->config) &&
-           !conn->initiator)
+       if (silc_server_config_is_primary_route(server) && !initiator)
          break;
 
        SILC_LOG_DEBUG(("We are not standalone server anymore"));
@@ -1400,15 +1515,15 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       break;
     }
   default:
+    goto out;
     break;
   }
 
   sock->type = ctx->conn_type;
 
   /* Add the common data structure to the ID entry. */
-  if (id_entry)
-    silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
-      
+  silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+
   /* Add to sockets internal pointer for fast referencing */
   silc_free(sock->user_data);
   sock->user_data = id_entry;
@@ -1417,11 +1532,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SILC_LOG_DEBUG(("New connection authenticated"));
 
   /* Perform keepalive. The `hb_context' will be freed automatically
-     when finally calling the silc_socket_free function. XXX hardcoded 
-     timeout!! */
+     when finally calling the silc_socket_free function. */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 600, hb_context,
+  silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -1448,7 +1562,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
-  uint32 sequence = 0;
+  SilcUInt32 sequence = 0;
   int ret;
 
   if (!sock)
@@ -1505,11 +1619,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;
   }    
 
@@ -1521,7 +1635,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
        close the connection */
     if (SILC_IS_DISCONNECTING(sock)) {
       if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock);
+       silc_server_free_sock_user_data(server, sock, NULL);
       silc_server_close_connection(server, sock);
       return;
     }
@@ -1529,8 +1643,20 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
     SILC_SET_DISCONNECTING(sock);
 
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock);
+    if (sock->user_data) {
+      char tmp[128];
+      if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
+       silc_server_free_sock_user_data(server, sock, tmp);
+      else
+       silc_server_free_sock_user_data(server, sock, NULL);
+    } else if (server->router_conn && server->router_conn->sock == sock &&
+            !server->router && server->standalone)
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_connect_to_router, 
+                            server, 1, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+
     silc_server_close_connection(server, sock);
     return;
   }
@@ -1554,9 +1680,23 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
  
   /* Process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
-                             TRUE : FALSE, cipher, hmac, sequence, 
-                             silc_server_packet_parse, server);
+  ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                   TRUE : FALSE, cipher, hmac, sequence, 
+                                   silc_server_packet_parse, server);
+
+  /* If this socket connection is not authenticated yet and the packet
+     processing failed we will drop the connection since it can be
+     a malicious flooder. */
+  if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE &&
+      (!sock->protocol || sock->protocol->protocol->type ==
+       SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) {
+    SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock));
+    SILC_SET_DISCONNECTING(sock);
+
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_close_connection(server, sock);
+  }
 }
   
 /* Parses whole packet, received earlier. */
@@ -1608,7 +1748,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
        packet->dst_id_type == SILC_ID_SERVER && 
        sock->type != SILC_SOCKET_TYPE_CLIENT &&
-       memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       
       /* Route the packet to fastest route for the destination ID */
       void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len, 
@@ -1664,9 +1804,11 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
      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 (sock->protocol && sock->protocol->protocol && 
-      (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
+  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);
 
@@ -1697,12 +1839,9 @@ bool 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 TRUE;
@@ -2149,7 +2288,7 @@ void silc_server_packet_parse_type(SilcServer server,
 /* Creates connection to a remote router. */
 
 void silc_server_create_connection(SilcServer server,
-                                  char *remote_host, uint32 port)
+                                  const char *remote_host, SilcUInt32 port)
 {
   SilcServerConnection sconn;
 
@@ -2158,6 +2297,8 @@ void silc_server_create_connection(SilcServer server,
   sconn->server = server;
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
+  sconn->no_reconnect = TRUE;
+  sconn->param = &server->config->param;
 
   silc_schedule_task_add(server->schedule, 0, 
                         silc_server_connect_router,
@@ -2175,6 +2316,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" :
@@ -2263,7 +2407,7 @@ void silc_server_free_client_data(SilcServer server,
                                  SilcSocketConnection sock,
                                  SilcClientEntry client, 
                                  int notify,
-                                 char *signoff)
+                                 const char *signoff)
 {
   FreeClientInternal i = silc_calloc(1, sizeof(*i));
 
@@ -2283,11 +2427,19 @@ void silc_server_free_client_data(SilcServer server,
   /* Remove client from all channels */
   if (notify)
     silc_server_remove_from_channels(server, NULL, client, 
-                                    TRUE, signoff, TRUE);
+                                    TRUE, (char *)signoff, TRUE);
   else
     silc_server_remove_from_channels(server, NULL, client, 
                                     FALSE, NULL, FALSE);
     
+  /* Update statistics */
+  server->stat.my_clients--;
+  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);
+
   /* We will not delete the client entry right away. We will take it
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
@@ -2299,12 +2451,7 @@ void silc_server_free_client_data(SilcServer server,
   client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
   client->router = NULL;
   client->connection = NULL;
-
-  /* Free the client entry and everything in it */
-  server->stat.my_clients--;
-  server->stat.clients--;
-  if (server->server_type == SILC_ROUTER)
-    server->stat.cell_clients--;
+  client->mode = 0;
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
@@ -2312,7 +2459,8 @@ void silc_server_free_client_data(SilcServer server,
    entities. */
 
 void silc_server_free_sock_user_data(SilcServer server, 
-                                    SilcSocketConnection sock)
+                                    SilcSocketConnection sock,
+                                    const char *signoff_message)
 {
   SILC_LOG_DEBUG(("Start"));
 
@@ -2320,7 +2468,8 @@ void silc_server_free_sock_user_data(SilcServer server,
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-      silc_server_free_client_data(server, sock, user_data, TRUE, NULL);
+      silc_server_free_client_data(server, sock, user_data, TRUE, 
+                                  signoff_message);
       break;
     }
   case SILC_SOCKET_TYPE_SERVER:
@@ -2338,7 +2487,7 @@ void silc_server_free_sock_user_data(SilcServer server,
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
          silc_schedule_task_add(server->schedule, 0, 
-                                silc_server_connect_to_router,
+                                silc_server_connect_to_router, 
                                 server, 1, 0,
                                 SILC_TASK_TIMEOUT,
                                 SILC_TASK_PRI_NORMAL);
@@ -2386,6 +2535,8 @@ 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
@@ -2393,6 +2544,9 @@ void silc_server_free_sock_user_data(SilcServer server,
        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 */
@@ -2488,6 +2642,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* Remove client from channel's client list */
     silc_hash_table_del(channel->user_list, chl->client);
+    channel->user_count--;
 
     /* If there is no global users on the channel anymore mark the channel
        as local channel. Do not check if the removed client is local client. */
@@ -2519,14 +2674,16 @@ 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)) {
          silc_hash_table_del(chl2->client->channels, channel);
          silc_hash_table_del(channel->user_list, chl2->client);
+         channel->user_count--;
          silc_free(chl2);
        }
+       silc_hash_table_list_reset(&htl2);
        continue;
       }
 
@@ -2551,7 +2708,7 @@ void silc_server_remove_from_channels(SilcServer server,
     if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
-       return;
+       goto out;
       
       /* Send the channel key to the channel. The key of course is not sent
         to the client who was removed from the channel. */
@@ -2561,6 +2718,8 @@ void silc_server_remove_from_channels(SilcServer server,
     }
   }
 
+ out:
+  silc_hash_table_list_reset(&htl);
   silc_buffer_free(clidp);
 }
 
@@ -2609,6 +2768,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
 
   /* Remove client from channel's client list */
   silc_hash_table_del(channel->user_list, chl->client);
+  channel->user_count--;
   
   /* If there is no global users on the channel anymore mark the channel
      as local channel. Do not check if the client is local client. */
@@ -2639,14 +2799,16 @@ 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)) {
        silc_hash_table_del(chl2->client->channels, channel);
        silc_hash_table_del(channel->user_list, chl2->client);
+       channel->user_count--;
        silc_free(chl2);
       }
+      silc_hash_table_list_reset(&htl2);
       return FALSE;
     }
 
@@ -2685,13 +2847,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
   /* If we have protocol active we must assure that we call the protocol's
      final callback so that all the memory is freed. */
   if (sock->protocol) {
+    silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
     silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
     return;
   }
 
   if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock);
+    silc_server_free_sock_user_data(server, sock, NULL);
 
   silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                "Connection timeout");
@@ -2733,7 +2897,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 
   channel_name = strdup(channel_name);
 
-  /* Create the channel */
+  /* Create the channel ID */
   if (!silc_id_create_channel_id(server, router_id, server->rng, 
                                 &channel_id)) {
     silc_free(channel_name);
@@ -2741,13 +2905,16 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     silc_hmac_free(newhmac);
     return NULL;
   }
+
+  /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
-                                 NULL, key, newhmac);
+                                 NULL, key, newhmac, 0);
   if (!entry) {
     silc_free(channel_name);
     silc_cipher_free(key);
     silc_hmac_free(newhmac);
+    silc_free(channel_id);
     return NULL;
   }
 
@@ -2757,11 +2924,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   /* Now create the actual key material */
   if (!silc_server_create_channel_key(server, entry, 
                                      silc_cipher_get_key_len(key) / 8)) {
-    silc_free(channel_name);
-    silc_cipher_free(key);
-    silc_hmac_free(newhmac);
-    silc_free(entry->cipher);
-    silc_free(entry->hmac_name);
+    silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
 
@@ -2814,8 +2977,10 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
-                                 NULL, key, newhmac);
+                                 NULL, key, newhmac, 0);
   if (!entry) {
+    silc_cipher_free(key);
+    silc_hmac_free(newhmac);
     silc_free(channel_name);
     return NULL;
   }
@@ -2823,7 +2988,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Now create the actual key material */
   if (!silc_server_create_channel_key(server, entry, 
                                      silc_cipher_get_key_len(key) / 8)) {
-    silc_free(channel_name);
+    silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
 
@@ -2861,11 +3026,11 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
 
 bool silc_server_create_channel_key(SilcServer server, 
                                    SilcChannelEntry channel,
-                                   uint32 key_len)
+                                   SilcUInt32 key_len)
 {
   int i;
   unsigned char channel_key[32], hash[32];
-  uint32 len;
+  SilcUInt32 len;
 
   SILC_LOG_DEBUG(("Generating channel key"));
 
@@ -2875,8 +3040,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;
@@ -2899,8 +3066,7 @@ bool silc_server_create_channel_key(SilcServer server,
 
   /* Save the key */
   channel->key_len = len * 8;
-  channel->key = silc_calloc(len, sizeof(*channel->key));
-  memcpy(channel->key, channel_key, len);
+  channel->key = silc_memdup(channel_key, len);
   memset(channel_key, 0, sizeof(channel_key));
 
   /* Generate HMAC key from the channel key data and set it */
@@ -2923,7 +3089,8 @@ bool silc_server_create_channel_key(SilcServer server,
     channel->rekey->task = 
       silc_schedule_task_add(server->schedule, 0, 
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 3600, 0,
+                            (void *)channel->rekey, 
+                            server->config->channel_rekey_secs, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
   }
@@ -2942,15 +3109,16 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SilcChannelKeyPayload payload = NULL;
   SilcChannelID *id = NULL;
   unsigned char *tmp, hash[32];
-  uint32 tmp_len;
+  SilcUInt32 tmp_len;
   char *cipher;
 
   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"));
+    SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
     channel = NULL;
     goto out;
   }
@@ -2970,7 +3138,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
       if (!channel) {
-       SILC_LOG_ERROR(("Received key for non-existent channel"));
+       SILC_LOG_ERROR(("Received key for non-existent channel %s",
+                       silc_id_render(id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -2997,6 +3166,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;
   }
@@ -3007,8 +3177,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 
   /* Save the key */
   channel->key_len = tmp_len * 8;
-  channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
-  memcpy(channel->key, tmp, tmp_len);
+  channel->key = silc_memdup(tmp, tmp_len);
   silc_cipher_set_key(channel->channel_key, tmp, channel->key_len);
 
   /* Generate HMAC key from the channel key data and set it */
@@ -3032,7 +3201,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     channel->rekey->task = 
       silc_schedule_task_add(server->schedule, 0, 
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 3600, 0,
+                            (void *)channel->rekey, 
+                            server->config->channel_rekey_secs, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
   }
@@ -3054,8 +3224,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
 {
   SilcServerHBContext hb = (SilcServerHBContext)hb_context;
 
-  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname,
-                 sock->ip));
+  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
 
   /* Send the heartbeat */
   silc_server_send_heartbeat(hb->server, sock);
@@ -3111,6 +3280,19 @@ static void silc_server_announce_get_servers(SilcServer server,
   }
 }
 
+static SilcBuffer 
+silc_server_announce_encode_notify(SilcNotifyType notify, SilcUInt32 argc, ...)
+{
+  va_list ap;
+  SilcBuffer p;
+
+  va_start(ap, argc);
+  p = silc_notify_payload_encode(notify, argc, ap);
+  va_end(ap);
+  return p;
+}
+
 /* This function is used by router to announce existing servers to our
    primary router when we've connected to it. If `creation_time' is non-zero
    then only the servers that has been created after the `creation_time'
@@ -3154,12 +3336,15 @@ void silc_server_announce_servers(SilcServer server, bool global,
 static void silc_server_announce_get_clients(SilcServer server,
                                             SilcIDList id_list,
                                             SilcBuffer *clients,
+                                            SilcBuffer *umodes,
                                             unsigned long creation_time)
 {
   SilcIDCacheList list;
   SilcIDCacheEntry id_cache;
   SilcClientEntry client;
   SilcBuffer idp;
+  SilcBuffer tmp;
+  unsigned char mode[4];
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->clients, &list)) {
@@ -3182,6 +3367,20 @@ static void silc_server_announce_get_clients(SilcServer server,
        silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
        silc_buffer_put(*clients, idp->data, idp->len);
        silc_buffer_pull(*clients, idp->len);
+
+       SILC_PUT32_MSB(client->mode, mode);
+       tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+                                                2, idp->data, idp->len,
+                                                mode, 4);
+       *umodes = silc_buffer_realloc(*umodes, 
+                                     (*umodes ? 
+                                      (*umodes)->truelen + tmp->len :  
+                                      tmp->len));
+       silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+       silc_buffer_put(*umodes, tmp->data, tmp->len);
+       silc_buffer_pull(*umodes, tmp->len);
+       silc_buffer_free(tmp);
+
        silc_buffer_free(idp);
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -3203,17 +3402,18 @@ void silc_server_announce_clients(SilcServer server,
                                  SilcSocketConnection remote)
 {
   SilcBuffer clients = NULL;
+  SilcBuffer umodes = NULL;
 
   SILC_LOG_DEBUG(("Announcing clients"));
 
   /* Get clients in local list */
   silc_server_announce_get_clients(server, server->local_list,
-                                  &clients, creation_time);
+                                  &clients, &umodes, creation_time);
 
   /* As router we announce our global list as well */
   if (server->server_type == SILC_ROUTER)
     silc_server_announce_get_clients(server, server->global_list,
-                                    &clients, creation_time);
+                                    &clients, &umodes, creation_time);
 
   if (clients) {
     silc_buffer_push(clients, clients->data - clients->head);
@@ -3226,19 +3426,36 @@ void silc_server_announce_clients(SilcServer server,
 
     silc_buffer_free(clients);
   }
+
+  if (umodes) {
+    silc_buffer_push(umodes, umodes->data - umodes->head);
+    SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, remote,
+                           SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                           umodes->data, umodes->len, TRUE);
+
+    silc_buffer_free(umodes);
+  }
 }
 
-static SilcBuffer 
-silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
-{
-  va_list ap;
-  SilcBuffer p;
+/* Returns channel's topic for announcing it */
 
-  va_start(ap, argc);
-  p = silc_notify_payload_encode(notify, argc, ap);
-  va_end(ap);
-  return p;
+void silc_server_announce_get_channel_topic(SilcServer server,
+                                           SilcChannelEntry channel,
+                                           SilcBuffer *topic)
+{
+  SilcBuffer chidp;
+
+  if (channel->topic) {
+    chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+    *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+                                               chidp->data, chidp->len,
+                                               channel->topic, 
+                                               strlen(channel->topic));
+    silc_buffer_free(chidp);
+  }
 }
 
 /* Returns assembled packets for channel users of the `channel'. */
@@ -3301,6 +3518,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
     silc_buffer_free(clidp);
   }
+  silc_hash_table_list_reset(&htl);
   silc_buffer_free(chidp);
 }
 
@@ -3313,7 +3531,8 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer *channels,
                                       SilcBuffer *channel_users,
                                       SilcBuffer **channel_users_modes,
-                                      uint32 *channel_users_modes_c,
+                                      SilcUInt32 *channel_users_modes_c,
+                                      SilcBuffer **channel_topics,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
@@ -3321,8 +3540,8 @@ void silc_server_announce_get_channels(SilcServer server,
   SilcIDCacheEntry id_cache;
   SilcChannelEntry channel;
   unsigned char *cid;
-  uint32 id_len;
-  uint16 name_len;
+  SilcUInt32 id_len;
+  SilcUInt16 name_len;
   int len;
   int i = *channel_users_modes_c;
   bool announce;
@@ -3363,6 +3582,7 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_buffer_pull(*channels, len);
        }
 
+       /* Channel user modes */
        *channel_users_modes = silc_realloc(*channel_users_modes,
                                            sizeof(**channel_users_modes) * 
                                            (i + 1));
@@ -3372,8 +3592,15 @@ 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;
+
+       /* Channel's topic */
+       *channel_topics = silc_realloc(*channel_topics,
+                                      sizeof(**channel_topics) * (i + 1));
+       (*channel_topics)[i] = NULL;
+       silc_server_announce_get_channel_topic(server, channel,
+                                              &(*channel_topics)[i]);
        i++;
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -3400,7 +3627,8 @@ void silc_server_announce_channels(SilcServer server,
 {
   SilcBuffer channels = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
-  uint32 channel_users_modes_c = 0;
+  SilcBuffer *channel_topics = NULL;
+  SilcUInt32 channel_users_modes_c = 0;
   SilcChannelID **channel_ids = NULL;
 
   SILC_LOG_DEBUG(("Announcing channels and channel users"));
@@ -3410,14 +3638,17 @@ void silc_server_announce_channels(SilcServer server,
                                    &channels, &channel_users,
                                    &channel_users_modes,
                                    &channel_users_modes_c,
+                                   &channel_topics,
                                    &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_topics,
+                                     &channel_ids, creation_time);
 
   if (channels) {
     silc_buffer_push(channels, channels->data - channels->head);
@@ -3450,6 +3681,8 @@ void silc_server_announce_channels(SilcServer server,
     int i;
 
     for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_users_modes[i])
+        continue;
       silc_buffer_push(channel_users_modes[i], 
                       channel_users_modes[i]->data - 
                       channel_users_modes[i]->head);
@@ -3464,8 +3697,32 @@ void silc_server_announce_channels(SilcServer server,
       silc_buffer_free(channel_users_modes[i]);
     }
     silc_free(channel_users_modes);
-    silc_free(channel_ids);
   }
+
+  if (channel_topics) {
+    int i;
+
+    for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_topics[i])
+       continue;
+
+      silc_buffer_push(channel_topics[i], 
+                      channel_topics[i]->data - 
+                      channel_topics[i]->head);
+      SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data, 
+                      channel_topics[i]->len);
+      silc_server_packet_send_dest(server, remote,
+                                  SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                  channel_ids[i], SILC_ID_CHANNEL,
+                                  channel_topics[i]->data, 
+                                  channel_topics[i]->len,
+                                  FALSE);
+      silc_buffer_free(channel_topics[i]);
+    }
+    silc_free(channel_topics);
+  }
+
+  silc_free(channel_ids);
 }
 
 /* Failure timeout callback. If this is called then we will immediately
@@ -3493,18 +3750,19 @@ void silc_server_get_users_on_channel(SilcServer server,
                                      SilcChannelEntry channel,
                                      SilcBuffer *user_list,
                                      SilcBuffer *mode_list,
-                                     uint32 *user_count)
+                                     SilcUInt32 *user_count)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   SilcBuffer idp;
-  uint32 list_count = 0, len = 0;
+  SilcUInt32 list_count = 0, len = 0;
 
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl))
     len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
+  silc_hash_table_list_reset(&htl);
 
   client_id_list = silc_buffer_alloc(len);
   client_mode_list = 
@@ -3526,6 +3784,7 @@ void silc_server_get_users_on_channel(SilcServer server,
 
     list_count++;
   }
+  silc_hash_table_list_reset(&htl);
   silc_buffer_push(client_id_list, 
                   client_id_list->data - client_id_list->head);
   silc_buffer_push(client_mode_list, 
@@ -3544,16 +3803,19 @@ void silc_server_save_users_on_channel(SilcServer server,
                                       SilcClientID *noadd,
                                       SilcBuffer user_list,
                                       SilcBuffer mode_list,
-                                      uint32 user_count)
+                                      SilcUInt32 user_count)
 {
   int i;
+  SilcUInt16 idp_len;
+  SilcUInt32 mode;
+  SilcClientID *client_id;
+  SilcClientEntry client;
+  SilcIDCacheEntry cache;
+  bool global;
 
-  for (i = 0; i < user_count; i++) {
-    uint16 idp_len;
-    uint32 mode;
-    SilcClientID *client_id;
-    SilcClientEntry client;
+  SILC_LOG_DEBUG(("Start"));
 
+  for (i = 0; i < user_count; i++) {
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
     idp_len += 4;
@@ -3570,14 +3832,18 @@ void silc_server_save_users_on_channel(SilcServer server,
       silc_free(client_id);
       continue;
     }
+
+    global = FALSE;
     
     /* Check if we have this client cached already. */
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                          server->server_type, NULL);
-    if (!client)
+                                          server->server_type, &cache);
+    if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list, 
                                             client_id, server->server_type,
-                                            NULL);
+                                            &cache);
+      global = TRUE;
+    }
     if (!client) {
       /* If router did not find such Client ID in its lists then this must
         be bogus client or some router in the net is buggy. */
@@ -3591,7 +3857,7 @@ void silc_server_save_users_on_channel(SilcServer server,
         global. */
       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);
@@ -3599,6 +3865,11 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+    } else {
+      /* Found, if it is from global list we'll assure that we won't
+        expire it now that the entry is on channel. */
+      if (global)
+       cache->expire = 0;
     }
 
     silc_free(client_id);
@@ -3611,6 +3882,7 @@ void silc_server_save_users_on_channel(SilcServer server,
       chl->channel = channel;
       silc_hash_table_add(channel->user_list, chl->client, chl);
       silc_hash_table_add(client->channels, chl->channel, chl);
+      channel->user_count++;
     }
   }
 }
@@ -3622,7 +3894,7 @@ void silc_server_save_users_on_channel(SilcServer server,
 
 SilcSocketConnection silc_server_get_client_route(SilcServer server,
                                                  unsigned char *id_data,
-                                                 uint32 id_len,
+                                                 SilcUInt32 id_len,
                                                  SilcClientID *client_id,
                                                  SilcIDListData *idata)
 {
@@ -3707,8 +3979,8 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   unsigned char *cid;
-  uint32 id_len;
-  uint16 name_len;
+  SilcUInt32 id_len;
+  SilcUInt16 name_len;
   int len;
 
   silc_hash_table_list(client->channels, &htl);
@@ -3738,6 +4010,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
     silc_buffer_pull(buffer, len);
     silc_free(cid);
   }
+  silc_hash_table_list_reset(&htl);
 
   if (buffer)
     silc_buffer_push(buffer, buffer->data - buffer->head);
@@ -3749,10 +4022,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
    it using WHOIS command. */
 
 SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id)
+                                              SilcClientID *client_id,
+                                              bool *resolved)
 {
   SilcClientEntry client;
 
+  if (resolved)
+    *resolved = FALSE;
+
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (!client) {
@@ -3782,6 +4059,10 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(idp);
     silc_buffer_free(buffer);
+
+    if (resolved)
+      *resolved = TRUE;
+
     return NULL;
   }