X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fserverconfig.c;h=911caff0dde735085b13ccc4fa628097740cbe6e;hp=e51039d619484e970556ec1c4765f1d4c85226fe;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=d47a87b03b846e2333ef57b2c0d81f1644992964 diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index e51039d6..911caff0 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -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 #if 0 #define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt) @@ -37,11 +35,18 @@ __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; \ } @@ -53,41 +58,159 @@ __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; +}