updates.
[crypto.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       if (!cptr) {
184         fprintf(stderr, "%s:%d: Unknown start of a section `%s'\n", 
185                         config->filename, linenum, cp);
186         return FALSE;
187       } 
188
189       /* Handle config section */
190       if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
191         
192         if (strchr(cp, '\n'))
193             *strchr(cp, '\n') = ':';
194
195         if (parse == NULL) {
196           parse = silc_calloc(1, sizeof(*parse));
197           parse->line = NULL;
198           parse->section = NULL;
199           parse->next = NULL;
200           parse->prev = NULL;
201         } else {
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;
208             parse = parse->next;
209           }
210         }
211         
212         if (first == NULL)
213           first = parse;
214
215         /* Add the line to parsing structure for further parsing. */
216         if (parse) {
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));
222         }
223       }
224       break;
225     }
226   }
227   
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;
231
232   return TRUE;
233 }
234
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
238    function. */
239
240 int silc_client_config_parse_lines(SilcClientConfig config, 
241                                    SilcClientConfigParse parse_config)
242 {
243   int ret, check = FALSE;
244   char *tmp;
245   SilcClientConfigParse pc = parse_config;
246   SilcBuffer line;
247
248   SILC_LOG_DEBUG(("Parsing configuration lines"));
249   
250   if (!config)
251     return FALSE;
252   
253   while(pc) {
254     check = FALSE;
255     line = pc->line;
256
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) {
261       /* Bad line */
262       fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
263               config->filename, pc->linenum, ret, 
264               pc->section->maxfields);
265       break;
266     }
267
268     /* Parse the line */
269     switch(pc->section->type) {
270     case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
271
272       if (!config->cipher) {
273         config->cipher = silc_calloc(1, sizeof(*config->cipher));
274         config->cipher->next = NULL;
275         config->cipher->prev = NULL;
276       } else {
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;
283         }
284       }
285
286       /* Get cipher name */
287       ret = silc_config_get_token(line, &config->cipher->alg_name);
288       if (ret < 0)
289         break;
290       if (ret == 0) {
291         fprintf(stderr, "%s:%d: Cipher name not defined\n",
292                 config->filename, pc->linenum);
293         break;
294       }
295
296       /* Get module name */
297       config->cipher->sim_name = NULL;
298       ret = silc_config_get_token(line, &config->cipher->sim_name);
299       if (ret < 0)
300         break;
301
302       /* Get key length */
303       ret = silc_config_get_token(line, &tmp);
304       if (ret < 0)
305         break;
306       if (ret == 0) {
307         fprintf(stderr, "%s:%d: Cipher key length not defined\n",
308                 config->filename, pc->linenum);
309         break;
310       }
311       config->cipher->key_len = atoi(tmp);
312       silc_free(tmp);
313
314       /* Get block length */
315       ret = silc_config_get_token(line, &tmp);
316       if (ret < 0)
317         break;
318       if (ret == 0) {
319         fprintf(stderr, "%s:%d: Cipher block length not defined\n",
320                 config->filename, pc->linenum);
321         break;
322       }
323       config->cipher->block_len = atoi(tmp);
324       silc_free(tmp);
325
326       check = TRUE;
327       break;
328
329     case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
330
331       if (!config->pkcs) {
332         config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
333         config->pkcs->next = NULL;
334         config->pkcs->prev = NULL;
335       } else {
336         if (!config->pkcs->next) {
337           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;
342         }
343       }
344
345       /* Get PKCS name */
346       ret = silc_config_get_token(line, &config->pkcs->alg_name);
347       if (ret < 0)
348         break;
349       if (ret == 0) {
350         fprintf(stderr, "%s:%d: PKCS name not defined\n",
351                 config->filename, pc->linenum);
352         break;
353       }
354
355       check = TRUE;
356       break;
357
358     case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
359
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;
364       } else {
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;
371         }
372       }
373
374       /* Get Hash function name */
375       ret = silc_config_get_token(line, &config->hash_func->alg_name);
376       if (ret < 0)
377         break;
378       if (ret == 0) {
379         fprintf(stderr, "%s:%d: Hash function name not defined\n",
380                 config->filename, pc->linenum);
381         break;
382       }
383       
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);
387       if (ret < 0)
388         break;
389
390       /* Get block length */
391       ret = silc_config_get_token(line, &tmp);
392       if (ret < 0)
393         break;
394       if (ret == 0) {
395         fprintf(stderr, "%s:%d: Hash function block length not defined\n",
396                 config->filename, pc->linenum);
397         break;
398       }
399       config->hash_func->block_len = atoi(tmp);
400       silc_free(tmp);
401
402       /* Get hash length */
403       ret = silc_config_get_token(line, &tmp);
404       if (ret < 0)
405         break;
406       if (ret == 0) {
407         fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
408                 config->filename, pc->linenum);
409         break;
410       }
411       config->hash_func->key_len = atoi(tmp);
412       silc_free(tmp);
413
414       check = TRUE;
415       break;
416
417     case SILC_CLIENT_CONFIG_SECTION_TYPE_HMAC:
418
419       if (!config->hmac) {
420         config->hmac = silc_calloc(1, sizeof(*config->hmac));
421         config->hmac->next = NULL;
422         config->hmac->prev = NULL;
423       } else {
424         if (!config->hmac->next) {
425           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;
430         }
431       }
432
433       /* Get HMAC name */
434       ret = silc_config_get_token(line, &config->hmac->alg_name);
435       if (ret < 0)
436         break;
437       if (ret == 0) {
438         fprintf(stderr, "%s:%d: HMAC name not defined\n",
439                 config->filename, pc->linenum);
440         break;
441       }
442       
443       /* Get Hash function name */
444       ret = silc_config_get_token(line, &config->hmac->sim_name);
445       if (ret < 0)
446         break;
447       if (ret == 0) {
448         fprintf(stderr, "%s:%d: Hash function name not defined\n",
449                 config->filename, pc->linenum);
450         break;
451       }
452
453       /* Get MAC length */
454       ret = silc_config_get_token(line, &tmp);
455       if (ret < 0)
456         break;
457       if (ret == 0) {
458         fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
459                 config->filename, pc->linenum);
460         break;
461       }
462       config->hmac->key_len = atoi(tmp);
463       silc_free(tmp);
464
465       check = TRUE;
466       break;
467
468     case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
469
470       if (!config->conns) {
471         config->conns = silc_calloc(1, sizeof(*config->conns));
472         config->conns->next = NULL;
473         config->conns->prev = NULL;
474       } else {
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;
480         }
481       }
482       
483       /* Get host */
484       ret = silc_config_get_token(line, &config->conns->host);
485       if (ret < 0)
486         break;
487       if (ret == 0)
488         /* Any host */
489         config->conns->host = strdup("*");
490
491       /* Get authentication method */
492       ret = silc_config_get_token(line, &tmp);
493       if (ret < 0)
494         break;
495       if (ret) {
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);
500           break;
501         }
502
503         if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
504           config->conns->auth_meth = SILC_AUTH_PASSWORD;
505
506         if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
507           config->conns->auth_meth = SILC_AUTH_PUBLIC_KEY;
508
509         silc_free(tmp);
510       }
511
512       /* Get authentication data */
513       ret = silc_config_get_token(line, &config->conns->auth_data);
514       if (ret < 0)
515         break;
516
517       /* Get port */
518       ret = silc_config_get_token(line, &tmp);
519       if (ret < 0)
520         break;
521       if (ret) {
522         config->conns->port = atoi(tmp);
523         silc_free(tmp);
524       }
525
526       check = TRUE;
527       break;
528
529     case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
530     default:
531       break;
532     }
533
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);
538       break;
539     }
540
541     pc = pc->next;
542   }
543
544   if (check == FALSE)
545     return FALSE;;
546
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;
559   
560   SILC_LOG_DEBUG(("Done"));
561   
562   return TRUE;
563 }
564
565 /* Registers configured ciphers. These can then be allocated by the
566    client when needed. */
567
568 bool silc_client_config_register_ciphers(SilcClientConfig config)
569 {
570   SilcClientConfigSectionAlg *alg;
571   SilcClient client = config->client;
572
573   SILC_LOG_DEBUG(("Registering configured ciphers"));
574
575   if (!config->cipher)
576     return FALSE;
577
578   alg = config->cipher;
579   while(alg) {
580
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. */
584       int i;
585
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]);
589           break;
590         }
591
592       if (!silc_cipher_is_supported(alg->alg_name)) {
593         SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
594         silc_client_stop(client);
595         exit(1);
596       }
597
598 #ifdef SILC_SIM
599     } else {
600       /* Load (try at least) the crypto SIM module */
601       SilcCipherObject cipher;
602       SilcSimContext *sim;
603       char *alg_name;
604
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;
609
610       sim = silc_sim_alloc();
611       sim->type = SILC_SIM_CIPHER;
612       sim->libname = alg->sim_name;
613
614       alg_name = strdup(alg->alg_name);
615       if (strchr(alg_name, '-'))
616         *strchr(alg_name, '-') = '\0';
617
618       if ((silc_sim_load(sim))) {
619         cipher.set_key = 
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));
627         cipher.encrypt = 
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));
631         cipher.decrypt = 
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));
635         cipher.context_len = 
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));
639
640         /* Put the SIM to the table of all SIM's in client */
641         sims = silc_realloc(sims,
642                                    sizeof(*sims) * 
643                                    (sims_count + 1));
644         sims[sims_count] = sim;
645         sims_count++;
646
647         silc_free(alg_name);
648       } else {
649         SILC_LOG_ERROR(("Error configuring ciphers"));
650         silc_client_stop(client);
651         exit(1);
652       }
653
654       /* Register the cipher */
655       silc_cipher_register(&cipher);
656 #endif
657     }
658
659     alg = alg->next;
660   }
661
662   return TRUE;
663 }
664
665 /* Registers configured PKCS's. */
666
667 bool silc_client_config_register_pkcs(SilcClientConfig config)
668 {
669   SilcClientConfigSectionAlg *alg = config->pkcs;
670   SilcClient client = config->client;
671
672   SILC_LOG_DEBUG(("Registering configured PKCS"));
673
674   if (!alg)
675     return FALSE;
676
677   while(alg) {
678     int i;
679     
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]);
683         break;
684       }
685     
686     if (!silc_pkcs_is_supported(alg->alg_name)) {
687       SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
688       silc_client_stop(client);
689       exit(1);
690     }
691
692     alg = alg->next;
693   }
694
695   return TRUE;
696 }
697
698 /* Registers configured hash funtions. These can then be allocated by the
699    client when needed. */
700
701 bool silc_client_config_register_hashfuncs(SilcClientConfig config)
702 {
703   SilcClientConfigSectionAlg *alg;
704   SilcClient client = config->client;
705
706   SILC_LOG_DEBUG(("Registering configured hash functions"));
707
708   if (!config->hash_func)
709     return FALSE;
710
711   alg = config->hash_func;
712   while(alg) {
713     if (!alg->sim_name) {
714       int i;
715       
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]);
719           break;
720         }
721       
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);
725         exit(1);
726       }
727 #ifdef SILC_SIM
728     } else {
729       /* Load (try at least) the hash SIM module */
730       SilcHashObject hash;
731       SilcSimContext *sim;
732
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;
737
738       sim = silc_sim_alloc();
739       sim->type = SILC_SIM_HASH;
740       sim->libname = alg->sim_name;
741
742       if ((silc_sim_load(sim))) {
743         hash.init = 
744           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
745                                                 SILC_HASH_SIM_INIT));
746         SILC_LOG_DEBUG(("init=%p", hash.init));
747         hash.update = 
748           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
749                                                 SILC_HASH_SIM_UPDATE));
750         SILC_LOG_DEBUG(("update=%p", hash.update));
751         hash.final = 
752           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
753                                                 SILC_HASH_SIM_FINAL));
754         SILC_LOG_DEBUG(("final=%p", hash.final));
755         hash.context_len = 
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));
759
760         /* Put the SIM to the table of all SIM's in client */
761         sims = silc_realloc(sims,
762                                    sizeof(*sims) * 
763                                    (sims_count + 1));
764         sims[sims_count] = sim;
765         sims_count++;
766       } else {
767         SILC_LOG_ERROR(("Error configuring hash functions"));
768         silc_client_stop(client);
769         exit(1);
770       }
771
772       /* Register the hash function */
773       silc_hash_register(&hash);
774 #endif
775     }
776     alg = alg->next;
777   }
778
779   return TRUE;
780 }
781
782 /* Registers configured HMACs. These can then be allocated by the
783    client when needed. */
784
785 bool silc_client_config_register_hmacs(SilcClientConfig config)
786 {
787   SilcClientConfigSectionAlg *alg;
788   SilcClient client = config->client;
789
790   SILC_LOG_DEBUG(("Registering configured HMACs"));
791
792   if (!config->hmac)
793     return FALSE;
794
795   alg = config->hmac;
796   while(alg) {
797     SilcHmacObject hmac;
798     
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);
803       exit(1);
804     }
805     
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);
811
812     alg = alg->next;
813   }
814
815   return TRUE;
816 }
817
818 SilcClientConfigSectionConnection *
819 silc_client_config_find_connection(SilcClientConfig config, 
820                                    char *host, int port)
821 {
822   int i;
823   SilcClientConfigSectionConnection *conn = NULL;
824
825   SILC_LOG_DEBUG(("Finding connection"));
826
827   if (!host)
828     return NULL;
829
830   if (!config->conns)
831     return NULL;
832
833   conn = config->conns;
834   for (i = 0; conn; i++) {
835     if (silc_string_compare(conn->host, host))
836       break;
837     conn = conn->next;
838   }
839
840   if (!conn)
841     return NULL;
842
843   SILC_LOG_DEBUG(("Found match"));
844
845   return conn;
846 }