Merged from silc_1_0_branch.
[silc.git] / apps / silcd / serverconfig.c
index e51039d619484e970556ec1c4765f1d4c85226fe..911caff0dde735085b13ccc4fa628097740cbe6e 100644 (file)
@@ -21,9 +21,7 @@
 
 #include "serverincludes.h"
 #include "server_internal.h"
-
-#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
-#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
+#include <dirent.h>
 
 #if 0
 #define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
   __type__ *findtmp, *tmp = (__type__ *) config->tmp;                  \
   int got_errno = 0
 
+/* allocate the tmp field for fetching data */
+#define SILC_SERVER_CONFIG_ALLOCTMP(__type__)                          \
+  if (!tmp) {                                                          \
+    config->tmp = silc_calloc(1, sizeof(*findtmp));                    \
+    tmp = (__type__ *) config->tmp;                                    \
+  }
+
 /* append the tmp field to the specified list */
 #define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__)                    \
-  if (!__list__)                                                       \
+  if (!__list__) {                                                     \
     __list__ = tmp;                                                    \
-  else {                                                               \
+  } else {                                                             \
     for (findtmp = __list__; findtmp->next; findtmp = findtmp->next);  \
     findtmp->next = tmp;                                               \
   }
     __type__ *di = (__type__ *) tmp;                                   \
     tmp = (void *) di->next;
 
-/* free an authdata according to its auth method */
-static void my_free_authdata(SilcAuthMethod auth_meth, void *auth_data)
+/* Set EDOUBLE error value and bail out if necessary */
+#define CONFIG_IS_DOUBLE(__x__)                                                \
+  if ((__x__)) {                                                       \
+    got_errno = SILC_CONFIG_EDOUBLE;                                   \
+    goto got_err;                                                      \
+  }
+
+/* Free the authentication fields in the specified struct
+ * Expands to two instructions */
+#define CONFIG_FREE_AUTH(__section__)                  \
+  silc_free(__section__->passphrase);                  \
+  if (__section__->publickeys)                         \
+    silc_hash_table_free(__section__->publickeys);
+
+static void my_free_public_key(void *key, void *context, void *user_data)
 {
-  if (auth_meth == SILC_AUTH_PASSWORD) {
-    silc_free(auth_data);
-  } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
-    silc_pkcs_public_key_free((SilcPublicKey) auth_data);
+  silc_pkcs_public_key_free(context);
+}
+
+/* Set default values to those parameters that have not been defined */
+static void
+my_set_param_defaults(SilcServerConfigConnParams *params,
+                     SilcServerConfigConnParams *defaults)
+{
+#define SET_PARAM_DEFAULT(p, d)        params->p =                             \
+  (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
+
+  SET_PARAM_DEFAULT(connections_max, SILC_SERVER_MAX_CONNECTIONS);
+  SET_PARAM_DEFAULT(connections_max_per_host,
+                   SILC_SERVER_MAX_CONNECTIONS_SINGLE);
+  SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_KEEPALIVE);
+  SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_RETRY_COUNT);
+  SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_RETRY_INTERVAL_MIN);
+  SET_PARAM_DEFAULT(reconnect_interval_max, SILC_SERVER_RETRY_INTERVAL_MAX);
+  SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_REKEY);
+  SET_PARAM_DEFAULT(qos_rate_limit, SILC_SERVER_QOS_RATE_LIMIT);
+  SET_PARAM_DEFAULT(qos_bytes_limit, SILC_SERVER_QOS_BYTES_LIMIT);
+  SET_PARAM_DEFAULT(qos_limit_sec, SILC_SERVER_QOS_LIMIT_SEC);
+  SET_PARAM_DEFAULT(qos_limit_usec, SILC_SERVER_QOS_LIMIT_USEC);
+
+#undef SET_PARAM_DEFAULT
+}
+
+/* Find connection parameters by the parameter block name. */
+static SilcServerConfigConnParams *
+my_find_param(SilcServerConfig config, const char *name)
+{
+  SilcServerConfigConnParams *param;
+
+  for (param = config->conn_params; param; param = param->next) {
+    if (!strcasecmp(param->name, name))
+      return param;
   }
+
+  SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                        "Cannot find Params \"%s\".", name));
+
+  return NULL;
 }
 
 /* parse an authdata according to its auth method */
-static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
-                             void **auth_data, uint32 *auth_data_len)
+static bool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
+                             void **auth_data, SilcUInt32 *auth_data_len)
 {
   if (auth_meth == SILC_AUTH_PASSWORD) {
     /* p is a plain text password */
-    *auth_data = (void *) strdup(p);
-    *auth_data_len = (uint32) strlen(p);
+    if (auth_data && auth_data_len) {
+      if (!silc_utf8_valid(p, strlen(p))) {
+       *auth_data_len = silc_utf8_encoded_len(p, strlen(p),
+                                              SILC_STRING_LANGUAGE);
+       *auth_data = silc_calloc(*auth_data_len, sizeof(unsigned char));
+       silc_utf8_encode(p, strlen(p), SILC_STRING_LANGUAGE, *auth_data,
+                        *auth_data_len);
+      } else {
+       *auth_data = (void *) strdup(p);
+       *auth_data_len = (SilcUInt32) strlen(p);
+      }
+    }
   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
-    /* p is a public key */
+    /* p is a public key file name */
     SilcPublicKey public_key;
+    SilcPublicKey cached_key;
 
     if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
       if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
-       fprintf(stderr, "\nError while parsing config file at line %lu: "
-               "Could not load public key file!\n", line);
+       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                              "Could not load public key file!"));
        return FALSE;
       }
-    *auth_data = (void *) public_key;
-    *auth_data_len = 0;
-  } else {
-    fprintf(stderr, "\nError while parsing config file at line %lu: Specify "
-               "the AuthMethod before specifying the AuthData.\n", line);
+
+    if (*auth_data &&
+       silc_hash_table_find_ext(*auth_data, public_key, (void **)&cached_key,
+                                NULL, silc_hash_public_key, NULL,
+                                silc_hash_public_key_compare, NULL)) {
+      silc_pkcs_public_key_free(public_key);
+      SILC_SERVER_LOG_WARNING(("Warning: public key file \"%s\" already "
+                              "configured, ignoring this key", p));
+      return TRUE; /* non fatal error */
+    }
+
+    /* The auth_data is a pointer to the hash table of public keys. */
+    if (auth_data) {
+      if (*auth_data == NULL)
+       *auth_data = silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+                                          NULL, NULL,
+                                          my_free_public_key, NULL,
+                                          TRUE);
+      silc_hash_table_add(*auth_data, public_key, public_key);
+    }
+  } else
+    abort();
+
+  return TRUE;
+}
+
+static bool my_parse_publickeydir(const char *dirname, void **auth_data)
+{
+  int total = 0;
+  struct dirent *get_file;
+  DIR *dp;
+
+  if (!(dp = opendir(dirname))) {
+    SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                          "Could not open directory \"%s\"", dirname));
     return FALSE;
   }
+
+  /* errors are not considered fatal */
+  while ((get_file = readdir(dp))) {
+    const char *filename = get_file->d_name;
+    char buf[1024];
+    int dirname_len = strlen(dirname), filename_len = strlen(filename);
+    struct stat check_file;
+
+    /* Ignore "." and "..", and take files only with ".pub" suffix. */
+    if (!strcmp(filename, ".") || !strcmp(filename, "..") ||
+       (filename_len < 5) || strcmp(filename + filename_len - 4, ".pub"))
+      continue;
+
+    memset(buf, 0, sizeof(buf));
+    snprintf(buf, sizeof(buf) - 1, "%s%s%s", dirname,
+            (dirname[dirname_len - 1] == '/' ? "" : "/"), filename);
+
+    if (stat(buf, &check_file) < 0) {
+      SILC_SERVER_LOG_ERROR(("Error stating file %s: %s", buf,
+                            strerror(errno)));
+    } else if (S_ISREG(check_file.st_mode)) {
+      my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL);
+      total++;
+    }
+  }
+
+  SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname));
   return TRUE;
 }
 
