updates.
[silc.git] / apps / silcd / serverconfig.c
1 /*
2
3   serverconfig.c
4
5   Author: Johnny Mnemonic <johnny@themnemonic.org>
6
7   Copyright (C) 1997 - 2002 Johnny Mnemonic
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 "serverincludes.h"
23 #include "server_internal.h"
24
25 #if 0
26 #define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
27 #else
28 #define SERVER_CONFIG_DEBUG(fmt)
29 #endif
30
31 /* auto-declare needed variables for the common list parsing */
32 #define SILC_SERVER_CONFIG_SECTION_INIT(__type__)                       \
33   SilcServerConfig config = (SilcServerConfig) context;                 \
34   __type__ *findtmp, *tmp = (__type__ *) config->tmp;                   \
35   int got_errno = 0
36
37 /* append the tmp field to the specified list */
38 #define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__)                     \
39   if (!__list__) {                                                      \
40     __list__ = tmp;                                                     \
41   } else {                                                              \
42     for (findtmp = __list__; findtmp->next; findtmp = findtmp->next);   \
43     findtmp->next = tmp;                                                \
44   }
45
46 /* loops all elements in a list and provides a di struct pointer of the
47  * specified type containing the current element */
48 #define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__)             \
49   for (tmp = (void *) __list__; tmp;) {                                 \
50     __type__ *di = (__type__ *) tmp;                                    \
51     tmp = (void *) di->next;
52
53 /* free an authdata according to its auth method */
54 static void my_free_authdata(char *passphrase, void *public_key)
55 {
56   silc_free(passphrase);
57   if (public_key)
58     silc_pkcs_public_key_free((SilcPublicKey) public_key);
59 }
60
61 /* parse an authdata according to its auth method */
62 static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
63                               void **auth_data, uint32 *auth_data_len)
64 {
65   if (auth_meth == SILC_AUTH_PASSWORD) {
66     /* p is a plain text password */
67     if (auth_data)
68       *auth_data = (void *) strdup(p);
69     if (auth_data_len)
70       *auth_data_len = (uint32) strlen(p);
71   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
72     /* p is a public key */
73     SilcPublicKey public_key;
74
75     if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
76       if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
77         fprintf(stderr, "\nError while parsing config file at line %lu: "
78                 "Could not load public key file!\n", line);
79         return FALSE;
80       }
81     if (auth_data)
82       *auth_data = (void *) public_key;
83     if (auth_data_len)
84       *auth_data_len = 0;
85   } else {
86     fprintf(stderr, "\nError while parsing config file at line %lu: "
87             "Unkonwn authentication method\n", line);
88     return FALSE;
89   }
90   return TRUE;
91 }
92
93 /* Callbacks */
94
95 SILC_CONFIG_CALLBACK(fetch_generic)
96 {
97   SilcServerConfig config = (SilcServerConfig) context;
98
99   if (!strcmp(name, "module_path")) {
100     if (config->module_path) 
101       return SILC_CONFIG_EDOUBLE;
102
103     /* dup it only if non-empty, otherwise point it to NULL */
104     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
105   }
106   else if (!strcmp(name, "prefer_passphrase_auth")) {
107     config->prefer_passphrase_auth = *(bool *)val;
108   }
109   else
110     return SILC_CONFIG_EINTERNAL;
111
112   return SILC_CONFIG_OK;
113 }
114
115 SILC_CONFIG_CALLBACK(fetch_cipher)
116 {
117   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionCipher);
118
119   SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)", 
120                        type, name, context));
121   if (type == SILC_CONFIG_ARG_BLOCK) {
122     /* check the temporary struct's fields */
123     if (!tmp) /* empty sub-block? */
124       return SILC_CONFIG_OK;
125     if (!tmp->name) {
126       got_errno = SILC_CONFIG_EMISSFIELDS;
127       goto got_err;
128     }
129     /* the temporary struct is ok, append it to the list */
130     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
131     config->tmp = NULL;
132     return SILC_CONFIG_OK;
133   }
134   /* if there isn't a temporary struct alloc one */
135   if (!tmp) {
136     config->tmp = silc_calloc(1, sizeof(*findtmp));
137     tmp = (SilcServerConfigSectionCipher *) config->tmp;
138   }
139
140   /* Identify and save this value */
141   if (!strcmp(name, "name")) {
142     if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
143     tmp->name = strdup((char *) val);
144   }
145   else if (!strcmp(name, "module")) { /* can be empty */
146     if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
147     /* dup it only if non-empty, otherwise point it to NULL */
148     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
149   }
150   else if (!strcmp(name, "keylength"))
151     tmp->key_length = *(uint32 *)val;
152   else if (!strcmp(name, "blocklength"))
153     tmp->block_length = *(uint32 *)val;
154   else
155     return SILC_CONFIG_EINTERNAL;
156   return SILC_CONFIG_OK;
157
158  got_err:
159   silc_free(tmp->name);
160   silc_free(tmp->module);
161   silc_free(tmp);
162   config->tmp = NULL;
163   return got_errno;
164 }
165
166 SILC_CONFIG_CALLBACK(fetch_hash)
167 {
168   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHash);
169
170   SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)", 
171                        type, name, context));
172   if (type == SILC_CONFIG_ARG_BLOCK) {
173     /* check the temporary struct's fields */
174     if (!tmp) /* empty sub-block? */
175       return SILC_CONFIG_OK;
176     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
177       got_errno = SILC_CONFIG_EMISSFIELDS;
178       goto got_err;
179     }
180     /* the temporary struct in tmp is ok */
181     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
182     config->tmp = NULL;
183     return SILC_CONFIG_OK;
184   }
185   /* if there isn't a temporary struct alloc one */
186   if (!tmp) {
187     config->tmp = silc_calloc(1, sizeof(*findtmp));
188     tmp = (SilcServerConfigSectionHash *) config->tmp;
189   }
190
191   /* Identify and save this value */
192   if (!strcmp(name, "name")) {
193     if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
194     tmp->name = strdup((char *) val);
195   }
196   else if (!strcmp(name, "module")) { /* can be empty */
197     if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
198     /* dup it only if non-empty, otherwise point it to NULL */
199     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
200   }
201   else if (!strcmp(name, "blocklength"))
202     tmp->block_length = *(int *)val;
203   else if (!strcmp(name, "digestlength"))
204     tmp->digest_length = *(int *)val;
205   else
206     return SILC_CONFIG_EINTERNAL;
207   return SILC_CONFIG_OK;
208
209  got_err:
210   silc_free(tmp->name);
211   silc_free(tmp->module);
212   silc_free(tmp);
213   config->tmp = NULL;
214   return got_errno;
215 }
216
217 SILC_CONFIG_CALLBACK(fetch_hmac)
218 {
219   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHmac);
220
221   SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)", 
222                        type, name, context));
223   if (type == SILC_CONFIG_ARG_BLOCK) {
224     /* check the temporary struct's fields */
225     if (!tmp) /* empty sub-block? */
226       return SILC_CONFIG_OK;
227     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
228       got_errno = SILC_CONFIG_EMISSFIELDS;
229       goto got_err;
230     }
231     /* the temporary struct is ok, append it to the list */
232     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
233     config->tmp = NULL;
234     return SILC_CONFIG_OK;
235   }
236   /* if there isn't a temporary struct alloc one */
237   if (!tmp) {
238     config->tmp = silc_calloc(1, sizeof(*findtmp));
239     tmp = (SilcServerConfigSectionHmac *) config->tmp;
240   }
241
242   /* Identify and save this value */
243   if (!strcmp(name, "name")) {
244     if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
245     tmp->name = strdup((char *) val);
246   }
247   else if (!strcmp(name, "hash")) {
248     if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
249     tmp->hash = strdup((char *) val);
250   }
251   else if (!strcmp(name, "maclength"))
252     tmp->mac_length = *(int *)val;
253   else
254     return SILC_CONFIG_EINTERNAL;
255   return SILC_CONFIG_OK;
256
257  got_err:
258   silc_free(tmp->name);
259   silc_free(tmp->hash);
260   silc_free(tmp);
261   config->tmp = NULL;
262   return got_errno;
263 }
264
265 SILC_CONFIG_CALLBACK(fetch_pkcs)
266 {
267   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionPkcs);
268
269   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)", 
270                        type, name, context));
271   if (type == SILC_CONFIG_ARG_BLOCK) {
272     /* check the temporary struct's fields */
273     if (!tmp) /* empty sub-block? */
274       return SILC_CONFIG_OK;
275     if (!tmp->name) {
276       got_errno = SILC_CONFIG_EMISSFIELDS;
277       goto got_err;
278     }
279     /* the temporary struct is ok, append it to the list */
280     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
281     config->tmp = NULL;
282     return SILC_CONFIG_OK;
283   }
284   /* if there isn't a temporary struct alloc one */
285   if (!tmp) {
286     config->tmp = silc_calloc(1, sizeof(*findtmp));
287     tmp = (SilcServerConfigSectionPkcs *) config->tmp;
288   }
289
290   /* Identify and save this value */
291   if (!strcmp(name, "name")) {
292     if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
293     tmp->name = strdup((char *) val);
294   }
295   else
296     return SILC_CONFIG_EINTERNAL;
297   return SILC_CONFIG_OK;
298
299  got_err:
300   silc_free(tmp->name);
301   silc_free(tmp);
302   config->tmp = NULL;
303   return got_errno;
304 }
305
306 SILC_CONFIG_CALLBACK(fetch_serverinfo)
307 {
308   SilcServerConfig config = (SilcServerConfig) context;
309   SilcServerConfigSectionServerInfo *server_info = config->server_info;
310
311   /* if there isn't the struct alloc it */
312   if (!server_info) {
313     config->server_info = server_info = (SilcServerConfigSectionServerInfo *)
314                 silc_calloc(1, sizeof(*server_info));
315   }
316
317   if (type == SILC_CONFIG_ARG_BLOCK) {
318     /* check for mandatory inputs */
319     return SILC_CONFIG_OK;
320   }
321   if (!strcmp(name, "hostname")) {
322     if (server_info->server_name) return SILC_CONFIG_EDOUBLE;
323     server_info->server_name = strdup((char *) val);
324   }
325   else if (!strcmp(name, "ip")) {
326     if (server_info->server_ip) return SILC_CONFIG_EDOUBLE;
327     server_info->server_ip = strdup((char *) val);
328   }
329   else if (!strcmp(name, "port")) {
330     int port = *(int *)val;
331     if ((port <= 0) || (port > 65535)) {
332       fprintf(stderr, "Invalid port number!\n");
333       return SILC_CONFIG_ESILENT;
334     }
335     server_info->port = (uint16) port;
336   }
337   else if (!strcmp(name, "servertype")) {
338     if (server_info->server_type) return SILC_CONFIG_EDOUBLE;
339     server_info->server_type = strdup((char *) val);
340   }
341   else if (!strcmp(name, "admin")) {
342     if (server_info->admin) return SILC_CONFIG_EDOUBLE;
343     server_info->admin = strdup((char *) val);
344   }
345   else if (!strcmp(name, "adminemail")) {
346     if (server_info->email) return SILC_CONFIG_EDOUBLE;
347     server_info->email = strdup((char *) val);
348   }
349   else if (!strcmp(name, "location")) {
350     if (server_info->location) return SILC_CONFIG_EDOUBLE;
351     server_info->location = strdup((char *) val);
352   }
353   else if (!strcmp(name, "user")) {
354     if (server_info->user) return SILC_CONFIG_EDOUBLE;
355     server_info->user = strdup((char *) val);
356   }
357   else if (!strcmp(name, "group")) {
358     if (server_info->group) return SILC_CONFIG_EDOUBLE;
359     server_info->group = strdup((char *) val);
360   }
361   else if (!strcmp(name, "motdfile")) {
362     if (server_info->motd_file) return SILC_CONFIG_EDOUBLE;
363     server_info->motd_file = strdup((char *) val);
364   }
365   else if (!strcmp(name, "pidfile")) {
366     if (server_info->pid_file) return SILC_CONFIG_EDOUBLE;
367     server_info->pid_file = strdup((char *) val);
368   }
369   else if (!strcmp(name, "publickey")) {
370     char *tmp = (char *) val;
371
372     /* try to load specified file, if fail stop config parsing */
373     if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
374                                    SILC_PKCS_FILE_PEM))
375       if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
376                                      SILC_PKCS_FILE_BIN)) {
377         fprintf(stderr, "\nError: Could not load public key file.");
378         fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
379         return SILC_CONFIG_ESILENT;
380       }
381   }
382   else if (!strcmp(name, "privatekey")) {
383     char *tmp = (char *) val;
384
385     /* try to load specified file, if fail stop config parsing */
386     if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
387                                     SILC_PKCS_FILE_BIN))
388       if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
389                                       SILC_PKCS_FILE_PEM)) {
390         fprintf(stderr, "\nError: Could not load private key file.");
391         fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
392         return SILC_CONFIG_ESILENT;
393       }
394   }
395   else
396     return SILC_CONFIG_EINTERNAL;
397   return SILC_CONFIG_OK;
398 }
399
400 SILC_CONFIG_CALLBACK(fetch_logging)
401 {
402   SilcServerConfig config = (SilcServerConfig) context;
403   SilcServerConfigSectionLogging *tmp =
404         (SilcServerConfigSectionLogging *) config->tmp;
405   int got_errno;
406
407   if (!strcmp(name, "quicklogs")) {
408     silc_log_quick = *(bool *)val;
409   }
410   else if (!strcmp(name, "flushdelay")) {
411     int flushdelay = *(int *)val;
412     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
413       fprintf(stderr, "Error: line %lu: invalid flushdelay value, use "
414                 "quicklogs if you want real-time logging.\n", line);
415       return SILC_CONFIG_ESILENT;
416     }
417     silc_log_flushdelay = (long) flushdelay;
418   }
419 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
420   else if (!strcmp(name, __chan__)) {                           \
421     if (!tmp) return SILC_CONFIG_OK;                            \
422     if (!tmp->file) {                                           \
423       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
424     }                                                           \
425     config->__member__ = tmp;                                   \
426     config->tmp = NULL;                                         \
427   }
428   FETCH_LOGGING_CHAN("info", logging_info)
429   FETCH_LOGGING_CHAN("warnings", logging_warnings)
430   FETCH_LOGGING_CHAN("errors", logging_errors)
431   FETCH_LOGGING_CHAN("fatals", logging_fatals)
432 #undef FETCH_LOGGING_CHAN
433   else if (!strcmp(name, "file")) {
434     if (!tmp) { /* FIXME: what the fuck is this? */
435       config->tmp = silc_calloc(1, sizeof(*tmp));
436       tmp = (SilcServerConfigSectionLogging *) config->tmp;
437     }
438     if (tmp->file) {
439       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
440     }
441     tmp->file = strdup((char *) val);
442   }
443   else if (!strcmp(name, "size")) {
444     if (!tmp) {
445       config->tmp = silc_calloc(1, sizeof(*tmp));
446       tmp = (SilcServerConfigSectionLogging *) config->tmp;
447     }
448     tmp->maxsize = *(uint32 *) val;
449   }
450   else
451     return SILC_CONFIG_EINTERNAL;
452   return SILC_CONFIG_OK;
453
454  got_err:
455   silc_free(tmp->file);
456   silc_free(tmp);
457   config->tmp = NULL;
458   return got_errno;
459 }
460
461 SILC_CONFIG_CALLBACK(fetch_client)
462 {
463   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient);
464
465   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", 
466                        type, name, context));
467
468   if (type == SILC_CONFIG_ARG_BLOCK) {
469     if (!tmp) /* empty sub-block? */
470       return SILC_CONFIG_OK;
471
472     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
473     config->tmp = NULL;
474     return SILC_CONFIG_OK;
475   }
476
477   /* if there isn't a temporary struct alloc one */
478   if (!tmp) {
479     config->tmp = silc_calloc(1, sizeof(*findtmp));
480     tmp = (SilcServerConfigSectionClient *) config->tmp;
481   }
482
483   /* Identify and save this value */
484   if (!strcmp(name, "host")) { /* any host (*) accepted */
485     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
486     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
487   }
488   else if (!strcmp(name, "passphrase")) {
489     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
490                            (void **)&tmp->passphrase, 
491                            &tmp->passphrase_len)) {
492       got_errno = SILC_CONFIG_ESILENT;
493       goto got_err;
494     }
495   }
496   else if (!strcmp(name, "publickey")) {
497     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
498                            &tmp->publickey, NULL)) {
499       got_errno = SILC_CONFIG_ESILENT;
500       goto got_err;
501     }
502   }
503   else if (!strcmp(name, "port")) {
504     int port = *(int *)val;
505     if ((port <= 0) || (port > 65535)) {
506       fprintf(stderr, "Invalid port number!\n");
507       got_errno = SILC_CONFIG_ESILENT; goto got_err;
508     }
509     tmp->port = (uint16) port;
510   }
511   /* FIXME: Improvement: use a direct class struct pointer instead of num */
512   else if (!strcmp(name, "class")) {
513     /* XXX do nothing */
514   }
515   else
516     return SILC_CONFIG_EINTERNAL;
517   return SILC_CONFIG_OK;
518
519  got_err:
520   silc_free(tmp->host);
521   my_free_authdata(tmp->passphrase, tmp->publickey);
522   silc_free(tmp);
523   return got_errno;
524 }
525
526 SILC_CONFIG_CALLBACK(fetch_admin)
527 {
528   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin);
529
530   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", 
531                        type, name, context));
532
533   if (type == SILC_CONFIG_ARG_BLOCK) {
534     /* check the temporary struct's fields */
535     if (!tmp) /* empty sub-block? */
536       return SILC_CONFIG_OK;
537
538     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
539     config->tmp = NULL;
540     return SILC_CONFIG_OK;
541   }
542
543   /* if there isn't a temporary struct alloc one */
544   if (!tmp) {
545     config->tmp = silc_calloc(1, sizeof(*findtmp));
546     tmp = (SilcServerConfigSectionAdmin *) config->tmp;
547   }
548
549   /* Identify and save this value */
550   if (!strcmp(name, "host")) { /* any host (*) accepted */
551     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
552     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
553   }
554   else if (!strcmp(name, "user")) {
555     if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
556     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
557   }
558   else if (!strcmp(name, "nick")) {
559     if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
560     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
561   }
562   else if (!strcmp(name, "passphrase")) {
563     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
564                            (void **)&tmp->passphrase, 
565                            &tmp->passphrase_len)) {
566       got_errno = SILC_CONFIG_ESILENT;
567       goto got_err;
568     }
569   }
570   else if (!strcmp(name, "publickey")) {
571     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
572                            &tmp->publickey, NULL)) {
573       got_errno = SILC_CONFIG_ESILENT;
574       goto got_err;
575     }
576   }
577   else
578     return SILC_CONFIG_EINTERNAL;
579   return SILC_CONFIG_OK;
580
581  got_err:
582   silc_free(tmp->host);
583   silc_free(tmp->user);
584   silc_free(tmp->nick);
585   my_free_authdata(tmp->passphrase, tmp->publickey);
586   silc_free(tmp);
587   return got_errno;
588 }
589
590 SILC_CONFIG_CALLBACK(fetch_deny)
591 {
592   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny);
593
594   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", 
595                        type, name, context));
596   if (type == SILC_CONFIG_ARG_BLOCK) {
597     /* check the temporary struct's fields */
598     if (!tmp) /* empty sub-block? */
599       return SILC_CONFIG_OK;
600     if (!tmp->reason) {
601       got_errno = SILC_CONFIG_EMISSFIELDS;
602       goto got_err;
603     }
604     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
605     config->tmp = NULL;
606     return SILC_CONFIG_OK;
607   }
608   /* if there isn't a temporary struct alloc one */
609   if (!tmp) {
610     config->tmp = silc_calloc(1, sizeof(*findtmp));
611     tmp = (SilcServerConfigSectionDeny *) config->tmp;
612   }
613
614   /* Identify and save this value */
615   if (!strcmp(name, "host")) { /* any host (*) accepted */
616     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
617     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
618   }
619   else if (!strcmp(name, "port")) {
620     int port = *(int *)val;
621     if ((port <= 0) || (port > 65535)) {
622       fprintf(stderr, "Invalid port number!\n");
623       got_errno = SILC_CONFIG_ESILENT; goto got_err;
624     }
625     tmp->port = (uint16) port;
626   }
627   else if (!strcmp(name, "reason")) {
628     if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
629     tmp->reason = strdup((char *) val);
630   }
631   else
632     return SILC_CONFIG_EINTERNAL;
633   return SILC_CONFIG_OK;
634
635  got_err:
636   silc_free(tmp->host);
637   silc_free(tmp->reason);
638   silc_free(tmp);
639   return got_errno;
640 }
641
642 SILC_CONFIG_CALLBACK(fetch_server)
643 {
644   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer);
645
646   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", 
647                        type, name, context));
648
649   if (type == SILC_CONFIG_ARG_BLOCK) {
650     /* check the temporary struct's fields */
651     if (!tmp) /* empty sub-block? */
652       return SILC_CONFIG_OK;
653
654     /* the temporary struct is ok, append it to the list */
655     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
656     config->tmp = NULL;
657     return SILC_CONFIG_OK;
658   }
659
660   /* if there isn't a temporary struct alloc one */
661   if (!tmp) {
662     config->tmp = silc_calloc(1, sizeof(*findtmp));
663     tmp = (SilcServerConfigSectionServer *) config->tmp;
664   }
665
666   /* Identify and save this value */
667   if (!strcmp(name, "host")) { /* any host (*) accepted */
668     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
669     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
670   }
671   else if (!strcmp(name, "passphrase")) {
672     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
673                            (void **)&tmp->passphrase, 
674                            &tmp->passphrase_len)) {
675       got_errno = SILC_CONFIG_ESILENT;
676       goto got_err;
677     }
678   }
679   else if (!strcmp(name, "publickey")) {
680     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
681                            &tmp->publickey, NULL)) {
682       got_errno = SILC_CONFIG_ESILENT;
683       goto got_err;
684     }
685   }
686   else if (!strcmp(name, "versionid")) {
687     if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
688     tmp->version = strdup((char *) val);
689   }
690   /* FIXME: Improvement: use a direct class struct pointer instead of num */
691   else if (!strcmp(name, "class")) {
692     /* XXX do nothing */
693   }
694   else if (!strcmp(name, "backup")) {
695     tmp->backup_router = *(bool *)val;
696   }
697   else
698     return SILC_CONFIG_EINTERNAL;
699
700   return SILC_CONFIG_OK;
701
702  got_err:
703   silc_free(tmp->host);
704   silc_free(tmp->version);
705   my_free_authdata(tmp->passphrase, tmp->publickey);
706   silc_free(tmp);
707   return got_errno;
708 }
709
710 SILC_CONFIG_CALLBACK(fetch_router)
711 {
712   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionRouter);
713
714   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", 
715                        type, name, context));
716
717   if (type == SILC_CONFIG_ARG_BLOCK) {
718     if (!tmp) /* empty sub-block? */
719       return SILC_CONFIG_OK;
720
721     /* the temporary struct is ok, append it to the list */
722     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
723     config->tmp = NULL;
724     return SILC_CONFIG_OK;
725   }
726
727   /* if there isn't a temporary struct alloc one */
728   if (!tmp) {
729     config->tmp = silc_calloc(1, sizeof(*findtmp));
730     tmp = (SilcServerConfigSectionRouter *) config->tmp;
731   }
732
733   /* Identify and save this value */
734   if (!strcmp(name, "host")) {
735     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
736     tmp->host = strdup((char *) val);
737   }
738   else if (!strcmp(name, "port")) {
739     int port = *(int *)val;
740     if ((port <= 0) || (port > 65535)) {
741       fprintf(stderr, "Invalid port number!\n");
742       return SILC_CONFIG_ESILENT;
743     }
744     tmp->port = (uint16) port;
745   }
746   else if (!strcmp(name, "passphrase")) {
747     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
748                            (void **)&tmp->passphrase, 
749                            &tmp->passphrase_len)) {
750       got_errno = SILC_CONFIG_ESILENT;
751       goto got_err;
752     }
753   }
754   else if (!strcmp(name, "publickey")) {
755     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
756                            &tmp->publickey, NULL)) {
757       got_errno = SILC_CONFIG_ESILENT;
758       goto got_err;
759     }
760   }
761   else if (!strcmp(name, "versionid")) {
762     if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
763     tmp->version = strdup((char *) val);
764   }
765   /* FIXME: Improvement: use a direct class struct pointer instead of num */
766   else if (!strcmp(name, "class")) {
767     /* XXX do nothing */
768   }
769   else if (!strcmp(name, "initiator"))
770     tmp->initiator = *(bool *)val;
771   else if (!strcmp(name, "backuphost")) {
772     if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
773     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
774   }
775   else
776     return SILC_CONFIG_EINTERNAL;
777
778   return SILC_CONFIG_OK;
779
780  got_err:
781   silc_free(tmp->host);
782   silc_free(tmp->version);
783   silc_free(tmp->backup_replace_ip);
784   my_free_authdata(tmp->passphrase, tmp->publickey);
785   silc_free(tmp);
786   return got_errno;
787 }
788
789 /* known config options tables */
790 static const SilcConfigTable table_general[] = {
791   { "module_path",      SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
792   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
793   { 0, 0, 0, 0 }
794 };
795
796 static const SilcConfigTable table_cipher[] = {
797   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
798   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
799   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
800   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
801   { 0, 0, 0, 0 }
802 };
803
804 static const SilcConfigTable table_hash[] = {
805   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
806   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
807   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
808   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
809   { 0, 0, 0, 0 }
810 };
811
812 static const SilcConfigTable table_hmac[] = {
813   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
814   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
815   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
816   { 0, 0, 0, 0 }
817 };
818
819 static const SilcConfigTable table_pkcs[] = {
820   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
821   { 0, 0, 0, 0 }
822 };
823
824 static const SilcConfigTable table_serverinfo[] = {
825   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
826   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
827   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
828   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
829   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
830   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
831   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
832   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
833   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
834   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
835   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
836   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
837   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
838   { 0, 0, 0, 0 }
839 };
840
841 static const SilcConfigTable table_logging_c[] = {
842   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
843   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
844 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
845   { 0, 0, 0, 0 }
846 };
847
848 static const SilcConfigTable table_logging[] = {
849   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
850   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
851   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
852   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
853   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
854   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
855   { 0, 0, 0, 0 }
856 };
857
858 /* still unsupported
859 static const SilcConfigTable table_class[] = {
860   { "name",             SILC_CONFIG_ARG_STR,    fetch_class,    NULL },
861   { "ping",             SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
862   { "connect",          SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
863   { "links",            SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
864   { 0, 0, 0, 0 }
865 }; */
866
867 static const SilcConfigTable table_client[] = {
868   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
869   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
870   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
871   { "port",             SILC_CONFIG_ARG_INT,    fetch_client,   NULL },
872   { "class",            SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
873   { 0, 0, 0, 0 }
874 };
875
876 static const SilcConfigTable table_admin[] = {
877   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
878   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
879   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
880   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
881   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
882   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
883   { "class",            SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
884   { 0, 0, 0, 0 }
885 };
886
887 static const SilcConfigTable table_deny[] = {
888   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
889   { "port",             SILC_CONFIG_ARG_INT,    fetch_deny,     NULL },
890   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
891   { 0, 0, 0, 0 }
892 };
893
894 static const SilcConfigTable table_serverconn[] = {
895   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
896   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
897   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
898   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
899   { "class",            SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
900   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
901   { 0, 0, 0, 0 }
902 };
903
904 static const SilcConfigTable table_routerconn[] = {
905   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
906   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
907   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
908   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
909   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
910   { "class",            SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
911   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
912   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
913   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
914   { "localbackup",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
915   { 0, 0, 0, 0 }
916 };
917
918 static const SilcConfigTable table_main[] = {
919   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,           table_general },
920   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,   table_cipher },
921   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,     table_hash },
922   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,     table_hmac },
923   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,     table_pkcs },
924   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
925   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,           table_logging },
926 /*{ "class",            SILC_CONFIG_ARG_BLOCK,  fetch_class,    table_class }, */
927   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,   table_client },
928   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,    table_admin },
929   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,     table_deny },
930   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,   table_serverconn },
931   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,   table_routerconn },
932   { 0, 0, 0, 0 }
933 };
934
935 /* Allocates a new configuration object, opens configuration file and
936  * parses it. The parsed data is returned to the newly allocated
937  * configuration object. */
938
939 SilcServerConfig silc_server_config_alloc(char *filename)
940 {
941   SilcServerConfig config;
942   SilcConfigEntity ent;
943   SilcConfigFile *file;
944   int ret;
945   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
946
947   /* alloc a config object */
948   config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
949   /* obtain a config file object */
950   file = silc_config_open(filename);
951   if (!file) {
952     fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
953     return NULL;
954   }
955   /* obtain a SilcConfig entity, we can use it to start the parsing */
956   ent = silc_config_init(file);
957   /* load the known configuration options, give our empty object as context */
958   silc_config_register_table(ent, table_main, (void *) config);
959   /* enter the main parsing loop.  When this returns, we have the parsing
960    * result and the object filled (or partially, in case of errors). */
961   ret = silc_config_main(ent);
962   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, silc_config_strerror(ret)));
963
964   /* Check if the parser returned errors */
965   if (ret) {
966     /* handle this special error return which asks to quietly return */
967     if (ret != SILC_CONFIG_ESILENT) {
968       char *linebuf, *filename = silc_config_get_filename(file);
969       uint32 line = silc_config_get_line(file);
970       fprintf(stderr, "\nError while parsing config file: %s.\n",
971                 silc_config_strerror(ret));
972       linebuf = silc_config_read_line(file, line);
973       fprintf(stderr, "  file %s line %lu:  %s\n\n", filename, line, linebuf);
974       silc_free(linebuf);
975     }
976     return NULL;
977   }
978   /* close (destroy) the file object */
979   silc_config_close(file);
980
981   /* XXX FIXME: check for missing mandatory fields */
982   if (!config->server_info) {
983     fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
984     return NULL;
985   }
986   return config;
987 }
988
989 /* ... */
990
991 void silc_server_config_destroy(SilcServerConfig config)
992 {
993   void *tmp;
994   silc_free(config->module_path);
995
996   /* Destroy Logging channels */
997   if (config->logging_info)
998     silc_free(config->logging_info->file);
999   if (config->logging_warnings)
1000     silc_free(config->logging_warnings->file);
1001   if (config->logging_errors)
1002     silc_free(config->logging_errors->file);
1003   if (config->logging_fatals)
1004     silc_free(config->logging_fatals->file);
1005
1006   /* Destroy the ServerInfo struct */
1007   if (config->server_info) {
1008     register SilcServerConfigSectionServerInfo *si = config->server_info;
1009     silc_free(si->server_name);
1010     silc_free(si->server_ip);
1011     silc_free(si->server_type);
1012     silc_free(si->location);
1013     silc_free(si->admin);
1014     silc_free(si->email);
1015     silc_free(si->user);
1016     silc_free(si->group);
1017     silc_free(si->motd_file);
1018     silc_free(si->pid_file);
1019   }
1020
1021   /* Now let's destroy the lists */
1022
1023   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher,
1024                                   config->cipher)
1025     silc_free(di->name);
1026     silc_free(di->module);
1027     silc_free(di);
1028   }
1029   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHash, config->hash)
1030     silc_free(di->name);
1031     silc_free(di->module);
1032     silc_free(di);
1033   }
1034   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHmac, config->hmac)
1035     silc_free(di->name);
1036     silc_free(di->hash);
1037     silc_free(di);
1038   }
1039   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionPkcs, config->pkcs)
1040     silc_free(di->name);
1041     silc_free(di);
1042   }
1043   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionClient,
1044                                   config->clients)
1045     silc_free(di->host);
1046     my_free_authdata(di->passphrase, di->publickey);
1047     silc_free(di);
1048   }
1049   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins)
1050     silc_free(di->host);
1051     silc_free(di->user);
1052     silc_free(di->nick);
1053     my_free_authdata(di->passphrase, di->publickey);
1054     silc_free(di);
1055   }
1056   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied)
1057     silc_free(di->host);
1058     silc_free(di->reason);
1059     silc_free(di);
1060   }
1061   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer,
1062                                   config->servers)
1063     silc_free(di->host);
1064     silc_free(di->version);
1065     my_free_authdata(di->passphrase, di->publickey);
1066     silc_free(di);
1067   }
1068   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter,
1069                                   config->routers)
1070     silc_free(di->host);
1071     silc_free(di->version);
1072     silc_free(di->backup_replace_ip);
1073     my_free_authdata(di->passphrase, di->publickey);
1074     silc_free(di);
1075   }
1076 }
1077
1078 /* Registers configured ciphers. These can then be allocated by the
1079    server when needed. */
1080
1081 bool silc_server_config_register_ciphers(SilcServer server)
1082 {
1083   SilcServerConfig config = server->config;
1084   SilcServerConfigSectionCipher *cipher = config->cipher;
1085   char *module_path = config->module_path;
1086
1087   SILC_LOG_DEBUG(("Registering configured ciphers"));
1088
1089   if (!cipher) /* any cipher in the config file? */
1090     return FALSE;
1091
1092   while (cipher) {
1093     /* if there isn't a module_path OR there isn't a module sim name try to
1094      * use buil-in functions */
1095     if (!module_path || !cipher->module) {
1096       int i;
1097       for (i = 0; silc_default_ciphers[i].name; i++)
1098         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1099           silc_cipher_register(&silc_default_ciphers[i]);
1100           break;
1101         }
1102       if (!silc_cipher_is_supported(cipher->name)) {
1103         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1104         silc_server_stop(server);
1105         exit(1);
1106       }
1107     } else {
1108 #ifdef SILC_SIM
1109       /* Load (try at least) the crypto SIM module */
1110       char buf[1023], *alg_name;
1111       SilcCipherObject cipher_obj;
1112       SilcSimContext *sim;
1113
1114       memset(&cipher_obj, 0, sizeof(cipher_obj));
1115       cipher_obj.name = cipher->name;
1116       cipher_obj.block_len = cipher->block_length;
1117       cipher_obj.key_len = cipher->key_length * 8;
1118
1119       /* build the libname */
1120       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1121                 cipher->module);
1122       sim = silc_sim_alloc();
1123       sim->type = SILC_SIM_CIPHER;
1124       sim->libname = buf;
1125
1126       alg_name = strdup(cipher->name);
1127       if (strchr(alg_name, '-'))
1128         *strchr(alg_name, '-') = '\0';
1129
1130       if (silc_sim_load(sim)) {
1131         cipher_obj.set_key =
1132           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1133                                                 SILC_CIPHER_SIM_SET_KEY));
1134         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1135         cipher_obj.set_key_with_string =
1136           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1137                                                 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1138         SILC_LOG_DEBUG(("set_key_with_string=%p", cipher_obj.set_key_with_string));
1139         cipher_obj.encrypt =
1140           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1141                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1142         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1143         cipher_obj.decrypt =
1144           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1145                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1146         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1147         cipher_obj.context_len =
1148           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1149                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1150         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1151
1152         /* Put the SIM to the list of all SIM's in server */
1153         silc_dlist_add(server->sim, sim);
1154
1155         silc_free(alg_name);
1156       } else {
1157         SILC_LOG_ERROR(("Error configuring ciphers"));
1158         silc_server_stop(server);
1159         exit(1);
1160       }
1161
1162       /* Register the cipher */
1163       silc_cipher_register(&cipher_obj);
1164 #else
1165       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1166                         "can't load modules!"));
1167       silc_server_stop(server);
1168       exit(1);
1169 #endif
1170     }
1171     cipher = cipher->next;
1172   } /* while */
1173
1174   return TRUE;
1175 }
1176
1177 /* Registers configured hash functions. These can then be allocated by the
1178    server when needed. */
1179
1180 bool silc_server_config_register_hashfuncs(SilcServer server)
1181 {
1182   SilcServerConfig config = server->config;
1183   SilcServerConfigSectionHash *hash = config->hash;
1184   char *module_path = config->module_path;
1185
1186   SILC_LOG_DEBUG(("Registering configured hash functions"));
1187
1188   if (!hash) /* any hash func in the config file? */
1189     return FALSE;
1190
1191   while (hash) {
1192     /* if there isn't a module_path OR there isn't a module sim name try to
1193      * use buil-in functions */
1194     if (!module_path || !hash->module) {
1195       int i;
1196       for (i = 0; silc_default_hash[i].name; i++)
1197         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1198           silc_hash_register(&silc_default_hash[i]);
1199           break;
1200         }
1201       if (!silc_hash_is_supported(hash->name)) {
1202         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1203         silc_server_stop(server);
1204         exit(1);
1205       }
1206     } else {
1207 #ifdef SILC_SIM
1208       /* Load (try at least) the hash SIM module */
1209       SilcHashObject hash_obj;
1210       SilcSimContext *sim;
1211
1212       memset(&hash_obj, 0, sizeof(hash_obj));
1213       hash_obj.name = hash->name;
1214       hash_obj.block_len = hash->block_length;
1215       hash_obj.hash_len = hash->digest_length;
1216
1217       sim = silc_sim_alloc();
1218       sim->type = SILC_SIM_HASH;
1219       sim->libname = hash->module;
1220
1221       if ((silc_sim_load(sim))) {
1222         hash_obj.init =
1223           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1224                                                 SILC_HASH_SIM_INIT));
1225         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1226         hash_obj.update =
1227           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1228                                                 SILC_HASH_SIM_UPDATE));
1229         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1230         hash_obj.final =
1231           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1232                                                 SILC_HASH_SIM_FINAL));
1233         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1234         hash_obj.context_len =
1235           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1236                                                 SILC_HASH_SIM_CONTEXT_LEN));
1237         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1238
1239         /* Put the SIM to the table of all SIM's in server */
1240         silc_dlist_add(server->sim, sim);
1241       } else {
1242         SILC_LOG_ERROR(("Error configuring hash functions"));
1243         silc_server_stop(server);
1244         exit(1);
1245       }
1246
1247       /* Register the hash function */
1248       silc_hash_register(&hash_obj);
1249 #else
1250       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1251                         "can't load modules!"));
1252       silc_server_stop(server);
1253       exit(1);
1254 #endif
1255     }
1256     hash = hash->next;
1257   } /* while */
1258
1259   return TRUE;
1260 }
1261
1262 /* Registers configure HMACs. These can then be allocated by the server
1263    when needed. */
1264
1265 bool silc_server_config_register_hmacs(SilcServer server)
1266 {
1267   SilcServerConfig config = server->config;
1268   SilcServerConfigSectionHmac *hmac = config->hmac;
1269
1270   SILC_LOG_DEBUG(("Registering configured HMACs"));
1271
1272   if (!hmac)
1273     return FALSE;
1274
1275   while (hmac) {
1276     SilcHmacObject hmac_obj;
1277     if (!silc_hash_is_supported(hmac->hash)) {
1278       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1279       silc_server_stop(server);
1280       exit(1);
1281     }
1282     /* Register the HMAC */
1283     memset(&hmac_obj, 0, sizeof(hmac_obj));
1284     hmac_obj.name = hmac->name;
1285     hmac_obj.len = hmac->mac_length;
1286     silc_hmac_register(&hmac_obj);
1287
1288     hmac = hmac->next;
1289   } /* while */
1290
1291   return TRUE;
1292 }
1293
1294 /* Registers configured PKCS's. */
1295
1296 bool silc_server_config_register_pkcs(SilcServer server)
1297 {
1298   SilcServerConfig config = server->config;
1299   SilcServerConfigSectionPkcs *pkcs = config->pkcs;
1300
1301   SILC_LOG_DEBUG(("Registering configured PKCS"));
1302
1303   if (!pkcs)
1304     return FALSE;
1305
1306   while (pkcs) {
1307     int i;
1308     for (i = 0; silc_default_pkcs[i].name; i++)
1309       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1310         silc_pkcs_register(&silc_default_pkcs[i]);
1311         break;
1312       }
1313     if (!silc_pkcs_is_supported(pkcs->name)) {
1314       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1315       silc_server_stop(server);
1316       exit(1);
1317     }
1318     pkcs = pkcs->next;
1319   } /* while */
1320
1321   return TRUE;
1322 }
1323
1324 /* Sets log files where log messages are saved by the server logger. */
1325
1326 void silc_server_config_setlogfiles(SilcServer server)
1327 {
1328   SilcServerConfig config = server->config;
1329   SilcServerConfigSectionLogging *this;
1330
1331   SILC_LOG_DEBUG(("Setting configured log file names"));
1332
1333   if ((this = config->logging_info))
1334     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, 
1335                       server->schedule);
1336   if ((this = config->logging_warnings))
1337     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, 
1338                       server->schedule);
1339   if ((this = config->logging_errors))
1340     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1341                       server->schedule);
1342   if ((this = config->logging_fatals))
1343     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, 
1344                       server->schedule);
1345 }
1346
1347 /* Returns client authentication information from configuration file by host
1348    (name or ip) */
1349
1350 SilcServerConfigSectionClient *
1351 silc_server_config_find_client(SilcServer server, char *host, int port)
1352 {
1353   SilcServerConfig config = server->config;
1354   SilcServerConfigSectionClient *client;
1355
1356   if (!config || !port) {
1357     SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, "
1358                       "host=0x%08x \"%s\", port=%hu)",
1359                       (uint32) config, (uint32) host, host, port));
1360     return NULL;
1361   }
1362   if (!host)
1363     return NULL;
1364
1365   for (client = config->clients; client; client = client->next) {
1366     if (client->host && !silc_string_compare(client->host, host))
1367       continue;
1368     if (client->port && (client->port != port))
1369       continue;
1370     break;
1371   }
1372
1373   /* if none matched, then client is already NULL */
1374   return client;
1375 }
1376
1377 /* Returns admin connection configuration by host, username and/or
1378    nickname. */
1379
1380 SilcServerConfigSectionAdmin *
1381 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1382                               char *nick)
1383 {
1384   SilcServerConfig config = server->config;
1385   SilcServerConfigSectionAdmin *admin;
1386
1387   /* make sure we have a value for the matching parameters */
1388   if (!host)
1389     host = "*";
1390   if (!user)
1391     user = "*";
1392   if (!nick)
1393     nick = "*";
1394
1395   for (admin = config->admins; admin; admin = admin->next) {
1396     if (admin->host && !silc_string_compare(admin->host, host))
1397       continue;
1398     if (admin->user && !silc_string_compare(admin->user, user))
1399       continue;
1400     if (admin->nick && !silc_string_compare(admin->nick, nick))
1401       continue;
1402     /* no checks failed -> this entry matches */
1403     break;
1404   }
1405
1406   /* if none matched, then admin is already NULL */
1407   return admin;
1408 }
1409
1410 /* Returns the denied connection configuration entry by host and port. */
1411
1412 SilcServerConfigSectionDeny *
1413 silc_server_config_find_denied(SilcServer server, char *host, uint16 port)
1414 {
1415   SilcServerConfig config = server->config;
1416   SilcServerConfigSectionDeny *deny;
1417
1418   /* make sure we have a value for the matching parameters */
1419   if (!config || !port) {
1420     SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, "
1421                       "host=0x%08x \"%s\", port=%hu)",
1422                       (uint32) config, (uint32) host, host, port));
1423     return NULL;
1424   }
1425   if (!host)
1426     return NULL;
1427
1428   for (deny = config->denied; deny; deny = deny->next) {
1429     if (deny->host && !silc_string_compare(deny->host, host))
1430       continue;
1431     break;
1432   }
1433
1434   /* if none matched, then deny is already NULL */
1435   return deny;
1436 }
1437
1438 /* Returns server connection info from server configuartion by host
1439    (name or ip). */
1440
1441 SilcServerConfigSectionServer *
1442 silc_server_config_find_server_conn(SilcServer server, char *host)
1443 {
1444   SilcServerConfig config = server->config;
1445   SilcServerConfigSectionServer *serv = NULL;
1446
1447   if (!host)
1448     return NULL;
1449
1450   if (!config->servers)
1451     return NULL;
1452
1453   for (serv = config->servers; serv; serv = serv->next) {
1454     if (!silc_string_compare(serv->host, host))
1455       continue;
1456     break;
1457   }
1458
1459   return serv;
1460 }
1461
1462 /* Returns router connection info from server configuration by
1463    host (name or ip). */
1464
1465 SilcServerConfigSectionRouter *
1466 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1467 {
1468   SilcServerConfig config = server->config;
1469   SilcServerConfigSectionRouter *serv = NULL;
1470
1471   if (!host)
1472     return NULL;
1473
1474   if (!config->routers)
1475     return NULL;
1476
1477   for (serv = config->routers; serv; serv = serv->next) {
1478     if (!silc_string_compare(serv->host, host))
1479       continue;
1480     if (port && serv->port && serv->port != port)
1481       continue;
1482     break;
1483   }
1484
1485   return serv;
1486 }
1487
1488 /* Returns TRUE if configuration for a router connection that we are
1489    initiating exists. */
1490
1491 bool silc_server_config_is_primary_route(SilcServer server)
1492 {
1493   SilcServerConfig config = server->config;
1494   SilcServerConfigSectionRouter *serv = NULL;
1495   int i;
1496   bool found = FALSE;
1497
1498   serv = config->routers;
1499   for (i = 0; serv; i++) {
1500     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1501       found = TRUE;
1502       break;
1503     }
1504
1505     serv = serv->next;
1506   }
1507
1508   return found;
1509 }
1510
1511 /* Returns our primary connection configuration or NULL if we do not
1512    have primary router configured. */
1513
1514 SilcServerConfigSectionRouter *
1515 silc_server_config_get_primary_router(SilcServer server)
1516 {
1517   SilcServerConfig config = server->config;
1518   SilcServerConfigSectionRouter *serv = NULL;
1519   int i;
1520
1521   serv = config->routers;
1522   for (i = 0; serv; i++) {
1523     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1524       return serv;
1525     serv = serv->next;
1526   }
1527
1528   return NULL;
1529 }