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.
23 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
24 * Importet from internal CVS/Added Log headers.
29 #include "clientincludes.h"
30 #include "clientconfig.h"
33 All possible configuration sections for SILC client.
35 SilcClientConfigSection silc_client_config_sections[] = {
37 SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
39 SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 2 },
41 SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
43 SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
45 SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
47 { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
50 /* Allocates a new configuration object, opens configuration file and
51 parses the file. The parsed data is returned to the newly allocated
52 configuration object. */
54 SilcClientConfig silc_client_config_alloc(char *filename)
58 SilcClientConfigParse config_parse;
60 SILC_LOG_DEBUG(("Allocating new configuration object"));
62 new = silc_calloc(1, sizeof(*new));
64 fprintf(stderr, "Could not allocate new configuration object");
68 new->filename = filename;
70 /* Open configuration file and parse it */
73 silc_config_open(filename, &buffer);
76 if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
78 if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
90 /* Free's a configuration object. */
92 void silc_client_config_free(SilcClientConfig config)
100 /* Parses the the buffer and returns the parsed lines into return_config
101 argument. The return_config argument doesn't have to be initialized
102 before calling this. It will be initialized during the parsing. The
103 buffer sent as argument can be safely free'd after this function has
104 succesfully returned. */
106 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
107 SilcClientConfigParse *return_config)
110 unsigned int linenum;
111 char line[1024], *cp;
112 SilcClientConfigSection *cptr = NULL;
113 SilcClientConfigParse parse = *return_config, first = NULL;
115 SILC_LOG_DEBUG(("Parsing configuration file"));
119 while((begin = silc_gets(line, sizeof(line),
120 buffer->data, buffer->len, begin)) != EOF) {
124 /* Check for bad line */
125 if (silc_check_line(cp))
128 /* Remove tabs and whitespaces from the line */
129 if (strchr(cp, '\t')) {
131 while(strchr(cp + i, '\t')) {
132 *strchr(cp + i, '\t') = ' ';
136 for (i = 0; i < strlen(cp); i++) {
152 /* Remove new line sign */
153 if (strchr(cp, '\n'))
154 *strchr(cp, '\n') = '\0';
156 /* Check for matching sections */
157 for (cptr = silc_client_config_sections; cptr->section; cptr++)
158 if (!strcmp(cp, cptr->section))
161 if (!cptr->section) {
162 fprintf(stderr, "%s:%d: Unknown section `%s'\n",
163 config->filename, linenum, cp);
170 * Start of a configuration line
173 /* Handle config section */
174 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
176 if (strchr(cp, '\n'))
177 *strchr(cp, '\n') = ':';
180 parse = silc_calloc(1, sizeof(*parse));
182 parse->section = NULL;
186 if (parse->next == NULL) {
187 parse->next = silc_calloc(1, sizeof(*parse->next));
188 parse->next->line = NULL;
189 parse->next->section = NULL;
190 parse->next->next = NULL;
191 parse->next->prev = parse;
199 /* Add the line to parsing structure for further parsing. */
201 parse->section = cptr;
202 parse->line = silc_buffer_alloc(strlen(cp) + 1);
203 parse->linenum = linenum;
204 silc_buffer_pull_tail(parse->line, strlen(cp));
205 silc_buffer_put(parse->line, cp, strlen(cp));
212 /* Set the return_config argument to its first value so that further
213 parsing can be started from the first line. */
214 *return_config = first;
219 /* Parses the lines earlier read from configuration file. The config object
220 must not be initialized, it will be initialized in this function. The
221 parse_config argument is uninitialized automatically during this
224 int silc_client_config_parse_lines(SilcClientConfig config,
225 SilcClientConfigParse parse_config)
227 int ret, check = FALSE;
229 SilcClientConfigParse pc = parse_config;
232 SILC_LOG_DEBUG(("Parsing configuration lines"));
241 /* Get number of tokens in line (command section is handeled
242 specially and has no tokens at all). */
243 ret = silc_config_check_num_token(line);
244 if (ret != pc->section->maxfields &&
245 pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
247 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
248 config->filename, pc->linenum, ret,
249 pc->section->maxfields);
254 switch(pc->section->type) {
255 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
257 if (!config->cipher) {
258 config->cipher = silc_calloc(1, sizeof(*config->cipher));
259 config->cipher->next = NULL;
260 config->cipher->prev = NULL;
262 if (!config->cipher->next) {
263 config->cipher->next =
264 silc_calloc(1, sizeof(*config->cipher->next));
265 config->cipher->next->next = NULL;
266 config->cipher->next->prev = config->cipher;
267 config->cipher = config->cipher->next;
271 /* Get cipher name */
272 ret = silc_config_get_token(line, &config->cipher->alg_name);
276 fprintf(stderr, "%s:%d: Cipher name not defined\n",
277 config->filename, pc->linenum);
281 /* Get module name */
282 config->cipher->sim_name = NULL;
283 ret = silc_config_get_token(line, &config->cipher->sim_name);
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);
300 ret = silc_config_get_token(line, &tmp);
304 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
305 config->filename, pc->linenum);
308 config->cipher->key_len = atoi(tmp);
314 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
317 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
318 config->pkcs->next = NULL;
319 config->pkcs->prev = NULL;
321 if (!config->pkcs->next) {
323 silc_calloc(1, sizeof(*config->pkcs->next));
324 config->pkcs->next->next = NULL;
325 config->pkcs->next->prev = config->pkcs;
326 config->pkcs = config->pkcs->next;
331 ret = silc_config_get_token(line, &config->pkcs->alg_name);
335 fprintf(stderr, "%s:%d: PKCS name not defined\n",
336 config->filename, pc->linenum);
341 ret = silc_config_get_token(line, &tmp);
345 fprintf(stderr, "%s:%d: PKCS key length not defined\n",
346 config->filename, pc->linenum);
349 config->pkcs->key_len = atoi(tmp);
355 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
357 if (!config->hash_func) {
358 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
359 config->hash_func->next = NULL;
360 config->hash_func->prev = NULL;
362 if (!config->hash_func->next) {
363 config->hash_func->next =
364 silc_calloc(1, sizeof(*config->hash_func->next));
365 config->hash_func->next->next = NULL;
366 config->hash_func->next->prev = config->hash_func;
367 config->hash_func = config->hash_func->next;
371 /* Get Hash function name */
372 ret = silc_config_get_token(line, &config->hash_func->alg_name);
376 fprintf(stderr, "%s:%d: Hash function name not defined\n",
377 config->filename, pc->linenum);
381 /* Get Hash function module name */
382 config->hash_func->sim_name = NULL;
383 ret = silc_config_get_token(line, &config->hash_func->sim_name);
387 /* Get block length */
388 ret = silc_config_get_token(line, &tmp);
392 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
393 config->filename, pc->linenum);
396 config->hash_func->block_len = atoi(tmp);
399 /* Get hash length */
400 ret = silc_config_get_token(line, &tmp);
404 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
405 config->filename, pc->linenum);
408 config->hash_func->key_len = atoi(tmp);
414 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
416 if (!config->conns) {
417 config->conns = silc_calloc(1, sizeof(*config->conns));
418 config->conns->next = NULL;
419 config->conns->prev = NULL;
421 if (!config->conns->next) {
422 config->conns->next = silc_calloc(1, sizeof(*config->conns));
423 config->conns->next->next = NULL;
424 config->conns->next->prev = config->conns;
425 config->conns = config->conns->next;
430 ret = silc_config_get_token(line, &config->conns->host);
435 config->conns->host = strdup("*");
437 /* Get authentication method */
438 ret = silc_config_get_token(line, &tmp);
442 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
443 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
444 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
445 config->filename, pc->linenum, tmp);
449 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
450 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
452 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
453 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
458 /* Get authentication data */
459 ret = silc_config_get_token(line, &config->conns->auth_data);
464 ret = silc_config_get_token(line, &tmp);
468 config->conns->port = atoi(tmp);
475 case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
477 if (!config->commands) {
478 config->commands = silc_calloc(1, sizeof(*config->commands));
479 config->commands->next = NULL;
480 config->commands->prev = NULL;
482 if (!config->commands->next) {
483 config->commands->next = silc_calloc(1, sizeof(*config->commands));
484 config->commands->next->next = NULL;
485 config->commands->next->prev = config->commands;
486 config->commands = config->commands->next;
490 /* Get command line (this may include parameters as well. They
491 will be parsed later with standard command parser when
492 executing particular command.) */
493 config->commands->command = strdup(line->data);
500 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
505 /* Check for error */
506 if (check == FALSE) {
507 /* Line could not be parsed */
508 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
518 /* Before returning all the lists in the config object must be set
519 to their first values (the last value is first here). */
520 while (config->cipher && config->cipher->prev)
521 config->cipher = config->cipher->prev;
522 while (config->pkcs && config->pkcs->prev)
523 config->pkcs = config->pkcs->prev;
524 while (config->hash_func && config->hash_func->prev)
525 config->hash_func = config->hash_func->prev;
526 while (config->conns && config->conns->prev)
527 config->conns = config->conns->prev;
528 while (config->commands && config->commands->prev)
529 config->commands = config->commands->prev;
531 SILC_LOG_DEBUG(("Done"));
536 /* Registers configured ciphers. These can then be allocated by the
537 client when needed. */
539 void silc_client_config_register_ciphers(SilcClientConfig config)
541 SilcClientConfigSectionAlg *alg;
542 SilcClient client = (SilcClient)config->client;
544 SILC_LOG_DEBUG(("Registering configured ciphers"));
546 alg = config->cipher;
549 if (!alg->sim_name) {
550 /* Crypto module is supposed to be built in. Nothing to be done
551 here except to test that the cipher really is built in. */
552 SilcCipher tmp = NULL;
554 if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
555 SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
556 silc_client_stop(client);
559 silc_cipher_free(tmp);
563 /* Load (try at least) the crypto SIM module */
564 SilcCipherObject cipher;
567 memset(&cipher, 0, sizeof(cipher));
568 cipher.name = alg->alg_name;
569 cipher.block_len = alg->block_len;
570 cipher.key_len = alg->key_len * 8;
572 sim = silc_sim_alloc();
573 sim->type = SILC_SIM_CIPHER;
574 sim->libname = alg->sim_name;
576 if ((silc_sim_load(sim))) {
578 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
579 SILC_CIPHER_SIM_SET_KEY));
580 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
581 cipher.set_key_with_string =
582 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
583 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
584 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
586 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
587 SILC_CIPHER_SIM_ENCRYPT_CBC));
588 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
590 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
591 SILC_CIPHER_SIM_DECRYPT_CBC));
592 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
594 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
595 SILC_CIPHER_SIM_CONTEXT_LEN));
596 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
598 /* Put the SIM to the table of all SIM's in client */
599 client->sim = silc_realloc(client->sim,
600 sizeof(*client->sim) *
601 (client->sim_count + 1));
602 client->sim[client->sim_count] = sim;
605 SILC_LOG_ERROR(("Error configuring ciphers"));
606 silc_client_stop(client);
610 /* Register the cipher */
611 silc_cipher_register(&cipher);
619 /* Registers configured PKCS's. */
620 /* XXX: This really doesn't do anything now since we have statically
621 registered our PKCS's. This should be implemented when PKCS works
622 as SIM's. This checks now only that the PKCS user requested is
625 void silc_client_config_register_pkcs(SilcClientConfig config)
627 SilcClientConfigSectionAlg *alg = config->pkcs;
628 SilcClient client = (SilcClient)config->client;
631 SILC_LOG_DEBUG(("Registering configured PKCS"));
635 if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
636 SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
637 silc_client_stop(client);
646 /* Registers configured hash functions. These can then be allocated by the
647 client when needed. */
649 void silc_client_config_register_hashfuncs(SilcClientConfig config)
651 SilcClientConfigSectionAlg *alg;
652 SilcClient client = (SilcClient)config->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 client->sim = silc_realloc(client->sim,
706 sizeof(*client->sim) *
707 (client->sim_count + 1));
708 client->sim[client->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"));