@@ -96,55 +219,135 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
 SILC_CONFIG_CALLBACK(fetch_generic)
 {
   SilcServerConfig config = (SilcServerConfig) context;
+  int got_errno = 0;
 
-  if (!strcmp(name, "modulepath")) {
-    if (config->module_path) return SILC_CONFIG_EDOUBLE;
-    /* dup it only if non-empty, otherwise point it to NULL */
+  if (!strcmp(name, "module_path")) {
+    CONFIG_IS_DOUBLE(config->module_path);
     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
   }
+  else if (!strcmp(name, "prefer_passphrase_auth")) {
+    config->prefer_passphrase_auth = *(bool *)val;
+  }
+  else if (!strcmp(name, "require_reverse_lookup")) {
+    config->require_reverse_lookup = *(bool *)val;
+  }
+  else if (!strcmp(name, "connections_max")) {
+    config->param.connections_max = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "connections_max_per_host")) {
+    config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "keepalive_secs")) {
+    config->param.keepalive_secs = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "reconnect_count")) {
+    config->param.reconnect_count = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval")) {
+    config->param.reconnect_interval = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval_max")) {
+    config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "reconnect_keep_trying")) {
+    config->param.reconnect_keep_trying = *(bool *)val;
+  }
+  else if (!strcmp(name, "key_exchange_rekey")) {
+    config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "key_exchange_pfs")) {
+    config->param.key_exchange_pfs = *(bool *)val;
+  }
+  else if (!strcmp(name, "channel_rekey_secs")) {
+    config->channel_rekey_secs = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "key_exchange_timeout")) {
+    config->key_exchange_timeout = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "conn_auth_timeout")) {
+    config->conn_auth_timeout = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "version_protocol")) {
+    CONFIG_IS_DOUBLE(config->param.version_protocol);
+    config->param.version_protocol =
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software")) {
+    CONFIG_IS_DOUBLE(config->param.version_software);
+    config->param.version_software =
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software_vendor")) {
+    CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
+    config->param.version_software_vendor =
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "detach_disabled")) {
+    config->detach_disabled = *(bool *)val;
+  }
+  else if (!strcmp(name, "detach_timeout")) {
+    config->detach_timeout = (SilcUInt32) *(int *)val;
+  }
+  else if (!strcmp(name, "qos")) {
+    config->param.qos = *(bool *)val;
+  }
+  else if (!strcmp(name, "qos_rate_limit")) {
+    config->param.qos_rate_limit = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_bytes_limit")) {
+    config->param.qos_bytes_limit = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_limit_sec")) {
+    config->param.qos_limit_sec = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_limit_usec")) {
+    config->param.qos_limit_usec = *(SilcUInt32 *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
+
   return SILC_CONFIG_OK;
+
+ got_err:
+  return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_cipher)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionCipher);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher);
 
-  SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->name) {
       got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
-    /* the temporary struct is ok, append it to the list */
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionCipher *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigCipher);
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) { /* can be empty */
-    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    /* dup it only if non-empty, otherwise point it to NULL */
+  else if (!strcmp(name, "module")) {
+    CONFIG_IS_DOUBLE(tmp->module);
     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  else if (!strcmp(name, "key_length"))
-    tmp->key_length = *(uint32 *)val;
-  else if (!strcmp(name, "block_length"))
-    tmp->block_length = *(uint32 *)val;
+  else if (!strcmp(name, "keylength")) {
+    tmp->key_length = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "blocklength")) {
+    tmp->block_length = *(SilcUInt32 *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -159,42 +362,40 @@ SILC_CONFIG_CALLBACK(fetch_cipher)
 
 SILC_CONFIG_CALLBACK(fetch_hash)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHash);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash);
 
-  SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
       got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
-    /* the temporary struct in tmp is ok */
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionHash *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHash);
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) { /* can be empty */
-    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    /* dup it only if non-empty, otherwise point it to NULL */
+  else if (!strcmp(name, "module")) {
+    CONFIG_IS_DOUBLE(tmp->module);
     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  else if (!strcmp(name, "block_length"))
+  else if (!strcmp(name, "blocklength")) {
     tmp->block_length = *(int *)val;
-  else if (!strcmp(name, "digest_length"))
+  }
+  else if (!strcmp(name, "digestlength")) {
     tmp->digest_length = *(int *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -209,39 +410,37 @@ SILC_CONFIG_CALLBACK(fetch_hash)
 
 SILC_CONFIG_CALLBACK(fetch_hmac)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHmac);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac);
 
-  SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
       got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
-    /* the temporary struct is ok, append it to the list */
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionHmac *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHmac);
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
   else if (!strcmp(name, "hash")) {
-    if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->hash);
     tmp->hash = strdup((char *) val);
   }
-  else if (!strcmp(name, "mac_length"))
+  else if (!strcmp(name, "maclength")) {
     tmp->mac_length = *(int *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -256,31 +455,28 @@ SILC_CONFIG_CALLBACK(fetch_hmac)
 
 SILC_CONFIG_CALLBACK(fetch_pkcs)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionPkcs);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs);
 
-  SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->name) {
       got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
-    /* the temporary struct is ok, append it to the list */
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionPkcs *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigPkcs);
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
   else
@@ -296,117 +492,149 @@ SILC_CONFIG_CALLBACK(fetch_pkcs)
 
 SILC_CONFIG_CALLBACK(fetch_serverinfo)
 {
-  SilcServerConfig config = (SilcServerConfig) context;
-  SilcServerConfigSectionServerInfo *server_info = config->server_info;
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServerInfoInterface);
+  SilcServerConfigServerInfo *server_info = config->server_info;
 
   /* if there isn't the struct alloc it */
-  if (!server_info) {
-    config->server_info = server_info = (SilcServerConfigSectionServerInfo *)
+  if (!server_info)
+    config->server_info = server_info = (SilcServerConfigServerInfo *)
                silc_calloc(1, sizeof(*server_info));
-  }
 
   if (type == SILC_CONFIG_ARG_BLOCK) {
-    /* check for mandatory inputs */
+    if (!strcmp(name, "primary")) {
+      CONFIG_IS_DOUBLE(server_info->primary);
+      if (!tmp)
+       return SILC_CONFIG_OK;
+      server_info->primary = tmp;
+      config->tmp = NULL;
+      return SILC_CONFIG_OK;
+    } else if (!strcmp(name, "secondary")) {
+      if (!tmp)
+       return SILC_CONFIG_OK;
+      SILC_SERVER_CONFIG_LIST_APPENDTMP(server_info->secondary);
+      config->tmp = NULL;
+      return SILC_CONFIG_OK;
+    } else if (!server_info->public_key || !server_info->private_key) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
     return SILC_CONFIG_OK;
   }
   if (!strcmp(name, "hostname")) {
-    if (server_info->server_name) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->server_name);
     server_info->server_name = strdup((char *) val);
   }
   else if (!strcmp(name, "ip")) {
-    if (server_info->server_ip) return SILC_CONFIG_EDOUBLE;
-    server_info->server_ip = strdup((char *) val);
+    SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
+    CONFIG_IS_DOUBLE(tmp->server_ip);
+    tmp->server_ip = strdup((char *) val);
   }
   else if (!strcmp(name, "port")) {
     int port = *(int *)val;
+    SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
     if ((port <= 0) || (port > 65535)) {
-      fprintf(stderr, "Invalid port number!\n");
-      return SILC_CONFIG_ESILENT;
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                            "Invalid port number!"));
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
-    server_info->port = (uint16) port;
+    tmp->port = (SilcUInt16) port;
   }
   else if (!strcmp(name, "servertype")) {
-    if (server_info->server_type) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->server_type);
     server_info->server_type = strdup((char *) val);
   }
   else if (!strcmp(name, "admin")) {
-    if (server_info->admin) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->admin);
     server_info->admin = strdup((char *) val);
   }
