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