5626f2a0cfa254e283e4215af8063d0fb76f1f1d
[silc.git] / apps / irssi / src / silc / core / clientconfig.c
1 /*
2
3   serverconfig.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "module.h"
23
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
26 #include "signals.h"
27 #include "servers.h"
28 #include "commands.h"
29 #include "levels.h"
30 #include "modules.h"
31 #include "rawlog.h"
32 #include "misc.h"
33 #include "settings.h"
34
35 #include "servers-setup.h"
36
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "window-item-def.h"
41
42 #include "fe-common/core/printtext.h"
43
44 /* 
45    All possible configuration sections for SILC client.
46 */
47 SilcClientConfigSection silc_client_config_sections[] = {
48   { "[cipher]", 
49     SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
50   { "[pkcs]", 
51     SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 1 },
52   { "[hash]", 
53     SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
54   { "[hmac]", 
55     SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC, 3 },
56   { "[connection]", 
57     SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
58   
59   { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
60 };
61
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. */
65
66 SilcClientConfig silc_client_config_alloc(char *filename)
67 {
68   SilcClientConfig new;
69   SilcBuffer buffer;
70   SilcClientConfigParse config_parse;
71   char *str;
72
73   SILC_LOG_DEBUG(("Allocating new configuration object"));
74
75   new = silc_calloc(1, sizeof(*new));
76   new->filename = filename;
77
78   /* Open configuration file and parse it */
79   config_parse = NULL;
80   buffer = NULL;
81   str = convert_home(filename);
82   silc_config_open(str, &buffer);
83   g_free(str);
84   if (!buffer)
85     goto fail;
86   if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
87     goto fail;
88   if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
89     goto fail;
90
91   silc_free(buffer);
92
93   return new;
94
95  fail:
96   silc_free(new);
97   return NULL;
98 }
99
100 /* Free's a configuration object. */
101
102 void silc_client_config_free(SilcClientConfig config)
103 {
104   if (config) {
105
106     silc_free(config);
107   }
108 }
109
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. */
115
116 int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer, 
117                              SilcClientConfigParse *return_config)
118 {
119   int i, begin;
120   int linenum;
121   char line[1024], *cp;
122   SilcClientConfigSection *cptr = NULL;
123   SilcClientConfigParse parse = *return_config, first = NULL;
124
125   SILC_LOG_DEBUG(("Parsing configuration file"));
126
127   begin = 0;
128   linenum = 0;
129   while((begin = silc_gets(line, sizeof(line), 
130                            buffer->data, buffer->len, begin)) != EOF) {
131     cp = line;
132     linenum++;
133
134     /* Check for bad line */
135     if (silc_check_line(cp))
136       continue;
137
138     /* Remove tabs and whitespaces from the line */
139     if (strchr(cp, '\t')) {
140       i = 0;
141       while(strchr(cp + i, '\t')) {
142         *strchr(cp + i, '\t') = ' ';
143         i++;
144       }
145     }
146     for (i = 0; i < strlen(cp); i++) {
147       if (cp[i] != ' ') {
148         if (i)
149           cp++;
150         break;
151       }
152       cp++;
153     }
154
155     /* Parse line */
156     switch(cp[0]) {
157     case '[':
158       /*
159        * Start of a section
160        */
161
162       /* Remove new line sign */
163       if (strchr(cp, '\n'))
164         *strchr(cp, '\n') = '\0';
165       
166       /* Check for matching sections */
167       for (cptr = silc_client_config_sections; cptr->section; cptr++)
168         if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
169           break;
170
171       if (!cptr->section) {
172         fprintf(stderr, "%s:%d: Unknown section `%s'\n", 
173                         config->filename, linenum, cp);
174         return FALSE;
175       }
176
177       break;
178     default:
179       /*
180        * Start of a configuration line
181        */
182
183       /* Handle config section */
184       if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
185         
186         if (strchr(cp, '\n'))
187             *strchr(cp, '\n') = ':';
188
189         if (parse == NULL) {
190           parse = silc_calloc(1, sizeof(*parse));
191           parse->line = NULL;
192           parse->section = NULL;
193           parse->next = NULL;
194           parse->prev = NULL;
195         } else {
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;
202             parse = parse->next;
203           }
204         }
205         
206         if (first == NULL)
207           first = parse;
208
209         /* Add the line to parsing structure for further parsing. */
210         if (parse) {
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));
216         }
217       }
218       break;
219     }
220   }
221   
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;
225
226   return TRUE;
227 }
228
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
232    function. */
233
234 int silc_client_config_parse_lines(SilcClientConfig config, 
235                                    SilcClientConfigParse parse_config)
236 {
237   int ret, check = FALSE;
238   char *tmp;
239   SilcClientConfigParse pc = parse_config;
240   SilcBuffer line;
241
242   SILC_LOG_DEBUG(("Parsing configuration lines"));
243   
244   if (!config)
245     return FALSE;
246   
247   while(pc) {
248     check = FALSE;
249     line = pc->line;
250
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) {
255       /* Bad line */
256       fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
257               config->filename, pc->linenum, ret, 
258               pc->section->maxfields);
259       break;
260     }
261
262     /* Parse the line */
263     switch(pc->section->type) {
264     case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
265
266       if (!config->cipher) {
267         config->cipher = silc_calloc(1, sizeof(*config->cipher));
268         config->cipher->next = NULL;
269         config->cipher->prev = NULL;
270       } else {
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;
277         }
278       }
279
280       /* Get cipher name */
281       ret = silc_config_get_token(line, &config->cipher->alg_name);
282       if (ret < 0)
283         break;
284       if (ret == 0) {
285         fprintf(stderr, "%s:%d: Cipher name not defined\n",
286                 config->filename, pc->linenum);
287         break;
288       }
289
290       /* Get module name */
291       config->cipher->sim_name = NULL;
292       ret = silc_config_get_token(line, &config->cipher->sim_name);
293       if (ret < 0)
294         break;
295
296       /* Get key length */
297       ret = silc_config_get_token(line, &tmp);
298       if (ret < 0)
299         break;
300       if (ret == 0) {
301         fprintf(stderr, "%s:%d: Cipher key length not defined\n",
302                 config->filename, pc->linenum);
303         break;
304       }
305       config->cipher->key_len = atoi(tmp);
306       silc_free(tmp);
307
308       /* Get block length */
309       ret = silc_config_get_token(line, &tmp);
310       if (ret < 0)
311         break;
312       if (ret == 0) {
313         fprintf(stderr, "%s:%d: Cipher block length not defined\n",
314                 config->filename, pc->linenum);
315         break;
316       }
317       config->cipher->block_len = atoi(tmp);
318       silc_free(tmp);
319
320       check = TRUE;
321       break;
322
323     case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
324
325       if (!config->pkcs) {
326         config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
327         config->pkcs->next = NULL;
328         config->pkcs->prev = NULL;
329       } else {
330         if (!config->pkcs->next) {
331           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;
336         }
337       }
338
339       /* Get PKCS name */
340       ret = silc_config_get_token(line, &config->pkcs->alg_name);
341       if (ret < 0)
342         break;
343       if (ret == 0) {
344         fprintf(stderr, "%s:%d: PKCS name not defined\n",
345                 config->filename, pc->linenum);
346         break;
347       }
348
349       check = TRUE;
350       break;
351
352     case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
353
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;
358       } else {
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;
365         }
366       }
367
368       /* Get Hash function name */
369       ret = silc_config_get_token(line, &config->hash_func->alg_name);
370       if (ret < 0)
371         break;
372       if (ret == 0) {
373         fprintf(stderr, "%s:%d: Hash function name not defined\n",
374                 config->filename, pc->linenum);
375         break;
376       }
377       
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);
381       if (ret < 0)
382         break;
383
384       /* Get block length */
385       ret = silc_config_get_token(line, &tmp);
386       if (ret < 0)
387         break;
388       if (ret == 0) {
389         fprintf(stderr, "%s:%d: Hash function block length not defined\n",
390                 config->filename, pc->linenum);
391         break;
392       }
393       config->hash_func->block_len = atoi(tmp);
394       silc_free(tmp);
395
396       /* Get hash length */
397       ret = silc_config_get_token(line, &tmp);
398       if (ret < 0)
399         break;
400       if (ret == 0) {
401         fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
402                 config->filename, pc->linenum);
403         break;
404       }
405       config->hash_func->key_len = atoi(tmp);
406       silc_free(tmp);
407
408       check = TRUE;
409       break;
410
411     case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
412
413       if (!config->hmac) {
414         config->hmac = silc_calloc(1, sizeof(*config->hmac));
415         config->hmac->next = NULL;
416         config->hmac->prev = NULL;
417       } else {
418         if (!config->hmac->next) {
419           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;
424         }
425       }
426
427       /* Get HMAC name */
428       ret = silc_config_get_token(line, &config->hmac->alg_name);
429       if (ret < 0)
430         break;
431       if (ret == 0) {
432         fprintf(stderr, "%s:%d: HMAC name not defined\n",
433                 config->filename, pc->linenum);
434         break;
435       }
436       
437       /* Get Hash function name */
438       ret = silc_config_get_token(line, &config->hmac->sim_name);
439       if (ret < 0)
440         break;
441       if (ret == 0) {
442         fprintf(stderr, "%s:%d: Hash function name not defined\n",
443                 config->filename, pc->linenum);
444         break;
445       }
446
447       /* Get MAC length */
448       ret = silc_config_get_token(line, &tmp);
449       if (ret < 0)
450         break;
451       if (ret == 0) {
452         fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
453                 config->filename, pc->linenum);
454         break;
455       }
456       config->hmac->key_len = atoi(tmp);
457       silc_free(tmp);
458
459       check = TRUE;
460       break;
461
462     case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
463
464       if (!config->conns) {
465         config->conns = silc_calloc(1, sizeof(*config->conns));
466         config->conns->next = NULL;
467         config->conns->prev = NULL;
468       } else {
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;
474         }
475       }
476       
477       /* Get host */
478       ret = silc_config_get_token(line, &config->conns->host);
479       if (ret < 0)
480         break;
481       if (ret == 0)
482         /* Any host */
483         config->conns->host = strdup("*");
484
485       /* Get authentication method */
486       ret = silc_config_get_token(line, &tmp);
487       if (ret < 0)
488         break;
489       if (ret) {
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);
494           break;
495         }
496
497         if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
498           config->conns->auth_meth = SILC_AUTH_PASSWORD;
499
500         if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
501           config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
502
503         silc_free(tmp);
504       }
505
506       /* Get authentication data */
507       ret = silc_config_get_token(line, &config->conns->auth_data);
508       if (ret < 0)
509         break;
510
511       /* Get port */
512       ret = silc_config_get_token(line, &tmp);
513       if (ret < 0)
514         break;
515       if (ret) {
516         config->conns->port = atoi(tmp);
517         silc_free(tmp);
518       }
519
520       check = TRUE;
521       break;
522
523     case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
524     default:
525       break;
526     }
527
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);
532       break;
533     }
534
535     pc = pc->next;
536   }
537
538   if (check == FALSE)
539     return FALSE;;
540
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;
553   
554   SILC_LOG_DEBUG(("Done"));
555   
556   return TRUE;
557 }
558
559 /* Registers configured ciphers. These can then be allocated by the
560    client when needed. */
561
562 bool silc_client_config_register_ciphers(SilcClientConfig config)
563 {
564   SilcClientConfigSectionAlg *alg;
565   SilcClient client = config->client;
566
567   SILC_LOG_DEBUG(("Registering configured ciphers"));
568
569   if (!config->cipher)
570     return FALSE;
571
572   alg = config->cipher;
573   while(alg) {
574
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. */
578       int i;
579
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]);
583           break;
584         }
585
586       if (!silc_cipher_is_supported(alg->alg_name)) {
587         SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
588         silc_client_stop(client);
589         exit(1);
590       }
591
592 #ifdef SILC_SIM
593     } else {
594       /* Load (try at least) the crypto SIM module */
595       SilcCipherObject cipher;
596       SilcSimContext *sim;
597       char *alg_name;
598
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;
603
604       sim = silc_sim_alloc();
605       sim->type = SILC_SIM_CIPHER;
606       sim->libname = alg->sim_name;
607
608       alg_name = strdup(alg->alg_name);
609       if (strchr(alg_name, '-'))
610         *strchr(alg_name, '-') = '\0';
611
612       if ((silc_sim_load(sim))) {
613         cipher.set_key = 
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));
621         cipher.encrypt = 
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));
625         cipher.decrypt = 
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));
629         cipher.context_len = 
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));
633
634         /* Put the SIM to the table of all SIM's in client */
635         sims = silc_realloc(sims,
636                                    sizeof(*sims) * 
637                                    (sims_count + 1));
638         sims[sims_count] = sim;
639         sims_count++;
640
641         silc_free(alg_name);
642       } else {
643         SILC_LOG_ERROR(("Error configuring ciphers"));
644         silc_client_stop(client);
645         exit(1);
646       }
647
648       /* Register the cipher */
649       silc_cipher_register(&cipher);
650 #endif
651     }
652
653     alg = alg->next;
654   }
655
656   return TRUE;
657 }
658
659 /* Registers configured PKCS's. */
660
661 bool silc_client_config_register_pkcs(SilcClientConfig config)
662 {
663   SilcClientConfigSectionAlg *alg = config->pkcs;
664   SilcClient client = config->client;
665
666   SILC_LOG_DEBUG(("Registering configured PKCS"));
667
668   if (!alg)
669     return FALSE;
670
671   while(alg) {
672     int i;
673     
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]);
677         break;
678       }
679     
680     if (!silc_pkcs_is_supported(alg->alg_name)) {
681       SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
682       silc_client_stop(client);
683       exit(1);
684     }
685
686     alg = alg->next;
687   }
688
689   return TRUE;
690 }
691
692 /* Registers configured hash funtions. These can then be allocated by the
693    client when needed. */
694
695 bool silc_client_config_register_hashfuncs(SilcClientConfig config)
696 {
697   SilcClientConfigSectionAlg *alg;
698   SilcClient client = config->client;
699
700   SILC_LOG_DEBUG(("Registering configured hash functions"));
701
702   if (!config->hash_func)
703     return FALSE;
704
705   alg = config->hash_func;
706   while(alg) {
707     if (!alg->sim_name) {
708       int i;
709       
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]);
713           break;
714         }
715       
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);
719         exit(1);
720       }
721 #ifdef SILC_SIM
722     } else {
723       /* Load (try at least) the hash SIM module */
724       SilcHashObject hash;
725       SilcSimContext *sim;
726
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;
731
732       sim = silc_sim_alloc();
733       sim->type = SILC_SIM_HASH;
734       sim->libname = alg->sim_name;
735
736       if ((silc_sim_load(sim))) {
737         hash.init = 
738           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
739                                                 SILC_HASH_SIM_INIT));
740         SILC_LOG_DEBUG(("init=%p", hash.init));
741         hash.update = 
742           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
743                                                 SILC_HASH_SIM_UPDATE));
744         SILC_LOG_DEBUG(("update=%p", hash.update));
745         hash.final = 
746           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
747                                                 SILC_HASH_SIM_FINAL));
748         SILC_LOG_DEBUG(("final=%p", hash.final));
749         hash.context_len = 
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));
753
754         /* Put the SIM to the table of all SIM's in client */
755         sims = silc_realloc(sims,
756                                    sizeof(*sims) * 
757                                    (sims_count + 1));
758         sims[sims_count] = sim;
759         sims_count++;
760       } else {
761         SILC_LOG_ERROR(("Error configuring hash functions"));
762         silc_client_stop(client);
763         exit(1);
764       }
765
766       /* Register the hash function */
767       silc_hash_register(&hash);
768 #endif
769     }
770     alg = alg->next;
771   }
772
773   return TRUE;
774 }
775
776 /* Registers configured HMACs. These can then be allocated by the
777    client when needed. */
778
779 bool silc_client_config_register_hmacs(SilcClientConfig config)
780 {
781   SilcClientConfigSectionAlg *alg;
782   SilcClient client = config->client;
783
784   SILC_LOG_DEBUG(("Registering configured HMACs"));
785
786   if (!config->hmac)
787     return FALSE;
788
789   alg = config->hmac;
790   while(alg) {
791     SilcHmacObject hmac;
792     
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);
797       exit(1);
798     }
799     
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);
805
806     alg = alg->next;
807   }
808
809   return TRUE;
810 }
811
812 SilcClientConfigSectionConnection *
813 silc_client_config_find_connection(SilcClientConfig config, 
814                                    char *host, int port)
815 {
816   int i;
817   SilcClientConfigSectionConnection *conn = NULL;
818
819   SILC_LOG_DEBUG(("Finding connection"));
820
821   if (!host)
822     return NULL;
823
824   if (!config->conns)
825     return NULL;
826
827   conn = config->conns;
828   for (i = 0; conn; i++) {
829     if (silc_string_compare(conn->host, host))
830       break;
831     conn = conn->next;
832   }
833
834   if (!conn)
835     return NULL;
836
837   SILC_LOG_DEBUG(("Found match"));
838
839   return conn;
840 }