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, "versionid")) {
888     CONFIG_IS_DOUBLE(tmp->version);
889     tmp->version = strdup((char *) val);
890   }
891   else if (!strcmp(name, "params")) {
892     CONFIG_IS_DOUBLE(tmp->param);
893     tmp->param = my_find_param(config, (char *) val, line);
894     if (!tmp->param) { /* error already output */
895       got_errno = SILC_CONFIG_ESILENT;
896       goto got_err;
897     }
898   }
899   else if (!strcmp(name, "backup")) {
900     tmp->backup_router = *(bool *)val;
901   }
902   else
903     return SILC_CONFIG_EINTERNAL;
904
905   return SILC_CONFIG_OK;
906
907  got_err:
908   silc_free(tmp->host);
909   silc_free(tmp->version);
910   CONFIG_FREE_AUTH(tmp);
911   silc_free(tmp);
912   config->tmp = NULL;
913   return got_errno;
914 }
915
916 SILC_CONFIG_CALLBACK(fetch_router)
917 {
918   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
919
920   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
921                        type, name, context));
922
923   if (type == SILC_CONFIG_ARG_BLOCK) {
924     if (!tmp) /* empty sub-block? */
925       return SILC_CONFIG_OK;
926
927     /* the temporary struct is ok, append it to the list */
928     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
929     config->tmp = NULL;
930     return SILC_CONFIG_OK;
931   }
932
933   /* if there isn't a temporary struct alloc one */
934   if (!tmp) {
935     config->tmp = silc_calloc(1, sizeof(*findtmp));
936     tmp = (SilcServerConfigRouter *) config->tmp;
937   }
938
939   /* Identify and save this value */
940   if (!strcmp(name, "host")) {
941     CONFIG_IS_DOUBLE(tmp->host);
942     tmp->host = strdup((char *) val);
943   }
944   else if (!strcmp(name, "port")) {
945     int port = *(int *)val;
946     if ((port <= 0) || (port > 65535)) {
947       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
948       return SILC_CONFIG_ESILENT;
949     }
950     tmp->port = (SilcUInt16) port;
951   }
952   else if (!strcmp(name, "passphrase")) {
953     CONFIG_IS_DOUBLE(tmp->passphrase);
954     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
955                            (void **)&tmp->passphrase,
956                            &tmp->passphrase_len)) {
957       got_errno = SILC_CONFIG_ESILENT;
958       goto got_err;
959     }
960   }
961   else if (!strcmp(name, "publickey")) {
962     CONFIG_IS_DOUBLE(tmp->publickeys);
963     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
964                            (void **)&tmp->publickeys, NULL)) {
965       got_errno = SILC_CONFIG_ESILENT;
966       goto got_err;
967     }
968   }
969   else if (!strcmp(name, "versionid")) {
970     CONFIG_IS_DOUBLE(tmp->version);
971     tmp->version = strdup((char *) val);
972   }
973   else if (!strcmp(name, "params")) {
974     CONFIG_IS_DOUBLE(tmp->param);
975     tmp->param = my_find_param(config, (char *) val, line);
976     if (!tmp->param) { /* error already output */
977       got_errno = SILC_CONFIG_ESILENT;
978       goto got_err;
979     }
980   }
981   else if (!strcmp(name, "initiator")) {
982     tmp->initiator = *(bool *)val;
983   }
984   else if (!strcmp(name, "backuphost")) {
985     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
986     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
987                               strdup("*"));
988   }
989   else if (!strcmp(name, "backupport")) {
990     int port = *(int *)val;
991     if ((port <= 0) || (port > 65535)) {
992       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
993       return SILC_CONFIG_ESILENT;
994     }
995     tmp->backup_replace_port = (SilcUInt16) port;
996   }
997   else if (!strcmp(name, "backuplocal")) {
998     tmp->backup_local = *(bool *)val;
999   }
1000   else
1001     return SILC_CONFIG_EINTERNAL;
1002
1003   return SILC_CONFIG_OK;
1004
1005  got_err:
1006   silc_free(tmp->host);
1007   silc_free(tmp->version);
1008   silc_free(tmp->backup_replace_ip);
1009   CONFIG_FREE_AUTH(tmp);
1010   silc_free(tmp);
1011   config->tmp = NULL;
1012   return got_errno;
1013 }
1014
1015 /* known config options tables */
1016 static const SilcConfigTable table_general[] = {
1017   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1018   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1019   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1020   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1021   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1022   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1023   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1024   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1025   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1026   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1027   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1028   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1029   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1030   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1031   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1032   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1033   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1034   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1035   { 0, 0, 0, 0 }
1036 };
1037
1038 static const SilcConfigTable table_cipher[] = {
1039   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1040   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
1041   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1042   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1043   { 0, 0, 0, 0 }
1044 };
1045
1046 static const SilcConfigTable table_hash[] = {
1047   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1048   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
1049   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1050   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1051   { 0, 0, 0, 0 }
1052 };
1053
1054 static const SilcConfigTable table_hmac[] = {
1055   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1056   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1057   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1058   { 0, 0, 0, 0 }
1059 };
1060
1061 static const SilcConfigTable table_pkcs[] = {
1062   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1063   { 0, 0, 0, 0 }
1064 };
1065
1066 static const SilcConfigTable table_serverinfo[] = {
1067   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1068   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1069   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1070   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1071   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1072   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1073   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1074   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1075   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1076   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1077   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1078   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1079   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1080   { 0, 0, 0, 0 }
1081 };
1082
1083 static const SilcConfigTable table_logging_c[] = {
1084   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1085   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1086 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1087   { 0, 0, 0, 0 }
1088 };
1089
1090 static const SilcConfigTable table_logging[] = {
1091   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1092   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1093   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1094   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1095   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1096   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1097   { 0, 0, 0, 0 }
1098 };
1099
1100 static const SilcConfigTable table_connparam[] = {
1101   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1102   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1103   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1104   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1105   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1106   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1107   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1108   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1109   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1110   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1111   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1112   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1113   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1114   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1115   { 0, 0, 0, 0 }
1116 };
1117
1118 static const SilcConfigTable table_client[] = {
1119   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1120   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1121   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1122   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1123   { 0, 0, 0, 0 }
1124 };
1125
1126 static const SilcConfigTable table_admin[] = {
1127   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1128   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1129   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1130   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1131   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1132   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1133   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1134   { 0, 0, 0, 0 }
1135 };
1136
1137 static const SilcConfigTable table_deny[] = {
1138   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1139   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1140   { 0, 0, 0, 0 }
1141 };
1142
1143 static const SilcConfigTable table_serverconn[] = {
1144   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1145   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1146   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1147   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1148   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1149   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1150   { 0, 0, 0, 0 }
1151 };
1152
1153 static const SilcConfigTable table_routerconn[] = {
1154   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1155   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1156   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1157   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1158   { "versionid",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1159   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1160   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1161   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1162   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1163   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1164   { 0, 0, 0, 0 }
1165 };
1166
1167 static const SilcConfigTable table_main[] = {
1168   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1169   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1170   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1171   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1172   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1173   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1174   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1175   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1176   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1177   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1178   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1179   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1180   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1181   { 0, 0, 0, 0 }
1182 };
1183
1184 /* Set default values to stuff that was not configured. */
1185
1186 static void silc_server_config_set_defaults(SilcServerConfig config)
1187 {
1188   my_set_param_defaults(&config->param, NULL);
1189
1190   config->channel_rekey_secs = (config->channel_rekey_secs ?
1191                                 config->channel_rekey_secs :
1192                                 SILC_SERVER_CHANNEL_REKEY);
1193   config->key_exchange_timeout = (config->key_exchange_timeout ?
1194                                   config->key_exchange_timeout :
1195                                   SILC_SERVER_SKE_TIMEOUT);
1196   config->conn_auth_timeout = (config->conn_auth_timeout ?
1197                                config->conn_auth_timeout :
1198                                SILC_SERVER_CONNAUTH_TIMEOUT);
1199 }
1200
1201 /* Allocates a new configuration object, opens configuration file and
1202    parses it. The parsed data is returned to the newly allocated
1203    configuration object. The SilcServerConfig must be freed by calling
1204    the silc_server_config_destroy function. */
1205
1206 SilcServerConfig silc_server_config_alloc(const char *filename)
1207 {
1208   SilcServerConfig config_new;
1209   SilcConfigEntity ent;
1210   SilcConfigFile *file;
1211   int ret;
1212   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1213
1214   /* alloc a config object */
1215   config_new = silc_calloc(1, sizeof(*config_new));
1216   if (!config_new)
1217     return NULL;
1218
1219   /* obtain a config file object */
1220   file = silc_config_open(filename);
1221   if (!file) {
1222     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n",
1223                            filename));
1224     return NULL;
1225   }
1226
1227   /* obtain a SilcConfig entity, we can use it to start the parsing */
1228   ent = silc_config_init(file);
1229
1230   /* load the known configuration options, give our empty object as context */
1231   silc_config_register_table(ent, table_main, (void *) config_new);
1232
1233   /* enter the main parsing loop.  When this returns, we have the parsing
1234    * result and the object filled (or partially, in case of errors). */
1235   ret = silc_config_main(ent);
1236   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1237                   silc_config_strerror(ret)));
1238
1239   /* Check if the parser returned errors */
1240   if (ret) {
1241     /* handle this special error return which asks to quietly return */
1242     if (ret != SILC_CONFIG_ESILENT) {
1243       char *linebuf, *filename = silc_config_get_filename(file);
1244       SilcUInt32 line = silc_config_get_line(file);
1245       SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.\n",
1246                              silc_config_strerror(ret)));
1247       linebuf = silc_config_read_line(file, line);
1248       SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1249                              line, linebuf));
1250       silc_free(linebuf);
1251     }
1252     silc_server_config_destroy(config_new);
1253     return NULL;
1254   }
1255
1256   /* close (destroy) the file object */
1257   silc_config_close(file);
1258
1259   /* If config_new is incomplete, abort the object and return NULL */
1260   if (!config_new->server_info) {
1261     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block "
1262                            "`server_info'\n"));
1263     silc_server_config_destroy(config_new);
1264     return NULL;
1265   }
1266
1267   /* XXX are there any other mandatory sections in the config file? */
1268
1269   /* Set default to configuration parameters */
1270   silc_server_config_set_defaults(config_new);
1271
1272   config_new->refcount = 1;
1273   return config_new;
1274 }
1275
1276 /* Increments the reference counter of a config object */
1277
1278 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1279                             void *ref_ptr)
1280 {
1281   if (ref_ptr) {
1282     config->refcount++;
1283     ref->config = config;
1284     ref->ref_ptr = ref_ptr;
1285     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %hu->%hu", config,
1286                     config->refcount - 1, config->refcount));
1287   }
1288 }
1289
1290 /* Decrements the reference counter of a config object.  If the counter
1291    reaches 0, the config object is destroyed. */
1292
1293 void silc_server_config_unref(SilcServerConfigRef *ref)
1294 {
1295   if (ref->ref_ptr)
1296     silc_server_config_destroy(ref->config);
1297 }
1298
1299 /* Destroy a config object with all his children lists */
1300
1301 void silc_server_config_destroy(SilcServerConfig config)
1302 {
1303   void *tmp;
1304
1305   config->refcount--;
1306   SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %hu->%hu", config,
1307                   config->refcount + 1, config->refcount));
1308   if (config->refcount > 0)
1309     return;
1310
1311   SILC_LOG_DEBUG(("Freeing config context"));
1312
1313   silc_free(config->module_path);
1314
1315   /* Destroy Logging channels */
1316   if (config->logging_info)
1317     silc_free(config->logging_info->file);
1318   if (config->logging_warnings)
1319     silc_free(config->logging_warnings->file);
1320   if (config->logging_errors)
1321     silc_free(config->logging_errors->file);
1322   if (config->logging_fatals)
1323     silc_free(config->logging_fatals->file);
1324
1325   /* Destroy the ServerInfo struct */
1326   if (config->server_info) {
1327     register SilcServerConfigServerInfo *si = config->server_info;
1328     silc_free(si->server_name);
1329     silc_free(si->server_ip);
1330     silc_free(si->server_type);
1331     silc_free(si->location);
1332     silc_free(si->admin);
1333     silc_free(si->email);
1334     silc_free(si->user);
1335     silc_free(si->group);
1336     silc_free(si->motd_file);
1337     silc_free(si->pid_file);
1338     silc_pkcs_public_key_free(si->public_key);
1339     silc_pkcs_private_key_free(si->private_key);
1340   }
1341
1342   /* Now let's destroy the lists */
1343
1344   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1345                                   config->cipher)
1346     silc_free(di->name);
1347     silc_free(di->module);
1348     silc_free(di);
1349   }
1350   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1351     silc_free(di->name);
1352     silc_free(di->module);
1353     silc_free(di);
1354   }
1355   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1356     silc_free(di->name);
1357     silc_free(di->hash);
1358     silc_free(di);
1359   }
1360   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1361     silc_free(di->name);
1362     silc_free(di);
1363   }
1364   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient,
1365                                   config->clients)
1366     silc_free(di->host);
1367     CONFIG_FREE_AUTH(di);
1368     silc_free(di);
1369   }
1370   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1371     silc_free(di->host);
1372     silc_free(di->user);
1373     silc_free(di->nick);
1374     CONFIG_FREE_AUTH(di);
1375     silc_free(di);
1376   }
1377   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1378     silc_free(di->host);
1379     silc_free(di->reason);
1380     silc_free(di);
1381   }
1382   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1383                                   config->servers)
1384     silc_free(di->host);
1385     silc_free(di->version);
1386     CONFIG_FREE_AUTH(di);
1387     silc_free(di);
1388   }
1389   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1390                                   config->routers)
1391     silc_free(di->host);
1392     silc_free(di->version);
1393     silc_free(di->backup_replace_ip);
1394     CONFIG_FREE_AUTH(di);
1395     silc_free(di);
1396   }
1397
1398   memset(config, 'F', sizeof(*config));
1399   silc_free(config);
1400 }
1401
1402 /* Registers configured ciphers. These can then be allocated by the
1403    server when needed. */
1404
1405 bool silc_server_config_register_ciphers(SilcServer server)
1406 {
1407   SilcServerConfig config = server->config;
1408   SilcServerConfigCipher *cipher = config->cipher;
1409   char *module_path = config->module_path;
1410
1411   SILC_LOG_DEBUG(("Registering configured ciphers"));
1412
1413   if (!cipher) /* any cipher in the config file? */
1414     return FALSE;
1415
1416   while (cipher) {
1417     /* if there isn't a module_path OR there isn't a module sim name try to
1418      * use buil-in functions */
1419     if (!module_path || !cipher->module) {
1420       int i;
1421       for (i = 0; silc_default_ciphers[i].name; i++)
1422         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1423           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1424           break;
1425         }
1426       if (!silc_cipher_is_supported(cipher->name)) {
1427         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1428         silc_server_stop(server);
1429         exit(1);
1430       }
1431     } else {
1432 #ifdef SILC_SIM
1433       /* Load (try at least) the crypto SIM module */
1434       char buf[1023], *alg_name;
1435       SilcCipherObject cipher_obj;
1436       SilcSim sim;
1437
1438       memset(&cipher_obj, 0, sizeof(cipher_obj));
1439       cipher_obj.name = cipher->name;
1440       cipher_obj.block_len = cipher->block_length;
1441       cipher_obj.key_len = cipher->key_length * 8;
1442
1443       /* build the libname */
1444       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1445                 cipher->module);
1446       sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
1447
1448       alg_name = strdup(cipher->name);
1449       if (strchr(alg_name, '-'))
1450         *strchr(alg_name, '-') = '\0';
1451
1452       if (silc_sim_load(sim)) {
1453         cipher_obj.set_key =
1454           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1455                                                 SILC_CIPHER_SIM_SET_KEY));
1456         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1457         cipher_obj.set_key_with_string =
1458           silc_sim_getsym(sim, 
1459             silc_sim_symname(alg_name,
1460               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1461         SILC_LOG_DEBUG(("set_key_with_string=%p",
1462           cipher_obj.set_key_with_string));
1463         cipher_obj.encrypt =
1464           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1465                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1466         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1467         cipher_obj.decrypt =
1468           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1469                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1470         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1471         cipher_obj.context_len =
1472           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1473                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1474         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1475
1476         /* Put the SIM to the list of all SIM's in server */
1477         silc_dlist_add(server->sim, sim);
1478
1479         silc_free(alg_name);
1480       } else {
1481         SILC_LOG_ERROR(("Error configuring ciphers"));
1482         silc_server_stop(server);
1483         exit(1);
1484       }
1485
1486       /* Register the cipher */
1487       silc_cipher_register(&cipher_obj);
1488 #else
1489       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1490                         "can't load modules!"));
1491       silc_server_stop(server);
1492       exit(1);
1493 #endif
1494     }
1495     cipher = cipher->next;
1496   } /* while */
1497
1498   return TRUE;
1499 }
1500
1501 /* Registers configured hash functions. These can then be allocated by the
1502    server when needed. */
1503
1504 bool silc_server_config_register_hashfuncs(SilcServer server)
1505 {
1506   SilcServerConfig config = server->config;
1507   SilcServerConfigHash *hash = config->hash;
1508   char *module_path = config->module_path;
1509
1510   SILC_LOG_DEBUG(("Registering configured hash functions"));
1511
1512   if (!hash) /* any hash func in the config file? */
1513     return FALSE;
1514
1515   while (hash) {
1516     /* if there isn't a module_path OR there isn't a module sim name try to
1517      * use buil-in functions */
1518     if (!module_path || !hash->module) {
1519       int i;
1520       for (i = 0; silc_default_hash[i].name; i++)
1521         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1522           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1523           break;
1524         }
1525       if (!silc_hash_is_supported(hash->name)) {
1526         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1527         silc_server_stop(server);
1528         exit(1);
1529       }
1530     } else {
1531 #ifdef SILC_SIM
1532       /* Load (try at least) the hash SIM module */
1533       SilcHashObject hash_obj;
1534       SilcSim sim;
1535
1536       memset(&hash_obj, 0, sizeof(hash_obj));
1537       hash_obj.name = hash->name;
1538       hash_obj.block_len = hash->block_length;
1539       hash_obj.hash_len = hash->digest_length;
1540
1541       sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
1542
1543       if ((silc_sim_load(sim))) {
1544         hash_obj.init =
1545           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1546                                                 SILC_HASH_SIM_INIT));
1547         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1548         hash_obj.update =
1549           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1550                                                 SILC_HASH_SIM_UPDATE));
1551         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1552         hash_obj.final =
1553           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1554                                                 SILC_HASH_SIM_FINAL));
1555         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1556         hash_obj.context_len =
1557           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1558                                                 SILC_HASH_SIM_CONTEXT_LEN));
1559         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1560
1561         /* Put the SIM to the table of all SIM's in server */
1562         silc_dlist_add(server->sim, sim);
1563       } else {
1564         SILC_LOG_ERROR(("Error configuring hash functions"));
1565         silc_server_stop(server);
1566         exit(1);
1567       }
1568
1569       /* Register the hash function */
1570       silc_hash_register(&hash_obj);
1571 #else
1572       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1573                         "can't load modules!"));
1574       silc_server_stop(server);
1575       exit(1);
1576 #endif
1577     }
1578     hash = hash->next;
1579   } /* while */
1580
1581   return TRUE;
1582 }
1583
1584 /* Registers configure HMACs. These can then be allocated by the server
1585    when needed. */
1586
1587 bool silc_server_config_register_hmacs(SilcServer server)
1588 {
1589   SilcServerConfig config = server->config;
1590   SilcServerConfigHmac *hmac = config->hmac;
1591
1592   SILC_LOG_DEBUG(("Registering configured HMACs"));
1593
1594   if (!hmac)
1595     return FALSE;
1596
1597   while (hmac) {
1598     SilcHmacObject hmac_obj;
1599     if (!silc_hash_is_supported(hmac->hash)) {
1600       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1601       silc_server_stop(server);
1602       exit(1);
1603     }
1604
1605     /* Register the HMAC */
1606     memset(&hmac_obj, 0, sizeof(hmac_obj));
1607     hmac_obj.name = hmac->name;
1608     hmac_obj.len = hmac->mac_length;
1609     silc_hmac_register(&hmac_obj);
1610
1611     hmac = hmac->next;
1612   } /* while */
1613
1614   return TRUE;
1615 }
1616
1617 /* Registers configured PKCS's. */
1618
1619 bool silc_server_config_register_pkcs(SilcServer server)
1620 {
1621   SilcServerConfig config = server->config;
1622   SilcServerConfigPkcs *pkcs = config->pkcs;
1623
1624   SILC_LOG_DEBUG(("Registering configured PKCS"));
1625
1626   if (!pkcs)
1627     return FALSE;
1628
1629   while (pkcs) {
1630     int i;
1631     for (i = 0; silc_default_pkcs[i].name; i++)
1632       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1633         silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
1634         break;
1635       }
1636     if (!silc_pkcs_is_supported(pkcs->name)) {
1637       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1638       silc_server_stop(server);
1639       exit(1);
1640     }
1641     pkcs = pkcs->next;
1642   } /* while */
1643
1644   return TRUE;
1645 }
1646
1647 /* Sets log files where log messages are saved by the server logger. */
1648
1649 void silc_server_config_setlogfiles(SilcServer server)
1650 {
1651   SilcServerConfig config = server->config;
1652   SilcServerConfigLogging *this;
1653
1654   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1655
1656   silc_log_quick = config->logging_quick;
1657   silc_log_flushdelay = (config->logging_flushdelay ? 
1658                          config->logging_flushdelay :
1659                          SILC_SERVER_LOG_FLUSH_DELAY);
1660
1661   if ((this = config->logging_fatals))
1662     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1663                       server->schedule);
1664   if ((this = config->logging_errors))
1665     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1666                       server->schedule);
1667   if ((this = config->logging_warnings))
1668     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1669                       server->schedule);
1670   if ((this = config->logging_info))
1671     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1672                       server->schedule);
1673 }
1674
1675 /* Returns client authentication information from configuration file by host
1676    (name or ip) */
1677
1678 SilcServerConfigClient *
1679 silc_server_config_find_client(SilcServer server, char *host)
1680 {
1681   SilcServerConfig config = server->config;
1682   SilcServerConfigClient *client;
1683
1684   if (!config || !host)
1685     return NULL;
1686
1687   for (client = config->clients; client; client = client->next) {
1688     if (client->host && !silc_string_compare(client->host, host))
1689       continue;
1690     break;
1691   }
1692
1693   /* if none matched, then client is already NULL */
1694   return client;
1695 }
1696
1697 /* Returns admin connection configuration by host, username and/or
1698    nickname. */
1699
1700 SilcServerConfigAdmin *
1701 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1702                               char *nick)
1703 {
1704   SilcServerConfig config = server->config;
1705   SilcServerConfigAdmin *admin;
1706
1707   /* make sure we have a value for the matching parameters */
1708   if (!host)
1709     host = "*";
1710   if (!user)
1711     user = "*";
1712   if (!nick)
1713     nick = "*";
1714
1715   for (admin = config->admins; admin; admin = admin->next) {
1716     if (admin->host && !silc_string_compare(admin->host, host))
1717       continue;
1718     if (admin->user && !silc_string_compare(admin->user, user))
1719       continue;
1720     if (admin->nick && !silc_string_compare(admin->nick, nick))
1721       continue;
1722     /* no checks failed -> this entry matches */
1723     break;
1724   }
1725
1726   /* if none matched, then admin is already NULL */
1727   return admin;
1728 }
1729
1730 /* Returns the denied connection configuration entry by host. */
1731
1732 SilcServerConfigDeny *
1733 silc_server_config_find_denied(SilcServer server, char *host)
1734 {
1735   SilcServerConfig config = server->config;
1736   SilcServerConfigDeny *deny;
1737
1738   /* make sure we have a value for the matching parameters */
1739   if (!config || !host)
1740     return NULL;
1741
1742   for (deny = config->denied; deny; deny = deny->next) {
1743     if (deny->host && !silc_string_compare(deny->host, host))
1744       continue;
1745     break;
1746   }
1747
1748   /* if none matched, then deny is already NULL */
1749   return deny;
1750 }
1751
1752 /* Returns server connection info from server configuartion by host
1753    (name or ip). */
1754
1755 SilcServerConfigServer *
1756 silc_server_config_find_server_conn(SilcServer server, char *host)
1757 {
1758   SilcServerConfig config = server->config;
1759   SilcServerConfigServer *serv = NULL;
1760
1761   if (!host)
1762     return NULL;
1763
1764   if (!config->servers)
1765     return NULL;
1766
1767   for (serv = config->servers; serv; serv = serv->next) {
1768     if (!silc_string_compare(serv->host, host))
1769       continue;
1770     break;
1771   }
1772
1773   return serv;
1774 }
1775
1776 /* Returns router connection info from server configuration by
1777    host (name or ip). */
1778
1779 SilcServerConfigRouter *
1780 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1781 {
1782   SilcServerConfig config = server->config;
1783   SilcServerConfigRouter *serv = NULL;
1784
1785   if (!host)
1786     return NULL;
1787
1788   if (!config->routers)
1789     return NULL;
1790
1791   for (serv = config->routers; serv; serv = serv->next) {
1792     if (!silc_string_compare(serv->host, host))
1793       continue;
1794     if (port && serv->port && serv->port != port)
1795       continue;
1796     break;
1797   }
1798
1799   return serv;
1800 }
1801
1802 /* Returns TRUE if configuration for a router connection that we are
1803    initiating exists. */
1804
1805 bool silc_server_config_is_primary_route(SilcServer server)
1806 {
1807   SilcServerConfig config = server->config;
1808   SilcServerConfigRouter *serv = NULL;
1809   int i;
1810   bool found = FALSE;
1811
1812   serv = config->routers;
1813   for (i = 0; serv; i++) {
1814     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1815       found = TRUE;
1816       break;
1817     }
1818
1819     serv = serv->next;
1820   }
1821
1822   return found;
1823 }
1824
1825 /* Returns our primary connection configuration or NULL if we do not
1826    have primary router configured. */
1827
1828 SilcServerConfigRouter *
1829 silc_server_config_get_primary_router(SilcServer server)
1830 {
1831   SilcServerConfig config = server->config;
1832   SilcServerConfigRouter *serv = NULL;
1833   int i;
1834
1835   serv = config->routers;
1836   for (i = 0; serv; i++) {
1837     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1838       return serv;
1839     serv = serv->next;
1840   }
1841
1842   return NULL;
1843 }