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