-  else if (!strcmp(name, "email")) {
-    if (server_info->email) return SILC_CONFIG_EDOUBLE;
+  else if (!strcmp(name, "adminemail")) {
+    CONFIG_IS_DOUBLE(server_info->email);
     server_info->email = strdup((char *) val);
   }
   else if (!strcmp(name, "location")) {
-    if (server_info->location) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->location);
     server_info->location = strdup((char *) val);
   }
   else if (!strcmp(name, "user")) {
-    if (server_info->user) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->user);
     server_info->user = strdup((char *) val);
   }
   else if (!strcmp(name, "group")) {
-    if (server_info->group) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->group);
     server_info->group = strdup((char *) val);
   }
   else if (!strcmp(name, "motdfile")) {
-    if (server_info->motd_file) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->motd_file);
     server_info->motd_file = strdup((char *) val);
   }
   else if (!strcmp(name, "pidfile")) {
-    if (server_info->pid_file) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->pid_file);
     server_info->pid_file = strdup((char *) val);
   }
   else if (!strcmp(name, "publickey")) {
-    char *tmp = (char *) val;
+    char *file_tmp = (char *) val;
+    CONFIG_IS_DOUBLE(server_info->public_key);
 
     /* try to load specified file, if fail stop config parsing */
-    if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
+    if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
                                   SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
+      if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
                                     SILC_PKCS_FILE_BIN)) {
-       fprintf(stderr, "\nError: Could not load public key file.");
-       fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
-       return SILC_CONFIG_ESILENT;
+       SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
+       return SILC_CONFIG_EPRINTLINE;
       }
   }
   else if (!strcmp(name, "privatekey")) {
-    char *tmp = (char *) val;
+    char *file_tmp = (char *) val;
+    CONFIG_IS_DOUBLE(server_info->private_key);
 
     /* try to load specified file, if fail stop config parsing */
-    if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
-                                   SILC_PKCS_FILE_BIN))
-      if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
-                                     SILC_PKCS_FILE_PEM)) {
-       fprintf(stderr, "\nError: Could not load private key file.");
-       fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
-       return SILC_CONFIG_ESILENT;
+    if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
+                                   "", 0, SILC_PKCS_FILE_BIN))
+      if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
+                                     "", 0, SILC_PKCS_FILE_PEM)) {
+       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
+       return SILC_CONFIG_EPRINTLINE;
       }
   }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp);
+  silc_free(config->tmp);
+  config->tmp = NULL;
+  return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_logging)
 {
-  SilcServerConfig config = (SilcServerConfig) context;
-  SilcServerConfigSectionLogging *tmp =
-       (SilcServerConfigSectionLogging *) config->tmp;
-  int got_errno;
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
 
-  if (!strcmp(name, "quicklogs")) {
-    silc_log_quick = *(bool *)val;
+  if (!strcmp(name, "timestamp")) {
+    config->logging_timestamp = *(bool *)val;
+  }
+  else if (!strcmp(name, "quicklogs")) {
+    config->logging_quick = *(bool *)val;
   }
   else if (!strcmp(name, "flushdelay")) {
     int flushdelay = *(int *)val;
     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
-      fprintf(stderr, "Error: line %lu: invalid flushdelay value, use "
-               "quicklogs if you want real-time logging.\n", line);
-      return SILC_CONFIG_ESILENT;
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                           "Invalid flushdelay value, use quicklogs if you "
+                           "want real-time logging."));
+      return SILC_CONFIG_EPRINTLINE;
     }
-    silc_log_flushdelay = (long) flushdelay;
+    config->logging_flushdelay = (long) flushdelay;
   }
+
+  /* The following istances happens only in Logging's sub-blocks, a match
+     for the sub-block name means that you should store the filename/maxsize
+     temporary struct to the proper logging channel.
+     If we get a match for "file" or "maxsize" this means that we are inside
+     a sub-sub-block and it is safe to alloc a new tmp. */
 #define FETCH_LOGGING_CHAN(__chan__, __member__)               \
   else if (!strcmp(name, __chan__)) {                          \
     if (!tmp) return SILC_CONFIG_OK;                           \
@@ -422,21 +650,16 @@ SILC_CONFIG_CALLBACK(fetch_logging)
   FETCH_LOGGING_CHAN("fatals", logging_fatals)
 #undef FETCH_LOGGING_CHAN
   else if (!strcmp(name, "file")) {
-    if (!tmp) { /* FIXME: what the fuck is this? */
-      config->tmp = silc_calloc(1, sizeof(*tmp));
-      tmp = (SilcServerConfigSectionLogging *) config->tmp;
-    }
-    if (tmp->file) {
-      got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
-    }
+    SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigLogging);
+    CONFIG_IS_DOUBLE(tmp->file);
     tmp->file = strdup((char *) val);
   }
   else if (!strcmp(name, "size")) {
     if (!tmp) {
       config->tmp = silc_calloc(1, sizeof(*tmp));
-      tmp = (SilcServerConfigSectionLogging *) config->tmp;
+      tmp = (SilcServerConfigLogging *) config->tmp;
     }
-    tmp->maxsize = *(uint32 *) val;
+    tmp->maxsize = *(SilcUInt32 *) val;
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -449,63 +672,154 @@ SILC_CONFIG_CALLBACK(fetch_logging)
   return got_errno;
 }
 
-SILC_CONFIG_CALLBACK(fetch_client)
+SILC_CONFIG_CALLBACK(fetch_connparam)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
 
