From: Giovanni Giacobbi Date: Wed, 13 Feb 2002 11:56:01 +0000 (+0000) Subject: New silcconfig library and server parser. Merged silc-newconfig-final.patch. X-Git-Tag: silc.client.0.8.1~72 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=d47a87b03b846e2333ef57b2c0d81f1644992964;hp=e3654ab77286898065796f3aba10ab9d22446190 New silcconfig library and server parser. Merged silc-newconfig-final.patch. --- diff --git a/CHANGES b/CHANGES index 65d6f219..f3617b11 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,16 @@ +Wed Feb 13 12:46:25 CET 2002 Johnny Mnemonic + + * Merged the new SILC Config library, with the server parsing + support. Read the header file silcconfig.h or the toolkit + documentation for the news. Affected files are + doc/example_silcd.conf.in lib/silcutil/silcconfig.[ch] + silcd/command.c silcd/packet_receive.c silcd/packet_send.c + silcd/protocol.c silcd/server.c silcd/server_backup.c + silcd/serverconfig.[ch] silcd/silcd.c. + + * Fixed some silclog documentation. Affected file is + lib/silcutil/silclog.h. + Sun Feb 10 18:11:30 EET 2002 Pekka Riikonen * The silc_cipher_register, silc_hash_register and diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 3b3a8b5c..b4d5bcee 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -2849,10 +2849,10 @@ SILC_SERVER_CMD_FUNC(info) memset(info_string, 0, sizeof(info_string)); snprintf(info_string, sizeof(info_string), "location: %s server: %s admin: %s <%s>", - server->config->admin_info->location, - server->config->admin_info->server_type, - server->config->admin_info->admin_name, - server->config->admin_info->admin_email); + server->config->server_info->location, + server->config->server_info->server_type, + server->config->server_info->admin, + server->config->server_info->email); server_info = info_string; entry = server->id_entry; @@ -3526,10 +3526,10 @@ SILC_SERVER_CMD_FUNC(motd) idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER); - if (server->config && server->config->motd && - server->config->motd->motd_file) { + if (server->config && server->config->server_info && + server->config->server_info->motd_file) { /* Send motd */ - motd = silc_file_readfile(server->config->motd->motd_file, &motd_len); + motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len); if (!motd) goto out; @@ -4583,7 +4583,7 @@ SILC_SERVER_CMD_FUNC(oper) SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; unsigned char *username, *auth; uint32 tmp_len; - SilcServerConfigSectionAdminConnection *admin; + SilcServerConfigSectionAdmin *admin; SilcIDListData idata = (SilcIDListData)client; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2); @@ -4661,7 +4661,7 @@ SILC_SERVER_CMD_FUNC(silcoper) SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; unsigned char *username, *auth; uint32 tmp_len; - SilcServerConfigSectionAdminConnection *admin; + SilcServerConfigSectionAdmin *admin; SilcIDListData idata = (SilcIDListData)client; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2); diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index d1f6db8a..2f3aa2f7 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2499,7 +2499,7 @@ void silc_server_connection_auth_request(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet) { - SilcServerConfigSectionClientConnection *client = NULL; + SilcServerConfigSectionClient *client = NULL; uint16 conn_type; int ret, port; SilcAuthMethod auth_meth; @@ -2523,11 +2523,11 @@ void silc_server_connection_auth_request(SilcServer server, /* Get the authentication method for the client */ auth_meth = SILC_AUTH_NONE; port = server->sockets[server->sock]->port; /* Listenning port */ - client = silc_server_config_find_client_conn(server->config, + client = silc_server_config_find_client(server->config, sock->ip, port); if (!client) - client = silc_server_config_find_client_conn(server->config, + client = silc_server_config_find_client(server->config, sock->hostname, port); if (client) diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 2c8786c3..d2d21517 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -1036,13 +1036,14 @@ void silc_server_send_private_message(SilcServer server, void silc_server_send_motd(SilcServer server, SilcSocketConnection sock) { - char *motd; + char *motd, *motd_file = NULL; uint32 motd_len; - if (server->config && server->config->motd && - server->config->motd->motd_file) { + if (server->config) + motd_file = server->config->server_info->motd_file; - motd = silc_file_readfile(server->config->motd->motd_file, &motd_len); + if (motd_file) { + motd = silc_file_readfile(motd_file, &motd_len); if (!motd) return; diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index d5a287d5..a7a1b707 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -906,7 +906,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is client */ if (conn_type == SILC_SOCKET_TYPE_CLIENT) { - SilcServerConfigSectionClientConnection *client = ctx->cconfig; + SilcServerConfigSectionClient *client = ctx->cconfig; if (client) { switch(client->auth_meth) { @@ -968,7 +968,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is server */ if (conn_type == SILC_SOCKET_TYPE_SERVER) { - SilcServerConfigSectionServerConnection *serv = ctx->sconfig; + SilcServerConfigSectionServer *serv = ctx->sconfig; if (serv) { switch(serv->auth_meth) { @@ -1030,7 +1030,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is router */ if (conn_type == SILC_SOCKET_TYPE_ROUTER) { - SilcServerConfigSectionServerConnection *serv = ctx->rconfig; + SilcServerConfigSectionRouter *serv = ctx->rconfig; if (serv) { switch(serv->auth_meth) { diff --git a/apps/silcd/server.c b/apps/silcd/server.c index d033284d..f0ed13f8 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -115,21 +115,20 @@ int silc_server_init(SilcServer server) SilcServerID *id; SilcServerEntry id_entry; SilcIDListPurge purge; - SilcServerConfigSectionListenPort *listen; SILC_LOG_DEBUG(("Initializing server")); assert(server); assert(server->config); /* Set public and private keys */ - if (!server->config->server_keys || - !server->config->server_keys->public_key || - !server->config->server_keys->private_key) { + if (!server->config->server_info || + !server->config->server_info->public_key || + !server->config->server_info->private_key) { SILC_LOG_ERROR(("Server public key and/or private key does not exist")); return FALSE; } - server->public_key = server->config->server_keys->public_key; - server->private_key = server->config->server_keys->private_key; + server->public_key = server->config->server_info->public_key; + server->private_key = server->config->server_info->private_key; /* XXX After server is made as Silc Server Library this can be given as argument, for now this is hard coded */ @@ -141,17 +140,14 @@ int silc_server_init(SilcServer server) server->params->protocol_timeout = 60; server->params->require_reverse_mapping = FALSE; - /* Set log files where log message should be saved. */ - server->config->server = server; - /* Register all configured ciphers, PKCS and hash functions. */ - if (!silc_server_config_register_ciphers(server->config)) + if (!silc_server_config_register_ciphers(server)) silc_cipher_register_default(); - if (!silc_server_config_register_pkcs(server->config)) + if (!silc_server_config_register_pkcs(server)) silc_pkcs_register_default(); - if (!silc_server_config_register_hashfuncs(server->config)) + if (!silc_server_config_register_hashfuncs(server)) silc_hash_register_default(); - if (!silc_server_config_register_hmacs(server->config)) + if (!silc_server_config_register_hmacs(server)) silc_hmac_register_default(); /* Initialize random number generator for the server. */ @@ -171,24 +167,23 @@ int silc_server_init(SilcServer server) /* Create a listening server. Note that our server can listen on multiple ports. All listeners are created here and now. */ sock_count = 0; - listen = server->config->listen_port; - while(listen) { + while (1) { int tmp; - tmp = silc_net_create_server(server->config->listen_port->port, - server->config->listen_port->listener_ip); + tmp = silc_net_create_server(server->config->server_info->port, + server->config->server_info->server_ip); if (tmp < 0) { - SILC_LOG_ERROR(("Could not create server listener: %s on %d", - server->config->listen_port->listener_ip, - server->config->listen_port->port)); + SILC_LOG_ERROR(("Could not create server listener: %s on %hd", + server->config->server_info->server_ip, + server->config->server_info->port)); goto err0; } sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1)); sock[sock_count] = tmp; sock_count++; - listen = listen->next; + break; } /* Initialize ID caches */ @@ -307,7 +302,7 @@ int silc_server_init(SilcServer server) /* If server connections has been configured then we must be router as normal server cannot have server connections, only router connections. */ if (server->config->servers) { - SilcServerConfigSectionServerConnection *ptr = server->config->servers; + SilcServerConfigSectionServer *ptr = server->config->servers; server->server_type = SILC_ROUTER; while (ptr) { @@ -390,8 +385,7 @@ void silc_server_drop(SilcServer server) struct group *gr; char *user, *group; - if (!server->config->identity || !server->config->identity->user || - !server->config->identity->group) { + if (!server->config->server_info->user || !server->config->server_info->group) { fprintf(stderr, "Error:" "\tSILC server must not be run as root. For the security of your\n" "\tsystem it is strongly suggested that you run SILC under dedicated\n" @@ -401,8 +395,8 @@ void silc_server_drop(SilcServer server) } /* Get the values given for user and group in configuration file */ - user=server->config->identity->user; - group=server->config->identity->group; + user=server->config->server_info->user; + group=server->config->server_info->group; /* Check whether the user/group information is text */ if (atoi(user)!=0 || atoi(group)!=0) { @@ -635,7 +629,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router) server->router_connect = time(0); /* Connect to remote host */ - sock = silc_net_create_connection(server->config->listen_port->local_ip, + sock = silc_net_create_connection(server->config->server_info->server_ip, sconn->remote_port, sconn->remote_host); if (sock < 0) { @@ -662,7 +656,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) { SilcServer server = (SilcServer)context; SilcServerConnection sconn; - SilcServerConfigSectionServerConnection *ptr; + SilcServerConfigSectionRouter *ptr; SILC_LOG_DEBUG(("Connecting to router(s)")); @@ -729,7 +723,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) SilcServerConnection sconn = (SilcServerConnection)ctx->context; SilcSocketConnection sock = ctx->sock; SilcServerConnAuthInternalContext *proto_ctx; - SilcServerConfigSectionServerConnection *conn = NULL; + SilcServerConfigSectionRouter *conn = NULL; SILC_LOG_DEBUG(("Start")); @@ -1024,7 +1018,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, SilcServer server = (SilcServer)context; SilcServerKEInternalContext *proto_ctx; void *cconfig, *sconfig, *rconfig; - SilcServerConfigSectionDenyConnection *deny; + SilcServerConfigSectionDeny *deny; int port; SILC_LOG_DEBUG(("Start")); @@ -1055,16 +1049,16 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, port = server->sockets[server->sock]->port; /* Listenning port */ /* Check whether this connection is denied to connect to us. */ - deny = silc_server_config_denied_conn(server->config, sock->ip, port); + deny = silc_server_config_find_denied(server->config, sock->ip, port); if (!deny) - deny = silc_server_config_denied_conn(server->config, sock->hostname, + deny = silc_server_config_find_denied(server->config, sock->hostname, port); if (deny) { /* The connection is denied */ SILC_LOG_INFO(("Connection %s (%s) is denied", sock->hostname, sock->ip)); - silc_server_disconnect_remote(server, sock, deny->comment ? - deny->comment : + silc_server_disconnect_remote(server, sock, deny->reason ? + deny->reason : "Server closed connection: " "Connection refused"); server->stat.conn_failures++; @@ -1074,9 +1068,9 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, /* Check whether we have configred this sort of connection at all. We have to check all configurations since we don't know what type of connection this is. */ - if (!(cconfig = silc_server_config_find_client_conn(server->config, + if (!(cconfig = silc_server_config_find_client(server->config, sock->ip, port))) - cconfig = silc_server_config_find_client_conn(server->config, + cconfig = silc_server_config_find_client(server->config, sock->hostname, port); if (!(sconfig = silc_server_config_find_server_conn(server->config, @@ -1358,7 +1352,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) case SILC_SOCKET_TYPE_ROUTER: { SilcServerEntry new_server; - SilcServerConfigSectionServerConnection *conn = + /* XXX FIXME: Now server and router has different table, so this is probably broken. */ + SilcServerConfigSectionRouter *conn = ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? ctx->sconfig : ctx->rconfig; diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index 4bcf0b11..6b3d876a 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -524,7 +524,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router) sconn->remote_port)); /* Connect to remote host */ - sock = silc_net_create_connection(server->config->listen_port->local_ip, + sock = silc_net_create_connection(server->config->server_info->server_ip, sconn->remote_port, sconn->remote_host); if (sock < 0) { @@ -867,7 +867,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) protocol->state++; } else { /* Responder of the protocol. */ - SilcServerConfigSectionServerConnection *primary; + SilcServerConfigSectionRouter *primary; /* We should have received START or START_GLOBAL packet */ if (ctx->type != SILC_SERVER_BACKUP_START && diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index 5a8f731d..e51039d6 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 @@ -22,1314 +22,1136 @@ #include "serverincludes.h" #include "server_internal.h" -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. */ +#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd" +#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey" -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 + +/* 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; \ } - 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; - - silc_buffer_free(buffer); - - return new; - - fail: - silc_buffer_free(buffer); - silc_free(new); - return NULL; -} +/* 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; -/* Free's a configuration object. */ - -void silc_server_config_free(SilcServerConfig config) +/* free an authdata according to its auth method */ +static void my_free_authdata(SilcAuthMethod auth_meth, void *auth_data) { - 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); + if (auth_meth == SILC_AUTH_PASSWORD) { + silc_free(auth_data); + } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) { + silc_pkcs_public_key_free((SilcPublicKey) auth_data); } } -/* 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. */ - -int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, - SilcServerConfigParse *return_config) +/* parse an authdata according to its auth method */ +static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line, + void **auth_data, uint32 *auth_data_len) { - 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; - - /* 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; - } - 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); + if (auth_meth == SILC_AUTH_PASSWORD) { + /* p is a plain text password */ + *auth_data = (void *) strdup(p); + *auth_data_len = (uint32) strlen(p); + } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) { + /* p is a public key */ + SilcPublicKey public_key; + + if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "\nError while parsing config file at line %lu: " + "Could not load public key file!\n", line); 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; - } + *auth_data = (void *) public_key; + *auth_data_len = 0; + } else { + fprintf(stderr, "\nError while parsing config file at line %lu: Specify " + "the AuthMethod before specifying the AuthData.\n", line); + return FALSE; } - - /* Set the return_config argument to its first value so that further - parsing can be started from the first line. */ - *return_config = first; - 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. */ +/* Callbacks */ -int silc_server_config_parse_lines(SilcServerConfig config, - SilcServerConfigParse parse_config) +SILC_CONFIG_CALLBACK(fetch_generic) { - int ret, check = FALSE; - uint32 checkmask; - char *tmp; - SilcServerConfigParse pc = parse_config; - SilcBuffer line; - - SILC_LOG_DEBUG(("Parsing configuration lines")); - - if (!config) - 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: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port); - - /* Get local IP */ - ret = silc_config_get_token(line, &config->listen_port->local_ip); - if (ret < 0) - break; - - /* Get listener IP */ - ret = silc_config_get_token(line, &config->listen_port->listener_ip); - if (ret < 0) - break; - - /* 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); - } - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY: - - if (!config->identity) - config->identity = silc_calloc(1, sizeof(*config->identity)); - - /* Get user */ - ret = silc_config_get_token(line, &config->identity->user); - if (ret < 0) - break; - /* Get group */ - ret = silc_config_get_token(line, &config->identity->group); - if (ret < 0) - break; - - check = TRUE; - checkmask |= (1L << pc->section->type); - - case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class); - - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - /* Class number not defined */ - - } - config->conn_class->class = atoi(tmp); - silc_free(tmp); - - /* Get ping frequency */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->ping_freq = atoi(tmp); - silc_free(tmp); - - /* Get connect frequency */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->connect_freq = atoi(tmp); - silc_free(tmp); - - /* Get max links */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - config->conn_class->max_links = atoi(tmp); - silc_free(tmp); - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->logging); - - /* 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) - && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_QUICK) - && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) { - fprintf(stderr, "%s:%d: Unknown log file section '%s'\n", - config->filename, pc->linenum, config->logging->logtype); - break; - } - - /* 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; - } - - /* 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); - } - - 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); - } - - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->clients->auth_data); - if (ret < 0) - break; - - if (config->clients->auth_meth == SILC_AUTH_PASSWORD) { - config->clients->auth_data_len = strlen(config->clients->auth_data); - } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->clients->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->clients->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->clients->auth_data); - break; - } - - silc_free(config->clients->auth_data); - config->clients->auth_data = (void *)public_key; - config->clients->auth_data_len = 0; - } - - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->clients->port = atoi(tmp); - silc_free(tmp); - } - - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->clients->class = atoi(tmp); - silc_free(tmp); - } - - check = TRUE; - checkmask |= (1L << pc->section->type); - break; - - case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION: - - SILC_SERVER_CONFIG_LIST_ALLOC(config->servers); - - /* Get host */ - ret = silc_config_get_token(line, &config->servers->host); - if (ret < 0) - break; - if (ret == 0) - /* Any host */ - config->servers->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->servers->auth_meth = SILC_AUTH_PASSWORD; - - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY; - - silc_free(tmp); - } - - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->servers->auth_data); - if (ret < 0) - break; - - if (config->servers->auth_meth == SILC_AUTH_PASSWORD) { - config->servers->auth_data_len = strlen(config->servers->auth_data); - } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) { - /* Get the public key */ - SilcPublicKey public_key; - - if (!silc_pkcs_load_public_key(config->servers->auth_data, - &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(config->servers->auth_data, - &public_key, SILC_PKCS_FILE_BIN)) { - fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", - config->filename, pc->linenum, - (char *)config->servers->auth_data); - break; - } - - silc_free(config->servers->auth_data); - config->servers->auth_data = (void *)public_key; - config->servers->auth_data_len = 0; - } - - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->servers->port = atoi(tmp); - silc_free(tmp); - } - - /* Get version */ - ret = silc_config_get_token(line, &config->servers->version); - if (ret < 0) - break; + SilcServerConfig config = (SilcServerConfig) context; - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->servers->class = atoi(tmp); - silc_free(tmp); - } + if (!strcmp(name, "modulepath")) { + if (config->module_path) return SILC_CONFIG_EDOUBLE; + /* dup it only if non-empty, otherwise point it to NULL */ + config->module_path = (*(char *)val ? strdup((char *) val) : NULL); + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; +} - /* 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); - } +SILC_CONFIG_CALLBACK(fetch_cipher) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionCipher); + + SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->name) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionCipher *) config->tmp; + } - check = TRUE; - checkmask |= (1L << pc->section->type); - break; + /* Identify and save this value */ + if (!strcmp(name, "name")) { + if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "module")) { /* can be empty */ + if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + /* dup it only if non-empty, otherwise point it to NULL */ + tmp->module = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "key_length")) + tmp->key_length = *(uint32 *)val; + else if (!strcmp(name, "block_length")) + tmp->block_length = *(uint32 *)val; + else + 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; +} - case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION: +SILC_CONFIG_CALLBACK(fetch_hash) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHash); + + SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct in tmp is ok */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionHash *) config->tmp; + } - SILC_SERVER_CONFIG_LIST_ALLOC(config->routers); + /* Identify and save this value */ + if (!strcmp(name, "name")) { + if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "module")) { /* can be empty */ + if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + /* dup it only if non-empty, otherwise point it to NULL */ + tmp->module = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "block_length")) + tmp->block_length = *(int *)val; + else if (!strcmp(name, "digest_length")) + 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 host */ - ret = silc_config_get_token(line, &config->routers->host); - if (ret < 0) - break; +SILC_CONFIG_CALLBACK(fetch_hmac) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHmac); + + SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionHmac *) config->tmp; + } - /* 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; - } + /* Identify and save this value */ + if (!strcmp(name, "name")) { + if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->name = strdup((char *) val); + } + else if (!strcmp(name, "hash")) { + if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->hash = strdup((char *) val); + } + else if (!strcmp(name, "mac_length")) + 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; +} - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->routers->auth_meth = SILC_AUTH_PASSWORD; +SILC_CONFIG_CALLBACK(fetch_pkcs) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionPkcs); + + SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->name) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionPkcs *) config->tmp; + } - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY; + /* Identify and save this value */ + if (!strcmp(name, "name")) { + if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + 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; +} - silc_free(tmp); - } +SILC_CONFIG_CALLBACK(fetch_serverinfo) +{ + SilcServerConfig config = (SilcServerConfig) context; + SilcServerConfigSectionServerInfo *server_info = config->server_info; - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->routers->auth_data); - if (ret < 0) - break; + /* if there isn't the struct alloc it */ + if (!server_info) { + config->server_info = server_info = (SilcServerConfigSectionServerInfo *) + silc_calloc(1, sizeof(*server_info)); + } - 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; + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check for mandatory inputs */ + return SILC_CONFIG_OK; + } + if (!strcmp(name, "hostname")) { + if (server_info->server_name) return SILC_CONFIG_EDOUBLE; + server_info->server_name = strdup((char *) val); + } + else if (!strcmp(name, "ip")) { + if (server_info->server_ip) return SILC_CONFIG_EDOUBLE; + server_info->server_ip = strdup((char *) val); + } + else if (!strcmp(name, "port")) { + int port = *(int *)val; + if ((port <= 0) || (port > 65535)) { + fprintf(stderr, "Invalid port number!\n"); + return SILC_CONFIG_ESILENT; + } + server_info->port = (uint16) port; + } + else if (!strcmp(name, "servertype")) { + if (server_info->server_type) return SILC_CONFIG_EDOUBLE; + server_info->server_type = strdup((char *) val); + } + else if (!strcmp(name, "admin")) { + if (server_info->admin) return SILC_CONFIG_EDOUBLE; + server_info->admin = strdup((char *) val); + } + else if (!strcmp(name, "email")) { + if (server_info->email) return SILC_CONFIG_EDOUBLE; + server_info->email = strdup((char *) val); + } + else if (!strcmp(name, "location")) { + if (server_info->location) return SILC_CONFIG_EDOUBLE; + server_info->location = strdup((char *) val); + } + else if (!strcmp(name, "user")) { + if (server_info->user) return SILC_CONFIG_EDOUBLE; + server_info->user = strdup((char *) val); + } + else if (!strcmp(name, "group")) { + if (server_info->group) return SILC_CONFIG_EDOUBLE; + server_info->group = strdup((char *) val); + } + else if (!strcmp(name, "motdfile")) { + if (server_info->motd_file) return SILC_CONFIG_EDOUBLE; + server_info->motd_file = strdup((char *) val); + } + else if (!strcmp(name, "pidfile")) { + if (server_info->pid_file) return SILC_CONFIG_EDOUBLE; + server_info->pid_file = strdup((char *) val); + } + else if (!strcmp(name, "publickey")) { + char *tmp = (char *) val; + + /* try to load specified file, if fail stop config parsing */ + if (!silc_pkcs_load_public_key(tmp, &server_info->public_key, + SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(tmp, &server_info->public_key, + SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "\nError: Could not load public key file."); + fprintf(stderr, "\n line %lu: file \"%s\"\n", line, tmp); + return SILC_CONFIG_ESILENT; } - - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->routers->port = atoi(tmp); - silc_free(tmp); + } + else if (!strcmp(name, "privatekey")) { + char *tmp = (char *) val; + + /* try to load specified file, if fail stop config parsing */ + if (!silc_pkcs_load_private_key(tmp, &server_info->private_key, + SILC_PKCS_FILE_BIN)) + if (!silc_pkcs_load_private_key(tmp, &server_info->private_key, + SILC_PKCS_FILE_PEM)) { + fprintf(stderr, "\nError: Could not load private key file."); + fprintf(stderr, "\n line %lu: file \"%s\"\n", line, tmp); + return SILC_CONFIG_ESILENT; } + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; +} - /* Get version */ - ret = silc_config_get_token(line, &config->routers->version); - if (ret < 0) - break; +SILC_CONFIG_CALLBACK(fetch_logging) +{ + SilcServerConfig config = (SilcServerConfig) context; + SilcServerConfigSectionLogging *tmp = + (SilcServerConfigSectionLogging *) config->tmp; + int got_errno; - /* Get class number */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret) { - config->routers->class = atoi(tmp); - silc_free(tmp); - } + if (!strcmp(name, "quicklogs")) { + silc_log_quick = *(bool *)val; + } + else if (!strcmp(name, "flushdelay")) { + int flushdelay = *(int *)val; + if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */ + fprintf(stderr, "Error: line %lu: invalid flushdelay value, use " + "quicklogs if you want real-time logging.\n", line); + return SILC_CONFIG_ESILENT; + } + silc_log_flushdelay = (long) flushdelay; + } +#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")) { + if (!tmp) { /* FIXME: what the fuck is this? */ + config->tmp = silc_calloc(1, sizeof(*tmp)); + tmp = (SilcServerConfigSectionLogging *) config->tmp; + } + if (tmp->file) { + got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err; + } + tmp->file = strdup((char *) val); + } + else if (!strcmp(name, "size")) { + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*tmp)); + tmp = (SilcServerConfigSectionLogging *) config->tmp; + } + tmp->maxsize = *(uint32 *) 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 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); - } +SILC_CONFIG_CALLBACK(fetch_client) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient); + + SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (tmp->auth_meth && !tmp->auth_data) { + fprintf(stderr, "\nError: line %lu: If you specify \"AuthMethod\" field " + "then you must also specify the \"AuthData\" field.\n", line); + got_errno = SILC_CONFIG_ESILENT; + goto got_err; + } + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionClient *) config->tmp; + } - /* 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); - } - } + /* Identify and save this value */ + if (!strcmp(name, "host")) { /* any host (*) accepted */ + if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->host = (*(char *)val ? strdup((char *) val) : NULL); + } + /* get authentication method */ + else if (!strcmp(name, "authmethod")) { + if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) + tmp->auth_meth = SILC_AUTH_PASSWORD; + else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) + tmp->auth_meth = SILC_AUTH_PUBLIC_KEY; + else { + got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err; + } + } + else if (!strcmp(name, "authdata")) { + if (!my_parse_authdata(tmp->auth_meth, (char *) val, line, + &tmp->auth_data, &tmp->auth_data_len)) { + got_errno = SILC_CONFIG_ESILENT; + goto got_err; /* error outputted in my_parse_authdata */ + } + } + else if (!strcmp(name, "port")) { + int port = *(int *)val; + if ((port <= 0) || (port > 65535)) { + fprintf(stderr, "Invalid port number!\n"); + got_errno = SILC_CONFIG_ESILENT; goto got_err; + } + tmp->port = (uint16) port; + } + /* FIXME: Improvement: use a direct class struct pointer instead of num */ + else if (!strcmp(name, "class")) { + /* XXX do nothing */ + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + my_free_authdata(tmp->auth_meth, tmp->auth_data); + silc_free(tmp); + return got_errno; +} - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +SILC_CONFIG_CALLBACK(fetch_admin) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin); + + SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->auth_meth) { + got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err; + } + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionAdmin *) config->tmp; + } - case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION: + /* Identify and save this value */ + if (!strcmp(name, "host")) { /* any host (*) accepted */ + if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->host = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "user")) { + if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->user = (*(char *)val ? strdup((char *) val) : NULL); + } + else if (!strcmp(name, "nick")) { + if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->nick = (*(char *)val ? strdup((char *) val) : NULL); + } + /* get authentication method */ + else if (!strcmp(name, "authmethod")) { + if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) + tmp->auth_meth = SILC_AUTH_PASSWORD; + else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) + tmp->auth_meth = SILC_AUTH_PUBLIC_KEY; + else { + got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err; + } + } + else if (!strcmp(name, "authdata")) { + if (!my_parse_authdata(tmp->auth_meth, (char *) val, line, + &tmp->auth_data, &tmp->auth_data_len)) { + got_errno = SILC_CONFIG_ESILENT; + goto got_err; /* error outputted in my_parse_authdata */ + } + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + silc_free(tmp->user); + silc_free(tmp->nick); + my_free_authdata(tmp->auth_meth, tmp->auth_data); + silc_free(tmp); + return got_errno; +} - SILC_SERVER_CONFIG_LIST_ALLOC(config->admins); +SILC_CONFIG_CALLBACK(fetch_deny) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny); + + SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->reason) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionDeny *) config->tmp; + } - /* Get host */ - ret = silc_config_get_token(line, &config->admins->host); - if (ret < 0) - break; - if (ret == 0) - /* Any host */ - config->admins->host = strdup("*"); + /* Identify and save this value */ + if (!strcmp(name, "host")) { /* any host (*) accepted */ + if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*")); + } + else if (!strcmp(name, "port")) { + int port = *(int *)val; + if ((port <= 0) || (port > 65535)) { + fprintf(stderr, "Invalid port number!\n"); + got_errno = SILC_CONFIG_ESILENT; goto got_err; + } + tmp->port = (uint16) port; + } + else if (!strcmp(name, "reason")) { + if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + 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); + return got_errno; +} - /* Get username */ - ret = silc_config_get_token(line, &config->admins->username); - if (ret < 0) - break; - if (ret == 0) - /* Any username */ - config->admins->username = strdup("*"); +SILC_CONFIG_CALLBACK(fetch_server) +{ + SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer); + + SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + /* check the temporary struct's fields */ + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->auth_meth || !tmp->version) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionServer *) config->tmp; + } - /* Get nickname */ - ret = silc_config_get_token(line, &config->admins->nickname); - if (ret < 0) - break; - if (ret == 0) - /* Any nickname */ - config->admins->nickname = strdup("*"); + /* Identify and save this value */ + if (!strcmp(name, "host")) { /* any host (*) accepted */ + if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*")); + } + /* get authentication method */ + else if (!strcmp(name, "authmethod")) { + if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) + tmp->auth_meth = SILC_AUTH_PASSWORD; + else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) + tmp->auth_meth = SILC_AUTH_PUBLIC_KEY; + else { + got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err; + } + } + else if (!strcmp(name, "authdata")) { + if (!my_parse_authdata(tmp->auth_meth, (char *) val, line, + &tmp->auth_data, &tmp->auth_data_len)) { + got_errno = SILC_CONFIG_ESILENT; + goto got_err; /* error outputted in my_parse_authdata */ + } + } + else if (!strcmp(name, "port")) { + int port = *(int *)val; + if ((port <= 0) || (port > 65535)) { + fprintf(stderr, "Invalid port number!\n"); + got_errno = SILC_CONFIG_ESILENT; goto got_err; + } + tmp->port = (uint16) port; + } + else if (!strcmp(name, "versionid")) { + if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->version = strdup((char *) val); + } + /* FIXME: Improvement: use a direct class struct pointer instead of num */ + else if (!strcmp(name, "class")) { + /* XXX do nothing */ + } + else if (!strcmp(name, "backup")) { + tmp->backup_router = *(bool *)val; + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + silc_free(tmp->version); + my_free_authdata(tmp->auth_meth, tmp->auth_data); + silc_free(tmp); + 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(SilcServerConfigSectionRouter); + + SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", type, name, context)); + if (type == SILC_CONFIG_ARG_BLOCK) { + if (!tmp) /* empty sub-block? */ + return SILC_CONFIG_OK; + if (!tmp->auth_meth || !tmp->version) { + got_errno = SILC_CONFIG_EMISSFIELDS; + goto got_err; + } + /* the temporary struct is ok, append it to the list */ + SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers); + config->tmp = NULL; + return SILC_CONFIG_OK; + } + /* if there isn't a temporary struct alloc one */ + if (!tmp) { + config->tmp = silc_calloc(1, sizeof(*findtmp)); + tmp = (SilcServerConfigSectionRouter *) config->tmp; + } - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) - config->admins->auth_meth = SILC_AUTH_PASSWORD; + /* Identify and save this value */ + if (!strcmp(name, "host")) { + if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->host = strdup((char *) val); + } + else if (!strcmp(name, "authmethod")) { + if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD)) + tmp->auth_meth = SILC_AUTH_PASSWORD; + else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) + tmp->auth_meth = SILC_AUTH_PUBLIC_KEY; + else { + got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err; + } + } + else if (!strcmp(name, "authdata")) { + if (!my_parse_authdata(tmp->auth_meth, (char *) val, line, + &tmp->auth_data, &tmp->auth_data_len)) { + got_errno = SILC_CONFIG_ESILENT; + goto got_err; /* error outputted in my_parse_authdata */ + } + } + else if (!strcmp(name, "port")) { + int port = *(int *)val; + if ((port <= 0) || (port > 65535)) { + fprintf(stderr, "Invalid port number!\n"); + got_errno = SILC_CONFIG_ESILENT; goto got_err; + } + tmp->port = (uint16) port; + } + else if (!strcmp(name, "versionid")) { + if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->version = strdup((char *) val); + } + /* FIXME: Improvement: use a direct class struct pointer instead of num */ + else if (!strcmp(name, "class")) { + /* XXX do nothing */ + } + else if (!strcmp(name, "initiator")) + tmp->initiator = *(bool *)val; + else if (!strcmp(name, "backuphost")) { + if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; } + tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*")); + } + else + return SILC_CONFIG_EINTERNAL; + return SILC_CONFIG_OK; + + got_err: + silc_free(tmp->host); + silc_free(tmp->version); + silc_free(tmp->backup_replace_ip); + my_free_authdata(tmp->auth_meth, tmp->auth_data); + silc_free(tmp); + return got_errno; +} - if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) - config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY; +/* known config options tables */ +static const SilcConfigTable table_general[] = { + { "modulepath", SILC_CONFIG_ARG_STRE, fetch_generic, NULL }, + { 0, 0, 0, 0 } +}; - silc_free(tmp); - } +static const SilcConfigTable table_cipher[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_cipher, NULL }, + { "module", SILC_CONFIG_ARG_STRE, fetch_cipher, NULL }, + { "key_length", SILC_CONFIG_ARG_INT, fetch_cipher, NULL }, + { "block_length", SILC_CONFIG_ARG_INT, fetch_cipher, NULL }, + { 0, 0, 0, 0 } +}; - /* Get authentication data */ - ret = silc_config_get_token(line, (char **)&config->admins->auth_data); - if (ret < 0) - break; +static const SilcConfigTable table_hash[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_hash, NULL }, + { "module", SILC_CONFIG_ARG_STRE, fetch_hash, NULL }, + { "block_length", SILC_CONFIG_ARG_INT, fetch_hash, NULL }, + { "digest_length", SILC_CONFIG_ARG_INT, fetch_hash, NULL }, + { 0, 0, 0, 0 } +}; - 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; - } +static const SilcConfigTable table_hmac[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_hmac, NULL }, + { "hash", SILC_CONFIG_ARG_STR, fetch_hmac, NULL }, + { "mac_length", SILC_CONFIG_ARG_INT, fetch_hmac, NULL }, + { 0, 0, 0, 0 } +}; - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +static const SilcConfigTable table_pkcs[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_pkcs, NULL }, + { 0, 0, 0, 0 } +}; - case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION: +static const SilcConfigTable table_serverinfo[] = { + { "hostname", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "ip", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "port", SILC_CONFIG_ARG_INT, fetch_serverinfo, NULL}, + { "servertype", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "location", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "admin", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "email", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL}, + { "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 } +}; - SILC_SERVER_CONFIG_LIST_ALLOC(config->denied); +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 } +}; - /* 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); - } +static const SilcConfigTable table_logging[] = { + { "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 } +}; - /* Get port */ - ret = silc_config_get_token(line, &tmp); - if (ret < 0) - break; - if (ret == 0) { - /* Any port */ - config->denied->port = 0; - } else { - config->denied->port = atoi(tmp); - silc_free(tmp); - } +/* still unsupported +static const SilcConfigTable table_class[] = { + { "name", SILC_CONFIG_ARG_STR, fetch_class, NULL }, + { "ping", SILC_CONFIG_ARG_INT, fetch_class, NULL }, + { "connect", SILC_CONFIG_ARG_INT, fetch_class, NULL }, + { "links", SILC_CONFIG_ARG_INT, fetch_class, NULL }, + { 0, 0, 0, 0 } +}; */ + +static const SilcConfigTable table_client[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_client, NULL }, + { "authmethod", SILC_CONFIG_ARG_STR, fetch_client, NULL }, + { "authdata", SILC_CONFIG_ARG_STR, fetch_client, NULL }, + { "port", SILC_CONFIG_ARG_INT, fetch_client, NULL }, + { "class", SILC_CONFIG_ARG_STR, fetch_client, NULL }, + { 0, 0, 0, 0 } +}; - /* Get comment */ - ret = silc_config_get_token(line, &config->denied->comment); - if (ret < 0) - break; +static const SilcConfigTable table_admin[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_admin, NULL }, + { "user", SILC_CONFIG_ARG_STRE, fetch_admin, NULL }, + { "nick", SILC_CONFIG_ARG_STRE, fetch_admin, NULL }, + { "authmethod", SILC_CONFIG_ARG_STR, fetch_admin, NULL }, + { "authdata", SILC_CONFIG_ARG_STR, fetch_admin, NULL }, + { "port", SILC_CONFIG_ARG_INT, fetch_admin, NULL }, + { "class", SILC_CONFIG_ARG_STR, fetch_admin, NULL }, + { 0, 0, 0, 0 } +}; - check = TRUE; - checkmask |= (1L << pc->section->type); - break; +static const SilcConfigTable table_deny[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_deny, NULL }, + { "port", SILC_CONFIG_ARG_INT, fetch_deny, NULL }, + { "reason", SILC_CONFIG_ARG_STR, fetch_deny, NULL }, + { 0, 0, 0, 0 } +}; - case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD: +static const SilcConfigTable table_serverconn[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_server, NULL }, + { "authmethod", SILC_CONFIG_ARG_STR, fetch_server, NULL }, + { "authdata", SILC_CONFIG_ARG_STR, fetch_server, NULL }, + { "port", SILC_CONFIG_ARG_INT, fetch_server, NULL }, + { "versionid", SILC_CONFIG_ARG_STR, fetch_server, NULL }, + { "class", SILC_CONFIG_ARG_STR, fetch_server, NULL }, + { "backup", SILC_CONFIG_ARG_TOGGLE, fetch_server, NULL }, + { 0, 0, 0, 0 } +}; - if (!config->motd) - config->motd = silc_calloc(1, sizeof(*config->motd)); +static const SilcConfigTable table_routerconn[] = { + { "host", SILC_CONFIG_ARG_STRE, fetch_router, NULL }, + { "authmethod", SILC_CONFIG_ARG_STR, fetch_router, NULL }, + { "authdata", SILC_CONFIG_ARG_STR, fetch_router, NULL }, + { "port", SILC_CONFIG_ARG_INT, fetch_router, NULL }, + { "versionid", SILC_CONFIG_ARG_STR, fetch_router, NULL }, + { "class", SILC_CONFIG_ARG_STR, fetch_router, NULL }, + { "initiator", SILC_CONFIG_ARG_TOGGLE, fetch_router, NULL }, + { "backuphost", SILC_CONFIG_ARG_STRE, fetch_router, NULL }, + { "backupport", SILC_CONFIG_ARG_INT, fetch_router, NULL }, + { "localbackup", SILC_CONFIG_ARG_TOGGLE, fetch_router, NULL }, + { 0, 0, 0, 0 } +}; - /* Get motd file */ - ret = silc_config_get_token(line, &config->motd->motd_file); - if (ret < 0) - break; +static const SilcConfigTable table_main[] = { + { "general", SILC_CONFIG_ARG_BLOCK, NULL, table_general }, + { "cipher", SILC_CONFIG_ARG_BLOCK, fetch_cipher, table_cipher }, + { "hash", SILC_CONFIG_ARG_BLOCK, fetch_hash, table_hash }, + { "hmac", SILC_CONFIG_ARG_BLOCK, fetch_hmac, table_hmac }, + { "pkcs", SILC_CONFIG_ARG_BLOCK, fetch_pkcs, table_pkcs }, + { "serverinfo", SILC_CONFIG_ARG_BLOCK, fetch_serverinfo, table_serverinfo }, + { "logging", SILC_CONFIG_ARG_BLOCK, NULL, table_logging }, +/*{ "class", SILC_CONFIG_ARG_BLOCK, fetch_class, table_class }, */ + { "client", SILC_CONFIG_ARG_BLOCK, fetch_client, table_client }, + { "admin", SILC_CONFIG_ARG_BLOCK, fetch_admin, table_admin }, + { "deny", SILC_CONFIG_ARG_BLOCK, fetch_deny, table_deny }, + { "serverconnection", SILC_CONFIG_ARG_BLOCK, fetch_server, table_serverconn }, + { "routerconnection", SILC_CONFIG_ARG_BLOCK, fetch_router, table_routerconn }, + { 0, 0, 0, 0 } +}; - 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. */ - 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; - } +SilcServerConfig silc_server_config_alloc(char *filename) +{ + SilcServerConfig config; + SilcConfigEntity ent; + SilcConfigFile *file; + int ret; + SILC_LOG_DEBUG(("Loading config data from `%s'", filename)); - /* Check for error */ - if (check == FALSE) { - /* Line could not be parsed */ - fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum); - break; + /* alloc a config object */ + config = (SilcServerConfig) silc_calloc(1, sizeof(*config)); + /* obtain a config file object */ + file = silc_config_open(filename); + if (!file) { + fprintf(stderr, "\nError: can't open config file `%s'\n", filename); + return NULL; + } + /* obtain a SilcConfig entity, we can use it to start the parsing */ + ent = silc_config_init(file); + /* load the known configuration options, give our empty object as context */ + silc_config_register_table(ent, table_main, (void *) config); + /* 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); + uint32 line = silc_config_get_line(file); + fprintf(stderr, "\nError while parsing config file: %s.\n", + silc_config_strerror(ret)); + linebuf = silc_config_read_line(file, line); + fprintf(stderr, " file %s line %lu: %s\n\n", filename, line, linebuf); + silc_free(linebuf); } - - pc = pc->next; + return NULL; } + /* close (destroy) the file object */ + silc_config_close(file); - if (check == FALSE) - return FALSE; - - /* 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 */ - - } - - /* 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; + /* XXX FIXME: check for missing mandatory fields */ + if (!config->server_info) { + fprintf(stderr, "\nError: Missing mandatory block `server_info'\n"); + return NULL; + } + return config; } -/* This function checks that the mask sent as argument includes all the - sections that are mandatory in SILC server. */ +/* ... */ -int silc_server_config_check_sections(uint32 checkmask) +void silc_server_config_destroy(SilcServerConfig config) { - if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) { - - return FALSE; + void *tmp; + silc_free(config->module_path); + + /* 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); + + /* Destroy the ServerInfo struct */ + if (config->server_info) { + register SilcServerConfigSectionServerInfo *si = config->server_info; + silc_free(si->server_name); + silc_free(si->server_ip); + 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); } - if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) { - - return FALSE; + + /* Now let's destroy the lists */ + + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher, + 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(SilcServerConfigSectionHash, 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(SilcServerConfigSectionHmac, 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(SilcServerConfigSectionPkcs, 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(SilcServerConfigSectionClient, + config->clients) + silc_free(di->host); + my_free_authdata(di->auth_meth, di->auth_data); + 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) -{ - long tmp; - SilcServerConfigSectionLogging *log; - - SILC_LOG_DEBUG(("Setting configured log file names")); - log = config->logging; - while (log) { - /* Logging Files */ - 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); - /* Logging Options */ - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_QUICK)) { - if (!strcasecmp(log->filename, "yes") || - !strcasecmp(log->filename, "on")) - silc_log_quick = TRUE; - } - if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) { - tmp = atol(log->filename); - if (tmp > 0) - silc_log_flushdelay = tmp; - else { - fprintf(stderr, "config: invalid flushdelay value, use quicklogs if " - "you want real-time logging.\n"); - exit(1); - } - } - - log = log->next; + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins) + silc_free(di->host); + silc_free(di->user); + silc_free(di->nick); + my_free_authdata(di->auth_meth, di->auth_data); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied) + silc_free(di->host); + silc_free(di->reason); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer, + config->servers) + silc_free(di->host); + silc_free(di->version); + my_free_authdata(di->auth_meth, di->auth_data); + silc_free(di); + } + SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter, + config->routers) + silc_free(di->host); + silc_free(di->version); + silc_free(di->backup_replace_ip); + my_free_authdata(di->auth_meth, di->auth_data); + silc_free(di); } } /* 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; + SilcServerConfigSectionCipher *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)) { + if (!strcmp(silc_default_ciphers[i].name, cipher->name)) { silc_cipher_register(&silc_default_ciphers[i]); break; } - - if (!silc_cipher_is_supported(alg->alg_name)) { - SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name)); + 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; + char buf[1023], *alg_name; + SilcCipherObject cipher_obj; SilcSimContext *sim; - char *alg_name; - 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; + /* build the libname */ + snprintf(buf, sizeof(buf), "%s/%s", config->module_path, + cipher->module); sim = silc_sim_alloc(); sim->type = SILC_SIM_CIPHER; - sim->libname = alg->sim_name; + sim->libname = buf; - 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_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.set_key_with_string)); - cipher.encrypt = + 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); @@ -1342,45 +1164,16 @@ bool silc_server_config_register_ciphers(SilcServerConfig config) } /* 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; } @@ -1388,66 +1181,64 @@ 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; + SilcServerConfigSectionHash *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)) { + if (!strcmp(silc_default_hash[i].name, hash->name)) { silc_hash_register(&silc_default_hash[i]); break; } - - if (!silc_hash_is_supported(alg->alg_name)) { - SILC_LOG_ERROR(("Unknown hash funtion `%s'", alg->alg_name)); + 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; + SilcHashObject hash_obj; SilcSimContext *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->libname = hash->module; 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); @@ -1458,12 +1249,16 @@ bool silc_server_config_register_hashfuncs(SilcServerConfig config) } /* 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; } @@ -1471,87 +1266,180 @@ 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; + SilcServerConfigSectionHmac *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; + SilcServerConfigSectionPkcs *pkcs = config->pkcs; - if (!host) - return NULL; + SILC_LOG_DEBUG(("Registering configured PKCS")); + + if (!pkcs) + return FALSE; + + 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(&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 */ + + return TRUE; +} + +/* Sets log files where log messages are saved by the server logger. */ + +void silc_server_config_setlogfiles(SilcServerConfig config, + SilcSchedule sked) +{ + SilcServerConfigSectionLogging *this; + + SILC_LOG_DEBUG(("Setting configured log file names")); - if (!config->clients) + if ((this = config->logging_info)) + silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, sked); + if ((this = config->logging_warnings)) + silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, sked); + if ((this = config->logging_errors)) + silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize, sked); + if ((this = config->logging_fatals)) + silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, sked); +} + +/* Returns client authentication information from configuration file by host + (name or ip) */ + +SilcServerConfigSectionClient * +silc_server_config_find_client(SilcServerConfig config, char *host, int port) +{ + SilcServerConfigSectionClient *client; + + if (!config || !port) { + SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, " + "host=0x%08x \"%s\", port=%hu)", + (uint32) config, (uint32) host, host, port)); + return NULL; + } + if (!host) return NULL; - client = config->clients; + for (client = config->clients; client; client = client->next) { + if (client->host && !silc_string_compare(client->host, host)) + continue; + if (client->port && (client->port != port)) + continue; + break; + } + /* if none matched, then client is already NULL */ + return client; +} - for (i = 0; client; i++) { - if (silc_string_compare(client->host, host)) - match = TRUE; +/* Returns admin connection configuration by host, username and/or + nickname. */ - if (port && client->port && client->port != port) - match = FALSE; +SilcServerConfigSectionAdmin * +silc_server_config_find_admin(SilcServerConfig config, + char *host, char *user, char *nick) +{ + SilcServerConfigSectionAdmin *admin; - if (match) - break; + /* make sure we have a value for the matching parameters */ + if (!host) + host = "*"; + if (!user) + user = "*"; + if (!nick) + nick = "*"; - client = client->next; + 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; } + /* if none matched, then admin is already NULL */ + return admin; +} + +/* Returns the denied connection configuration entry by host and port. */ - if (!client) +SilcServerConfigSectionDeny * +silc_server_config_find_denied(SilcServerConfig config, + char *host, uint16 port) +{ + SilcServerConfigSectionDeny *deny; + + /* make sure we have a value for the matching parameters */ + if (!config || !port) { + SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, " + "host=0x%08x \"%s\", port=%hu)", + (uint32) config, (uint32) host, host, port)); + return NULL; + } + if (!host) return NULL; - return client; + for (deny = config->denied; deny; deny = deny->next) { + if (deny->host && !silc_string_compare(deny->host, host)) + continue; + break; + } + /* if none matched, then deny is already NULL */ + return deny; } -/* Returns server connection info from server configuartion by host +/* 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. */ -SilcServerConfigSectionServerConnection * -silc_server_config_find_server_conn(SilcServerConfig config, +SilcServerConfigSectionServer * +silc_server_config_find_server_conn(SilcServerConfig config, char *host, int port) { int i; - SilcServerConfigSectionServerConnection *serv = NULL; + SilcServerConfigSectionServer *serv = NULL; bool match = FALSE; if (!host) @@ -1580,15 +1468,15 @@ silc_server_config_find_server_conn(SilcServerConfig config, 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, +SilcServerConfigSectionRouter * +silc_server_config_find_router_conn(SilcServerConfig config, char *host, int port) { int i; - SilcServerConfigSectionServerConnection *serv = NULL; + SilcServerConfigSectionRouter *serv = NULL; bool match = FALSE; if (!host) @@ -1617,13 +1505,13 @@ silc_server_config_find_router_conn(SilcServerConfig config, 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) { int i; - SilcServerConfigSectionServerConnection *serv = NULL; + SilcServerConfigSectionRouter *serv = NULL; bool found = FALSE; serv = config->routers; @@ -1642,11 +1530,11 @@ 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 * +SilcServerConfigSectionRouter * silc_server_config_get_primary_router(SilcServerConfig config) { int i; - SilcServerConfigSectionServerConnection *serv = NULL; + SilcServerConfigSectionRouter *serv = NULL; serv = config->routers; for (i = 0; serv; i++) { @@ -1657,75 +1545,3 @@ 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. */ - -SilcServerConfigSectionDenyConnection * -silc_server_config_denied_conn(SilcServerConfig config, char *host, - int port) -{ - int i; - SilcServerConfigSectionDenyConnection *deny = NULL; - bool match = FALSE; - - if (!host) - return NULL; - - if (!config->denied) - 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; - } - - if (!deny) - return NULL; - - return deny; -} diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h index 4bf80bd0..8be6d7cb 100644 --- a/apps/silcd/serverconfig.h +++ b/apps/silcd/serverconfig.h @@ -2,15 +2,15 @@ serverconfig.h - 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,111 +21,109 @@ #ifndef SERVERCONFIG_H #define SERVERCONFIG_H -/* Holds information of configured algorithms */ -typedef struct SilcServerConfigSectionAlgStruct { - char *alg_name; - char *sim_name; - uint32 block_len; - uint32 key_len; - struct SilcServerConfigSectionAlgStruct *next; - struct SilcServerConfigSectionAlgStruct *prev; -#define SILC_CONFIG_SERVER_MODNAME "builtin" -} SilcServerConfigSectionAlg; - -/* Holds server keys from config file */ -typedef struct { - SilcPublicKey public_key; - SilcPrivateKey private_key; -} SilcServerConfigSectionServerKeys; - -/* Holds server information from config file */ -typedef struct { +typedef struct SilcServerConfigSectionCipherStruct { + char *name; + char *module; + uint32 key_length; + uint32 block_length; + struct SilcServerConfigSectionCipherStruct *next; +} SilcServerConfigSectionCipher; + +typedef struct SilcServerConfigSectionHashStruct { + char *name; + char *module; + uint32 block_length; + uint32 digest_length; + struct SilcServerConfigSectionHashStruct *next; +} SilcServerConfigSectionHash; + +typedef struct SilcServerConfigSectionHmacStruct { + char *name; + char *hash; + uint32 mac_length; + struct SilcServerConfigSectionHmacStruct *next; +} SilcServerConfigSectionHmac; + +typedef struct SilcServerConfigSectionPkcsStruct { + char *name; + struct SilcServerConfigSectionPkcsStruct *next; +} SilcServerConfigSectionPkcs; + +typedef struct SilcServerConfigSectionServerInfoStruct { char *server_name; char *server_ip; - char *location; uint16 port; + char *server_type; /* E.g. "Test Server" */ + char *location; /* geographic location */ + char *admin; /* admin full name */ + char *email; /* admin's email address */ + char *user; /* userid the server should be runned at */ + char *group; /* ditto, but about groupid */ + SilcPublicKey public_key; + SilcPrivateKey private_key; + char *motd_file; /* path to text motd file (reading only) */ + char *pid_file; /* path to the pid file (for reading and writing) */ } SilcServerConfigSectionServerInfo; -/* Holds server's administrative information from config file */ -typedef struct { - char *location; - char *server_type; - char *admin_name; - char *admin_email; -} SilcServerConfigSectionAdminInfo; - -/* Holds all the ports the server is listenning on */ -typedef struct SilcServerConfigSectionListenPortStruct { - char *local_ip; - char *listener_ip; - uint16 port; - struct SilcServerConfigSectionListenPortStruct *next; - struct SilcServerConfigSectionListenPortStruct *prev; -} SilcServerConfigSectionListenPort; - -/* Holds server's execution identity, or the user and group which - to change from root when server starts */ -typedef struct { - char *user; - char *group; -} SilcServerConfigSectionIdentity; - -/* Holds all the configured log files. */ typedef struct SilcServerConfigSectionLoggingStruct { - char *logtype; - char *filename; + char *file; uint32 maxsize; - struct SilcServerConfigSectionLoggingStruct *next; - struct SilcServerConfigSectionLoggingStruct *prev; - -/* Allowed section types */ -#define SILC_CONFIG_SERVER_LF_INFO "infologfile" -#define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile" -#define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile" -#define SILC_CONFIG_SERVER_LF_FATAL "fatallogfile" -#define SILC_CONFIG_SERVER_LO_QUICK "quicklogs" -#define SILC_CONFIG_SERVER_LO_FDELAY "flushdelay" } SilcServerConfigSectionLogging; /* Holds all configured connection classes */ -typedef struct SilcServerConfigSectionConnectionClassStruct { +/* typedef struct SilcServerConfigSectionClassStruct { uint32 class; uint32 ping_freq; uint32 connect_freq; uint32 max_links; - struct SilcServerConfigSectionConnectionClassStruct *next; - struct SilcServerConfigSectionConnectionClassStruct *prev; -} SilcServerConfigSectionConnectionClass; - -#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd" -#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey" + struct SilcServerConfigSectionClassStruct *next; +} SilcServerConfigSectionClass; */ /* Holds all client authentication data from config file */ -typedef struct SilcServerConfigSectionClientConnectionStruct { +typedef struct SilcServerConfigSectionClientStruct { char *host; SilcAuthMethod auth_meth; void *auth_data; uint32 auth_data_len; uint16 port; uint32 class; - struct SilcServerConfigSectionClientConnectionStruct *next; - struct SilcServerConfigSectionClientConnectionStruct *prev; -} SilcServerConfigSectionClientConnection; + struct SilcServerConfigSectionClientStruct *next; +} SilcServerConfigSectionClient; + +/* Holds all server's administrators authentication data from config file */ +typedef struct SilcServerConfigSectionAdminStruct { + char *host; + char *user; + char *nick; + SilcAuthMethod auth_meth; + void *auth_data; + uint32 auth_data_len; + struct SilcServerConfigSectionAdminStruct *next; +} SilcServerConfigSectionAdmin; + +/* Holds all configured denied connections from config file */ +typedef struct SilcServerConfigSectionDenyStruct { + char *host; + uint16 port; + char *reason; + struct SilcServerConfigSectionDenyStruct *next; +} SilcServerConfigSectionDeny; -/* Hols all server's administrators authentication data from config file */ -typedef struct SilcServerConfigSectionAdminConnectionStruct { +/* Holds all configured server connections from config file */ +typedef struct SilcServerConfigSectionServerStruct { char *host; - char *username; - char *nickname; SilcAuthMethod auth_meth; void *auth_data; uint32 auth_data_len; - struct SilcServerConfigSectionAdminConnectionStruct *next; - struct SilcServerConfigSectionAdminConnectionStruct *prev; -} SilcServerConfigSectionAdminConnection; + uint16 port; + char *version; + uint32 class; + bool backup_router; + struct SilcServerConfigSectionServerStruct *next; +} SilcServerConfigSectionServer; -/* Holds all configured server/router connections from config file */ -typedef struct SilcServerConfigSectionServerConnectionStruct { +/* Holds all configured router connections from config file */ +typedef struct SilcServerConfigSectionRouterStruct { char *host; SilcAuthMethod auth_meth; void *auth_data; @@ -138,159 +136,65 @@ typedef struct SilcServerConfigSectionServerConnectionStruct { char *backup_replace_ip; uint16 backup_replace_port; bool backup_local; - struct SilcServerConfigSectionServerConnectionStruct *next; - struct SilcServerConfigSectionServerConnectionStruct *prev; -} SilcServerConfigSectionServerConnection; - -/* Holds all configured denied connections from config file */ -typedef struct SilcServerConfigSectionDenyConnectionStruct { - char *host; - char *comment; - uint16 port; - struct SilcServerConfigSectionDenyConnectionStruct *next; - struct SilcServerConfigSectionDenyConnectionStruct *prev; -} SilcServerConfigSectionDenyConnection; - -/* Holds motd file */ -typedef struct { - char *motd_file; -} SilcServerConfigSectionMotd; - -/* holds pid file */ -typedef struct { - char *pid_file; -} SilcServerConfigSectionPid; - -/* - SILC Server Config object. - - This object holds all the data parsed from the SILC server configuration - file. This is mainly used at the initialization of the server. + struct SilcServerConfigSectionRouterStruct *next; +} SilcServerConfigSectionRouter; -*/ +/* define the SilcServerConfig object */ typedef struct { - /* Pointer back to the server */ - void *server; - - /* Filename of the configuration file */ - char *filename; - - /* Configuration sections */ - SilcServerConfigSectionAlg *cipher; - SilcServerConfigSectionAlg *pkcs; - SilcServerConfigSectionAlg *hash_func; - SilcServerConfigSectionAlg *hmac; - SilcServerConfigSectionServerKeys *server_keys; + void *tmp; + char *module_path; + + SilcServerConfigSectionCipher *cipher; + SilcServerConfigSectionHash *hash; + SilcServerConfigSectionHmac *hmac; + SilcServerConfigSectionPkcs *pkcs; + SilcServerConfigSectionLogging *logging_info; + SilcServerConfigSectionLogging *logging_warnings; + SilcServerConfigSectionLogging *logging_errors; + SilcServerConfigSectionLogging *logging_fatals; SilcServerConfigSectionServerInfo *server_info; - SilcServerConfigSectionAdminInfo *admin_info; - SilcServerConfigSectionListenPort *listen_port; - SilcServerConfigSectionIdentity *identity; - SilcServerConfigSectionLogging *logging; - SilcServerConfigSectionConnectionClass *conn_class; - SilcServerConfigSectionClientConnection *clients; - SilcServerConfigSectionServerConnection *servers; - SilcServerConfigSectionServerConnection *routers; - SilcServerConfigSectionAdminConnection *admins; - SilcServerConfigSectionDenyConnection *denied; - SilcServerConfigSectionMotd *motd; - SilcServerConfigSectionPid *pidfile; -} SilcServerConfigObject; - -typedef SilcServerConfigObject *SilcServerConfig; +/*SilcServerConfigSectionClass *conn_class; */ + SilcServerConfigSectionClient *clients; + SilcServerConfigSectionAdmin *admins; + SilcServerConfigSectionDeny *denied; + SilcServerConfigSectionServer *servers; + SilcServerConfigSectionRouter *routers; +} *SilcServerConfig; -/* Configuration section type enumerations. */ -typedef enum { - SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0, - SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, - SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, - SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, - SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS, - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, - SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, - SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, - SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, - SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, - SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, - SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, - SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, - SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, - SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, - SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, - SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, - SILC_CONFIG_SERVER_SECTION_TYPE_PID, -} SilcServerConfigSectionType; +/* Prototypes */ -/* SILC Configuration Section structure. */ -typedef struct { - const char *section; - SilcServerConfigSectionType type; - int maxfields; -} SilcServerConfigSection; +/* basic config operations */ +SilcServerConfig silc_server_config_alloc(char *filename); +void silc_server_config_destroy(SilcServerConfig config); -/* LIst of all possible config sections in SILC server. */ -extern SilcServerConfigSection silc_server_config_sections[]; +/* algorithm registering and reset functions */ +bool silc_server_config_register_ciphers(SilcServer server); +bool silc_server_config_register_hashfuncs(SilcServer server); +bool silc_server_config_register_hmacs(SilcServer server); +bool silc_server_config_register_pkcs(SilcServer server); +void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked); -/* Structure used in parsing the configuration lines. The line is read - from a file to this structure before parsing it further. */ -typedef struct SilcServerConfigParseStruct { - SilcBuffer line; - int linenum; - SilcServerConfigSection *section; - struct SilcServerConfigParseStruct *next; - struct SilcServerConfigParseStruct *prev; -} *SilcServerConfigParse; +/* run-time config access functions */ +SilcServerConfigSectionClient * +silc_server_config_find_client(SilcServerConfig config, char *host, int port); -/* Macros */ +SilcServerConfigSectionAdmin * +silc_server_config_find_admin(SilcServerConfig config, + char *host, char *user, char *nick); -/* Allocates list entries for configuration sections. Used by all - config sections as this is common. */ -#define SILC_SERVER_CONFIG_LIST_ALLOC(x) \ -do { \ - if (!(x)) { \ - (x) = silc_calloc(1, sizeof(*(x))); \ - (x)->next = NULL; \ - (x)->prev = NULL; \ - } else { \ - if (!(x)->next) { \ - (x)->next = silc_calloc(1, sizeof(*(x)->next)); \ - (x)->next->next = NULL; \ - (x)->next->prev = (x); \ - (x) = (x)->next; \ - } \ - } \ -} while(0) +SilcServerConfigSectionDeny * +silc_server_config_find_denied(SilcServerConfig config, + char *host, uint16 port); -/* Prototypes */ -SilcServerConfig silc_server_config_alloc(char *filename); -void silc_server_config_free(SilcServerConfig config); -int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, - SilcServerConfigParse *return_config); -int silc_server_config_parse_lines(SilcServerConfig config, - SilcServerConfigParse parse_config); -int silc_server_config_check_sections(uint32 checkmask); -void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked); -bool silc_server_config_register_ciphers(SilcServerConfig config); -bool silc_server_config_register_pkcs(SilcServerConfig config); -bool silc_server_config_register_hashfuncs(SilcServerConfig config); -bool silc_server_config_register_hmacs(SilcServerConfig config); -SilcServerConfigSectionClientConnection * -silc_server_config_find_client_conn(SilcServerConfig config, - char *host, int port); -SilcServerConfigSectionServerConnection * -silc_server_config_find_server_conn(SilcServerConfig config, +/* Prototypes - OLD */ +SilcServerConfigSectionServer * +silc_server_config_find_server_conn(SilcServerConfig config, char *host, int port); -SilcServerConfigSectionServerConnection * -silc_server_config_find_router_conn(SilcServerConfig config, +SilcServerConfigSectionRouter * +silc_server_config_find_router_conn(SilcServerConfig config, char *host, int port); bool silc_server_config_is_primary_route(SilcServerConfig config); -SilcServerConfigSectionServerConnection * +SilcServerConfigSectionRouter * silc_server_config_get_primary_router(SilcServerConfig config); -SilcServerConfigSectionAdminConnection * -silc_server_config_find_admin(SilcServerConfig config, - char *host, char *username, char *nickname); -SilcServerConfigSectionDenyConnection * -silc_server_config_denied_conn(SilcServerConfig config, char *host, - int port); -#endif +#endif /* !SERVERCONFIG_H */ diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index 0eadeba5..cf3315a2 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -102,15 +102,15 @@ Usage: silcd [options]\n\ /* Dies if a *valid* pid file exists already */ -static void silc_checkpid(SilcServer silcd) +static void silc_server_checkpid(SilcServer silcd) { - if (silcd->config->pidfile && silcd->config->pidfile->pid_file) { + if (silcd->config->server_info->pid_file) { int oldpid; char *buf; uint32 buf_len; SILC_LOG_DEBUG(("Checking for another silcd running")); - buf = silc_file_readfile(silcd->config->pidfile->pid_file, &buf_len); + buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len); if (!buf) return; oldpid = atoi(buf); @@ -121,7 +121,7 @@ static void silc_checkpid(SilcServer silcd) if (errno != ESRCH) { fprintf(stderr, "\nI detected another daemon running with the same pid file.\n"); fprintf(stderr, "Please change the config file, or erase the %s\n", - silcd->config->pidfile->pid_file); + silcd->config->server_info->pid_file); exit(1); } } @@ -239,7 +239,7 @@ int main(int argc, char **argv) goto fail; /* Check for another silcd running */ - silc_checkpid(silcd); + silc_server_checkpid(silcd); /* Initialize the server */ ret = silc_server_init(silcd); @@ -263,11 +263,11 @@ int main(int argc, char **argv) silc_server_daemonise(silcd); /* If set, write pid to file */ - if (silcd->config->pidfile && silcd->config->pidfile->pid_file) { - char buf[10]; - unlink(silcd->config->pidfile->pid_file); + if (silcd->config->server_info->pid_file) { + char buf[10], *pidfile = silcd->config->server_info->pid_file; + unlink(pidfile); snprintf(buf, sizeof(buf) - 1, "%d\n", getpid()); - silc_file_writefile(silcd->config->pidfile->pid_file, buf, strlen(buf)); + silc_file_writefile(pidfile, buf, strlen(buf)); } /* Drop root. */ diff --git a/doc/example_silcd.conf.in b/doc/example_silcd.conf.in index d12a141b..afe74b3e 100644 --- a/doc/example_silcd.conf.in +++ b/doc/example_silcd.conf.in @@ -1,241 +1,348 @@ # # Example configuration file. Note that this attempts to present various -# configuration possibilities and may not actually give any sensible +# configuration possibilities and may not actually give any sensible # configuration. For real life example see the examples/ directory. # # -# Configured ciphers. +# General configuration options # -# Format: ::: -# -# If the cipher is builtin the maybe omitted. -# -[Cipher] -aes-256-cbc:@MODULESDIR@/aes.sim.so:32:16 -aes-192-cbc:@MODULESDIR@/aes.sim.so:24:16 -aes-128-cbc:@MODULESDIR@/aes.sim.so:16:16 -twofish-256-cbc:@MODULESDIR@/twofish.sim.so:32:16 -twofish-192-cbc:@MODULESDIR@/twofish.sim.so:24:16 -twofish-128-cbc:@MODULESDIR@/twofish.sim.so:16:16 -mars-256-cbc:@MODULESDIR@/mars.sim.so:32:16 -mars-192-cbc:@MODULESDIR@/mars.sim.so:24:16 -mars-128-cbc:@MODULESDIR@/mars.sim.so:16:16 -none:@MODULESDIR@/none.sim.so:0:0 +General { + # This is the default path where to search modules + # You can comment it out to use builtin modules globally. + ModulePath = "@MODULESDIR@"; +}; # -# Configured hash functions. -# -# Format: ::: -# -# If the hash function is builtin the maybe omitted. +# Configured ciphers +# +# The "Module" option can be either absolute or relative to the "ModulePath" +# option. +# If commented out forces using of built-in modules. +# +cipher { + name = "aes-256-cbc"; + module = "aes.sim.so"; + key_length = 32; + block_length = 16; +}; +cipher { + name = "aes-192-cbc"; + module = "aes.sim.so"; + key_length = 24; + block_length = 16; +}; +cipher { + name = "aes-128-cbc"; + module = "aes.sim.so"; + key_length = 16; + block_length = 16; +}; +cipher { + name = "twofish-256-cbc"; + module = "twofish.sim.so"; + key_length = 32; + block_length = 16; +}; +cipher { + name = "twofish-192-cbc"; + module = "twofish.sim.so"; + key_length = 24; + block_length = 16; +}; +cipher { + name = "twofish-128-cbc"; + module = "twofish.sim.so"; + key_length = 16; + block_length = 16; +}; +cipher { + name = "mars-256-cbc"; + module = "mars.sim.so"; + key_length = 32; + block_length = 16; +}; +cipher { + name = "mars-192-cbc"; + module = "mars.sim.so"; + key_length = 24; + block_length = 16; +}; +cipher { + name = "mars-128-cbc"; + module = "mars.sim.so"; + key_length = 16; + block_length = 16; +}; +cipher { + name = "none"; + module = "none.sim.so"; +}; + # -[Hash] -sha1::64:20 -md5::64:16 +# Configured hash functions +# +hash { + name = "sha1"; + block_length = 64; + digest_length = 20; +}; +hash { + name = "md5"; + block_length = 64; + digest_length = 16; +}; # # Configured HMAC functions. The hash function used in the HMAC must -# configured to the [hash] section. -# -# Format: :: -# -[hmac] -hmac-sha1-96:sha1:12 -hmac-md5-96:md5:12 -hmac-sha1:sha1:20 -hmac-md5:md5:16 +# be configured in the hash section. +# +hmac { + name = "hmac-sha1-96"; + hash = "sha1"; + mac_length = 12; +}; +hmac { + name = "hmac-md5-96"; + hash = "md5"; + mac_length = 12; +}; +hmac { + name = "hmac-sha1"; + hash = "sha1"; + mac_length = 20; +}; +hmac { + name = "hmac-md5"; + hash = "md5"; + mac_length = 16; +}; # -# Configured PKCS. +# Configured PKCS # -# Format: -# -[PKCS] -rsa +PKCS { name = "rsa"; }; # -# Run SILC server as specific user and group. The server must be initially -# run as root. -# -# Format: : +# Server information # -[Identity] -nobody:nobody +ServerInfo { + # + # Server FQDN and IP address + # + hostname = "lassi.kuo.fi.ssh.com"; + ip = "10.2.1.6"; + port = 706; -# -# Server's administrative information. -# -# Format: ::: -# -[AdminInfo] -Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi + # + # ServerType field specifies the purpose of this server + # This is only a descriptive field. + # + ServerType = "Test Server"; -# -# Server information. -# -# Format: +::: -# -[ServerInfo] -lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:706 + # + # Geographic location + # + Location = "Kuopio, Finland"; -# -# Server keys -# -# Format: +: -# -[ServerKeys] -@ETCDIR@/silcd.pub:@ETCDIR@/silcd.prv + # + # Full admin name + # + Admin = "Pekka Riikonen"; -# -# Listenning ports. -# -# Format: :: -# -[ListenPort] -10.2.1.6:10.2.1.6:706 + # + # Admin's email address + # + EMail = "priikone@poseidon.pspt.fi"; + + # + # Run SILC server as specific user and group. The server must be initially + # run as root. + # + User = "nobody"; + Group = "nobody"; + + # + # Public and private keys + # + PublicKey = "@ETCDIR@/silcd.pub"; + PrivateKey = "@ETCDIR@/silcd.prv"; + + # + # Motd file + # + # Specifies the text file displayed on client connection + # + #MotdFile = "@ETCDIR@/motd.txt"; + + # + # Pid file + # + PidFile = "@PIDFILE@"; +}; # # Log files. # -# This section is used to set various logging files, their paths -# and maximum sizes. There are only four defined channels allowed for -# defining (see list below). +# This section is used to set various logging files, their paths, maximum +# sizes and logging options. +# There are only four defined channels allowed for defining (see below). # The log channels have an importance value, and most important channels -# are printed on the less important ones, thus setting the logging file -# for "infologfile" will ensure logging for all channels, while setting -# logging file for "errorlogfile" will ensure logging for channels -# "error" and "fatal" only. -# If a message can't find a valid output file it will be discarded, thus, -# if you unset all files you will completely disable server logging (and -# this is NOT recommended). -# If maximum size is given, the logfile will be rotated to a logfile with -# the ".old" extension added. Older logfiles are flushed. -# There are also two options, quicklogs and flushdelay. Their values -# must be enclosed in colons (:), see the format below. -# -# Format: quicklogs:: -# flushdelay:: -# infologfile:: -# warninglogile:: -# errorlogile:: -# fatallogile:: -# -[Logging] -quicklogs:no: -flushdelay:300: -infologfile:@LOGSDIR@/silcd.log:50000 -warninglogfile:@LOGSDIR@/silcd_warnings.log:50000 -#errorlogfile:@LOGSDIR@/silcd_errors.log:50000 -#fatallogfile:@LOGSDIR@/silcd_fatals.log: - -# -# Connection classes. -# -# This section is used to define connection classes. These can be -# used to optimize the server and the connections.# +# are redirected on the less important ones, thus setting a valid logging +# file for "infologfile" will ensure logging for all channels, while setting +# logging file for "errorlogfile" will ensure logging for channels "error" +# and "fatal" +# +Logging { + # + # If QuickLogs is true, then the logging files will be updated + # real-time. This causes a bit more CPU and HDD activity, but + # reduces memory usage. (if unsure say true). + # + QuickLogs = false; + + # + # (Only if QuickLogs is false) + # FlushDelay tells log files update delay in case you have chosen + # buffering output. + # + FlushDelay = 180; + + Info { + File = "@LOGSDIR@/silcd.log"; + Size = "50k"; + }; + Warnings { + File = "@LOGSDIR@/silcd_warnings.log"; + Size = "50k"; + }; + Errors { + File = "@LOGSDIR@/silcd_errors.log"; + Size = "50k"; + }; + Fatals { + File = "@LOGSDIR@/silcd_fatals.log"; + Size = "50k"; + }; +}; + # -# Format: ::: +# Connection classes (UNSUPPORTED) # -[ConnectionClass] -1:100:100:100 -2:200:300:400 +# This section is used to define connection classes. These can be +# used to optimize the server and the connections. +# +#Class { +# Name = "norm"; +# Ping = 100; +# Connect = 100; +# Links = 100; +#}; # # Configured client connections. # -# Format: :::: +# All fields except Class are optional. Omitted fields are assumed +# to be generic (e.g. if the "Host" field is omitted all hosts will match +# this client class). +# +#Client { +# Host = "127.0.0.1"; +# Port = 706; +# Class = "local"; +#}; +Client { + Port = 706; + Class = "norm"; +}; + # -# The is either passphrase or file path to the public key -# file. +# Configured server administrator connections # -[ClientConnection] -:::706:1 +# The fields "Host", "User", and "Nick", are optional but you are encouraged +# in using them to better identify your admins. +# "AuthMethod" and "AuthData" fields are mandatory. The "AuthMethod" field +# can be either the special string "passwd" or "pubkey" to identify the type +# of data specified by "AuthData". +# +Admin { + Host = "10.2.1.199"; + User = "priikone"; + Nick = "pekka"; + AuthMethod = "passwd"; + AuthData = "verysecret"; +}; # -# Configured server administrator connections +# Denied connections # -# Format: :::: +# These connections are denied to connect to our server. # -# The is either passphrase or file path to the public key -# file. +# The "Reason" field is mandatory, while the "Host" and "Port" fields can be +# omitted to match everything. # -[AdminConnection] -10.2.1.199:priikone:pekka:passwd:veryscret +#Deny { +# Host = "10.2.1.99"; +# Port = 706; +# Reason = "Go away spammer"; +#}; +#Deny { +# Host = "10.3.*"; +# Reason = "You are not welcome."; +#}; # # Configured server connections. # -# If server connections are configured it means that our server is -# router server. Normal server must not configure server connections. -# Thus, if your server is not router do not configure this section. If +# If server connections are configured it means that this server is +# router server. Normal servers must not configure server connections. +# Thus, if this server is not router do not configure this section. If # your server is router, this must be configured. # -# Format: :::: -# :: -# -# The is either passphrase or file path to the public key -# file. If the connection is backup connection then set the to value 1. For normal connections set it 0. If it is -# set to value 1 then this server will be backup router. -# -[ServerConnection] -10.2.1.7:passwd:veryscret:706:1:1:0 -10.2.1.17:passwd:veryscret13:706:1:1:1 # backup connection, that host - # will use this server as backup - # router. +# The "AuthData" option is either passphrase or file path to the public key +# file. If the connection is backup connection then set the "Backup" option +# to true. For normal connections set it false. If it is +# set to true then this server will be backup router. +# +ServerConnection { + Host = "10.2.1.7"; + AuthMethod = passwd; + AuthData = "verysecret"; + Port = 706; + VersionID = 1; + Class = "norm"; + Backup = false; +}; # -# Configured router connections. +# Configured router connections # -# For normal server only one entry maybe configured to this section. It -# must be the router this server will be connected to. For router server, -# this sections includes all configured router connections. The first +# For normal servers only one entry maybe configured to this section. It +# must be the router this server will be connected to. For router servers, +# this section includes all configured router connections. The first # configured connection is the primary route. # -# Format: ::::: -# :::: -# +# The "AuthData" option is either passphrase or file path to the public key +# file. If you are the initiator of the connection then set the "Initiator" +# option to true. If you are the responder of the connection (waiting for +# incoming connection) then set it to false. # -# The is either passphrase or file path to the public key -# file. If you are the initiator of the connection then set the -# to value 1. If you are the responder of the connection (waiting for -# incoming connection) then set it to 0. -# -# If the connection is backup router connection then set the to the IP address of the router that the backup router will +# If the connection is backup router connection then set the "BackupHost" +# option to the IP address of the router that the backup router will # replace if it becomes unavailable. Set also the router's port to the -# . For normal connection leave both empty. If this -# backup router is in our cell then set the to value 1. -# If the backup router is in other cell then set it to value 0. -# -[RouterConnection] -#10.2.1.100:passwd:veryverysecret:706:1:1:1 -#10.2.100.131:pubkey:/path/to/the/publickey:706:1:1:1 -#10.2.100.100:pubkey:/path/to/the/publickey:706:1:1:0:10.2.1.6:706:1 - -# -# Denied connections. -# -# These connections are denied to connect our server. -# -# Format: :: -# -[DenyConnection] -#10.2.1.99:0:Your connection has been denied - -# -# Message Of The Day -# -# specify the text file containing the motd: -# -#[motd] -#@ETCDIR@/motd.txt - -# -# Pid File -# -# specify the pidfile where it will be written: -# -[pid] -@PIDFILE@ +# "BackupPort" option. For normal connection leave both commented. If this +# backup router is in our cell then set the "LocalBackup" option to true. +# If the backup router is in other cell then set it to false. +# +RouterConnection { + Host = "10.2.1.100"; + AuthMethod = passwd; + AuthData = "verysecret"; + Port = 706; + VersionID = 1; + Class = "norm"; + Initiator = true; + #BackupHost = "10.2.1.6"; + #BackupPort = 706; + #LocalBackup = true; +}; diff --git a/lib/silcutil/silcconfig.c b/lib/silcutil/silcconfig.c index 19ae0b97..188ffa2b 100644 --- a/lib/silcutil/silcconfig.c +++ b/lib/silcutil/silcconfig.c @@ -2,15 +2,15 @@ silcconfig.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,66 +21,614 @@ #include "silcincludes.h" -/* Opens and reads a configuration file to a buffer. The read data is - returned to the ret_buffer argument. */ +/* limit debug logging verbosity */ +#if 0 +#define SILC_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt) +#else +#define SILC_CONFIG_DEBUG(fmt) +#endif + +/* this is the option struct and currently it is only used internally to + * the module and other structs. */ +typedef struct SilcConfigOptionStruct { + char *name; /* *lowercase* name of the option */ + SilcConfigType type; /* important: the type of the returned value */ + SilcConfigCallback cb; /* the value handler */ + const SilcConfigTable *subtable; /* used if type is SILC_CONFIG_ARG_BLOCK */ + void *context; /* context passed to the callback function */ + struct SilcConfigOptionStruct *next; +} SilcConfigOption; + +/* unique for each config file (and included ones) */ +struct SilcConfigFileObject { + char *filename; /* the original filename opened */ + int level; /* parsing level, how many nested silc_config_main we have */ + char *base; /* this is a fixed pointer to the base location */ + char *p; /* the Parser poitner */ + uint32 len; /* fixed length of the whole file */ + uint32 line; /* current parsing line, strictly linked to p */ + bool included; /* wether this file is main or included */ +}; + +/* We need the entity to base our block-style parsing on */ +struct SilcConfigEntityObject { + SilcConfigOption *opts; /* known options list */ + SilcConfigFile *file; /* parsing file object */ +}; + +/* access error descriptions only with silc_config_strerror() */ +static char *errorstrs[] = { + "-OK", /* SILC_CONFIG_OK */ + "-SILENT", /* SILC_CONFIG_ESILENT */ + "Invalid syntax", /* SILC_CONFIG_EGENERIC */ + "Internal error! Please report this bug", /* SILC_CONFIG_EINTERNAL */ + "Can't open specified file", /* SILC_CONFIG_ECANTOPEN */ + "Expected open-brace '{'", /* SILC_CONFIG_EOPENBRACE */ + "Missing close-brace '}'", /* SILC_CONFIG_ECLOSEBRACE */ + "Invalid data type", /* SILC_CONFIG_ETYPE */ + "Unknown option", /* SILC_CONFIG_EBADOPTION */ + "Invalid text", /* SILC_CONFIG_EINVALIDTEXT */ + "Double option specification", /* SILC_CONFIG_EDOUBLE */ + "Expected data but not found", /* SILC_CONFIG_EEXPECTED */ + "Expected '='", /* SILC_CONFIG_EEXPECTEDEQUAL */ + "Unexpected data", /* SILC_CONFIG_EUNEXPECTED */ + "Missing needed fields", /* SILC_CONFIG_EMISSFIELDS */ + "Missing ';'", /* SILC_CONFIG_EMISSCOLON */ +}; + +/* return string describing SilcConfig's error code */ +char *silc_config_strerror(int errnum) +{ + if ((errnum < 0) || (errnum >= sizeof(errorstrs)/sizeof(*errorstrs)) || + (errorstrs[errnum] == NULL)) { + char *defret = "-INVALIDERROR"; + return defret; + } + return errorstrs[errnum]; +} + +/* Begin of internal SilcConfig's text util functions */ + +/* Points the first non-space character */ +static void my_trim_spaces(SilcConfigFile *file) +{ + register char *r = file->p; + while (isspace(*r)) + if (*r++ == '\n') file->line++; + file->p = r; +} +/* Skips the current line until newline (lf or cr) */ +static void my_skip_line(SilcConfigFile *file) +{ + register char *r = file->p; + while (*r && (*r != '\n') && (*r != '\r')) r++; + file->p = (*r ? r + 1 : r); + file->line++; +} +/* Obtains a text token from the current position until first separator. + * a separator is any non alphanumeric character nor "_" or "-" */ +static char *my_next_token(SilcConfigFile *file, char *to) +{ + register char *o; + my_trim_spaces(file); + o = file->p; + while (isalnum(*o) || (*o == '_') || (*o == '-')) + *to++ = *o++; + *to = '\0'; + file->p = o; + return to; +} +/* Obtains a string from the current position. The only difference from + * next_token() is that quoted-strings are also accepted */ +static char *my_get_string(SilcConfigFile *file, char *to) +{ + char *o; + my_trim_spaces(file); + o = file->p; + if (*o == '"') { + char *quot = strchr(++o, '"'); + int len = quot - o; + if (!quot) { /* XXX FIXME: gotta do something here */ + printf("Bullshit, missing matching \""); + exit(1); + } + if (len <= 0) + *to = '\0'; + else { + strncpy(to, o, len); + to[len] = '\0'; + } + /* update stream pointer */ + file->p = quot + 1; + return to; + } + /* we don't need quote parsing, fall-back to token extractor */ + my_next_token(file, to); + return to; +}; +/* Skips all comment lines and spaces lines until first useful character */ +static void my_skip_comments(SilcConfigFile *file) +{ + while (1) { + my_trim_spaces(file); + if (*file->p != '#') return; + my_skip_line(file); + } +} + +/* End of internal text functions + * Next section contains SilcConfig internal config utils */ -void silc_config_open(char *filename, SilcBuffer *ret_buffer) +/* find an option in the list by name and returns its pointer */ +static SilcConfigOption *silc_config_find_option(SilcConfigEntity ent, + const char *name) +{ + SilcConfigOption *tmp; + for (tmp = ent->opts; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->name, name)) + return tmp; + } + return NULL; +} +/* ... */ +static void *silc_config_marshall(SilcConfigType type, const char *val) +{ + void *pt; + int val_int; + bool val_bool; + char *val_tmp; + uint32 val_size; + + switch (type) { + case SILC_CONFIG_ARG_TOGGLE: + if (!strcasecmp(val, "yes") || !strcasecmp(val, "true") || + !strcasecmp(val, "on") || !strcasecmp(val, "1")) { + val_bool = TRUE; + } + else if (!strcasecmp(val, "no") || !strcasecmp(val, "false") || + !strcasecmp(val, "off") || !strcasecmp(val, "0")) { + val_bool = FALSE; + } + else + return NULL; + pt = silc_calloc(1, sizeof(val_bool)); + *(bool *)pt = (bool) val_bool; + return pt; + case SILC_CONFIG_ARG_INT: + val_int = (int) strtol(val, &val_tmp, 0); + if (*val_tmp) /* error converting string */ + return NULL; + pt = silc_calloc(1, sizeof(val_int)); + *(int *)pt = val_int; + return pt; + case SILC_CONFIG_ARG_SIZE: + val_size = (uint32) strtol(val, &val_tmp, 0); + if (val == val_tmp) + return NULL; /* really wrong, there must be at least one digit */ + /* Search for a designator */ + switch (tolower(val_tmp[0])) { + case '\0': /* None */ + break; + case 'k': /* Kilobytes */ + val_size *= (uint32) 1024; + break; + case 'm': /* Megabytes */ + val_size *= (uint32) (1024 * 1024); + break; + case 'g': + val_size *= (uint32) (1024 * 1024 * 1024); + break; + default: + return NULL; + } + /* the string must die here */ + if (val_tmp[1]) + return NULL; + pt = silc_calloc(1, sizeof(val_size)); + *(uint32 *)pt = val_size; + return pt; + case SILC_CONFIG_ARG_STR: /* the only difference between STR and STRE is */ + if (!val[0]) /* that STR cannot be empty, while STRE can. */ + return NULL; + case SILC_CONFIG_ARG_STRE: + pt = (void *) strdup(val); + return pt; + /* following types are not supposed to have a return value */ + case SILC_CONFIG_ARG_BLOCK: + case SILC_CONFIG_ARG_NONE: + return NULL; + default: + return NULL; + } + + return NULL; +} + +/* End of internal functions */ + + +/* Tries to open the config file and returns a valid SilcConfigFile object + * or NULL if failed */ + +SilcConfigFile *silc_config_open(char *configfile) { char *buffer; uint32 filelen; + SilcConfigFile *ret; - buffer = silc_file_readfile(filename, &filelen); - if (buffer == NULL) - return; + if (!(buffer = silc_file_readfile(configfile, &filelen))) + return NULL; - /* Buffer don't have EOF, but we'll need it. */ - buffer[filelen] = EOF; + ret = (SilcConfigFile *) silc_calloc(1, sizeof(*ret)); + ret->filename = strdup(configfile); + ret->base = ret->p = buffer; + ret->len = filelen; + ret->line = 1; /* line count, start from first line */ + return ret; +} - *ret_buffer = silc_buffer_alloc(filelen + 1); - silc_buffer_pull_tail(*ret_buffer, filelen + 1); - silc_buffer_put(*ret_buffer, buffer, filelen + 1); +/* Frees a file object */ - SILC_LOG_DEBUG(("Config file `%s' opened", filename)); +void silc_config_close(SilcConfigFile *file) +{ + if (file) { + /* XXX FIXME: this check could probably be removed later */ + uint32 my_len = (uint32) (strchr(file->base, EOF) - file->base); + SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", (uint32) file, + file->filename, file->level, file->line)); + if (my_len != file->len) { + fprintf(stderr, "FATAL ERROR: saved len and current len does not match!\n"); + abort(); + } + silc_free(file->filename); + memset(file->base, 'F', file->len); + silc_free(file->base); + memset(file, 'F', sizeof(*file)); + silc_free(file); + } } -/* Returns next token from a buffer to the dest argument. Returns the - length of the token. This is used to take tokens from a configuration - line. */ +/* initializes a SilcConfigEntity pointer allocation */ + +SilcConfigEntity silc_config_init(SilcConfigFile *file) +{ + SilcConfigEntity ret; + if (!file) + return NULL; + SILC_CONFIG_DEBUG(("Allocating new config entity")); + ret = (SilcConfigEntity) silc_calloc(1, sizeof(*ret)); + ret->file = file; + return ret; +}; + +/* Returns the original filename of the object file */ -int silc_config_get_token(SilcBuffer buffer, char **dest) +char *silc_config_get_filename(SilcConfigFile *file) { + if (file) + return file->filename; + return NULL; +} + +/* Returns the current line that file parsing arrived at */ + +uint32 silc_config_get_line(SilcConfigFile *file) +{ + if (file) + return file->line; + return 0; +} + +/* Returns a pointer to the beginning of the requested line. If the line + * was not found, NULL is returned */ + +char *silc_config_read_line(SilcConfigFile *file, uint32 line) +{ + register char *p; int len; + char *ret, *endbuf; - if (strchr(buffer->data, ':')) { - len = strcspn(buffer->data, ":"); - if (len) { - *dest = silc_calloc(len + 1, sizeof(char)); - memcpy(*dest, buffer->data, len); - } - silc_buffer_pull(buffer, len + 1); - return len; + if (!file || (line <= 0)) + return NULL; + for (p = file->base; *p && (*p != EOF); p++) { + if (line <= 1) + goto found; + if (*p == '\n') + line--; } + return NULL; - return -1; + found: + if ((endbuf = strchr(p, '\n'))) { + len = endbuf - p; + ret = silc_calloc(len, sizeof(*ret)); + strncpy(ret, p, len); + ret[len] = '\0'; + } + else { + ret = silc_calloc(strlen(p), sizeof(*ret)); + strcpy(ret, p); + } + return ret; } -/* Returns number of tokens in a buffer. */ +/* Convenience function to read the current parsed line */ -int silc_config_check_num_token(SilcBuffer buffer) +char *silc_config_read_current_line(SilcConfigFile *file) { - int len, len2, num; + return silc_config_read_line(file, file->line); +} + +/* (Private) destroy a SilcConfigEntity */ - if (strchr(buffer->data, ':')) { - len = 0; - num = 0; - while (strchr(buffer->data + len, ':')) { - num++; - len2 = strcspn(buffer->data + len, ":") + 1; - len += len2; +static void silc_config_destroy(SilcConfigEntity ent) +{ + SilcConfigOption *oldopt, *nextopt; + SILC_CONFIG_DEBUG(("Freeing config entity [ent=0x%x] [opts=0x%x]", + (uint32) ent, (uint32) ent->opts)); + for (oldopt = ent->opts; oldopt; oldopt = nextopt) { + nextopt = oldopt->next; + memset(oldopt->name, 'F', strlen(oldopt->name) + 1); + silc_free(oldopt->name); + memset(oldopt, 'F', sizeof(*oldopt)); + silc_free(oldopt); + } + memset(ent, 'F', sizeof(*ent)); + silc_free(ent); +} + +/* Registers a new option in the specified entity */ + +void silc_config_register(SilcConfigEntity ent, const char *name, + SilcConfigType type, SilcConfigCallback cb, + const SilcConfigTable *subtable, void *context) +{ + SilcConfigOption *newopt; + SILC_CONFIG_DEBUG(("Register new option=\"%s\" type=%u cb=0x%08x context=0x%08x", + name, type, (uint32) cb, (uint32) context)); + + if (!ent || !name) + return; + /* if we are registering a block, make sure there is a specified sub-table */ + if ((type == SILC_CONFIG_ARG_BLOCK) && !subtable) + return; + /* refuse special tag */ + if (!strcasecmp(name, "include")) + return; + if (silc_config_find_option(ent, name)) { + fprintf(stderr, "Internal Error: Option double registered\n"); + abort(); + } + + /* allocate and append the new option */ + newopt = (SilcConfigOption *) silc_calloc(1, sizeof(*newopt)); + newopt->name = strdup(name); + newopt->type = type; + newopt->cb = cb; + newopt->subtable = subtable; + newopt->context = context; + + if (!ent->opts) + ent->opts = newopt; + else { + SilcConfigOption *tmp; + for (tmp = ent->opts; tmp->next; tmp = tmp->next); + tmp->next = newopt; + } +} + +/* Register a new option table in the specified config entity */ + +void silc_config_register_table(SilcConfigEntity ent, + const SilcConfigTable table[], void *context) +{ + int i; + if (!ent || !table) return; + SILC_CONFIG_DEBUG(("Registering table")); + /* FIXME: some potability checks needed */ + for (i = 0; table[i].name; i++) { + silc_config_register(ent, table[i].name, table[i].type, + table[i].callback, table[i].subtable, context); + } +} + +/* ... */ + +static int silc_config_main_internal(SilcConfigEntity ent) +{ + SilcConfigFile *file = ent->file; + char **p = &file->p; + + /* loop throught statements */ + while (1) { + char buf[255]; + SilcConfigOption *thisopt; + + /* makes it pointing to the next interesting char */ + my_skip_comments(file); + /* got eof? */ + if (**p == '\0' || **p == EOF) { + if (file->level > 1) /* cannot get eof in a sub-level! */ + return SILC_CONFIG_EEXPECTED; + goto finish; + } + /* check if we completed this (sub) section (it doesn't matter if this + * is the main section) */ + if (**p == '}') { + if (file->level < 2) /* can't be! must be at least one sub-block */ + return SILC_CONFIG_EUNEXPECTED; + (*p)++; + goto finish; + } + //SILC_LOG_HEXDUMP(("Preparing lookup at line=%lu", file->line), *p, 16); + + /* obtain the keyword */ + my_next_token(file, buf); + SILC_CONFIG_DEBUG(("Looking up keyword=\"%s\" [line=%lu]", buf, file->line)); + + /* handle special directive */ + if (!strcasecmp(buf, "include")) { + int ret; + SilcConfigFile *inc_file; + SilcConfigEntity inc_ent; + + my_trim_spaces(file); /* prepare next char */ + + /* Now trying to include the specified file. The included file will + * be allowed to include sub-files but it will preserve the block-level + * of the including block. Note that the included file won't be allowed + * to raise the block level of the including block. */ + + my_get_string(file, buf); /* get the filename */ + SILC_LOG_DEBUG(("Including file \"%s\"", buf)); + /* before getting on, check if this row is REALLY complete */ + if (*(*p)++ != ';') + return SILC_CONFIG_EMISSCOLON; + + /* open the file and start the parsing */ + inc_file = silc_config_open(buf); + if (!inc_file) /* does it point a valid filename? */ + return SILC_CONFIG_ECANTOPEN; + inc_file->included = TRUE; + + /* create a new entity and hack it to use the same options */ + inc_ent = silc_config_init(inc_file); + inc_ent->opts = ent->opts; + ret = silc_config_main(inc_ent); + + /* Cleanup. + * If the included file returned an error, the application will probably + * want to output some kind of error message. Because of this, we can't + * destroy THIS file object. The hack works this way: The application + * expects to destroy the originally created object file, so we'll swap + * the original file with the included file. */ + if (ret) { + SilcConfigFile tmp_file; + SILC_CONFIG_DEBUG(("SWAPPING FILE OBJECTS")); + memcpy(&tmp_file, inc_file, sizeof(tmp_file)); + memcpy(inc_file, file, sizeof(tmp_file)); + silc_config_close(inc_file); + memcpy(file, &tmp_file, sizeof(tmp_file)); + return ret; + } + /* otherwise if no errors encoured, continue normally */ + silc_config_close(inc_file); + continue; /* this one is handled */ } - return num; + /* we have a registered option (it can also be a sub-block) */ + thisopt = silc_config_find_option(ent, buf); + if (!thisopt) + return SILC_CONFIG_EBADOPTION; + + my_trim_spaces(file); /* prepare next char */ + + /* option type is a block? */ + if (thisopt->type == SILC_CONFIG_ARG_BLOCK) { + int ret; + SilcConfigEntity sub_ent; + + SILC_CONFIG_DEBUG(("Entering sub-block")); + if (*(*p)++ != '{') + return SILC_CONFIG_EOPENBRACE; + /* build the new entity for this sub-block */ + sub_ent = silc_config_init(ent->file); + /* use the previous specified table to describe this block's options */ + silc_config_register_table(sub_ent, thisopt->subtable, thisopt->context); + /* run this block! */ + ret = silc_config_main(sub_ent); + SILC_CONFIG_DEBUG(("Returned from sub-block [ret=%d]", ret)); + + if (ret) /* now check the result */ + return ret; + + /* now call block clean-up callback (if any) */ + if (thisopt->cb) { + SILC_CONFIG_DEBUG(("Now calling clean-up callback (if any)")); + thisopt->cb(thisopt->type, thisopt->name, file->line, + NULL, thisopt->context); + } + /* Do we want ';' to be mandatory after close brace? */ + if (*(*p)++ != ';') + return SILC_CONFIG_EMISSCOLON; + } + else if (thisopt->type == SILC_CONFIG_ARG_NONE) { + /* before getting on, check if this row is REALLY complete */ + if (*(*p)++ != ';') + return SILC_CONFIG_EMISSCOLON; + SILC_CONFIG_DEBUG(("Triggering callback for none")); + if (thisopt->cb) { + thisopt->cb(thisopt->type, thisopt->name, file->line, + NULL, thisopt->context); + } + } + else { + void *pt; + int ret; + + if (*(*p)++ != '=') + return SILC_CONFIG_EEXPECTEDEQUAL; + + my_get_string(file, buf); /* get the option argument */ + SILC_CONFIG_DEBUG(("With argument=\"%s\"", buf)); + + /* before getting on, check if this row is REALLY complete */ + if (*(*p)++ != ';') + return SILC_CONFIG_EMISSCOLON; + + /* convert the option argument to the right format */ + pt = silc_config_marshall(thisopt->type, buf); + if (!pt) + return SILC_CONFIG_EINVALIDTEXT; + if (thisopt->cb) { + ret = thisopt->cb(thisopt->type, thisopt->name, file->line, + pt, thisopt->context); + if (ret) { + SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret)); + return ret; + } + } + silc_free(pt); + } + continue; + + finish: + break; } - return 0; + return SILC_CONFIG_OK; +} + +/* ... */ + +int silc_config_main(SilcConfigEntity ent) +{ + SilcConfigFile *file = ent->file; + int ret; + + /* don't silently accept a NULL entity */ + if (!ent) { + ret = SILC_CONFIG_EGENERIC; + goto main_cleanup; + } + + /* call the real main and store the result */ + file->level++; + SILC_CONFIG_DEBUG(("[Lev=%d] Entering config parsing core", file->level)); + ret = silc_config_main_internal(ent); + SILC_CONFIG_DEBUG(("[Lev=%d] Quitting main [ret=%d]", file->level, ret)); + if (!file->level) /* when swap happens, we could close a file twice */ + goto main_end; + file->level--; + + /* If this file was included don't destroy the options set because it is + * the same of the including block. Although if this entity is in a + * sub-block created inside the included file, this options set must be + * destroyed. */ + main_cleanup: + if ((file->level != 0) || (file->included != TRUE)) + silc_config_destroy(ent); + + main_end: + return ret; } diff --git a/lib/silcutil/silcconfig.h b/lib/silcutil/silcconfig.h index 3153f256..87db1cf8 100644 --- a/lib/silcutil/silcconfig.h +++ b/lib/silcutil/silcconfig.h @@ -2,15 +2,15 @@ silcconfig.h - 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 @@ -18,12 +18,430 @@ */ +/****h* silcutil/SilcConfigAPI + * + * DESCRIPTION + * + * The SILC Config util library is based on two main objects, SilcConfigFile + * (or File object) and SilcConfigEntity (or Entity). The File objects are + * structs directly corresponding to the real files in the filesystem, while + * Entities are a little more abstract. + * An Entity is composed by delimited area on a File object (it can take the + * whole File object or just part of it), plus a group of known options. + * + * In order to parse this file, first you need to create a File object with + * the silc_config_open() function, and then you need to create the Entity + * with the silc_config_init() function. + * Now you can use the newly created Entity to register a group of expected + * known options and sub-blocks, and then you can call the main parsing loop + * with the silc_config_main() function. + * When silc_config_main() will return, if some error encoured the object file + * will point to the file that caused this error (this can be different from + * the originally opened file if it contained `Include' directives). If no + * errors encoured then the File objects will still point to the original + * file. + * While silc_config_main() will take care of destroying Entities before + * returning, you need to take care that the File object you created is freed + * with the silc_config_close() function. + * + * The SILC Config library won't take care about storing the values contained + * in the config file. You must take care about it with the callback + * functions. + * + * The config file syntax is pretty straightforward. All lines starting + * with `#' will be skipped, while sub-blocks are delimited by braces (see + * the example below). + * Options with argument must have the `=' character between the option + * name and the value. Simple words and numbers does not require quoting. + * There is a special built-in directive "Include" which allows you to include + * another config file in the point the directive is. You can also Include + * inside a sub-block body, in this case when parsing the included config file + * it will be assumed that we are within this block, and the included file + * won't be allowed to close his root block. + * + * Example: + * + * cipher { + * name = aes-256-cbc; + * module = "aes.sim.so"; + * key_length = 32; # usually the default is just fine + * block_length = 16; + * }; + * Include "/etc/silc/hash_funcs.conf"; + * + ***/ + #ifndef SILCCONFIG_H #define SILCCONFIG_H +/****d* silcutil/SilcConfigAPI/errno + * + * NAME + * + * enum { ... } - describe a SILC Config error + * + * DESCRIPTION + * + * The virtual integer `errno' is returned by the silc_config_main() + * function and indicates what went wrong. + * You can convert it to the corresponding error string with the function + * silc_config_strerror(). + * + * SOURCE + */ +enum { + SILC_CONFIG_OK, /* OK */ + SILC_CONFIG_ESILENT, /* Error defined by callback function */ + SILC_CONFIG_EGENERIC, /* Invalid syntax */ + SILC_CONFIG_EINTERNAL, /* Internal Error (caused by developer) */ + SILC_CONFIG_ECANTOPEN, /* Can't open specified file */ + SILC_CONFIG_EOPENBRACE, /* Expected open-brace '{' */ + SILC_CONFIG_ECLOSEBRACE, /* Missing close-brace '}' */ + SILC_CONFIG_ETYPE, /* Invalid data type */ + SILC_CONFIG_EBADOPTION, /* Unknown option */ + SILC_CONFIG_EINVALIDTEXT, /* Invalid text */ + SILC_CONFIG_EDOUBLE, /* Double option specification */ + SILC_CONFIG_EEXPECTED, /* Expected data but not found */ + SILC_CONFIG_EEXPECTEDEQUAL, /* Expected '=' */ + SILC_CONFIG_EUNEXPECTED, /* Unexpected data */ + SILC_CONFIG_EMISSFIELDS, /* Missing needed fields */ + SILC_CONFIG_EMISSCOLON, /* Missing ';' */ +}; +/***/ + +/****d* silcutil/SilcConfigAPI/SilcConfigType + * + * NAME + * + * typedef enum { ... } SilcConfigType; + * + * DESCRIPTION + * + * This identifies the parameter type that an option has. This parameter + * is very important because the callback's *val pointer points to a + * memory location containing the previously specified data type. + * For example, if you specified an option with an integer parameter + * callback's *val will be a pointer to an integer. + * + * SOURCE + */ +typedef enum { + SILC_CONFIG_ARG_TOGGLE, /* TOGGLE on,off; yes,no; true, false; */ + SILC_CONFIG_ARG_INT, /* callback wants an integer */ + SILC_CONFIG_ARG_STR, /* callback expects \0-terminated str */ + SILC_CONFIG_ARG_STRE, /* same as above, but can also be empty */ + SILC_CONFIG_ARG_BLOCK, /* this is a sub-block */ + SILC_CONFIG_ARG_SIZE, /* like int, but accepts suffixes kMG */ + SILC_CONFIG_ARG_NONE, /* does not expect any args */ +} SilcConfigType; +/***/ + +/****f* silcutil/SilcConfigAPI/SilcConfigCallback + * + * SYNOPSIS + * + * typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name, + * uint32 line, void *val, void *context); + * DESCRIPTION + * + * This is the callback prototype for the options handler. The pointer + * `val' points to a location of type described by `type'. `name' points + * to a null-terminated string with the name of the option which triggered + * this callback, that is stated at line `line'. `context' is the + * user-specified context provided when this option was registered. + * + ***/ +typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name, + uint32 line, void *val, void *context); + +/****s* silcutil/SilcConfigAPI/SilcConfigTable + * + * SYNOPSIS + * + * typedef struct { ... } SilcConfigTable; + * + * DESCRIPTION + * + * SILC Config table defines an easy and quick way of registering options + * in an entity. The function silc_config_register_table() will take as + * argument a SilcConfigTable array terminated by a NULL struct, it is + * important thus, that the `name' field of the terminating struct is set + * to NULL. + * + * char *name + * + * The option name lowercase. The matching is always case-insensitive, + * but for convention the option specification must always be lowercase. + * + * SilcConfigType type + * + * This specifies what kind of parameter this option expects. The + * special cases SILC_CONFIG_ARG_BLOCK tells SILC Config that this is + * not a normal option but the name of a sub-block of the current + * block (there is no limit to the number of nested blocks allowed). + * + * SilcConfigCallback callback + * + * Normally this is the value handler of the current option. If this + * field is set to NULL then the value is silently discarded. Useful + * for example to support deprecated options. + * + * SilcConfigTable *subtable + * + * If the `type' field is set to SILC_CONFIG_ARG_BLOCK, then this field + * must point to a valid sub-table NULL-terminated array. If `type' is + * something else, this valued is unused. + * + ***/ +typedef struct SilcConfigTableStruct { + char *name; + SilcConfigType type; + SilcConfigCallback callback; + const struct SilcConfigTableStruct *subtable; +} SilcConfigTable; + +/****s* silcutil/SilcConfigAPI/SilcConfigFile + * + * SYNOPSIS + * + * typedef struct { ... } SilcConfigFile; + * + * DESCRIPTION + * + * A File object holds the data contained in a previously loaded file by + * the silc_config_open() function. + * This is an internally allocated struct and must be used only with the + * helper functions. + * + ***/ +typedef struct SilcConfigFileObject SilcConfigFile; + +/****s* silcutil/SilcConfigAPI/SilcConfigEntity + * + * SYNOPSIS + * + * typedef struct { ... } SilcConfigEntity; + * + * DESCRIPTION + * + * The SILC Config is based on config entities. An entity contains the + * SilcConfigFile object we are parsing and the registered options. + * + ***/ +typedef struct SilcConfigEntityObject *SilcConfigEntity; + +/* Macros */ + +/****d* silcutil/SilcConfigAPI/SILC_CONFIG_CALLBACK + * + * NAME + * + * #define SILC_CONFIG_CALLBACK ... + * + * DESCRIPTION + * + * Generic macro to define SilcConfigCallback functions. This defines a + * static function with name `func' as a config callback function. + * + * SOURCE + */ +#define SILC_CONFIG_CALLBACK(func) \ +static int func(SilcConfigType type, const char *name, \ + uint32 line, void *val, void *context) +/***/ + /* Prototypes */ -void silc_config_open(char *filename, SilcBuffer *ret_buffer); -int silc_config_get_token(SilcBuffer buffer, char **dest); -int silc_config_check_num_token(SilcBuffer); -#endif +/****f* silcutil/SilcConfigAPI/silc_config_open + * + * SYNOPSIS + * + * SilcConfigFile *silc_config_open(char *configfile); + * + * DESCRIPTION + * + * Tries to open the config file `configfile' and returns a valid File + * object on success, or NULL on failure. + * An File object created this way must be destroyed with the function + * silc_config_close(). + * + ***/ +SilcConfigFile *silc_config_open(char *configfile); + +/****f* silcutil/SilcConfigAPI/silc_config_close + * + * SYNOPSIS + * + * void silc_config_close(SilcConfigFile *file); + * + * DESCRIPTION + * + * Closes and frees the File object `file', which must have been returned + * by a previous call to silc_config_open(). Otherwise, or if + * this function has already been called before for the same File object, + * undefined behaviour occurs. + * If `file' is NULL, no operation is performed. + * + ***/ +void silc_config_close(SilcConfigFile *file); + +/****f* silcutil/SilcConfigAPI/silc_config_init + * + * SYNOPSIS + * + * SilcConfigEntity silc_config_init(SilcConfigFile *file); + * + * DESCRIPTION + * + * Creates an Entity pointing to the valid File object `file', which must + * be returned by a previous call to silc_config_open(), otherwise NULL + * is returned. + * Entities will be automatically destroyed after the call to the + * silc_config_main() function, because of this no uninit functions are + * provided. + * + ***/ +SilcConfigEntity silc_config_init(SilcConfigFile *file); + +/****f* silcutil/SilcConfigAPI/silc_config_strerror + * + * SYNOPSIS + * + * char *silc_config_strerror(int errnum); + * + * DESCRIPTION + * + * The silc_config_strerror() function returns a string describing the + * error code passed in the argument `errnum'. + * + ***/ +char *silc_config_strerror(int errnum); + +/****f* silcutil/SilcConfigAPI/silc_config_get_filename + * + * SYNOPSIS + * + * char *silc_config_get_filename(SilcConfigFile *file); + * + * DESCRIPTION + * + * Returns the original filename of the object file. + * The returned pointer points to internally allocated storage and must + * not be freed, modified or stored. + * + ***/ +char *silc_config_get_filename(SilcConfigFile *file); + +/****f* silcutil/SilcConfigAPI/silc_config_get_line + * + * SYNOPSIS + * + * uint32 silc_config_get_line(SilcConfigFile *file); + * + * DESCRIPTION + * + * Returns the current line that file parsing arrived at. + * + ***/ +uint32 silc_config_get_line(SilcConfigFile *file); + +/****f* silcutil/SilcConfigAPI/silc_config_read_line + * + * SYNOPSIS + * + * char *silc_config_read_line(SilcConfigFile *file, uint32 line); + * + * DESCRIPTION + * + * Returns a dynamically allocated null-terminated buffer containing the + * line `line' of `file'. + * The returned pointer must be freed when it's not needed any longer. + * + * SEE ALSO + * silc_config_read_current_line + * + ***/ +char *silc_config_read_line(SilcConfigFile *file, uint32 line); + +/****f* silcutil/SilcConfigAPI/silc_config_read_current_line + * + * SYNOPSIS + * + * char *silc_config_read_current_line(SilcConfigFile *file); + * + * DESCRIPTION + * + * Returns a dynamically allocated buffer containing the line that the + * parser stopped at. This is a convenience function for + * silc_config_read_line. + * The returned pointer must be freed when it's not needed any longer. + * + ***/ +char *silc_config_read_current_line(SilcConfigFile *file); + +/****f* silcutil/SilcConfigAPI/silc_config_register + * + * SYNOPSIS + * + * void silc_config_register(SilcConfigEntity ent, const char *name, + * SilcConfigType type, SilcConfigCallback cb, + * const SilcConfigTable *subtable, + * void *context); + * + * DESCRIPTION + * + * Register option `name' in the entity `ent'. If `cb' is not NULL, it + * will be called with the *val pointer pointing to an internally + * allocated storage of type described by `type'. + * If `type' is SILC_CONFIG_ARG_BLOCK, then `subtable' must be a valid + * pointer to a SilcConfigTable array specified the options in the + * sub-block. + * + * SEE ALSO + * silc_config_register_table + * + ***/ +void silc_config_register(SilcConfigEntity ent, const char *name, + SilcConfigType type, SilcConfigCallback cb, + const SilcConfigTable *subtable, void *context); + +/****f* silcutil/SilcConfigAPI/silc_config_register_table + * + * SYNOPSIS + * + * void silc_config_register_table(SilcConfigEntity ent, + * const SilcConfigTable table[], + * void *context); + * + * DESCRIPTION + * + * Register the tableset of options `table' automatically in the entity + * `ent'. If defined in the table, the callback functions will be called + * all with the same context `context'. + * The `table' array must be terminated with an entry with the name field + * set to NULL. + * + * SEE ALSO + * SilcConfigTable + * + ***/ +void silc_config_register_table(SilcConfigEntity ent, + const SilcConfigTable table[], void *context); + +/****f* silcutil/SilcConfigAPI/silc_config_main + * + * SYNOPSIS + * + * int silc_config_main(SilcConfigEntity ent); + * + * DESCRIPTION + * + * Enter the main parsing loop. When this function returns the parsing + * is finished in the current block (and sub-blocks). + * When this function exits, the entity is already destroyed, because + * of this you should set it to NULL right after the function call. + * + ***/ +int silc_config_main(SilcConfigEntity ent); + +#endif /* !SILCCONFIG_H */ diff --git a/lib/silcutil/silclog.h b/lib/silcutil/silclog.h index 76f8f67c..46db3249 100644 --- a/lib/silcutil/silclog.h +++ b/lib/silcutil/silclog.h @@ -41,7 +41,7 @@ * This is the main logging channel id. There are currently four known * logging channels (plus the debugging output channel), and they are * ordered by importance. - * See the source code for SILC coding conventions about how choosing + * See the source code for SILC coding conventions about how to choose * the right output channel. * * SOURCE @@ -59,7 +59,7 @@ typedef enum { /* Fatal messages (usually situations that will lead to a program crash */ SILC_LOG_FATAL, - /* Total logging channels */ + /* Total number logging channels */ SILC_LOG_MAX } SilcLogType; /***/ @@ -122,8 +122,8 @@ typedef bool (*SilcLogDebugCb)(char *file, char *function, int line, * DESCRIPTION * * The hexdump logging callback function. The default behaviour is to - * print a formatted hexdump to stderr, and is commonly what you would it - * like to be. `file', `function', and `line' are the corresponding + * print a formatted hexdump to stderr, and is commonly what you would + * like it to be. `file', `function', and `line' are the corresponding * offsets in the source files. `data' is the begin of the buffer that * should be hexdumped, which is `data_len' bytes long. * The `message' parameter points to a null-terminated buffer containing @@ -316,14 +316,12 @@ extern DLLAPI bool silc_debug_hexdump; * DESCRIPTION * * This is a special wrapper to the debugging output (usually stderr). - * The standard behaviour is the same as SILC_LOG_INFO, but this macro - * also depends on the global debugging macro SILC_DEBUG. - * Undefining the global SILC_DEBUG define causes these functions to be - * defined to an empty value, thus removing all logging calls from the - * compiled program. - * - * SEE ALSO - * SILC_LOG_INFO + * The standard behaviour is the same as SILC_LOG_INFO, with the difference + * that this macro also depends on the global define SILC_DEBUG. + * Undefining SILC_DEBUG causes these functions to be defined to an empty + * value, thus removing all debug logging calls from the compiled + * application. + * This macro is also affected by the global variable silc_debug. * * SOURCE */ @@ -349,13 +347,13 @@ extern DLLAPI bool silc_debug_hexdump; * behaves slightly differently from other logging wrappers. * The first parameter, is composed by a group of parameters delimited by * parenthesis. - * The second parameter is a (char *) pointer to the beginning of the - * memory section that should be hexdumped, and the third parameter is - * the length of this memory section. - * This macro is also affected by the global variable silc_debug_hexdump. + * The second parameter is a `char *' pointer pointing to the beginning + * of the memory section that should be hexdumped, and the third parameter + * is the length of this memory section. * Undefining the global SILC_DEBUG define causes these functions to be - * defined to an empty value, thus removing all logging calls from the - * compiled program. + * defined to an empty value, thus removing all debug logging calls from + * the compiled application. + * This macro is also affected by the global variable silc_debug_hexdump. * * EXAMPLE * @@ -414,7 +412,7 @@ void silc_log_output(SilcLogType type, char *string); * is returned, even if the file has been previously set with * silc_log_set_file(). * The returned pointer points to internally allocated storage and must - * must not be freed, modified or stored. + * not be freed, modified or stored. * ***/ char *silc_log_get_file(SilcLogType type); @@ -461,7 +459,7 @@ bool silc_log_set_file(SilcLogType type, char *filename, uint32 maxsize, * SilcLogCb. * * SEE ALSO - * SilcLogCb, silc_log_reset_callbacks + * silc_log_reset_callbacks * ***/ void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context);