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