-  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
-    if (!tmp) /* empty sub-block? */
+    /* check the temporary struct's fields */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
-    if (tmp->auth_meth && !tmp->auth_data) {
-      fprintf(stderr, "\nError: line %lu: If you specify \"AuthMethod\" field "
-               "then you must also specify the \"AuthData\" field.\n", line);
-      got_errno = SILC_CONFIG_ESILENT;
+    if (!tmp->name) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
-    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
+    /* Set defaults */
+    my_set_param_defaults(tmp, &config->param);
+
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionClient *) config->tmp;
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigConnParams);
+
+  if (!strcmp(name, "name")) {
+    CONFIG_IS_DOUBLE(tmp->name);
+    tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "connections_max")) {
+    tmp->connections_max = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "connections_max_per_host")) {
+    tmp->connections_max_per_host = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "keepalive_secs")) {
+    tmp->keepalive_secs = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_count")) {
+    tmp->reconnect_count = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval")) {
+    tmp->reconnect_interval = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval_max")) {
+    tmp->reconnect_interval_max = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_keep_trying")) {
+    tmp->reconnect_keep_trying = *(bool *)val;
+  }
+  else if (!strcmp(name, "key_exchange_rekey")) {
+    tmp->key_exchange_rekey = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "key_exchange_pfs")) {
+    tmp->key_exchange_pfs = *(bool *)val;
+  }
+  else if (!strcmp(name, "version_protocol")) {
+    CONFIG_IS_DOUBLE(tmp->version_protocol);
+    tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software")) {
+    CONFIG_IS_DOUBLE(tmp->version_software);
+    tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software_vendor")) {
+    CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
+    tmp->version_software_vendor =
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "anonymous")) {
+    tmp->anonymous = *(bool *)val;
+  }
+  else if (!strcmp(name, "qos")) {
+    tmp->qos = *(bool *)val;
+  }
+  else if (!strcmp(name, "qos_rate_limit")) {
+    tmp->qos_rate_limit = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_bytes_limit")) {
+    tmp->qos_bytes_limit = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_limit_sec")) {
+    tmp->qos_limit_sec = *(SilcUInt32 *)val;
+  }
+  else if (!strcmp(name, "qos_limit_usec")) {
+    tmp->qos_limit_usec = *(SilcUInt32 *)val;
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
+
+SILC_CONFIG_CALLBACK(fetch_client)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
+
+  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
+
+  /* Alloc before block checking, because empty sub-blocks are welcome here */
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigClient);
+
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* empty sub-blocks are welcome */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
   }
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  /* get authentication method */
-  else if (!strcmp(name, "authmethod")) {
-    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-      tmp->auth_meth = SILC_AUTH_PASSWORD;
-    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
-    else {
-      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+  else if (!strcmp(name, "passphrase")) {
+    CONFIG_IS_DOUBLE(tmp->passphrase);
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
+                          (void **)&tmp->passphrase,
+                          &tmp->passphrase_len)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
-  else if (!strcmp(name, "authdata")) {
-    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
-                          &tmp->auth_data, &tmp->auth_data_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
-      goto got_err; /* error outputted in my_parse_authdata */
+  else if (!strcmp(name, "publickey")) {
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
+                          (void **)&tmp->publickeys, NULL)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
-  else if (!strcmp(name, "port")) {
-    int port = *(int *)val;
-    if ((port <= 0) || (port > 65535)) {
-      fprintf(stderr, "Invalid port number!\n");
-      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+  else if (!strcmp(name, "publickeydir")) {
+    if (!my_parse_publickeydir((char *) val, (void **)&tmp->publickeys)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
-    tmp->port = (uint16) port;
   }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
+  else if (!strcmp(name, "params")) {
+    CONFIG_IS_DOUBLE(tmp->param);
+    tmp->param = my_find_param(config, (char *) val);
+    if (!tmp->param) { /* error message already output */
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -513,61 +827,62 @@ SILC_CONFIG_CALLBACK(fetch_client)
 
  got_err:
   silc_free(tmp->host);
-  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  CONFIG_FREE_AUTH(tmp);
   silc_free(tmp);
+  config->tmp = NULL;
   return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_admin)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
 
-  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
-    if (!tmp->auth_meth) {
-      got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
-    }
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionAdmin *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigAdmin);
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "user")) {
-    if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->user);
     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "nick")) {
-    if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->nick);
     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  /* get authentication method */
-  else if (!strcmp(name, "authmethod")) {
-    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-      tmp->auth_meth = SILC_AUTH_PASSWORD;
-    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
-    else {
-      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+  else if (!strcmp(name, "passphrase")) {
+    CONFIG_IS_DOUBLE(tmp->passphrase);
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
+                          (void **)&tmp->passphrase,
+                          &tmp->passphrase_len)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
+  }
+  else if (!strcmp(name, "publickey")) {
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
+                          (void **)&tmp->publickeys, NULL)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
-  else if (!strcmp(name, "authdata")) {
-    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
-                          &tmp->auth_data, &tmp->auth_data_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
-      goto got_err; /* error outputted in my_parse_authdata */
+  else if (!strcmp(name, "publickeydir")) {
+    if (!my_parse_publickeydir((char *) val, (void **)&tmp->publickeys)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
   else
@@ -578,49 +893,40 @@ SILC_CONFIG_CALLBACK(fetch_admin)
   silc_free(tmp->host);
   silc_free(tmp->user);
   silc_free(tmp->nick);
-  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  CONFIG_FREE_AUTH(tmp);
   silc_free(tmp);
+  config->tmp = NULL;
   return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_deny)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
 
-  SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->reason) {
       got_errno = SILC_CONFIG_EMISSFIELDS;
       goto got_err;
     }
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionDeny *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny);
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
   }
-  else if (!strcmp(name, "port")) {
-    int port = *(int *)val;
-    if ((port <= 0) || (port > 65535)) {
-      fprintf(stderr, "Invalid port number!\n");
-      got_errno = SILC_CONFIG_ESILENT; goto got_err;
-    }
-    tmp->port = (uint16) port;
-  }
   else if (!strcmp(name, "reason")) {
-    if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->reason);
     tmp->reason = strdup((char *) val);
   }
   else
@@ -631,191 +937,216 @@ SILC_CONFIG_CALLBACK(fetch_deny)
   silc_free(tmp->host);
   silc_free(tmp->reason);
   silc_free(tmp);
+  config->tmp = NULL;
   return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_server)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
 
-  SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check the temporary struct's fields */
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
-    if (!tmp->auth_meth || !tmp->version) {
-      got_errno = SILC_CONFIG_EMISSFIELDS;
-      goto got_err;
-    }
+
     /* the temporary struct is ok, append it to the list */
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionServer *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer);
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
   }
-  /* get authentication method */
-  else if (!strcmp(name, "authmethod")) {
-    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-      tmp->auth_meth = SILC_AUTH_PASSWORD;
-    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
-    else {
-      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+  else if (!strcmp(name, "passphrase")) {
+    CONFIG_IS_DOUBLE(tmp->passphrase);
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
+                          (void **)&tmp->passphrase,
+                          &tmp->passphrase_len)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
-  else if (!strcmp(name, "authdata")) {
-    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
-                          &tmp->auth_data, &tmp->auth_data_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
-      goto got_err; /* error outputted in my_parse_authdata */
+  else if (!strcmp(name, "publickey")) {
+    CONFIG_IS_DOUBLE(tmp->publickeys);
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
+                          (void **)&tmp->publickeys, NULL)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
   }
-  else if (!strcmp(name, "port")) {
-    int port = *(int *)val;
-    if ((port <= 0) || (port > 65535)) {
-      fprintf(stderr, "Invalid port number!\n");
-      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+  else if (!strcmp(name, "params")) {
+    CONFIG_IS_DOUBLE(tmp->param);
+    tmp->param = my_find_param(config, (char *) val);
+    if (!tmp->param) { /* error message already output */
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
-    tmp->port = (uint16) port;
-  }
-  else if (!strcmp(name, "versionid")) {
-    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    tmp->version = strdup((char *) val);
-  }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
   }
   else if (!strcmp(name, "backup")) {
     tmp->backup_router = *(bool *)val;
   }
   else
     return SILC_CONFIG_EINTERNAL;
+
   return SILC_CONFIG_OK;
 
  got_err:
   silc_free(tmp->host);
-  silc_free(tmp->version);
-  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  CONFIG_FREE_AUTH(tmp);
   silc_free(tmp);
+  config->tmp = NULL;
   return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_router)
 {
-  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionRouter);
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
 
-  SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", type, name, context));
+  SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
+                      type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
-    if (!tmp) /* empty sub-block? */
+    if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
-    if (!tmp->auth_meth || !tmp->version) {
-      got_errno = SILC_CONFIG_EMISSFIELDS;
-      goto got_err;
-    }
-    /* the temporary struct is ok, append it to the list */
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
-  /* if there isn't a temporary struct alloc one */
-  if (!tmp) {
-    config->tmp = silc_calloc(1, sizeof(*findtmp));
-    tmp = (SilcServerConfigSectionRouter *) config->tmp;
-  }
+  SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigRouter);
 
   /* Identify and save this value */
   if (!strcmp(name, "host")) {
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = strdup((char *) val);
   }
-  else if (!strcmp(name, "authmethod")) {
-    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-      tmp->auth_meth = SILC_AUTH_PASSWORD;
-    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
-    else {
-      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
-    }
-  }
-  else if (!strcmp(name, "authdata")) {
-    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
-                          &tmp->auth_data, &tmp->auth_data_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
-      goto got_err; /* error outputted in my_parse_authdata */
-    }
-  }
   else if (!strcmp(name, "port")) {
     int port = *(int *)val;
     if ((port <= 0) || (port > 65535)) {
-      fprintf(stderr, "Invalid port number!\n");
-      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                            "Invalid port number!"));
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
+    tmp->port = (SilcUInt16) port;
+  }
+  else if (!strcmp(name, "passphrase")) {
+    CONFIG_IS_DOUBLE(tmp->passphrase);
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
+                          (void **)&tmp->passphrase,
+                          &tmp->passphrase_len)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
     }
-    tmp->port = (uint16) port;
   }
-  else if (!strcmp(name, "versionid")) {
-    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    tmp->version = strdup((char *) val);
+  else if (!strcmp(name, "publickey")) {
+    CONFIG_IS_DOUBLE(tmp->publickeys);
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
+                          (void **)&tmp->publickeys, NULL)) {
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
   }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
