5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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_HMAC, 3 },
38 SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
40 SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
42 { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
45 /* Allocates a new configuration object, opens configuration file and
46 parses the file. The parsed data is returned to the newly allocated
47 configuration object. */
49 SilcClientConfig silc_client_config_alloc(char *filename)
53 SilcClientConfigParse config_parse;
55 SILC_LOG_DEBUG(("Allocating new configuration object"));
57 new = silc_calloc(1, sizeof(*new));
58 new->filename = filename;
60 /* Open configuration file and parse it */
63 silc_config_open(filename, &buffer);
66 if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
68 if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
80 /* Free's a configuration object. */
82 void silc_client_config_free(SilcClientConfig config)
90 /* Parses the the buffer and returns the parsed lines into return_config
91 argument. The return_config argument doesn't have to be initialized
92 before calling this. It will be initialized during the parsing. The
93 buffer sent as argument can be safely free'd after this function has
94 succesfully returned. */
96 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
97 SilcClientConfigParse *return_config)
101 char line[1024], *cp;
102 SilcClientConfigSection *cptr = NULL;
103 SilcClientConfigParse parse = *return_config, first = NULL;
105 SILC_LOG_DEBUG(("Parsing configuration file"));
109 while((begin = silc_gets(line, sizeof(line),
110 buffer->data, buffer->len, begin)) != EOF) {
114 /* Check for bad line */
115 if (silc_check_line(cp))
118 /* Remove tabs and whitespaces from the line */
119 if (strchr(cp, '\t')) {
121 while(strchr(cp + i, '\t')) {
122 *strchr(cp + i, '\t') = ' ';
126 for (i = 0; i < strlen(cp); i++) {
142 /* Remove new line sign */
143 if (strchr(cp, '\n'))
144 *strchr(cp, '\n') = '\0';
146 /* Check for matching sections */
147 for (cptr = silc_client_config_sections; cptr->section; cptr++)
148 if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
151 if (!cptr->section) {
152 fprintf(stderr, "%s:%d: Unknown section `%s'\n",
153 config->filename, linenum, cp);
160 * Start of a configuration line
163 /* Handle config section */
164 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
166 if (strchr(cp, '\n'))
167 *strchr(cp, '\n') = ':';
170 parse = silc_calloc(1, sizeof(*parse));
172 parse->section = NULL;
176 if (parse->next == NULL) {
177 parse->next = silc_calloc(1, sizeof(*parse->next));
178 parse->next->line = NULL;
179 parse->next->section = NULL;
180 parse->next->next = NULL;
181 parse->next->prev = parse;
189 /* Add the line to parsing structure for further parsing. */
191 parse->section = cptr;
192 parse->line = silc_buffer_alloc(strlen(cp) + 1);
193 parse->linenum = linenum;
194 silc_buffer_pull_tail(parse->line, strlen(cp));
195 silc_buffer_put(parse->line, cp, strlen(cp));
202 /* Set the return_config argument to its first value so that further
203 parsing can be started from the first line. */
204 *return_config = first;
209 /* Parses the lines earlier read from configuration file. The config object
210 must not be initialized, it will be initialized in this function. The
211 parse_config argument is uninitialized automatically during this
214 int silc_client_config_parse_lines(SilcClientConfig config,
215 SilcClientConfigParse parse_config)
217 int ret, check = FALSE;
219 SilcClientConfigParse pc = parse_config;
222 SILC_LOG_DEBUG(("Parsing configuration lines"));
231 /* Get number of tokens in line (command section is handeled
232 specially and has no tokens at all). */
233 ret = silc_config_check_num_token(line);
234 if (ret != pc->section->maxfields &&
235 pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
237 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
238 config->filename, pc->linenum, ret,
239 pc->section->maxfields);
244 switch(pc->section->type) {
245 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
247 if (!config->cipher) {
248 config->cipher = silc_calloc(1, sizeof(*config->cipher));
249 config->cipher->next = NULL;
250 config->cipher->prev = NULL;
252 if (!config->cipher->next) {
253 config->cipher->next =
254 silc_calloc(1, sizeof(*config->cipher->next));
255 config->cipher->next->next = NULL;
256 config->cipher->next->prev = config->cipher;
257 config->cipher = config->cipher->next;
261 /* Get cipher name */
262 ret = silc_config_get_token(line, &config->cipher->alg_name);
266 fprintf(stderr, "%s:%d: Cipher name not defined\n",
267 config->filename, pc->linenum);
271 /* Get module name */
272 config->cipher->sim_name = NULL;
273 ret = silc_config_get_token(line, &config->cipher->sim_name);
278 ret = silc_config_get_token(line, &tmp);
282 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
283 config->filename, pc->linenum);
286 config->cipher->key_len = atoi(tmp);
289 /* Get block length */
290 ret = silc_config_get_token(line, &tmp);
294 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
295 config->filename, pc->linenum);
298 config->cipher->block_len = atoi(tmp);
304 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
307 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
308 config->pkcs->next = NULL;
309 config->pkcs->prev = NULL;
311 if (!config->pkcs->next) {
313 silc_calloc(1, sizeof(*config->pkcs->next));
314 config->pkcs->next->next = NULL;
315 config->pkcs->next->prev = config->pkcs;
316 config->pkcs = config->pkcs->next;
321 ret = silc_config_get_token(line, &config->pkcs->alg_name);
325 fprintf(stderr, "%s:%d: PKCS name not defined\n",
326 config->filename, pc->linenum);
331 ret = silc_config_get_token(line, &tmp);
335 fprintf(stderr, "%s:%d: PKCS key length not defined\n",
336 config->filename, pc->linenum);
339 config->pkcs->key_len = atoi(tmp);
345 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
347 if (!config->hash_func) {
348 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
349 config->hash_func->next = NULL;
350 config->hash_func->prev = NULL;
352 if (!config->hash_func->next) {
353 config->hash_func->next =
354 silc_calloc(1, sizeof(*config->hash_func->next));
355 config->hash_func->next->next = NULL;
356 config->hash_func->next->prev = config->hash_func;
357 config->hash_func = config->hash_func->next;
361 /* Get Hash function name */
362 ret = silc_config_get_token(line, &config->hash_func->alg_name);
366 fprintf(stderr, "%s:%d: Hash function name not defined\n",
367 config->filename, pc->linenum);
371 /* Get Hash function module name */
372 config->hash_func->sim_name = NULL;
373 ret = silc_config_get_token(line, &config->hash_func->sim_name);
377 /* Get block length */
378 ret = silc_config_get_token(line, &tmp);
382 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
383 config->filename, pc->linenum);
386 config->hash_func->block_len = atoi(tmp);
389 /* Get hash length */
390 ret = silc_config_get_token(line, &tmp);
394 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
395 config->filename, pc->linenum);
398 config->hash_func->key_len = atoi(tmp);
404 case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
407 config->hmac = silc_calloc(1, sizeof(*config->hmac));
408 config->hmac->next = NULL;
409 config->hmac->prev = NULL;
411 if (!config->hmac->next) {
413 silc_calloc(1, sizeof(*config->hmac->next));
414 config->hmac->next->next = NULL;
415 config->hmac->next->prev = config->hmac;
416 config->hmac = config->hmac->next;
421 ret = silc_config_get_token(line, &config->hmac->alg_name);
425 fprintf(stderr, "%s:%d: HMAC name not defined\n",
426 config->filename, pc->linenum);
430 /* Get Hash function name */
431 ret = silc_config_get_token(line, &config->hmac->sim_name);
435 fprintf(stderr, "%s:%d: Hash function name not defined\n",
436 config->filename, pc->linenum);
441 ret = silc_config_get_token(line, &tmp);
445 fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
446 config->filename, pc->linenum);
449 config->hmac->key_len = atoi(tmp);
455 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
457 if (!config->conns) {
458 config->conns = silc_calloc(1, sizeof(*config->conns));
459 config->conns->next = NULL;
460 config->conns->prev = NULL;
462 if (!config->conns->next) {
463 config->conns->next = silc_calloc(1, sizeof(*config->conns));
464 config->conns->next->next = NULL;
465 config->conns->next->prev = config->conns;
466 config->conns = config->conns->next;
471 ret = silc_config_get_token(line, &config->conns->host);
476 config->conns->host = strdup("*");
478 /* Get authentication method */
479 ret = silc_config_get_token(line, &tmp);
483 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
484 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
485 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
486 config->filename, pc->linenum, tmp);
490 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
491 config->conns->auth_meth = SILC_AUTH_PASSWORD;
493 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
494 config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
499 /* Get authentication data */
500 ret = silc_config_get_token(line, &config->conns->auth_data);
505 ret = silc_config_get_token(line, &tmp);
509 config->conns->port = atoi(tmp);
516 case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
518 if (!config->commands) {
519 config->commands = silc_calloc(1, sizeof(*config->commands));
520 config->commands->next = NULL;
521 config->commands->prev = NULL;
523 if (!config->commands->next) {
524 config->commands->next = silc_calloc(1, sizeof(*config->commands));
525 config->commands->next->next = NULL;
526 config->commands->next->prev = config->commands;
527 config->commands = config->commands->next;
531 /* Get command line (this may include parameters as well. They
532 will be parsed later with standard command parser when
533 executing particular command.) */
534 config->commands->command = silc_calloc(strlen(line->data),
536 memcpy(config->commands->command, line->data, strlen(line->data) - 1);
543 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
548 /* Check for error */
549 if (check == FALSE) {
550 /* Line could not be parsed */
551 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
561 /* Before returning all the lists in the config object must be set
562 to their first values (the last value is first here). */
563 while (config->cipher && config->cipher->prev)
564 config->cipher = config->cipher->prev;
565 while (config->pkcs && config->pkcs->prev)
566 config->pkcs = config->pkcs->prev;
567 while (config->hash_func && config->hash_func->prev)
568 config->hash_func = config->hash_func->prev;
569 while (config->hmac && config->hmac->prev)
570 config->hmac = config->hmac->prev;
571 while (config->conns && config->conns->prev)
572 config->conns = config->conns->prev;
573 while (config->commands && config->commands->prev)
574 config->commands = config->commands->prev;
576 SILC_LOG_DEBUG(("Done"));
581 /* Registers configured ciphers. These can then be allocated by the
582 client when needed. */
584 void silc_client_config_register_ciphers(SilcClientConfig config)
586 SilcClientConfigSectionAlg *alg;
587 SilcClientInternal app = (SilcClientInternal)config->client;
588 SilcClient client = app->client;
590 SILC_LOG_DEBUG(("Registering configured ciphers"));
592 alg = config->cipher;
595 if (!alg->sim_name) {
596 /* Crypto module is supposed to be built in. Nothing to be done
597 here except to test that the cipher really is built in. */
598 SilcCipher tmp = NULL;
600 if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
601 SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
602 silc_client_stop(client);
605 silc_cipher_free(tmp);
609 /* Load (try at least) the crypto SIM module */
610 SilcCipherObject cipher;
614 memset(&cipher, 0, sizeof(cipher));
615 cipher.name = alg->alg_name;
616 cipher.block_len = alg->block_len;
617 cipher.key_len = alg->key_len * 8;
619 sim = silc_sim_alloc();
620 sim->type = SILC_SIM_CIPHER;
621 sim->libname = alg->sim_name;
623 alg_name = strdup(alg->alg_name);
624 if (strchr(alg_name, '-'))
625 *strchr(alg_name, '-') = '\0';
627 if ((silc_sim_load(sim))) {
629 silc_sim_getsym(sim, silc_sim_symname(alg_name,
630 SILC_CIPHER_SIM_SET_KEY));
631 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
632 cipher.set_key_with_string =
633 silc_sim_getsym(sim, silc_sim_symname(alg_name,
634 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
635 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
637 silc_sim_getsym(sim, silc_sim_symname(alg_name,
638 SILC_CIPHER_SIM_ENCRYPT_CBC));
639 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
641 silc_sim_getsym(sim, silc_sim_symname(alg_name,
642 SILC_CIPHER_SIM_DECRYPT_CBC));
643 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
645 silc_sim_getsym(sim, silc_sim_symname(alg_name,
646 SILC_CIPHER_SIM_CONTEXT_LEN));
647 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
649 /* Put the SIM to the table of all SIM's in client */
650 app->sim = silc_realloc(app->sim,
652 (app->sim_count + 1));
653 app->sim[app->sim_count] = sim;
658 SILC_LOG_ERROR(("Error configuring ciphers"));
659 silc_client_stop(client);
663 /* Register the cipher */
664 silc_cipher_register(&cipher);
672 /* Registers configured PKCS's. */
673 /* XXX: This really doesn't do anything now since we have statically
674 registered our PKCS's. This should be implemented when PKCS works
675 as SIM's. This checks now only that the PKCS user requested is
678 void silc_client_config_register_pkcs(SilcClientConfig config)
680 SilcClientConfigSectionAlg *alg = config->pkcs;
681 SilcClientInternal app = (SilcClientInternal)config->client;
682 SilcClient client = app->client;
685 SILC_LOG_DEBUG(("Registering configured PKCS"));
689 if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
690 SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
691 silc_client_stop(client);
700 /* Registers configured hash funtions. These can then be allocated by the
701 client when needed. */
703 void silc_client_config_register_hashfuncs(SilcClientConfig config)
705 SilcClientConfigSectionAlg *alg;
706 SilcClientInternal app = (SilcClientInternal)config->client;
707 SilcClient client = app->client;
709 SILC_LOG_DEBUG(("Registering configured hash functions"));
711 alg = config->hash_func;
713 if (!alg->sim_name) {
714 if (!silc_hash_is_supported(alg->alg_name)) {
715 SILC_LOG_ERROR(("Unsupported hash function `%s'",
717 silc_client_stop(client);
725 /* Registers configured HMACs. These can then be allocated by the
726 client when needed. */
728 void silc_client_config_register_hmacs(SilcClientConfig config)
730 SilcClientConfigSectionAlg *alg;
731 SilcClientInternal app = (SilcClientInternal)config->client;
732 SilcClient client = app->client;
734 SILC_LOG_DEBUG(("Registering configured HMACs"));
737 SILC_LOG_ERROR(("HMACs are not configured. SILC cannot work without "
739 silc_client_stop(client);
747 if (!silc_hash_is_supported(alg->sim_name)) {
748 SILC_LOG_ERROR(("Unsupported hash function `%s'",
750 silc_client_stop(client);
754 /* Register the HMAC */
755 memset(&hmac, 0, sizeof(hmac));
756 hmac.name = alg->alg_name;
757 hmac.len = alg->key_len;
758 silc_hmac_register(&hmac);
764 SilcClientConfigSectionConnection *
765 silc_client_config_find_connection(SilcClientConfig config,
766 char *host, int port)
769 SilcClientConfigSectionConnection *conn = NULL;
771 SILC_LOG_DEBUG(("Finding connection"));
779 conn = config->conns;
780 for (i = 0; conn; i++) {
781 if (silc_string_compare(conn->host, host))
789 SILC_LOG_DEBUG(("Found match"));