fixed a crashing bug in silcd/serverconfig.c
[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   config->tmp = NULL;
524   return got_errno;
525 }
526
527 SILC_CONFIG_CALLBACK(fetch_admin)
528 {
529   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin);
530
531   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", 
532                        type, name, context));
533
534   if (type == SILC_CONFIG_ARG_BLOCK) {
535     /* check the temporary struct's fields */
536     if (!tmp) /* empty sub-block? */
537       return SILC_CONFIG_OK;
538
539     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
540     config->tmp = NULL;
541     return SILC_CONFIG_OK;
542   }
543
544   /* if there isn't a temporary struct alloc one */
545   if (!tmp) {
546     config->tmp = silc_calloc(1, sizeof(*findtmp));
547     tmp = (SilcServerConfigSectionAdmin *) config->tmp;
548   }
549
550   /* Identify and save this value */
551   if (!strcmp(name, "host")) { /* any host (*) accepted */
552     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
553     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
554   }
555   else if (!strcmp(name, "user")) {
556     if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
557     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
558   }
559   else if (!strcmp(name, "nick")) {
560     if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
561     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
562   }
563   else if (!strcmp(name, "passphrase")) {
564     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
565                            (void **)&tmp->passphrase, 
566                            &tmp->passphrase_len)) {
567       got_errno = SILC_CONFIG_ESILENT;
568       goto got_err;
569     }
570   }
571   else if (!strcmp(name, "publickey")) {
572     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
573                            &tmp->publickey, NULL)) {
574       got_errno = SILC_CONFIG_ESILENT;
575       goto got_err;
576     }
577   }
578   else
579     return SILC_CONFIG_EINTERNAL;
580   return SILC_CONFIG_OK;
581
582  got_err:
583   silc_free(tmp->host);
584   silc_free(tmp->user);
585   silc_free(tmp->nick);
586   my_free_authdata(tmp->passphrase, tmp->publickey);
587   silc_free(tmp);
588   config->tmp = NULL;
589   return got_errno;
590 }
591
592 SILC_CONFIG_CALLBACK(fetch_deny)
593 {
594   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny);
595
596   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", 
597                        type, name, context));
598   if (type == SILC_CONFIG_ARG_BLOCK) {
599     /* check the temporary struct's fields */
600     if (!tmp) /* empty sub-block? */
601       return SILC_CONFIG_OK;
602     if (!tmp->reason) {
603       got_errno = SILC_CONFIG_EMISSFIELDS;
604       goto got_err;
605     }
606     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
607     config->tmp = NULL;
608     return SILC_CONFIG_OK;
609   }
610   /* if there isn't a temporary struct alloc one */
611   if (!tmp) {
612     config->tmp = silc_calloc(1, sizeof(*findtmp));
613     tmp = (SilcServerConfigSectionDeny *) config->tmp;
614   }
615
616   /* Identify and save this value */
617   if (!strcmp(name, "host")) { /* any host (*) accepted */
618     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
619     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
620   }
621   else if (!strcmp(name, "port")) {
622     int port = *(int *)val;
623     if ((port <= 0) || (port > 65535)) {
624       fprintf(stderr, "Invalid port number!\n");
625       got_errno = SILC_CONFIG_ESILENT; goto got_err;
626     }
627     tmp->port = (uint16) port;
628   }
629   else if (!strcmp(name, "reason")) {
630     if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
631     tmp->reason = strdup((char *) val);
632   }
633   else
634     return SILC_CONFIG_EINTERNAL;
635   return SILC_CONFIG_OK;
636
637  got_err:
638   silc_free(tmp->host);
639   silc_free(tmp->reason);
640   silc_free(tmp);
641   config->tmp = NULL;
642   return got_errno;
643 }
644
645 SILC_CONFIG_CALLBACK(fetch_server)
646 {
647   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer);
648
649   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", 
650                        type, name, context));
651
652   if (type == SILC_CONFIG_ARG_BLOCK) {
653     /* check the temporary struct's fields */
654     if (!tmp) /* empty sub-block? */
655       return SILC_CONFIG_OK;
656
657     /* the temporary struct is ok, append it to the list */
658     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
659     config->tmp = NULL;
660     return SILC_CONFIG_OK;
661   }
662
663   /* if there isn't a temporary struct alloc one */
664   if (!tmp) {
665     config->tmp = silc_calloc(1, sizeof(*findtmp));
666     tmp = (SilcServerConfigSectionServer *) config->tmp;
667   }
668
669   /* Identify and save this value */
670   if (!strcmp(name, "host")) { /* any host (*) accepted */
671     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
672     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
673   }
674   else if (!strcmp(name, "passphrase")) {
675     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
676                            (void **)&tmp->passphrase, 
677                            &tmp->passphrase_len)) {
678       got_errno = SILC_CONFIG_ESILENT;
679       goto got_err;
680     }
681   }
682   else if (!strcmp(name, "publickey")) {
683     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
684                            &tmp->publickey, NULL)) {
685       got_errno = SILC_CONFIG_ESILENT;
686       goto got_err;
687     }
688   }
689   else if (!strcmp(name, "versionid")) {
690     if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
691     tmp->version = strdup((char *) val);
692   }
693   /* FIXME: Improvement: use a direct class struct pointer instead of num */
694   else if (!strcmp(name, "class")) {
695     /* XXX do nothing */
696   }
697   else if (!strcmp(name, "backup")) {
698     tmp->backup_router = *(bool *)val;
699   }
700   else
701     return SILC_CONFIG_EINTERNAL;
702
703   return SILC_CONFIG_OK;
704
705  got_err:
706   silc_free(tmp->host);
707   silc_free(tmp->version);
708   my_free_authdata(tmp->passphrase, tmp->publickey);
709   silc_free(tmp);
710   config->tmp = NULL;
711   return got_errno;
712 }
713
714 SILC_CONFIG_CALLBACK(fetch_router)
715 {
716   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionRouter);
717
718   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", 
719                        type, name, context));
720
721   if (type == SILC_CONFIG_ARG_BLOCK) {
722     if (!tmp) /* empty sub-block? */
723       return SILC_CONFIG_OK;
724
725     /* the temporary struct is ok, append it to the list */
726     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
727     config->tmp = NULL;
728     return SILC_CONFIG_OK;
729   }
730
731   /* if there isn't a temporary struct alloc one */
732   if (!tmp) {
733     config->tmp = silc_calloc(1, sizeof(*findtmp));
734     tmp = (SilcServerConfigSectionRouter *) config->tmp;
735   }
736
737   /* Identify and save this value */
738   if (!strcmp(name, "host")) {
739     if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
740     tmp->host = strdup((char *) val);
741   }
742   else if (!strcmp(name, "port")) {
743     int port = *(int *)val;
744     if ((port <= 0) || (port > 65535)) {
745       fprintf(stderr, "Invalid port number!\n");
746       return SILC_CONFIG_ESILENT;
747     }
748     tmp->port = (uint16) port;
749   }
750   else if (!strcmp(name, "passphrase")) {
751     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
752                            (void **)&tmp->passphrase, 
753                            &tmp->passphrase_len)) {
754       got_errno = SILC_CONFIG_ESILENT;
755       goto got_err;
756     }
757   }
758   else if (!strcmp(name, "publickey")) {
759     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
760                            &tmp->publickey, NULL)) {
761       got_errno = SILC_CONFIG_ESILENT;
762       goto got_err;
763     }
764   }
765   else if (!strcmp(name, "versionid")) {
766     if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
767     tmp->version = strdup((char *) val);
768   }
769   /* FIXME: Improvement: use a direct class struct pointer instead of num */
770   else if (!strcmp(name, "class")) {
771     /* XXX do nothing */
772   }
773   else if (!strcmp(name, "initiator"))
774     tmp->initiator = *(bool *)val;
775   else if (!strcmp(name, "backuphost")) {
776     if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
777     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
778   }
779   else
780     return SILC_CONFIG_EINTERNAL;
781
782   return SILC_CONFIG_OK;
783
784  got_err:
785   silc_free(tmp->host);
786   silc_free(tmp->version);
787   silc_free(tmp->backup_replace_ip);
788   my_free_authdata(tmp->passphrase, tmp->publickey);
789   silc_free(tmp);
790   config->tmp = NULL;
791   return got_errno;
792 }
793
794 /* known config options tables */
795 static const SilcConfigTable table_general[] = {
796   { "module_path",      SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
797   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
798   { 0, 0, 0, 0 }
799 };
800
801 static const SilcConfigTable table_cipher[] = {
802   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
803   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
804   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
805   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
806   { 0, 0, 0, 0 }
807 };
808
809 static const SilcConfigTable table_hash[] = {
810   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
811   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
812   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
813   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
814   { 0, 0, 0, 0 }
815 };
816
817 static const SilcConfigTable table_hmac[] = {
818   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
819   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
820   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
821   { 0, 0, 0, 0 }
822 };
823
824 static const SilcConfigTable table_pkcs[] = {
825   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
826   { 0, 0, 0, 0 }
827 };
828
829 static const SilcConfigTable table_serverinfo[] = {
830   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
831   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
832   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
833   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
834   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
835   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
836   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
837   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
838   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
839   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
840   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
841   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
842   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
843   { 0, 0, 0, 0 }
844 };
845
846 static const SilcConfigTable table_logging_c[] = {
847   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
848   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
849 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
850   { 0, 0, 0, 0 }
851 };
852
853 static const SilcConfigTable table_logging[] = {
854   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
855   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
856   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
857   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
858   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
859   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
860   { 0, 0, 0, 0 }
861 };
862
863 /* still unsupported
864 static const SilcConfigTable table_class[] = {
865   { "name",             SILC_CONFIG_ARG_STR,    fetch_class,    NULL },
866   { "ping",             SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
867   { "connect",          SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
868   { "links",            SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
869   { 0, 0, 0, 0 }
870 }; */
871
872 static const SilcConfigTable table_client[] = {
873   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
874   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
875   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
876   { "port",             SILC_CONFIG_ARG_INT,    fetch_client,   NULL },
877   { "class",            SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
878   { 0, 0, 0, 0 }
879 };
880
881 static const SilcConfigTable table_admin[] = {
882   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
883   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
884   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
885   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
886   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
887   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
888   { "class",            SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
889   { 0, 0, 0, 0 }
890 };
891
892 static const SilcConfigTable table_deny[] = {
893   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
894   { "port",             SILC_CONFIG_ARG_INT,    fetch_deny,     NULL },
895   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
896   { 0, 0, 0, 0 }
897 };
898
899 static const SilcConfigTable table_serverconn[] = {
900   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
901   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
902   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
903   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
904   { "class",            SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
905   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
906   { 0, 0, 0, 0 }
907 };
908
909 static const SilcConfigTable table_routerconn[] = {
910   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
911   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
912   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
913   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
914   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
915   { "class",            SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
916   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
917   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
918   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
919   { "localbackup",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
920   { 0, 0, 0, 0 }
921 };
922
923 static const SilcConfigTable table_main[] = {
924   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,           table_general },
925   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,   table_cipher },
926   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,     table_hash },
927   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,     table_hmac },
928   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,     table_pkcs },
929   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
930   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,           table_logging },
931 /*{ "class",            SILC_CONFIG_ARG_BLOCK,  fetch_class,    table_class }, */
932   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,   table_client },
933   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,    table_admin },
934   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,     table_deny },
935   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,   table_serverconn },
936   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,   table_routerconn },
937   { 0, 0, 0, 0 }
938 };
939
940 /* Allocates a new configuration object, opens configuration file and
941  * parses it. The parsed data is returned to the newly allocated
942  * configuration object. */
943
944 SilcServerConfig silc_server_config_alloc(char *filename)
945 {
946   SilcServerConfig config;
947   SilcConfigEntity ent;
948   SilcConfigFile *file;
949   int ret;
950   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
951
952   /* alloc a config object */
953   config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
954   /* obtain a config file object */
955   file = silc_config_open(filename);
956   if (!file) {
957     fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
958     return NULL;
959   }
960   /* obtain a SilcConfig entity, we can use it to start the parsing */
961   ent = silc_config_init(file);
962   /* load the known configuration options, give our empty object as context */
963   silc_config_register_table(ent, table_main, (void *) config);
964   /* enter the main parsing loop.  When this returns, we have the parsing
965    * result and the object filled (or partially, in case of errors). */
966   ret = silc_config_main(ent);
967   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, silc_config_strerror(ret)));
968
969   /* Check if the parser returned errors */
970   if (ret) {
971     /* handle this special error return which asks to quietly return */
972     if (ret != SILC_CONFIG_ESILENT) {
973       char *linebuf, *filename = silc_config_get_filename(file);
974       uint32 line = silc_config_get_line(file);
975       fprintf(stderr, "\nError while parsing config file: %s.\n",
976                 silc_config_strerror(ret));
977       linebuf = silc_config_read_line(file, line);
978       fprintf(stderr, "  file %s line %lu:  %s\n\n", filename, line, linebuf);
979       silc_free(linebuf);
980     }
981     return NULL;
982   }
983   /* close (destroy) the file object */
984   silc_config_close(file);
985
986   /* XXX FIXME: check for missing mandatory fields */
987   if (!config->server_info) {
988     fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
989     return NULL;
990   }
991   return config;
992 }
993
994 /* ... */
995
996 void silc_server_config_destroy(SilcServerConfig config)
997 {
998   void *tmp;
999   silc_free(config->module_path);
1000
1001   /* Destroy Logging channels */
1002   if (config->logging_info)
1003     silc_free(config->logging_info->file);
1004   if (config->logging_warnings)
1005     silc_free(config->logging_warnings->file);
1006   if (config->logging_errors)
1007     silc_free(config->logging_errors->file);
1008   if (config->logging_fatals)
1009     silc_free(config->logging_fatals->file);
1010
1011   /* Destroy the ServerInfo struct */
1012   if (config->server_info) {
1013     register SilcServerConfigSectionServerInfo *si = config->server_info;
1014     silc_free(si->server_name);
1015     silc_free(si->server_ip);
1016     silc_free(si->server_type);
1017     silc_free(si->location);
1018     silc_free(si->admin);
1019     silc_free(si->email);
1020     silc_free(si->user);
1021     silc_free(si->group);
1022     silc_free(si->motd_file);
1023     silc_free(si->pid_file);
1024   }
1025
1026   /* Now let's destroy the lists */
1027
1028   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher,
1029                                   config->cipher)
1030     silc_free(di->name);
1031     silc_free(di->module);
1032     silc_free(di);
1033   }
1034   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHash, config->hash)
1035     silc_free(di->name);
1036     silc_free(di->module);
1037     silc_free(di);
1038   }
1039   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHmac, config->hmac)
1040     silc_free(di->name);
1041     silc_free(di->hash);
1042     silc_free(di);
1043   }
1044   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionPkcs, config->pkcs)
1045     silc_free(di->name);
1046     silc_free(di);
1047   }
1048   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionClient,
1049                                   config->clients)
1050     silc_free(di->host);
1051     my_free_authdata(di->passphrase, di->publickey);
1052     silc_free(di);
1053   }
1054   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins)
1055     silc_free(di->host);
1056     silc_free(di->user);
1057     silc_free(di->nick);
1058     my_free_authdata(di->passphrase, di->publickey);
1059     silc_free(di);
1060   }
1061   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied)
1062     silc_free(di->host);
1063     silc_free(di->reason);
1064     silc_free(di);
1065   }
1066   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer,
1067                                   config->servers)
1068     silc_free(di->host);
1069     silc_free(di->version);
1070     my_free_authdata(di->passphrase, di->publickey);
1071     silc_free(di);
1072   }
1073   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter,
1074                                   config->routers)
1075     silc_free(di->host);
1076     silc_free(di->version);
1077     silc_free(di->backup_replace_ip);
1078     my_free_authdata(di->passphrase, di->publickey);
1079     silc_free(di);
1080   }
1081 }
1082
1083 /* Registers configured ciphers. These can then be allocated by the
1084    server when needed. */
1085
1086 bool silc_server_config_register_ciphers(SilcServer server)
1087 {
1088   SilcServerConfig config = server->config;
1089   SilcServerConfigSectionCipher *cipher = config->cipher;
1090   char *module_path = config->module_path;
1091
1092   SILC_LOG_DEBUG(("Registering configured ciphers"));
1093
1094   if (!cipher) /* any cipher in the config file? */
1095     return FALSE;
1096
1097   while (cipher) {
1098     /* if there isn't a module_path OR there isn't a module sim name try to
1099      * use buil-in functions */
1100     if (!module_path || !cipher->module) {
1101       int i;
1102       for (i = 0; silc_default_ciphers[i].name; i++)
1103         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1104           silc_cipher_register(&silc_default_ciphers[i]);
1105           break;
1106         }
1107       if (!silc_cipher_is_supported(cipher->name)) {
1108         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1109         silc_server_stop(server);
1110         exit(1);
1111       }
1112     } else {
1113 #ifdef SILC_SIM
1114       /* Load (try at least) the crypto SIM module */
1115       char buf[1023], *alg_name;
1116       SilcCipherObject cipher_obj;
1117       SilcSimContext *sim;
1118
1119       memset(&cipher_obj, 0, sizeof(cipher_obj));
1120       cipher_obj.name = cipher->name;
1121       cipher_obj.block_len = cipher->block_length;
1122       cipher_obj.key_len = cipher->key_length * 8;
1123
1124       /* build the libname */
1125       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1126                 cipher->module);
1127       sim = silc_sim_alloc();
1128       sim->type = SILC_SIM_CIPHER;
1129       sim->libname = buf;
1130
1131       alg_name = strdup(cipher->name);
1132       if (strchr(alg_name, '-'))
1133         *strchr(alg_name, '-') = '\0';
1134
1135       if (silc_sim_load(sim)) {
1136         cipher_obj.set_key =
1137           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1138                                                 SILC_CIPHER_SIM_SET_KEY));
1139         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1140         cipher_obj.set_key_with_string =
1141           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1142                                                 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1143         SILC_LOG_DEBUG(("set_key_with_string=%p", cipher_obj.set_key_with_string));
1144         cipher_obj.encrypt =
1145           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1146                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1147         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1148         cipher_obj.decrypt =
1149           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1150                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1151         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1152         cipher_obj.context_len =
1153           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1154                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1155         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1156
1157         /* Put the SIM to the list of all SIM's in server */
1158         silc_dlist_add(server->sim, sim);
1159
1160         silc_free(alg_name);
1161       } else {
1162         SILC_LOG_ERROR(("Error configuring ciphers"));
1163         silc_server_stop(server);
1164         exit(1);
1165       }
1166
1167       /* Register the cipher */
1168       silc_cipher_register(&cipher_obj);
1169 #else
1170       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1171                         "can't load modules!"));
1172       silc_server_stop(server);
1173       exit(1);
1174 #endif
1175     }
1176     cipher = cipher->next;
1177   } /* while */
1178
1179   return TRUE;
1180 }
1181
1182 /* Registers configured hash functions. These can then be allocated by the
1183    server when needed. */
1184
1185 bool silc_server_config_register_hashfuncs(SilcServer server)
1186 {
1187   SilcServerConfig config = server->config;
1188   SilcServerConfigSectionHash *hash = config->hash;
1189   char *module_path = config->module_path;
1190
1191   SILC_LOG_DEBUG(("Registering configured hash functions"));
1192
1193   if (!hash) /* any hash func in the config file? */
1194     return FALSE;
1195
1196   while (hash) {
1197     /* if there isn't a module_path OR there isn't a module sim name try to
1198      * use buil-in functions */
1199     if (!module_path || !hash->module) {
1200       int i;
1201       for (i = 0; silc_default_hash[i].name; i++)
1202         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1203           silc_hash_register(&silc_default_hash[i]);
1204           break;
1205         }
1206       if (!silc_hash_is_supported(hash->name)) {
1207         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1208         silc_server_stop(server);
1209         exit(1);
1210       }
1211     } else {
1212 #ifdef SILC_SIM
1213       /* Load (try at least) the hash SIM module */
1214       SilcHashObject hash_obj;
1215       SilcSimContext *sim;
1216
1217       memset(&hash_obj, 0, sizeof(hash_obj));
1218       hash_obj.name = hash->name;
1219       hash_obj.block_len = hash->block_length;
1220       hash_obj.hash_len = hash->digest_length;
1221
1222       sim = silc_sim_alloc();
1223       sim->type = SILC_SIM_HASH;
1224       sim->libname = hash->module;
1225
1226       if ((silc_sim_load(sim))) {
1227         hash_obj.init =
1228           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1229                                                 SILC_HASH_SIM_INIT));
1230         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1231         hash_obj.update =
1232           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1233                                                 SILC_HASH_SIM_UPDATE));
1234         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1235         hash_obj.final =
1236           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1237                                                 SILC_HASH_SIM_FINAL));
1238         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1239         hash_obj.context_len =
1240           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1241                                                 SILC_HASH_SIM_CONTEXT_LEN));
1242         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1243
1244         /* Put the SIM to the table of all SIM's in server */
1245         silc_dlist_add(server->sim, sim);
1246       } else {
1247         SILC_LOG_ERROR(("Error configuring hash functions"));
1248         silc_server_stop(server);
1249         exit(1);
1250       }
1251
1252       /* Register the hash function */
1253       silc_hash_register(&hash_obj);
1254 #else
1255       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1256                         "can't load modules!"));
1257       silc_server_stop(server);
1258       exit(1);
1259 #endif
1260     }
1261     hash = hash->next;
1262   } /* while */
1263
1264   return TRUE;
1265 }
1266
1267 /* Registers configure HMACs. These can then be allocated by the server
1268    when needed. */
1269
1270 bool silc_server_config_register_hmacs(SilcServer server)
1271 {
1272   SilcServerConfig config = server->config;
1273   SilcServerConfigSectionHmac *hmac = config->hmac;
1274
1275   SILC_LOG_DEBUG(("Registering configured HMACs"));
1276
1277   if (!hmac)
1278     return FALSE;
1279
1280   while (hmac) {
1281     SilcHmacObject hmac_obj;
1282     if (!silc_hash_is_supported(hmac->hash)) {
1283       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1284       silc_server_stop(server);
1285       exit(1);
1286     }
1287     /* Register the HMAC */
1288     memset(&hmac_obj, 0, sizeof(hmac_obj));
1289     hmac_obj.name = hmac->name;
1290     hmac_obj.len = hmac->mac_length;
1291     silc_hmac_register(&hmac_obj);
1292
1293     hmac = hmac->next;
1294   } /* while */
1295
1296   return TRUE;
1297 }
1298
1299 /* Registers configured PKCS's. */
1300
1301 bool silc_server_config_register_pkcs(SilcServer server)
1302 {
1303   SilcServerConfig config = server->config;
1304   SilcServerConfigSectionPkcs *pkcs = config->pkcs;
1305
1306   SILC_LOG_DEBUG(("Registering configured PKCS"));
1307
1308   if (!pkcs)
1309     return FALSE;
1310
1311   while (pkcs) {
1312     int i;
1313     for (i = 0; silc_default_pkcs[i].name; i++)
1314       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1315         silc_pkcs_register(&silc_default_pkcs[i]);
1316         break;
1317       }
1318     if (!silc_pkcs_is_supported(pkcs->name)) {
1319       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1320       silc_server_stop(server);
1321       exit(1);
1322     }
1323     pkcs = pkcs->next;
1324   } /* while */
1325
1326   return TRUE;
1327 }
1328
1329 /* Sets log files where log messages are saved by the server logger. */
1330
1331 void silc_server_config_setlogfiles(SilcServer server)
1332 {
1333   SilcServerConfig config = server->config;
1334   SilcServerConfigSectionLogging *this;
1335
1336   SILC_LOG_DEBUG(("Setting configured log file names"));
1337
1338   if ((this = config->logging_info))
1339     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, 
1340                       server->schedule);
1341   if ((this = config->logging_warnings))
1342     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, 
1343                       server->schedule);
1344   if ((this = config->logging_errors))
1345     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1346                       server->schedule);
1347   if ((this = config->logging_fatals))
1348     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, 
1349                       server->schedule);
1350 }
1351
1352 /* Returns client authentication information from configuration file by host
1353    (name or ip) */
1354
1355 SilcServerConfigSectionClient *
1356 silc_server_config_find_client(SilcServer server, char *host, int port)
1357 {
1358   SilcServerConfig config = server->config;
1359   SilcServerConfigSectionClient *client;
1360
1361   if (!config || !port) {
1362     SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, "
1363                       "host=0x%08x \"%s\", port=%hu)",
1364                       (uint32) config, (uint32) host, host, port));
1365     return NULL;
1366   }
1367   if (!host)
1368     return NULL;
1369
1370   for (client = config->clients; client; client = client->next) {
1371     if (client->host && !silc_string_compare(client->host, host))
1372       continue;
1373     if (client->port && (client->port != port))
1374       continue;
1375     break;
1376   }
1377
1378   /* if none matched, then client is already NULL */
1379   return client;
1380 }
1381
1382 /* Returns admin connection configuration by host, username and/or
1383    nickname. */
1384
1385 SilcServerConfigSectionAdmin *
1386 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1387                               char *nick)
1388 {
1389   SilcServerConfig config = server->config;
1390   SilcServerConfigSectionAdmin *admin;
1391
1392   /* make sure we have a value for the matching parameters */
1393   if (!host)
1394     host = "*";
1395   if (!user)
1396     user = "*";
1397   if (!nick)
1398     nick = "*";
1399
1400   for (admin = config->admins; admin; admin = admin->next) {
1401     if (admin->host && !silc_string_compare(admin->host, host))
1402       continue;
1403     if (admin->user && !silc_string_compare(admin->user, user))
1404       continue;
1405     if (admin->nick && !silc_string_compare(admin->nick, nick))
1406       continue;
1407     /* no checks failed -> this entry matches */
1408     break;
1409   }
1410
1411   /* if none matched, then admin is already NULL */
1412   return admin;
1413 }
1414
1415 /* Returns the denied connection configuration entry by host and port. */
1416
1417 SilcServerConfigSectionDeny *
1418 silc_server_config_find_denied(SilcServer server, char *host, uint16 port)
1419 {
1420   SilcServerConfig config = server->config;
1421   SilcServerConfigSectionDeny *deny;
1422
1423   /* make sure we have a value for the matching parameters */
1424   if (!config || !port) {
1425     SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, "
1426                       "host=0x%08x \"%s\", port=%hu)",
1427                       (uint32) config, (uint32) host, host, port));
1428     return NULL;
1429   }
1430   if (!host)
1431     return NULL;
1432
1433   for (deny = config->denied; deny; deny = deny->next) {
1434     if (deny->host && !silc_string_compare(deny->host, host))
1435       continue;
1436     break;
1437   }
1438
1439   /* if none matched, then deny is already NULL */
1440   return deny;
1441 }
1442
1443 /* Returns server connection info from server configuartion by host
1444    (name or ip). */
1445
1446 SilcServerConfigSectionServer *
1447 silc_server_config_find_server_conn(SilcServer server, char *host)
1448 {
1449   SilcServerConfig config = server->config;
1450   SilcServerConfigSectionServer *serv = NULL;
1451
1452   if (!host)
1453     return NULL;
1454
1455   if (!config->servers)
1456     return NULL;
1457
1458   for (serv = config->servers; serv; serv = serv->next) {
1459     if (!silc_string_compare(serv->host, host))
1460       continue;
1461     break;
1462   }
1463
1464   return serv;
1465 }
1466
1467 /* Returns router connection info from server configuration by
1468    host (name or ip). */
1469
1470 SilcServerConfigSectionRouter *
1471 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1472 {
1473   SilcServerConfig config = server->config;
1474   SilcServerConfigSectionRouter *serv = NULL;
1475
1476   if (!host)
1477     return NULL;
1478
1479   if (!config->routers)
1480     return NULL;
1481
1482   for (serv = config->routers; serv; serv = serv->next) {
1483     if (!silc_string_compare(serv->host, host))
1484       continue;
1485     if (port && serv->port && serv->port != port)
1486       continue;
1487     break;
1488   }
1489
1490   return serv;
1491 }
1492
1493 /* Returns TRUE if configuration for a router connection that we are
1494    initiating exists. */
1495
1496 bool silc_server_config_is_primary_route(SilcServer server)
1497 {
1498   SilcServerConfig config = server->config;
1499   SilcServerConfigSectionRouter *serv = NULL;
1500   int i;
1501   bool found = FALSE;
1502
1503   serv = config->routers;
1504   for (i = 0; serv; i++) {
1505     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1506       found = TRUE;
1507       break;
1508     }
1509
1510     serv = serv->next;
1511   }
1512
1513   return found;
1514 }
1515
1516 /* Returns our primary connection configuration or NULL if we do not
1517    have primary router configured. */
1518
1519 SilcServerConfigSectionRouter *
1520 silc_server_config_get_primary_router(SilcServer server)
1521 {
1522   SilcServerConfig config = server->config;
1523   SilcServerConfigSectionRouter *serv = NULL;
1524   int i;
1525
1526   serv = config->routers;
1527   for (i = 0; serv; i++) {
1528     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1529       return serv;
1530     serv = serv->next;
1531   }
1532
1533   return NULL;
1534 }