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