silcd: allow ServerType, Location, Admin and AdminEmail to be empty
[silc.git] / apps / silcd / serverconfig.c
index f48c7dab298d2d0e73d0722304604c5a286cce2c..d2d062a79da93147fdbbc808511ba991e8c937c5 100644 (file)
@@ -2,9 +2,10 @@
 
   serverconfig.c
 
-  Author: Giovanni Giacobbi <giovanni@giacobbi.net>
+  Authors: Giovanni Giacobbi <giovanni@giacobbi.net>
+           Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2007 Pekka Riikonen
+  Copyright (C) 1997 - 2014 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -150,7 +151,7 @@ static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
     SilcPublicKey public_key;
     SilcSKR skr = *auth_data;
     SilcSKRFind find;
-    SilcSKRStatus status;
+    SilcSKRStatus status = SILC_SKR_NOT_FOUND;
 
     if (!silc_pkcs_load_public_key(p, &public_key)) {
       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
@@ -161,19 +162,20 @@ static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
     find = silc_skr_find_alloc();
     silc_skr_find_set_public_key(find, public_key);
     silc_skr_find_set_usage(find, usage);
-    silc_skr_find_set_context(find, key_context ? key_context : (void *)usage);
+    if (!key_context)
+      silc_skr_find_set_context(find, SILC_32_TO_PTR(usage));
     silc_skr_find(skr, NULL, find, my_find_callback, &status);
-    if (status == SILC_SKR_ALREADY_EXIST) {
+    if (status == SILC_SKR_OK) {
+      /* Already added, ignore error */
       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 */
+      return TRUE;
     }
 
     /* Add the public key to repository */
-    if (silc_skr_add_public_key(skr, public_key, usage,
-                               key_context ? key_context : (void *)usage,
-                               NULL) != SILC_SKR_OK) {
+    status = silc_skr_add_public_key(skr, public_key, usage,
+                                    key_context ? key_context :
+                                    (void *)usage, NULL);
+    if (status != SILC_SKR_OK) {
       SILC_SERVER_LOG_ERROR(("Error while adding public key \"%s\"", p));
       return FALSE;
     }
@@ -182,8 +184,8 @@ static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
   return TRUE;
 }
 
-static SilcBool my_parse_publickeydir(const char *dirname, void **auth_data,
-                                     SilcSKRKeyUsage usage)
+static int my_parse_publickeydir(const char *dirname, void **auth_data,
+                                SilcSKRKeyUsage usage)
 {
   int total = 0;
   struct dirent *get_file;
@@ -192,7 +194,7 @@ static SilcBool my_parse_publickeydir(const char *dirname, void **auth_data,
   if (!(dp = opendir(dirname))) {
     SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
                           "Could not open directory \"%s\"", dirname));
-    return FALSE;
+    return -1;
   }
 
   /* errors are not considered fatal */
@@ -215,14 +217,14 @@ static SilcBool my_parse_publickeydir(const char *dirname, void **auth_data,
       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,
-                       usage, NULL);
-      total++;
+      if (my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL,
+                           usage, NULL))
+       total++;
     }
   }
 
   SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname));
-  return TRUE;
+  return total;
 }
 
 /* Callbacks */
@@ -232,11 +234,7 @@ SILC_CONFIG_CALLBACK(fetch_generic)
   SilcServerConfig config = (SilcServerConfig) context;
   int got_errno = 0;
 
-  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")) {
+  if (!strcmp(name, "prefer_passphrase_auth")) {
     config->prefer_passphrase_auth = *(SilcBool *)val;
   }
   else if (!strcmp(name, "require_reverse_lookup")) {
@@ -379,10 +377,6 @@ SILC_CONFIG_CALLBACK(fetch_cipher)
     CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) {
-    CONFIG_IS_DOUBLE(tmp->module);
-    tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
-  }
   else if (!strcmp(name, "keylength")) {
     tmp->key_length = *(SilcUInt32 *)val;
   }
@@ -395,7 +389,6 @@ SILC_CONFIG_CALLBACK(fetch_cipher)
 
  got_err:
   silc_free(tmp->name);
-  silc_free(tmp->module);
   silc_free(tmp);
   config->tmp = NULL;
   return got_errno;
@@ -427,10 +420,6 @@ SILC_CONFIG_CALLBACK(fetch_hash)
     CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) {
-    CONFIG_IS_DOUBLE(tmp->module);
-    tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
-  }
   else if (!strcmp(name, "blocklength")) {
     tmp->block_length = *(int *)val;
   }
