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, 1 },
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);
333 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
335 if (!config->hash_func) {
336 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
337 config->hash_func->next = NULL;
338 config->hash_func->prev = NULL;
340 if (!config->hash_func->next) {
341 config->hash_func->next =
342 silc_calloc(1, sizeof(*config->hash_func->next));
343 config->hash_func->next->next = NULL;
344 config->hash_func->next->prev = config->hash_func;
345 config->hash_func = config->hash_func->next;
349 /* Get Hash function name */
350 ret = silc_config_get_token(line, &config->hash_func->alg_name);
354 fprintf(stderr, "%s:%d: Hash function name not defined\n",
355 config->filename, pc->linenum);
359 /* Get Hash function module name */
360 config->hash_func->sim_name = NULL;
361 ret = silc_config_get_token(line, &config->hash_func->sim_name);
365 /* Get block length */
366 ret = silc_config_get_token(line, &tmp);
370 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
371 config->filename, pc->linenum);
374 config->hash_func->block_len = atoi(tmp);
377 /* Get hash length */
378 ret = silc_config_get_token(line, &tmp);
382 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
383 config->filename, pc->linenum);
386 config->hash_func->key_len = atoi(tmp);
392 case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
395 config->hmac = silc_calloc(1, sizeof(*config->hmac));
396 config->hmac->next = NULL;
397 config->hmac->prev = NULL;
399 if (!config->hmac->next) {
401 silc_calloc(1, sizeof(*config->hmac->next));
402 config->hmac->next->next = NULL;
403 config->hmac->next->prev = config->hmac;
404 config->hmac = config->hmac->next;
409 ret = silc_config_get_token(line, &config->hmac->alg_name);
413 fprintf(stderr, "%s:%d: HMAC name not defined\n",
414 config->filename, pc->linenum);
418 /* Get Hash function name */
419 ret = silc_config_get_token(line, &config->hmac->sim_name);
423 fprintf(stderr, "%s:%d: Hash function name not defined\n",
424 config->filename, pc->linenum);
429 ret = silc_config_get_token(line, &tmp);
433 fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
434 config->filename, pc->linenum);
437 config->hmac->key_len = atoi(tmp);
443 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
445 if (!config->conns) {
446 config->conns = silc_calloc(1, sizeof(*config->conns));
447 config->conns->next = NULL;
448 config->conns->prev = NULL;
450 if (!config->conns->next) {
451 config->conns->next = silc_calloc(1, sizeof(*config->conns));
452 config->conns->next->next = NULL;
453 config->conns->next->prev = config->conns;
454 config->conns = config->conns->next;
459 ret = silc_config_get_token(line, &config->conns->host);
464 config->conns->host = strdup("*");
466 /* Get authentication method */
467 ret = silc_config_get_token(line, &tmp);
471 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
472 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
473 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
474 config->filename, pc->linenum, tmp);
478 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
479 config->conns->auth_meth = SILC_AUTH_PASSWORD;
481 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
482 config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
487 /* Get authentication data */
488 ret = silc_config_get_token(line, &config->conns->auth_data);
493 ret = silc_config_get_token(line, &tmp);
497 config->conns->port = atoi(tmp);
504 case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
506 if (!config->commands) {
507 config->commands = silc_calloc(1, sizeof(*config->commands));
508 config->commands->next = NULL;
509 config->commands->prev = NULL;
511 if (!config->commands->next) {
512 config->commands->next = silc_calloc(1, sizeof(*config->commands));
513 config->commands->next->next = NULL;
514 config->commands->next->prev = config->commands;
515 config->commands = config->commands->next;
519 /* Get command line (this may include parameters as well. They
520 will be parsed later with standard command parser when
521 executing particular command.) */
522 config->commands->command = silc_calloc(strlen(line->data),
524 memcpy(config->commands->command, line->data, strlen(line->data) - 1);
531 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
536 /* Check for error */
537 if (check == FALSE) {
538 /* Line could not be parsed */
539 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
549 /* Before returning all the lists in the config object must be set
550 to their first values (the last value is first here). */
551 while (config->cipher && config->cipher->prev)
552 config->cipher = config->cipher->prev;
553 while (config->pkcs && config->pkcs->prev)
554 config->pkcs = config->pkcs->prev;
555 while (config->hash_func && config->hash_func->prev)
556 config->hash_func = config->hash_func->prev;
557 while (config->hmac && config->hmac->prev)
558 config->hmac = config->hmac->prev;
559 while (config->conns && config->conns->prev)
560 config->conns = config->conns->prev;
561 while (config->commands && config->commands->prev)
562 config->commands = config->commands->prev;
564 SILC_LOG_DEBUG(("Done"));
569 /* Registers configured ciphers. These can then be allocated by the
570 client when needed. */
572 bool silc_client_config_register_ciphers(SilcClientConfig config)
574 SilcClientConfigSectionAlg *alg;
575 SilcClientInternal app = (SilcClientInternal)config->client;
576 SilcClient client = app->client;
578 SILC_LOG_DEBUG(("Registering configured ciphers"));
583 alg = config->cipher;
586 if (!alg->sim_name) {
587 /* Crypto module is supposed to be built in. Get the pointer to the
588 built in cipher and register it. */
591 for (i = 0; silc_default_ciphers[i].name; i++)
592 if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
593 silc_cipher_register(&silc_default_ciphers[i]);
597 if (!silc_cipher_is_supported(alg->alg_name)) {
598 SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
599 silc_client_stop(client);
605 /* Load (try at least) the crypto SIM module */
606 SilcCipherObject cipher;
610 memset(&cipher, 0, sizeof(cipher));
611 cipher.name = alg->alg_name;
612 cipher.block_len = alg->block_len;
613 cipher.key_len = alg->key_len * 8;
615 sim = silc_sim_alloc();
616 sim->type = SILC_SIM_CIPHER;
617 sim->libname = alg->sim_name;
619 alg_name = strdup(alg->alg_name);
620 if (strchr(alg_name, '-'))
621 *strchr(alg_name, '-') = '\0';
623 if ((silc_sim_load(sim))) {
625 silc_sim_getsym(sim, silc_sim_symname(alg_name,
626 SILC_CIPHER_SIM_SET_KEY));
627 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
628 cipher.set_key_with_string =
629 silc_sim_getsym(sim, silc_sim_symname(alg_name,
630 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
631 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
633 silc_sim_getsym(sim, silc_sim_symname(alg_name,
634 SILC_CIPHER_SIM_ENCRYPT_CBC));
635 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
637 silc_sim_getsym(sim, silc_sim_symname(alg_name,
638 SILC_CIPHER_SIM_DECRYPT_CBC));
639 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
641 silc_sim_getsym(sim, silc_sim_symname(alg_name,
642 SILC_CIPHER_SIM_CONTEXT_LEN));
643 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
645 /* Put the SIM to the table of all SIM's in client */
646 app->sim = silc_realloc(app->sim,
648 (app->sim_count + 1));
649 app->sim[app->sim_count] = sim;
654 SILC_LOG_ERROR(("Error configuring ciphers"));
655 silc_client_stop(client);
659 /* Register the cipher */
660 silc_cipher_register(&cipher);
670 /* Registers configured PKCS's. */
672 bool silc_client_config_register_pkcs(SilcClientConfig config)
674 SilcClientConfigSectionAlg *alg = config->pkcs;
675 SilcClientInternal app = (SilcClientInternal)config->client;
676 SilcClient client = app->client;
678 SILC_LOG_DEBUG(("Registering configured PKCS"));
686 for (i = 0; silc_default_pkcs[i].name; i++)
687 if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
688 silc_pkcs_register(&silc_default_pkcs[i]);
692 if (!silc_pkcs_is_supported(alg->alg_name)) {
693 SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
694 silc_client_stop(client);
704 /* Registers configured hash funtions. These can then be allocated by the
705 client when needed. */
707 bool silc_client_config_register_hashfuncs(SilcClientConfig config)
709 SilcClientConfigSectionAlg *alg;
710 SilcClientInternal app = (SilcClientInternal)config->client;
711 SilcClient client = app->client;
713 SILC_LOG_DEBUG(("Registering configured hash functions"));
715 if (!config->hash_func)
718 alg = config->hash_func;
720 if (!alg->sim_name) {
723 for (i = 0; silc_default_hash[i].name; i++)
724 if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
725 silc_hash_register(&silc_default_hash[i]);
729 if (!silc_hash_is_supported(alg->alg_name)) {
730 SILC_LOG_ERROR(("Unknown hash function `%s'", alg->alg_name));
731 silc_client_stop(client);
736 /* Load (try at least) the hash SIM module */
740 memset(&hash, 0, sizeof(hash));
741 hash.name = alg->alg_name;
742 hash.block_len = alg->block_len;
743 hash.hash_len = alg->key_len;
745 sim = silc_sim_alloc();
746 sim->type = SILC_SIM_HASH;
747 sim->libname = alg->sim_name;
749 if ((silc_sim_load(sim))) {
751 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
752 SILC_HASH_SIM_INIT));
753 SILC_LOG_DEBUG(("init=%p", hash.init));
755 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
756 SILC_HASH_SIM_UPDATE));
757 SILC_LOG_DEBUG(("update=%p", hash.update));
759 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
760 SILC_HASH_SIM_FINAL));
761 SILC_LOG_DEBUG(("final=%p", hash.final));
763 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
764 SILC_HASH_SIM_CONTEXT_LEN));
765 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
767 /* Put the SIM to the table of all SIM's in client */
768 app->sim = silc_realloc(app->sim,
770 (app->sim_count + 1));
771 app->sim[app->sim_count] = sim;
774 SILC_LOG_ERROR(("Error configuring hash functions"));
775 silc_client_stop(client);
779 /* Register the hash function */
780 silc_hash_register(&hash);
789 /* Registers configured HMACs. These can then be allocated by the
790 client when needed. */
792 bool silc_client_config_register_hmacs(SilcClientConfig config)
794 SilcClientConfigSectionAlg *alg;
795 SilcClientInternal app = (SilcClientInternal)config->client;
796 SilcClient client = app->client;
798 SILC_LOG_DEBUG(("Registering configured HMACs"));
807 if (!silc_hash_is_supported(alg->sim_name)) {
808 SILC_LOG_ERROR(("Unknown hash function `%s' for HMAC `%s'",
809 alg->sim_name, alg->alg_name));
810 silc_client_stop(client);
814 /* Register the HMAC */
815 memset(&hmac, 0, sizeof(hmac));
816 hmac.name = alg->alg_name;
817 hmac.len = alg->key_len;
818 silc_hmac_register(&hmac);
826 SilcClientConfigSectionConnection *
827 silc_client_config_find_connection(SilcClientConfig config,
828 char *host, int port)
831 SilcClientConfigSectionConnection *conn = NULL;
833 SILC_LOG_DEBUG(("Finding connection"));
841 conn = config->conns;
842 for (i = 0; conn; i++) {
843 if (silc_string_compare(conn->host, host))
851 SILC_LOG_DEBUG(("Found match"));