5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientincludes.h"
23 #include "clientconfig.h"
26 All possible configuration sections for SILC client.
28 SilcClientConfigSection silc_client_config_sections[] = {
30 SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
32 SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 2 },
34 SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
36 SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
38 SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
40 { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
43 /* Allocates a new configuration object, opens configuration file and
44 parses the file. The parsed data is returned to the newly allocated
45 configuration object. */
47 SilcClientConfig silc_client_config_alloc(char *filename)
51 SilcClientConfigParse config_parse;
53 SILC_LOG_DEBUG(("Allocating new configuration object"));
55 new = silc_calloc(1, sizeof(*new));
56 new->filename = filename;
58 /* Open configuration file and parse it */
61 silc_config_open(filename, &buffer);
64 if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
66 if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
78 /* Free's a configuration object. */
80 void silc_client_config_free(SilcClientConfig config)
88 /* Parses the the buffer and returns the parsed lines into return_config
89 argument. The return_config argument doesn't have to be initialized
90 before calling this. It will be initialized during the parsing. The
91 buffer sent as argument can be safely free'd after this function has
92 succesfully returned. */
94 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
95 SilcClientConfigParse *return_config)
100 SilcClientConfigSection *cptr = NULL;
101 SilcClientConfigParse parse = *return_config, first = NULL;
103 SILC_LOG_DEBUG(("Parsing configuration file"));
107 while((begin = silc_gets(line, sizeof(line),
108 buffer->data, buffer->len, begin)) != EOF) {
112 /* Check for bad line */
113 if (silc_check_line(cp))
116 /* Remove tabs and whitespaces from the line */
117 if (strchr(cp, '\t')) {
119 while(strchr(cp + i, '\t')) {
120 *strchr(cp + i, '\t') = ' ';
124 for (i = 0; i < strlen(cp); i++) {
140 /* Remove new line sign */
141 if (strchr(cp, '\n'))
142 *strchr(cp, '\n') = '\0';
144 /* Check for matching sections */
145 for (cptr = silc_client_config_sections; cptr->section; cptr++)
146 if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
149 if (!cptr->section) {
150 fprintf(stderr, "%s:%d: Unknown section `%s'\n",
151 config->filename, linenum, cp);
158 * Start of a configuration line
161 /* Handle config section */
162 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
164 if (strchr(cp, '\n'))
165 *strchr(cp, '\n') = ':';
168 parse = silc_calloc(1, sizeof(*parse));
170 parse->section = NULL;
174 if (parse->next == NULL) {
175 parse->next = silc_calloc(1, sizeof(*parse->next));
176 parse->next->line = NULL;
177 parse->next->section = NULL;
178 parse->next->next = NULL;
179 parse->next->prev = parse;
187 /* Add the line to parsing structure for further parsing. */
189 parse->section = cptr;
190 parse->line = silc_buffer_alloc(strlen(cp) + 1);
191 parse->linenum = linenum;
192 silc_buffer_pull_tail(parse->line, strlen(cp));
193 silc_buffer_put(parse->line, cp, strlen(cp));
200 /* Set the return_config argument to its first value so that further
201 parsing can be started from the first line. */
202 *return_config = first;
207 /* Parses the lines earlier read from configuration file. The config object
208 must not be initialized, it will be initialized in this function. The
209 parse_config argument is uninitialized automatically during this
212 int silc_client_config_parse_lines(SilcClientConfig config,
213 SilcClientConfigParse parse_config)
215 int ret, check = FALSE;
217 SilcClientConfigParse pc = parse_config;
220 SILC_LOG_DEBUG(("Parsing configuration lines"));
229 /* Get number of tokens in line (command section is handeled
230 specially and has no tokens at all). */
231 ret = silc_config_check_num_token(line);
232 if (ret != pc->section->maxfields &&
233 pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
235 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
236 config->filename, pc->linenum, ret,
237 pc->section->maxfields);
242 switch(pc->section->type) {
243 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
245 if (!config->cipher) {
246 config->cipher = silc_calloc(1, sizeof(*config->cipher));
247 config->cipher->next = NULL;
248 config->cipher->prev = NULL;
250 if (!config->cipher->next) {
251 config->cipher->next =
252 silc_calloc(1, sizeof(*config->cipher->next));
253 config->cipher->next->next = NULL;
254 config->cipher->next->prev = config->cipher;
255 config->cipher = config->cipher->next;
259 /* Get cipher name */
260 ret = silc_config_get_token(line, &config->cipher->alg_name);
264 fprintf(stderr, "%s:%d: Cipher name not defined\n",
265 config->filename, pc->linenum);
269 /* Get module name */
270 config->cipher->sim_name = NULL;
271 ret = silc_config_get_token(line, &config->cipher->sim_name);
275 /* Get block length */
276 ret = silc_config_get_token(line, &tmp);
280 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
281 config->filename, pc->linenum);
284 config->cipher->block_len = atoi(tmp);
288 ret = silc_config_get_token(line, &tmp);
292 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
293 config->filename, pc->linenum);
296 config->cipher->key_len = atoi(tmp);
302 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
305 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
306 config->pkcs->next = NULL;
307 config->pkcs->prev = NULL;
309 if (!config->pkcs->next) {
311 silc_calloc(1, sizeof(*config->pkcs->next));
312 config->pkcs->next->next = NULL;
313 config->pkcs->next->prev = config->pkcs;
314 config->pkcs = config->pkcs->next;
319 ret = silc_config_get_token(line, &config->pkcs->alg_name);
323 fprintf(stderr, "%s:%d: PKCS name not defined\n",
324 config->filename, pc->linenum);
329 ret = silc_config_get_token(line, &tmp);
333 fprintf(stderr, "%s:%d: PKCS key length not defined\n",
334 config->filename, pc->linenum);
337 config->pkcs->key_len = atoi(tmp);
343 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
345 if (!config->hash_func) {
346 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
347 config->hash_func->next = NULL;
348 config->hash_func->prev = NULL;
350 if (!config->hash_func->next) {
351 config->hash_func->next =
352 silc_calloc(1, sizeof(*config->hash_func->next));
353 config->hash_func->next->next = NULL;
354 config->hash_func->next->prev = config->hash_func;
355 config->hash_func = config->hash_func->next;
359 /* Get Hash function name */
360 ret = silc_config_get_token(line, &config->hash_func->alg_name);
364 fprintf(stderr, "%s:%d: Hash function name not defined\n",
365 config->filename, pc->linenum);
369 /* Get Hash function module name */
370 config->hash_func->sim_name = NULL;
371 ret = silc_config_get_token(line, &config->hash_func->sim_name);
375 /* Get block length */
376 ret = silc_config_get_token(line, &tmp);
380 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
381 config->filename, pc->linenum);
384 config->hash_func->block_len = atoi(tmp);
387 /* Get hash length */
388 ret = silc_config_get_token(line, &tmp);
392 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
393 config->filename, pc->linenum);
396 config->hash_func->key_len = atoi(tmp);
402 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
404 if (!config->conns) {
405 config->conns = silc_calloc(1, sizeof(*config->conns));
406 config->conns->next = NULL;
407 config->conns->prev = NULL;
409 if (!config->conns->next) {
410 config->conns->next = silc_calloc(1, sizeof(*config->conns));
411 config->conns->next->next = NULL;
412 config->conns->next->prev = config->conns;
413 config->conns = config->conns->next;
418 ret = silc_config_get_token(line, &config->conns->host);
423 config->conns->host = strdup("*");
425 /* Get authentication method */
426 ret = silc_config_get_token(line, &tmp);
430 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
431 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
432 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
433 config->filename, pc->linenum, tmp);
437 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
438 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
440 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
441 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
446 /* Get authentication data */
447 ret = silc_config_get_token(line, &config->conns->auth_data);
452 ret = silc_config_get_token(line, &tmp);
456 config->conns->port = atoi(tmp);
463 case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
465 if (!config->commands) {
466 config->commands = silc_calloc(1, sizeof(*config->commands));
467 config->commands->next = NULL;
468 config->commands->prev = NULL;
470 if (!config->commands->next) {
471 config->commands->next = silc_calloc(1, sizeof(*config->commands));
472 config->commands->next->next = NULL;
473 config->commands->next->prev = config->commands;
474 config->commands = config->commands->next;
478 /* Get command line (this may include parameters as well. They
479 will be parsed later with standard command parser when
480 executing particular command.) */
481 config->commands->command = silc_calloc(strlen(line->data),
483 memcpy(config->commands->command, line->data, strlen(line->data) - 1);
490 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
495 /* Check for error */
496 if (check == FALSE) {
497 /* Line could not be parsed */
498 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
508 /* Before returning all the lists in the config object must be set
509 to their first values (the last value is first here). */
510 while (config->cipher && config->cipher->prev)
511 config->cipher = config->cipher->prev;
512 while (config->pkcs && config->pkcs->prev)
513 config->pkcs = config->pkcs->prev;
514 while (config->hash_func && config->hash_func->prev)
515 config->hash_func = config->hash_func->prev;
516 while (config->conns && config->conns->prev)
517 config->conns = config->conns->prev;
518 while (config->commands && config->commands->prev)
519 config->commands = config->commands->prev;
521 SILC_LOG_DEBUG(("Done"));
526 /* Registers configured ciphers. These can then be allocated by the
527 client when needed. */
529 void silc_client_config_register_ciphers(SilcClientConfig config)
531 SilcClientConfigSectionAlg *alg;
532 SilcClientInternal app = (SilcClientInternal)config->client;
533 SilcClient client = app->client;
535 SILC_LOG_DEBUG(("Registering configured ciphers"));
537 alg = config->cipher;
540 if (!alg->sim_name) {
541 /* Crypto module is supposed to be built in. Nothing to be done
542 here except to test that the cipher really is built in. */
543 SilcCipher tmp = NULL;
545 if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
546 SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
547 silc_client_stop(client);
550 silc_cipher_free(tmp);
554 /* Load (try at least) the crypto SIM module */
555 SilcCipherObject cipher;
558 memset(&cipher, 0, sizeof(cipher));
559 cipher.name = alg->alg_name;
560 cipher.block_len = alg->block_len;
561 cipher.key_len = alg->key_len * 8;
563 sim = silc_sim_alloc();
564 sim->type = SILC_SIM_CIPHER;
565 sim->libname = alg->sim_name;
567 if ((silc_sim_load(sim))) {
569 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
570 SILC_CIPHER_SIM_SET_KEY));
571 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
572 cipher.set_key_with_string =
573 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
574 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
575 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
577 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
578 SILC_CIPHER_SIM_ENCRYPT_CBC));
579 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
581 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
582 SILC_CIPHER_SIM_DECRYPT_CBC));
583 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
585 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
586 SILC_CIPHER_SIM_CONTEXT_LEN));
587 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
589 /* Put the SIM to the table of all SIM's in client */
590 app->sim = silc_realloc(app->sim,
592 (app->sim_count + 1));
593 app->sim[app->sim_count] = sim;
596 SILC_LOG_ERROR(("Error configuring ciphers"));
597 silc_client_stop(client);
601 /* Register the cipher */
602 silc_cipher_register(&cipher);
610 /* Registers configured PKCS's. */
611 /* XXX: This really doesn't do anything now since we have statically
612 registered our PKCS's. This should be implemented when PKCS works
613 as SIM's. This checks now only that the PKCS user requested is
616 void silc_client_config_register_pkcs(SilcClientConfig config)
618 SilcClientConfigSectionAlg *alg = config->pkcs;
619 SilcClientInternal app = (SilcClientInternal)config->client;
620 SilcClient client = app->client;
623 SILC_LOG_DEBUG(("Registering configured PKCS"));
627 if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
628 SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
629 silc_client_stop(client);
638 /* Registers configured hash functions. These can then be allocated by the
639 client when needed. */
641 void silc_client_config_register_hashfuncs(SilcClientConfig config)
643 SilcClientConfigSectionAlg *alg;
644 SilcClientInternal app = (SilcClientInternal)config->client;
645 SilcClient client = app->client;
647 SILC_LOG_DEBUG(("Registering configured hash functions"));
649 alg = config->hash_func;
652 if (!alg->sim_name) {
653 /* Hash module is supposed to be built in. Nothing to be done
654 here except to test that the hash function really is built in. */
657 if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
658 SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
659 silc_client_stop(client);
666 /* Load (try at least) the hash SIM module */
670 memset(&hash, 0, sizeof(hash));
671 hash.name = alg->alg_name;
672 hash.block_len = alg->block_len;
673 hash.hash_len = alg->key_len;
675 sim = silc_sim_alloc();
676 sim->type = SILC_SIM_HASH;
677 sim->libname = alg->sim_name;
679 if ((silc_sim_load(sim))) {
681 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
682 SILC_HASH_SIM_INIT));
683 SILC_LOG_DEBUG(("init=%p", hash.init));
685 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
686 SILC_HASH_SIM_UPDATE));
687 SILC_LOG_DEBUG(("update=%p", hash.update));
689 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
690 SILC_HASH_SIM_FINAL));
691 SILC_LOG_DEBUG(("final=%p", hash.final));
693 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
694 SILC_HASH_SIM_CONTEXT_LEN));
695 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
697 /* Put the SIM to the table of all SIM's in client */
698 app->sim = silc_realloc(app->sim,
700 (app->sim_count + 1));
701 app->sim[app->sim_count] = sim;
704 SILC_LOG_ERROR(("Error configuring hash functions"));
705 silc_client_stop(client);
709 /* Register the cipher */
710 silc_hash_register(&hash);
719 SilcClientConfigSectionConnection *
720 silc_client_config_find_connection(SilcClientConfig config,
721 char *host, int port)
724 SilcClientConfigSectionConnection *conn = NULL;
726 SILC_LOG_DEBUG(("Finding connection"));
734 conn = config->conns;
735 for (i = 0; conn; i++) {
736 if (silc_string_compare(conn->host, host))
744 SILC_LOG_DEBUG(("Found match"));