More SILC Server 1.1 porting. Added HTTP statistics access.
[silc.git] / apps / silcd / serverconfig.c
1 /*
2
3   serverconfig.c
4
5   Author: Giovanni Giacobbi <giovanni@giacobbi.net>
6
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23 #include <dirent.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 /* allocate the tmp field for fetching data */
38 #define SILC_SERVER_CONFIG_ALLOCTMP(__type__)                           \
39   if (!tmp) {                                                           \
40     config->tmp = silc_calloc(1, sizeof(*findtmp));                     \
41     tmp = (__type__ *) config->tmp;                                     \
42   }
43
44 /* append the tmp field to the specified list */
45 #define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__)                     \
46   if (!__list__) {                                                      \
47     __list__ = tmp;                                                     \
48   } else {                                                              \
49     for (findtmp = __list__; findtmp->next; findtmp = findtmp->next);   \
50     findtmp->next = tmp;                                                \
51   }
52
53 /* loops all elements in a list and provides a di struct pointer of the
54  * specified type containing the current element */
55 #define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__)             \
56   for (tmp = (void *) __list__; tmp;) {                                 \
57     __type__ *di = (__type__ *) tmp;                                    \
58     tmp = (void *) di->next;
59
60 /* Set EDOUBLE error value and bail out if necessary */
61 #define CONFIG_IS_DOUBLE(__x__)                                         \
62   if ((__x__)) {                                                        \
63     got_errno = SILC_CONFIG_EDOUBLE;                                    \
64     goto got_err;                                                       \
65   }
66
67 /* Free the authentication fields in the specified struct
68  * Expands to two instructions */
69 #define CONFIG_FREE_AUTH(__section__)                   \
70   silc_free(__section__->passphrase);
71
72 /* Set default values to those parameters that have not been defined */
73 static void
74 my_set_param_defaults(SilcServerConfigConnParams *params,
75                       SilcServerConfigConnParams *defaults)
76 {
77 #define SET_PARAM_DEFAULT(p, d) params->p =                             \
78   (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
79
80   SET_PARAM_DEFAULT(connections_max, SILC_SERVER_MAX_CONNECTIONS);
81   SET_PARAM_DEFAULT(connections_max_per_host,
82                     SILC_SERVER_MAX_CONNECTIONS_SINGLE);
83   SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_KEEPALIVE);
84   SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_RETRY_COUNT);
85   SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_RETRY_INTERVAL_MIN);
86   SET_PARAM_DEFAULT(reconnect_interval_max, SILC_SERVER_RETRY_INTERVAL_MAX);
87   SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_REKEY);
88   SET_PARAM_DEFAULT(qos_rate_limit, SILC_SERVER_QOS_RATE_LIMIT);
89   SET_PARAM_DEFAULT(qos_bytes_limit, SILC_SERVER_QOS_BYTES_LIMIT);
90   SET_PARAM_DEFAULT(qos_limit_sec, SILC_SERVER_QOS_LIMIT_SEC);
91   SET_PARAM_DEFAULT(qos_limit_usec, SILC_SERVER_QOS_LIMIT_USEC);
92   SET_PARAM_DEFAULT(chlimit, SILC_SERVER_CH_JOIN_LIMIT);
93
94 #undef SET_PARAM_DEFAULT
95 }
96
97 /* Find connection parameters by the parameter block name. */
98 static SilcServerConfigConnParams *
99 my_find_param(SilcServerConfig config, const char *name)
100 {
101   SilcServerConfigConnParams *param;
102
103   for (param = config->conn_params; param; param = param->next) {
104     if (!strcasecmp(param->name, name))
105       return param;
106   }
107
108   SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
109                          "Cannot find Params \"%s\".", name));
110
111   return NULL;
112 }
113
114 /* SKR find callbcak */
115
116 static void my_find_callback(SilcSKR skr, SilcSKRFind find,
117                              SilcSKRStatus status, SilcDList keys,
118                              void *context)
119 {
120   SilcSKRStatus *s = context;
121
122   *s = status;
123   if (keys)
124     silc_dlist_uninit(keys);
125
126   silc_skr_find_free(find);
127 }
128
129 /* parse an authdata according to its auth method */
130 static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
131                                   void **auth_data, SilcUInt32 *auth_data_len,
132                                   SilcSKRKeyUsage usage, void *key_context)
133 {
134   if (auth_meth == SILC_AUTH_PASSWORD) {
135     /* p is a plain text password */
136     if (auth_data && auth_data_len) {
137       if (!silc_utf8_valid(p, strlen(p))) {
138         *auth_data_len = silc_utf8_encoded_len(p, strlen(p),
139                                                SILC_STRING_LOCALE);
140         *auth_data = silc_calloc(*auth_data_len, sizeof(unsigned char));
141         silc_utf8_encode(p, strlen(p), SILC_STRING_LOCALE, *auth_data,
142                          *auth_data_len);
143       } else {
144         *auth_data = (void *) strdup(p);
145         *auth_data_len = (SilcUInt32) strlen(p);
146       }
147     }
148   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
149     /* p is a public key file name */
150     SilcPublicKey public_key;
151     SilcSKR skr = *auth_data;
152     SilcSKRFind find;
153     SilcSKRStatus status;
154
155     if (!silc_pkcs_load_public_key(p, &public_key)) {
156       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
157                              "Could not load public key file!"));
158       return FALSE;
159     }
160
161     find = silc_skr_find_alloc();
162     silc_skr_find_set_public_key(find, public_key);
163     silc_skr_find_set_usage(find, usage);
164     silc_skr_find_set_context(find, key_context ? key_context : (void *)usage);
165     silc_skr_find(skr, NULL, find, my_find_callback, &status);
166     if (status == SILC_SKR_ALREADY_EXIST) {
167       silc_pkcs_public_key_free(public_key);
168       SILC_SERVER_LOG_WARNING(("Warning: public key file \"%s\" already "
169                                "configured, ignoring this key", p));
170       return TRUE; /* non fatal error */
171     }
172
173     /* Add the public key to repository */
174     if (silc_skr_add_public_key(skr, public_key, usage,
175                                 key_context ? key_context : (void *)usage,
176                                 NULL) != SILC_SKR_OK) {
177       SILC_SERVER_LOG_ERROR(("Error while adding public key \"%s\"", p));
178       return FALSE;
179     }
180   }
181
182   return TRUE;
183 }
184
185 static SilcBool my_parse_publickeydir(const char *dirname, void **auth_data,
186                                       SilcSKRKeyUsage usage)
187 {
188   int total = 0;
189   struct dirent *get_file;
190   DIR *dp;
191
192   if (!(dp = opendir(dirname))) {
193     SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
194                            "Could not open directory \"%s\"", dirname));
195     return FALSE;
196   }
197
198   /* errors are not considered fatal */
199   while ((get_file = readdir(dp))) {
200     const char *filename = get_file->d_name;
201     char buf[1024];
202     int dirname_len = strlen(dirname), filename_len = strlen(filename);
203     struct stat check_file;
204
205     /* Ignore "." and "..", and take files only with ".pub" suffix. */
206     if (!strcmp(filename, ".") || !strcmp(filename, "..") ||
207         (filename_len < 5) || strcmp(filename + filename_len - 4, ".pub"))
208       continue;
209
210     memset(buf, 0, sizeof(buf));
211     snprintf(buf, sizeof(buf) - 1, "%s%s%s", dirname,
212              (dirname[dirname_len - 1] == '/' ? "" : "/"), filename);
213
214     if (stat(buf, &check_file) < 0) {
215       SILC_SERVER_LOG_ERROR(("Error stating file %s: %s", buf,
216                              strerror(errno)));
217     } else if (S_ISREG(check_file.st_mode)) {
218       my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL,
219                         usage, NULL);
220       total++;
221     }
222   }
223
224   SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname));
225   return TRUE;
226 }
227
228 /* Callbacks */
229
230 SILC_CONFIG_CALLBACK(fetch_generic)
231 {
232   SilcServerConfig config = (SilcServerConfig) context;
233   int got_errno = 0;
234
235   if (!strcmp(name, "module_path")) {
236     CONFIG_IS_DOUBLE(config->module_path);
237     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
238   }
239   else if (!strcmp(name, "prefer_passphrase_auth")) {
240     config->prefer_passphrase_auth = *(SilcBool *)val;
241   }
242   else if (!strcmp(name, "require_reverse_lookup")) {
243     config->require_reverse_lookup = *(SilcBool *)val;
244   }
245   else if (!strcmp(name, "connections_max")) {
246     config->param.connections_max = (SilcUInt32) *(int *)val;
247   }
248   else if (!strcmp(name, "connections_max_per_host")) {
249     config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
250   }
251   else if (!strcmp(name, "keepalive_secs")) {
252     config->param.keepalive_secs = (SilcUInt32) *(int *)val;
253   }
254   else if (!strcmp(name, "reconnect_count")) {
255     config->param.reconnect_count = (SilcUInt32) *(int *)val;
256   }
257   else if (!strcmp(name, "reconnect_interval")) {
258     config->param.reconnect_interval = (SilcUInt32) *(int *)val;
259   }
260   else if (!strcmp(name, "reconnect_interval_max")) {
261     config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
262   }
263   else if (!strcmp(name, "reconnect_keep_trying")) {
264     config->param.reconnect_keep_trying = *(SilcBool *)val;
265   }
266   else if (!strcmp(name, "key_exchange_rekey")) {
267     config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
268   }
269   else if (!strcmp(name, "key_exchange_pfs")) {
270     config->param.key_exchange_pfs = *(SilcBool *)val;
271   }
272   else if (!strcmp(name, "channel_rekey_secs")) {
273     config->channel_rekey_secs = (SilcUInt32) *(int *)val;
274   }
275   else if (!strcmp(name, "key_exchange_timeout")) {
276     config->key_exchange_timeout = (SilcUInt32) *(int *)val;
277   }
278   else if (!strcmp(name, "conn_auth_timeout")) {
279     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
280   }
281   else if (!strcmp(name, "version_protocol")) {
282     CONFIG_IS_DOUBLE(config->param.version_protocol);
283     config->param.version_protocol =
284       (*(char *)val ? strdup((char *) val) : NULL);
285   }
286   else if (!strcmp(name, "version_software")) {
287     CONFIG_IS_DOUBLE(config->param.version_software);
288     config->param.version_software =
289       (*(char *)val ? strdup((char *) val) : NULL);
290   }
291   else if (!strcmp(name, "version_software_vendor")) {
292     CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
293     config->param.version_software_vendor =
294       (*(char *)val ? strdup((char *) val) : NULL);
295   }
296   else if (!strcmp(name, "detach_disabled")) {
297     config->detach_disabled = *(SilcBool *)val;
298   }
299   else if (!strcmp(name, "detach_timeout")) {
300     config->detach_timeout = (SilcUInt32) *(int *)val;
301   }
302   else if (!strcmp(name, "qos")) {
303     config->param.qos = *(SilcBool *)val;
304   }
305   else if (!strcmp(name, "qos_rate_limit")) {
306     config->param.qos_rate_limit = *(SilcUInt32 *)val;
307   }
308   else if (!strcmp(name, "qos_bytes_limit")) {
309     config->param.qos_bytes_limit = *(SilcUInt32 *)val;
310   }
311   else if (!strcmp(name, "qos_limit_sec")) {
312     config->param.qos_limit_sec = *(SilcUInt32 *)val;
313   }
314   else if (!strcmp(name, "qos_limit_usec")) {
315     config->param.qos_limit_usec = *(SilcUInt32 *)val;
316   }
317   else if (!strcmp(name, "channel_join_limit")) {
318     config->param.chlimit = *(SilcUInt32 *)val;
319   }
320   else if (!strcmp(name, "debug_string")) {
321     CONFIG_IS_DOUBLE(config->debug_string);
322     config->debug_string = (*(char *)val ? strdup((char *) val) : NULL);
323   }
324   else if (!strcmp(name, "http_server")) {
325     config->httpd = *(SilcBool *)val;
326   }
327   else if (!strcmp(name, "http_server_ip")) {
328     CONFIG_IS_DOUBLE(config->httpd_ip);
329     config->httpd_ip = (*(char *)val ? strdup((char *) val) : NULL);
330   }
331   else if (!strcmp(name, "http_server_port")) {
332     int port = *(int *)val;
333     if ((port <= 0) || (port > 65535)) {
334       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
335                              "Invalid port number!"));
336       got_errno = SILC_CONFIG_EPRINTLINE;
337       goto got_err;
338     }
339     config->httpd_port = (SilcUInt16)port;
340   }
341   else
342     return SILC_CONFIG_EINTERNAL;
343
344   return SILC_CONFIG_OK;
345
346  got_err:
347   return got_errno;
348 }
349
350 SILC_CONFIG_CALLBACK(fetch_cipher)
351 {
352   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher);
353
354   SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)",
355                        type, name, context));
356   if (type == SILC_CONFIG_ARG_BLOCK) {
357     /* check the temporary struct's fields */
358     if (!tmp) /* discard empty sub-blocks */
359       return SILC_CONFIG_OK;
360     if (!tmp->name) {
361       got_errno = SILC_CONFIG_EMISSFIELDS;
362       goto got_err;
363     }
364
365     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
366     config->tmp = NULL;
367     return SILC_CONFIG_OK;
368   }
369   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigCipher);
370
371   /* Identify and save this value */
372   if (!strcmp(name, "name")) {
373     CONFIG_IS_DOUBLE(tmp->name);
374     tmp->name = strdup((char *) val);
375   }
376   else if (!strcmp(name, "module")) {
377     CONFIG_IS_DOUBLE(tmp->module);
378     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
379   }
380   else if (!strcmp(name, "keylength")) {
381     tmp->key_length = *(SilcUInt32 *)val;
382   }
383   else if (!strcmp(name, "blocklength")) {
384     tmp->block_length = *(SilcUInt32 *)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->module);
393   silc_free(tmp);
394   config->tmp = NULL;
395   return got_errno;
396 }
397
398 SILC_CONFIG_CALLBACK(fetch_hash)
399 {
400   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash);
401
402   SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)",
403                        type, name, context));
404   if (type == SILC_CONFIG_ARG_BLOCK) {
405     /* check the temporary struct's fields */
406     if (!tmp) /* discard empty sub-blocks */
407       return SILC_CONFIG_OK;
408     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
409       got_errno = SILC_CONFIG_EMISSFIELDS;
410       goto got_err;
411     }
412
413     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
414     config->tmp = NULL;
415     return SILC_CONFIG_OK;
416   }
417   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHash);
418
419   /* Identify and save this value */
420   if (!strcmp(name, "name")) {
421     CONFIG_IS_DOUBLE(tmp->name);
422     tmp->name = strdup((char *) val);
423   }
424   else if (!strcmp(name, "module")) {
425     CONFIG_IS_DOUBLE(tmp->module);
426     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
427   }
428   else if (!strcmp(name, "blocklength")) {
429     tmp->block_length = *(int *)val;
430   }
431   else if (!strcmp(name, "digestlength")) {
432     tmp->digest_length = *(int *)val;
433   }
434   else
435     return SILC_CONFIG_EINTERNAL;
436   return SILC_CONFIG_OK;
437
438  got_err:
439   silc_free(tmp->name);
440   silc_free(tmp->module);
441   silc_free(tmp);
442   config->tmp = NULL;
443   return got_errno;
444 }
445
446 SILC_CONFIG_CALLBACK(fetch_hmac)
447 {
448   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac);
449
450   SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)",
451                        type, name, context));
452   if (type == SILC_CONFIG_ARG_BLOCK) {
453     /* check the temporary struct's fields */
454     if (!tmp) /* discard empty sub-blocks */
455       return SILC_CONFIG_OK;
456     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
457       got_errno = SILC_CONFIG_EMISSFIELDS;
458       goto got_err;
459     }
460
461     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
462     config->tmp = NULL;
463     return SILC_CONFIG_OK;
464   }
465   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHmac);
466
467   /* Identify and save this value */
468   if (!strcmp(name, "name")) {
469     CONFIG_IS_DOUBLE(tmp->name);
470     tmp->name = strdup((char *) val);
471   }
472   else if (!strcmp(name, "hash")) {
473     CONFIG_IS_DOUBLE(tmp->hash);
474     tmp->hash = strdup((char *) val);
475   }
476   else if (!strcmp(name, "maclength")) {
477     tmp->mac_length = *(int *)val;
478   }
479   else
480     return SILC_CONFIG_EINTERNAL;
481   return SILC_CONFIG_OK;
482
483  got_err:
484   silc_free(tmp->name);
485   silc_free(tmp->hash);
486   silc_free(tmp);
487   config->tmp = NULL;
488   return got_errno;
489 }
490
491 SILC_CONFIG_CALLBACK(fetch_pkcs)
492 {
493   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs);
494
495   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
496                        type, name, context));
497   if (type == SILC_CONFIG_ARG_BLOCK) {
498     /* Check the temporary struct's fields */
499     if (!tmp) /* discard empty sub-blocks */
500       return SILC_CONFIG_OK;
501     if (!tmp->name) {
502       got_errno = SILC_CONFIG_EMISSFIELDS;
503       goto got_err;
504     }
505
506     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
507     config->tmp = NULL;
508     return SILC_CONFIG_OK;
509   }
510   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigPkcs);
511
512   /* Identify and save this value */
513   if (!strcmp(name, "name")) {
514     CONFIG_IS_DOUBLE(tmp->name);
515     tmp->name = strdup((char *) val);
516   }
517   else
518     return SILC_CONFIG_EINTERNAL;
519   return SILC_CONFIG_OK;
520
521  got_err:
522   silc_free(tmp->name);
523   silc_free(tmp);
524   config->tmp = NULL;
525   return got_errno;
526 }
527
528 SILC_CONFIG_CALLBACK(fetch_serverinfo)
529 {
530   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServerInfoInterface);
531   SilcServerConfigServerInfo *server_info = config->server_info;
532
533   SERVER_CONFIG_DEBUG(("Received SERVERINFO type=%d name=\"%s\" (val=%x)",
534                        type, name, context));
535
536   /* If there isn't the main struct alloc it */
537   if (!server_info)
538     config->server_info = server_info = (SilcServerConfigServerInfo *)
539                 silc_calloc(1, sizeof(*server_info));
540
541   if (type == SILC_CONFIG_ARG_BLOCK) {
542     if (!strcmp(name, "primary")) {
543       if (server_info->primary) {
544         SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
545                                "Double primary specification."));
546         got_errno = SILC_CONFIG_EPRINTLINE;
547         goto got_err;
548       }
549       CONFIG_IS_DOUBLE(server_info->primary);
550
551       /* now check the temporary struct, don't accept empty block and
552          make sure all fields are there */
553       if (!tmp || !tmp->server_ip || !tmp->port) {
554         got_errno = SILC_CONFIG_EMISSFIELDS;
555         goto got_err;
556       }
557       server_info->primary = tmp;
558       config->tmp = NULL;
559       return SILC_CONFIG_OK;
560     } else if (!strcmp(name, "secondary")) {
561       if (!tmp)
562         return SILC_CONFIG_OK;
563       if (!tmp || !tmp->server_ip || !tmp->port) {
564         got_errno = SILC_CONFIG_EMISSFIELDS;
565         goto got_err;
566       }
567       SILC_SERVER_CONFIG_LIST_APPENDTMP(server_info->secondary);
568       config->tmp = NULL;
569       return SILC_CONFIG_OK;
570     } else if (!server_info->public_key || !server_info->private_key) {
571       got_errno = SILC_CONFIG_EMISSFIELDS;
572       goto got_err;
573     }
574     return SILC_CONFIG_OK;
575   }
576   if (!strcmp(name, "hostname")) {
577     CONFIG_IS_DOUBLE(server_info->server_name);
578     server_info->server_name = strdup((char *) val);
579   }
580   else if (!strcmp(name, "ip")) {
581     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
582     CONFIG_IS_DOUBLE(tmp->server_ip);
583     tmp->server_ip = strdup((char *) val);
584   }
585   else if (!strcmp(name, "port")) {
586     int port = *(int *)val;
587     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
588     if ((port <= 0) || (port > 65535)) {
589       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
590                              "Invalid port number!"));
591       got_errno = SILC_CONFIG_EPRINTLINE;
592       goto got_err;
593     }
594     tmp->port = (SilcUInt16) port;
595   }
596   else if (!strcmp(name, "servertype")) {
597     CONFIG_IS_DOUBLE(server_info->server_type);
598     server_info->server_type = strdup((char *) val);
599   }
600   else if (!strcmp(name, "admin")) {
601     CONFIG_IS_DOUBLE(server_info->admin);
602     server_info->admin = strdup((char *) val);
603   }
604   else if (!strcmp(name, "adminemail")) {
605     CONFIG_IS_DOUBLE(server_info->email);
606     server_info->email = strdup((char *) val);
607   }
608   else if (!strcmp(name, "location")) {
609     CONFIG_IS_DOUBLE(server_info->location);
610     server_info->location = strdup((char *) val);
611   }
612   else if (!strcmp(name, "user")) {
613     CONFIG_IS_DOUBLE(server_info->user);
614     server_info->user = strdup((char *) val);
615   }
616   else if (!strcmp(name, "group")) {
617     CONFIG_IS_DOUBLE(server_info->group);
618     server_info->group = strdup((char *) val);
619   }
620   else if (!strcmp(name, "motdfile")) {
621     CONFIG_IS_DOUBLE(server_info->motd_file);
622     server_info->motd_file = strdup((char *) val);
623   }
624   else if (!strcmp(name, "pidfile")) {
625     CONFIG_IS_DOUBLE(server_info->pid_file);
626     server_info->pid_file = strdup((char *) val);
627   }
628   else if (!strcmp(name, "publickey")) {
629     char *file_tmp = (char *) val;
630     CONFIG_IS_DOUBLE(server_info->public_key);
631
632     /* Try to load specified file, if fail stop config parsing */
633     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key)) {
634       SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
635       return SILC_CONFIG_EPRINTLINE;
636     }
637   }
638   else if (!strcmp(name, "privatekey")) {
639     struct stat st;
640     char *file_tmp = (char *) val;
641     CONFIG_IS_DOUBLE(server_info->private_key);
642
643     /* Check the private key file permissions. */
644     if ((stat(file_tmp, &st)) != -1) {
645       if ((st.st_mode & 0777) != 0600) {
646         SILC_SERVER_LOG_ERROR(("Wrong permissions in private key "
647                               "file \"%s\".  The permissions must be "
648                               "0600.", file_tmp));
649         return SILC_CONFIG_ESILENT;
650       }
651     }
652
653     /* Try to load specified file, if fail stop config parsing */
654     if (!silc_pkcs_load_private_key(file_tmp, "", 0,
655                                     &server_info->private_key)) {
656       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
657       return SILC_CONFIG_EPRINTLINE;
658     }
659   }
660   else
661     return SILC_CONFIG_EINTERNAL;
662   return SILC_CONFIG_OK;
663
664  got_err:
665   /* Here we need to check if tmp exists because this function handles
666    * misc data (multiple fields and single-only fields) */
667   if (tmp) {
668     silc_free(tmp->server_ip);
669     silc_free(tmp);
670     config->tmp = NULL;
671   }
672   return got_errno;
673 }
674
675 SILC_CONFIG_CALLBACK(fetch_logging)
676 {
677   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
678
679   if (!strcmp(name, "timestamp")) {
680     config->logging_timestamp = *(SilcBool *)val;
681   }
682   else if (!strcmp(name, "quicklogs")) {
683     config->logging_quick = *(SilcBool *)val;
684   }
685   else if (!strcmp(name, "flushdelay")) {
686     int flushdelay = *(int *)val;
687     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
688       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
689                             "Invalid flushdelay value, use quicklogs if you "
690                             "want real-time logging."));
691       return SILC_CONFIG_EPRINTLINE;
692     }
693     config->logging_flushdelay = (long) flushdelay;
694   }
695
696   /* The following istances happens only in Logging's sub-blocks, a match
697      for the sub-block name means that you should store the filename/maxsize
698      temporary struct to the proper logging channel.
699      If we get a match for "file" or "maxsize" this means that we are inside
700      a sub-sub-block and it is safe to alloc a new tmp. */
701 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
702   else if (!strcmp(name, __chan__)) {                           \
703     if (!tmp) return SILC_CONFIG_OK;                            \
704     if (!tmp->file) {                                           \
705       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
706     }                                                           \
707     config->__member__ = tmp;                                   \
708     config->tmp = NULL;                                         \
709   }
710   FETCH_LOGGING_CHAN("info", logging_info)
711   FETCH_LOGGING_CHAN("warnings", logging_warnings)
712   FETCH_LOGGING_CHAN("errors", logging_errors)
713   FETCH_LOGGING_CHAN("fatals", logging_fatals)
714 #undef FETCH_LOGGING_CHAN
715   else if (!strcmp(name, "file")) {
716     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigLogging);
717     CONFIG_IS_DOUBLE(tmp->file);
718     tmp->file = strdup((char *) val);
719   }
720   else if (!strcmp(name, "size")) {
721     if (!tmp) {
722       config->tmp = silc_calloc(1, sizeof(*tmp));
723       tmp = (SilcServerConfigLogging *) config->tmp;
724     }
725     tmp->maxsize = *(SilcUInt32 *) val;
726   }
727   else
728     return SILC_CONFIG_EINTERNAL;
729   return SILC_CONFIG_OK;
730
731  got_err:
732   silc_free(tmp->file);
733   silc_free(tmp);
734   config->tmp = NULL;
735   return got_errno;
736 }
737
738 SILC_CONFIG_CALLBACK(fetch_connparam)
739 {
740   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
741
742   SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)",
743                        type, name, context));
744   if (type == SILC_CONFIG_ARG_BLOCK) {
745     /* check the temporary struct's fields */
746     if (!tmp) /* discard empty sub-blocks */
747       return SILC_CONFIG_OK;
748     if (!tmp->name) {
749       got_errno = SILC_CONFIG_EMISSFIELDS;
750       goto got_err;
751     }
752     /* Set defaults */
753     my_set_param_defaults(tmp, &config->param);
754
755     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
756     config->tmp = NULL;
757     return SILC_CONFIG_OK;
758   }
759   if (!tmp) {
760     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigConnParams);
761     tmp->reconnect_keep_trying = TRUE;
762   }
763
764   if (!strcmp(name, "name")) {
765     CONFIG_IS_DOUBLE(tmp->name);
766     tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
767   }
768   else if (!strcmp(name, "connections_max")) {
769     tmp->connections_max = *(SilcUInt32 *)val;
770   }
771   else if (!strcmp(name, "connections_max_per_host")) {
772     tmp->connections_max_per_host = *(SilcUInt32 *)val;
773   }
774   else if (!strcmp(name, "keepalive_secs")) {
775     tmp->keepalive_secs = *(SilcUInt32 *)val;
776   }
777   else if (!strcmp(name, "reconnect_count")) {
778     tmp->reconnect_count = *(SilcUInt32 *)val;
779   }
780   else if (!strcmp(name, "reconnect_interval")) {
781     tmp->reconnect_interval = *(SilcUInt32 *)val;
782   }
783   else if (!strcmp(name, "reconnect_interval_max")) {
784     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
785   }
786   else if (!strcmp(name, "reconnect_keep_trying")) {
787     tmp->reconnect_keep_trying = *(SilcBool *)val;
788   }
789   else if (!strcmp(name, "key_exchange_rekey")) {
790     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
791   }
792   else if (!strcmp(name, "key_exchange_pfs")) {
793     tmp->key_exchange_pfs = *(SilcBool *)val;
794   }
795   else if (!strcmp(name, "version_protocol")) {
796     CONFIG_IS_DOUBLE(tmp->version_protocol);
797     tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
798   }
799   else if (!strcmp(name, "version_software")) {
800     CONFIG_IS_DOUBLE(tmp->version_software);
801     tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
802   }
803   else if (!strcmp(name, "version_software_vendor")) {
804     CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
805     tmp->version_software_vendor =
806       (*(char *)val ? strdup((char *) val) : NULL);
807   }
808   else if (!strcmp(name, "anonymous")) {
809     tmp->anonymous = *(SilcBool *)val;
810   }
811   else if (!strcmp(name, "qos")) {
812     tmp->qos = *(SilcBool *)val;
813   }
814   else if (!strcmp(name, "qos_rate_limit")) {
815     tmp->qos_rate_limit = *(SilcUInt32 *)val;
816   }
817   else if (!strcmp(name, "qos_bytes_limit")) {
818     tmp->qos_bytes_limit = *(SilcUInt32 *)val;
819   }
820   else if (!strcmp(name, "qos_limit_sec")) {
821     tmp->qos_limit_sec = *(SilcUInt32 *)val;
822   }
823   else if (!strcmp(name, "qos_limit_usec")) {
824     tmp->qos_limit_usec = *(SilcUInt32 *)val;
825   }
826   else
827     return SILC_CONFIG_EINTERNAL;
828
829   return SILC_CONFIG_OK;
830
831  got_err:
832   silc_free(tmp->name);
833   silc_free(tmp);
834   config->tmp = NULL;
835   return got_errno;
836 }
837
838 SILC_CONFIG_CALLBACK(fetch_client)
839 {
840   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
841
842   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
843                        type, name, context));
844
845   /* Alloc before block checking, because empty sub-blocks are welcome here */
846   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigClient);
847
848   if (type == SILC_CONFIG_ARG_BLOCK) {
849     /* empty sub-blocks are welcome */
850     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
851     config->tmp = NULL;
852     return SILC_CONFIG_OK;
853   }
854
855   /* Identify and save this value */
856   if (!strcmp(name, "host")) {
857     CONFIG_IS_DOUBLE(tmp->host);
858     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
859   }
860   else if (!strcmp(name, "passphrase")) {
861     CONFIG_IS_DOUBLE(tmp->passphrase);
862     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
863                            (void *)&tmp->passphrase,
864                            &tmp->passphrase_len, 0, NULL)) {
865       got_errno = SILC_CONFIG_EPRINTLINE;
866       goto got_err;
867     }
868   }
869   else if (!strcmp(name, "publickey")) {
870     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
871                            (void *)&config->server->repository, NULL,
872                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
873       got_errno = SILC_CONFIG_EPRINTLINE;
874       goto got_err;
875     }
876   }
877   else if (!strcmp(name, "publickeydir")) {
878     if (!my_parse_publickeydir((char *) val,
879                                (void *)&config->server->repository,
880                                SILC_SKR_USAGE_KEY_AGREEMENT)) {
881       got_errno = SILC_CONFIG_EPRINTLINE;
882       goto got_err;
883     }
884   }
885   else if (!strcmp(name, "params")) {
886     CONFIG_IS_DOUBLE(tmp->param);
887     tmp->param = my_find_param(config, (char *) val);
888     if (!tmp->param) { /* error message already output */
889       got_errno = SILC_CONFIG_EPRINTLINE;
890       goto got_err;
891     }
892   }
893   else
894     return SILC_CONFIG_EINTERNAL;
895   return SILC_CONFIG_OK;
896
897  got_err:
898   silc_free(tmp->host);
899   CONFIG_FREE_AUTH(tmp);
900   silc_free(tmp);
901   config->tmp = NULL;
902   return got_errno;
903 }
904
905 SILC_CONFIG_CALLBACK(fetch_admin)
906 {
907   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
908
909   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
910                        type, name, context));
911   if (type == SILC_CONFIG_ARG_BLOCK) {
912     /* check the temporary struct's fields */
913     if (!tmp) /* discard empty sub-blocks */
914       return SILC_CONFIG_OK;
915
916     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
917     config->tmp = NULL;
918     return SILC_CONFIG_OK;
919   }
920   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigAdmin);
921
922   /* Identify and save this value */
923   if (!strcmp(name, "host")) {
924     CONFIG_IS_DOUBLE(tmp->host);
925     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
926   }
927   else if (!strcmp(name, "user")) {
928     CONFIG_IS_DOUBLE(tmp->user);
929     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
930   }
931   else if (!strcmp(name, "nick")) {
932     CONFIG_IS_DOUBLE(tmp->nick);
933     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
934   }
935   else if (!strcmp(name, "passphrase")) {
936     CONFIG_IS_DOUBLE(tmp->passphrase);
937     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
938                            (void *)&tmp->passphrase,
939                            &tmp->passphrase_len, 0, NULL)) {
940       got_errno = SILC_CONFIG_EPRINTLINE;
941       goto got_err;
942     }
943   }
944   else if (!strcmp(name, "publickey")) {
945     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
946                            (void *)&config->server->repository, NULL,
947                            SILC_SKR_USAGE_SERVICE_AUTHORIZATION, tmp)) {
948       got_errno = SILC_CONFIG_EPRINTLINE;
949       goto got_err;
950     }
951   }
952   else
953     return SILC_CONFIG_EINTERNAL;
954   return SILC_CONFIG_OK;
955
956  got_err:
957   silc_free(tmp->host);
958   silc_free(tmp->user);
959   silc_free(tmp->nick);
960   CONFIG_FREE_AUTH(tmp);
961   silc_free(tmp);
962   config->tmp = NULL;
963   return got_errno;
964 }
965
966 SILC_CONFIG_CALLBACK(fetch_deny)
967 {
968   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
969
970   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
971                        type, name, context));
972   if (type == SILC_CONFIG_ARG_BLOCK) {
973     /* check the temporary struct's fields */
974     if (!tmp) /* discard empty sub-blocks */
975       return SILC_CONFIG_OK;
976     if (!tmp->reason) {
977       got_errno = SILC_CONFIG_EMISSFIELDS;
978       goto got_err;
979     }
980
981     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
982     config->tmp = NULL;
983     return SILC_CONFIG_OK;
984   }
985   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny);
986
987   /* Identify and save this value */
988   if (!strcmp(name, "host")) {
989     CONFIG_IS_DOUBLE(tmp->host);
990     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
991   }
992   else if (!strcmp(name, "reason")) {
993     CONFIG_IS_DOUBLE(tmp->reason);
994     tmp->reason = strdup((char *) val);
995   }
996   else
997     return SILC_CONFIG_EINTERNAL;
998   return SILC_CONFIG_OK;
999
1000  got_err:
1001   silc_free(tmp->host);
1002   silc_free(tmp->reason);
1003   silc_free(tmp);
1004   config->tmp = NULL;
1005   return got_errno;
1006 }
1007
1008 SILC_CONFIG_CALLBACK(fetch_server)
1009 {
1010   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
1011
1012   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
1013                        type, name, context));
1014   if (type == SILC_CONFIG_ARG_BLOCK) {
1015     /* check the temporary struct's fields */
1016     if (!tmp) /* discard empty sub-blocks */
1017       return SILC_CONFIG_OK;
1018     if (!tmp->host) {
1019       got_errno = SILC_CONFIG_EMISSFIELDS;
1020       goto got_err;
1021     }
1022
1023     /* the temporary struct is ok, append it to the list */
1024     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
1025     config->tmp = NULL;
1026     return SILC_CONFIG_OK;
1027   }
1028   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer);
1029
1030   /* Identify and save this value */
1031   if (!strcmp(name, "host")) {
1032     CONFIG_IS_DOUBLE(tmp->host);
1033     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
1034   }
1035   else if (!strcmp(name, "passphrase")) {
1036     CONFIG_IS_DOUBLE(tmp->passphrase);
1037     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1038                            (void *)&tmp->passphrase,
1039                            &tmp->passphrase_len, 0, NULL)) {
1040       got_errno = SILC_CONFIG_EPRINTLINE;
1041       goto got_err;
1042     }
1043   }
1044   else if (!strcmp(name, "publickey")) {
1045     CONFIG_IS_DOUBLE(tmp->publickeys);
1046     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1047                            (void *)&config->server->repository, NULL,
1048                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
1049       got_errno = SILC_CONFIG_EPRINTLINE;
1050       goto got_err;
1051     }
1052   }
1053   else if (!strcmp(name, "params")) {
1054     CONFIG_IS_DOUBLE(tmp->param);
1055     tmp->param = my_find_param(config, (char *) val);
1056     if (!tmp->param) { /* error message already output */
1057       got_errno = SILC_CONFIG_EPRINTLINE;
1058       goto got_err;
1059     }
1060   }
1061   else if (!strcmp(name, "backup")) {
1062     tmp->backup_router = *(SilcBool *)val;
1063   }
1064   else
1065     return SILC_CONFIG_EINTERNAL;
1066
1067   return SILC_CONFIG_OK;
1068
1069  got_err:
1070   silc_free(tmp->host);
1071   CONFIG_FREE_AUTH(tmp);
1072   silc_free(tmp);
1073   config->tmp = NULL;
1074   return got_errno;
1075 }
1076
1077 SILC_CONFIG_CALLBACK(fetch_router)
1078 {
1079   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
1080
1081   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
1082                        type, name, context));
1083   if (type == SILC_CONFIG_ARG_BLOCK) {
1084     if (!tmp) /* discard empty sub-blocks */
1085       return SILC_CONFIG_OK;
1086     if (!tmp->host) {
1087       got_errno = SILC_CONFIG_EMISSFIELDS;
1088       goto got_err;
1089     }
1090
1091     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
1092     config->tmp = NULL;
1093     return SILC_CONFIG_OK;
1094   }
1095   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigRouter);
1096
1097   /* Identify and save this value */
1098   if (!strcmp(name, "host")) {
1099     CONFIG_IS_DOUBLE(tmp->host);
1100     tmp->host = strdup((char *) val);
1101   }
1102   else if (!strcmp(name, "port")) {
1103     int port = *(int *)val;
1104     if ((port <= 0) || (port > 65535)) {
1105       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1106                              "Invalid port number!"));
1107       got_errno = SILC_CONFIG_EPRINTLINE;
1108       goto got_err;
1109     }
1110     tmp->port = (SilcUInt16) port;
1111   }
1112   else if (!strcmp(name, "passphrase")) {
1113     CONFIG_IS_DOUBLE(tmp->passphrase);
1114     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1115                            (void *)&tmp->passphrase,
1116                            &tmp->passphrase_len, 0, NULL)) {
1117       got_errno = SILC_CONFIG_EPRINTLINE;
1118       goto got_err;
1119     }
1120   }
1121   else if (!strcmp(name, "publickey")) {
1122     CONFIG_IS_DOUBLE(tmp->publickeys);
1123     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1124                            (void *)&config->server->repository, NULL,
1125                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
1126       got_errno = SILC_CONFIG_EPRINTLINE;
1127       goto got_err;
1128     }
1129   }
1130   else if (!strcmp(name, "params")) {
1131     CONFIG_IS_DOUBLE(tmp->param);
1132     tmp->param = my_find_param(config, (char *) val);
1133     if (!tmp->param) { /* error message already output */
1134       got_errno = SILC_CONFIG_EPRINTLINE;
1135       goto got_err;
1136     }
1137   }
1138   else if (!strcmp(name, "initiator")) {
1139     tmp->initiator = *(SilcBool *)val;
1140   }
1141   else if (!strcmp(name, "backuphost")) {
1142     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
1143     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
1144                               strdup("*"));
1145     tmp->backup_router = TRUE;
1146   }
1147   else if (!strcmp(name, "backupport")) {
1148     int port = *(int *)val;
1149     if ((port <= 0) || (port > 65535)) {
1150       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1151                              "Invalid port number!"));
1152       got_errno = SILC_CONFIG_EPRINTLINE;
1153       goto got_err;
1154     }
1155     tmp->backup_replace_port = (SilcUInt16) port;
1156   }
1157   else if (!strcmp(name, "backuplocal")) {
1158     tmp->backup_local = *(SilcBool *)val;
1159   }
1160   else
1161     return SILC_CONFIG_EINTERNAL;
1162
1163   return SILC_CONFIG_OK;
1164
1165  got_err:
1166   silc_free(tmp->host);
1167   silc_free(tmp->backup_replace_ip);
1168   CONFIG_FREE_AUTH(tmp);
1169   silc_free(tmp);
1170   config->tmp = NULL;
1171   return got_errno;
1172 }
1173
1174 /* known config options tables */
1175 static const SilcConfigTable table_general[] = {
1176   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1177   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1178   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1179   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1180   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1181   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1182   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1183   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1184   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1185   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1186   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1187   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1188   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1189   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1190   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1191   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1192   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1193   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1194   { "detach_disabled",          SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1195   { "detach_timeout",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1196   { "qos",                      SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1197   { "qos_rate_limit",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1198   { "qos_bytes_limit",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1199   { "qos_limit_sec",            SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1200   { "qos_limit_usec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1201   { "channel_join_limit",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1202   { "debug_string",             SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1203   { "http_server",              SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1204   { "http_server_ip",           SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1205   { "http_server_port",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1206   { 0, 0, 0, 0 }
1207 };
1208
1209 static const SilcConfigTable table_cipher[] = {
1210   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1211   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
1212   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1213   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1214   { 0, 0, 0, 0 }
1215 };
1216
1217 static const SilcConfigTable table_hash[] = {
1218   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1219   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
1220   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1221   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1222   { 0, 0, 0, 0 }
1223 };
1224
1225 static const SilcConfigTable table_hmac[] = {
1226   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1227   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1228   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1229   { 0, 0, 0, 0 }
1230 };
1231
1232 static const SilcConfigTable table_pkcs[] = {
1233   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1234   { 0, 0, 0, 0 }
1235 };
1236
1237 static const SilcConfigTable table_serverinfo_c[] = {
1238   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1239   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1240   { 0, 0, 0, 0 }
1241 };
1242
1243 static const SilcConfigTable table_serverinfo[] = {
1244   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1245   { "primary",          SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1246   { "secondary",        SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1247   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1248   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1249   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1250   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1251   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1252   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1253   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1254   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1255   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1256   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1257   { 0, 0, 0, 0 }
1258 };
1259
1260 static const SilcConfigTable table_logging_c[] = {
1261   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1262   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1263 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1264   { 0, 0, 0, 0 }
1265 };
1266
1267 static const SilcConfigTable table_logging[] = {
1268   { "timestamp",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1269   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1270   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1271   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1272   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1273   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1274   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1275   { 0, 0, 0, 0 }
1276 };
1277
1278 static const SilcConfigTable table_connparam[] = {
1279   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1280   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1281   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1282   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1283   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1284   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1285   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1286   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1287   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1288   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1289   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1290   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1291   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1292   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1293   { "anonymous",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1294   { "qos",                     SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1295   { "qos_rate_limit",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1296   { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1297   { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1298   { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1299   { 0, 0, 0, 0 }
1300 };
1301
1302 static const SilcConfigTable table_client[] = {
1303   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1304   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1305   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1306   { "publickeydir",     SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1307   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1308   { 0, 0, 0, 0 }
1309 };
1310
1311 static const SilcConfigTable table_admin[] = {
1312   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1313   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1314   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1315   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1316   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1317   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1318   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1319   { 0, 0, 0, 0 }
1320 };
1321
1322 static const SilcConfigTable table_deny[] = {
1323   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1324   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1325   { 0, 0, 0, 0 }
1326 };
1327
1328 static const SilcConfigTable table_serverconn[] = {
1329   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1330   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1331   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1332   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1333   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1334   { 0, 0, 0, 0 }
1335 };
1336
1337 static const SilcConfigTable table_routerconn[] = {
1338   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1339   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1340   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1341   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1342   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1343   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1344   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1345   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1346   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1347   { 0, 0, 0, 0 }
1348 };
1349
1350 static const SilcConfigTable table_main[] = {
1351   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1352   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1353   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1354   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1355   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1356   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1357   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1358   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1359   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1360   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1361   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1362   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1363   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1364   { 0, 0, 0, 0 }
1365 };
1366
1367 /* Set default values to stuff that was not configured. */
1368
1369 static void silc_server_config_set_defaults(SilcServerConfig config)
1370 {
1371   my_set_param_defaults(&config->param, NULL);
1372
1373   config->channel_rekey_secs = (config->channel_rekey_secs ?
1374                                 config->channel_rekey_secs :
1375                                 SILC_SERVER_CHANNEL_REKEY);
1376   config->key_exchange_timeout = (config->key_exchange_timeout ?
1377                                   config->key_exchange_timeout :
1378                                   SILC_SERVER_SKE_TIMEOUT);
1379   config->conn_auth_timeout = (config->conn_auth_timeout ?
1380                                config->conn_auth_timeout :
1381                                SILC_SERVER_CONNAUTH_TIMEOUT);
1382 }
1383
1384 /* Check for correctness of the configuration */
1385
1386 static SilcBool silc_server_config_check(SilcServerConfig config)
1387 {
1388   SilcBool ret = TRUE;
1389   SilcServerConfigServer *s;
1390   SilcServerConfigRouter *r;
1391   SilcBool b = FALSE;
1392
1393   /* ServerConfig is mandatory */
1394   if (!config->server_info) {
1395     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `ServerInfo'"));
1396     ret = FALSE;
1397   }
1398
1399   /* RouterConnection sanity checks */
1400
1401   if (config->routers && config->routers->backup_router == TRUE &&
1402       !config->servers) {
1403     SILC_SERVER_LOG_ERROR((
1404          "\nError: First RouterConnection block must be primary router "
1405          "connection. You have marked it incorrectly as backup router."));
1406     ret = FALSE;
1407   }
1408 #if 0
1409   if (config->routers && config->routers->initiator == FALSE &&
1410       config->routers->backup_router == FALSE) {
1411     SILC_SERVER_LOG_ERROR((
1412          "\nError: First RouterConnection block must be primary router "
1413          "connection and it must be marked as Initiator."));
1414     ret = FALSE;
1415   }
1416 #endif
1417   if (config->routers && config->routers->backup_router == TRUE &&
1418       !config->servers && !config->routers->next) {
1419     SILC_SERVER_LOG_ERROR((
1420          "\nError: You have configured backup router but not primary router. "
1421          "If backup router is configured also primary router must be "
1422          "configured."));
1423     ret = FALSE;
1424   }
1425
1426   /* Backup router sanity checks */
1427
1428   for (r = config->routers; r; r = r->next) {
1429     if (r->backup_router && !strcmp(r->host, r->backup_replace_ip)) {
1430       SILC_SERVER_LOG_ERROR((
1431           "\nError: Backup router connection incorrectly configured to use "
1432           "primary and backup router as same host `%s'. They must not be "
1433           "same host.", r->host));
1434       ret = FALSE;
1435     }
1436
1437     if (r->initiator == FALSE && r->port != 0) {
1438       SILC_SERVER_LOG_WARNING(("\nWarning: Initiator is FALSE and Port is "
1439                                "specified. Ignoring Port value."));
1440       r->port = 0;
1441     }
1442   }
1443
1444   /* ServerConnection sanity checks */
1445
1446   for (s = config->servers; s; s = s->next) {
1447     if (s->backup_router) {
1448       b = TRUE;
1449       break;
1450     }
1451   }
1452   if (b) {
1453     for (s = config->servers; s; s = s->next) {
1454       if (!s->backup_router) {
1455         SILC_SERVER_LOG_ERROR((
1456           "\nError: Your server is backup router but not all ServerConnection "
1457           "blocks were marked as backup connections. They all must be "
1458           "marked as backup connections."));
1459         ret = FALSE;
1460         break;
1461       }
1462     }
1463   }
1464
1465   return ret;
1466 }
1467
1468 /* Allocates a new configuration object, opens configuration file and
1469    parses it. The parsed data is returned to the newly allocated
1470    configuration object. The SilcServerConfig must be freed by calling
1471    the silc_server_config_destroy function. */
1472
1473 SilcServerConfig silc_server_config_alloc(const char *filename,
1474                                           SilcServer server)
1475 {
1476   SilcServerConfig config_new;
1477   SilcConfigEntity ent;
1478   SilcConfigFile *file;
1479   int ret;
1480   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1481
1482   /* alloc a config object */
1483   config_new = silc_calloc(1, sizeof(*config_new));
1484   if (!config_new)
1485     return NULL;
1486
1487   /* general config defaults */
1488   config_new->refcount = 1;
1489   config_new->logging_timestamp = TRUE;
1490   config_new->param.reconnect_keep_trying = TRUE;
1491   config_new->server = server;
1492
1493   /* obtain a config file object */
1494   file = silc_config_open(filename);
1495   if (!file) {
1496     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'",
1497                            filename));
1498     return NULL;
1499   }
1500
1501   /* obtain a SilcConfig entity, we can use it to start the parsing */
1502   ent = silc_config_init(file);
1503
1504   /* load the known configuration options, give our empty object as context */
1505   silc_config_register_table(ent, table_main, (void *) config_new);
1506
1507   /* enter the main parsing loop.  When this returns, we have the parsing
1508    * result and the object filled (or partially, in case of errors). */
1509   ret = silc_config_main(ent);
1510   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1511                   silc_config_strerror(ret)));
1512
1513   /* Check if the parser returned errors */
1514   if (ret) {
1515     /* handle this special error return which asks to quietly return */
1516     if (ret != SILC_CONFIG_ESILENT) {
1517       char *linebuf, *filename = silc_config_get_filename(file);
1518       SilcUInt32 line = silc_config_get_line(file);
1519       if (ret != SILC_CONFIG_EPRINTLINE)
1520         SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.",
1521                                silc_config_strerror(ret)));
1522       linebuf = silc_config_read_line(file, line);
1523       if (linebuf) {
1524         SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1525                                line, linebuf));
1526         silc_free(linebuf);
1527       }
1528     }
1529     silc_server_config_destroy(config_new);
1530     silc_config_close(file);
1531     return NULL;
1532   }
1533
1534   /* close (destroy) the file object */
1535   silc_config_close(file);
1536
1537   /* Check the configuration */
1538   if (!silc_server_config_check(config_new)) {
1539     silc_server_config_destroy(config_new);
1540     return NULL;
1541   }
1542
1543   /* Set default to configuration parameters */
1544   silc_server_config_set_defaults(config_new);
1545
1546   return config_new;
1547 }
1548
1549 /* Increments the reference counter of a config object */
1550
1551 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1552                             void *ref_ptr)
1553 {
1554   if (ref_ptr) {
1555     config->refcount++;
1556     ref->config = config;
1557     ref->ref_ptr = ref_ptr;
1558     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %d->%d", config,
1559                     config->refcount - 1, config->refcount));
1560   }
1561 }
1562
1563 /* Decrements the reference counter of a config object.  If the counter
1564    reaches 0, the config object is destroyed. */
1565
1566 void silc_server_config_unref(SilcServerConfigRef *ref)
1567 {
1568   if (ref->ref_ptr)
1569     silc_server_config_destroy(ref->config);
1570 }
1571
1572 /* Destroy a config object with all his children lists */
1573
1574 void silc_server_config_destroy(SilcServerConfig config)
1575 {
1576   void *tmp;
1577
1578   config->refcount--;
1579   SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %d->%d", config,
1580                   config->refcount + 1, config->refcount));
1581   if (config->refcount > 0)
1582     return;
1583
1584   SILC_LOG_DEBUG(("Freeing config context"));
1585
1586   /* Destroy general config stuff */
1587   silc_free(config->module_path);
1588   silc_free(config->debug_string);
1589   silc_free(config->param.version_protocol);
1590   silc_free(config->param.version_software);
1591   silc_free(config->param.version_software_vendor);
1592   silc_free(config->httpd_ip);
1593
1594   /* Destroy Logging channels */
1595   if (config->logging_info)
1596     silc_free(config->logging_info->file);
1597   if (config->logging_warnings)
1598     silc_free(config->logging_warnings->file);
1599   if (config->logging_errors)
1600     silc_free(config->logging_errors->file);
1601   if (config->logging_fatals)
1602     silc_free(config->logging_fatals->file);
1603   silc_free(config->logging_info);
1604   silc_free(config->logging_warnings);
1605   silc_free(config->logging_errors);
1606   silc_free(config->logging_fatals);
1607
1608   /* Destroy the ServerInfo struct */
1609   if (config->server_info) {
1610     register SilcServerConfigServerInfo *si = config->server_info;
1611     silc_free(si->server_name);
1612     if (si->primary) {
1613       silc_free(si->primary->server_ip);
1614       silc_free(si->primary);
1615     }
1616     SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServerInfoInterface,
1617                                   si->secondary)
1618       silc_free(di->server_ip);
1619       silc_free(di);
1620     }
1621     silc_free(si->server_type);
1622     silc_free(si->location);
1623     silc_free(si->admin);
1624     silc_free(si->email);
1625     silc_free(si->user);
1626     silc_free(si->group);
1627     silc_free(si->motd_file);
1628     silc_free(si->pid_file);
1629     if (si->public_key)
1630       silc_pkcs_public_key_free(si->public_key);
1631     if (si->private_key)
1632       silc_pkcs_private_key_free(si->private_key);
1633     silc_free(si);
1634   }
1635
1636   /* Now let's destroy the lists */
1637
1638   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1639                                   config->cipher)
1640     silc_free(di->name);
1641     silc_free(di->module);
1642     silc_free(di);
1643   }
1644   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1645     silc_free(di->name);
1646     silc_free(di->module);
1647     silc_free(di);
1648   }
1649   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1650     silc_free(di->name);
1651     silc_free(di->hash);
1652     silc_free(di);
1653   }
1654   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1655     silc_free(di->name);
1656     silc_free(di);
1657   }
1658   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1659                                   config->conn_params)
1660     silc_free(di->name);
1661     silc_free(di->version_protocol);
1662     silc_free(di->version_software);
1663     silc_free(di->version_software_vendor);
1664     silc_free(di);
1665   }
1666   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1667     silc_free(di->host);
1668     CONFIG_FREE_AUTH(di);
1669     silc_free(di);
1670   }
1671   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1672     silc_free(di->host);
1673     silc_free(di->user);
1674     silc_free(di->nick);
1675     CONFIG_FREE_AUTH(di);
1676     silc_free(di);
1677   }
1678   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1679     silc_free(di->host);
1680     silc_free(di->reason);
1681     silc_free(di);
1682   }
1683   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1684                                   config->servers)
1685     silc_free(di->host);
1686     CONFIG_FREE_AUTH(di);
1687     silc_free(di);
1688   }
1689   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1690                                   config->routers)
1691     silc_free(di->host);
1692     silc_free(di->backup_replace_ip);
1693     CONFIG_FREE_AUTH(di);
1694     silc_free(di);
1695   }
1696
1697   memset(config, 'F', sizeof(*config));
1698   silc_free(config);
1699 }
1700
1701 /* Registers configured ciphers. These can then be allocated by the
1702    server when needed. */
1703
1704 SilcBool silc_server_config_register_ciphers(SilcServer server)
1705 {
1706   SilcServerConfig config = server->config;
1707   SilcServerConfigCipher *cipher = config->cipher;
1708   char *module_path = config->module_path;
1709
1710   SILC_LOG_DEBUG(("Registering configured ciphers"));
1711
1712   if (!cipher) /* any cipher in the config file? */
1713     return FALSE;
1714
1715   while (cipher) {
1716     /* if there isn't a module_path OR there isn't a module sim name try to
1717      * use buil-in functions */
1718     if (!module_path || !cipher->module) {
1719       int i;
1720       for (i = 0; silc_default_ciphers[i].name; i++)
1721         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1722           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1723           break;
1724         }
1725       if (!silc_cipher_is_supported(cipher->name)) {
1726         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1727         silc_server_stop(server);
1728         exit(1);
1729       }
1730     }
1731     cipher = cipher->next;
1732   } /* while */
1733
1734   return TRUE;
1735 }
1736
1737 /* Registers configured hash functions. These can then be allocated by the
1738    server when needed. */
1739
1740 SilcBool silc_server_config_register_hashfuncs(SilcServer server)
1741 {
1742   SilcServerConfig config = server->config;
1743   SilcServerConfigHash *hash = config->hash;
1744   char *module_path = config->module_path;
1745
1746   SILC_LOG_DEBUG(("Registering configured hash functions"));
1747
1748   if (!hash) /* any hash func in the config file? */
1749     return FALSE;
1750
1751   while (hash) {
1752     /* if there isn't a module_path OR there isn't a module sim name try to
1753      * use buil-in functions */
1754     if (!module_path || !hash->module) {
1755       int i;
1756       for (i = 0; silc_default_hash[i].name; i++)
1757         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1758           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1759           break;
1760         }
1761       if (!silc_hash_is_supported(hash->name)) {
1762         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1763         silc_server_stop(server);
1764         exit(1);
1765       }
1766     }
1767     hash = hash->next;
1768   } /* while */
1769
1770   return TRUE;
1771 }
1772
1773 /* Registers configure HMACs. These can then be allocated by the server
1774    when needed. */
1775
1776 SilcBool silc_server_config_register_hmacs(SilcServer server)
1777 {
1778   SilcServerConfig config = server->config;
1779   SilcServerConfigHmac *hmac = config->hmac;
1780
1781   SILC_LOG_DEBUG(("Registering configured HMACs"));
1782
1783   if (!hmac)
1784     return FALSE;
1785
1786   while (hmac) {
1787     SilcHmacObject hmac_obj;
1788     if (!silc_hash_is_supported(hmac->hash)) {
1789       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1790       silc_server_stop(server);
1791       exit(1);
1792     }
1793
1794     /* Register the HMAC */
1795     memset(&hmac_obj, 0, sizeof(hmac_obj));
1796     hmac_obj.name = hmac->name;
1797     hmac_obj.len = hmac->mac_length;
1798     silc_hmac_register(&hmac_obj);
1799
1800     hmac = hmac->next;
1801   } /* while */
1802
1803   return TRUE;
1804 }
1805
1806 /* Registers configured PKCS's. */
1807
1808 SilcBool silc_server_config_register_pkcs(SilcServer server)
1809 {
1810   return FALSE;
1811 }
1812
1813 /* Sets log files where log messages are saved by the server logger. */
1814
1815 void silc_server_config_setlogfiles(SilcServer server)
1816 {
1817   SilcServerConfig config = server->config;
1818   SilcServerConfigLogging *this;
1819
1820   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1821
1822   silc_log_timestamp(config->logging_timestamp);
1823   silc_log_quick(config->logging_quick);
1824   silc_log_flushdelay(config->logging_flushdelay ?
1825                       config->logging_flushdelay :
1826                       SILC_SERVER_LOG_FLUSH_DELAY);
1827
1828   if ((this = config->logging_fatals))
1829     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1830                       server->schedule);
1831   if ((this = config->logging_errors))
1832     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1833                       server->schedule);
1834   if ((this = config->logging_warnings))
1835     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1836                       server->schedule);
1837   if ((this = config->logging_info))
1838     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1839                       server->schedule);
1840 }
1841
1842 /* Returns client authentication information from configuration file by host
1843    (name or ip) */
1844
1845 SilcServerConfigClient *
1846 silc_server_config_find_client(SilcServer server, char *host)
1847 {
1848   SilcServerConfig config = server->config;
1849   SilcServerConfigClient *client;
1850
1851   if (!config || !host)
1852     return NULL;
1853
1854   for (client = config->clients; client; client = client->next) {
1855     if (client->host && !silc_string_compare(client->host, host))
1856       continue;
1857     break;
1858   }
1859
1860   /* if none matched, then client is already NULL */
1861   return client;
1862 }
1863
1864 /* Returns admin connection configuration by host, username and/or
1865    nickname. */
1866
1867 SilcServerConfigAdmin *
1868 silc_server_config_find_admin(SilcServer server, char *host, char *user,
1869                               char *nick)
1870 {
1871   SilcServerConfig config = server->config;
1872   SilcServerConfigAdmin *admin;
1873
1874   /* make sure we have a value for the matching parameters */
1875   if (!host)
1876     host = "*";
1877   if (!user)
1878     user = "*";
1879   if (!nick)
1880     nick = "*";
1881
1882   for (admin = config->admins; admin; admin = admin->next) {
1883     if (admin->host && !silc_string_compare(admin->host, host))
1884       continue;
1885     if (admin->user && !silc_string_compare(admin->user, user))
1886       continue;
1887     if (admin->nick && !silc_string_compare(admin->nick, nick))
1888       continue;
1889     /* no checks failed -> this entry matches */
1890     break;
1891   }
1892
1893   /* if none matched, then admin is already NULL */
1894   return admin;
1895 }
1896
1897 /* Returns the denied connection configuration entry by host. */
1898
1899 SilcServerConfigDeny *
1900 silc_server_config_find_denied(SilcServer server, char *host)
1901 {
1902   SilcServerConfig config = server->config;
1903   SilcServerConfigDeny *deny;
1904
1905   /* make sure we have a value for the matching parameters */
1906   if (!config || !host)
1907     return NULL;
1908
1909   for (deny = config->denied; deny; deny = deny->next) {
1910     if (deny->host && !silc_string_compare(deny->host, host))
1911       continue;
1912     break;
1913   }
1914
1915   /* if none matched, then deny is already NULL */
1916   return deny;
1917 }
1918
1919 /* Returns server connection info from server configuartion by host
1920    (name or ip). */
1921
1922 SilcServerConfigServer *
1923 silc_server_config_find_server_conn(SilcServer server, char *host)
1924 {
1925   SilcServerConfig config = server->config;
1926   SilcServerConfigServer *serv = NULL;
1927
1928   if (!host)
1929     return NULL;
1930
1931   if (!config->servers)
1932     return NULL;
1933
1934   for (serv = config->servers; serv; serv = serv->next) {
1935     if (!silc_string_compare(serv->host, host))
1936       continue;
1937     break;
1938   }
1939
1940   return serv;
1941 }
1942
1943 /* Returns router connection info from server configuration by
1944    host (name or ip). */
1945
1946 SilcServerConfigRouter *
1947 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1948 {
1949   SilcServerConfig config = server->config;
1950   SilcServerConfigRouter *serv = NULL;
1951
1952   if (!host)
1953     return NULL;
1954
1955   if (!config->routers)
1956     return NULL;
1957
1958   for (serv = config->routers; serv; serv = serv->next) {
1959     if (!silc_string_compare(serv->host, host))
1960       continue;
1961     if (port && serv->port && serv->port != port)
1962       continue;
1963     break;
1964   }
1965
1966   return serv;
1967 }
1968
1969 /* Find backup router connection by host (name or ip) */
1970
1971 SilcServerConfigRouter *
1972 silc_server_config_find_backup_conn(SilcServer server, char *host)
1973 {
1974   SilcServerConfig config = server->config;
1975   SilcServerConfigRouter *serv = NULL;
1976
1977   if (!host)
1978     return NULL;
1979
1980   if (!config->routers)
1981     return NULL;
1982
1983   for (serv = config->routers; serv; serv = serv->next) {
1984     if (!serv->backup_router)
1985       continue;
1986     if (!silc_string_compare(serv->host, host))
1987       continue;
1988     break;
1989   }
1990
1991   return serv;
1992 }
1993
1994 /* Returns TRUE if configuration for a router connection that we are
1995    initiating exists. */
1996
1997 SilcBool silc_server_config_is_primary_route(SilcServer server)
1998 {
1999   SilcServerConfig config = server->config;
2000   SilcServerConfigRouter *serv = NULL;
2001   int i;
2002   SilcBool found = FALSE;
2003
2004   serv = config->routers;
2005   for (i = 0; serv; i++) {
2006     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
2007       found = TRUE;
2008       break;
2009     }
2010
2011     serv = serv->next;
2012   }
2013
2014   return found;
2015 }
2016
2017 /* Returns our primary connection configuration or NULL if we do not
2018    have primary router configured. */
2019
2020 SilcServerConfigRouter *
2021 silc_server_config_get_primary_router(SilcServer server)
2022 {
2023   SilcServerConfig config = server->config;
2024   SilcServerConfigRouter *serv = NULL;
2025   int i;
2026
2027   serv = config->routers;
2028   for (i = 0; serv; i++) {
2029     if (serv->initiator == TRUE && serv->backup_router == FALSE)
2030       return serv;
2031     serv = serv->next;
2032   }
2033
2034   return NULL;
2035 }
2036
2037 /* If we have backup router configured that is going to replace us this
2038    function returns it. */
2039
2040 SilcServerConfigRouter *
2041 silc_server_config_get_backup_router(SilcServer server)
2042 {
2043   SilcServerConfig config = server->config;
2044   SilcServerConfigRouter *serv = NULL;
2045   int i;
2046
2047   if (server->server_type != SILC_ROUTER)
2048     return NULL;
2049
2050   serv = config->routers;
2051   for (i = 0; serv; i++) {
2052     if (serv->initiator == FALSE && serv->backup_router == TRUE &&
2053         serv->backup_local == TRUE &&
2054         !strcmp(server->config->server_info->primary->server_ip,
2055                 serv->backup_replace_ip) &&
2056         server->config->server_info->primary->port ==
2057         serv->backup_replace_port)
2058       return serv;
2059     serv = serv->next;
2060   }
2061
2062   return NULL;
2063 }