+  else if (!strcmp(name, "params")) {
+    CONFIG_IS_DOUBLE(tmp->param);
+    tmp->param = my_find_param(config, (char *) val);
+    if (!tmp->param) { /* error message already output */
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
   }
-  else if (!strcmp(name, "initiator"))
+  else if (!strcmp(name, "initiator")) {
     tmp->initiator = *(bool *)val;
+  }
   else if (!strcmp(name, "backuphost")) {
-    if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
+    CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
+    tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
+                             strdup("*"));
+    tmp->backup_router = TRUE;
+  }
+  else if (!strcmp(name, "backupport")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                            "Invalid port number!"));
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
+    tmp->backup_replace_port = (SilcUInt16) port;
+  }
+  else if (!strcmp(name, "backuplocal")) {
+    tmp->backup_local = *(bool *)val;
   }
   else
     return SILC_CONFIG_EINTERNAL;
+
   return SILC_CONFIG_OK;
 
  got_err:
   silc_free(tmp->host);
-  silc_free(tmp->version);
   silc_free(tmp->backup_replace_ip);
-  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  CONFIG_FREE_AUTH(tmp);
   silc_free(tmp);
+  config->tmp = NULL;
   return got_errno;
 }
 
 /* known config options tables */
 static const SilcConfigTable table_general[] = {
-  { "modulepath",      SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { "module_path",             SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { "prefer_passphrase_auth",  SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic, NULL },
+  { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_interval",              SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,   fetch_generic,  NULL },
+  { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "key_exchange_pfs",                SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "channel_rekey_secs",      SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "key_exchange_timeout",    SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "conn_auth_timeout",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "version_protocol",                SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "version_software",                SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "detach_disabled",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "detach_timeout",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos",                     SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "qos_rate_limit",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_cipher[] = {
   { "name",            SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
   { "module",          SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
-  { "key_length",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
-  { "block_length",    SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
+  { "keylength",       SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
+  { "blocklength",     SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_hash[] = {
   { "name",            SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
   { "module",          SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
-  { "block_length",    SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
-  { "digest_length",   SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
+  { "blocklength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
+  { "digestlength",    SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_hmac[] = {
   { "name",            SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
   { "hash",            SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
-  { "mac_length",      SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
+  { "maclength",       SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -824,14 +1155,20 @@ static const SilcConfigTable table_pkcs[] = {
   { 0, 0, 0, 0 }
 };
 
-static const SilcConfigTable table_serverinfo[] = {
-  { "hostname",                SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+static const SilcConfigTable table_serverinfo_c[] = {
   { "ip",              SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "port",            SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
+  { 0, 0, 0, 0 }
+};
+
+static const SilcConfigTable table_serverinfo[] = {
+  { "hostname",                SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "primary",         SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
+  { "secondary",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
   { "servertype",      SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "location",                SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "admin",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
-  { "email",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "adminemail",      SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "user",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "group",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
   { "publickey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
@@ -849,6 +1186,7 @@ static const SilcConfigTable table_logging_c[] = {
 };
 
 static const SilcConfigTable table_logging[] = {
+  { "timestamp",       SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
   { "quicklogs",       SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
   { "flushdelay",      SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
   { "info",            SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
@@ -858,21 +1196,36 @@ static const SilcConfigTable table_logging[] = {
   { 0, 0, 0, 0 }
 };
 
-/* still unsupported
-static const SilcConfigTable table_class[] = {
-  { "name",            SILC_CONFIG_ARG_STR,    fetch_class,    NULL },
-  { "ping",            SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
-  { "connect",         SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
-  { "links",           SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
+static const SilcConfigTable table_connparam[] = {
+  { "name",                   SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
+  { "connections_max",        SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "keepalive_secs",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "reconnect_count",        SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
+  { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
+  { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
+  { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
+  { "key_exchange_pfs",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
+  { "version_protocol",               SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "version_software",               SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam,        NULL },
+  { "anonymous",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
+  { "qos",                    SILC_CONFIG_ARG_TOGGLE,  fetch_generic,  NULL },
+  { "qos_rate_limit",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { 0, 0, 0, 0 }
-}; */
+};
 
 static const SilcConfigTable table_client[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
-  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
-  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
-  { "port",            SILC_CONFIG_ARG_INT,    fetch_client,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "publickey",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "publickeydir",    SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "params",          SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -880,122 +1233,271 @@ static const SilcConfigTable table_admin[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
   { "user",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
   { "nick",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
-  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
-  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "publickey",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "publickeydir",    SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
   { "port",            SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "params",          SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_deny[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
-  { "port",            SILC_CONFIG_ARG_INT,    fetch_deny,     NULL },
   { "reason",          SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_serverconn[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
-  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
-  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
-  { "port",            SILC_CONFIG_ARG_INT,    fetch_server,   NULL },
-  { "versionid",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "publickey",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "params",          SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
   { "backup",          SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_routerconn[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
-  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
-  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
   { "port",            SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
-  { "versionid",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "publickey",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "params",          SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
   { "initiator",       SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
   { "backuphost",      SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
   { "backupport",      SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
-  { "localbackup",     SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
+  { "backuplocal",     SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
   { 0, 0, 0, 0 }
 };
 
 static const SilcConfigTable table_main[] = {
-  { "general",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_general },
-  { "cipher",          SILC_CONFIG_ARG_BLOCK,  fetch_cipher,   table_cipher },
-  { "hash",            SILC_CONFIG_ARG_BLOCK,  fetch_hash,     table_hash },
-  { "hmac",            SILC_CONFIG_ARG_BLOCK,  fetch_hmac,     table_hmac },
-  { "pkcs",            SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,     table_pkcs },
+  { "cipher",          SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
+  { "hash",            SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
+  { "hmac",            SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
+  { "pkcs",            SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
+  { "general",         SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
   { "serverinfo",      SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
-  { "logging",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_logging },
-/*{ "class",           SILC_CONFIG_ARG_BLOCK,  fetch_class,    table_class }, */
-  { "client",          SILC_CONFIG_ARG_BLOCK,  fetch_client,   table_client },
-  { "admin",           SILC_CONFIG_ARG_BLOCK,  fetch_admin,    table_admin },
-  { "deny",            SILC_CONFIG_ARG_BLOCK,  fetch_deny,     table_deny },
-  { "serverconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_server,   table_serverconn },
-  { "routerconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_router,   table_routerconn },
+  { "logging",         SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
+  { "connectionparams",        SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
+  { "client",          SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
+  { "admin",           SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
+  { "deny",            SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
+  { "serverconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
+  { "routerconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
   { 0, 0, 0, 0 }
 };
 
+/* Set default values to stuff that was not configured. */
+
+static void silc_server_config_set_defaults(SilcServerConfig config)
+{
+  my_set_param_defaults(&config->param, NULL);
+
+  config->channel_rekey_secs = (config->channel_rekey_secs ?
+                               config->channel_rekey_secs :
+                               SILC_SERVER_CHANNEL_REKEY);
+  config->key_exchange_timeout = (config->key_exchange_timeout ?
+                                 config->key_exchange_timeout :
+                                 SILC_SERVER_SKE_TIMEOUT);
+  config->conn_auth_timeout = (config->conn_auth_timeout ?
+                              config->conn_auth_timeout :
+                              SILC_SERVER_CONNAUTH_TIMEOUT);
+}
+
+/* Check for correctness of the configuration */
+
+static bool silc_server_config_check(SilcServerConfig config)
+{
+  bool ret = TRUE;
+  SilcServerConfigServer *s;
+  SilcServerConfigRouter *r;
+  bool b = FALSE;
+
+  /* ServerConfig is mandatory */
+  if (!config->server_info) {
+    SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `ServerInfo'"));
+    ret = FALSE;
+  }
+
+  /* RouterConnection sanity checks */
+
+  if (config->routers && config->routers->backup_router == TRUE &&
+      !config->servers) {
+    SILC_SERVER_LOG_ERROR((
+         "\nError: First RouterConnection block must be primary router "
+        "connection. You have marked it incorrectly as backup router."));
+    ret = FALSE;
+  }
+  if (config->routers && config->routers->initiator == FALSE &&
+      config->routers->backup_router == FALSE) {
+    SILC_SERVER_LOG_ERROR((
+         "\nError: First RouterConnection block must be primary router "
+        "connection and it must be marked as Initiator."));
+    ret = FALSE;
+  }
+  if (config->routers && config->routers->backup_router == TRUE &&
+      !config->servers && !config->routers->next) {
+    SILC_SERVER_LOG_ERROR((
+         "\nError: You have configured backup router but not primary router. "
+        "If backup router is configured also primary router must be "
+        "configured."));
+    ret = FALSE;
+  }
+
+  /* Backup router sanity checks */
+
+  for (r = config->routers; r; r = r->next) {
+    if (r->backup_router && !strcmp(r->host, r->backup_replace_ip)) {
+      SILC_SERVER_LOG_ERROR((
+          "\nError: Backup router connection incorrectly configured to use "
+         "primary and backup router as same host `%s'. They must not be "
+         "same host.", r->host));
+      ret = FALSE;
+    }
+  }
+  
+  /* ServerConnection sanity checks */
+  
+  for (s = config->servers; s; s = s->next) {
+    if (s->backup_router) {
+      b = TRUE;
+      break;
+    }
+  }
+  if (b) {
+    for (s = config->servers; s; s = s->next) {
+      if (!s->backup_router) {
+       SILC_SERVER_LOG_ERROR((
+          "\nError: Your server is backup router but not all ServerConnection "
+         "blocks were marked as backup connections. They all must be "
+         "marked as backup connections."));
+       ret = FALSE;
+       break;
+      }
+    }
+  }
+
+  return ret;
+}
+
 /* Allocates a new configuration object, opens configuration file and
- * parses it. The parsed data is returned to the newly allocated
- * configuration object. */
+   parses it. The parsed data is returned to the newly allocated
+   configuration object. The SilcServerConfig must be freed by calling
+   the silc_server_config_destroy function. */
 
-SilcServerConfig silc_server_config_alloc(char *filename)
+SilcServerConfig silc_server_config_alloc(const char *filename)
 {
-  SilcServerConfig config;
+  SilcServerConfig config_new;
   SilcConfigEntity ent;
   SilcConfigFile *file;
   int ret;
   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
 
   /* alloc a config object */
-  config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
+  config_new = silc_calloc(1, sizeof(*config_new));
+  if (!config_new)
+    return NULL;
+
+  /* general config defaults */
+  config_new->refcount = 1;
+  config_new->logging_timestamp = TRUE;
+
   /* obtain a config file object */
   file = silc_config_open(filename);
   if (!file) {
-    fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
+    SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'",
+                          filename));
     return NULL;
   }
+
   /* obtain a SilcConfig entity, we can use it to start the parsing */
   ent = silc_config_init(file);
+
   /* load the known configuration options, give our empty object as context */
-  silc_config_register_table(ent, table_main, (void *) config);
+  silc_config_register_table(ent, table_main, (void *) config_new);
+
   /* enter the main parsing loop.  When this returns, we have the parsing
    * result and the object filled (or partially, in case of errors). */
   ret = silc_config_main(ent);
-  SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, silc_config_strerror(ret)));
+  SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
+                 silc_config_strerror(ret)));
 
   /* Check if the parser returned errors */
   if (ret) {
     /* handle this special error return which asks to quietly return */
     if (ret != SILC_CONFIG_ESILENT) {
       char *linebuf, *filename = silc_config_get_filename(file);
-      uint32 line = silc_config_get_line(file);
-      fprintf(stderr, "\nError while parsing config file: %s.\n",
-               silc_config_strerror(ret));
+      SilcUInt32 line = silc_config_get_line(file);
+      if (ret != SILC_CONFIG_EPRINTLINE)
+        SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.",
+                              silc_config_strerror(ret)));
       linebuf = silc_config_read_line(file, line);
-      fprintf(stderr, "  file %s line %lu:  %s\n\n", filename, line, linebuf);
-      silc_free(linebuf);
+      if (linebuf) {
+       SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
+                              line, linebuf));
+       silc_free(linebuf);
+      }
     }
+    silc_server_config_destroy(config_new);
     return NULL;
   }
+
   /* close (destroy) the file object */
   silc_config_close(file);
 
-  /* XXX FIXME: check for missing mandatory fields */
-  if (!config->server_info) {
-    fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
+  /* Check the configuration */
+  if (!silc_server_config_check(config_new)) {
+    silc_server_config_destroy(config_new);
     return NULL;
   }
-  return config;
+
+  /* Set default to configuration parameters */
+  silc_server_config_set_defaults(config_new);
+
+  return config_new;
 }
 
-/* ... */
+/* Increments the reference counter of a config object */
+
+void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
+                           void *ref_ptr)
+{
+  if (ref_ptr) {
+    config->refcount++;
+    ref->config = config;
+    ref->ref_ptr = ref_ptr;
+    SILC_LOG_DEBUG(("Referencing config [%p] refcnt %d->%d", config,
+                   config->refcount - 1, config->refcount));
+  }
+}
+
+/* Decrements the reference counter of a config object.  If the counter
+   reaches 0, the config object is destroyed. */
+
+void silc_server_config_unref(SilcServerConfigRef *ref)
+{
+  if (ref->ref_ptr)
+    silc_server_config_destroy(ref->config);
+}
+
+/* Destroy a config object with all his children lists */
 
 void silc_server_config_destroy(SilcServerConfig config)
 {
   void *tmp;
+
+  config->refcount--;
+  SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %d->%d", config,
+                 config->refcount + 1, config->refcount));
+  if (config->refcount > 0)
+    return;
+
+  SILC_LOG_DEBUG(("Freeing config context"));
+
+  /* Destroy general config stuff */
   silc_free(config->module_path);
+  silc_free(config->param.version_protocol);
+  silc_free(config->param.version_software);
+  silc_free(config->param.version_software_vendor);
 
   /* Destroy Logging channels */
   if (config->logging_info)
@@ -1006,12 +1508,24 @@ void silc_server_config_destroy(SilcServerConfig config)
     silc_free(config->logging_errors->file);
   if (config->logging_fatals)
     silc_free(config->logging_fatals->file);
+  silc_free(config->logging_info);
+  silc_free(config->logging_warnings);
+  silc_free(config->logging_errors);
+  silc_free(config->logging_fatals);
 
   /* Destroy the ServerInfo struct */
   if (config->server_info) {
-    register SilcServerConfigSectionServerInfo *si = config->server_info;
+    register SilcServerConfigServerInfo *si = config->server_info;
     silc_free(si->server_name);
-    silc_free(si->server_ip);
+    if (si->primary) {
+      silc_free(si->primary->server_ip);
+      silc_free(si->primary);
+    }
+    SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServerInfoInterface,
+                                 si->secondary)
+      silc_free(di->server_ip);
+      silc_free(di);
+    }
     silc_free(si->server_type);
     silc_free(si->location);
     silc_free(si->admin);
@@ -1020,63 +1534,74 @@ void silc_server_config_destroy(SilcServerConfig config)
     silc_free(si->group);
     silc_free(si->motd_file);
     silc_free(si->pid_file);
+    silc_pkcs_public_key_free(si->public_key);
+    silc_pkcs_private_key_free(si->private_key);
+    silc_free(si);
   }
 
   /* Now let's destroy the lists */
 
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher,
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
                                  config->cipher)
     silc_free(di->name);
     silc_free(di->module);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHash, config->hash)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
     silc_free(di->name);
     silc_free(di->module);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHmac, config->hmac)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
     silc_free(di->name);
     silc_free(di->hash);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionPkcs, config->pkcs)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
     silc_free(di->name);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionClient,
-                                 config->clients)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
+                                  config->conn_params)
+    silc_free(di->name);
+    silc_free(di->version_protocol);
+    silc_free(di->version_software);
+    silc_free(di->version_software_vendor);
+    silc_free(di);
+  }
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
     silc_free(di->host);
-    my_free_authdata(di->auth_meth, di->auth_data);
+    CONFIG_FREE_AUTH(di);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
     silc_free(di->host);
     silc_free(di->user);
     silc_free(di->nick);
-    my_free_authdata(di->auth_meth, di->auth_data);
+    CONFIG_FREE_AUTH(di);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied)
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
     silc_free(di->host);
     silc_free(di->reason);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer,
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
                                  config->servers)
     silc_free(di->host);
-    silc_free(di->version);
-    my_free_authdata(di->auth_meth, di->auth_data);
+    CONFIG_FREE_AUTH(di);
     silc_free(di);
   }
-  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter,
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
                                  config->routers)
     silc_free(di->host);
-    silc_free(di->version);
     silc_free(di->backup_replace_ip);
-    my_free_authdata(di->auth_meth, di->auth_data);
+    CONFIG_FREE_AUTH(di);
     silc_free(di);
   }
+
+  memset(config, 'F', sizeof(*config));
+  silc_free(config);
 }
 
 /* Registers configured ciphers. These can then be allocated by the
@@ -1085,7 +1610,7 @@ void silc_server_config_destroy(SilcServerConfig config)
 bool silc_server_config_register_ciphers(SilcServer server)
 {
   SilcServerConfig config = server->config;
-  SilcServerConfigSectionCipher *cipher = config->cipher;
+  SilcServerConfigCipher *cipher = config->cipher;
   char *module_path = config->module_path;
 
   SILC_LOG_DEBUG(("Registering configured ciphers"));
@@ -1100,7 +1625,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
       int i;
       for (i = 0; silc_default_ciphers[i].name; i++)
        if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
-         silc_cipher_register(&silc_default_ciphers[i]);
+         silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
          break;
        }
       if (!silc_cipher_is_supported(cipher->name)) {
@@ -1113,7 +1638,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
       /* Load (try at least) the crypto SIM module */
       char buf[1023], *alg_name;
       SilcCipherObject cipher_obj;
-      SilcSimContext *sim;
+      SilcSim sim;
 
       memset(&cipher_obj, 0, sizeof(cipher_obj));
       cipher_obj.name = cipher->name;
@@ -1123,9 +1648,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
       /* build the libname */
       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
                cipher->module);
-      sim = silc_sim_alloc();
-      sim->type = SILC_SIM_CIPHER;
-      sim->libname = buf;
+      sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
 
       alg_name = strdup(cipher->name);
       if (strchr(alg_name, '-'))
@@ -1137,9 +1660,11 @@ bool silc_server_config_register_ciphers(SilcServer server)
                                                SILC_CIPHER_SIM_SET_KEY));
        SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
        cipher_obj.set_key_with_string =
-         silc_sim_getsym(sim, silc_sim_symname(alg_name,
-                                               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
-       SILC_LOG_DEBUG(("set_key_with_string=%p", cipher_obj.set_key_with_string));
+         silc_sim_getsym(sim,
+           silc_sim_symname(alg_name,
+             SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
+       SILC_LOG_DEBUG(("set_key_with_string=%p",
+         cipher_obj.set_key_with_string));
        cipher_obj.encrypt =
          silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_ENCRYPT_CBC));
@@ -1159,6 +1684,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
        silc_free(alg_name);
       } else {
        SILC_LOG_ERROR(("Error configuring ciphers"));
+        silc_sim_free(sim);
        silc_server_stop(server);
        exit(1);
       }
@@ -1184,7 +1710,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
 bool silc_server_config_register_hashfuncs(SilcServer server)
 {
   SilcServerConfig config = server->config;
-  SilcServerConfigSectionHash *hash = config->hash;
+  SilcServerConfigHash *hash = config->hash;
   char *module_path = config->module_path;
 
   SILC_LOG_DEBUG(("Registering configured hash functions"));
@@ -1199,7 +1725,7 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
       int i;
       for (i = 0; silc_default_hash[i].name; i++)
        if (!strcmp(silc_default_hash[i].name, hash->name)) {
-         silc_hash_register(&silc_default_hash[i]);
+         silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
          break;
        }
       if (!silc_hash_is_supported(hash->name)) {
@@ -1211,16 +1737,14 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
 #ifdef SILC_SIM
       /* Load (try at least) the hash SIM module */
       SilcHashObject hash_obj;
-      SilcSimContext *sim;
+      SilcSim sim;
 
       memset(&hash_obj, 0, sizeof(hash_obj));
       hash_obj.name = hash->name;
       hash_obj.block_len = hash->block_length;
       hash_obj.hash_len = hash->digest_length;
 
-      sim = silc_sim_alloc();
-      sim->type = SILC_SIM_HASH;
-      sim->libname = hash->module;
+      sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
 
       if ((silc_sim_load(sim))) {
        hash_obj.init =
@@ -1244,6 +1768,7 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
        silc_dlist_add(server->sim, sim);
       } else {
        SILC_LOG_ERROR(("Error configuring hash functions"));
+        silc_sim_free(sim);
        silc_server_stop(server);
        exit(1);
       }
@@ -1269,7 +1794,7 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
 bool silc_server_config_register_hmacs(SilcServer server)
 {
   SilcServerConfig config = server->config;
-  SilcServerConfigSectionHmac *hmac = config->hmac;
+  SilcServerConfigHmac *hmac = config->hmac;
 
   SILC_LOG_DEBUG(("Registering configured HMACs"));
 
@@ -1283,6 +1808,7 @@ bool silc_server_config_register_hmacs(SilcServer server)
       silc_server_stop(server);
       exit(1);
     }
+
     /* Register the HMAC */
     memset(&hmac_obj, 0, sizeof(hmac_obj));
     hmac_obj.name = hmac->name;
@@ -1300,7 +1826,7 @@ bool silc_server_config_register_hmacs(SilcServer server)
 bool silc_server_config_register_pkcs(SilcServer server)
 {
   SilcServerConfig config = server->config;
-  SilcServerConfigSectionPkcs *pkcs = config->pkcs;
+  SilcServerConfigPkcs *pkcs = config->pkcs;
 
   SILC_LOG_DEBUG(("Registering configured PKCS"));
 
@@ -1311,7 +1837,7 @@ bool silc_server_config_register_pkcs(SilcServer server)
     int i;
     for (i = 0; silc_default_pkcs[i].name; i++)
       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
-       silc_pkcs_register(&silc_default_pkcs[i]);
+       silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
        break;
       }
     if (!silc_pkcs_is_supported(pkcs->name)) {
@@ -1327,47 +1853,51 @@ bool silc_server_config_register_pkcs(SilcServer server)
 
 /* Sets log files where log messages are saved by the server logger. */
 
-void silc_server_config_setlogfiles(SilcServerConfig config,
-                               SilcSchedule sked)
+void silc_server_config_setlogfiles(SilcServer server)
 {
-  SilcServerConfigSectionLogging *this;
+  SilcServerConfig config = server->config;
+  SilcServerConfigLogging *this;
 
-  SILC_LOG_DEBUG(("Setting configured log file names"));
+  SILC_LOG_DEBUG(("Setting configured log file names and options"));
+
+  silc_log_timestamp = config->logging_timestamp;
+  silc_log_quick = config->logging_quick;
+  silc_log_flushdelay = (config->logging_flushdelay ?
+                        config->logging_flushdelay :
+                        SILC_SERVER_LOG_FLUSH_DELAY);
 
-  if ((this = config->logging_info))
-    silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, sked);
-  if ((this = config->logging_warnings))
-    silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, sked);
-  if ((this = config->logging_errors))
-    silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize, sked);
   if ((this = config->logging_fatals))
-    silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, sked);
+    silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
+                     server->schedule);
+  if ((this = config->logging_errors))
+    silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
+                     server->schedule);
+  if ((this = config->logging_warnings))
+    silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
+                     server->schedule);
+  if ((this = config->logging_info))
+    silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
+                     server->schedule);
 }
 
 /* Returns client authentication information from configuration file by host
    (name or ip) */
 
-SilcServerConfigSectionClient *
-silc_server_config_find_client(SilcServerConfig config, char *host, int port)
+SilcServerConfigClient *
+silc_server_config_find_client(SilcServer server, char *host)
 {
-  SilcServerConfigSectionClient *client;
+  SilcServerConfig config = server->config;
+  SilcServerConfigClient *client;
 
-  if (!config || !port) {
-    SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, "
-                     "host=0x%08x \"%s\", port=%hu)",
-                     (uint32) config, (uint32) host, host, port));
-    return NULL;
-  }
-  if (!host)
+  if (!config || !host)
     return NULL;
 
   for (client = config->clients; client; client = client->next) {
     if (client->host && !silc_string_compare(client->host, host))
       continue;
-    if (client->port && (client->port != port))
-      continue;
     break;
   }
+
   /* if none matched, then client is already NULL */
   return client;
 }
@@ -1375,11 +1905,12 @@ silc_server_config_find_client(SilcServerConfig config, char *host, int port)
 /* Returns admin connection configuration by host, username and/or
    nickname. */
 
-SilcServerConfigSectionAdmin *
-silc_server_config_find_admin(SilcServerConfig config,
-                             char *host, char *user, char *nick)
+SilcServerConfigAdmin *
+silc_server_config_find_admin(SilcServer server, char *host, char *user,
+                             char *nick)
 {
-  SilcServerConfigSectionAdmin *admin;
+  SilcServerConfig config = server->config;
+  SilcServerConfigAdmin *admin;
 
   /* make sure we have a value for the matching parameters */
   if (!host)
@@ -1399,26 +1930,21 @@ silc_server_config_find_admin(SilcServerConfig config,
     /* no checks failed -> this entry matches */
     break;
   }
+
   /* if none matched, then admin is already NULL */
   return admin;
 }
 
-/* Returns the denied connection configuration entry by host and port. */
+/* Returns the denied connection configuration entry by host. */
 
-SilcServerConfigSectionDeny *
-silc_server_config_find_denied(SilcServerConfig config,
-                              char *host, uint16 port)
+SilcServerConfigDeny *
+silc_server_config_find_denied(SilcServer server, char *host)
 {
-  SilcServerConfigSectionDeny *deny;
+  SilcServerConfig config = server->config;
+  SilcServerConfigDeny *deny;
 
   /* make sure we have a value for the matching parameters */
-  if (!config || !port) {
-    SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, "
-                     "host=0x%08x \"%s\", port=%hu)",
-                     (uint32) config, (uint32) host, host, port));
-    return NULL;
-  }
-  if (!host)
+  if (!config || !host)
     return NULL;
 
   for (deny = config->denied; deny; deny = deny->next) {
@@ -1426,21 +1952,19 @@ silc_server_config_find_denied(SilcServerConfig config,
       continue;
     break;
   }
+
   /* if none matched, then deny is already NULL */
   return deny;
 }
 
 /* Returns server connection info from server configuartion by host
-   (name or ip). If `port' is non-null then both name or IP and the port
-   must match. */
+   (name or ip). */
 
-SilcServerConfigSectionServer *
-silc_server_config_find_server_conn(SilcServerConfig config,
-                                   char *host, int port)
+SilcServerConfigServer *
+silc_server_config_find_server_conn(SilcServer server, char *host)
 {
-  int i;
-  SilcServerConfigSectionServer *serv = NULL;
-  bool match = FALSE;
+  SilcServerConfig config = server->config;
+  SilcServerConfigServer *serv = NULL;
 
   if (!host)
     return NULL;
@@ -1448,36 +1972,23 @@ silc_server_config_find_server_conn(SilcServerConfig config,
   if (!config->servers)
     return NULL;
 
-  serv = config->servers;
-  for (i = 0; serv; i++) {
-    if (silc_string_compare(serv->host, host))
-      match = TRUE;
-
-    if (port && serv->port && serv->port != port)
-      match = FALSE;
-
-    if (match)
-      break;
-
-    serv = serv->next;
+  for (serv = config->servers; serv; serv = serv->next) {
+    if (!silc_string_compare(serv->host, host))
+      continue;
+    break;
   }
 
-  if (!serv)
-    return NULL;
-
   return serv;
 }
 
 /* Returns router connection info from server configuration by
    host (name or ip). */
 
-SilcServerConfigSectionRouter *
-silc_server_config_find_router_conn(SilcServerConfig config,
-                                   char *host, int port)
+SilcServerConfigRouter *
+silc_server_config_find_router_conn(SilcServer server, char *host, int port)
 {
-  int i;
-  SilcServerConfigSectionRouter *serv = NULL;
-  bool match = FALSE;
+  SilcServerConfig config = server->config;
+  SilcServerConfigRouter *serv = NULL;
 
   if (!host)
     return NULL;
@@ -1485,33 +1996,50 @@ silc_server_config_find_router_conn(SilcServerConfig config,
   if (!config->routers)
     return NULL;
 
-  serv = config->routers;
-  for (i = 0; serv; i++) {
-    if (silc_string_compare(serv->host, host))
-      match = TRUE;
-
+  for (serv = config->routers; serv; serv = serv->next) {
+    if (!silc_string_compare(serv->host, host))
+      continue;
     if (port && serv->port && serv->port != port)
-      match = FALSE;
+      continue;
+    break;
+  }
 
-    if (match)
-      break;
+  return serv;
+}
 
-    serv = serv->next;
-  }
+/* Find backup router connection by host (name or ip) */
+
+SilcServerConfigRouter *
+silc_server_config_find_backup_conn(SilcServer server, char *host)
+{
+  SilcServerConfig config = server->config;
+  SilcServerConfigRouter *serv = NULL;
 
-  if (!serv)
+  if (!host)
     return NULL;
 
+  if (!config->routers)
+    return NULL;
+
+  for (serv = config->routers; serv; serv = serv->next) {
+    if (!serv->backup_router)
+      continue;
+    if (!silc_string_compare(serv->host, host))
+      continue;
+    break;
+  }
+
   return serv;
 }
 
 /* Returns TRUE if configuration for a router connection that we are
    initiating exists. */
 
-bool silc_server_config_is_primary_route(SilcServerConfig config)
+bool silc_server_config_is_primary_route(SilcServer server)
 {
+  SilcServerConfig config = server->config;
+  SilcServerConfigRouter *serv = NULL;
   int i;
-  SilcServerConfigSectionRouter *serv = NULL;
   bool found = FALSE;
 
   serv = config->routers;
@@ -1530,11 +2058,12 @@ bool silc_server_config_is_primary_route(SilcServerConfig config)
 /* Returns our primary connection configuration or NULL if we do not
    have primary router configured. */
 
-SilcServerConfigSectionRouter *
-silc_server_config_get_primary_router(SilcServerConfig config)
+SilcServerConfigRouter *
+silc_server_config_get_primary_router(SilcServer server)
 {
+  SilcServerConfig config = server->config;
+  SilcServerConfigRouter *serv = NULL;
   int i;
-  SilcServerConfigSectionRouter *serv = NULL;
 
   serv = config->routers;
   for (i = 0; serv; i++) {
@@ -1545,3 +2074,31 @@ silc_server_config_get_primary_router(SilcServerConfig config)
 
   return NULL;
 }
+
+/* If we have backup router configured that is going to replace us this
+   function returns it. */
+
+SilcServerConfigRouter *
+silc_server_config_get_backup_router(SilcServer server)
+{
+  SilcServerConfig config = server->config;
+  SilcServerConfigRouter *serv = NULL;
+  int i;
+
+  if (server->server_type != SILC_ROUTER)
+    return NULL;
+
+  serv = config->routers;
+  for (i = 0; serv; i++) {
+    if (serv->initiator == FALSE && serv->backup_router == TRUE &&
+       serv->backup_local == TRUE &&
+       !strcmp(server->config->server_info->primary->server_ip,
+               serv->backup_replace_ip) &&
+       server->config->server_info->primary->port ==
+       serv->backup_replace_port)
+      return serv;
+    serv = serv->next;
+  }
+
+  return NULL;
+}