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);
276 ret = silc_config_get_token(line, &tmp);
280 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
281 config->filename, pc->linenum);
284 config->cipher->key_len = atoi(tmp);
287 /* Get block length */
288 ret = silc_config_get_token(line, &tmp);
292 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
293 config->filename, pc->linenum);
296 config->cipher->block_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_AUTH_PASSWORD;
440 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
441 config->conns->auth_meth = SILC_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;
559 memset(&cipher, 0, sizeof(cipher));
560 cipher.name = alg->alg_name;
561 cipher.block_len = alg->block_len;
562 cipher.key_len = alg->key_len * 8;
564 sim = silc_sim_alloc();
565 sim->type = SILC_SIM_CIPHER;
566 sim->libname = alg->sim_name;
568 alg_name = strdup(alg->alg_name);
569 if (strchr(alg_name, '-'))
570 *strchr(alg_name, '-') = '\0';
572 if ((silc_sim_load(sim))) {
574 silc_sim_getsym(sim, silc_sim_symname(alg_name,
575 SILC_CIPHER_SIM_SET_KEY));
576 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
577 cipher.set_key_with_string =
578 silc_sim_getsym(sim, silc_sim_symname(alg_name,
579 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
580 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
582 silc_sim_getsym(sim, silc_sim_symname(alg_name,
583 SILC_CIPHER_SIM_ENCRYPT_CBC));
584 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
586 silc_sim_getsym(sim, silc_sim_symname(alg_name,
587 SILC_CIPHER_SIM_DECRYPT_CBC));
588 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
590 silc_sim_getsym(sim, silc_sim_symname(alg_name,
591 SILC_CIPHER_SIM_CONTEXT_LEN));
592 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
594 /* Put the SIM to the table of all SIM's in client */
595 app->sim = silc_realloc(app->sim,
597 (app->sim_count + 1));
598 app->sim[app->sim_count] = sim;
603 SILC_LOG_ERROR(("Error configuring ciphers"));
604 silc_client_stop(client);
608 /* Register the cipher */
609 silc_cipher_register(&cipher);
617 /* Registers configured PKCS's. */
618 /* XXX: This really doesn't do anything now since we have statically
619 registered our PKCS's. This should be implemented when PKCS works
620 as SIM's. This checks now only that the PKCS user requested is
623 void silc_client_config_register_pkcs(SilcClientConfig config)
625 SilcClientConfigSectionAlg *alg = config->pkcs;
626 SilcClientInternal app = (SilcClientInternal)config->client;
627 SilcClient client = app->client;
630 SILC_LOG_DEBUG(("Registering configured PKCS"));
634 if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
635 SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
636 silc_client_stop(client);
645 /* Registers configured hash functions. These can then be allocated by the
646 client when needed. */
648 void silc_client_config_register_hashfuncs(SilcClientConfig config)
650 SilcClientConfigSectionAlg *alg;
651 SilcClientInternal app = (SilcClientInternal)config->client;
652 SilcClient client = app->client;
654 SILC_LOG_DEBUG(("Registering configured hash functions"));
656 alg = config->hash_func;
659 if (!alg->sim_name) {
660 /* Hash module is supposed to be built in. Nothing to be done
661 here except to test that the hash function really is built in. */
664 if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
665 SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
666 silc_client_stop(client);
673 /* Load (try at least) the hash SIM module */
677 memset(&hash, 0, sizeof(hash));
678 hash.name = alg->alg_name;
679 hash.block_len = alg->block_len;
680 hash.hash_len = alg->key_len;
682 sim = silc_sim_alloc();
683 sim->type = SILC_SIM_HASH;
684 sim->libname = alg->sim_name;
686 if ((silc_sim_load(sim))) {
688 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
689 SILC_HASH_SIM_INIT));
690 SILC_LOG_DEBUG(("init=%p", hash.init));
692 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
693 SILC_HASH_SIM_UPDATE));
694 SILC_LOG_DEBUG(("update=%p", hash.update));
696 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
697 SILC_HASH_SIM_FINAL));
698 SILC_LOG_DEBUG(("final=%p", hash.final));
700 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
701 SILC_HASH_SIM_CONTEXT_LEN));
702 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
704 /* Put the SIM to the table of all SIM's in client */
705 app->sim = silc_realloc(app->sim,
707 (app->sim_count + 1));
708 app->sim[app->sim_count] = sim;
711 SILC_LOG_ERROR(("Error configuring hash functions"));
712 silc_client_stop(client);
716 /* Register the cipher */
717 silc_hash_register(&hash);
726 SilcClientConfigSectionConnection *
727 silc_client_config_find_connection(SilcClientConfig config,
728 char *host, int port)
731 SilcClientConfigSectionConnection *conn = NULL;
733 SILC_LOG_DEBUG(("Finding connection"));
741 conn = config->conns;
742 for (i = 0; conn; i++) {
743 if (silc_string_compare(conn->host, host))
751 SILC_LOG_DEBUG(("Found match"));