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