@@ -443,7 +432,6 @@ SILC_CONFIG_CALLBACK(fetch_hash)
 
  got_err:
   silc_free(tmp->name);
-  silc_free(tmp->module);
   silc_free(tmp);
   config->tmp = NULL;
   return got_errno;
@@ -653,10 +641,11 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
 
     /* Check the private key file permissions. */
     if ((stat(file_tmp, &st)) != -1) {
-      if ((st.st_mode & 0777) != 0600) {
+      if (((st.st_mode & 0777) != 0600) &&
+         ((st.st_mode & 0777) != 0640)) {
        SILC_SERVER_LOG_ERROR(("Wrong permissions in private key "
                              "file \"%s\".  The permissions must be "
-                             "0600.", file_tmp));
+                             "0600 or 0640.", file_tmp));
         return SILC_CONFIG_ESILENT;
       }
     }
@@ -667,6 +656,14 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
       return SILC_CONFIG_EPRINTLINE;
     }
+
+    /* Warn if key length is < 4096 (some versions created 4095 bit keys). */
+    if (silc_pkcs_private_key_get_len(server_info->private_key) < 4095) {
+      fprintf(stderr,
+              "warning: Your server private key %s length is under 4096 bits. "
+             "It is recommended to use at least 4096 bits. Consider "
+             "generating a new server key pair.\n", file_tmp);
+    }
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -880,18 +877,22 @@ SILC_CONFIG_CALLBACK(fetch_client)
   else if (!strcmp(name, "publickey")) {
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_AUTH |
                           SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
+    tmp->publickeys = TRUE;
   }
   else if (!strcmp(name, "publickeydir")) {
-    if (!my_parse_publickeydir((char *) val,
-                              (void *)&config->server->repository,
-                              SILC_SKR_USAGE_KEY_AGREEMENT)) {
+    if (my_parse_publickeydir((char *) val,
+                             (void *)&config->server->repository,
+                             SILC_SKR_USAGE_AUTH |
+                             SILC_SKR_USAGE_KEY_AGREEMENT) < 0) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
+    tmp->publickeys = TRUE;
   }
   else if (!strcmp(name, "params")) {
     CONFIG_IS_DOUBLE(tmp->param);
@@ -959,6 +960,7 @@ SILC_CONFIG_CALLBACK(fetch_admin)
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
+    tmp->publickeys = TRUE;
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -1056,10 +1058,12 @@ SILC_CONFIG_CALLBACK(fetch_server)
     CONFIG_IS_DOUBLE(tmp->publickeys);
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_AUTH |
                           SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
+    tmp->publickeys = TRUE;
   }
   else if (!strcmp(name, "params")) {
     CONFIG_IS_DOUBLE(tmp->param);
@@ -1133,10 +1137,12 @@ SILC_CONFIG_CALLBACK(fetch_router)
     CONFIG_IS_DOUBLE(tmp->publickeys);
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_AUTH |
                           SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
+    tmp->publickeys = TRUE;
   }
   else if (!strcmp(name, "params")) {
     CONFIG_IS_DOUBLE(tmp->param);
@@ -1187,7 +1193,6 @@ SILC_CONFIG_CALLBACK(fetch_router)
 
 /* known config options tables */
 static const SilcConfigTable table_general[] = {
-  { "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 },
@@ -1224,7 +1229,6 @@ static const SilcConfigTable table_general[] = {
 
 static const SilcConfigTable table_cipher[] = {
   { "name",            SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
-  { "module",          SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
   { "keylength",       SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
   { "blocklength",     SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
   { 0, 0, 0, 0 }
@@ -1232,7 +1236,6 @@ static const SilcConfigTable table_cipher[] = {
 
 static const SilcConfigTable table_hash[] = {
   { "name",            SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
-  { "module",          SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
   { "blocklength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
   { "digestlength",    SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
   { 0, 0, 0, 0 }
@@ -1261,10 +1264,10 @@ 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},
-  { "adminemail",      SILC_CONFIG_ARG_STR   fetch_serverinfo, NULL},
+  { "servertype",      SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
+  { "location",                SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
+  { "admin",           SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
+  { "adminemail",      SILC_CONFIG_ARG_STRE,   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},
@@ -1414,6 +1417,24 @@ static SilcBool silc_server_config_check(SilcServerConfig config)
     ret = FALSE;
   }
 
+  if (!config->server_info->public_key ||
+      !config->server_info->private_key) {
+    SILC_SERVER_LOG_ERROR(("\nError: Server keypair is missing"));
+    ret = FALSE;
+  }
+
+  if (!config->server_info->primary) {
+    SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `Primary' "
+                          "in `ServerInfo'"));
+    ret = FALSE;
+  }
+
+  if (!config->server_info->primary->server_ip) {
+    SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory field `Ip' "
+                          "in `Primary' in `ServerInfo'"));
+    ret = FALSE;
+  }
+
   /* RouterConnection sanity checks */
 
   if (config->routers && config->routers->backup_router == TRUE &&
@@ -1423,15 +1444,6 @@ static SilcBool silc_server_config_check(SilcServerConfig config)
         "connection. You have marked it incorrectly as backup router."));
     ret = FALSE;
   }
-#if 0
-  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;
-  }
-#endif
   if (config->routers && config->routers->backup_router == TRUE &&
       !config->servers && !config->routers->next) {
     SILC_SERVER_LOG_ERROR((
@@ -1539,7 +1551,7 @@ SilcServerConfig silc_server_config_alloc(const char *filename,
                               silc_config_strerror(ret)));
       linebuf = silc_config_read_line(file, line);
       if (linebuf) {
-       SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
+       SILC_SERVER_LOG_ERROR(("  file %s line %u:  %s\n", filename,
                               line, linebuf));
        silc_free(linebuf);
       }
@@ -1602,7 +1614,6 @@ void silc_server_config_destroy(SilcServerConfig config)
   SILC_LOG_DEBUG(("Freeing config context"));
 
   /* Destroy general config stuff */
-  silc_free(config->module_path);
   silc_free(config->debug_string);
   silc_free(config->param.version_protocol);
   silc_free(config->param.version_software);
@@ -1656,12 +1667,10 @@ void silc_server_config_destroy(SilcServerConfig config)
   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
                                  config->cipher)
     silc_free(di->name);
-    silc_free(di->module);
     silc_free(di);
   }
   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
     silc_free(di->name);
-    silc_free(di->module);
     silc_free(di);
   }
   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
@@ -1870,7 +1879,7 @@ silc_server_config_find_client(SilcServer server, char *host)
     return NULL;
 
   for (client = config->clients; client; client = client->next) {
-    if (client->host && !silc_string_compare(client->host, host))
+    if (client->host && !silc_string_match(client->host, host))
       continue;
     break;
   }
@@ -1898,11 +1907,11 @@ silc_server_config_find_admin(SilcServer server, char *host, char *user,
     nick = "*";
 
   for (admin = config->admins; admin; admin = admin->next) {
-    if (admin->host && !silc_string_compare(admin->host, host))
+    if (admin->host && !silc_string_match(admin->host, host))
       continue;
-    if (admin->user && !silc_string_compare(admin->user, user))
+    if (admin->user && !silc_string_match(admin->user, user))
       continue;
-    if (admin->nick && !silc_string_compare(admin->nick, nick))
+    if (admin->nick && !silc_string_match(admin->nick, nick))
       continue;
     /* no checks failed -> this entry matches */
     break;
@@ -1925,7 +1934,7 @@ silc_server_config_find_denied(SilcServer server, char *host)
     return NULL;
 
   for (deny = config->denied; deny; deny = deny->next) {
-    if (deny->host && !silc_string_compare(deny->host, host))
+    if (deny->host && !silc_string_match(deny->host, host))
       continue;
     break;
   }
@@ -1950,7 +1959,7 @@ silc_server_config_find_server_conn(SilcServer server, char *host)
     return NULL;
 
   for (serv = config->servers; serv; serv = serv->next) {
-    if (!silc_string_compare(serv->host, host))
+    if (!silc_string_match(serv->host, host))
       continue;
     break;
   }
@@ -1974,7 +1983,7 @@ silc_server_config_find_router_conn(SilcServer server, char *host, int port)
     return NULL;
 
   for (serv = config->routers; serv; serv = serv->next) {
-    if (!silc_string_compare(serv->host, host))
+    if (!silc_string_match(serv->host, host))
       continue;
     if (port && serv->port && serv->port != port)
       continue;
@@ -2001,7 +2010,7 @@ silc_server_config_find_backup_conn(SilcServer server, char *host)
   for (serv = config->routers; serv; serv = serv->next) {
     if (!serv->backup_router)
       continue;
-    if (!silc_string_compare(serv->host, host))
+    if (!silc_string_match(serv->host, host))
       continue;
     break;
   }