Fixed detaching bugs, channel key distribution after detach,
[silc.git] / apps / silcd / serverconfig.c
index d9fe747adb60d02bd2a43f4b5bb194f00c68754c..73a38bfde43bba4a89a656b8cd95d75622496d76 100644 (file)
@@ -92,6 +92,10 @@ my_set_param_defaults(SilcServerConfigConnParams *params,
   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
 }
@@ -108,23 +112,23 @@ my_find_param(SilcServerConfig config, const char *name)
   }
 
   SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
-                        "Cannot find Params \"%s\".\n", name));
+                        "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,
-                             SilcUInt32 line, void **auth_data,
-                             SilcUInt32 *auth_data_len)
+                             void **auth_data, SilcUInt32 *auth_data_len)
 {
   if (auth_meth == SILC_AUTH_PASSWORD) {
     /* p is a plain text password */
     if (auth_data && auth_data_len) {
       if (!silc_utf8_valid(p, strlen(p))) {
-       *auth_data_len = silc_utf8_encoded_len(p, strlen(p), 0);
+       *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_ASCII, *auth_data,
+       silc_utf8_encode(p, strlen(p), SILC_STRING_LANGUAGE, *auth_data,
                         *auth_data_len);
       } else {
        *auth_data = (void *) strdup(p);
@@ -137,9 +141,8 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p,
 
     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)) {
-       SILC_SERVER_LOG_ERROR(("\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;
       }
 
@@ -152,11 +155,9 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p,
                                           TRUE);
       silc_hash_table_add(*auth_data, public_key, public_key);
     }
-  } else {
-    SILC_SERVER_LOG_ERROR(("\nError while parsing config file at line %lu: "
-                          "Unknown authentication method.\n", line));
-    return FALSE;
-  }
+  } else
+    abort();
+
   return TRUE;
 }
 
@@ -234,6 +235,21 @@ SILC_CONFIG_CALLBACK(fetch_generic)
   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;
 
@@ -465,7 +481,7 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
     if ((port <= 0) || (port > 65535)) {
       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
-                            "Invalid port number!\n"));
+                            "Invalid port number!"));
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -511,9 +527,8 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
                                   SILC_PKCS_FILE_PEM))
       if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
                                     SILC_PKCS_FILE_BIN)) {
-       SILC_SERVER_LOG_ERROR(("Error: Could not load public key file.\n"));
-       SILC_SERVER_LOG_ERROR(("   line %lu, file \"%s\"\n", line, file_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")) {
@@ -521,12 +536,11 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
 
     /* try to load specified file, if fail stop config parsing */
     if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
-                                   SILC_PKCS_FILE_BIN))
+                                   "", 0, SILC_PKCS_FILE_BIN))
       if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
-                                     SILC_PKCS_FILE_PEM)) {
-       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file.\n"));
-       SILC_SERVER_LOG_ERROR(("   line %lu, file \"%s\"\n", line, file_tmp));
-       return SILC_CONFIG_ESILENT;
+                                     "", 0, SILC_PKCS_FILE_PEM)) {
+       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
+       return SILC_CONFIG_EPRINTLINE;
       }
   }
   else
@@ -544,7 +558,10 @@ SILC_CONFIG_CALLBACK(fetch_logging)
 {
   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
 
-  if (!strcmp(name, "quicklogs")) {
+  if (!strcmp(name, "timestamp")) {
+    config->logging_timestamp = *(bool *)val;
+  }
+  else if (!strcmp(name, "quicklogs")) {
     config->logging_quick = *(bool *)val;
   }
   else if (!strcmp(name, "flushdelay")) {
@@ -552,7 +569,7 @@ SILC_CONFIG_CALLBACK(fetch_logging)
     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
                            "Invalid flushdelay value, use quicklogs if you "
-                           "want real-time logging.\n"));
+                           "want real-time logging."));
       return SILC_CONFIG_EPRINTLINE;
     }
     config->logging_flushdelay = (long) flushdelay;
@@ -667,6 +684,24 @@ SILC_CONFIG_CALLBACK(fetch_connparam)
     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;
 
@@ -703,17 +738,17 @@ SILC_CONFIG_CALLBACK(fetch_client)
   }
   else if (!strcmp(name, "passphrase")) {
     CONFIG_IS_DOUBLE(tmp->passphrase);
-    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void **)&tmp->passphrase,
                           &tmp->passphrase_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
