Preliminary SILC Server 1.1 commit.
[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_OK) {
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     silc_pkcs_public_key_free(si->public_key);
1609     silc_pkcs_private_key_free(si->private_key);
1610     silc_free(si);
1611   }
1612
1613   /* Now let's destroy the lists */
1614
1615   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1616                                   config->cipher)
1617     silc_free(di->name);
1618     silc_free(di->module);
1619     silc_free(di);
1620   }
1621   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1622     silc_free(di->name);
1623     silc_free(di->module);
1624     silc_free(di);
1625   }
1626   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1627     silc_free(di->name);
1628     silc_free(di->hash);
1629     silc_free(di);
1630   }
1631   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1632     silc_free(di->name);
1633     silc_free(di);
1634   }
1635   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1636                                   config->conn_params)
1637     silc_free(di->name);
1638     silc_free(di->version_protocol);
1639     silc_free(di->version_software);
1640     silc_free(di->version_software_vendor);
1641     silc_free(di);
1642   }
1643   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1644     silc_free(di->host);
1645     CONFIG_FREE_AUTH(di);
1646     silc_free(di);
1647   }
1648   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1649     silc_free(di->host);
1650     silc_free(di->user);
1651     silc_free(di->nick);
1652     CONFIG_FREE_AUTH(di);
1653     silc_free(di);
1654   }
1655   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1656     silc_free(di->host);
1657     silc_free(di->reason);
1658     silc_free(di);
1659   }
1660   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1661                                   config->servers)
1662     silc_free(di->host);
1663     CONFIG_FREE_AUTH(di);
1664     silc_free(di);
1665   }
1666   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1667                                   config->routers)
1668     silc_free(di->host);
1669     silc_free(di->backup_replace_ip);
1670     CONFIG_FREE_AUTH(di);
1671     silc_free(di);
1672   }
1673
1674   memset(config, 'F', sizeof(*config));
1675   silc_free(config);
1676 }
1677
1678 /* Registers configured ciphers. These can then be allocated by the
1679    server when needed. */
1680
1681 SilcBool silc_server_config_register_ciphers(SilcServer server)
1682 {
1683   SilcServerConfig config = server->config;
1684   SilcServerConfigCipher *cipher = config->cipher;
1685   char *module_path = config->module_path;
1686
1687   SILC_LOG_DEBUG(("Registering configured ciphers"));
1688
1689   if (!cipher) /* any cipher in the config file? */
1690     return FALSE;
1691
1692   while (cipher) {
1693     /* if there isn't a module_path OR there isn't a module sim name try to
1694      * use buil-in functions */
1695     if (!module_path || !cipher->module) {
1696       int i;
1697       for (i = 0; silc_default_ciphers[i].name; i++)
1698         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1699           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1700           break;
1701         }
1702       if (!silc_cipher_is_supported(cipher->name)) {
1703         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1704         silc_server_stop(server);
1705         exit(1);
1706       }
1707     }
1708     cipher = cipher->next;
1709   } /* while */
1710
1711   return TRUE;
1712 }
1713
1714 /* Registers configured hash functions. These can then be allocated by the
1715    server when needed. */
1716
1717 SilcBool silc_server_config_register_hashfuncs(SilcServer server)
1718 {
1719   SilcServerConfig config = server->config;
1720   SilcServerConfigHash *hash = config->hash;
1721   char *module_path = config->module_path;
1722
1723   SILC_LOG_DEBUG(("Registering configured hash functions"));
1724
1725   if (!hash) /* any hash func in the config file? */
1726     return FALSE;
1727
1728   while (hash) {
1729     /* if there isn't a module_path OR there isn't a module sim name try to
1730      * use buil-in functions */
1731     if (!module_path || !hash->module) {
1732       int i;
1733       for (i = 0; silc_default_hash[i].name; i++)
1734         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1735           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1736           break;
1737         }
1738       if (!silc_hash_is_supported(hash->name)) {
1739         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1740         silc_server_stop(server);
1741         exit(1);
1742       }
1743     }
1744     hash = hash->next;
1745   } /* while */
1746
1747   return TRUE;
1748 }
1749
1750 /* Registers configure HMACs. These can then be allocated by the server
1751    when needed. */
1752
1753 SilcBool silc_server_config_register_hmacs(SilcServer server)
1754 {
1755   SilcServerConfig config = server->config;
1756   SilcServerConfigHmac *hmac = config->hmac;
1757
1758   SILC_LOG_DEBUG(("Registering configured HMACs"));
1759
1760   if (!hmac)
1761     return FALSE;
1762
1763   while (hmac) {
1764     SilcHmacObject hmac_obj;
1765     if (!silc_hash_is_supported(hmac->hash)) {
1766       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1767       silc_server_stop(server);
1768       exit(1);
1769     }
1770
1771     /* Register the HMAC */
1772     memset(&hmac_obj, 0, sizeof(hmac_obj));
1773     hmac_obj.name = hmac->name;
1774     hmac_obj.len = hmac->mac_length;
1775     silc_hmac_register(&hmac_obj);
1776
1777     hmac = hmac->next;
1778   } /* while */
1779
1780   return TRUE;
1781 }
1782
1783 /* Registers configured PKCS's. */
1784
1785 SilcBool silc_server_config_register_pkcs(SilcServer server)
1786 {
1787   return TRUE;
1788 }
1789
1790 /* Sets log files where log messages are saved by the server logger. */
1791
1792 void silc_server_config_setlogfiles(SilcServer server)
1793 {
1794   SilcServerConfig config = server->config;
1795   SilcServerConfigLogging *this;
1796
1797   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1798
1799   silc_log_timestamp(config->logging_timestamp);
1800   silc_log_quick(config->logging_quick);
1801   silc_log_flushdelay(config->logging_flushdelay ?
1802                       config->logging_flushdelay :
1803                       SILC_SERVER_LOG_FLUSH_DELAY);
1804
1805   if ((this = config->logging_fatals))
1806     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1807                       server->schedule);
1808   if ((this = config->logging_errors))
1809     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1810                       server->schedule);
1811   if ((this = config->logging_warnings))
1812     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1813                       server->schedule);
1814   if ((this = config->logging_info))
1815     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1816                       server->schedule);
1817 }
1818
1819 /* Returns client authentication information from configuration file by host
1820    (name or ip) */
1821
1822 SilcServerConfigClient *
1823 silc_server_config_find_client(SilcServer server, char *host)
1824 {
1825   SilcServerConfig config = server->config;
1826   SilcServerConfigClient *client;
1827
1828   if (!config || !host)
1829     return NULL;
1830
1831   for (client = config->clients; client; client = client->next) {
1832     if (client->host && !silc_string_compare(client->host, host))
1833       continue;
1834     break;
1835   }
1836
1837   /* if none matched, then client is already NULL */
1838   return client;
1839 }
1840
1841 /* Returns admin connection configuration by host, username and/or
1842    nickname. */
1843
1844 SilcServerConfigAdmin *
1845 silc_server_config_find_admin(SilcServer server, char *host, char *user,
1846                               char *nick)
1847 {
1848   SilcServerConfig config = server->config;
1849   SilcServerConfigAdmin *admin;
1850
1851   /* make sure we have a value for the matching parameters */
1852   if (!host)
1853     host = "*";
1854   if (!user)
1855     user = "*";
1856   if (!nick)
1857     nick = "*";
1858
1859   for (admin = config->admins; admin; admin = admin->next) {
1860     if (admin->host && !silc_string_compare(admin->host, host))
1861       continue;
1862     if (admin->user && !silc_string_compare(admin->user, user))
1863       continue;
1864     if (admin->nick && !silc_string_compare(admin->nick, nick))
1865       continue;
1866     /* no checks failed -> this entry matches */
1867     break;
1868   }
1869
1870   /* if none matched, then admin is already NULL */
1871   return admin;
1872 }
1873
1874 /* Returns the denied connection configuration entry by host. */
1875
1876 SilcServerConfigDeny *
1877 silc_server_config_find_denied(SilcServer server, char *host)
1878 {
1879   SilcServerConfig config = server->config;
1880   SilcServerConfigDeny *deny;
1881
1882   /* make sure we have a value for the matching parameters */
1883   if (!config || !host)
1884     return NULL;
1885
1886   for (deny = config->denied; deny; deny = deny->next) {
1887     if (deny->host && !silc_string_compare(deny->host, host))
1888       continue;
1889     break;
1890   }
1891
1892   /* if none matched, then deny is already NULL */
1893   return deny;
1894 }
1895
1896 /* Returns server connection info from server configuartion by host
1897    (name or ip). */
1898
1899 SilcServerConfigServer *
1900 silc_server_config_find_server_conn(SilcServer server, char *host)
1901 {
1902   SilcServerConfig config = server->config;
1903   SilcServerConfigServer *serv = NULL;
1904
1905   if (!host)
1906     return NULL;
1907
1908   if (!config->servers)
1909     return NULL;
1910
1911   for (serv = config->servers; serv; serv = serv->next) {
1912     if (!silc_string_compare(serv->host, host))
1913       continue;
1914     break;
1915   }
1916
1917   return serv;
1918 }
1919
1920 /* Returns router connection info from server configuration by
1921    host (name or ip). */
1922
1923 SilcServerConfigRouter *
1924 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1925 {
1926   SilcServerConfig config = server->config;
1927   SilcServerConfigRouter *serv = NULL;
1928
1929   if (!host)
1930     return NULL;
1931
1932   if (!config->routers)
1933     return NULL;
1934
1935   for (serv = config->routers; serv; serv = serv->next) {
1936     if (!silc_string_compare(serv->host, host))
1937       continue;
1938     if (port && serv->port && serv->port != port)
1939       continue;
1940     break;
1941   }
1942
1943   return serv;
1944 }
1945
1946 /* Find backup router connection by host (name or ip) */
1947
1948 SilcServerConfigRouter *
1949 silc_server_config_find_backup_conn(SilcServer server, char *host)
1950 {
1951   SilcServerConfig config = server->config;
1952   SilcServerConfigRouter *serv = NULL;
1953
1954   if (!host)
1955     return NULL;
1956
1957   if (!config->routers)
1958     return NULL;
1959
1960   for (serv = config->routers; serv; serv = serv->next) {
1961     if (!serv->backup_router)
1962       continue;
1963     if (!silc_string_compare(serv->host, host))
1964       continue;
1965     break;
1966   }
1967
1968   return serv;
1969 }
1970
1971 /* Returns TRUE if configuration for a router connection that we are
1972    initiating exists. */
1973
1974 SilcBool silc_server_config_is_primary_route(SilcServer server)
1975 {
1976   SilcServerConfig config = server->config;
1977   SilcServerConfigRouter *serv = NULL;
1978   int i;
1979   SilcBool found = FALSE;
1980
1981   serv = config->routers;
1982   for (i = 0; serv; i++) {
1983     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1984       found = TRUE;
1985       break;
1986     }
1987
1988     serv = serv->next;
1989   }
1990
1991   return found;
1992 }
1993
1994 /* Returns our primary connection configuration or NULL if we do not
1995    have primary router configured. */
1996
1997 SilcServerConfigRouter *
1998 silc_server_config_get_primary_router(SilcServer server)
1999 {
2000   SilcServerConfig config = server->config;
2001   SilcServerConfigRouter *serv = NULL;
2002   int i;
2003
2004   serv = config->routers;
2005   for (i = 0; serv; i++) {
2006     if (serv->initiator == TRUE && serv->backup_router == FALSE)
2007       return serv;
2008     serv = serv->next;
2009   }
2010
2011   return NULL;
2012 }
2013
2014 /* If we have backup router configured that is going to replace us this
2015    function returns it. */
2016
2017 SilcServerConfigRouter *
2018 silc_server_config_get_backup_router(SilcServer server)
2019 {
2020   SilcServerConfig config = server->config;
2021   SilcServerConfigRouter *serv = NULL;
2022   int i;
2023
2024   if (server->server_type != SILC_ROUTER)
2025     return NULL;
2026
2027   serv = config->routers;
2028   for (i = 0; serv; i++) {
2029     if (serv->initiator == FALSE && serv->backup_router == TRUE &&
2030         serv->backup_local == TRUE &&
2031         !strcmp(server->config->server_info->primary->server_ip,
2032                 serv->backup_replace_ip) &&
2033         server->config->server_info->primary->port ==
2034         serv->backup_replace_port)
2035       return serv;
2036     serv = serv->next;
2037   }
2038
2039   return NULL;
2040 }