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