-    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void **)&tmp->publickeys, NULL)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
@@ -769,18 +804,18 @@ SILC_CONFIG_CALLBACK(fetch_admin)
   }
   else if (!strcmp(name, "passphrase")) {
     CONFIG_IS_DOUBLE(tmp->passphrase);
-    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void **)&tmp->passphrase,
                           &tmp->passphrase_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
     CONFIG_IS_DOUBLE(tmp->publickeys);
-    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void **)&tmp->publickeys, NULL)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
@@ -865,18 +900,18 @@ SILC_CONFIG_CALLBACK(fetch_server)
   }
   else if (!strcmp(name, "passphrase")) {
     CONFIG_IS_DOUBLE(tmp->passphrase);
-    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void **)&tmp->passphrase,
                           &tmp->passphrase_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
     CONFIG_IS_DOUBLE(tmp->publickeys);
-    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void **)&tmp->publickeys, NULL)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
@@ -929,7 +964,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
     int port = *(int *)val;
     if ((port <= 0) || (port > 65535)) {
       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
-                            "Invalid port number!\n"));
+                            "Invalid port number!"));
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -937,18 +972,18 @@ SILC_CONFIG_CALLBACK(fetch_router)
   }
   else if (!strcmp(name, "passphrase")) {
     CONFIG_IS_DOUBLE(tmp->passphrase);
-    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void **)&tmp->passphrase,
                           &tmp->passphrase_len)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
     CONFIG_IS_DOUBLE(tmp->publickeys);
-    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
+    if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
                           (void **)&tmp->publickeys, NULL)) {
-      got_errno = SILC_CONFIG_ESILENT;
+      got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
@@ -973,7 +1008,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
     int port = *(int *)val;
     if ((port <= 0) || (port > 65535)) {
       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
-                            "Invalid port number!\n"));
+                            "Invalid port number!"));
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1018,6 +1053,11 @@ static const SilcConfigTable table_general[] = {
   { "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 }
 };
 
@@ -1080,6 +1120,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 },
@@ -1103,7 +1144,13 @@ static const SilcConfigTable table_connparam[] = {
   { "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 },
+  { "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 }
 };
 
@@ -1155,11 +1202,11 @@ static const SilcConfigTable table_routerconn[] = {
 };
 
 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 },
+  { "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 },
   { "connectionparams",        SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
@@ -1203,14 +1250,17 @@ SilcServerConfig silc_server_config_alloc(const char *filename)
 
   /* alloc a config object */
   config_new = silc_calloc(1, sizeof(*config_new));
-  config_new->refcount = 1;
   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) {
-    SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n",
+    SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'",
                           filename));
     return NULL;
   }
@@ -1234,10 +1284,10 @@ SilcServerConfig silc_server_config_alloc(const char *filename)
       char *linebuf, *filename = silc_config_get_filename(file);
       SilcUInt32 line = silc_config_get_line(file);
       if (ret != SILC_CONFIG_EPRINTLINE)
-        SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.\n",
+        SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.",
                               silc_config_strerror(ret)));
       linebuf = silc_config_read_line(file, line);
-      SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n\n", filename,
+      SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
                             line, linebuf));
       silc_free(linebuf);
     }
@@ -1251,7 +1301,7 @@ SilcServerConfig silc_server_config_alloc(const char *filename)
   /* If config_new is incomplete, abort the object and return NULL */
   if (!config_new->server_info) {
     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block "
-                          "`server_info'\n"));
+                          "`server_info'"));
     silc_server_config_destroy(config_new);
     return NULL;
   }
@@ -1314,6 +1364,10 @@ 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) {
@@ -1338,6 +1392,7 @@ void silc_server_config_destroy(SilcServerConfig config)
     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 */
@@ -1485,6 +1540,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);
       }
@@ -1568,6 +1624,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);
       }
@@ -1659,6 +1716,7 @@ void silc_server_config_setlogfiles(SilcServer server)
 
   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 :
@@ -1805,6 +1863,31 @@ silc_server_config_find_router_conn(SilcServer server, char *host, int port)
   return serv;
 }
 
+/* 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 (!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. */
 
@@ -1847,3 +1930,31 @@ silc_server_config_get_primary_router(SilcServer server)
 
   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;
+}