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
184 fprintf(stderr, "%s:%d: Unknown start of a section `%s'\n",
185 config->filename, linenum, cp);
189 /* Handle config section */
190 if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
192 if (strchr(cp, '\n'))
193 *strchr(cp, '\n') = ':';
196 parse = silc_calloc(1, sizeof(*parse));
198 parse->section = NULL;
202 if (parse->next == NULL) {
203 parse->next = silc_calloc(1, sizeof(*parse->next));
204 parse->next->line = NULL;
205 parse->next->section = NULL;
206 parse->next->next = NULL;
207 parse->next->prev = parse;
215 /* Add the line to parsing structure for further parsing. */
217 parse->section = cptr;
218 parse->line = silc_buffer_alloc(strlen(cp) + 1);
219 parse->linenum = linenum;
220 silc_buffer_pull_tail(parse->line, strlen(cp));
221 silc_buffer_put(parse->line, cp, strlen(cp));
228 /* Set the return_config argument to its first value so that further
229 parsing can be started from the first line. */
230 *return_config = first;
235 /* Parses the lines earlier read from configuration file. The config object
236 must not be initialized, it will be initialized in this function. The
237 parse_config argument is uninitialized automatically during this
240 int silc_client_config_parse_lines(SilcClientConfig config,
241 SilcClientConfigParse parse_config)
243 int ret, check = FALSE;
245 SilcClientConfigParse pc = parse_config;
248 SILC_LOG_DEBUG(("Parsing configuration lines"));
257 /* Get number of tokens in line (command section is handeled
258 specially and has no tokens at all). */
259 ret = silc_config_check_num_token(line);
260 if (ret != pc->section->maxfields) {
262 fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
263 config->filename, pc->linenum, ret,
264 pc->section->maxfields);
269 switch(pc->section->type) {
270 case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
272 if (!config->cipher) {
273 config->cipher = silc_calloc(1, sizeof(*config->cipher));
274 config->cipher->next = NULL;
275 config->cipher->prev = NULL;
277 if (!config->cipher->next) {
278 config->cipher->next =
279 silc_calloc(1, sizeof(*config->cipher->next));
280 config->cipher->next->next = NULL;
281 config->cipher->next->prev = config->cipher;
282 config->cipher = config->cipher->next;
286 /* Get cipher name */
287 ret = silc_config_get_token(line, &config->cipher->alg_name);
291 fprintf(stderr, "%s:%d: Cipher name not defined\n",
292 config->filename, pc->linenum);
296 /* Get module name */
297 config->cipher->sim_name = NULL;
298 ret = silc_config_get_token(line, &config->cipher->sim_name);
303 ret = silc_config_get_token(line, &tmp);
307 fprintf(stderr, "%s:%d: Cipher key length not defined\n",
308 config->filename, pc->linenum);
311 config->cipher->key_len = atoi(tmp);
314 /* Get block length */
315 ret = silc_config_get_token(line, &tmp);
319 fprintf(stderr, "%s:%d: Cipher block length not defined\n",
320 config->filename, pc->linenum);
323 config->cipher->block_len = atoi(tmp);
329 case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
332 config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
333 config->pkcs->next = NULL;
334 config->pkcs->prev = NULL;
336 if (!config->pkcs->next) {
338 silc_calloc(1, sizeof(*config->pkcs->next));
339 config->pkcs->next->next = NULL;
340 config->pkcs->next->prev = config->pkcs;
341 config->pkcs = config->pkcs->next;
346 ret = silc_config_get_token(line, &config->pkcs->alg_name);
350 fprintf(stderr, "%s:%d: PKCS name not defined\n",
351 config->filename, pc->linenum);
358 case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
360 if (!config->hash_func) {
361 config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
362 config->hash_func->next = NULL;
363 config->hash_func->prev = NULL;
365 if (!config->hash_func->next) {
366 config->hash_func->next =
367 silc_calloc(1, sizeof(*config->hash_func->next));
368 config->hash_func->next->next = NULL;
369 config->hash_func->next->prev = config->hash_func;
370 config->hash_func = config->hash_func->next;
374 /* Get Hash function name */
375 ret = silc_config_get_token(line, &config->hash_func->alg_name);
379 fprintf(stderr, "%s:%d: Hash function name not defined\n",
380 config->filename, pc->linenum);
384 /* Get Hash function module name */
385 config->hash_func->sim_name = NULL;
386 ret = silc_config_get_token(line, &config->hash_func->sim_name);
390 /* Get block length */
391 ret = silc_config_get_token(line, &tmp);
395 fprintf(stderr, "%s:%d: Hash function block length not defined\n",
396 config->filename, pc->linenum);
399 config->hash_func->block_len = atoi(tmp);
402 /* Get hash length */
403 ret = silc_config_get_token(line, &tmp);
407 fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
408 config->filename, pc->linenum);
411 config->hash_func->key_len = atoi(tmp);
417 case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
420 config->hmac = silc_calloc(1, sizeof(*config->hmac));
421 config->hmac->next = NULL;
422 config->hmac->prev = NULL;
424 if (!config->hmac->next) {
426 silc_calloc(1, sizeof(*config->hmac->next));
427 config->hmac->next->next = NULL;
428 config->hmac->next->prev = config->hmac;
429 config->hmac = config->hmac->next;
434 ret = silc_config_get_token(line, &config->hmac->alg_name);
438 fprintf(stderr, "%s:%d: HMAC name not defined\n",
439 config->filename, pc->linenum);
443 /* Get Hash function name */
444 ret = silc_config_get_token(line, &config->hmac->sim_name);
448 fprintf(stderr, "%s:%d: Hash function name not defined\n",
449 config->filename, pc->linenum);
454 ret = silc_config_get_token(line, &tmp);
458 fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
459 config->filename, pc->linenum);
462 config->hmac->key_len = atoi(tmp);
468 case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
470 if (!config->conns) {
471 config->conns = silc_calloc(1, sizeof(*config->conns));
472 config->conns->next = NULL;
473 config->conns->prev = NULL;
475 if (!config->conns->next) {
476 config->conns->next = silc_calloc(1, sizeof(*config->conns));
477 config->conns->next->next = NULL;
478 config->conns->next->prev = config->conns;
479 config->conns = config->conns->next;
484 ret = silc_config_get_token(line, &config->conns->host);
489 config->conns->host = strdup("*");
491 /* Get authentication method */
492 ret = silc_config_get_token(line, &tmp);
496 if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
497 strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
498 fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
499 config->filename, pc->linenum, tmp);
503 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
504 config->conns->auth_meth = SILC_AUTH_PASSWORD;
506 if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
507 config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
512 /* Get authentication data */
513 ret = silc_config_get_token(line, &config->conns->auth_data);
518 ret = silc_config_get_token(line, &tmp);
522 config->conns->port = atoi(tmp);
529 case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
534 /* Check for error */
535 if (check == FALSE) {
536 /* Line could not be parsed */
537 fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
547 /* Before returning all the lists in the config object must be set
548 to their first values (the last value is first here). */
549 while (config->cipher && config->cipher->prev)
550 config->cipher = config->cipher->prev;
551 while (config->pkcs && config->pkcs->prev)
552 config->pkcs = config->pkcs->prev;
553 while (config->hash_func && config->hash_func->prev)
554 config->hash_func = config->hash_func->prev;
555 while (config->hmac && config->hmac->prev)
556 config->hmac = config->hmac->prev;
557 while (config->conns && config->conns->prev)
558 config->conns = config->conns->prev;
560 SILC_LOG_DEBUG(("Done"));
565 /* Registers configured ciphers. These can then be allocated by the
566 client when needed. */
568 bool silc_client_config_register_ciphers(SilcClientConfig config)
570 SilcClientConfigSectionAlg *alg;
571 SilcClient client = config->client;
573 SILC_LOG_DEBUG(("Registering configured ciphers"));
578 alg = config->cipher;
581 if (!alg->sim_name) {
582 /* Crypto module is supposed to be built in. Get the pointer to the
583 built in cipher and register it. */
586 for (i = 0; silc_default_ciphers[i].name; i++)
587 if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
588 silc_cipher_register(&silc_default_ciphers[i]);
592 if (!silc_cipher_is_supported(alg->alg_name)) {
593 SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
594 silc_client_stop(client);
600 /* Load (try at least) the crypto SIM module */
601 SilcCipherObject cipher;
605 memset(&cipher, 0, sizeof(cipher));
606 cipher.name = alg->alg_name;
607 cipher.block_len = alg->block_len;
608 cipher.key_len = alg->key_len * 8;
610 sim = silc_sim_alloc();
611 sim->type = SILC_SIM_CIPHER;
612 sim->libname = alg->sim_name;
614 alg_name = strdup(alg->alg_name);
615 if (strchr(alg_name, '-'))
616 *strchr(alg_name, '-') = '\0';
618 if ((silc_sim_load(sim))) {
620 silc_sim_getsym(sim, silc_sim_symname(alg_name,
621 SILC_CIPHER_SIM_SET_KEY));
622 SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
623 cipher.set_key_with_string =
624 silc_sim_getsym(sim, silc_sim_symname(alg_name,
625 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
626 SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
628 silc_sim_getsym(sim, silc_sim_symname(alg_name,
629 SILC_CIPHER_SIM_ENCRYPT_CBC));
630 SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
632 silc_sim_getsym(sim, silc_sim_symname(alg_name,
633 SILC_CIPHER_SIM_DECRYPT_CBC));
634 SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
636 silc_sim_getsym(sim, silc_sim_symname(alg_name,
637 SILC_CIPHER_SIM_CONTEXT_LEN));
638 SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
640 /* Put the SIM to the table of all SIM's in client */
641 sims = silc_realloc(sims,
644 sims[sims_count] = sim;
649 SILC_LOG_ERROR(("Error configuring ciphers"));
650 silc_client_stop(client);
654 /* Register the cipher */
655 silc_cipher_register(&cipher);
665 /* Registers configured PKCS's. */
667 bool silc_client_config_register_pkcs(SilcClientConfig config)
669 SilcClientConfigSectionAlg *alg = config->pkcs;
670 SilcClient client = config->client;
672 SILC_LOG_DEBUG(("Registering configured PKCS"));
680 for (i = 0; silc_default_pkcs[i].name; i++)
681 if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
682 silc_pkcs_register(&silc_default_pkcs[i]);
686 if (!silc_pkcs_is_supported(alg->alg_name)) {
687 SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
688 silc_client_stop(client);
698 /* Registers configured hash funtions. These can then be allocated by the
699 client when needed. */
701 bool silc_client_config_register_hashfuncs(SilcClientConfig config)
703 SilcClientConfigSectionAlg *alg;
704 SilcClient client = config->client;
706 SILC_LOG_DEBUG(("Registering configured hash functions"));
708 if (!config->hash_func)
711 alg = config->hash_func;
713 if (!alg->sim_name) {
716 for (i = 0; silc_default_hash[i].name; i++)
717 if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
718 silc_hash_register(&silc_default_hash[i]);
722 if (!silc_hash_is_supported(alg->alg_name)) {
723 SILC_LOG_ERROR(("Unknown hash function `%s'", alg->alg_name));
724 silc_client_stop(client);
729 /* Load (try at least) the hash SIM module */
733 memset(&hash, 0, sizeof(hash));
734 hash.name = alg->alg_name;
735 hash.block_len = alg->block_len;
736 hash.hash_len = alg->key_len;
738 sim = silc_sim_alloc();
739 sim->type = SILC_SIM_HASH;
740 sim->libname = alg->sim_name;
742 if ((silc_sim_load(sim))) {
744 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
745 SILC_HASH_SIM_INIT));
746 SILC_LOG_DEBUG(("init=%p", hash.init));
748 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
749 SILC_HASH_SIM_UPDATE));
750 SILC_LOG_DEBUG(("update=%p", hash.update));
752 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
753 SILC_HASH_SIM_FINAL));
754 SILC_LOG_DEBUG(("final=%p", hash.final));
756 silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
757 SILC_HASH_SIM_CONTEXT_LEN));
758 SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
760 /* Put the SIM to the table of all SIM's in client */
761 sims = silc_realloc(sims,
764 sims[sims_count] = sim;
767 SILC_LOG_ERROR(("Error configuring hash functions"));
768 silc_client_stop(client);
772 /* Register the hash function */
773 silc_hash_register(&hash);
782 /* Registers configured HMACs. These can then be allocated by the
783 client when needed. */
785 bool silc_client_config_register_hmacs(SilcClientConfig config)
787 SilcClientConfigSectionAlg *alg;
788 SilcClient client = config->client;
790 SILC_LOG_DEBUG(("Registering configured HMACs"));
799 if (!silc_hash_is_supported(alg->sim_name)) {
800 SILC_LOG_ERROR(("Unknown hash function `%s' for HMAC `%s'",
801 alg->sim_name, alg->alg_name));
802 silc_client_stop(client);
806 /* Register the HMAC */
807 memset(&hmac, 0, sizeof(hmac));
808 hmac.name = alg->alg_name;
809 hmac.len = alg->key_len;
810 silc_hmac_register(&hmac);
818 SilcClientConfigSectionConnection *
819 silc_client_config_find_connection(SilcClientConfig config,
820 char *host, int port)
823 SilcClientConfigSectionConnection *conn = NULL;
825 SILC_LOG_DEBUG(("Finding connection"));
833 conn = config->conns;
834 for (i = 0; conn; i++) {
835 if (silc_string_compare(conn->host, host))
843 SILC_LOG_DEBUG(("Found match"));