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.
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
35 #include "servers-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "window-item-def.h"
42 #include "fe-common/core/printtext.h"
45 All possible configuration sections for SILC client.
47 SilcClientConfigSection silc_client_config_sections[] = {
49 SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
51 SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 1 },
53 SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
55 SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC, 3 },
57 SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
59 { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
62 /* Allocates a new configuration object, opens configuration file and
63 parses the file. The parsed data is returned to the newly allocated
64 configuration object. */
66 SilcClientConfig silc_client_config_alloc(char *filename)
70 SilcClientConfigParse config_parse;
73 SILC_LOG_DEBUG(("Allocating new configuration object"));
75 new = silc_calloc(1, sizeof(*new));
76 new->filename = filename;
78 /* Open configuration file and parse it */
81 str = convert_home(filename);
82 silc_config_open(str, &buffer);
86 if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
88 if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
100 /* Free's a configuration object. */
102 void silc_client_config_free(SilcClientConfig config)
110 /* Parses the the buffer and returns the parsed lines into return_config
111 argument. The return_config argument doesn't have to be initialized
112 before calling this. It will be initialized during the parsing. The
113 buffer sent as argument can be safely free'd after this function has
114 succesfully returned. */
116 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
117 SilcClientConfigParse *return_config)
121 char line[1024], *cp;
122 SilcClientConfigSection *cptr = NULL;
123 SilcClientConfigParse parse = *return_config, first = NULL;
125 SILC_LOG_DEBUG(("Parsing configuration file"));
129 while((begin = silc_gets(line, sizeof(line),
130 buffer->data, buffer->len, begin)) != EOF) {
134 /* Check for bad line */
135 if (silc_check_line(cp))
138 /* Remove tabs and whitespaces from the line */
139 if (strchr(cp, '\t')) {
141 while(strchr(cp + i, '\t')) {
142 *strchr(cp + i, '\t') = ' ';
146 for (i = 0; i < strlen(cp); i++) {
162 /* Remove new line sign */
163 if (strchr(cp, '\n'))
164 *strchr(cp, '\n') = '\0';
166 /* Check for matching sections */
167 for (cptr = silc_client_config_sections; cptr->section; cptr++)
168 if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
171 if (!cptr->section) {
172 fprintf(stderr, "%s:%d: Unknown section `%s'\n",
173 config->filename, linenum, cp);
180 * Start of a configuration line
183 /* Handle config section */
184 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
186 if (strchr(cp, '\n'))
187 *strchr(cp, '\n') = ':';
190 parse = silc_calloc(1, sizeof(*parse));
192 parse->section = NULL;
196 if (parse->next == NULL) {
197 parse->next = silc_calloc(1, sizeof(*parse->next));
198 parse->next->line = NULL;
199 parse->next->section = NULL;
200 parse->next->next = NULL;
201 parse->next->prev = parse;
209 /* Add the line to parsing structure for further parsing. */
211 parse->section = cptr;
212 parse->line = silc_buffer_alloc(strlen(cp) + 1);
213 parse->linenum = linenum;
214 silc_buffer_pull_tail(parse->line, strlen(cp));
215 silc_buffer_put(parse->line, cp, strlen(cp));
222 /* Set the return_config argument to its first value so that further
223 parsing can be started from the first line. */
224 *return_config = first;
229 /* Parses the lines earlier read from configuration file. The config object
230 must not be initialized, it will be initialized in this function. The
231 parse_config argument is uninitialized automatically during this
234 int silc_client_config_parse_lines(SilcClientConfig config,
235 SilcClientConfigParse parse_config)
237 int ret, check = FALSE;
239 SilcClientConfigParse pc = parse_config;
242 SILC_LOG_DEBUG(("Parsing configuration lines"));
251 /* Get number of tokens in line (command section is handeled
252 specially and has no tokens at all). */
253 ret = silc_config_check_num_token(line);
254 if (ret != pc->section->maxfields) {
256 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
257 config->filename, pc->linenum, ret,
258 pc->section->maxfields);
263 switch(pc->section->type) {
264 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
266 if (!config->cipher) {
267 config->cipher = silc_calloc(1, sizeof(*config->cipher));
268 config->cipher->next = NULL;
269 config->cipher->prev = NULL;
271 if (!config->cipher->next) {
272 config->cipher->next =
273 silc_calloc(1, sizeof(*config->cipher->next));
274 config->cipher->next->next = NULL;
275 config->cipher->next->prev = config->cipher;
276 config->cipher = config->cipher->next;
280 /* Get cipher name */
281 ret = silc_config_get_token(line, &config->cipher->alg_name);
285 fprintf(stderr, "%s:%d: Cipher name not defined\n",
286 config->filename, pc->linenum);
290 /* Get module name */
291 config->cipher->sim_name = NULL;
292 ret = silc_config_get_token(line, &config->cipher->sim_name);
297 ret = silc_config_get_token(line, &tmp);
301 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
302 config->filename, pc->linenum);
305 config->cipher->key_len = atoi(tmp);
308 /* Get block length */
309 ret = silc_config_get_token(line, &tmp);
313 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
314 config->filename, pc->linenum);
317 config->cipher->block_len = atoi(tmp);
323 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
326 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
327 config->pkcs->next = NULL;
328 config->pkcs->prev = NULL;
330 if (!config->pkcs->next) {
332 silc_calloc(1, sizeof(*config->pkcs->next));
333 config->pkcs->next->next = NULL;
334 config->pkcs->next->prev = config->pkcs;
335 config->pkcs = config->pkcs->next;
340 ret = silc_config_get_token(line, &config->pkcs->alg_name);
344 fprintf(stderr, "%s:%d: PKCS name not defined\n",
345 config->filename, pc->linenum);
352 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
354 if (!config->hash_func) {
355 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
356 config->hash_func->next = NULL;
357 config->hash_func->prev = NULL;
359 if (!config->hash_func->next) {
360 config->hash_func->next =
361 silc_calloc(1, sizeof(*config->hash_func->next));
362 config->hash_func->next->next = NULL;
363 config->hash_func->next->prev = config->hash_func;
364 config->hash_func = config->hash_func->next;
368 /* Get Hash function name */
369 ret = silc_config_get_token(line, &config->hash_func->alg_name);
373 fprintf(stderr, "%s:%d: Hash function name not defined\n",
374 config->filename, pc->linenum);
378 /* Get Hash function module name */
379 config->hash_func->sim_name = NULL;
380 ret = silc_config_get_token(line, &config->hash_func->sim_name);
384 /* Get block length */
385 ret = silc_config_get_token(line, &tmp);
389 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
390 config->filename, pc->linenum);
393 config->hash_func->block_len = atoi(tmp);
396 /* Get hash length */
397 ret = silc_config_get_token(line, &tmp);
401 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
402 config->filename, pc->linenum);
405 config->hash_func->key_len = atoi(tmp);
411 case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
414 config->hmac = silc_calloc(1, sizeof(*config->hmac));
415 config->hmac->next = NULL;
416 config->hmac->prev = NULL;
418 if (!config->hmac->next) {
420 silc_calloc(1, sizeof(*config->hmac->next));
421 config->hmac->next->next = NULL;
422 config->hmac->next->prev = config->hmac;
423 config->hmac = config->hmac->next;
428 ret = silc_config_get_token(line, &config->hmac->alg_name);
432 fprintf(stderr, "%s:%d: HMAC name not defined\n",
433 config->filename, pc->linenum);
437 /* Get Hash function name */
438 ret = silc_config_get_token(line, &config->hmac->sim_name);
442 fprintf(stderr, "%s:%d: Hash function name not defined\n",
443 config->filename, pc->linenum);
448 ret = silc_config_get_token(line, &tmp);
452 fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
453 config->filename, pc->linenum);
456 config->hmac->key_len = atoi(tmp);
462 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
464 if (!config->conns) {
465 config->conns = silc_calloc(1, sizeof(*config->conns));
466 config->conns->next = NULL;
467 config->conns->prev = NULL;
469 if (!config->conns->next) {
470 config->conns->next = silc_calloc(1, sizeof(*config->conns));
471 config->conns->next->next = NULL;
472 config->conns->next->prev = config->conns;
473 config->conns = config->conns->next;
478 ret = silc_config_get_token(line, &config->conns->host);
483 config->conns->host = strdup("*");
485 /* Get authentication method */
486 ret = silc_config_get_token(line, &tmp);
490 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
491 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
492 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
493 config->filename, pc->linenum, tmp);
497 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
498 config->conns->auth_meth = SILC_AUTH_PASSWORD;
500 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
501 config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
506 /* Get authentication data */
507 ret = silc_config_get_token(line, &config->conns->auth_data);
512 ret = silc_config_get_token(line, &tmp);
516 config->conns->port = atoi(tmp);
523 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
528 /* Check for error */
529 if (check == FALSE) {
530 /* Line could not be parsed */
531 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
541 /* Before returning all the lists in the config object must be set
542 to their first values (the last value is first here). */
543 while (config->cipher && config->cipher->prev)
544 config->cipher = config->cipher->prev;
545 while (config->pkcs && config->pkcs->prev)
546 config->pkcs = config->pkcs->prev;
547 while (config->hash_func && config->hash_func->prev)
548 config->hash_func = config->hash_func->prev;
549 while (config->hmac && config->hmac->prev)
550 config->hmac = config->hmac->prev;
551 while (config->conns && config->conns->prev)
552 config->conns = config->conns->prev;
554 SILC_LOG_DEBUG(("Done"));
559 /* Registers configured ciphers. These can then be allocated by the
560 client when needed. */
562 bool silc_client_config_register_ciphers(SilcClientConfig config)
564 SilcClientConfigSectionAlg *alg;
565 SilcClient client = config->client;
567 SILC_LOG_DEBUG(("Registering configured ciphers"));
572 alg = config->cipher;
575 if (!alg->sim_name) {
576 /* Crypto module is supposed to be built in. Get the pointer to the
577 built in cipher and register it. */
580 for (i = 0; silc_default_ciphers[i].name; i++)
581 if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
582 silc_cipher_register(&silc_default_ciphers[i]);
586 if (!silc_cipher_is_supported(alg->alg_name)) {
587 SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
588 silc_client_stop(client);
594 /* Load (try at least) the crypto SIM module */
595 SilcCipherObject cipher;
599 memset(&cipher, 0, sizeof(cipher));
600 cipher.name = alg->alg_name;
601 cipher.block_len = alg->block_len;
602 cipher.key_len = alg->key_len * 8;
604 sim = silc_sim_alloc();
605 sim->type = SILC_SIM_CIPHER;
606 sim->libname = alg->sim_name;
608 alg_name = strdup(alg->alg_name);
609 if (strchr(alg_name, '-'))
610 *strchr(alg_name, '-') = '\0';
612 if ((silc_sim_load(sim))) {
614 silc_sim_getsym(sim, silc_sim_symname(alg_name,
615 SILC_CIPHER_SIM_SET_KEY));
616 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
617 cipher.set_key_with_string =
618 silc_sim_getsym(sim, silc_sim_symname(alg_name,
619 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
620 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
622 silc_sim_getsym(sim, silc_sim_symname(alg_name,
623 SILC_CIPHER_SIM_ENCRYPT_CBC));
624 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
626 silc_sim_getsym(sim, silc_sim_symname(alg_name,
627 SILC_CIPHER_SIM_DECRYPT_CBC));
628 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
630 silc_sim_getsym(sim, silc_sim_symname(alg_name,
631 SILC_CIPHER_SIM_CONTEXT_LEN));
632 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
634 /* Put the SIM to the table of all SIM's in client */
635 sims = silc_realloc(sims,
638 sims[sims_count] = sim;
643 SILC_LOG_ERROR(("Error configuring ciphers"));
644 silc_client_stop(client);
648 /* Register the cipher */
649 silc_cipher_register(&cipher);
659 /* Registers configured PKCS's. */
661 bool silc_client_config_register_pkcs(SilcClientConfig config)
663 SilcClientConfigSectionAlg *alg = config->pkcs;
664 SilcClient client = config->client;
666 SILC_LOG_DEBUG(("Registering configured PKCS"));
674 for (i = 0; silc_default_pkcs[i].name; i++)
675 if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
676 silc_pkcs_register(&silc_default_pkcs[i]);
680 if (!silc_pkcs_is_supported(alg->alg_name)) {
681 SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
682 silc_client_stop(client);
692 /* Registers configured hash funtions. These can then be allocated by the
693 client when needed. */
695 bool silc_client_config_register_hashfuncs(SilcClientConfig config)
697 SilcClientConfigSectionAlg *alg;
698 SilcClient client = config->client;
700 SILC_LOG_DEBUG(("Registering configured hash functions"));
702 if (!config->hash_func)
705 alg = config->hash_func;
707 if (!alg->sim_name) {
710 for (i = 0; silc_default_hash[i].name; i++)
711 if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
712 silc_hash_register(&silc_default_hash[i]);
716 if (!silc_hash_is_supported(alg->alg_name)) {
717 SILC_LOG_ERROR(("Unknown hash function `%s'", alg->alg_name));
718 silc_client_stop(client);
723 /* Load (try at least) the hash SIM module */
727 memset(&hash, 0, sizeof(hash));
728 hash.name = alg->alg_name;
729 hash.block_len = alg->block_len;
730 hash.hash_len = alg->key_len;
732 sim = silc_sim_alloc();
733 sim->type = SILC_SIM_HASH;
734 sim->libname = alg->sim_name;
736 if ((silc_sim_load(sim))) {
738 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
739 SILC_HASH_SIM_INIT));
740 SILC_LOG_DEBUG(("init=%p", hash.init));
742 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
743 SILC_HASH_SIM_UPDATE));
744 SILC_LOG_DEBUG(("update=%p", hash.update));
746 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
747 SILC_HASH_SIM_FINAL));
748 SILC_LOG_DEBUG(("final=%p", hash.final));
750 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
751 SILC_HASH_SIM_CONTEXT_LEN));
752 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
754 /* Put the SIM to the table of all SIM's in client */
755 sims = silc_realloc(sims,
758 sims[sims_count] = sim;
761 SILC_LOG_ERROR(("Error configuring hash functions"));
762 silc_client_stop(client);
766 /* Register the hash function */
767 silc_hash_register(&hash);
776 /* Registers configured HMACs. These can then be allocated by the
777 client when needed. */
779 bool silc_client_config_register_hmacs(SilcClientConfig config)
781 SilcClientConfigSectionAlg *alg;
782 SilcClient client = config->client;
784 SILC_LOG_DEBUG(("Registering configured HMACs"));
793 if (!silc_hash_is_supported(alg->sim_name)) {
794 SILC_LOG_ERROR(("Unknown hash function `%s' for HMAC `%s'",
795 alg->sim_name, alg->alg_name));
796 silc_client_stop(client);
800 /* Register the HMAC */
801 memset(&hmac, 0, sizeof(hmac));
802 hmac.name = alg->alg_name;
803 hmac.len = alg->key_len;
804 silc_hmac_register(&hmac);
812 SilcClientConfigSectionConnection *
813 silc_client_config_find_connection(SilcClientConfig config,
814 char *host, int port)
817 SilcClientConfigSectionConnection *conn = NULL;
819 SILC_LOG_DEBUG(("Finding connection"));
827 conn = config->conns;
828 for (i = 0; conn; i++) {
829 if (silc_string_compare(conn->host, host))
837 SILC_LOG_DEBUG(("Found match"));