Integer type name change.
[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, SilcUInt32 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, SilcUInt32 line,
110                               void **auth_data, SilcUInt32 *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 = (SilcUInt32) 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 = (SilcUInt32) *(int *)val;
159   }
160   else if (!strcmp(name, "connections_max_per_host")) {
161     config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
162   }
163   else if (!strcmp(name, "keepalive_secs")) {
164     config->param.keepalive_secs = (SilcUInt32) *(int *)val;
165   }
166   else if (!strcmp(name, "reconnect_count")) {
167     config->param.reconnect_count = (SilcUInt32) *(int *)val;
168   }
169   else if (!strcmp(name, "reconnect_interval")) {
170     config->param.reconnect_interval = (SilcUInt32) *(int *)val;
171   }
172   else if (!strcmp(name, "reconnect_interval_max")) {
173     config->param.reconnect_interval_max = (SilcUInt32) *(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 = (SilcUInt32) *(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 = (SilcUInt32) *(int *)val;
186   }
187   else if (!strcmp(name, "key_exchange_timeout")) {
188     config->key_exchange_timeout = (SilcUInt32) *(int *)val;
189   }
190   else if (!strcmp(name, "conn_auth_timeout")) {
191     config->conn_auth_timeout = (SilcUInt32) *(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 = *(SilcUInt32 *)val;
238   }
239   else if (!strcmp(name, "blocklength")) {
240     tmp->block_length = *(SilcUInt32 *)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 = (SilcUInt16) 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 = *(SilcUInt32 *) 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 = *(SilcUInt32 *)val;
591   }
592   else if (!strcmp(name, "connections_max_per_host")) {
593     tmp->connections_max_per_host = *(SilcUInt32 *)val;
594   }
595   else if (!strcmp(name, "keepalive_secs")) {
596     tmp->keepalive_secs = *(SilcUInt32 *)val;
597   }
598   else if (!strcmp(name, "reconnect_count")) {
599     tmp->reconnect_count = *(SilcUInt32 *)val;
600   }
601   else if (!strcmp(name, "reconnect_interval")) {
602     tmp->reconnect_interval = *(SilcUInt32 *)val;
603   }
604   else if (!strcmp(name, "reconnect_interval_max")) {
605     tmp->reconnect_interval_max = *(SilcUInt32 *)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 = *(SilcUInt32 *)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, "reason")) {
783     CONFIG_IS_DOUBLE(tmp->reason);
784     tmp->reason = strdup((char *) val);
785   }
786   else
787     return SILC_CONFIG_EINTERNAL;
788   return SILC_CONFIG_OK;
789
790  got_err:
791   silc_free(tmp->host);
792   silc_free(tmp->reason);
793   silc_free(tmp);
794   config->tmp = NULL;
795   return got_errno;
796 }
797
798 SILC_CONFIG_CALLBACK(fetch_server)
799 {
800   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
801
802   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
803                        type, name, context));
804
805   if (type == SILC_CONFIG_ARG_BLOCK) {
806     /* check the temporary struct's fields */
807     if (!tmp) /* empty sub-block? */
808       return SILC_CONFIG_OK;
809
810     /* the temporary struct is ok, append it to the list */
811     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
812     config->tmp = NULL;
813     return SILC_CONFIG_OK;
814   }
815
816   /* if there isn't a temporary struct alloc one */
817   if (!tmp) {
818     config->tmp = silc_calloc(1, sizeof(*findtmp));
819     tmp = (SilcServerConfigServer *) config->tmp;
820   }
821
822   /* Identify and save this value */
823   if (!strcmp(name, "host")) {
824     CONFIG_IS_DOUBLE(tmp->host);
825     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
826   }
827   else if (!strcmp(name, "passphrase")) {
828     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
829                            (void **)&tmp->passphrase,
830                            &tmp->passphrase_len)) {
831       got_errno = SILC_CONFIG_ESILENT;
832       goto got_err;
833     }
834   }
835   else if (!strcmp(name, "publickey")) {
836     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
837                            &tmp->publickey, NULL)) {
838       got_errno = SILC_CONFIG_ESILENT;
839       goto got_err;
840     }
841   }
842   else if (!strcmp(name, "versionid")) {
843     CONFIG_IS_DOUBLE(tmp->version);
844     tmp->version = strdup((char *) val);
845   }
846   else if (!strcmp(name, "params")) {
847     CONFIG_IS_DOUBLE(tmp->param);
848     tmp->param = my_find_param(config, (char *) val, line);
849     if (!tmp->param) { /* error already output */
850       got_errno = SILC_CONFIG_ESILENT;
851       goto got_err;
852     }
853   }
854   else if (!strcmp(name, "backup")) {
855     tmp->backup_router = *(bool *)val;
856   }
857   else
858     return SILC_CONFIG_EINTERNAL;
859
860   return SILC_CONFIG_OK;
861
862  got_err:
863   silc_free(tmp->host);
864   silc_free(tmp->version);
865   CONFIG_FREE_AUTH(tmp);
866   silc_free(tmp);
867   config->tmp = NULL;
868   return got_errno;
869 }
870
871 SILC_CONFIG_CALLBACK(fetch_router)
872 {
873   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
874
875   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
876                        type, name, context));
877
878   if (type == SILC_CONFIG_ARG_BLOCK) {
879     if (!tmp) /* empty sub-block? */
880       return SILC_CONFIG_OK;
881
882     /* the temporary struct is ok, append it to the list */
883     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
884     config->tmp = NULL;
885     return SILC_CONFIG_OK;
886   }
887
888   /* if there isn't a temporary struct alloc one */
889   if (!tmp) {
890     config->tmp = silc_calloc(1, sizeof(*findtmp));
891     tmp = (SilcServerConfigRouter *) config->tmp;
892   }
893
894   /* Identify and save this value */
895   if (!strcmp(name, "host")) {
896     CONFIG_IS_DOUBLE(tmp->host);
897     tmp->host = strdup((char *) val);
898   }
899   else if (!strcmp(name, "port")) {
900     int port = *(int *)val;
901     if ((port <= 0) || (port > 65535)) {
902       fprintf(stderr, "Invalid port number!\n");
903       return SILC_CONFIG_ESILENT;
904     }
905     tmp->port = (SilcUInt16) port;
906   }
907   else if (!strcmp(name, "passphrase")) {
908     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
909                            (void **)&tmp->passphrase,
910                            &tmp->passphrase_len)) {
911       got_errno = SILC_CONFIG_ESILENT;
912       goto got_err;
913     }
914   }
915   else if (!strcmp(name, "publickey")) {
916     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
917                            &tmp->publickey, NULL)) {
918       got_errno = SILC_CONFIG_ESILENT;
919       goto got_err;
920     }
921   }
922   else if (!strcmp(name, "versionid")) {
923     CONFIG_IS_DOUBLE(tmp->version);
924     tmp->version = strdup((char *) val);
925   }
926   else if (!strcmp(name, "params")) {
927     CONFIG_IS_DOUBLE(tmp->param);
928     tmp->param = my_find_param(config, (char *) val, line);
929     if (!tmp->param) { /* error already output */
930       got_errno = SILC_CONFIG_ESILENT;
931       goto got_err;
932     }
933   }
934   else if (!strcmp(name, "initiator")) {
935     tmp->initiator = *(bool *)val;
936   }
937   else if (!strcmp(name, "backuphost")) {
938     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
939     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
940                               strdup("*"));
941   }
942   else if (!strcmp(name, "backupport")) {
943     int port = *(int *)val;
944     if ((port <= 0) || (port > 65535)) {
945       fprintf(stderr, "Invalid port number!\n");
946       return SILC_CONFIG_ESILENT;
947     }
948     tmp->backup_replace_port = (SilcUInt16) port;
949   }
950   else if (!strcmp(name, "backuplocal")) {
951     tmp->backup_local = *(bool *)val;
952   }
953   else
954     return SILC_CONFIG_EINTERNAL;
955
956   return SILC_CONFIG_OK;
957
958  got_err:
959   silc_free(tmp->host);
960   silc_free(tmp->version);
961   silc_free(tmp->backup_replace_ip);
962   CONFIG_FREE_AUTH(tmp);
963   silc_free(tmp);
964   config->tmp = NULL;
965   return got_errno;
966 }
967
968 /* known config options tables */
969 static const SilcConfigTable table_general[] = {
970   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
971   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
972   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
973   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
974   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
975   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
976   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
977   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
978   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
979   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
980   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
981   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
982   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
983   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
984   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
985   { 0, 0, 0, 0 }
986 };
987
988 static const SilcConfigTable table_cipher[] = {
989   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
990   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
991   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
992   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
993   { 0, 0, 0, 0 }
994 };
995
996 static const SilcConfigTable table_hash[] = {
997   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
998   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
999   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1000   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1001   { 0, 0, 0, 0 }
1002 };
1003
1004 static const SilcConfigTable table_hmac[] = {
1005   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1006   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1007   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1008   { 0, 0, 0, 0 }
1009 };
1010
1011 static const SilcConfigTable table_pkcs[] = {
1012   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1013   { 0, 0, 0, 0 }
1014 };
1015
1016 static const SilcConfigTable table_serverinfo[] = {
1017   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1018   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1019   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1020   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1021   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1022   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1023   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1024   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1025   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1026   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1027   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1028   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1029   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1030   { 0, 0, 0, 0 }
1031 };
1032
1033 static const SilcConfigTable table_logging_c[] = {
1034   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1035   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1036 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1037   { 0, 0, 0, 0 }
1038 };
1039
1040 static const SilcConfigTable table_logging[] = {
1041   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1042   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1043   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1044   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1045   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1046   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1047   { 0, 0, 0, 0 }
1048 };
1049
1050 static const SilcConfigTable table_connparam[] = {
1051   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1052   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1053   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1054   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1055   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1056   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1057   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1058   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1059   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1060   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1061   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1062   { 0, 0, 0, 0 }
1063 };
1064
1065 static const SilcConfigTable table_client[] = {
1066   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1067   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1068   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1069   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1070   { 0, 0, 0, 0 }
1071 };
1072
1073 static const SilcConfigTable table_admin[] = {
1074   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1075   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1076   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1077   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1078   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1079   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1080   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1081   { 0, 0, 0, 0 }
1082 };
1083
1084 static const SilcConfigTable table_deny[] = {
1085   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1086   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1087   { 0, 0, 0, 0 }
1088 };
1089
1090 static const SilcConfigTable table_serverconn[] = {
1091   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1092   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1093   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1094   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1095   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1096   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1097   { 0, 0, 0, 0 }
1098 };
1099
1100 static const SilcConfigTable table_routerconn[] = {
1101   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1102   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1103   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1104   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1105   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1106   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1107   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1108   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1109   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1110   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1111   { 0, 0, 0, 0 }
1112 };
1113
1114 static const SilcConfigTable table_main[] = {
1115   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1116   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1117   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1118   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1119   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1120   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1121   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1122   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1123   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1124   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1125   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1126   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1127   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1128   { 0, 0, 0, 0 }
1129 };
1130
1131 /* Allocates a new configuration object, opens configuration file and
1132  * parses it. The parsed data is returned to the newly allocated
1133  * configuration object. */
1134
1135 SilcServerConfig silc_server_config_alloc(char *filename)
1136 {
1137   SilcServerConfig config;
1138   SilcConfigEntity ent;
1139   SilcConfigFile *file;
1140   int ret;
1141   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1142
1143   /* alloc a config object */
1144   config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
1145   /* obtain a config file object */
1146   file = silc_config_open(filename);
1147   if (!file) {
1148     fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
1149     return NULL;
1150   }
1151   /* obtain a SilcConfig entity, we can use it to start the parsing */
1152   ent = silc_config_init(file);
1153   /* load the known configuration options, give our empty object as context */
1154   silc_config_register_table(ent, table_main, (void *) config);
1155   /* enter the main parsing loop.  When this returns, we have the parsing
1156    * result and the object filled (or partially, in case of errors). */
1157   ret = silc_config_main(ent);
1158   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, 
1159                   silc_config_strerror(ret)));
1160
1161   /* Check if the parser returned errors */
1162   if (ret) {
1163     /* handle this special error return which asks to quietly return */
1164     if (ret != SILC_CONFIG_ESILENT) {
1165       char *linebuf, *filename = silc_config_get_filename(file);
1166       SilcUInt32 line = silc_config_get_line(file);
1167       fprintf(stderr, "\nError while parsing config file: %s.\n",
1168                 silc_config_strerror(ret));
1169       linebuf = silc_config_read_line(file, line);
1170       fprintf(stderr, "  file %s line %lu:  %s\n\n", filename, line, linebuf);
1171       silc_free(linebuf);
1172     }
1173     return NULL;
1174   }
1175   /* close (destroy) the file object */
1176   silc_config_close(file);
1177
1178   /* XXX FIXME: check for missing mandatory fields */
1179   if (!config->server_info) {
1180     fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
1181     return NULL;
1182   }
1183   return config;
1184 }
1185
1186 /* ... */
1187
1188 void silc_server_config_destroy(SilcServerConfig config)
1189 {
1190   void *tmp;
1191   silc_free(config->module_path);
1192
1193   /* Destroy Logging channels */
1194   if (config->logging_info)
1195     silc_free(config->logging_info->file);
1196   if (config->logging_warnings)
1197     silc_free(config->logging_warnings->file);
1198   if (config->logging_errors)
1199     silc_free(config->logging_errors->file);
1200   if (config->logging_fatals)
1201     silc_free(config->logging_fatals->file);
1202
1203   /* Destroy the ServerInfo struct */
1204   if (config->server_info) {
1205     register SilcServerConfigServerInfo *si = config->server_info;
1206     silc_free(si->server_name);
1207     silc_free(si->server_ip);
1208     silc_free(si->server_type);
1209     silc_free(si->location);
1210     silc_free(si->admin);
1211     silc_free(si->email);
1212     silc_free(si->user);
1213     silc_free(si->group);
1214     silc_free(si->motd_file);
1215     silc_free(si->pid_file);
1216   }
1217
1218   /* Now let's destroy the lists */
1219
1220   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1221                                   config->cipher)
1222     silc_free(di->name);
1223     silc_free(di->module);
1224     silc_free(di);
1225   }
1226   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1227     silc_free(di->name);
1228     silc_free(di->module);
1229     silc_free(di);
1230   }
1231   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1232     silc_free(di->name);
1233     silc_free(di->hash);
1234     silc_free(di);
1235   }
1236   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1237     silc_free(di->name);
1238     silc_free(di);
1239   }
1240   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient,
1241                                   config->clients)
1242     silc_free(di->host);
1243     CONFIG_FREE_AUTH(di);
1244     silc_free(di);
1245   }
1246   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1247     silc_free(di->host);
1248     silc_free(di->user);
1249     silc_free(di->nick);
1250     CONFIG_FREE_AUTH(di);
1251     silc_free(di);
1252   }
1253   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1254     silc_free(di->host);
1255     silc_free(di->reason);
1256     silc_free(di);
1257   }
1258   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1259                                   config->servers)
1260     silc_free(di->host);
1261     silc_free(di->version);
1262     CONFIG_FREE_AUTH(di);
1263     silc_free(di);
1264   }
1265   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1266                                   config->routers)
1267     silc_free(di->host);
1268     silc_free(di->version);
1269     silc_free(di->backup_replace_ip);
1270     CONFIG_FREE_AUTH(di);
1271     silc_free(di);
1272   }
1273 }
1274
1275 /* Registers configured ciphers. These can then be allocated by the
1276    server when needed. */
1277
1278 bool silc_server_config_register_ciphers(SilcServer server)
1279 {
1280   SilcServerConfig config = server->config;
1281   SilcServerConfigCipher *cipher = config->cipher;
1282   char *module_path = config->module_path;
1283
1284   SILC_LOG_DEBUG(("Registering configured ciphers"));
1285
1286   if (!cipher) /* any cipher in the config file? */
1287     return FALSE;
1288
1289   while (cipher) {
1290     /* if there isn't a module_path OR there isn't a module sim name try to
1291      * use buil-in functions */
1292     if (!module_path || !cipher->module) {
1293       int i;
1294       for (i = 0; silc_default_ciphers[i].name; i++)
1295         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1296           silc_cipher_register(&silc_default_ciphers[i]);
1297           break;
1298         }
1299       if (!silc_cipher_is_supported(cipher->name)) {
1300         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1301         silc_server_stop(server);
1302         exit(1);
1303       }
1304     } else {
1305 #ifdef SILC_SIM
1306       /* Load (try at least) the crypto SIM module */
1307       char buf[1023], *alg_name;
1308       SilcCipherObject cipher_obj;
1309       SilcSimContext *sim;
1310
1311       memset(&cipher_obj, 0, sizeof(cipher_obj));
1312       cipher_obj.name = cipher->name;
1313       cipher_obj.block_len = cipher->block_length;
1314       cipher_obj.key_len = cipher->key_length * 8;
1315
1316       /* build the libname */
1317       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1318                 cipher->module);
1319       sim = silc_sim_alloc();
1320       sim->type = SILC_SIM_CIPHER;
1321       sim->libname = buf;
1322
1323       alg_name = strdup(cipher->name);
1324       if (strchr(alg_name, '-'))
1325         *strchr(alg_name, '-') = '\0';
1326
1327       if (silc_sim_load(sim)) {
1328         cipher_obj.set_key =
1329           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1330                                                 SILC_CIPHER_SIM_SET_KEY));
1331         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1332         cipher_obj.set_key_with_string =
1333           silc_sim_getsym(sim, 
1334             silc_sim_symname(alg_name,
1335               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1336         SILC_LOG_DEBUG(("set_key_with_string=%p", 
1337           cipher_obj.set_key_with_string));
1338         cipher_obj.encrypt =
1339           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1340                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1341         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1342         cipher_obj.decrypt =
1343           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1344                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1345         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1346         cipher_obj.context_len =
1347           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1348                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1349         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1350
1351         /* Put the SIM to the list of all SIM's in server */
1352         silc_dlist_add(server->sim, sim);
1353
1354         silc_free(alg_name);
1355       } else {
1356         SILC_LOG_ERROR(("Error configuring ciphers"));
1357         silc_server_stop(server);
1358         exit(1);
1359       }
1360
1361       /* Register the cipher */
1362       silc_cipher_register(&cipher_obj);
1363 #else
1364       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1365                         "can't load modules!"));
1366       silc_server_stop(server);
1367       exit(1);
1368 #endif
1369     }
1370     cipher = cipher->next;
1371   } /* while */
1372
1373   return TRUE;
1374 }
1375
1376 /* Registers configured hash functions. These can then be allocated by the
1377    server when needed. */
1378
1379 bool silc_server_config_register_hashfuncs(SilcServer server)
1380 {
1381   SilcServerConfig config = server->config;
1382   SilcServerConfigHash *hash = config->hash;
1383   char *module_path = config->module_path;
1384
1385   SILC_LOG_DEBUG(("Registering configured hash functions"));
1386
1387   if (!hash) /* any hash func in the config file? */
1388     return FALSE;
1389
1390   while (hash) {
1391     /* if there isn't a module_path OR there isn't a module sim name try to
1392      * use buil-in functions */
1393     if (!module_path || !hash->module) {
1394       int i;
1395       for (i = 0; silc_default_hash[i].name; i++)
1396         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1397           silc_hash_register(&silc_default_hash[i]);
1398           break;
1399         }
1400       if (!silc_hash_is_supported(hash->name)) {
1401         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1402         silc_server_stop(server);
1403         exit(1);
1404       }
1405     } else {
1406 #ifdef SILC_SIM
1407       /* Load (try at least) the hash SIM module */
1408       SilcHashObject hash_obj;
1409       SilcSimContext *sim;
1410
1411       memset(&hash_obj, 0, sizeof(hash_obj));
1412       hash_obj.name = hash->name;
1413       hash_obj.block_len = hash->block_length;
1414       hash_obj.hash_len = hash->digest_length;
1415
1416       sim = silc_sim_alloc();
1417       sim->type = SILC_SIM_HASH;
1418       sim->libname = hash->module;
1419
1420       if ((silc_sim_load(sim))) {
1421         hash_obj.init =
1422           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1423                                                 SILC_HASH_SIM_INIT));
1424         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1425         hash_obj.update =
1426           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1427                                                 SILC_HASH_SIM_UPDATE));
1428         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1429         hash_obj.final =
1430           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1431                                                 SILC_HASH_SIM_FINAL));
1432         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1433         hash_obj.context_len =
1434           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1435                                                 SILC_HASH_SIM_CONTEXT_LEN));
1436         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1437
1438         /* Put the SIM to the table of all SIM's in server */
1439         silc_dlist_add(server->sim, sim);
1440       } else {
1441         SILC_LOG_ERROR(("Error configuring hash functions"));
1442         silc_server_stop(server);
1443         exit(1);
1444       }
1445
1446       /* Register the hash function */
1447       silc_hash_register(&hash_obj);
1448 #else
1449       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1450                         "can't load modules!"));
1451       silc_server_stop(server);
1452       exit(1);
1453 #endif
1454     }
1455     hash = hash->next;
1456   } /* while */
1457
1458   return TRUE;
1459 }
1460
1461 /* Registers configure HMACs. These can then be allocated by the server
1462    when needed. */
1463
1464 bool silc_server_config_register_hmacs(SilcServer server)
1465 {
1466   SilcServerConfig config = server->config;
1467   SilcServerConfigHmac *hmac = config->hmac;
1468
1469   SILC_LOG_DEBUG(("Registering configured HMACs"));
1470
1471   if (!hmac)
1472     return FALSE;
1473
1474   while (hmac) {
1475     SilcHmacObject hmac_obj;
1476     if (!silc_hash_is_supported(hmac->hash)) {
1477       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1478       silc_server_stop(server);
1479       exit(1);
1480     }
1481     /* Register the HMAC */
1482     memset(&hmac_obj, 0, sizeof(hmac_obj));
1483     hmac_obj.name = hmac->name;
1484     hmac_obj.len = hmac->mac_length;
1485     silc_hmac_register(&hmac_obj);
1486
1487     hmac = hmac->next;
1488   } /* while */
1489
1490   return TRUE;
1491 }
1492
1493 /* Registers configured PKCS's. */
1494
1495 bool silc_server_config_register_pkcs(SilcServer server)
1496 {
1497   SilcServerConfig config = server->config;
1498   SilcServerConfigPkcs *pkcs = config->pkcs;
1499
1500   SILC_LOG_DEBUG(("Registering configured PKCS"));
1501
1502   if (!pkcs)
1503     return FALSE;
1504
1505   while (pkcs) {
1506     int i;
1507     for (i = 0; silc_default_pkcs[i].name; i++)
1508       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1509         silc_pkcs_register(&silc_default_pkcs[i]);
1510         break;
1511       }
1512     if (!silc_pkcs_is_supported(pkcs->name)) {
1513       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1514       silc_server_stop(server);
1515       exit(1);
1516     }
1517     pkcs = pkcs->next;
1518   } /* while */
1519
1520   return TRUE;
1521 }
1522
1523 /* Sets log files where log messages are saved by the server logger. */
1524
1525 void silc_server_config_setlogfiles(SilcServer server)
1526 {
1527   SilcServerConfig config = server->config;
1528   SilcServerConfigLogging *this;
1529
1530   SILC_LOG_DEBUG(("Setting configured log file names"));
1531
1532   if ((this = config->logging_info))
1533     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, 
1534                       server->schedule);
1535   if ((this = config->logging_warnings))
1536     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, 
1537                       server->schedule);
1538   if ((this = config->logging_errors))
1539     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1540                       server->schedule);
1541   if ((this = config->logging_fatals))
1542     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, 
1543                       server->schedule);
1544 }
1545
1546 /* Returns client authentication information from configuration file by host
1547    (name or ip) */
1548
1549 SilcServerConfigClient *
1550 silc_server_config_find_client(SilcServer server, char *host)
1551 {
1552   SilcServerConfig config = server->config;
1553   SilcServerConfigClient *client;
1554
1555   if (!config || !host)
1556     return NULL;
1557
1558   for (client = config->clients; client; client = client->next) {
1559     if (client->host && !silc_string_compare(client->host, host))
1560       continue;
1561     break;
1562   }
1563
1564   /* if none matched, then client is already NULL */
1565   return client;
1566 }
1567
1568 /* Returns admin connection configuration by host, username and/or
1569    nickname. */
1570
1571 SilcServerConfigAdmin *
1572 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1573                               char *nick)
1574 {
1575   SilcServerConfig config = server->config;
1576   SilcServerConfigAdmin *admin;
1577
1578   /* make sure we have a value for the matching parameters */
1579   if (!host)
1580     host = "*";
1581   if (!user)
1582     user = "*";
1583   if (!nick)
1584     nick = "*";
1585
1586   for (admin = config->admins; admin; admin = admin->next) {
1587     if (admin->host && !silc_string_compare(admin->host, host))
1588       continue;
1589     if (admin->user && !silc_string_compare(admin->user, user))
1590       continue;
1591     if (admin->nick && !silc_string_compare(admin->nick, nick))
1592       continue;
1593     /* no checks failed -> this entry matches */
1594     break;
1595   }
1596
1597   /* if none matched, then admin is already NULL */
1598   return admin;
1599 }
1600
1601 /* Returns the denied connection configuration entry by host. */
1602
1603 SilcServerConfigDeny *
1604 silc_server_config_find_denied(SilcServer server, char *host)
1605 {
1606   SilcServerConfig config = server->config;
1607   SilcServerConfigDeny *deny;
1608
1609   /* make sure we have a value for the matching parameters */
1610   if (!config || !host)
1611     return NULL;
1612
1613   for (deny = config->denied; deny; deny = deny->next) {
1614     if (deny->host && !silc_string_compare(deny->host, host))
1615       continue;
1616     break;
1617   }
1618
1619   /* if none matched, then deny is already NULL */
1620   return deny;
1621 }
1622
1623 /* Returns server connection info from server configuartion by host
1624    (name or ip). */
1625
1626 SilcServerConfigServer *
1627 silc_server_config_find_server_conn(SilcServer server, char *host)
1628 {
1629   SilcServerConfig config = server->config;
1630   SilcServerConfigServer *serv = NULL;
1631
1632   if (!host)
1633     return NULL;
1634
1635   if (!config->servers)
1636     return NULL;
1637
1638   for (serv = config->servers; serv; serv = serv->next) {
1639     if (!silc_string_compare(serv->host, host))
1640       continue;
1641     break;
1642   }
1643
1644   return serv;
1645 }
1646
1647 /* Returns router connection info from server configuration by
1648    host (name or ip). */
1649
1650 SilcServerConfigRouter *
1651 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1652 {
1653   SilcServerConfig config = server->config;
1654   SilcServerConfigRouter *serv = NULL;
1655
1656   if (!host)
1657     return NULL;
1658
1659   if (!config->routers)
1660     return NULL;
1661
1662   for (serv = config->routers; serv; serv = serv->next) {
1663     if (!silc_string_compare(serv->host, host))
1664       continue;
1665     if (port && serv->port && serv->port != port)
1666       continue;
1667     break;
1668   }
1669
1670   return serv;
1671 }
1672
1673 /* Returns TRUE if configuration for a router connection that we are
1674    initiating exists. */
1675
1676 bool silc_server_config_is_primary_route(SilcServer server)
1677 {
1678   SilcServerConfig config = server->config;
1679   SilcServerConfigRouter *serv = NULL;
1680   int i;
1681   bool found = FALSE;
1682
1683   serv = config->routers;
1684   for (i = 0; serv; i++) {
1685     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1686       found = TRUE;
1687       break;
1688     }
1689
1690     serv = serv->next;
1691   }
1692
1693   return found;
1694 }
1695
1696 /* Returns our primary connection configuration or NULL if we do not
1697    have primary router configured. */
1698
1699 SilcServerConfigRouter *
1700 silc_server_config_get_primary_router(SilcServer server)
1701 {
1702   SilcServerConfig config = server->config;
1703   SilcServerConfigRouter *serv = NULL;
1704   int i;
1705
1706   serv = config->routers;
1707   for (i = 0; serv; i++) {
1708     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1709       return serv;
1710     serv = serv->next;
1711   }
1712
1713   return NULL;
1714 }
1715
1716 /* Set default values to stuff that was not configured. */
1717
1718 bool silc_server_config_set_defaults(SilcServer server)
1719 {
1720   SilcServerConfig config = server->config;
1721
1722   my_set_param_defaults(&config->param, NULL);
1723
1724   config->channel_rekey_secs = (config->channel_rekey_secs ? 
1725                                 config->channel_rekey_secs :
1726                                 SILC_SERVER_CHANNEL_REKEY);
1727   config->key_exchange_timeout = (config->key_exchange_timeout ? 
1728                                   config->key_exchange_timeout :
1729                                   SILC_SERVER_SKE_TIMEOUT);
1730   config->conn_auth_timeout = (config->conn_auth_timeout ? 
1731                                config->conn_auth_timeout :
1732                                SILC_SERVER_CONNAUTH_TIMEOUT);
1733
1734   return TRUE;
1735 }