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