updates.
[silc.git] / apps / silcd / serverconfig.c
index ffc7e118ab474d1ccc88a71b3d4f033d67eaf081..ecc35e2fa799ca880a0c7ef696b60362246d1933 100644 (file)
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/*  XXX
-   All possible configuration sections for SILC server. 
-
-   <Cipher>
-
-       Format:
-
-       +<Cipher name>:<SIM path>
-
-   <PKCS>
-
-       Format:
-
-       +<PKCS name>:<key length>
-
-   <HashFunction>
-
-       Format:
-
-       +<Hash function name>:<SIM path>
-
-   <ServerInfo>
-
-       This section is used to set the server informations.
-
-       Format:
-
-       +<Server DNS name>:<Server IP>:<Geographic location>:<Port>
-
-   <AdminInfo>
-
-       This section is used to set the server's administrative information.
-
-       Format:
-
-       +<Location>:<Server type>:<Admin's name>:<Admin's email address>
-
-   <ListenPort>
-
-       This section is used to set ports the server is listenning.
-
-       Format:
-
-       +<Local IP/UNIX socket path>:<Remote IP>:<Port>
-
-   <Logging>
-
-       This section is used to set various logging files, their paths
-       and maximum sizes. All the other directives except those defined
-       below are ignored in this section. Log files are purged after they
-       reach the maximum set byte size.
-
-       Format:
-
-       +infologfile:<path>:<max byte size>
-       +errorlogfile:<path>:<max byte size>
-
-   <ConnectionClass>
-
-       This section is used to define connection classes. These can be
-       used to optimize the server and the connections.
-
-       Format:
-
-       +<Class number>:<Ping freq>:<Connect freq>:<Max links>
-
-   <ClientAuth>
-
-       This section is used to define client authentications.
-
-       Format:
-
-       +<Remote address or name>:<auth method>:<password/cert/key/???>:<Port>:<Class>
-
-   <AdminAuth>
-
-       This section is used to define the server's administration 
-       authentications.
-
-       Format:
-
-       +<Hostname>:<auth method>:<password/cert/key/???>:<Nickname hash>:<Class>
-
-   <ServerConnection>
-
-       This section is used to define the server connections to this
-       server/router. Only routers can have normal server connections.
-       Normal servers leave this section epmty. The remote server cannot be
-       older than specified Version ID.
-
-       Format:
-
-       +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
-
-   <RouterConnection>
-
-       This section is used to define the router connections to this
-       server/router. Both normal server and router can have router
-       connections. Normal server usually has only one connection while
-       a router can have multiple. The remote server cannot be older than
-       specified Version ID.
-
-       Format:
-
-       +<Remote address or name>:<auth method>:<password/key/???>:
-       <Port>:<Version ID>:<Class>:<Initiator>
-
-   <DenyConnection>
-
-       This section is used to deny specific connections to your server. This
-       can be used to deny both clients and servers.
-
-       Format:
-
-       +<Remote address or name or nickname>:<Time interval>:<Comment>:<Port>
-
-   <RedirectClient>
-
-       This section is used to set the alternate servers that clients will be
-       redirected to when our server is full.
-
-       Format:
-
-       +<Remote address or name>:<Port>
-
-*/
-SilcConfigServerSection silc_config_server_sections[] = {
+SilcServerConfigSection silc_server_config_sections[] = {
   { "[Cipher]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
   { "[PKCS]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 2 },
-  { "[HashFunction]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 1 },
+  { "[Hash]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
+  { "[hmac]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, 3 },
+  { "[ServerKeys]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS, 2 },
   { "[ServerInfo]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
   { "[AdminInfo]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
   { "[ListenPort]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
+  { "[Identity]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 },
   { "[Logging]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
   { "[ConnectionClass]", 
@@ -174,9 +54,7 @@ SilcConfigServerSection silc_config_server_sections[] = {
   { "[AdminConnection]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
   { "[DenyConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
-  { "[RedirectClient]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
+    SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 3 },
   { "[motd]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 },
   
@@ -187,11 +65,11 @@ SilcConfigServerSection silc_config_server_sections[] = {
    parses the file. The parsed data is returned to the newly allocated
    configuration object. */
 
-SilcConfigServer silc_config_server_alloc(char *filename)
+SilcServerConfig silc_server_config_alloc(char *filename)
 {
-  SilcConfigServer new;
+  SilcServerConfig new;
   SilcBuffer buffer;
-  SilcConfigServerParse config_parse;
+  SilcServerConfigParse config_parse;
 
   SILC_LOG_DEBUG(("Allocating new configuration object"));
 
@@ -203,15 +81,17 @@ SilcConfigServer silc_config_server_alloc(char *filename)
 
   new->filename = filename;
 
+  SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
+
   /* Open configuration file and parse it */
   config_parse = NULL;
   buffer = NULL;
   silc_config_open(filename, &buffer);
   if (!buffer)
     goto fail;
-  if ((silc_config_server_parse(new, buffer, &config_parse)) == FALSE)
+  if ((silc_server_config_parse(new, buffer, &config_parse)) == FALSE)
     goto fail;
-  if ((silc_config_server_parse_lines(new, config_parse)) == FALSE)
+  if ((silc_server_config_parse_lines(new, config_parse)) == FALSE)
     goto fail;
 
   silc_free(buffer);
@@ -225,20 +105,21 @@ SilcConfigServer silc_config_server_alloc(char *filename)
 
 /* Free's a configuration object. */
 
-void silc_config_server_free(SilcConfigServer config)
+void silc_server_config_free(SilcServerConfig config)
 {
   if (config) {
     silc_free(config->filename);
+    silc_free(config->server_keys);
     silc_free(config->server_info);
     silc_free(config->admin_info);
     silc_free(config->listen_port);
+    silc_free(config->identity);
     silc_free(config->conn_class);
     silc_free(config->clients);
     silc_free(config->admins);
     silc_free(config->servers);
     silc_free(config->routers);
     silc_free(config->denied);
-    silc_free(config->redirect);
     silc_free(config->motd);
     silc_free(config);
   }
@@ -250,14 +131,13 @@ void silc_config_server_free(SilcConfigServer config)
    buffer sent as argument can be safely free'd after this function has
    succesfully returned. */
 
-int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer, 
-                            SilcConfigServerParse *return_config)
+int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, 
+                            SilcServerConfigParse *return_config)
 {
-  int i, begin;
-  unsigned int linenum;
+  int i, begin, linenum;
   char line[1024], *cp;
-  SilcConfigServerSection *cptr = NULL;
-  SilcConfigServerParse parse = *return_config, first = NULL;
+  SilcServerConfigSection *cptr = NULL;
+  SilcServerConfigParse parse = *return_config, first = NULL;
 
   SILC_LOG_DEBUG(("Parsing configuration file"));
 
@@ -301,7 +181,7 @@ int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
        *strchr(cp, '\n') = '\0';
       
       /* Check for matching sections */
-      for (cptr = silc_config_server_sections; cptr->section; cptr++)
+      for (cptr = silc_server_config_sections; cptr->section; cptr++)
        if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
          break;
 
@@ -367,13 +247,13 @@ int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
    parse_config argument is uninitialized automatically during this
    function. */
 
-int silc_config_server_parse_lines(SilcConfigServer config, 
-                                  SilcConfigServerParse parse_config)
+int silc_server_config_parse_lines(SilcServerConfig config, 
+                                  SilcServerConfigParse parse_config)
 {
   int ret, check = FALSE;
-  unsigned int checkmask;
+  uint32 checkmask;
   char *tmp;
-  SilcConfigServerParse pc = parse_config;
+  SilcServerConfigParse pc = parse_config;
   SilcBuffer line;
 
   SILC_LOG_DEBUG(("Parsing configuration lines"));
@@ -388,7 +268,7 @@ int silc_config_server_parse_lines(SilcConfigServer config,
 
     /* Get number of tokens in line */
     ret = silc_config_check_num_token(line);
-    if (ret != pc->section->maxfields) {
+    if (ret < pc->section->maxfields) {
       /* Bad line */
       fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
              config->filename, pc->linenum, ret, 
@@ -418,28 +298,28 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       if (ret < 0)
        break;
 
-      /* Get block length */
+      /* Get key length */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
        break;
       if (ret == 0) {
-       fprintf(stderr, "%s:%d: Cipher block length not defined\n",
+       fprintf(stderr, "%s:%d: Cipher key length not defined\n",
                config->filename, pc->linenum);
        break;
       }
-      config->cipher->block_len = atoi(tmp);
+      config->cipher->key_len = atoi(tmp);
       silc_free(tmp);
 
-      /* Get key length */
+      /* Get block length */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
        break;
       if (ret == 0) {
-       fprintf(stderr, "%s:%d: Cipher key length not defined\n",
+       fprintf(stderr, "%s:%d: Cipher block length not defined\n",
                config->filename, pc->linenum);
        break;
       }
-      config->cipher->key_len = atoi(tmp);
+      config->cipher->block_len = atoi(tmp);
       silc_free(tmp);
 
       check = TRUE;
@@ -460,18 +340,6 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        break;
       }
 
-      /* Get key length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: PKCS key length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->pkcs->key_len = atoi(tmp);
-      silc_free(tmp);
-
       check = TRUE;
       checkmask |= (1L << pc->section->type);
       break;
@@ -524,6 +392,94 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       checkmask |= (1L << pc->section->type);
       break;
 
+    case SILC_CONFIG_SERVER_SECTION_TYPE_HMAC:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->hmac);
+
+      /* Get HMAC name */
+      ret = silc_config_get_token(line, &config->hmac->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: HMAC name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get hash name */
+      ret = silc_config_get_token(line, &config->hmac->sim_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      
+      /* Get MAC length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->hmac->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS:
+
+      if (!config->server_keys)
+       config->server_keys = silc_calloc(1, sizeof(*config->server_keys));
+
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Public key name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      
+      if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, 
+                                    SILC_PKCS_FILE_PEM))
+       if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, 
+                                      SILC_PKCS_FILE_BIN)) {
+         fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+      silc_free(tmp);
+
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Private key name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      
+      if (!silc_pkcs_load_private_key(tmp, &config->server_keys->private_key, 
+                                    SILC_PKCS_FILE_BIN))
+       if (!silc_pkcs_load_private_key(tmp, 
+                                       &config->server_keys->private_key, 
+                                       SILC_PKCS_FILE_PEM)) {
+         fprintf(stderr, "%s:%d: Could not load private key file `%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
     case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
 
       if (!config->server_info)
@@ -601,13 +557,13 @@ int silc_config_server_parse_lines(SilcConfigServer config,
 
       SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
 
-      /* Get host */
-      ret = silc_config_get_token(line, &config->listen_port->host);
+      /* Get local IP */
+      ret = silc_config_get_token(line, &config->listen_port->local_ip);
       if (ret < 0)
        break;
 
-      /* Get remote IP */
-      ret = silc_config_get_token(line, &config->listen_port->remote_ip);
+      /* Get listener IP */
+      ret = silc_config_get_token(line, &config->listen_port->listener_ip);
       if (ret < 0)
        break;
 
@@ -627,6 +583,23 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       checkmask |= (1L << pc->section->type);
       break;
 
+    case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY:
+
+      if (!config->identity)
+        config->identity = silc_calloc(1, sizeof(*config->identity));
+
+      /* Get user */
+      ret = silc_config_get_token(line, &config->identity->user);
+      if (ret < 0)
+        break;
+      /* Get group */
+      ret = silc_config_get_token(line, &config->identity->group);
+      if (ret < 0)
+        break;
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+
     case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
 
       SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
@@ -737,27 +710,45 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        }
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+         config->clients->auth_meth = SILC_AUTH_PASSWORD;
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+         config->clients->auth_meth = SILC_AUTH_PUBLIC_KEY;
 
        silc_free(tmp);
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->clients->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->clients->auth_data);
       if (ret < 0)
        break;
-      if (ret == 0)
-       /* Any host */
-       config->clients->host = strdup("*");
+
+      if (config->clients->auth_meth == SILC_AUTH_PASSWORD) {
+       config->clients->auth_data_len = strlen(config->clients->auth_data);
+      } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->clients->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->clients->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->clients->auth_data);
+           break;
+         }
+
+       silc_free(config->clients->auth_data);
+       config->clients->auth_data = (void *)public_key;
+       config->clients->auth_data_len = 0;
+      }
 
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
        break;
-      if (ret == 0) {
+      if (ret) {
        config->clients->port = atoi(tmp);
        silc_free(tmp);
       }
@@ -800,19 +791,40 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        }
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+         config->servers->auth_meth = SILC_AUTH_PASSWORD;
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+         config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY;
 
        silc_free(tmp);
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->servers->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->servers->auth_data);
       if (ret < 0)
        break;
 
+      if (config->servers->auth_meth == SILC_AUTH_PASSWORD) {
+       config->servers->auth_data_len = strlen(config->servers->auth_data);
+      } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->servers->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->servers->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->servers->auth_data);
+           break;
+         }
+
+       silc_free(config->servers->auth_data);
+       config->servers->auth_data = (void *)public_key;
+       config->servers->auth_data_len = 0;
+      }
+
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
@@ -836,6 +848,15 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        silc_free(tmp);
       }
 
+      /* Check whether this connection is backup router connection */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret != -1) {
+       config->servers->backup_router = atoi(tmp);
+       if (config->servers->backup_router != 0)
+         config->servers->backup_router = TRUE;
+       silc_free(tmp);
+      }
+
       check = TRUE;
       checkmask |= (1L << pc->section->type);
       break;
@@ -848,9 +869,6 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       ret = silc_config_get_token(line, &config->routers->host);
       if (ret < 0)
        break;
-      //      if (ret == 0)
-      ///* Any host */
-      //       config->routers->host = strdup("*");
 
       /* Get authentication method */
       ret = silc_config_get_token(line, &tmp);
@@ -865,19 +883,40 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        }
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+         config->routers->auth_meth = SILC_AUTH_PASSWORD;
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+         config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY;
 
        silc_free(tmp);
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->routers->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->routers->auth_data);
       if (ret < 0)
        break;
 
+      if (config->routers->auth_meth == SILC_AUTH_PASSWORD) {
+       config->routers->auth_data_len = strlen(config->routers->auth_data);
+      } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->routers->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->routers->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->routers->auth_data);
+           break;
+         }
+
+       silc_free(config->routers->auth_data);
+       config->routers->auth_data = (void *)public_key;
+       config->routers->auth_data_len = 0;
+      }
+
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
@@ -912,6 +951,24 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        silc_free(tmp);
       }
 
+      /* Check whether this connection is backup router connection */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret != -1) {
+       config->routers->backup_router = atoi(tmp);
+       if (config->routers->backup_router != 0)
+         config->routers->backup_router = TRUE;
+       silc_free(tmp);
+      }
+
+      /* Check whether this backup is local (in cell) or remote (other cell) */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret != -1) {
+       config->routers->backup_local = atoi(tmp);
+       if (config->routers->backup_local != 0)
+         config->routers->backup_local = TRUE;
+       silc_free(tmp);
+      }
+
       check = TRUE;
       checkmask |= (1L << pc->section->type);
       break;
@@ -928,6 +985,22 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        /* Any host */
        config->admins->host = strdup("*");
 
+      /* Get username */
+      ret = silc_config_get_token(line, &config->admins->username);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any username */
+       config->admins->username = strdup("*");
+
+      /* Get nickname */
+      ret = silc_config_get_token(line, &config->admins->nickname);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any nickname */
+       config->admins->nickname = strdup("*");
+
       /* Get authentication method */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
@@ -941,45 +1014,78 @@ int silc_config_server_parse_lines(SilcConfigServer config,
        }
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+         config->admins->auth_meth = SILC_AUTH_PASSWORD;
 
        if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+         config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY;
 
        silc_free(tmp);
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->admins->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->admins->auth_data);
       if (ret < 0)
        break;
 
-      /* Get nickname */
-      ret = silc_config_get_token(line, &config->admins->nickname);
+      if (config->admins->auth_meth == SILC_AUTH_PASSWORD) {
+       config->admins->auth_data_len = strlen(config->admins->auth_data);
+      } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->admins->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->admins->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->admins->auth_data);
+           break;
+         }
+
+       silc_free(config->admins->auth_data);
+       config->admins->auth_data = (void *)public_key;
+       config->admins->auth_data_len = 0;
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->denied);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->denied->host);
       if (ret < 0)
        break;
+      if (ret == 0) {
+       /* Any host */
+       config->denied->host = strdup("*");
+       fprintf(stderr, "warning: %s:%d: Denying all connections",
+               config->filename, pc->linenum);
+      }
 
-      /* Get class number */
+      /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
        break;
-      if (ret) {
-       config->admins->class = atoi(tmp);
+      if (ret == 0) {
+       /* Any port */
+       config->denied->port = 0;
+      } else {
+       config->denied->port = atoi(tmp);
        silc_free(tmp);
       }
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
-      /* Not implemented yet */
-      check = TRUE;
-      break;
+      /* Get comment */
+      ret = silc_config_get_token(line, &config->denied->comment);
+      if (ret < 0)
+       break;
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT:
-      /* Not implemented yet */
       check = TRUE;
+      checkmask |= (1L << pc->section->type);
       break;
 
     case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD:
@@ -1010,9 +1116,6 @@ int silc_config_server_parse_lines(SilcConfigServer config,
     }
 
     pc = pc->next;
-    /* XXXX */
-    //    silc_free(pc->prev);
-    //    pc->prev = NULL;
   }
 
   if (check == FALSE)
@@ -1020,7 +1123,7 @@ int silc_config_server_parse_lines(SilcConfigServer config,
 
   /* Check that all mandatory sections really were found. If not, the server
      cannot function and we return error. */
-  ret = silc_config_server_check_sections(checkmask);
+  ret = silc_server_config_check_sections(checkmask);
   if (ret == FALSE) {
     /* XXX */
 
@@ -1034,6 +1137,8 @@ int silc_config_server_parse_lines(SilcConfigServer config,
     config->pkcs = config->pkcs->prev;
   while (config->hash_func && config->hash_func->prev)
     config->hash_func = config->hash_func->prev;
+  while (config->hmac && config->hmac->prev)
+    config->hmac = config->hmac->prev;
   while (config->listen_port && config->listen_port->prev)
     config->listen_port = config->listen_port->prev;
   while (config->logging && config->logging->prev)
@@ -1044,6 +1149,8 @@ int silc_config_server_parse_lines(SilcConfigServer config,
     config->clients = config->clients->prev;
   while (config->servers && config->servers->prev)
     config->servers = config->servers->prev;
+  while (config->admins && config->admins->prev)
+    config->admins = config->admins->prev;
   while (config->routers && config->routers->prev)
     config->routers = config->routers->prev;
   
@@ -1055,7 +1162,7 @@ int silc_config_server_parse_lines(SilcConfigServer config,
 /* This function checks that the mask sent as argument includes all the 
    sections that are mandatory in SILC server. */
 
-int silc_config_server_check_sections(unsigned int checkmask)
+int silc_server_config_check_sections(uint32 checkmask)
 {
   if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
     
@@ -1069,7 +1176,8 @@ int silc_config_server_check_sections(unsigned int checkmask)
     
     return FALSE;
   }
-  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
+  if (!(checkmask & 
+       (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
     
     return FALSE;
   }
@@ -1089,11 +1197,11 @@ int silc_config_server_check_sections(unsigned int checkmask)
 
 /* Sets log files where log messages is saved by the server. */
 
-void silc_config_server_setlogfiles(SilcConfigServer config)
+void silc_server_config_setlogfiles(SilcServerConfig config)
 {
-  SilcConfigServerSectionLogging *log;
+  SilcServerConfigSectionLogging *log;
   char *info, *warning, *error, *fatal;
-  unsigned int info_size, warning_size, error_size, fatal_size;
+  uint32 info_size, warning_size, error_size, fatal_size;
 
   SILC_LOG_DEBUG(("Setting configured log file names"));
 
@@ -1136,33 +1244,39 @@ void silc_config_server_setlogfiles(SilcConfigServer config)
 /* Registers configured ciphers. These can then be allocated by the
    server when needed. */
 
-void silc_config_server_register_ciphers(SilcConfigServer config)
+bool silc_server_config_register_ciphers(SilcServerConfig config)
 {
-  SilcConfigServerSectionAlg *alg;
+  SilcServerConfigSectionAlg *alg;
   SilcServer server = (SilcServer)config->server;
 
   SILC_LOG_DEBUG(("Registering configured ciphers"));
 
+  if (!config->cipher)
+    return FALSE;
+
   alg = config->cipher;
   while(alg) {
 
     if (!alg->sim_name) {
-      /* Crypto module is supposed to be built in. Nothing to be done
-        here except to test that the cipher really is built in. */
-      SilcCipher tmp = NULL;
-
-      if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
-       SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
+      int i;
+      
+      for (i = 0; silc_default_ciphers[i].name; i++)
+       if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
+         silc_cipher_register(&silc_default_ciphers[i]);
+         break;
+       }
+      
+      if (!silc_cipher_is_supported(alg->alg_name)) {
+       SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
        silc_server_stop(server);
        exit(1);
       }
-      silc_cipher_free(tmp);
-
 #ifdef SILC_SIM
     } else {
       /* Load (try at least) the crypto SIM module */
       SilcCipherObject cipher;
       SilcSimContext *sim;
+      char *alg_name;
 
       memset(&cipher, 0, sizeof(cipher));
       cipher.name = alg->alg_name;
@@ -1173,30 +1287,36 @@ void silc_config_server_register_ciphers(SilcConfigServer config)
       sim->type = SILC_SIM_CIPHER;
       sim->libname = alg->sim_name;
 
+      alg_name = strdup(alg->alg_name);
+      if (strchr(alg_name, '-'))
+       *strchr(alg_name, '-') = '\0';
+
       if ((silc_sim_load(sim))) {
        cipher.set_key = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+         silc_sim_getsym(sim, silc_sim_symname(alg_name, 
                                                SILC_CIPHER_SIM_SET_KEY));
        SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
        cipher.set_key_with_string = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+         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.set_key_with_string));
        cipher.encrypt = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+         silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_ENCRYPT_CBC));
        SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
         cipher.decrypt = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+         silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_DECRYPT_CBC));
        SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
         cipher.context_len = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+         silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_CONTEXT_LEN));
        SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
 
        /* Put the SIM to the list of all SIM's in server */
        silc_dlist_add(server->sim, sim);
+
+       silc_free(alg_name);
       } else {
        SILC_LOG_ERROR(("Error configuring ciphers"));
        silc_server_stop(server);
@@ -1210,59 +1330,73 @@ void silc_config_server_register_ciphers(SilcConfigServer config)
 
     alg = alg->next;
   }
+
+  return TRUE;
 }
 
 /* Registers configured PKCS's. */
-/* XXX: This really doesn't do anything now since we have statically
-   registered our PKCS's. This should be implemented when PKCS works
-   as SIM's. This checks now only that the PKCS user requested is 
-   really out there. */
 
-void silc_config_server_register_pkcs(SilcConfigServer config)
+bool silc_server_config_register_pkcs(SilcServerConfig config)
 {
-  SilcConfigServerSectionAlg *alg = config->pkcs;
+  SilcServerConfigSectionAlg *alg = config->pkcs;
   SilcServer server = (SilcServer)config->server;
-  SilcPKCS tmp = NULL;
 
   SILC_LOG_DEBUG(("Registering configured PKCS"));
 
-  while(alg) {
+  if (!config->pkcs)
+    return FALSE;
 
-    if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
-      SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
+  while(alg) {
+    int i;
+    
+    for (i = 0; silc_default_pkcs[i].name; i++)
+      if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
+       silc_pkcs_register(&silc_default_pkcs[i]);
+       break;
+      }
+      
+    if (!silc_pkcs_is_supported(alg->alg_name)) {
+      SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
       silc_server_stop(server);
       exit(1);
     }
-    silc_free(tmp);
 
     alg = alg->next;
   }
+
+  return TRUE;
 }
 
 /* Registers configured hash functions. These can then be allocated by the
    server when needed. */
 
-void silc_config_server_register_hashfuncs(SilcConfigServer config)
+bool silc_server_config_register_hashfuncs(SilcServerConfig config)
 {
-  SilcConfigServerSectionAlg *alg;
+  SilcServerConfigSectionAlg *alg;
   SilcServer server = (SilcServer)config->server;
 
   SILC_LOG_DEBUG(("Registering configured hash functions"));
 
+  if (!config->hash_func)
+    return FALSE;
+
   alg = config->hash_func;
   while(alg) {
 
     if (!alg->sim_name) {
-      /* Hash module is supposed to be built in. Nothing to be done
-        here except to test that the hash function really is built in. */
-      SilcHash tmp = NULL;
-
-      if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
-       SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
+      int i;
+      
+      for (i = 0; silc_default_hash[i].name; i++)
+       if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
+         silc_hash_register(&silc_default_hash[i]);
+         break;
+       }
+      
+      if (!silc_hash_is_supported(alg->alg_name)) {
+       SILC_LOG_ERROR(("Unknown hash funtion `%s'", alg->alg_name));
        silc_server_stop(server);
        exit(1);
       }
-      silc_free(tmp);
 
 #ifdef SILC_SIM
     } else {
@@ -1305,24 +1439,63 @@ void silc_config_server_register_hashfuncs(SilcConfigServer config)
        exit(1);
       }
 
-      /* Register the cipher */
+      /* Register the hash function */
       silc_hash_register(&hash);
 #endif
     }
 
     alg = alg->next;
   }
+
+  return TRUE;
+}
+
+/* Registers configure HMACs. These can then be allocated by the server
+   when needed. */
+
+bool silc_server_config_register_hmacs(SilcServerConfig config)
+{
+  SilcServerConfigSectionAlg *alg;
+  SilcServer server = (SilcServer)config->server;
+
+  SILC_LOG_DEBUG(("Registering configured HMACs"));
+
+  if (!config->hmac)
+    return FALSE;
+
+  alg = config->hmac;
+  while(alg) {
+    SilcHmacObject hmac;
+    
+    if (!silc_hash_is_supported(alg->sim_name)) {
+      SILC_LOG_ERROR(("Unknown hash function `%s'", alg->sim_name));
+      silc_server_stop(server);
+      exit(1);
+    }
+    
+    /* Register the HMAC */
+    memset(&hmac, 0, sizeof(hmac));
+    hmac.name = alg->alg_name;
+    hmac.len = alg->key_len;
+    silc_hmac_register(&hmac);
+
+    alg = alg->next;
+  }
+
+  return TRUE;
 }
 
 /* Returns client authentication information from server configuration
-   by host (name or ip). */
+   by host (name or ip). If `port' is non-null then both name or IP and 
+   the port must match. */
 
-SilcConfigServerSectionClientConnection *
-silc_config_server_find_client_conn(SilcConfigServer config, 
+SilcServerConfigSectionClientConnection *
+silc_server_config_find_client_conn(SilcServerConfig config, 
                                    char *host, int port)
 {
   int i;
-  SilcConfigServerSectionClientConnection *client = NULL;
+  SilcServerConfigSectionClientConnection *client = NULL;
+  bool match = FALSE;
 
   if (!host)
     return NULL;
@@ -1334,7 +1507,14 @@ silc_config_server_find_client_conn(SilcConfigServer config,
 
   for (i = 0; client; i++) {
     if (silc_string_compare(client->host, host))
+      match = TRUE;
+
+    if (port && client->port && client->port != port)
+      match = FALSE;
+
+    if (match)
       break;
+
     client = client->next;
   }
 
@@ -1345,14 +1525,16 @@ silc_config_server_find_client_conn(SilcConfigServer config,
 }
 
 /* Returns server connection info from server configuartion by host 
-   (name or ip). */
+   (name or ip). If `port' is non-null then both name or IP and the port
+   must match. */
 
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_server_conn(SilcConfigServer config, 
+SilcServerConfigSectionServerConnection *
+silc_server_config_find_server_conn(SilcServerConfig config, 
                                    char *host, int port)
 {
   int i;
-  SilcConfigServerSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionServerConnection *serv = NULL;
+  bool match = FALSE;
 
   if (!host)
     return NULL;
@@ -1363,7 +1545,14 @@ silc_config_server_find_server_conn(SilcConfigServer config,
   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;
   }
 
@@ -1376,12 +1565,13 @@ silc_config_server_find_server_conn(SilcConfigServer config,
 /* Returns router connection info from server configuartion by
    host (name or ip). */
 
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_router_conn(SilcConfigServer config, 
+SilcServerConfigSectionServerConnection *
+silc_server_config_find_router_conn(SilcServerConfig config, 
                                    char *host, int port)
 {
   int i;
-  SilcConfigServerSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionServerConnection *serv = NULL;
+  bool match = FALSE;
 
   if (!host)
     return NULL;
@@ -1392,7 +1582,14 @@ silc_config_server_find_router_conn(SilcConfigServer config,
   serv = config->routers;
   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;
   }
 
@@ -1402,64 +1599,115 @@ silc_config_server_find_router_conn(SilcConfigServer config,
   return serv;
 }
 
-/* Prints out example configuration file with default built in
-   configuration values. */
+/* Returns TRUE if configuartion for a router connection that we are 
+   initiating exists. */
+
+bool silc_server_config_is_primary_route(SilcServerConfig config)
+{
+  int i;
+  SilcServerConfigSectionServerConnection *serv = NULL;
+  bool found = FALSE;
+
+  serv = config->routers;
+  for (i = 0; serv; i++) {
+    if (serv->initiator == TRUE && serv->backup_router == FALSE) {
+      found = TRUE;
+      break;
+    }
+
+    serv = serv->next;
+  }
+
+  return found;
+}
+
+/* Returns our primary connection configuration or NULL if we do not
+   have primary router configured. */
 
-void silc_config_server_print()
+SilcServerConfigSectionServerConnection *
+silc_server_config_get_primary_router(SilcServerConfig config)
 {
-  char *buf;
+  int i;
+  SilcServerConfigSectionServerConnection *serv = NULL;
 
-  buf = "\
-#\n\
-# Automatically generated example SILCd configuration file with default\n\
-# built in values. Use this as a guide to configure your SILCd configuration\n\
-# file for your system. For detailed description of different configuration\n\
-# sections refer to silcd(8) manual page.\n\
-#\n";
-  /*
-#<Cipher>
-#+blowfish
-#+twofish
-#+rc5
-#+rc6
-#+3des
+  serv = config->routers;
+  for (i = 0; serv; i++) {
+    if (serv->initiator == TRUE && serv->backup_router == FALSE)
+      return serv;
+    serv = serv->next;
+  }
 
-#<HashFunction>
-#+md5
-#+sha1
+  return NULL;
+}
 
-<ServerInfo>
-+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+/* Returns Admin connection configuration by host, username and/or 
+   nickname. */
 
-<AdminInfo>
-+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+SilcServerConfigSectionAdminConnection *
+silc_server_config_find_admin(SilcServerConfig config,
+                             char *host, char *username, char *nickname)
+{
+  SilcServerConfigSectionAdminConnection *admin = NULL;
+  int i;
 
-<ListenPort>
-+10.2.1.6:10.2.1.6:1333
+  if (!config->admins)
+    return NULL;
+
+  if (!host)
+    host = "*";
+  if (!username)
+    username = "*";
+  if (!nickname)
+    nickname = "*";
+
+  admin = config->admins;
+  for (i = 0; admin; i++) {
+    if (silc_string_compare(admin->host, host) &&
+       silc_string_compare(admin->username, username) &&
+       silc_string_compare(admin->nickname, nickname))
+      break;
+
+    admin = admin->next;
+  }
+
+  if (!admin)
+    return NULL;
+
+  return admin;
+}
 
-<Logging>
-+infologfile:silcd.log:10000
-#+warninglogfile:/var/log/silcd_warning.log:10000
-#+errorlogfile:ERROR.log:10000
-#+fatallogfile:/var/log/silcd_error.log:
+/* Returns the Denied connection configuration by host and port. */
 
-<ConnectionClass>
-               +1:100:100:100
-                       +2:200:300:400
+SilcServerConfigSectionDenyConnection *
+silc_server_config_denied_conn(SilcServerConfig config, char *host,
+                              int port)
+{
+  int i;
+  SilcServerConfigSectionDenyConnection *deny = NULL;
+  bool match = FALSE;
+
+  if (!host)
+    return NULL;
 
-<ClientAuth>
-+10.2.1.199:priikone:333:1
+  if (!config->denied)
+    return NULL;
 
-<AdminAuth>
-+10.2.1.199:priikone:priikone:1
+  deny = config->denied;
+  for (i = 0; deny; i++) {
+    if (silc_string_compare(deny->host, host))
+      match = TRUE;
 
-<ServerConnection>
+    if (port && deny->port && deny->port != port)
+      match = FALSE;
 
-<RouterConnection>
+    if (match)
+      break;
 
-<DenyConnection>
-<RedirectClient>
-  */
+    deny = deny->next;
+  }
+
+  if (!deny)
+    return NULL;
 
-  fprintf(stdout, "%s\n", buf);
+  return deny;
 }