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.2 2000/07/03 05:49:11 priikone
24 * Remove ':' from the end of line when in commands section. Command
25 * execution should work now from config file ok.
27 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
28 * Importet from internal CVS/Added Log headers.
33 #include "clientincludes.h"
34 #include "clientconfig.h"
37 All possible configuration sections for SILC client.
39 SilcClientConfigSection silc_client_config_sections[] = {
41 SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
43 SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 2 },
45 SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
47 SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
49 SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
51 { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
54 /* Allocates a new configuration object, opens configuration file and
55 parses the file. The parsed data is returned to the newly allocated
56 configuration object. */
58 SilcClientConfig silc_client_config_alloc(char *filename)
62 SilcClientConfigParse config_parse;
64 SILC_LOG_DEBUG(("Allocating new configuration object"));
66 new = silc_calloc(1, sizeof(*new));
68 fprintf(stderr, "Could not allocate new configuration object");
72 new->filename = filename;
74 /* Open configuration file and parse it */
77 silc_config_open(filename, &buffer);
80 if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
82 if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
94 /* Free's a configuration object. */
96 void silc_client_config_free(SilcClientConfig config)
104 /* Parses the the buffer and returns the parsed lines into return_config
105 argument. The return_config argument doesn't have to be initialized
106 before calling this. It will be initialized during the parsing. The
107 buffer sent as argument can be safely free'd after this function has
108 succesfully returned. */
110 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
111 SilcClientConfigParse *return_config)
114 unsigned int linenum;
115 char line[1024], *cp;
116 SilcClientConfigSection *cptr = NULL;
117 SilcClientConfigParse parse = *return_config, first = NULL;
119 SILC_LOG_DEBUG(("Parsing configuration file"));
123 while((begin = silc_gets(line, sizeof(line),
124 buffer->data, buffer->len, begin)) != EOF) {
128 /* Check for bad line */
129 if (silc_check_line(cp))
132 /* Remove tabs and whitespaces from the line */
133 if (strchr(cp, '\t')) {
135 while(strchr(cp + i, '\t')) {
136 *strchr(cp + i, '\t') = ' ';
140 for (i = 0; i < strlen(cp); i++) {
156 /* Remove new line sign */
157 if (strchr(cp, '\n'))
158 *strchr(cp, '\n') = '\0';
160 /* Check for matching sections */
161 for (cptr = silc_client_config_sections; cptr->section; cptr++)
162 if (!strcmp(cp, cptr->section))
165 if (!cptr->section) {
166 fprintf(stderr, "%s:%d: Unknown section `%s'\n",
167 config->filename, linenum, cp);
174 * Start of a configuration line
177 /* Handle config section */
178 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
180 if (strchr(cp, '\n'))
181 *strchr(cp, '\n') = ':';
184 parse = silc_calloc(1, sizeof(*parse));
186 parse->section = NULL;
190 if (parse->next == NULL) {
191 parse->next = silc_calloc(1, sizeof(*parse->next));
192 parse->next->line = NULL;
193 parse->next->section = NULL;
194 parse->next->next = NULL;
195 parse->next->prev = parse;
203 /* Add the line to parsing structure for further parsing. */
205 parse->section = cptr;
206 parse->line = silc_buffer_alloc(strlen(cp) + 1);
207 parse->linenum = linenum;
208 silc_buffer_pull_tail(parse->line, strlen(cp));
209 silc_buffer_put(parse->line, cp, strlen(cp));
216 /* Set the return_config argument to its first value so that further
217 parsing can be started from the first line. */
218 *return_config = first;
223 /* Parses the lines earlier read from configuration file. The config object
224 must not be initialized, it will be initialized in this function. The
225 parse_config argument is uninitialized automatically during this
228 int silc_client_config_parse_lines(SilcClientConfig config,
229 SilcClientConfigParse parse_config)
231 int ret, check = FALSE;
233 SilcClientConfigParse pc = parse_config;
236 SILC_LOG_DEBUG(("Parsing configuration lines"));
245 /* Get number of tokens in line (command section is handeled
246 specially and has no tokens at all). */
247 ret = silc_config_check_num_token(line);
248 if (ret != pc->section->maxfields &&
249 pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
251 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
252 config->filename, pc->linenum, ret,
253 pc->section->maxfields);
258 switch(pc->section->type) {
259 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
261 if (!config->cipher) {
262 config->cipher = silc_calloc(1, sizeof(*config->cipher));
263 config->cipher->next = NULL;
264 config->cipher->prev = NULL;
266 if (!config->cipher->next) {
267 config->cipher->next =
268 silc_calloc(1, sizeof(*config->cipher->next));
269 config->cipher->next->next = NULL;
270 config->cipher->next->prev = config->cipher;
271 config->cipher = config->cipher->next;
275 /* Get cipher name */
276 ret = silc_config_get_token(line, &config->cipher->alg_name);
280 fprintf(stderr, "%s:%d: Cipher name not defined\n",
281 config->filename, pc->linenum);
285 /* Get module name */
286 config->cipher->sim_name = NULL;
287 ret = silc_config_get_token(line, &config->cipher->sim_name);
291 /* Get block length */
292 ret = silc_config_get_token(line, &tmp);
296 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
297 config->filename, pc->linenum);
300 config->cipher->block_len = atoi(tmp);
304 ret = silc_config_get_token(line, &tmp);
308 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
309 config->filename, pc->linenum);
312 config->cipher->key_len = atoi(tmp);
318 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
321 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
322 config->pkcs->next = NULL;
323 config->pkcs->prev = NULL;
325 if (!config->pkcs->next) {
327 silc_calloc(1, sizeof(*config->pkcs->next));
328 config->pkcs->next->next = NULL;
329 config->pkcs->next->prev = config->pkcs;
330 config->pkcs = config->pkcs->next;
335 ret = silc_config_get_token(line, &config->pkcs->alg_name);
339 fprintf(stderr, "%s:%d: PKCS name not defined\n",
340 config->filename, pc->linenum);
345 ret = silc_config_get_token(line, &tmp);
349 fprintf(stderr, "%s:%d: PKCS key length not defined\n",
350 config->filename, pc->linenum);
353 config->pkcs->key_len = atoi(tmp);
359 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
361 if (!config->hash_func) {
362 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
363 config->hash_func->next = NULL;
364 config->hash_func->prev = NULL;
366 if (!config->hash_func->next) {
367 config->hash_func->next =
368 silc_calloc(1, sizeof(*config->hash_func->next));
369 config->hash_func->next->next = NULL;
370 config->hash_func->next->prev = config->hash_func;
371 config->hash_func = config->hash_func->next;
375 /* Get Hash function name */
376 ret = silc_config_get_token(line, &config->hash_func->alg_name);
380 fprintf(stderr, "%s:%d: Hash function name not defined\n",
381 config->filename, pc->linenum);
385 /* Get Hash function module name */
386 config->hash_func->sim_name = NULL;
387 ret = silc_config_get_token(line, &config->hash_func->sim_name);
391 /* Get block length */
392 ret = silc_config_get_token(line, &tmp);
396 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
397 config->filename, pc->linenum);
400 config->hash_func->block_len = atoi(tmp);
403 /* Get hash length */
404 ret = silc_config_get_token(line, &tmp);
408 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
409 config->filename, pc->linenum);
412 config->hash_func->key_len = atoi(tmp);
418 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
420 if (!config->conns) {
421 config->conns = silc_calloc(1, sizeof(*config->conns));
422 config->conns->next = NULL;
423 config->conns->prev = NULL;
425 if (!config->conns->next) {
426 config->conns->next = silc_calloc(1, sizeof(*config->conns));
427 config->conns->next->next = NULL;
428 config->conns->next->prev = config->conns;
429 config->conns = config->conns->next;
434 ret = silc_config_get_token(line, &config->conns->host);
439 config->conns->host = strdup("*");
441 /* Get authentication method */
442 ret = silc_config_get_token(line, &tmp);
446 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
447 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
448 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
449 config->filename, pc->linenum, tmp);
453 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
454 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
456 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
457 config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
462 /* Get authentication data */
463 ret = silc_config_get_token(line, &config->conns->auth_data);
468 ret = silc_config_get_token(line, &tmp);
472 config->conns->port = atoi(tmp);
479 case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
481 if (!config->commands) {
482 config->commands = silc_calloc(1, sizeof(*config->commands));
483 config->commands->next = NULL;
484 config->commands->prev = NULL;
486 if (!config->commands->next) {
487 config->commands->next = silc_calloc(1, sizeof(*config->commands));
488 config->commands->next->next = NULL;
489 config->commands->next->prev = config->commands;
490 config->commands = config->commands->next;
494 /* Get command line (this may include parameters as well. They
495 will be parsed later with standard command parser when
496 executing particular command.) */
497 config->commands->command = silc_calloc(strlen(line->data),
499 memcpy(config->commands->command, line->data, strlen(line->data) - 1);
506 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
511 /* Check for error */
512 if (check == FALSE) {
513 /* Line could not be parsed */
514 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
524 /* Before returning all the lists in the config object must be set
525 to their first values (the last value is first here). */
526 while (config->cipher && config->cipher->prev)
527 config->cipher = config->cipher->prev;
528 while (config->pkcs && config->pkcs->prev)
529 config->pkcs = config->pkcs->prev;
530 while (config->hash_func && config->hash_func->prev)
531 config->hash_func = config->hash_func->prev;
532 while (config->conns && config->conns->prev)
533 config->conns = config->conns->prev;
534 while (config->commands && config->commands->prev)
535 config->commands = config->commands->prev;
537 SILC_LOG_DEBUG(("Done"));
542 /* Registers configured ciphers. These can then be allocated by the
543 client when needed. */
545 void silc_client_config_register_ciphers(SilcClientConfig config)
547 SilcClientConfigSectionAlg *alg;
548 SilcClient client = (SilcClient)config->client;
550 SILC_LOG_DEBUG(("Registering configured ciphers"));
552 alg = config->cipher;
555 if (!alg->sim_name) {
556 /* Crypto module is supposed to be built in. Nothing to be done
557 here except to test that the cipher really is built in. */
558 SilcCipher tmp = NULL;
560 if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
561 SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
562 silc_client_stop(client);
565 silc_cipher_free(tmp);
569 /* Load (try at least) the crypto SIM module */
570 SilcCipherObject cipher;
573 memset(&cipher, 0, sizeof(cipher));
574 cipher.name = alg->alg_name;
575 cipher.block_len = alg->block_len;
576 cipher.key_len = alg->key_len * 8;
578 sim = silc_sim_alloc();
579 sim->type = SILC_SIM_CIPHER;
580 sim->libname = alg->sim_name;
582 if ((silc_sim_load(sim))) {
584 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
585 SILC_CIPHER_SIM_SET_KEY));
586 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
587 cipher.set_key_with_string =
588 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
589 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
590 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
592 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
593 SILC_CIPHER_SIM_ENCRYPT_CBC));
594 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
596 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
597 SILC_CIPHER_SIM_DECRYPT_CBC));
598 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
600 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
601 SILC_CIPHER_SIM_CONTEXT_LEN));
602 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
604 /* Put the SIM to the table of all SIM's in client */
605 client->sim = silc_realloc(client->sim,
606 sizeof(*client->sim) *
607 (client->sim_count + 1));
608 client->sim[client->sim_count] = sim;
611 SILC_LOG_ERROR(("Error configuring ciphers"));
612 silc_client_stop(client);
616 /* Register the cipher */
617 silc_cipher_register(&cipher);
625 /* Registers configured PKCS's. */
626 /* XXX: This really doesn't do anything now since we have statically
627 registered our PKCS's. This should be implemented when PKCS works
628 as SIM's. This checks now only that the PKCS user requested is
631 void silc_client_config_register_pkcs(SilcClientConfig config)
633 SilcClientConfigSectionAlg *alg = config->pkcs;
634 SilcClient client = (SilcClient)config->client;
637 SILC_LOG_DEBUG(("Registering configured PKCS"));
641 if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
642 SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
643 silc_client_stop(client);
652 /* Registers configured hash functions. These can then be allocated by the
653 client when needed. */
655 void silc_client_config_register_hashfuncs(SilcClientConfig config)
657 SilcClientConfigSectionAlg *alg;
658 SilcClient client = (SilcClient)config->client;
660 SILC_LOG_DEBUG(("Registering configured hash functions"));
662 alg = config->hash_func;
665 if (!alg->sim_name) {
666 /* Hash module is supposed to be built in. Nothing to be done
667 here except to test that the hash function really is built in. */
670 if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
671 SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
672 silc_client_stop(client);
679 /* Load (try at least) the hash SIM module */
683 memset(&hash, 0, sizeof(hash));
684 hash.name = alg->alg_name;
685 hash.block_len = alg->block_len;
686 hash.hash_len = alg->key_len;
688 sim = silc_sim_alloc();
689 sim->type = SILC_SIM_HASH;
690 sim->libname = alg->sim_name;
692 if ((silc_sim_load(sim))) {
694 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
695 SILC_HASH_SIM_INIT));
696 SILC_LOG_DEBUG(("init=%p", hash.init));
698 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
699 SILC_HASH_SIM_UPDATE));
700 SILC_LOG_DEBUG(("update=%p", hash.update));
702 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
703 SILC_HASH_SIM_FINAL));
704 SILC_LOG_DEBUG(("final=%p", hash.final));
706 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
707 SILC_HASH_SIM_CONTEXT_LEN));
708 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
710 /* Put the SIM to the table of all SIM's in client */
711 client->sim = silc_realloc(client->sim,
712 sizeof(*client->sim) *
713 (client->sim_count + 1));
714 client->sim[client->sim_count] = sim;
717 SILC_LOG_ERROR(("Error configuring hash functions"));
718 silc_client_stop(client);
722 /* Register the cipher */
723 silc_hash_register(&hash);
732 SilcClientConfigSectionConnection *
733 silc_client_config_find_connection(SilcClientConfig config,
734 char *host, int port)
737 SilcClientConfigSectionConnection *conn = NULL;
739 SILC_LOG_DEBUG(("Finding connection"));
747 conn = config->conns;
748 for (i = 0; conn; i++) {
749 if (silc_string_compare(conn->host, host))
757 SILC_LOG_DEBUG(("Found match"));