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