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