Merged silc_1_0_branch to trunk.
[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 if (!strcmp(name, "publickeydir")) {
925     if (!my_parse_publickeydir((char *) val, (void *)&tmp->publickeys)) {
926       got_errno = SILC_CONFIG_EPRINTLINE;
927       goto got_err;
928     }
929   }
930   else
931     return SILC_CONFIG_EINTERNAL;
932   return SILC_CONFIG_OK;
933
934  got_err:
935   silc_free(tmp->host);
936   silc_free(tmp->user);
937   silc_free(tmp->nick);
938   CONFIG_FREE_AUTH(tmp);
939   silc_free(tmp);
940   config->tmp = NULL;
941   return got_errno;
942 }
943
944 SILC_CONFIG_CALLBACK(fetch_deny)
945 {
946   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
947
948   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
949                        type, name, context));
950   if (type == SILC_CONFIG_ARG_BLOCK) {
951     /* check the temporary struct's fields */
952     if (!tmp) /* discard empty sub-blocks */
953       return SILC_CONFIG_OK;
954     if (!tmp->reason) {
955       got_errno = SILC_CONFIG_EMISSFIELDS;
956       goto got_err;
957     }
958
959     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
960     config->tmp = NULL;
961     return SILC_CONFIG_OK;
962   }
963   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny);
964
965   /* Identify and save this value */
966   if (!strcmp(name, "host")) {
967     CONFIG_IS_DOUBLE(tmp->host);
968     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
969   }
970   else if (!strcmp(name, "reason")) {
971     CONFIG_IS_DOUBLE(tmp->reason);
972     tmp->reason = strdup((char *) val);
973   }
974   else
975     return SILC_CONFIG_EINTERNAL;
976   return SILC_CONFIG_OK;
977
978  got_err:
979   silc_free(tmp->host);
980   silc_free(tmp->reason);
981   silc_free(tmp);
982   config->tmp = NULL;
983   return got_errno;
984 }
985
986 SILC_CONFIG_CALLBACK(fetch_server)
987 {
988   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
989
990   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
991                        type, name, context));
992   if (type == SILC_CONFIG_ARG_BLOCK) {
993     /* check the temporary struct's fields */
994     if (!tmp) /* discard empty sub-blocks */
995       return SILC_CONFIG_OK;
996     if (!tmp->host) {
997       got_errno = SILC_CONFIG_EMISSFIELDS;
998       goto got_err;
999     }
1000
1001     /* the temporary struct is ok, append it to the list */
1002     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
1003     config->tmp = NULL;
1004     return SILC_CONFIG_OK;
1005   }
1006   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer);
1007
1008   /* Identify and save this value */
1009   if (!strcmp(name, "host")) {
1010     CONFIG_IS_DOUBLE(tmp->host);
1011     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
1012   }
1013   else if (!strcmp(name, "passphrase")) {
1014     CONFIG_IS_DOUBLE(tmp->passphrase);
1015     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1016                            (void *)&tmp->passphrase,
1017                            &tmp->passphrase_len)) {
1018       got_errno = SILC_CONFIG_EPRINTLINE;
1019       goto got_err;
1020     }
1021   }
1022   else if (!strcmp(name, "publickey")) {
1023     CONFIG_IS_DOUBLE(tmp->publickeys);
1024     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1025                            (void *)&tmp->publickeys, NULL)) {
1026       got_errno = SILC_CONFIG_EPRINTLINE;
1027       goto got_err;
1028     }
1029   }
1030   else if (!strcmp(name, "params")) {
1031     CONFIG_IS_DOUBLE(tmp->param);
1032     tmp->param = my_find_param(config, (char *) val);
1033     if (!tmp->param) { /* error message already output */
1034       got_errno = SILC_CONFIG_EPRINTLINE;
1035       goto got_err;
1036     }
1037   }
1038   else if (!strcmp(name, "backup")) {
1039     tmp->backup_router = *(bool *)val;
1040   }
1041   else
1042     return SILC_CONFIG_EINTERNAL;
1043
1044   return SILC_CONFIG_OK;
1045
1046  got_err:
1047   silc_free(tmp->host);
1048   CONFIG_FREE_AUTH(tmp);
1049   silc_free(tmp);
1050   config->tmp = NULL;
1051   return got_errno;
1052 }
1053
1054 SILC_CONFIG_CALLBACK(fetch_router)
1055 {
1056   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
1057
1058   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
1059                        type, name, context));
1060   if (type == SILC_CONFIG_ARG_BLOCK) {
1061     if (!tmp) /* discard empty sub-blocks */
1062       return SILC_CONFIG_OK;
1063     if (!tmp->host) {
1064       got_errno = SILC_CONFIG_EMISSFIELDS;
1065       goto got_err;
1066     }
1067
1068     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
1069     config->tmp = NULL;
1070     return SILC_CONFIG_OK;
1071   }
1072   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigRouter);
1073
1074   /* Identify and save this value */
1075   if (!strcmp(name, "host")) {
1076     CONFIG_IS_DOUBLE(tmp->host);
1077     tmp->host = strdup((char *) val);
1078   }
1079   else if (!strcmp(name, "port")) {
1080     int port = *(int *)val;
1081     if ((port <= 0) || (port > 65535)) {
1082       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1083                              "Invalid port number!"));
1084       got_errno = SILC_CONFIG_EPRINTLINE;
1085       goto got_err;
1086     }
1087     tmp->port = (SilcUInt16) port;
1088   }
1089   else if (!strcmp(name, "passphrase")) {
1090     CONFIG_IS_DOUBLE(tmp->passphrase);
1091     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1092                            (void *)&tmp->passphrase,
1093                            &tmp->passphrase_len)) {
1094       got_errno = SILC_CONFIG_EPRINTLINE;
1095       goto got_err;
1096     }
1097   }
1098   else if (!strcmp(name, "publickey")) {
1099     CONFIG_IS_DOUBLE(tmp->publickeys);
1100     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1101                            (void *)&tmp->publickeys, NULL)) {
1102       got_errno = SILC_CONFIG_EPRINTLINE;
1103       goto got_err;
1104     }
1105   }
1106   else if (!strcmp(name, "params")) {
1107     CONFIG_IS_DOUBLE(tmp->param);
1108     tmp->param = my_find_param(config, (char *) val);
1109     if (!tmp->param) { /* error message already output */
1110       got_errno = SILC_CONFIG_EPRINTLINE;
1111       goto got_err;
1112     }
1113   }
1114   else if (!strcmp(name, "initiator")) {
1115     tmp->initiator = *(bool *)val;
1116   }
1117   else if (!strcmp(name, "backuphost")) {
1118     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
1119     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
1120                               strdup("*"));
1121     tmp->backup_router = TRUE;
1122   }
1123   else if (!strcmp(name, "backupport")) {
1124     int port = *(int *)val;
1125     if ((port <= 0) || (port > 65535)) {
1126       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1127                              "Invalid port number!"));
1128       got_errno = SILC_CONFIG_EPRINTLINE;
1129       goto got_err;
1130     }
1131     tmp->backup_replace_port = (SilcUInt16) port;
1132   }
1133   else if (!strcmp(name, "backuplocal")) {
1134     tmp->backup_local = *(bool *)val;
1135   }
1136   else
1137     return SILC_CONFIG_EINTERNAL;
1138
1139   return SILC_CONFIG_OK;
1140
1141  got_err:
1142   silc_free(tmp->host);
1143   silc_free(tmp->backup_replace_ip);
1144   CONFIG_FREE_AUTH(tmp);
1145   silc_free(tmp);
1146   config->tmp = NULL;
1147   return got_errno;
1148 }
1149
1150 /* known config options tables */
1151 static const SilcConfigTable table_general[] = {
1152   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1153   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1154   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1155   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1156   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1157   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1158   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1159   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1160   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1161   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1162   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1163   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1164   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1165   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1166   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1167   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1168   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1169   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1170   { "detach_disabled",          SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1171   { "detach_timeout",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1172   { "qos",                      SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1173   { "qos_rate_limit",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1174   { "qos_bytes_limit",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1175   { "qos_limit_sec",            SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1176   { "qos_limit_usec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1177   { "debug_string",             SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1178   { 0, 0, 0, 0 }
1179 };
1180
1181 static const SilcConfigTable table_cipher[] = {
1182   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1183   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
1184   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1185   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1186   { 0, 0, 0, 0 }
1187 };
1188
1189 static const SilcConfigTable table_hash[] = {
1190   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1191   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
1192   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1193   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1194   { 0, 0, 0, 0 }
1195 };
1196
1197 static const SilcConfigTable table_hmac[] = {
1198   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1199   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1200   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1201   { 0, 0, 0, 0 }
1202 };
1203
1204 static const SilcConfigTable table_pkcs[] = {
1205   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1206   { 0, 0, 0, 0 }
1207 };
1208
1209 static const SilcConfigTable table_serverinfo_c[] = {
1210   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1211   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1212   { 0, 0, 0, 0 }
1213 };
1214
1215 static const SilcConfigTable table_serverinfo[] = {
1216   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1217   { "primary",          SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1218   { "secondary",        SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1219   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1220   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1221   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1222   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1223   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1224   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1225   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1226   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1227   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1228   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1229   { 0, 0, 0, 0 }
1230 };
1231
1232 static const SilcConfigTable table_logging_c[] = {
1233   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1234   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1235 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1236   { 0, 0, 0, 0 }
1237 };
1238
1239 static const SilcConfigTable table_logging[] = {
1240   { "timestamp",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1241   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1242   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1243   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1244   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1245   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1246   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1247   { 0, 0, 0, 0 }
1248 };
1249
1250 static const SilcConfigTable table_connparam[] = {
1251   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1252   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1253   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1254   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1255   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1256   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1257   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1258   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1259   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1260   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1261   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1262   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1263   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1264   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1265   { "anonymous",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1266   { "qos",                     SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1267   { "qos_rate_limit",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1268   { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1269   { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1270   { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1271   { 0, 0, 0, 0 }
1272 };
1273
1274 static const SilcConfigTable table_client[] = {
1275   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1276   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1277   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1278   { "publickeydir",     SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1279   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1280   { 0, 0, 0, 0 }
1281 };
1282
1283 static const SilcConfigTable table_admin[] = {
1284   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1285   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1286   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1287   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1288   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1289   { "publickeydir",     SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1290   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1291   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1292   { 0, 0, 0, 0 }
1293 };
1294
1295 static const SilcConfigTable table_deny[] = {
1296   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1297   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1298   { 0, 0, 0, 0 }
1299 };
1300
1301 static const SilcConfigTable table_serverconn[] = {
1302   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1303   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1304   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1305   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1306   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1307   { 0, 0, 0, 0 }
1308 };
1309
1310 static const SilcConfigTable table_routerconn[] = {
1311   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1312   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1313   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1314   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1315   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1316   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1317   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1318   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1319   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1320   { 0, 0, 0, 0 }
1321 };
1322
1323 static const SilcConfigTable table_main[] = {
1324   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1325   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1326   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1327   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1328   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1329   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1330   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1331   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1332   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1333   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1334   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1335   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1336   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1337   { 0, 0, 0, 0 }
1338 };
1339
1340 /* Set default values to stuff that was not configured. */
1341
1342 static void silc_server_config_set_defaults(SilcServerConfig config)
1343 {
1344   my_set_param_defaults(&config->param, NULL);
1345
1346   config->channel_rekey_secs = (config->channel_rekey_secs ?
1347                                 config->channel_rekey_secs :
1348                                 SILC_SERVER_CHANNEL_REKEY);
1349   config->key_exchange_timeout = (config->key_exchange_timeout ?
1350                                   config->key_exchange_timeout :
1351                                   SILC_SERVER_SKE_TIMEOUT);
1352   config->conn_auth_timeout = (config->conn_auth_timeout ?
1353                                config->conn_auth_timeout :
1354                                SILC_SERVER_CONNAUTH_TIMEOUT);
1355 }
1356
1357 /* Check for correctness of the configuration */
1358
1359 static bool silc_server_config_check(SilcServerConfig config)
1360 {
1361   bool ret = TRUE;
1362   SilcServerConfigServer *s;
1363   SilcServerConfigRouter *r;
1364   bool b = FALSE;
1365
1366   /* ServerConfig is mandatory */
1367   if (!config->server_info) {
1368     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `ServerInfo'"));
1369     ret = FALSE;
1370   }
1371
1372   /* RouterConnection sanity checks */
1373
1374   if (config->routers && config->routers->backup_router == TRUE &&
1375       !config->servers) {
1376     SILC_SERVER_LOG_ERROR((
1377          "\nError: First RouterConnection block must be primary router "
1378          "connection. You have marked it incorrectly as backup router."));
1379     ret = FALSE;
1380   }
1381 #if 0
1382   if (config->routers && config->routers->initiator == FALSE &&
1383       config->routers->backup_router == FALSE) {
1384     SILC_SERVER_LOG_ERROR((
1385          "\nError: First RouterConnection block must be primary router "
1386          "connection and it must be marked as Initiator."));
1387     ret = FALSE;
1388   }
1389 #endif
1390   if (config->routers && config->routers->backup_router == TRUE &&
1391       !config->servers && !config->routers->next) {
1392     SILC_SERVER_LOG_ERROR((
1393          "\nError: You have configured backup router but not primary router. "
1394          "If backup router is configured also primary router must be "
1395          "configured."));
1396     ret = FALSE;
1397   }
1398
1399   /* Backup router sanity checks */
1400
1401   for (r = config->routers; r; r = r->next) {
1402     if (r->backup_router && !strcmp(r->host, r->backup_replace_ip)) {
1403       SILC_SERVER_LOG_ERROR((
1404           "\nError: Backup router connection incorrectly configured to use "
1405           "primary and backup router as same host `%s'. They must not be "
1406           "same host.", r->host));
1407       ret = FALSE;
1408     }
1409
1410     if (r->initiator == FALSE && r->port != 0) {
1411       SILC_SERVER_LOG_WARNING(("\nWarning: Initiator is FALSE and Port is "
1412                                "specified. Ignoring Port value."));
1413       r->port = 0;
1414     }
1415   }
1416
1417   /* ServerConnection sanity checks */
1418
1419   for (s = config->servers; s; s = s->next) {
1420     if (s->backup_router) {
1421       b = TRUE;
1422       break;
1423     }
1424   }
1425   if (b) {
1426     for (s = config->servers; s; s = s->next) {
1427       if (!s->backup_router) {
1428         SILC_SERVER_LOG_ERROR((
1429           "\nError: Your server is backup router but not all ServerConnection "
1430           "blocks were marked as backup connections. They all must be "
1431           "marked as backup connections."));
1432         ret = FALSE;
1433         break;
1434       }
1435     }
1436   }
1437
1438   return ret;
1439 }
1440
1441 /* Allocates a new configuration object, opens configuration file and
1442    parses it. The parsed data is returned to the newly allocated
1443    configuration object. The SilcServerConfig must be freed by calling
1444    the silc_server_config_destroy function. */
1445
1446 SilcServerConfig silc_server_config_alloc(const char *filename)
1447 {
1448   SilcServerConfig config_new;
1449   SilcConfigEntity ent;
1450   SilcConfigFile *file;
1451   int ret;
1452   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1453
1454   /* alloc a config object */
1455   config_new = silc_calloc(1, sizeof(*config_new));
1456   if (!config_new)
1457     return NULL;
1458
1459   /* general config defaults */
1460   config_new->refcount = 1;
1461   config_new->logging_timestamp = TRUE;
1462   config_new->param.reconnect_keep_trying = TRUE;
1463
1464   /* obtain a config file object */
1465   file = silc_config_open(filename);
1466   if (!file) {
1467     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'",
1468                            filename));
1469     return NULL;
1470   }
1471
1472   /* obtain a SilcConfig entity, we can use it to start the parsing */
1473   ent = silc_config_init(file);
1474
1475   /* load the known configuration options, give our empty object as context */
1476   silc_config_register_table(ent, table_main, (void *) config_new);
1477
1478   /* enter the main parsing loop.  When this returns, we have the parsing
1479    * result and the object filled (or partially, in case of errors). */
1480   ret = silc_config_main(ent);
1481   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1482                   silc_config_strerror(ret)));
1483
1484   /* Check if the parser returned errors */
1485   if (ret) {
1486     /* handle this special error return which asks to quietly return */
1487     if (ret != SILC_CONFIG_ESILENT) {
1488       char *linebuf, *filename = silc_config_get_filename(file);
1489       SilcUInt32 line = silc_config_get_line(file);
1490       if (ret != SILC_CONFIG_EPRINTLINE)
1491         SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.",
1492                                silc_config_strerror(ret)));
1493       linebuf = silc_config_read_line(file, line);
1494       if (linebuf) {
1495         SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1496                                line, linebuf));
1497         silc_free(linebuf);
1498       }
1499     }
1500     silc_server_config_destroy(config_new);
1501     silc_config_close(file);
1502     return NULL;
1503   }
1504
1505   /* close (destroy) the file object */
1506   silc_config_close(file);
1507
1508   /* Check the configuration */
1509   if (!silc_server_config_check(config_new)) {
1510     silc_server_config_destroy(config_new);
1511     return NULL;
1512   }
1513
1514   /* Set default to configuration parameters */
1515   silc_server_config_set_defaults(config_new);
1516
1517   return config_new;
1518 }
1519
1520 /* Increments the reference counter of a config object */
1521
1522 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1523                             void *ref_ptr)
1524 {
1525   if (ref_ptr) {
1526     config->refcount++;
1527     ref->config = config;
1528     ref->ref_ptr = ref_ptr;
1529     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %d->%d", config,
1530                     config->refcount - 1, config->refcount));
1531   }
1532 }
1533
1534 /* Decrements the reference counter of a config object.  If the counter
1535    reaches 0, the config object is destroyed. */
1536
1537 void silc_server_config_unref(SilcServerConfigRef *ref)
1538 {
1539   if (ref->ref_ptr)
1540     silc_server_config_destroy(ref->config);
1541 }
1542
1543 /* Destroy a config object with all his children lists */
1544
1545 void silc_server_config_destroy(SilcServerConfig config)
1546 {
1547   void *tmp;
1548
1549   config->refcount--;
1550   SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %d->%d", config,
1551                   config->refcount + 1, config->refcount));
1552   if (config->refcount > 0)
1553     return;
1554
1555   SILC_LOG_DEBUG(("Freeing config context"));
1556
1557   /* Destroy general config stuff */
1558   silc_free(config->module_path);
1559   silc_free(config->debug_string);
1560   silc_free(config->param.version_protocol);
1561   silc_free(config->param.version_software);
1562   silc_free(config->param.version_software_vendor);
1563
1564   /* Destroy Logging channels */
1565   if (config->logging_info)
1566     silc_free(config->logging_info->file);
1567   if (config->logging_warnings)
1568     silc_free(config->logging_warnings->file);
1569   if (config->logging_errors)
1570     silc_free(config->logging_errors->file);
1571   if (config->logging_fatals)
1572     silc_free(config->logging_fatals->file);
1573   silc_free(config->logging_info);
1574   silc_free(config->logging_warnings);
1575   silc_free(config->logging_errors);
1576   silc_free(config->logging_fatals);
1577
1578   /* Destroy the ServerInfo struct */
1579   if (config->server_info) {
1580     register SilcServerConfigServerInfo *si = config->server_info;
1581     silc_free(si->server_name);
1582     if (si->primary) {
1583       silc_free(si->primary->server_ip);
1584       silc_free(si->primary);
1585     }
1586     SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServerInfoInterface,
1587                                   si->secondary)
1588       silc_free(di->server_ip);
1589       silc_free(di);
1590     }
1591     silc_free(si->server_type);
1592     silc_free(si->location);
1593     silc_free(si->admin);
1594     silc_free(si->email);
1595     silc_free(si->user);
1596     silc_free(si->group);
1597     silc_free(si->motd_file);
1598     silc_free(si->pid_file);
1599     silc_pkcs_public_key_free(si->public_key);
1600     silc_pkcs_private_key_free(si->private_key);
1601     silc_free(si);
1602   }
1603
1604   /* Now let's destroy the lists */
1605
1606   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1607                                   config->cipher)
1608     silc_free(di->name);
1609     silc_free(di->module);
1610     silc_free(di);
1611   }
1612   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1613     silc_free(di->name);
1614     silc_free(di->module);
1615     silc_free(di);
1616   }
1617   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1618     silc_free(di->name);
1619     silc_free(di->hash);
1620     silc_free(di);
1621   }
1622   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1623     silc_free(di->name);
1624     silc_free(di);
1625   }
1626   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1627                                   config->conn_params)
1628     silc_free(di->name);
1629     silc_free(di->version_protocol);
1630     silc_free(di->version_software);
1631     silc_free(di->version_software_vendor);
1632     silc_free(di);
1633   }
1634   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1635     silc_free(di->host);
1636     CONFIG_FREE_AUTH(di);
1637     silc_free(di);
1638   }
1639   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1640     silc_free(di->host);
1641     silc_free(di->user);
1642     silc_free(di->nick);
1643     CONFIG_FREE_AUTH(di);
1644     silc_free(di);
1645   }
1646   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1647     silc_free(di->host);
1648     silc_free(di->reason);
1649     silc_free(di);
1650   }
1651   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1652                                   config->servers)
1653     silc_free(di->host);
1654     CONFIG_FREE_AUTH(di);
1655     silc_free(di);
1656   }
1657   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1658                                   config->routers)
1659     silc_free(di->host);
1660     silc_free(di->backup_replace_ip);
1661     CONFIG_FREE_AUTH(di);
1662     silc_free(di);
1663   }
1664
1665   memset(config, 'F', sizeof(*config));
1666   silc_free(config);
1667 }
1668
1669 /* Registers configured ciphers. These can then be allocated by the
1670    server when needed. */
1671
1672 bool silc_server_config_register_ciphers(SilcServer server)
1673 {
1674   SilcServerConfig config = server->config;
1675   SilcServerConfigCipher *cipher = config->cipher;
1676   char *module_path = config->module_path;
1677
1678   SILC_LOG_DEBUG(("Registering configured ciphers"));
1679
1680   if (!cipher) /* any cipher in the config file? */
1681     return FALSE;
1682
1683   while (cipher) {
1684     /* if there isn't a module_path OR there isn't a module sim name try to
1685      * use buil-in functions */
1686     if (!module_path || !cipher->module) {
1687       int i;
1688       for (i = 0; silc_default_ciphers[i].name; i++)
1689         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1690           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1691           break;
1692         }
1693       if (!silc_cipher_is_supported(cipher->name)) {
1694         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1695         silc_server_stop(server);
1696         exit(1);
1697       }
1698     } else {
1699 #ifdef SILC_SIM
1700       /* Load (try at least) the crypto SIM module */
1701       char buf[1023], *alg_name;
1702       SilcCipherObject cipher_obj;
1703       SilcSim sim;
1704
1705       memset(&cipher_obj, 0, sizeof(cipher_obj));
1706       cipher_obj.name = cipher->name;
1707       cipher_obj.block_len = cipher->block_length;
1708       cipher_obj.key_len = cipher->key_length * 8;
1709
1710       /* build the libname */
1711       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1712                 cipher->module);
1713       sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
1714
1715       alg_name = strdup(cipher->name);
1716       if (strchr(alg_name, '-'))
1717         *strchr(alg_name, '-') = '\0';
1718
1719       if (silc_sim_load(sim)) {
1720         cipher_obj.set_key =
1721           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1722                                                 SILC_CIPHER_SIM_SET_KEY));
1723         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1724         cipher_obj.set_key_with_string =
1725           silc_sim_getsym(sim,
1726             silc_sim_symname(alg_name,
1727               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1728         SILC_LOG_DEBUG(("set_key_with_string=%p",
1729           cipher_obj.set_key_with_string));
1730         cipher_obj.encrypt =
1731           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1732                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1733         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1734         cipher_obj.decrypt =
1735           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1736                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1737         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1738         cipher_obj.context_len =
1739           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1740                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1741         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1742
1743         /* Put the SIM to the list of all SIM's in server */
1744         silc_dlist_add(server->sim, sim);
1745
1746         silc_free(alg_name);
1747       } else {
1748         SILC_LOG_ERROR(("Error configuring ciphers"));
1749         silc_sim_free(sim);
1750         silc_server_stop(server);
1751         exit(1);
1752       }
1753
1754       /* Register the cipher */
1755       silc_cipher_register(&cipher_obj);
1756 #else
1757       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1758                         "can't load modules!"));
1759       silc_server_stop(server);
1760       exit(1);
1761 #endif
1762     }
1763     cipher = cipher->next;
1764   } /* while */
1765
1766   return TRUE;
1767 }
1768
1769 /* Registers configured hash functions. These can then be allocated by the
1770    server when needed. */
1771
1772 bool silc_server_config_register_hashfuncs(SilcServer server)
1773 {
1774   SilcServerConfig config = server->config;
1775   SilcServerConfigHash *hash = config->hash;
1776   char *module_path = config->module_path;
1777
1778   SILC_LOG_DEBUG(("Registering configured hash functions"));
1779
1780   if (!hash) /* any hash func in the config file? */
1781     return FALSE;
1782
1783   while (hash) {
1784     /* if there isn't a module_path OR there isn't a module sim name try to
1785      * use buil-in functions */
1786     if (!module_path || !hash->module) {
1787       int i;
1788       for (i = 0; silc_default_hash[i].name; i++)
1789         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1790           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1791           break;
1792         }
1793       if (!silc_hash_is_supported(hash->name)) {
1794         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1795         silc_server_stop(server);
1796         exit(1);
1797       }
1798     } else {
1799 #ifdef SILC_SIM
1800       /* Load (try at least) the hash SIM module */
1801       SilcHashObject hash_obj;
1802       SilcSim sim;
1803
1804       memset(&hash_obj, 0, sizeof(hash_obj));
1805       hash_obj.name = hash->name;
1806       hash_obj.block_len = hash->block_length;
1807       hash_obj.hash_len = hash->digest_length;
1808
1809       sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
1810
1811       if ((silc_sim_load(sim))) {
1812         hash_obj.init =
1813           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1814                                                 SILC_HASH_SIM_INIT));
1815         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1816         hash_obj.update =
1817           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1818                                                 SILC_HASH_SIM_UPDATE));
1819         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1820         hash_obj.final =
1821           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1822                                                 SILC_HASH_SIM_FINAL));
1823         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1824         hash_obj.context_len =
1825           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1826                                                 SILC_HASH_SIM_CONTEXT_LEN));
1827         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1828
1829         /* Put the SIM to the table of all SIM's in server */
1830         silc_dlist_add(server->sim, sim);
1831       } else {
1832         SILC_LOG_ERROR(("Error configuring hash functions"));
1833         silc_sim_free(sim);
1834         silc_server_stop(server);
1835         exit(1);
1836       }
1837
1838       /* Register the hash function */
1839       silc_hash_register(&hash_obj);
1840 #else
1841       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1842                         "can't load modules!"));
1843       silc_server_stop(server);
1844       exit(1);
1845 #endif
1846     }
1847     hash = hash->next;
1848   } /* while */
1849
1850   return TRUE;
1851 }
1852
1853 /* Registers configure HMACs. These can then be allocated by the server
1854    when needed. */
1855
1856 bool silc_server_config_register_hmacs(SilcServer server)
1857 {
1858   SilcServerConfig config = server->config;
1859   SilcServerConfigHmac *hmac = config->hmac;
1860
1861   SILC_LOG_DEBUG(("Registering configured HMACs"));
1862
1863   if (!hmac)
1864     return FALSE;
1865
1866   while (hmac) {
1867     SilcHmacObject hmac_obj;
1868     if (!silc_hash_is_supported(hmac->hash)) {
1869       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1870       silc_server_stop(server);
1871       exit(1);
1872     }
1873
1874     /* Register the HMAC */
1875     memset(&hmac_obj, 0, sizeof(hmac_obj));
1876     hmac_obj.name = hmac->name;
1877     hmac_obj.len = hmac->mac_length;
1878     silc_hmac_register(&hmac_obj);
1879
1880     hmac = hmac->next;
1881   } /* while */
1882
1883   return TRUE;
1884 }
1885
1886 /* Registers configured PKCS's. */
1887
1888 bool silc_server_config_register_pkcs(SilcServer server)
1889 {
1890   SilcServerConfig config = server->config;
1891   SilcServerConfigPkcs *pkcs = config->pkcs;
1892
1893   SILC_LOG_DEBUG(("Registering configured PKCS"));
1894
1895   if (!pkcs)
1896     return FALSE;
1897
1898   while (pkcs) {
1899     int i;
1900     for (i = 0; silc_default_pkcs[i].name; i++)
1901       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1902         silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
1903         break;
1904       }
1905     if (!silc_pkcs_is_supported(pkcs->name)) {
1906       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1907       silc_server_stop(server);
1908       exit(1);
1909     }
1910     pkcs = pkcs->next;
1911   } /* while */
1912
1913   return TRUE;
1914 }
1915
1916 /* Sets log files where log messages are saved by the server logger. */
1917
1918 void silc_server_config_setlogfiles(SilcServer server)
1919 {
1920   SilcServerConfig config = server->config;
1921   SilcServerConfigLogging *this;
1922
1923   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1924
1925   silc_log_timestamp = config->logging_timestamp;
1926   silc_log_quick = config->logging_quick;
1927   silc_log_flushdelay = (config->logging_flushdelay ?
1928                          config->logging_flushdelay :
1929                          SILC_SERVER_LOG_FLUSH_DELAY);
1930
1931   if ((this = config->logging_fatals))
1932     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1933                       server->schedule);
1934   if ((this = config->logging_errors))
1935     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1936                       server->schedule);
1937   if ((this = config->logging_warnings))
1938     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1939                       server->schedule);
1940   if ((this = config->logging_info))
1941     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1942                       server->schedule);
1943 }
1944
1945 /* Returns client authentication information from configuration file by host
1946    (name or ip) */
1947
1948 SilcServerConfigClient *
1949 silc_server_config_find_client(SilcServer server, char *host)
1950 {
1951   SilcServerConfig config = server->config;
1952   SilcServerConfigClient *client;
1953
1954   if (!config || !host)
1955     return NULL;
1956
1957   for (client = config->clients; client; client = client->next) {
1958     if (client->host && !silc_string_compare(client->host, host))
1959       continue;
1960     break;
1961   }
1962
1963   /* if none matched, then client is already NULL */
1964   return client;
1965 }
1966
1967 /* Returns admin connection configuration by host, username and/or
1968    nickname. */
1969
1970 SilcServerConfigAdmin *
1971 silc_server_config_find_admin(SilcServer server, char *host, char *user,
1972                               char *nick)
1973 {
1974   SilcServerConfig config = server->config;
1975   SilcServerConfigAdmin *admin;
1976
1977   /* make sure we have a value for the matching parameters */
1978   if (!host)
1979     host = "*";
1980   if (!user)
1981     user = "*";
1982   if (!nick)
1983     nick = "*";
1984
1985   for (admin = config->admins; admin; admin = admin->next) {
1986     if (admin->host && !silc_string_compare(admin->host, host))
1987       continue;
1988     if (admin->user && !silc_string_compare(admin->user, user))
1989       continue;
1990     if (admin->nick && !silc_string_compare(admin->nick, nick))
1991       continue;
1992     /* no checks failed -> this entry matches */
1993     break;
1994   }
1995
1996   /* if none matched, then admin is already NULL */
1997   return admin;
1998 }
1999
2000 /* Returns the denied connection configuration entry by host. */
2001
2002 SilcServerConfigDeny *
2003 silc_server_config_find_denied(SilcServer server, char *host)
2004 {
2005   SilcServerConfig config = server->config;
2006   SilcServerConfigDeny *deny;
2007
2008   /* make sure we have a value for the matching parameters */
2009   if (!config || !host)
2010     return NULL;
2011
2012   for (deny = config->denied; deny; deny = deny->next) {
2013     if (deny->host && !silc_string_compare(deny->host, host))
2014       continue;
2015     break;
2016   }
2017
2018   /* if none matched, then deny is already NULL */
2019   return deny;
2020 }
2021
2022 /* Returns server connection info from server configuartion by host
2023    (name or ip). */
2024
2025 SilcServerConfigServer *
2026 silc_server_config_find_server_conn(SilcServer server, char *host)
2027 {
2028   SilcServerConfig config = server->config;
2029   SilcServerConfigServer *serv = NULL;
2030
2031   if (!host)
2032     return NULL;
2033
2034   if (!config->servers)
2035     return NULL;
2036
2037   for (serv = config->servers; serv; serv = serv->next) {
2038     if (!silc_string_compare(serv->host, host))
2039       continue;
2040     break;
2041   }
2042
2043   return serv;
2044 }
2045
2046 /* Returns router connection info from server configuration by
2047    host (name or ip). */
2048
2049 SilcServerConfigRouter *
2050 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
2051 {
2052   SilcServerConfig config = server->config;
2053   SilcServerConfigRouter *serv = NULL;
2054
2055   if (!host)
2056     return NULL;
2057
2058   if (!config->routers)
2059     return NULL;
2060
2061   for (serv = config->routers; serv; serv = serv->next) {
2062     if (!silc_string_compare(serv->host, host))
2063       continue;
2064     if (port && serv->port && serv->port != port)
2065       continue;
2066     break;
2067   }
2068
2069   return serv;
2070 }
2071
2072 /* Find backup router connection by host (name or ip) */
2073
2074 SilcServerConfigRouter *
2075 silc_server_config_find_backup_conn(SilcServer server, char *host)
2076 {
2077   SilcServerConfig config = server->config;
2078   SilcServerConfigRouter *serv = NULL;
2079
2080   if (!host)
2081     return NULL;
2082
2083   if (!config->routers)
2084     return NULL;
2085
2086   for (serv = config->routers; serv; serv = serv->next) {
2087     if (!serv->backup_router)
2088       continue;
2089     if (!silc_string_compare(serv->host, host))
2090       continue;
2091     break;
2092   }
2093
2094   return serv;
2095 }
2096
2097 /* Returns TRUE if configuration for a router connection that we are
2098    initiating exists. */
2099
2100 bool silc_server_config_is_primary_route(SilcServer server)
2101 {
2102   SilcServerConfig config = server->config;
2103   SilcServerConfigRouter *serv = NULL;
2104   int i;
2105   bool found = FALSE;
2106
2107   serv = config->routers;
2108   for (i = 0; serv; i++) {
2109     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
2110       found = TRUE;
2111       break;
2112     }
2113
2114     serv = serv->next;
2115   }
2116
2117   return found;
2118 }
2119
2120 /* Returns our primary connection configuration or NULL if we do not
2121    have primary router configured. */
2122
2123 SilcServerConfigRouter *
2124 silc_server_config_get_primary_router(SilcServer server)
2125 {
2126   SilcServerConfig config = server->config;
2127   SilcServerConfigRouter *serv = NULL;
2128   int i;
2129
2130   serv = config->routers;
2131   for (i = 0; serv; i++) {
2132     if (serv->initiator == TRUE && serv->backup_router == FALSE)
2133       return serv;
2134     serv = serv->next;
2135   }
2136
2137   return NULL;
2138 }
2139
2140 /* If we have backup router configured that is going to replace us this
2141    function returns it. */
2142
2143 SilcServerConfigRouter *
2144 silc_server_config_get_backup_router(SilcServer server)
2145 {
2146   SilcServerConfig config = server->config;
2147   SilcServerConfigRouter *serv = NULL;
2148   int i;
2149
2150   if (server->server_type != SILC_ROUTER)
2151     return NULL;
2152
2153   serv = config->routers;
2154   for (i = 0; serv; i++) {
2155     if (serv->initiator == FALSE && serv->backup_router == TRUE &&
2156         serv->backup_local == TRUE &&
2157         !strcmp(server->config->server_info->primary->server_ip,
2158                 serv->backup_replace_ip) &&
2159         server->config->server_info->primary->port ==
2160         serv->backup_replace_port)
2161       return serv;
2162     serv = serv->next;
2163   }
2164
2165   return NULL;
2166 }