X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fserverconfig.c;h=911caff0dde735085b13ccc4fa628097740cbe6e;hp=4e575c2eb1c6d69109b8f83f4b22529b6dc75bc3;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=d724e6e0616bad77bdcd83ed08a3f20daf5660b2 diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index 4e575c2e..911caff0 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -2,15 +2,15 @@ serverconfig.c - Author: Pekka Riikonen + Author: Johnny Mnemonic - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -21,1295 +21,1662 @@ #include "serverincludes.h" #include "server_internal.h" +#include -SilcServerConfigSection silc_server_config_sections[] = { - { "[Cipher]", - SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 }, - { "[PKCS]", - SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 1 }, - { "[Hash]", - SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 }, - { "[hmac]", - SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, 3 }, - { "[ServerKeys]", - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS, 2 }, - { "[ServerInfo]", - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 }, - { "[AdminInfo]", - SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 }, - { "[ListenPort]", - SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 }, - { "[Identity]", - SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 }, - { "[Logging]", - SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 }, - { "[ConnectionClass]", - SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 }, - { "[ClientConnection]", - SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 }, - { "[ServerConnection]", - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 }, - { "[RouterConnection]", - SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 7 }, - { "[AdminConnection]", - SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 }, - { "[DenyConnection]", - SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 3 }, - { "[motd]", - SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 }, - { "[pid]", - SILC_CONFIG_SERVER_SECTION_TYPE_PID, 1}, - - { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 } -}; - -/* Allocates a new configuration object, opens configuration file and - parses the file. The parsed data is returned to the newly allocated - configuration object. */ - -SilcServerConfig silc_server_config_alloc(char *filename) -{ - SilcServerConfig new; - SilcBuffer buffer; - SilcServerConfigParse config_parse; - - SILC_LOG_DEBUG(("Allocating new configuration object")); +#if 0 +#define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt) +#else +#define SERVER_CONFIG_DEBUG(fmt) +#endif - new = silc_calloc(1, sizeof(*new)); - if (!new) { - fprintf(stderr, "Could not allocate new configuration object"); - return NULL; +/* auto-declare needed variables for the common list parsing */ +#define SILC_SERVER_CONFIG_SECTION_INIT(__type__) \ + SilcServerConfig config = (SilcServerConfig) context; \ + __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; \ } - new->filename = filename; - - SILC_LOG_DEBUG(("Loading config data from `%s'", filename)); - - /* Open configuration file and parse it */ - config_parse = NULL; - buffer = NULL; - silc_config_open(filename, &buffer); - if (!buffer) - goto fail; - if ((silc_server_config_parse(new, buffer, &config_parse)) == FALSE) - goto fail; - if ((silc_server_config_parse_lines(new, config_parse)) == FALSE) - goto fail; +/* append the tmp field to the specified list */ +#define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__) \ + if (!__list__) { \ + __list__ = tmp; \ + } else { \ + for (findtmp = __list__; findtmp->next; findtmp = findtmp->next); \ + findtmp->next = tmp; \ + } - silc_buffer_free(buffer); +/* loops all elements in a list and provides a di struct pointer of the + * specified type containing the current element */ +#define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__) \ + for (tmp = (void *) __list__; tmp;) { \ + __type__ *di = (__type__ *) tmp; \ + tmp = (void *) di->next; + +/* Set EDOUBLE error value and bail out if necessary */ +#define CONFIG_IS_DOUBLE(__x__) \ + if ((__x__)) { \ + got_errno = SILC_CONFIG_EDOUBLE; \ + goto got_err; \ + } - return new; +/* 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); - fail: - silc_buffer_free(buffer); - silc_free(new); - return NULL; +static void my_free_public_key(void *key, void *context, void *user_data) +{ + silc_pkcs_public_key_free(context); } -/* Free's a configuration object. */ +/* 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 +} -void silc_server_config_free(SilcServerConfig config) +/* Find connection parameters by the parameter block name. */ +static SilcServerConfigConnParams * +my_find_param(SilcServerConfig config, const char *name) { - if (config) { - silc_free(config->filename); - silc_free(config->server_keys); - silc_free(config->server_info); - silc_free(config->admin_info); - silc_free(config->listen_port); - silc_free(config->identity); - silc_free(config->conn_class); - silc_free(config->clients); - silc_free(config->admins); - silc_free(config->servers); - silc_free(config->routers); - silc_free(config->denied); - silc_free(config->motd); - silc_free(config->pidfile); - silc_free(config); + SilcServerConfigConnParams *param; + + for (param = config->conn_params; param; param = param->next) { + if (!strcasecmp(param->name, name)) + return param; } -} -/* Parses the the buffer and returns the parsed lines into return_config - argument. The return_config argument doesn't have to be initialized - before calling this. It will be initialized during the parsing. The - buffer sent as argument can be safely free'd after this function has - succesfully returned. */ + SILC_SERVER_LOG_ERROR(("Error while parsing config file: " + "Cannot find Params \"%s\".", name)); -int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, - SilcServerConfigParse *return_config) -{ - int i, begin, linenum; - char line[1024], *cp; - SilcServerConfigSection *cptr = NULL; - SilcServerConfigParse parse = *return_config, first = NULL; - - SILC_LOG_DEBUG(("Parsing configuration file")); - - begin = 0; - linenum = 0; - while((begin = silc_gets(line, sizeof(line), - buffer->data, buffer->len, begin)) != EOF) { - cp = line; - linenum++; - - /* Check for bad line */ - if (silc_check_line(cp)) - continue; + return NULL; +} - /* Remove tabs and whitespaces from the line */ - if (strchr(cp, '\t')) { - i = 0; - while(strchr(cp + i, '\t')) { - *strchr(cp + i, '\t') = ' '; - i++; - } - } - for (i = 0; i < strlen(cp); i++) { - if (cp[i] != ' ') { - if (i) - cp++; - break; +/* parse an authdata according to its auth method */ +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 */ + 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); } - cp++; } - - /* Parse line */ - switch(cp[0]) { - case '[': - /* - * Start of a section - */ - - /* Remove new line sign */ - if (strchr(cp, '\n')) - *strchr(cp, '\n') = '\0'; - - /* Check for matching sections */ - for (cptr = silc_server_config_sections; cptr->section; cptr++) - if (!strncasecmp(cp, cptr->section, strlen(cptr->section))) - break; - - if (!cptr->section) { - fprintf(stderr, "%s:%d: Unknown section `%s'\n", - config->filename, linenum, cp); + } else if (auth_meth == SILC_AUTH_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)) { + SILC_SERVER_LOG_ERROR(("Error while parsing config file: " + "Could not load public key file!")); return FALSE; } - break; - default: - /* - * Start of a configuration line - */ - - if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) { - - if (strchr(cp, '\n')) - *strchr(cp, '\n') = ':'; - - if (parse == NULL) { - parse = silc_calloc(1, sizeof(*parse)); - parse->line = NULL; - parse->section = NULL; - parse->next = NULL; - parse->prev = NULL; - } else { - if (parse->next == NULL) { - parse->next = silc_calloc(1, sizeof(*parse->next)); - parse->next->line = NULL; - parse->next->section = NULL; - parse->next->next = NULL; - parse->next->prev = parse; - parse = parse->next; - } - } - - if (first == NULL) - first = parse; - - /* Add the line to parsing structure for further parsing. */ - if (parse) { - parse->section = cptr; - parse->line = silc_buffer_alloc(strlen(cp) + 1); - parse->linenum = linenum; - silc_buffer_pull_tail(parse->line, strlen(cp)); - silc_buffer_put(parse->line, cp, strlen(cp)); - } - } - break; + 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 */ } - } - - /* Set the return_config argument to its first value so that further - parsing can be started from the first line. */ - *return_config = first; + + /* 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; } -/* Parses the lines earlier read from configuration file. The config object - must not be initialized, it will be initialized in this function. The - parse_config argument is uninitialized automatically during this - function. */ - -int silc_server_config_parse_lines(SilcServerConfig config, - SilcServerConfigParse parse_config) +static bool my_parse_publickeydir(const char *dirname, void **auth_data) { - int ret, check = FALSE; - uint32 checkmask; - char *tmp; - SilcServerConfigParse pc = parse_config; - SilcBuffer line; + int total = 0; + struct dirent *get_file; + DIR *dp; - SILC_LOG_DEBUG(("Parsing configuration lines")); - - if (!config) + if (!(dp = opendir(dirname))) { + SILC_SERVER_LOG_ERROR(("Error while parsing config file: " + "Could not open directory \"%s\"", dirname)); return FALSE; - - checkmask = 0; - while(pc) { - check = FALSE; - line = pc->line; - - /* Get number of tokens in line */ - ret = silc_config_check_num_token(line); - if (ret < pc->section->maxfields) { - /* Bad line */ - fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n", - config->filename, pc->linenum, ret, - pc->section->maxfields); - break; - } - - /* Parse the line */ - switch(pc->section->type) { - case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher); - - /* Get cipher name */ - ret = silc_config_get_token(line, &config->cipher->alg_name); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Cipher name not defined\n", - config->filename, pc->linenum); - break; - } - - /* Get module name */ - config->cipher->sim_name = NULL; - ret = silc_config_get_token(line, &config->cipher->sim_name); - if (ret < 0) - break; - - /* Get key length */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Cipher key length not defined\n", - config->filename, pc->linenum); - break; - } - config->cipher->key_len = atoi(tmp); - silc_free(tmp); - - /* Get block length */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Cipher block length not defined\n", - config->filename, pc->linenum); - break; - } - config->cipher->block_len = atoi(tmp); - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs); - - /* Get PKCS name */ - ret = silc_config_get_token(line, &config->pkcs->alg_name); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: PKCS name not defined\n", - config->filename, pc->linenum); - break; - } - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func); - - /* Get Hash function name */ - ret = silc_config_get_token(line, &config->hash_func->alg_name); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Hash function name not defined\n", - config->filename, pc->linenum); - break; - } - - /* Get Hash function module name */ - config->hash_func->sim_name = NULL; - ret = silc_config_get_token(line, &config->hash_func->sim_name); - if (ret < 0) - break; - - /* Get block length */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Hash function block length not defined\n", - config->filename, pc->linenum); - break; - } - config->hash_func->block_len = atoi(tmp); - silc_free(tmp); - - /* Get hash length */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Hash function hash length not defined\n", - config->filename, pc->linenum); - break; - } - config->hash_func->key_len = atoi(tmp); - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_HMAC: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->hmac); - - /* Get HMAC name */ - ret = silc_config_get_token(line, &config->hmac->alg_name); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: HMAC name not defined\n", - config->filename, pc->linenum); - break; - } - - /* Get hash name */ - ret = silc_config_get_token(line, &config->hmac->sim_name); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Hash function name not defined\n", - config->filename, pc->linenum); - break; - } - - /* Get MAC length */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n", - config->filename, pc->linenum); - break; - } - config->hmac->key_len = atoi(tmp); - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS: - - if (!config->server_keys) - config->server_keys = silc_calloc(1, sizeof(*config->server_keys)); - - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Public key name not defined\n", - config->filename, pc->linenum); - break; - } - - if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, - SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, - SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, tmp); - break; - } - silc_free(tmp); - - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Private key name not defined\n", - config->filename, pc->linenum); - break; - } - - if (!silc_pkcs_load_private_key(tmp, &config->server_keys->private_key, - SILC_PKCS_FILE_BIN)) - if (!silc_pkcs_load_private_key(tmp, - &config->server_keys->private_key, - SILC_PKCS_FILE_PEM)) { - fprintf(stderr, "%s:%d: Could not load private key file `%s'\n", - config->filename, pc->linenum, tmp); - break; - } - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO: - - if (!config->server_info) - config->server_info = silc_calloc(1, sizeof(*config->server_info)); - - /* Get server name */ - ret = silc_config_get_token(line, &config->server_info->server_name); - if (ret < 0) - break; - if (ret == 0) { - /* Server name not defined */ - - } - - /* Get server IP */ - ret = silc_config_get_token(line, &config->server_info->server_ip); - if (ret < 0) - break; - if (ret == 0) { - /* Server IP not defined */ - - } - - /* Get server location */ - ret = silc_config_get_token(line, &config->server_info->location); - if (ret < 0) - break; - - /* Get server port */ - /* XXX: Need port here??? */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - /* Port not defined */ - - } - config->server_info->port = atoi(tmp); - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO: - - if (!config->admin_info) - config->admin_info = silc_calloc(1, sizeof(*config->admin_info)); - - /* Get location */ - ret = silc_config_get_token(line, &config->admin_info->location); - if (ret < 0) - break; - - /* Get server type */ - ret = silc_config_get_token(line, &config->admin_info->server_type); - if (ret < 0) - break; - - /* Get admins name */ - ret = silc_config_get_token(line, &config->admin_info->admin_name); - if (ret < 0) - break; - - /* Get admins email address */ - ret = silc_config_get_token(line, &config->admin_info->admin_email); - if (ret < 0) - break; - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; + } - case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT: + /* 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; - SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port); + /* Ignore "." and "..", and take files only with ".pub" suffix. */ + if (!strcmp(filename, ".") || !strcmp(filename, "..") || + (filename_len < 5) || strcmp(filename + filename_len - 4, ".pub")) + continue; - /* Get local IP */ - ret = silc_config_get_token(line, &config->listen_port->local_ip); - if (ret < 0) - break; + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s%s%s", dirname, + (dirname[dirname_len - 1] == '/' ? "" : "/"), filename); - /* Get listener IP */ - ret = silc_config_get_token(line, &config->listen_port->listener_ip); - if (ret < 0) - break; + 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++; + } + } - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - /* Any port */ - config->listen_port->port = 0; - } else { - config->listen_port->port = atoi(tmp); - silc_free(tmp); - } + SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname)); + return TRUE; +} - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +/* Callbacks */ - case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY: +SILC_CONFIG_CALLBACK(fetch_generic) +{ + SilcServerConfig config = (SilcServerConfig) context; + int got_errno = 0; - if (!config->identity) - config->identity = silc_calloc(1, sizeof(*config->identity)); + 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; - /* Get user */ - ret = silc_config_get_token(line, &config->identity->user); - if (ret < 0) - break; - /* Get group */ - ret = silc_config_get_token(line, &config->identity->group); - if (ret < 0) - break; + return SILC_CONFIG_OK; - check = TRUE; - checkmask |= (1L << pc->section->type); + got_err: + return got_errno; +} - case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS: +SILC_CONFIG_CALLBACK(fetch_cipher) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher); + + 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) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + if (!tmp->name) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } - SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class); + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigCipher); - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - /* Class number not defined */ + /* Identify and save this value */ + if (!strcmp(name, "name")) { + CONFIG_IS_DOUBLE(tmp->name); + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "module")) { + CONFIG_IS_DOUBLE(tmp->module); + tmp->module = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "keylength")) { + tmp->key_length = *(SilcUInt32 *)val; + } + else if (!strcmp(name, "blocklength")) { + tmp->block_length = *(SilcUInt32 *)val; + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->name); + silc_free(tmp->module); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - } - config->conn_class->class = atoi(tmp); - silc_free(tmp); +SILC_CONFIG_CALLBACK(fetch_hash) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash); + + 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) /* 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; + } - /* Get ping frequency */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->ping_freq = atoi(tmp); - silc_free(tmp); + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHash); - /* Get connect frequency */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->connect_freq = atoi(tmp); - silc_free(tmp); + /* Identify and save this value */ + if (!strcmp(name, "name")) { + CONFIG_IS_DOUBLE(tmp->name); + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "module")) { + CONFIG_IS_DOUBLE(tmp->module); + tmp->module = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "blocklength")) { + tmp->block_length = *(int *)val; + } + else if (!strcmp(name, "digestlength")) { + tmp->digest_length = *(int *)val; + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->name); + silc_free(tmp->module); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get max links */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->max_links = atoi(tmp); - silc_free(tmp); +SILC_CONFIG_CALLBACK(fetch_hmac) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac); + + 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) /* 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; + } - check = TRUE; - checkmask |= (1L << pc->section->type); - break; + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHmac); - case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING: + /* Identify and save this value */ + if (!strcmp(name, "name")) { + CONFIG_IS_DOUBLE(tmp->name); + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "hash")) { + CONFIG_IS_DOUBLE(tmp->hash); + tmp->hash = strdup((char *) val); + } + else if (!strcmp(name, "maclength")) { + tmp->mac_length = *(int *)val; + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->name); + silc_free(tmp->hash); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - SILC_SERVER_CONFIG_LIST_ALLOC(config->logging); +SILC_CONFIG_CALLBACK(fetch_pkcs) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs); + + 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) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + if (!tmp->name) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } - /* Get log section type and check it */ - ret = silc_config_get_token(line, &config->logging->logtype); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Log file section not defined\n", - config->filename, pc->linenum); - break; - } - if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO) - && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING) - && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR) - && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)) { - fprintf(stderr, "%s:%d: Unknown log file section '%s'\n", - config->filename, pc->linenum, config->logging->logtype); - break; - } + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigPkcs); - /* Get log filename */ - ret = silc_config_get_token(line, &config->logging->filename); - if (ret < 0) - break; - if (ret == 0) { - fprintf(stderr, "%s:%d: Log file name not defined\n", - config->filename, pc->linenum); - break; - } + /* Identify and save this value */ + if (!strcmp(name, "name")) { + CONFIG_IS_DOUBLE(tmp->name); + tmp->name = strdup((char *) 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; +} - /* Get max byte size */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->logging->maxsize = atoi(tmp); - silc_free(tmp); +SILC_CONFIG_CALLBACK(fetch_serverinfo) +{ + 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 = (SilcServerConfigServerInfo *) + silc_calloc(1, sizeof(*server_info)); + + if (type == SILC_CONFIG_ARG_BLOCK) { + 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")) { + CONFIG_IS_DOUBLE(server_info->server_name); + server_info->server_name = strdup((char *) val); + } + else if (!strcmp(name, "ip")) { + 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)) { + 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, "servertype")) { + CONFIG_IS_DOUBLE(server_info->server_type); + server_info->server_type = strdup((char *) val); + } + else if (!strcmp(name, "admin")) { + CONFIG_IS_DOUBLE(server_info->admin); + server_info->admin = strdup((char *) val); + } + else if (!strcmp(name, "adminemail")) { + CONFIG_IS_DOUBLE(server_info->email); + server_info->email = strdup((char *) val); + } + else if (!strcmp(name, "location")) { + CONFIG_IS_DOUBLE(server_info->location); + server_info->location = strdup((char *) val); + } + else if (!strcmp(name, "user")) { + CONFIG_IS_DOUBLE(server_info->user); + server_info->user = strdup((char *) val); + } + else if (!strcmp(name, "group")) { + CONFIG_IS_DOUBLE(server_info->group); + server_info->group = strdup((char *) val); + } + else if (!strcmp(name, "motdfile")) { + CONFIG_IS_DOUBLE(server_info->motd_file); + server_info->motd_file = strdup((char *) val); + } + else if (!strcmp(name, "pidfile")) { + CONFIG_IS_DOUBLE(server_info->pid_file); + server_info->pid_file = strdup((char *) val); + } + else if (!strcmp(name, "publickey")) { + 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(file_tmp, &server_info->public_key, + 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.")); + return SILC_CONFIG_EPRINTLINE; } - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->clients); - - /* Get host */ - ret = silc_config_get_token(line, &config->clients->host); - if (ret < 0) - break; - if (ret == 0) - /* Any host */ - config->clients->host = strdup("*"); - - /* Get authentication method */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) && - strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) { - fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n", - config->filename, pc->linenum, tmp); - break; - } - - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->clients->auth_meth = SILC_AUTH_PASSWORD; - - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->clients->auth_meth = SILC_AUTH_PUBLIC_KEY; - - silc_free(tmp); + } + else if (!strcmp(name, "privatekey")) { + 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(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; +} - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->clients->auth_data); - if (ret < 0) - break; +SILC_CONFIG_CALLBACK(fetch_logging) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging); - if (config->clients->auth_meth == SILC_AUTH_PASSWORD) { - config->clients->auth_data_len = strlen(config->clients->auth_data); - } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->clients->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->clients->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->clients->auth_data); - break; - } - - silc_free(config->clients->auth_data); - config->clients->auth_data = (void *)public_key; - config->clients->auth_data_len = 0; - } + 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) */ + SILC_SERVER_LOG_ERROR(("Error while parsing config file: " + "Invalid flushdelay value, use quicklogs if you " + "want real-time logging.")); + return SILC_CONFIG_EPRINTLINE; + } + config->logging_flushdelay = (long) flushdelay; + } - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->clients->port = atoi(tmp); - silc_free(tmp); - } + /* 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; \ + if (!tmp->file) { \ + got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err; \ + } \ + config->__member__ = tmp; \ + config->tmp = NULL; \ + } + FETCH_LOGGING_CHAN("info", logging_info) + FETCH_LOGGING_CHAN("warnings", logging_warnings) + FETCH_LOGGING_CHAN("errors", logging_errors) + FETCH_LOGGING_CHAN("fatals", logging_fatals) +#undef FETCH_LOGGING_CHAN + else if (!strcmp(name, "file")) { + 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 = (SilcServerConfigLogging *) config->tmp; + } + tmp->maxsize = *(SilcUInt32 *) val; + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->file); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->clients->class = atoi(tmp); - silc_free(tmp); - } +SILC_CONFIG_CALLBACK(fetch_connparam) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams); + + SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)", + type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + if (!tmp->name) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* Set defaults */ + my_set_param_defaults(tmp, &config->param); - check = TRUE; - checkmask |= (1L << pc->section->type); - break; + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigConnParams); - case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION: + 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; - SILC_SERVER_CONFIG_LIST_ALLOC(config->servers); + return SILC_CONFIG_OK; - /* Get host */ - ret = silc_config_get_token(line, &config->servers->host); - if (ret < 0) - break; - if (ret == 0) - /* Any host */ - config->servers->host = strdup("*"); + got_err: + silc_free(tmp->name); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get authentication method */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) && - strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) { - fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n", - config->filename, pc->linenum, tmp); - break; - } +SILC_CONFIG_CALLBACK(fetch_client) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient); - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->servers->auth_meth = SILC_AUTH_PASSWORD; + SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", + type, name, context)); - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY; + /* Alloc before block checking, because empty sub-blocks are welcome here */ + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigClient); - silc_free(tmp); - } + 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; + } - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->servers->auth_data); - if (ret < 0) - break; + /* Identify and save this value */ + if (!strcmp(name, "host")) { + CONFIG_IS_DOUBLE(tmp->host); + tmp->host = (*(char *)val ? strdup((char *) val) : NULL); + } + 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, "publickeydir")) { + if (!my_parse_publickeydir((char *) val, (void **)&tmp->publickeys)) { + got_errno = SILC_CONFIG_EPRINTLINE; + 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; + } + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + CONFIG_FREE_AUTH(tmp); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - if (config->servers->auth_meth == SILC_AUTH_PASSWORD) { - config->servers->auth_data_len = strlen(config->servers->auth_data); - } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->servers->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->servers->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->servers->auth_data); - break; - } - - silc_free(config->servers->auth_data); - config->servers->auth_data = (void *)public_key; - config->servers->auth_data_len = 0; - } +SILC_CONFIG_CALLBACK(fetch_admin) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin); + + 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) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigAdmin); - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->servers->port = atoi(tmp); - silc_free(tmp); - } + /* Identify and save this value */ + if (!strcmp(name, "host")) { + CONFIG_IS_DOUBLE(tmp->host); + tmp->host = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "user")) { + CONFIG_IS_DOUBLE(tmp->user); + tmp->user = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "nick")) { + CONFIG_IS_DOUBLE(tmp->nick); + tmp->nick = (*(char *)val ? strdup((char *) val) : NULL); + } + 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, "publickeydir")) { + if (!my_parse_publickeydir((char *) val, (void **)&tmp->publickeys)) { + got_errno = SILC_CONFIG_EPRINTLINE; + goto got_err; + } + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + silc_free(tmp->user); + silc_free(tmp->nick); + CONFIG_FREE_AUTH(tmp); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get version */ - ret = silc_config_get_token(line, &config->servers->version); - if (ret < 0) - break; +SILC_CONFIG_CALLBACK(fetch_deny) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny); + + 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) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + if (!tmp->reason) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->servers->class = atoi(tmp); - silc_free(tmp); - } + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny); - /* Check whether this connection is backup router connection */ - ret = silc_config_get_token(line, &tmp); - if (ret != -1) { - config->servers->backup_router = atoi(tmp); - if (config->servers->backup_router != 0) - config->servers->backup_router = TRUE; - silc_free(tmp); - } + /* Identify and save this value */ + if (!strcmp(name, "host")) { + CONFIG_IS_DOUBLE(tmp->host); + tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*")); + } + else if (!strcmp(name, "reason")) { + CONFIG_IS_DOUBLE(tmp->reason); + tmp->reason = strdup((char *) val); + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + silc_free(tmp->reason); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +SILC_CONFIG_CALLBACK(fetch_server) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer); + + 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) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; + + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer); - case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION: + /* Identify and save this value */ + if (!strcmp(name, "host")) { + CONFIG_IS_DOUBLE(tmp->host); + tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*")); + } + 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")) { + 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, "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, "backup")) { + tmp->backup_router = *(bool *)val; + } + else + return SILC_CONFIG_EINTERNAL; - SILC_SERVER_CONFIG_LIST_ALLOC(config->routers); + return SILC_CONFIG_OK; - /* Get host */ - ret = silc_config_get_token(line, &config->routers->host); - if (ret < 0) - break; + got_err: + silc_free(tmp->host); + CONFIG_FREE_AUTH(tmp); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get authentication method */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) && - strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) { - fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n", - config->filename, pc->linenum, tmp); - break; - } +SILC_CONFIG_CALLBACK(fetch_router) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter); - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->routers->auth_meth = SILC_AUTH_PASSWORD; + SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", + type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + if (!tmp) /* discard empty sub-blocks */ + return SILC_CONFIG_OK; - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY; + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigRouter); - silc_free(tmp); - } + /* Identify and save this value */ + if (!strcmp(name, "host")) { + CONFIG_IS_DOUBLE(tmp->host); + tmp->host = strdup((char *) val); + } + else if (!strcmp(name, "port")) { + 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->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; + } + } + 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, "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")) { + tmp->initiator = *(bool *)val; + } + else if (!strcmp(name, "backuphost")) { + 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->backup_replace_ip); + CONFIG_FREE_AUTH(tmp); + silc_free(tmp); + config->tmp = NULL; + return got_errno; +} - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->routers->auth_data); - if (ret < 0) - break; +/* known config options tables */ +static const SilcConfigTable table_general[] = { + { "module_path", SILC_CONFIG_ARG_STRE, fetch_generic, NULL }, + { "prefer_passphrase_auth", SILC_CONFIG_ARG_TOGGLE, fetch_generic, NULL }, + { "require_reverse_lookup", SILC_CONFIG_ARG_TOGGLE, fetch_generic, NULL }, + { "connections_max", SILC_CONFIG_ARG_INT, fetch_generic, NULL }, + { "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 } +}; - if (config->routers->auth_meth == SILC_AUTH_PASSWORD) { - config->routers->auth_data_len = strlen(config->routers->auth_data); - } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->routers->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->routers->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->routers->auth_data); - break; - } - - silc_free(config->routers->auth_data); - config->routers->auth_data = (void *)public_key; - config->routers->auth_data_len = 0; - } +static const SilcConfigTable table_cipher[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_cipher, NULL }, + { "module", SILC_CONFIG_ARG_STRE, fetch_cipher, NULL }, + { "keylength", SILC_CONFIG_ARG_INT, fetch_cipher, NULL }, + { "blocklength", SILC_CONFIG_ARG_INT, fetch_cipher, NULL }, + { 0, 0, 0, 0 } +}; - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->routers->port = atoi(tmp); - silc_free(tmp); - } +static const SilcConfigTable table_hash[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_hash, NULL }, + { "module", SILC_CONFIG_ARG_STRE, fetch_hash, NULL }, + { "blocklength", SILC_CONFIG_ARG_INT, fetch_hash, NULL }, + { "digestlength", SILC_CONFIG_ARG_INT, fetch_hash, NULL }, + { 0, 0, 0, 0 } +}; - /* Get version */ - ret = silc_config_get_token(line, &config->routers->version); - if (ret < 0) - break; +static const SilcConfigTable table_hmac[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_hmac, NULL }, + { "hash", SILC_CONFIG_ARG_STR, fetch_hmac, NULL }, + { "maclength", SILC_CONFIG_ARG_INT, fetch_hmac, NULL }, + { 0, 0, 0, 0 } +}; - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->routers->class = atoi(tmp); - silc_free(tmp); - } +static const SilcConfigTable table_pkcs[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_pkcs, NULL }, + { 0, 0, 0, 0 } +}; - /* Get whether we are initiator or not */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->routers->initiator = atoi(tmp); - if (config->routers->initiator != 0) - config->routers->initiator = TRUE; - silc_free(tmp); - } +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 } +}; - /* Get backup replace IP */ - ret = silc_config_get_token(line, &config->routers->backup_replace_ip); - if (ret != -1) - config->routers->backup_router = TRUE; - - if (config->routers->backup_router) { - /* Get backup replace port */ - ret = silc_config_get_token(line, &tmp); - if (ret != -1) { - config->routers->backup_replace_port = atoi(tmp); - silc_free(tmp); - } - - /* Check whether the backup connection is local */ - ret = silc_config_get_token(line, &tmp); - if (ret != -1) { - config->routers->backup_local = atoi(tmp); - if (config->routers->backup_local != 0) - config->routers->backup_local = TRUE; - silc_free(tmp); - } - } +static const SilcConfigTable table_serverinfo[] = { + { "hostname", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "primary", SILC_CONFIG_ARG_BLOCK, fetch_serverinfo, table_serverinfo_c}, + { "secondary", SILC_CONFIG_ARG_BLOCK, fetch_serverinfo, table_serverinfo_c}, + { "servertype", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "location", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "admin", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "adminemail", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "user", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "group", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "publickey", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "privatekey", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "motdfile", SILC_CONFIG_ARG_STRE, fetch_serverinfo, NULL}, + { "pidfile", SILC_CONFIG_ARG_STRE, fetch_serverinfo, NULL}, + { 0, 0, 0, 0 } +}; - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +static const SilcConfigTable table_logging_c[] = { + { "file", SILC_CONFIG_ARG_STR, fetch_logging, NULL }, + { "size", SILC_CONFIG_ARG_SIZE, fetch_logging, NULL }, +/*{ "quicklog", SILC_CONFIG_ARG_NONE, fetch_logging, NULL }, */ + { 0, 0, 0, 0 } +}; - case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION: +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 }, + { "warnings", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c }, + { "errors", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c }, + { "fatals", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c }, + { 0, 0, 0, 0 } +}; - SILC_SERVER_CONFIG_LIST_ALLOC(config->admins); +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 } +}; - /* Get host */ - ret = silc_config_get_token(line, &config->admins->host); - if (ret < 0) - break; - if (ret == 0) - /* Any host */ - config->admins->host = strdup("*"); +static const SilcConfigTable table_client[] = { + { "host", SILC_CONFIG_ARG_STRE, 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 } +}; - /* Get username */ - ret = silc_config_get_token(line, &config->admins->username); - if (ret < 0) - break; - if (ret == 0) - /* Any username */ - config->admins->username = strdup("*"); +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 }, + { "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 }, + { "params", SILC_CONFIG_ARG_STR, fetch_admin, NULL }, + { 0, 0, 0, 0 } +}; - /* Get nickname */ - ret = silc_config_get_token(line, &config->admins->nickname); - if (ret < 0) - break; - if (ret == 0) - /* Any nickname */ - config->admins->nickname = strdup("*"); +static const SilcConfigTable table_deny[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_deny, NULL }, + { "reason", SILC_CONFIG_ARG_STR, fetch_deny, NULL }, + { 0, 0, 0, 0 } +}; - /* Get authentication method */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) && - strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) { - fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n", - config->filename, pc->linenum, tmp); - break; - } +static const SilcConfigTable table_serverconn[] = { + { "host", SILC_CONFIG_ARG_STRE, 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 } +}; - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->admins->auth_meth = SILC_AUTH_PASSWORD; +static const SilcConfigTable table_routerconn[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_router, NULL }, + { "port", SILC_CONFIG_ARG_INT, 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 }, + { "backuplocal", SILC_CONFIG_ARG_TOGGLE, fetch_router, NULL }, + { 0, 0, 0, 0 } +}; - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY; +static const SilcConfigTable table_main[] = { + { "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 }, + { "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 } +}; - silc_free(tmp); - } +/* Set default values to stuff that was not configured. */ - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->admins->auth_data); - if (ret < 0) - break; +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); +} - if (config->admins->auth_meth == SILC_AUTH_PASSWORD) { - config->admins->auth_data_len = strlen(config->admins->auth_data); - } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->admins->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->admins->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->admins->auth_data); - break; - } - - silc_free(config->admins->auth_data); - config->admins->auth_data = (void *)public_key; - config->admins->auth_data_len = 0; - } +/* Check for correctness of the configuration */ - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +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; + } - case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION: + /* RouterConnection sanity checks */ - SILC_SERVER_CONFIG_LIST_ALLOC(config->denied); + 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; + } - /* Get host */ - ret = silc_config_get_token(line, &config->denied->host); - if (ret < 0) - break; - if (ret == 0) { - /* Any host */ - config->denied->host = strdup("*"); - fprintf(stderr, "warning: %s:%d: Denying all connections", - config->filename, pc->linenum); - } + /* Backup router sanity checks */ - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) + 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; - if (ret == 0) { - /* Any port */ - config->denied->port = 0; - } else { - config->denied->port = atoi(tmp); - silc_free(tmp); } + } + } - /* Get comment */ - ret = silc_config_get_token(line, &config->denied->comment); - if (ret < 0) - break; + return ret; +} - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +/* Allocates a new configuration object, opens configuration file and + 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. */ - case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD: +SilcServerConfig silc_server_config_alloc(const char *filename) +{ + SilcServerConfig config_new; + SilcConfigEntity ent; + SilcConfigFile *file; + int ret; + SILC_LOG_DEBUG(("Loading config data from `%s'", filename)); - if (!config->motd) - config->motd = silc_calloc(1, sizeof(*config->motd)); + /* alloc a config object */ + config_new = silc_calloc(1, sizeof(*config_new)); + if (!config_new) + return NULL; - /* Get motd file */ - ret = silc_config_get_token(line, &config->motd->motd_file); - if (ret < 0) - break; + /* general config defaults */ + config_new->refcount = 1; + config_new->logging_timestamp = TRUE; - check = TRUE; - checkmask |= (1L << pc->section->type); - break; + /* obtain a config file object */ + file = silc_config_open(filename); + if (!file) { + SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'", + filename)); + return NULL; + } - case SILC_CONFIG_SERVER_SECTION_TYPE_PID: - - if (!config->pidfile) - config->pidfile = silc_calloc(1, sizeof(*config->pidfile)); - - ret = silc_config_get_token(line, &config->pidfile->pid_file); - if (ret < 0) - break; - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_NONE: - default: - /* Error */ - break; + /* 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_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))); + + /* 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); + 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); + 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; + } - /* Check for error */ - if (check == FALSE) { - /* Line could not be parsed */ - fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum); - break; - } + /* close (destroy) the file object */ + silc_config_close(file); - pc = pc->next; + /* Check the configuration */ + if (!silc_server_config_check(config_new)) { + silc_server_config_destroy(config_new); + return NULL; } - if (check == FALSE) - return FALSE; + /* Set default to configuration parameters */ + silc_server_config_set_defaults(config_new); + + return config_new; +} - /* Check that all mandatory sections really were found. If not, the server - cannot function and we return error. */ - ret = silc_server_config_check_sections(checkmask); - if (ret == FALSE) { - /* XXX */ +/* 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)); } - - /* Before returning all the lists in the config object must be set - to their first values (the last value is first here). */ - while (config->cipher && config->cipher->prev) - config->cipher = config->cipher->prev; - while (config->pkcs && config->pkcs->prev) - config->pkcs = config->pkcs->prev; - while (config->hash_func && config->hash_func->prev) - config->hash_func = config->hash_func->prev; - while (config->hmac && config->hmac->prev) - config->hmac = config->hmac->prev; - while (config->listen_port && config->listen_port->prev) - config->listen_port = config->listen_port->prev; - while (config->logging && config->logging->prev) - config->logging = config->logging->prev; - while (config->conn_class && config->conn_class->prev) - config->conn_class = config->conn_class->prev; - while (config->clients && config->clients->prev) - config->clients = config->clients->prev; - while (config->servers && config->servers->prev) - config->servers = config->servers->prev; - while (config->admins && config->admins->prev) - config->admins = config->admins->prev; - while (config->routers && config->routers->prev) - config->routers = config->routers->prev; - - SILC_LOG_DEBUG(("Done")); - - return TRUE; } -/* This function checks that the mask sent as argument includes all the - sections that are mandatory in SILC server. */ +/* Decrements the reference counter of a config object. If the counter + reaches 0, the config object is destroyed. */ -int silc_server_config_check_sections(uint32 checkmask) +void silc_server_config_unref(SilcServerConfigRef *ref) { - if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) { - - return FALSE; + 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) + silc_free(config->logging_info->file); + if (config->logging_warnings) + silc_free(config->logging_warnings->file); + if (config->logging_errors) + 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 SilcServerConfigServerInfo *si = config->server_info; + silc_free(si->server_name); + 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); + silc_free(si->email); + silc_free(si->user); + 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); } - if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) { - - return FALSE; + + /* Now let's destroy the lists */ + + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher, + config->cipher) + silc_free(di->name); + silc_free(di->module); + silc_free(di); } - if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) { - - return FALSE; + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash) + silc_free(di->name); + silc_free(di->module); + silc_free(di); } - if (!(checkmask & - (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) { - - return FALSE; + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac) + silc_free(di->name); + silc_free(di->hash); + silc_free(di); } - if (!(checkmask - & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) { - - return FALSE; + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs) + silc_free(di->name); + silc_free(di); } - if (!(checkmask - & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) { - - return FALSE; + 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); } - - return TRUE; -} - -/* Sets log files where log messages is saved by the server. */ - -void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked) -{ - SilcServerConfigSectionLogging *log; - - SILC_LOG_DEBUG(("Setting configured log file names")); - log = config->logging; - while (log) { - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO)) - silc_log_set_file(SILC_LOG_INFO, log->filename, log->maxsize, sked); - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING)) - silc_log_set_file(SILC_LOG_WARNING, log->filename, log->maxsize, sked); - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR)) - silc_log_set_file(SILC_LOG_ERROR, log->filename, log->maxsize, sked); - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL)) - silc_log_set_file(SILC_LOG_FATAL, log->filename, log->maxsize, sked); - - log = log->next; + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients) + silc_free(di->host); + CONFIG_FREE_AUTH(di); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins) + silc_free(di->host); + silc_free(di->user); + silc_free(di->nick); + CONFIG_FREE_AUTH(di); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied) + silc_free(di->host); + silc_free(di->reason); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer, + config->servers) + silc_free(di->host); + CONFIG_FREE_AUTH(di); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter, + config->routers) + silc_free(di->host); + silc_free(di->backup_replace_ip); + 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 server when needed. */ -bool silc_server_config_register_ciphers(SilcServerConfig config) +bool silc_server_config_register_ciphers(SilcServer server) { - SilcServerConfigSectionAlg *alg; - SilcServer server = (SilcServer)config->server; + SilcServerConfig config = server->config; + SilcServerConfigCipher *cipher = config->cipher; + char *module_path = config->module_path; SILC_LOG_DEBUG(("Registering configured ciphers")); - if (!config->cipher) + if (!cipher) /* any cipher in the config file? */ return FALSE; - alg = config->cipher; - while(alg) { - - if (!alg->sim_name) { + while (cipher) { + /* if there isn't a module_path OR there isn't a module sim name try to + * use buil-in functions */ + if (!module_path || !cipher->module) { int i; - for (i = 0; silc_default_ciphers[i].name; i++) - if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) { - silc_cipher_register(&silc_default_ciphers[i]); + if (!strcmp(silc_default_ciphers[i].name, cipher->name)) { + silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]); break; } - - if (!silc_cipher_is_supported(alg->alg_name)) { - SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name)); + if (!silc_cipher_is_supported(cipher->name)) { + SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name)); silc_server_stop(server); exit(1); } -#ifdef SILC_SIM } else { +#ifdef SILC_SIM /* Load (try at least) the crypto SIM module */ - SilcCipherObject cipher; - SilcSimContext *sim; - char *alg_name; + char buf[1023], *alg_name; + SilcCipherObject cipher_obj; + SilcSim sim; - memset(&cipher, 0, sizeof(cipher)); - cipher.name = alg->alg_name; - cipher.block_len = alg->block_len; - cipher.key_len = alg->key_len * 8; + memset(&cipher_obj, 0, sizeof(cipher_obj)); + cipher_obj.name = cipher->name; + cipher_obj.block_len = cipher->block_length; + cipher_obj.key_len = cipher->key_length * 8; - sim = silc_sim_alloc(); - sim->type = SILC_SIM_CIPHER; - sim->libname = alg->sim_name; + /* build the libname */ + snprintf(buf, sizeof(buf), "%s/%s", config->module_path, + cipher->module); + sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0); - alg_name = strdup(alg->alg_name); + alg_name = strdup(cipher->name); if (strchr(alg_name, '-')) *strchr(alg_name, '-') = '\0'; - if ((silc_sim_load(sim))) { - cipher.set_key = - silc_sim_getsym(sim, silc_sim_symname(alg_name, + if (silc_sim_load(sim)) { + cipher_obj.set_key = + silc_sim_getsym(sim, silc_sim_symname(alg_name, SILC_CIPHER_SIM_SET_KEY)); - SILC_LOG_DEBUG(("set_key=%p", cipher.set_key)); - cipher.set_key_with_string = - silc_sim_getsym(sim, silc_sim_symname(alg_name, - SILC_CIPHER_SIM_SET_KEY_WITH_STRING)); - SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string)); - cipher.encrypt = + 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)); + cipher_obj.encrypt = silc_sim_getsym(sim, silc_sim_symname(alg_name, SILC_CIPHER_SIM_ENCRYPT_CBC)); - SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt)); - cipher.decrypt = + SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt)); + cipher_obj.decrypt = silc_sim_getsym(sim, silc_sim_symname(alg_name, SILC_CIPHER_SIM_DECRYPT_CBC)); - SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt)); - cipher.context_len = + SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt)); + cipher_obj.context_len = silc_sim_getsym(sim, silc_sim_symname(alg_name, SILC_CIPHER_SIM_CONTEXT_LEN)); - SILC_LOG_DEBUG(("context_len=%p", cipher.context_len)); + SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len)); /* Put the SIM to the list of all SIM's in server */ silc_dlist_add(server->sim, sim); @@ -1317,50 +1684,22 @@ bool silc_server_config_register_ciphers(SilcServerConfig config) silc_free(alg_name); } else { SILC_LOG_ERROR(("Error configuring ciphers")); + silc_sim_free(sim); silc_server_stop(server); exit(1); } /* Register the cipher */ - silc_cipher_register(&cipher); -#endif - } - - alg = alg->next; - } - - return TRUE; -} - -/* Registers configured PKCS's. */ - -bool silc_server_config_register_pkcs(SilcServerConfig config) -{ - SilcServerConfigSectionAlg *alg = config->pkcs; - SilcServer server = (SilcServer)config->server; - - SILC_LOG_DEBUG(("Registering configured PKCS")); - - if (!config->pkcs) - return FALSE; - - while(alg) { - int i; - - for (i = 0; silc_default_pkcs[i].name; i++) - if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) { - silc_pkcs_register(&silc_default_pkcs[i]); - break; - } - - if (!silc_pkcs_is_supported(alg->alg_name)) { - SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name)); + silc_cipher_register(&cipher_obj); +#else + SILC_LOG_ERROR(("Dynamic module support not compiled, " + "can't load modules!")); silc_server_stop(server); exit(1); +#endif } - - alg = alg->next; - } + cipher = cipher->next; + } /* while */ return TRUE; } @@ -1368,82 +1707,83 @@ bool silc_server_config_register_pkcs(SilcServerConfig config) /* Registers configured hash functions. These can then be allocated by the server when needed. */ -bool silc_server_config_register_hashfuncs(SilcServerConfig config) +bool silc_server_config_register_hashfuncs(SilcServer server) { - SilcServerConfigSectionAlg *alg; - SilcServer server = (SilcServer)config->server; + SilcServerConfig config = server->config; + SilcServerConfigHash *hash = config->hash; + char *module_path = config->module_path; SILC_LOG_DEBUG(("Registering configured hash functions")); - if (!config->hash_func) + if (!hash) /* any hash func in the config file? */ return FALSE; - alg = config->hash_func; - while(alg) { - - if (!alg->sim_name) { + while (hash) { + /* if there isn't a module_path OR there isn't a module sim name try to + * use buil-in functions */ + if (!module_path || !hash->module) { int i; - for (i = 0; silc_default_hash[i].name; i++) - if (!strcmp(silc_default_hash[i].name, alg->alg_name)) { - silc_hash_register(&silc_default_hash[i]); + if (!strcmp(silc_default_hash[i].name, hash->name)) { + silc_hash_register((SilcHashObject *)&silc_default_hash[i]); break; } - - if (!silc_hash_is_supported(alg->alg_name)) { - SILC_LOG_ERROR(("Unknown hash funtion `%s'", alg->alg_name)); + if (!silc_hash_is_supported(hash->name)) { + SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name)); silc_server_stop(server); exit(1); } - -#ifdef SILC_SIM } else { +#ifdef SILC_SIM /* Load (try at least) the hash SIM module */ - SilcHashObject hash; - SilcSimContext *sim; + SilcHashObject hash_obj; + SilcSim sim; - memset(&hash, 0, sizeof(hash)); - hash.name = alg->alg_name; - hash.block_len = alg->block_len; - hash.hash_len = alg->key_len; + 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 = alg->sim_name; + sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0); if ((silc_sim_load(sim))) { - hash.init = - silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, + hash_obj.init = + silc_sim_getsym(sim, silc_sim_symname(hash->name, SILC_HASH_SIM_INIT)); - SILC_LOG_DEBUG(("init=%p", hash.init)); - hash.update = - silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, + SILC_LOG_DEBUG(("init=%p", hash_obj.init)); + hash_obj.update = + silc_sim_getsym(sim, silc_sim_symname(hash->name, SILC_HASH_SIM_UPDATE)); - SILC_LOG_DEBUG(("update=%p", hash.update)); - hash.final = - silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, + SILC_LOG_DEBUG(("update=%p", hash_obj.update)); + hash_obj.final = + silc_sim_getsym(sim, silc_sim_symname(hash->name, SILC_HASH_SIM_FINAL)); - SILC_LOG_DEBUG(("final=%p", hash.final)); - hash.context_len = - silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, + SILC_LOG_DEBUG(("final=%p", hash_obj.final)); + hash_obj.context_len = + silc_sim_getsym(sim, silc_sim_symname(hash->name, SILC_HASH_SIM_CONTEXT_LEN)); - SILC_LOG_DEBUG(("context_len=%p", hash.context_len)); + SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len)); /* Put the SIM to the table of all SIM's in 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); } /* Register the hash function */ - silc_hash_register(&hash); + silc_hash_register(&hash_obj); +#else + SILC_LOG_ERROR(("Dynamic module support not compiled, " + "can't load modules!")); + silc_server_stop(server); + exit(1); #endif } - - alg = alg->next; - } + hash = hash->next; + } /* while */ return TRUE; } @@ -1451,125 +1791,204 @@ bool silc_server_config_register_hashfuncs(SilcServerConfig config) /* Registers configure HMACs. These can then be allocated by the server when needed. */ -bool silc_server_config_register_hmacs(SilcServerConfig config) +bool silc_server_config_register_hmacs(SilcServer server) { - SilcServerConfigSectionAlg *alg; - SilcServer server = (SilcServer)config->server; + SilcServerConfig config = server->config; + SilcServerConfigHmac *hmac = config->hmac; SILC_LOG_DEBUG(("Registering configured HMACs")); - if (!config->hmac) + if (!hmac) return FALSE; - alg = config->hmac; - while(alg) { - SilcHmacObject hmac; - - if (!silc_hash_is_supported(alg->sim_name)) { - SILC_LOG_ERROR(("Unknown hash function `%s'", alg->sim_name)); + while (hmac) { + SilcHmacObject hmac_obj; + if (!silc_hash_is_supported(hmac->hash)) { + SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash)); silc_server_stop(server); exit(1); } - + /* Register the HMAC */ - memset(&hmac, 0, sizeof(hmac)); - hmac.name = alg->alg_name; - hmac.len = alg->key_len; - silc_hmac_register(&hmac); + memset(&hmac_obj, 0, sizeof(hmac_obj)); + hmac_obj.name = hmac->name; + hmac_obj.len = hmac->mac_length; + silc_hmac_register(&hmac_obj); - alg = alg->next; - } + hmac = hmac->next; + } /* while */ return TRUE; } -/* Returns client authentication information from server configuration - by host (name or ip). If `port' is non-null then both name or IP and - the port must match. */ +/* Registers configured PKCS's. */ -SilcServerConfigSectionClientConnection * -silc_server_config_find_client_conn(SilcServerConfig config, - char *host, int port) +bool silc_server_config_register_pkcs(SilcServer server) { - int i; - SilcServerConfigSectionClientConnection *client = NULL; - bool match = FALSE; + SilcServerConfig config = server->config; + SilcServerConfigPkcs *pkcs = config->pkcs; - if (!host) - return NULL; + SILC_LOG_DEBUG(("Registering configured PKCS")); - if (!config->clients) - return NULL; + if (!pkcs) + return FALSE; - client = config->clients; + while (pkcs) { + int i; + for (i = 0; silc_default_pkcs[i].name; i++) + if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) { + silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]); + break; + } + if (!silc_pkcs_is_supported(pkcs->name)) { + SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name)); + silc_server_stop(server); + exit(1); + } + pkcs = pkcs->next; + } /* while */ - for (i = 0; client; i++) { - if (silc_string_compare(client->host, host)) - match = TRUE; + return TRUE; +} - if (port && client->port && client->port != port) - match = FALSE; +/* Sets log files where log messages are saved by the server logger. */ - if (match) - break; +void silc_server_config_setlogfiles(SilcServer server) +{ + SilcServerConfig config = server->config; + SilcServerConfigLogging *this; + + 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_fatals)) + 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); +} - client = client->next; - } +/* Returns client authentication information from configuration file by host + (name or ip) */ + +SilcServerConfigClient * +silc_server_config_find_client(SilcServer server, char *host) +{ + SilcServerConfig config = server->config; + SilcServerConfigClient *client; - if (!client) + if (!config || !host) return NULL; + for (client = config->clients; client; client = client->next) { + if (client->host && !silc_string_compare(client->host, host)) + continue; + break; + } + + /* if none matched, then client is already NULL */ return client; } -/* 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. */ +/* Returns admin connection configuration by host, username and/or + nickname. */ -SilcServerConfigSectionServerConnection * -silc_server_config_find_server_conn(SilcServerConfig config, - char *host, int port) +SilcServerConfigAdmin * +silc_server_config_find_admin(SilcServer server, char *host, char *user, + char *nick) { - int i; - SilcServerConfigSectionServerConnection *serv = NULL; - bool match = FALSE; + SilcServerConfig config = server->config; + SilcServerConfigAdmin *admin; + /* make sure we have a value for the matching parameters */ if (!host) - return NULL; + host = "*"; + if (!user) + user = "*"; + if (!nick) + nick = "*"; - if (!config->servers) - return NULL; + for (admin = config->admins; admin; admin = admin->next) { + if (admin->host && !silc_string_compare(admin->host, host)) + continue; + if (admin->user && !silc_string_compare(admin->user, user)) + continue; + if (admin->nick && !silc_string_compare(admin->nick, nick)) + continue; + /* no checks failed -> this entry matches */ + break; + } - serv = config->servers; - for (i = 0; serv; i++) { - if (silc_string_compare(serv->host, host)) - match = TRUE; + /* if none matched, then admin is already NULL */ + return admin; +} - if (port && serv->port && serv->port != port) - match = FALSE; +/* Returns the denied connection configuration entry by host. */ - if (match) - break; +SilcServerConfigDeny * +silc_server_config_find_denied(SilcServer server, char *host) +{ + SilcServerConfig config = server->config; + SilcServerConfigDeny *deny; - serv = serv->next; + /* make sure we have a value for the matching parameters */ + if (!config || !host) + return NULL; + + for (deny = config->denied; deny; deny = deny->next) { + if (deny->host && !silc_string_compare(deny->host, host)) + continue; + break; } - if (!serv) + /* if none matched, then deny is already NULL */ + return deny; +} + +/* Returns server connection info from server configuartion by host + (name or ip). */ + +SilcServerConfigServer * +silc_server_config_find_server_conn(SilcServer server, char *host) +{ + SilcServerConfig config = server->config; + SilcServerConfigServer *serv = NULL; + + if (!host) + return NULL; + + if (!config->servers) return NULL; + for (serv = config->servers; serv; serv = serv->next) { + if (!silc_string_compare(serv->host, host)) + continue; + break; + } + return serv; } -/* Returns router connection info from server configuartion by +/* Returns router connection info from server configuration by host (name or ip). */ -SilcServerConfigSectionServerConnection * -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; - SilcServerConfigSectionServerConnection *serv = NULL; - bool match = FALSE; + SilcServerConfig config = server->config; + SilcServerConfigRouter *serv = NULL; if (!host) return NULL; @@ -1577,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 (!host) + return NULL; - if (!serv) + 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 configuartion for a router connection that we are +/* 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; - SilcServerConfigSectionServerConnection *serv = NULL; bool found = FALSE; serv = config->routers; @@ -1622,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. */ -SilcServerConfigSectionServerConnection * -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; - SilcServerConfigSectionServerConnection *serv = NULL; serv = config->routers; for (i = 0; serv; i++) { @@ -1638,74 +2075,30 @@ silc_server_config_get_primary_router(SilcServerConfig config) return NULL; } -/* Returns Admin connection configuration by host, username and/or - nickname. */ - -SilcServerConfigSectionAdminConnection * -silc_server_config_find_admin(SilcServerConfig config, - char *host, char *username, char *nickname) -{ - SilcServerConfigSectionAdminConnection *admin = NULL; - int i; - - if (!config->admins) - return NULL; - - if (!host) - host = "*"; - if (!username) - username = "*"; - if (!nickname) - nickname = "*"; - - admin = config->admins; - for (i = 0; admin; i++) { - if (silc_string_compare(admin->host, host) && - silc_string_compare(admin->username, username) && - silc_string_compare(admin->nickname, nickname)) - break; - - admin = admin->next; - } - - if (!admin) - return NULL; - - return admin; -} - -/* Returns the Denied connection configuration by host and port. */ +/* If we have backup router configured that is going to replace us this + function returns it. */ -SilcServerConfigSectionDenyConnection * -silc_server_config_denied_conn(SilcServerConfig config, char *host, - int port) +SilcServerConfigRouter * +silc_server_config_get_backup_router(SilcServer server) { + SilcServerConfig config = server->config; + SilcServerConfigRouter *serv = NULL; int i; - SilcServerConfigSectionDenyConnection *deny = NULL; - bool match = FALSE; - - if (!host) - return NULL; - if (!config->denied) + if (server->server_type != SILC_ROUTER) return NULL; - deny = config->denied; - for (i = 0; deny; i++) { - if (silc_string_compare(deny->host, host)) - match = TRUE; - - if (port && deny->port && deny->port != port) - match = FALSE; - - if (match) - break; - - deny = deny->next; + 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; } - if (!deny) - return NULL; - - return deny; + return NULL; }