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