updates.
[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     if (!server_info->public_key || !server_info->private_key) {
434       got_errno = SILC_CONFIG_EMISSFIELDS;
435       goto got_err;
436     }
437     return SILC_CONFIG_OK;
438   }
439   if (!strcmp(name, "hostname")) {
440     CONFIG_IS_DOUBLE(server_info->server_name);
441     server_info->server_name = strdup((char *) val);
442   }
443   else if (!strcmp(name, "ip")) {
444     CONFIG_IS_DOUBLE(server_info->server_ip);
445     server_info->server_ip = strdup((char *) val);
446   }
447   else if (!strcmp(name, "port")) {
448     int port = *(int *)val;
449     if ((port <= 0) || (port > 65535)) {
450       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
451       return SILC_CONFIG_ESILENT;
452     }
453     server_info->port = (SilcUInt16) port;
454   }
455   else if (!strcmp(name, "servertype")) {
456     CONFIG_IS_DOUBLE(server_info->server_type);
457     server_info->server_type = strdup((char *) val);
458   }
459   else if (!strcmp(name, "admin")) {
460     CONFIG_IS_DOUBLE(server_info->admin);
461     server_info->admin = strdup((char *) val);
462   }
463   else if (!strcmp(name, "adminemail")) {
464     CONFIG_IS_DOUBLE(server_info->email);
465     server_info->email = strdup((char *) val);
466   }
467   else if (!strcmp(name, "location")) {
468     CONFIG_IS_DOUBLE(server_info->location);
469     server_info->location = strdup((char *) val);
470   }
471   else if (!strcmp(name, "user")) {
472     CONFIG_IS_DOUBLE(server_info->user);
473     server_info->user = strdup((char *) val);
474   }
475   else if (!strcmp(name, "group")) {
476     CONFIG_IS_DOUBLE(server_info->group);
477     server_info->group = strdup((char *) val);
478   }
479   else if (!strcmp(name, "motdfile")) {
480     CONFIG_IS_DOUBLE(server_info->motd_file);
481     server_info->motd_file = strdup((char *) val);
482   }
483   else if (!strcmp(name, "pidfile")) {
484     CONFIG_IS_DOUBLE(server_info->pid_file);
485     server_info->pid_file = strdup((char *) val);
486   }
487   else if (!strcmp(name, "publickey")) {
488     char *file_tmp = (char *) val;
489
490     /* try to load specified file, if fail stop config parsing */
491     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
492                                    SILC_PKCS_FILE_PEM))
493       if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
494                                      SILC_PKCS_FILE_BIN)) {
495         SILC_SERVER_LOG_ERROR(("Error: Could not load public key file.\n"));
496         SILC_SERVER_LOG_ERROR(("   line %lu: file \"%s\"\n", line, file_tmp));
497         return SILC_CONFIG_ESILENT;
498       }
499   }
500   else if (!strcmp(name, "privatekey")) {
501     char *file_tmp = (char *) val;
502
503     /* try to load specified file, if fail stop config parsing */
504     if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
505                                     SILC_PKCS_FILE_BIN))
506       if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
507                                       SILC_PKCS_FILE_PEM)) {
508         SILC_SERVER_LOG_ERROR(("Error: Could not load private key file.\n"));
509         SILC_SERVER_LOG_ERROR(("   line %lu: file \"%s\"\n", line, file_tmp));
510         return SILC_CONFIG_ESILENT;
511       }
512   }
513   else
514     return SILC_CONFIG_EINTERNAL;
515   return SILC_CONFIG_OK;
516
517  got_err:
518   return got_errno;
519 }
520
521 SILC_CONFIG_CALLBACK(fetch_logging)
522 {
523   SilcServerConfig config = (SilcServerConfig) context;
524   SilcServerConfigLogging *tmp =
525         (SilcServerConfigLogging *) config->tmp;
526   int got_errno;
527
528   if (!strcmp(name, "quicklogs")) {
529     config->logging_quick = *(bool *)val;
530   }
531   else if (!strcmp(name, "flushdelay")) {
532     int flushdelay = *(int *)val;
533     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
534       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid flushdelay value, use "
535                         "quicklogs if you want real-time logging.\n", line));
536       return SILC_CONFIG_ESILENT;
537     }
538     config->logging_flushdelay = (long) flushdelay;
539   }
540 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
541   else if (!strcmp(name, __chan__)) {                           \
542     if (!tmp) return SILC_CONFIG_OK;                            \
543     if (!tmp->file) {                                           \
544       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
545     }                                                           \
546     config->__member__ = tmp;                                   \
547     config->tmp = NULL;                                         \
548   }
549   FETCH_LOGGING_CHAN("info", logging_info)
550   FETCH_LOGGING_CHAN("warnings", logging_warnings)
551   FETCH_LOGGING_CHAN("errors", logging_errors)
552   FETCH_LOGGING_CHAN("fatals", logging_fatals)
553 #undef FETCH_LOGGING_CHAN
554   else if (!strcmp(name, "file")) {
555     if (!tmp) { /* FIXME: what the fuck is this? */
556       config->tmp = silc_calloc(1, sizeof(*tmp));
557       tmp = (SilcServerConfigLogging *) config->tmp;
558     }
559     if (tmp->file) {
560       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
561     }
562     tmp->file = strdup((char *) val);
563   }
564   else if (!strcmp(name, "size")) {
565     if (!tmp) {
566       config->tmp = silc_calloc(1, sizeof(*tmp));
567       tmp = (SilcServerConfigLogging *) config->tmp;
568     }
569     tmp->maxsize = *(SilcUInt32 *) val;
570   }
571   else
572     return SILC_CONFIG_EINTERNAL;
573   return SILC_CONFIG_OK;
574
575  got_err:
576   silc_free(tmp->file);
577   silc_free(tmp);
578   config->tmp = NULL;
579   return got_errno;
580 }
581
582 SILC_CONFIG_CALLBACK(fetch_connparam)
583 {
584   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
585
586   SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)", 
587                        type, name, context));
588
589   if (type == SILC_CONFIG_ARG_BLOCK) {
590     if (!tmp)
591       return SILC_CONFIG_OK;
592
593     if (!tmp->name) {
594       got_errno = SILC_CONFIG_EMISSFIELDS;
595       goto got_err;
596     }
597
598     /* Set defaults */
599     my_set_param_defaults(tmp, &config->param);
600
601     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
602     config->tmp = NULL;
603     return SILC_CONFIG_OK;
604   }
605
606   /* if there isn't a temporary struct alloc one */
607   if (!tmp) {
608     config->tmp = silc_calloc(1, sizeof(*findtmp));
609     tmp = (SilcServerConfigConnParams *) config->tmp;
610   }
611
612   if (!strcmp(name, "name")) {
613     CONFIG_IS_DOUBLE(tmp->name);
614     tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
615   }
616   else if (!strcmp(name, "connections_max")) {
617     tmp->connections_max = *(SilcUInt32 *)val;
618   }
619   else if (!strcmp(name, "connections_max_per_host")) {
620     tmp->connections_max_per_host = *(SilcUInt32 *)val;
621   }
622   else if (!strcmp(name, "keepalive_secs")) {
623     tmp->keepalive_secs = *(SilcUInt32 *)val;
624   }
625   else if (!strcmp(name, "reconnect_count")) {
626     tmp->reconnect_count = *(SilcUInt32 *)val;
627   }
628   else if (!strcmp(name, "reconnect_interval")) {
629     tmp->reconnect_interval = *(SilcUInt32 *)val;
630   }
631   else if (!strcmp(name, "reconnect_interval_max")) {
632     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
633   }
634   else if (!strcmp(name, "reconnect_keep_trying")) {
635     tmp->reconnect_keep_trying = *(bool *)val;
636   }
637   else if (!strcmp(name, "key_exchange_rekey")) {
638     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
639   }
640   else if (!strcmp(name, "key_exchange_pfs")) {
641     tmp->key_exchange_pfs = *(bool *)val;
642   }
643   else if (!strcmp(name, "version_protocol")) {
644     CONFIG_IS_DOUBLE(tmp->version_protocol);
645     tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
646   }
647   else if (!strcmp(name, "version_software")) {
648     CONFIG_IS_DOUBLE(tmp->version_software);
649     tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
650   }
651   else if (!strcmp(name, "version_software_vendor")) {
652     CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
653     tmp->version_software_vendor = 
654       (*(char *)val ? strdup((char *) val) : NULL);
655   }
656   else
657     return SILC_CONFIG_EINTERNAL;
658
659   return SILC_CONFIG_OK;
660
661  got_err:
662   silc_free(tmp->name);
663   silc_free(tmp);
664   config->tmp = NULL;
665   return got_errno;
666 }
667
668 SILC_CONFIG_CALLBACK(fetch_client)
669 {
670   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
671
672   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
673                        type, name, context));
674
675   /* alloc tmp before block checking (empty sub-blocks are welcome here) */
676   if (!tmp) {
677     config->tmp = silc_calloc(1, sizeof(*findtmp));
678     tmp = (SilcServerConfigClient *) config->tmp;
679   }
680
681   if (type == SILC_CONFIG_ARG_BLOCK) {
682     /* closing the block */
683     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
684     config->tmp = NULL;
685     return SILC_CONFIG_OK;
686   }
687
688   /* Identify and save this value */
689   if (!strcmp(name, "host")) {
690     CONFIG_IS_DOUBLE(tmp->host);
691     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
692   }
693   else if (!strcmp(name, "passphrase")) {
694     CONFIG_IS_DOUBLE(tmp->passphrase);
695     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
696                            (void **)&tmp->passphrase,
697                            &tmp->passphrase_len)) {
698       got_errno = SILC_CONFIG_ESILENT;
699       goto got_err;
700     }
701   }
702   else if (!strcmp(name, "publickey")) {
703     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
704                            (void **)&tmp->publickeys, NULL)) {
705       got_errno = SILC_CONFIG_ESILENT;
706       goto got_err;
707     }
708   }
709   else if (!strcmp(name, "params")) {
710     CONFIG_IS_DOUBLE(tmp->param);
711     tmp->param = my_find_param(config, (char *) val, line);
712     if (!tmp->param) { /* error already output */
713       got_errno = SILC_CONFIG_ESILENT;
714       goto got_err;
715     }
716   }
717   else
718     return SILC_CONFIG_EINTERNAL;
719   return SILC_CONFIG_OK;
720
721  got_err:
722   silc_free(tmp->host);
723   CONFIG_FREE_AUTH(tmp);
724   silc_free(tmp);
725   config->tmp = NULL;
726   return got_errno;
727 }
728
729 SILC_CONFIG_CALLBACK(fetch_admin)
730 {
731   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
732
733   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
734                        type, name, context));
735
736   if (type == SILC_CONFIG_ARG_BLOCK) {
737     /* check the temporary struct's fields */
738     if (!tmp) /* empty sub-block? */
739       return SILC_CONFIG_OK;
740
741     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
742     config->tmp = NULL;
743     return SILC_CONFIG_OK;
744   }
745
746   /* if there isn't a temporary struct alloc one */
747   if (!tmp) {
748     config->tmp = silc_calloc(1, sizeof(*findtmp));
749     tmp = (SilcServerConfigAdmin *) config->tmp;
750   }
751
752   /* Identify and save this value */
753   if (!strcmp(name, "host")) {
754     CONFIG_IS_DOUBLE(tmp->host);
755     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
756   }
757   else if (!strcmp(name, "user")) {
758     CONFIG_IS_DOUBLE(tmp->user);
759     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
760   }
761   else if (!strcmp(name, "nick")) {
762     CONFIG_IS_DOUBLE(tmp->nick);
763     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
764   }
765   else if (!strcmp(name, "passphrase")) {
766     CONFIG_IS_DOUBLE(tmp->passphrase);
767     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
768                            (void **)&tmp->passphrase,
769                            &tmp->passphrase_len)) {
770       got_errno = SILC_CONFIG_ESILENT;
771       goto got_err;
772     }
773   }
774   else if (!strcmp(name, "publickey")) {
775     CONFIG_IS_DOUBLE(tmp->publickeys);
776     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
777                            (void **)&tmp->publickeys, NULL)) {
778       got_errno = SILC_CONFIG_ESILENT;
779       goto got_err;
780     }
781   }
782   else
783     return SILC_CONFIG_EINTERNAL;
784   return SILC_CONFIG_OK;
785
786  got_err:
787   silc_free(tmp->host);
788   silc_free(tmp->user);
789   silc_free(tmp->nick);
790   CONFIG_FREE_AUTH(tmp);
791   silc_free(tmp);
792   config->tmp = NULL;
793   return got_errno;
794 }
795
796 SILC_CONFIG_CALLBACK(fetch_deny)
797 {
798   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
799
800   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
801                        type, name, context));
802   if (type == SILC_CONFIG_ARG_BLOCK) {
803     /* check the temporary struct's fields */
804     if (!tmp) /* empty sub-block? */
805       return SILC_CONFIG_OK;
806     if (!tmp->reason) {
807       got_errno = SILC_CONFIG_EMISSFIELDS;
808       goto got_err;
809     }
810     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
811     config->tmp = NULL;
812     return SILC_CONFIG_OK;
813   }
814   /* if there isn't a temporary struct alloc one */
815   if (!tmp) {
816     config->tmp = silc_calloc(1, sizeof(*findtmp));
817     tmp = (SilcServerConfigDeny *) config->tmp;
818   }
819
820   /* Identify and save this value */
821   if (!strcmp(name, "host")) {
822     CONFIG_IS_DOUBLE(tmp->host);
823     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
824   }
825   else if (!strcmp(name, "reason")) {
826     CONFIG_IS_DOUBLE(tmp->reason);
827     tmp->reason = strdup((char *) val);
828   }
829   else
830     return SILC_CONFIG_EINTERNAL;
831   return SILC_CONFIG_OK;
832
833  got_err:
834   silc_free(tmp->host);
835   silc_free(tmp->reason);
836   silc_free(tmp);
837   config->tmp = NULL;
838   return got_errno;
839 }
840
841 SILC_CONFIG_CALLBACK(fetch_server)
842 {
843   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
844
845   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
846                        type, name, context));
847
848   if (type == SILC_CONFIG_ARG_BLOCK) {
849     /* check the temporary struct's fields */
850     if (!tmp) /* empty sub-block? */
851       return SILC_CONFIG_OK;
852
853     /* the temporary struct is ok, append it to the list */
854     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
855     config->tmp = NULL;
856     return SILC_CONFIG_OK;
857   }
858
859   /* if there isn't a temporary struct alloc one */
860   if (!tmp) {
861     config->tmp = silc_calloc(1, sizeof(*findtmp));
862     tmp = (SilcServerConfigServer *) config->tmp;
863   }
864
865   /* Identify and save this value */
866   if (!strcmp(name, "host")) {
867     CONFIG_IS_DOUBLE(tmp->host);
868     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
869   }
870   else if (!strcmp(name, "passphrase")) {
871     CONFIG_IS_DOUBLE(tmp->passphrase);
872     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
873                            (void **)&tmp->passphrase,
874                            &tmp->passphrase_len)) {
875       got_errno = SILC_CONFIG_ESILENT;
876       goto got_err;
877     }
878   }
879   else if (!strcmp(name, "publickey")) {
880     CONFIG_IS_DOUBLE(tmp->publickeys);
881     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
882                            (void **)&tmp->publickeys, NULL)) {
883       got_errno = SILC_CONFIG_ESILENT;
884       goto got_err;
885     }
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   CONFIG_FREE_AUTH(tmp);
906   silc_free(tmp);
907   config->tmp = NULL;
908   return got_errno;
909 }
910
911 SILC_CONFIG_CALLBACK(fetch_router)
912 {
913   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
914
915   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
916                        type, name, context));
917
918   if (type == SILC_CONFIG_ARG_BLOCK) {
919     if (!tmp) /* empty sub-block? */
920       return SILC_CONFIG_OK;
921
922     /* the temporary struct is ok, append it to the list */
923     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
924     config->tmp = NULL;
925     return SILC_CONFIG_OK;
926   }
927
928   /* if there isn't a temporary struct alloc one */
929   if (!tmp) {
930     config->tmp = silc_calloc(1, sizeof(*findtmp));
931     tmp = (SilcServerConfigRouter *) config->tmp;
932   }
933
934   /* Identify and save this value */
935   if (!strcmp(name, "host")) {
936     CONFIG_IS_DOUBLE(tmp->host);
937     tmp->host = strdup((char *) val);
938   }
939   else if (!strcmp(name, "port")) {
940     int port = *(int *)val;
941     if ((port <= 0) || (port > 65535)) {
942       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
943       return SILC_CONFIG_ESILENT;
944     }
945     tmp->port = (SilcUInt16) port;
946   }
947   else if (!strcmp(name, "passphrase")) {
948     CONFIG_IS_DOUBLE(tmp->passphrase);
949     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
950                            (void **)&tmp->passphrase,
951                            &tmp->passphrase_len)) {
952       got_errno = SILC_CONFIG_ESILENT;
953       goto got_err;
954     }
955   }
956   else if (!strcmp(name, "publickey")) {
957     CONFIG_IS_DOUBLE(tmp->publickeys);
958     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
959                            (void **)&tmp->publickeys, NULL)) {
960       got_errno = SILC_CONFIG_ESILENT;
961       goto got_err;
962     }
963   }
964   else if (!strcmp(name, "params")) {
965     CONFIG_IS_DOUBLE(tmp->param);
966     tmp->param = my_find_param(config, (char *) val, line);
967     if (!tmp->param) { /* error already output */
968       got_errno = SILC_CONFIG_ESILENT;
969       goto got_err;
970     }
971   }
972   else if (!strcmp(name, "initiator")) {
973     tmp->initiator = *(bool *)val;
974   }
975   else if (!strcmp(name, "backuphost")) {
976     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
977     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
978                               strdup("*"));
979   }
980   else if (!strcmp(name, "backupport")) {
981     int port = *(int *)val;
982     if ((port <= 0) || (port > 65535)) {
983       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
984       return SILC_CONFIG_ESILENT;
985     }
986     tmp->backup_replace_port = (SilcUInt16) port;
987   }
988   else if (!strcmp(name, "backuplocal")) {
989     tmp->backup_local = *(bool *)val;
990   }
991   else
992     return SILC_CONFIG_EINTERNAL;
993
994   return SILC_CONFIG_OK;
995
996  got_err:
997   silc_free(tmp->host);
998   silc_free(tmp->backup_replace_ip);
999   CONFIG_FREE_AUTH(tmp);
1000   silc_free(tmp);
1001   config->tmp = NULL;
1002   return got_errno;
1003 }
1004
1005 /* known config options tables */
1006 static const SilcConfigTable table_general[] = {
1007   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1008   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1009   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1010   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1011   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1012   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1013   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1014   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1015   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1016   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1017   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1018   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1019   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1020   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1021   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1022   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1023   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1024   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1025   { 0, 0, 0, 0 }
1026 };
1027
1028 static const SilcConfigTable table_cipher[] = {
1029   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1030   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
1031   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1032   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1033   { 0, 0, 0, 0 }
1034 };
1035
1036 static const SilcConfigTable table_hash[] = {
1037   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1038   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
1039   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1040   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1041   { 0, 0, 0, 0 }
1042 };
1043
1044 static const SilcConfigTable table_hmac[] = {
1045   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1046   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1047   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1048   { 0, 0, 0, 0 }
1049 };
1050
1051 static const SilcConfigTable table_pkcs[] = {
1052   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1053   { 0, 0, 0, 0 }
1054 };
1055
1056 static const SilcConfigTable table_serverinfo[] = {
1057   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1058   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1059   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1060   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1061   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1062   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1063   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1064   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1065   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1066   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1067   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1068   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1069   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1070   { 0, 0, 0, 0 }
1071 };
1072
1073 static const SilcConfigTable table_logging_c[] = {
1074   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1075   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1076 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1077   { 0, 0, 0, 0 }
1078 };
1079
1080 static const SilcConfigTable table_logging[] = {
1081   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1082   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1083   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1084   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1085   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1086   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1087   { 0, 0, 0, 0 }
1088 };
1089
1090 static const SilcConfigTable table_connparam[] = {
1091   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1092   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1093   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1094   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1095   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1096   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1097   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1098   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1099   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1100   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1101   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1102   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1103   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1104   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1105   { 0, 0, 0, 0 }
1106 };
1107
1108 static const SilcConfigTable table_client[] = {
1109   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1110   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1111   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1112   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1113   { 0, 0, 0, 0 }
1114 };
1115
1116 static const SilcConfigTable table_admin[] = {
1117   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1118   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1119   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1120   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1121   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1122   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1123   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1124   { 0, 0, 0, 0 }
1125 };
1126
1127 static const SilcConfigTable table_deny[] = {
1128   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1129   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1130   { 0, 0, 0, 0 }
1131 };
1132
1133 static const SilcConfigTable table_serverconn[] = {
1134   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1135   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1136   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1137   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1138   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1139   { 0, 0, 0, 0 }
1140 };
1141
1142 static const SilcConfigTable table_routerconn[] = {
1143   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1144   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1145   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1146   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1147   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1148   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1149   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1150   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1151   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1152   { 0, 0, 0, 0 }
1153 };
1154
1155 static const SilcConfigTable table_main[] = {
1156   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1157   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1158   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1159   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1160   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1161   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1162   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1163   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1164   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1165   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1166   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1167   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1168   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1169   { 0, 0, 0, 0 }
1170 };
1171
1172 /* Set default values to stuff that was not configured. */
1173
1174 static void silc_server_config_set_defaults(SilcServerConfig config)
1175 {
1176   my_set_param_defaults(&config->param, NULL);
1177
1178   config->channel_rekey_secs = (config->channel_rekey_secs ?
1179                                 config->channel_rekey_secs :
1180                                 SILC_SERVER_CHANNEL_REKEY);
1181   config->key_exchange_timeout = (config->key_exchange_timeout ?
1182                                   config->key_exchange_timeout :
1183                                   SILC_SERVER_SKE_TIMEOUT);
1184   config->conn_auth_timeout = (config->conn_auth_timeout ?
1185                                config->conn_auth_timeout :
1186                                SILC_SERVER_CONNAUTH_TIMEOUT);
1187 }
1188
1189 /* Allocates a new configuration object, opens configuration file and
1190    parses it. The parsed data is returned to the newly allocated
1191    configuration object. The SilcServerConfig must be freed by calling
1192    the silc_server_config_destroy function. */
1193
1194 SilcServerConfig silc_server_config_alloc(const char *filename)
1195 {
1196   SilcServerConfig config_new;
1197   SilcConfigEntity ent;
1198   SilcConfigFile *file;
1199   int ret;
1200   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1201
1202   /* alloc a config object */
1203   config_new = silc_calloc(1, sizeof(*config_new));
1204   if (!config_new)
1205     return NULL;
1206
1207   /* obtain a config file object */
1208   file = silc_config_open(filename);
1209   if (!file) {
1210     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n",
1211                            filename));
1212     return NULL;
1213   }
1214
1215   /* obtain a SilcConfig entity, we can use it to start the parsing */
1216   ent = silc_config_init(file);
1217
1218   /* load the known configuration options, give our empty object as context */
1219   silc_config_register_table(ent, table_main, (void *) config_new);
1220
1221   /* enter the main parsing loop.  When this returns, we have the parsing
1222    * result and the object filled (or partially, in case of errors). */
1223   ret = silc_config_main(ent);
1224   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1225                   silc_config_strerror(ret)));
1226
1227   /* Check if the parser returned errors */
1228   if (ret) {
1229     /* handle this special error return which asks to quietly return */
1230     if (ret != SILC_CONFIG_ESILENT) {
1231       char *linebuf, *filename = silc_config_get_filename(file);
1232       SilcUInt32 line = silc_config_get_line(file);
1233       SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.\n",
1234                              silc_config_strerror(ret)));
1235       linebuf = silc_config_read_line(file, line);
1236       SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1237                              line, linebuf));
1238       silc_free(linebuf);
1239     }
1240     silc_server_config_destroy(config_new);
1241     return NULL;
1242   }
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 "
1250                            "`server_info'\n"));
1251     silc_server_config_destroy(config_new);
1252     return NULL;
1253   }
1254
1255   /* XXX are there any other mandatory sections in the config file? */
1256
1257   /* Set default to configuration parameters */
1258   silc_server_config_set_defaults(config_new);
1259
1260   config_new->refcount = 1;
1261   return config_new;
1262 }
1263
1264 /* Increments the reference counter of a config object */
1265
1266 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1267                             void *ref_ptr)
1268 {
1269   if (ref_ptr) {
1270     config->refcount++;
1271     ref->config = config;
1272     ref->ref_ptr = ref_ptr;
1273     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %hu->%hu", config,
1274                     config->refcount - 1, config->refcount));
1275   }
1276 }
1277
1278 /* Decrements the reference counter of a config object.  If the counter
1279    reaches 0, the config object is destroyed. */
1280
1281 void silc_server_config_unref(SilcServerConfigRef *ref)
1282 {
1283   if (ref->ref_ptr)
1284     silc_server_config_destroy(ref->config);
1285 }
1286
1287 /* Destroy a config object with all his children lists */
1288
1289 void silc_server_config_destroy(SilcServerConfig config)
1290 {
1291   void *tmp;
1292
1293   config->refcount--;
1294   SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %hu->%hu", config,
1295                   config->refcount + 1, config->refcount));
1296   if (config->refcount > 0)
1297     return;
1298
1299   SILC_LOG_DEBUG(("Freeing config context"));
1300
1301   /* Destroy general config stuff */
1302   silc_free(config->module_path);
1303   silc_free(config->param.version_protocol);
1304   silc_free(config->param.version_software);
1305   silc_free(config->param.version_software_vendor);
1306
1307   /* Destroy Logging channels */
1308   if (config->logging_info)
1309     silc_free(config->logging_info->file);
1310   if (config->logging_warnings)
1311     silc_free(config->logging_warnings->file);
1312   if (config->logging_errors)
1313     silc_free(config->logging_errors->file);
1314   if (config->logging_fatals)
1315     silc_free(config->logging_fatals->file);
1316
1317   /* Destroy the ServerInfo struct */
1318   if (config->server_info) {
1319     register SilcServerConfigServerInfo *si = config->server_info;
1320     silc_free(si->server_name);
1321     silc_free(si->server_ip);
1322     silc_free(si->server_type);
1323     silc_free(si->location);
1324     silc_free(si->admin);
1325     silc_free(si->email);
1326     silc_free(si->user);
1327     silc_free(si->group);
1328     silc_free(si->motd_file);
1329     silc_free(si->pid_file);
1330     silc_pkcs_public_key_free(si->public_key);
1331     silc_pkcs_private_key_free(si->private_key);
1332   }
1333
1334   /* Now let's destroy the lists */
1335
1336   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1337                                   config->cipher)
1338     silc_free(di->name);
1339     silc_free(di->module);
1340     silc_free(di);
1341   }
1342   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1343     silc_free(di->name);
1344     silc_free(di->module);
1345     silc_free(di);
1346   }
1347   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1348     silc_free(di->name);
1349     silc_free(di->hash);
1350     silc_free(di);
1351   }
1352   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1353     silc_free(di->name);
1354     silc_free(di);
1355   }
1356   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1357                                   config->conn_params)
1358     silc_free(di->name);
1359     silc_free(di->version_protocol);
1360     silc_free(di->version_software);
1361     silc_free(di->version_software_vendor);
1362     silc_free(di);
1363   }
1364   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1365     silc_free(di->host);
1366     CONFIG_FREE_AUTH(di);
1367     silc_free(di);
1368   }
1369   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1370     silc_free(di->host);
1371     silc_free(di->user);
1372     silc_free(di->nick);
1373     CONFIG_FREE_AUTH(di);
1374     silc_free(di);
1375   }
1376   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1377     silc_free(di->host);
1378     silc_free(di->reason);
1379     silc_free(di);
1380   }
1381   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1382                                   config->servers)
1383     silc_free(di->host);
1384     CONFIG_FREE_AUTH(di);
1385     silc_free(di);
1386   }
1387   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1388                                   config->routers)
1389     silc_free(di->host);
1390     silc_free(di->backup_replace_ip);
1391     CONFIG_FREE_AUTH(di);
1392     silc_free(di);
1393   }
1394
1395   memset(config, 'F', sizeof(*config));
1396   silc_free(config);
1397 }
1398
1399 /* Registers configured ciphers. These can then be allocated by the
1400    server when needed. */
1401
1402 bool silc_server_config_register_ciphers(SilcServer server)
1403 {
1404   SilcServerConfig config = server->config;
1405   SilcServerConfigCipher *cipher = config->cipher;
1406   char *module_path = config->module_path;
1407
1408   SILC_LOG_DEBUG(("Registering configured ciphers"));
1409
1410   if (!cipher) /* any cipher in the config file? */
1411     return FALSE;
1412
1413   while (cipher) {
1414     /* if there isn't a module_path OR there isn't a module sim name try to
1415      * use buil-in functions */
1416     if (!module_path || !cipher->module) {
1417       int i;
1418       for (i = 0; silc_default_ciphers[i].name; i++)
1419         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1420           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1421           break;
1422         }
1423       if (!silc_cipher_is_supported(cipher->name)) {
1424         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1425         silc_server_stop(server);
1426         exit(1);
1427       }
1428     } else {
1429 #ifdef SILC_SIM
1430       /* Load (try at least) the crypto SIM module */
1431       char buf[1023], *alg_name;
1432       SilcCipherObject cipher_obj;
1433       SilcSim sim;
1434
1435       memset(&cipher_obj, 0, sizeof(cipher_obj));
1436       cipher_obj.name = cipher->name;
1437       cipher_obj.block_len = cipher->block_length;
1438       cipher_obj.key_len = cipher->key_length * 8;
1439
1440       /* build the libname */
1441       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1442                 cipher->module);
1443       sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
1444
1445       alg_name = strdup(cipher->name);
1446       if (strchr(alg_name, '-'))
1447         *strchr(alg_name, '-') = '\0';
1448
1449       if (silc_sim_load(sim)) {
1450         cipher_obj.set_key =
1451           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1452                                                 SILC_CIPHER_SIM_SET_KEY));
1453         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1454         cipher_obj.set_key_with_string =
1455           silc_sim_getsym(sim, 
1456             silc_sim_symname(alg_name,
1457               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1458         SILC_LOG_DEBUG(("set_key_with_string=%p",
1459           cipher_obj.set_key_with_string));
1460         cipher_obj.encrypt =
1461           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1462                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1463         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1464         cipher_obj.decrypt =
1465           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1466                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1467         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1468         cipher_obj.context_len =
1469           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1470                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1471         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1472
1473         /* Put the SIM to the list of all SIM's in server */
1474         silc_dlist_add(server->sim, sim);
1475
1476         silc_free(alg_name);
1477       } else {
1478         SILC_LOG_ERROR(("Error configuring ciphers"));
1479         silc_server_stop(server);
1480         exit(1);
1481       }
1482
1483       /* Register the cipher */
1484       silc_cipher_register(&cipher_obj);
1485 #else
1486       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1487                         "can't load modules!"));
1488       silc_server_stop(server);
1489       exit(1);
1490 #endif
1491     }
1492     cipher = cipher->next;
1493   } /* while */
1494
1495   return TRUE;
1496 }
1497
1498 /* Registers configured hash functions. These can then be allocated by the
1499    server when needed. */
1500
1501 bool silc_server_config_register_hashfuncs(SilcServer server)
1502 {
1503   SilcServerConfig config = server->config;
1504   SilcServerConfigHash *hash = config->hash;
1505   char *module_path = config->module_path;
1506
1507   SILC_LOG_DEBUG(("Registering configured hash functions"));
1508
1509   if (!hash) /* any hash func in the config file? */
1510     return FALSE;
1511
1512   while (hash) {
1513     /* if there isn't a module_path OR there isn't a module sim name try to
1514      * use buil-in functions */
1515     if (!module_path || !hash->module) {
1516       int i;
1517       for (i = 0; silc_default_hash[i].name; i++)
1518         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1519           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1520           break;
1521         }
1522       if (!silc_hash_is_supported(hash->name)) {
1523         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1524         silc_server_stop(server);
1525         exit(1);
1526       }
1527     } else {
1528 #ifdef SILC_SIM
1529       /* Load (try at least) the hash SIM module */
1530       SilcHashObject hash_obj;
1531       SilcSim sim;
1532
1533       memset(&hash_obj, 0, sizeof(hash_obj));
1534       hash_obj.name = hash->name;
1535       hash_obj.block_len = hash->block_length;
1536       hash_obj.hash_len = hash->digest_length;
1537
1538       sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
1539
1540       if ((silc_sim_load(sim))) {
1541         hash_obj.init =
1542           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1543                                                 SILC_HASH_SIM_INIT));
1544         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1545         hash_obj.update =
1546           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1547                                                 SILC_HASH_SIM_UPDATE));
1548         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1549         hash_obj.final =
1550           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1551                                                 SILC_HASH_SIM_FINAL));
1552         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1553         hash_obj.context_len =
1554           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1555                                                 SILC_HASH_SIM_CONTEXT_LEN));
1556         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1557
1558         /* Put the SIM to the table of all SIM's in server */
1559         silc_dlist_add(server->sim, sim);
1560       } else {
1561         SILC_LOG_ERROR(("Error configuring hash functions"));
1562         silc_server_stop(server);
1563         exit(1);
1564       }
1565
1566       /* Register the hash function */
1567       silc_hash_register(&hash_obj);
1568 #else
1569       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1570                         "can't load modules!"));
1571       silc_server_stop(server);
1572       exit(1);
1573 #endif
1574     }
1575     hash = hash->next;
1576   } /* while */
1577
1578   return TRUE;
1579 }
1580
1581 /* Registers configure HMACs. These can then be allocated by the server
1582    when needed. */
1583
1584 bool silc_server_config_register_hmacs(SilcServer server)
1585 {
1586   SilcServerConfig config = server->config;
1587   SilcServerConfigHmac *hmac = config->hmac;
1588
1589   SILC_LOG_DEBUG(("Registering configured HMACs"));
1590
1591   if (!hmac)
1592     return FALSE;
1593
1594   while (hmac) {
1595     SilcHmacObject hmac_obj;
1596     if (!silc_hash_is_supported(hmac->hash)) {
1597       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1598       silc_server_stop(server);
1599       exit(1);
1600     }
1601
1602     /* Register the HMAC */
1603     memset(&hmac_obj, 0, sizeof(hmac_obj));
1604     hmac_obj.name = hmac->name;
1605     hmac_obj.len = hmac->mac_length;
1606     silc_hmac_register(&hmac_obj);
1607
1608     hmac = hmac->next;
1609   } /* while */
1610
1611   return TRUE;
1612 }
1613
1614 /* Registers configured PKCS's. */
1615
1616 bool silc_server_config_register_pkcs(SilcServer server)
1617 {
1618   SilcServerConfig config = server->config;
1619   SilcServerConfigPkcs *pkcs = config->pkcs;
1620
1621   SILC_LOG_DEBUG(("Registering configured PKCS"));
1622
1623   if (!pkcs)
1624     return FALSE;
1625
1626   while (pkcs) {
1627     int i;
1628     for (i = 0; silc_default_pkcs[i].name; i++)
1629       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1630         silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
1631         break;
1632       }
1633     if (!silc_pkcs_is_supported(pkcs->name)) {
1634       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1635       silc_server_stop(server);
1636       exit(1);
1637     }
1638     pkcs = pkcs->next;
1639   } /* while */
1640
1641   return TRUE;
1642 }
1643
1644 /* Sets log files where log messages are saved by the server logger. */
1645
1646 void silc_server_config_setlogfiles(SilcServer server)
1647 {
1648   SilcServerConfig config = server->config;
1649   SilcServerConfigLogging *this;
1650
1651   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1652
1653   silc_log_quick = config->logging_quick;
1654   silc_log_flushdelay = (config->logging_flushdelay ? 
1655                          config->logging_flushdelay :
1656                          SILC_SERVER_LOG_FLUSH_DELAY);
1657
1658   if ((this = config->logging_fatals))
1659     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1660                       server->schedule);
1661   if ((this = config->logging_errors))
1662     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1663                       server->schedule);
1664   if ((this = config->logging_warnings))
1665     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1666                       server->schedule);
1667   if ((this = config->logging_info))
1668     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1669                       server->schedule);
1670 }
1671
1672 /* Returns client authentication information from configuration file by host
1673    (name or ip) */
1674
1675 SilcServerConfigClient *
1676 silc_server_config_find_client(SilcServer server, char *host)
1677 {
1678   SilcServerConfig config = server->config;
1679   SilcServerConfigClient *client;
1680
1681   if (!config || !host)
1682     return NULL;
1683
1684   for (client = config->clients; client; client = client->next) {
1685     if (client->host && !silc_string_compare(client->host, host))
1686       continue;
1687     break;
1688   }
1689
1690   /* if none matched, then client is already NULL */
1691   return client;
1692 }
1693
1694 /* Returns admin connection configuration by host, username and/or
1695    nickname. */
1696
1697 SilcServerConfigAdmin *
1698 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1699                               char *nick)
1700 {
1701   SilcServerConfig config = server->config;
1702   SilcServerConfigAdmin *admin;
1703
1704   /* make sure we have a value for the matching parameters */
1705   if (!host)
1706     host = "*";
1707   if (!user)
1708     user = "*";
1709   if (!nick)
1710     nick = "*";
1711
1712   for (admin = config->admins; admin; admin = admin->next) {
1713     if (admin->host && !silc_string_compare(admin->host, host))
1714       continue;
1715     if (admin->user && !silc_string_compare(admin->user, user))
1716       continue;
1717     if (admin->nick && !silc_string_compare(admin->nick, nick))
1718       continue;
1719     /* no checks failed -> this entry matches */
1720     break;
1721   }
1722
1723   /* if none matched, then admin is already NULL */
1724   return admin;
1725 }
1726
1727 /* Returns the denied connection configuration entry by host. */
1728
1729 SilcServerConfigDeny *
1730 silc_server_config_find_denied(SilcServer server, char *host)
1731 {
1732   SilcServerConfig config = server->config;
1733   SilcServerConfigDeny *deny;
1734
1735   /* make sure we have a value for the matching parameters */
1736   if (!config || !host)
1737     return NULL;
1738
1739   for (deny = config->denied; deny; deny = deny->next) {
1740     if (deny->host && !silc_string_compare(deny->host, host))
1741       continue;
1742     break;
1743   }
1744
1745   /* if none matched, then deny is already NULL */
1746   return deny;
1747 }
1748
1749 /* Returns server connection info from server configuartion by host
1750    (name or ip). */
1751
1752 SilcServerConfigServer *
1753 silc_server_config_find_server_conn(SilcServer server, char *host)
1754 {
1755   SilcServerConfig config = server->config;
1756   SilcServerConfigServer *serv = NULL;
1757
1758   if (!host)
1759     return NULL;
1760
1761   if (!config->servers)
1762     return NULL;
1763
1764   for (serv = config->servers; serv; serv = serv->next) {
1765     if (!silc_string_compare(serv->host, host))
1766       continue;
1767     break;
1768   }
1769
1770   return serv;
1771 }
1772
1773 /* Returns router connection info from server configuration by
1774    host (name or ip). */
1775
1776 SilcServerConfigRouter *
1777 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1778 {
1779   SilcServerConfig config = server->config;
1780   SilcServerConfigRouter *serv = NULL;
1781
1782   if (!host)
1783     return NULL;
1784
1785   if (!config->routers)
1786     return NULL;
1787
1788   for (serv = config->routers; serv; serv = serv->next) {
1789     if (!silc_string_compare(serv->host, host))
1790       continue;
1791     if (port && serv->port && serv->port != port)
1792       continue;
1793     break;
1794   }
1795
1796   return serv;
1797 }
1798
1799 /* Returns TRUE if configuration for a router connection that we are
1800    initiating exists. */
1801
1802 bool silc_server_config_is_primary_route(SilcServer server)
1803 {
1804   SilcServerConfig config = server->config;
1805   SilcServerConfigRouter *serv = NULL;
1806   int i;
1807   bool found = FALSE;
1808
1809   serv = config->routers;
1810   for (i = 0; serv; i++) {
1811     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1812       found = TRUE;
1813       break;
1814     }
1815
1816     serv = serv->next;
1817   }
1818
1819   return found;
1820 }
1821
1822 /* Returns our primary connection configuration or NULL if we do not
1823    have primary router configured. */
1824
1825 SilcServerConfigRouter *
1826 silc_server_config_get_primary_router(SilcServer server)
1827 {
1828   SilcServerConfig config = server->config;
1829   SilcServerConfigRouter *serv = NULL;
1830   int i;
1831
1832   serv = config->routers;
1833   for (i = 0; serv; i++) {
1834     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1835       return serv;
1836     serv = serv->next;
1837   }
1838
1839   return NULL;
1840 }