Added checking for prv/pub keys in serverconfig.
[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   return config_new;
1273 }
1274
1275 /* Increments the reference counter of a config object */
1276
1277 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1278                             void *ref_ptr)
1279 {
1280   if (ref_ptr) {
1281     config->refcount++;
1282     ref->config = config;
1283     ref->ref_ptr = ref_ptr;
1284     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %hu->%hu", config,
1285                     config->refcount - 1, config->refcount));
1286   }
1287 }
1288
1289 /* Decrements the reference counter of a config object.  If the counter
1290    reaches 0, the config object is destroyed. */
1291
1292 void silc_server_config_unref(SilcServerConfigRef *ref)
1293 {
1294   SilcServerConfig config = ref->config;
1295
1296   if (ref->ref_ptr) {
1297     config->refcount--;
1298     SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %hu->%hu", config,
1299                     config->refcount + 1, config->refcount));
1300     if (!config->refcount)
1301       silc_server_config_destroy(config);
1302     ref->ref_ptr = NULL;
1303   }
1304 }
1305
1306 /* Destroy a config object with all his children lists */
1307
1308 void silc_server_config_destroy(SilcServerConfig config)
1309 {
1310   void *tmp;
1311
1312   SILC_LOG_DEBUG(("Freeing config context"));
1313
1314   silc_free(config->module_path);
1315
1316   /* Destroy Logging channels */
1317   if (config->logging_info)
1318     silc_free(config->logging_info->file);
1319   if (config->logging_warnings)
1320     silc_free(config->logging_warnings->file);
1321   if (config->logging_errors)
1322     silc_free(config->logging_errors->file);
1323   if (config->logging_fatals)
1324     silc_free(config->logging_fatals->file);
1325
1326   /* Destroy the ServerInfo struct */
1327   if (config->server_info) {
1328     register SilcServerConfigServerInfo *si = config->server_info;
1329     silc_free(si->server_name);
1330     silc_free(si->server_ip);
1331     silc_free(si->server_type);
1332     silc_free(si->location);
1333     silc_free(si->admin);
1334     silc_free(si->email);
1335     silc_free(si->user);
1336     silc_free(si->group);
1337     silc_free(si->motd_file);
1338     silc_free(si->pid_file);
1339     silc_pkcs_public_key_free(si->public_key);
1340     silc_pkcs_private_key_free(si->private_key);
1341   }
1342
1343   /* Now let's destroy the lists */
1344
1345   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1346                                   config->cipher)
1347     silc_free(di->name);
1348     silc_free(di->module);
1349     silc_free(di);
1350   }
1351   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1352     silc_free(di->name);
1353     silc_free(di->module);
1354     silc_free(di);
1355   }
1356   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1357     silc_free(di->name);
1358     silc_free(di->hash);
1359     silc_free(di);
1360   }
1361   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1362     silc_free(di->name);
1363     silc_free(di);
1364   }
1365   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient,
1366                                   config->clients)
1367     silc_free(di->host);
1368     CONFIG_FREE_AUTH(di);
1369     silc_free(di);
1370   }
1371   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1372     silc_free(di->host);
1373     silc_free(di->user);
1374     silc_free(di->nick);
1375     CONFIG_FREE_AUTH(di);
1376     silc_free(di);
1377   }
1378   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1379     silc_free(di->host);
1380     silc_free(di->reason);
1381     silc_free(di);
1382   }
1383   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1384                                   config->servers)
1385     silc_free(di->host);
1386     silc_free(di->version);
1387     CONFIG_FREE_AUTH(di);
1388     silc_free(di);
1389   }
1390   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1391                                   config->routers)
1392     silc_free(di->host);
1393     silc_free(di->version);
1394     silc_free(di->backup_replace_ip);
1395     CONFIG_FREE_AUTH(di);
1396     silc_free(di);
1397   }
1398
1399   memset(config, 'F', sizeof(*config));
1400   silc_free(config);
1401 }
1402
1403 /* Registers configured ciphers. These can then be allocated by the
1404    server when needed. */
1405
1406 bool silc_server_config_register_ciphers(SilcServer server)
1407 {
1408   SilcServerConfig config = server->config;
1409   SilcServerConfigCipher *cipher = config->cipher;
1410   char *module_path = config->module_path;
1411
1412   SILC_LOG_DEBUG(("Registering configured ciphers"));
1413
1414   if (!cipher) /* any cipher in the config file? */
1415     return FALSE;
1416
1417   while (cipher) {
1418     /* if there isn't a module_path OR there isn't a module sim name try to
1419      * use buil-in functions */
1420     if (!module_path || !cipher->module) {
1421       int i;
1422       for (i = 0; silc_default_ciphers[i].name; i++)
1423         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1424           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1425           break;
1426         }
1427       if (!silc_cipher_is_supported(cipher->name)) {
1428         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1429         silc_server_stop(server);
1430         exit(1);
1431       }
1432     } else {
1433 #ifdef SILC_SIM
1434       /* Load (try at least) the crypto SIM module */
1435       char buf[1023], *alg_name;
1436       SilcCipherObject cipher_obj;
1437       SilcSim sim;
1438
1439       memset(&cipher_obj, 0, sizeof(cipher_obj));
1440       cipher_obj.name = cipher->name;
1441       cipher_obj.block_len = cipher->block_length;
1442       cipher_obj.key_len = cipher->key_length * 8;
1443
1444       /* build the libname */
1445       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1446                 cipher->module);
1447       sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
1448
1449       alg_name = strdup(cipher->name);
1450       if (strchr(alg_name, '-'))
1451         *strchr(alg_name, '-') = '\0';
1452
1453       if (silc_sim_load(sim)) {
1454         cipher_obj.set_key =
1455           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1456                                                 SILC_CIPHER_SIM_SET_KEY));
1457         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1458         cipher_obj.set_key_with_string =
1459           silc_sim_getsym(sim, 
1460             silc_sim_symname(alg_name,
1461               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1462         SILC_LOG_DEBUG(("set_key_with_string=%p",
1463           cipher_obj.set_key_with_string));
1464         cipher_obj.encrypt =
1465           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1466                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1467         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1468         cipher_obj.decrypt =
1469           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1470                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1471         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1472         cipher_obj.context_len =
1473           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1474                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1475         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1476
1477         /* Put the SIM to the list of all SIM's in server */
1478         silc_dlist_add(server->sim, sim);
1479
1480         silc_free(alg_name);
1481       } else {
1482         SILC_LOG_ERROR(("Error configuring ciphers"));
1483         silc_server_stop(server);
1484         exit(1);
1485       }
1486
1487       /* Register the cipher */
1488       silc_cipher_register(&cipher_obj);
1489 #else
1490       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1491                         "can't load modules!"));
1492       silc_server_stop(server);
1493       exit(1);
1494 #endif
1495     }
1496     cipher = cipher->next;
1497   } /* while */
1498
1499   return TRUE;
1500 }
1501
1502 /* Registers configured hash functions. These can then be allocated by the
1503    server when needed. */
1504
1505 bool silc_server_config_register_hashfuncs(SilcServer server)
1506 {
1507   SilcServerConfig config = server->config;
1508   SilcServerConfigHash *hash = config->hash;
1509   char *module_path = config->module_path;
1510
1511   SILC_LOG_DEBUG(("Registering configured hash functions"));
1512
1513   if (!hash) /* any hash func in the config file? */
1514     return FALSE;
1515
1516   while (hash) {
1517     /* if there isn't a module_path OR there isn't a module sim name try to
1518      * use buil-in functions */
1519     if (!module_path || !hash->module) {
1520       int i;
1521       for (i = 0; silc_default_hash[i].name; i++)
1522         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1523           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1524           break;
1525         }
1526       if (!silc_hash_is_supported(hash->name)) {
1527         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1528         silc_server_stop(server);
1529         exit(1);
1530       }
1531     } else {
1532 #ifdef SILC_SIM
1533       /* Load (try at least) the hash SIM module */
1534       SilcHashObject hash_obj;
1535       SilcSim sim;
1536
1537       memset(&hash_obj, 0, sizeof(hash_obj));
1538       hash_obj.name = hash->name;
1539       hash_obj.block_len = hash->block_length;
1540       hash_obj.hash_len = hash->digest_length;
1541
1542       sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
1543
1544       if ((silc_sim_load(sim))) {
1545         hash_obj.init =
1546           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1547                                                 SILC_HASH_SIM_INIT));
1548         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1549         hash_obj.update =
1550           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1551                                                 SILC_HASH_SIM_UPDATE));
1552         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1553         hash_obj.final =
1554           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1555                                                 SILC_HASH_SIM_FINAL));
1556         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1557         hash_obj.context_len =
1558           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1559                                                 SILC_HASH_SIM_CONTEXT_LEN));
1560         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1561
1562         /* Put the SIM to the table of all SIM's in server */
1563         silc_dlist_add(server->sim, sim);
1564       } else {
1565         SILC_LOG_ERROR(("Error configuring hash functions"));
1566         silc_server_stop(server);
1567         exit(1);
1568       }
1569
1570       /* Register the hash function */
1571       silc_hash_register(&hash_obj);
1572 #else
1573       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1574                         "can't load modules!"));
1575       silc_server_stop(server);
1576       exit(1);
1577 #endif
1578     }
1579     hash = hash->next;
1580   } /* while */
1581
1582   return TRUE;
1583 }
1584
1585 /* Registers configure HMACs. These can then be allocated by the server
1586    when needed. */
1587
1588 bool silc_server_config_register_hmacs(SilcServer server)
1589 {
1590   SilcServerConfig config = server->config;
1591   SilcServerConfigHmac *hmac = config->hmac;
1592
1593   SILC_LOG_DEBUG(("Registering configured HMACs"));
1594
1595   if (!hmac)
1596     return FALSE;
1597
1598   while (hmac) {
1599     SilcHmacObject hmac_obj;
1600     if (!silc_hash_is_supported(hmac->hash)) {
1601       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1602       silc_server_stop(server);
1603       exit(1);
1604     }
1605
1606     /* Register the HMAC */
1607     memset(&hmac_obj, 0, sizeof(hmac_obj));
1608     hmac_obj.name = hmac->name;
1609     hmac_obj.len = hmac->mac_length;
1610     silc_hmac_register(&hmac_obj);
1611
1612     hmac = hmac->next;
1613   } /* while */
1614
1615   return TRUE;
1616 }
1617
1618 /* Registers configured PKCS's. */
1619
1620 bool silc_server_config_register_pkcs(SilcServer server)
1621 {
1622   SilcServerConfig config = server->config;
1623   SilcServerConfigPkcs *pkcs = config->pkcs;
1624
1625   SILC_LOG_DEBUG(("Registering configured PKCS"));
1626
1627   if (!pkcs)
1628     return FALSE;
1629
1630   while (pkcs) {
1631     int i;
1632     for (i = 0; silc_default_pkcs[i].name; i++)
1633       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1634         silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
1635         break;
1636       }
1637     if (!silc_pkcs_is_supported(pkcs->name)) {
1638       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1639       silc_server_stop(server);
1640       exit(1);
1641     }
1642     pkcs = pkcs->next;
1643   } /* while */
1644
1645   return TRUE;
1646 }
1647
1648 /* Sets log files where log messages are saved by the server logger. */
1649
1650 void silc_server_config_setlogfiles(SilcServer server)
1651 {
1652   SilcServerConfig config = server->config;
1653   SilcServerConfigLogging *this;
1654
1655   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1656
1657   silc_log_quick = config->logging_quick;
1658   silc_log_flushdelay = (config->logging_flushdelay ? 
1659                          config->logging_flushdelay :
1660                          SILC_SERVER_LOG_FLUSH_DELAY);
1661
1662   if ((this = config->logging_fatals))
1663     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1664                       server->schedule);
1665   if ((this = config->logging_errors))
1666     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1667                       server->schedule);
1668   if ((this = config->logging_warnings))
1669     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1670                       server->schedule);
1671   if ((this = config->logging_info))
1672     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1673                       server->schedule);
1674 }
1675
1676 /* Returns client authentication information from configuration file by host
1677    (name or ip) */
1678
1679 SilcServerConfigClient *
1680 silc_server_config_find_client(SilcServer server, char *host)
1681 {
1682   SilcServerConfig config = server->config;
1683   SilcServerConfigClient *client;
1684
1685   if (!config || !host)
1686     return NULL;
1687
1688   for (client = config->clients; client; client = client->next) {
1689     if (client->host && !silc_string_compare(client->host, host))
1690       continue;
1691     break;
1692   }
1693
1694   /* if none matched, then client is already NULL */
1695   return client;
1696 }
1697
1698 /* Returns admin connection configuration by host, username and/or
1699    nickname. */
1700
1701 SilcServerConfigAdmin *
1702 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1703                               char *nick)
1704 {
1705   SilcServerConfig config = server->config;
1706   SilcServerConfigAdmin *admin;
1707
1708   /* make sure we have a value for the matching parameters */
1709   if (!host)
1710     host = "*";
1711   if (!user)
1712     user = "*";
1713   if (!nick)
1714     nick = "*";
1715
1716   for (admin = config->admins; admin; admin = admin->next) {
1717     if (admin->host && !silc_string_compare(admin->host, host))
1718       continue;
1719     if (admin->user && !silc_string_compare(admin->user, user))
1720       continue;
1721     if (admin->nick && !silc_string_compare(admin->nick, nick))
1722       continue;
1723     /* no checks failed -> this entry matches */
1724     break;
1725   }
1726
1727   /* if none matched, then admin is already NULL */
1728   return admin;
1729 }
1730
1731 /* Returns the denied connection configuration entry by host. */
1732
1733 SilcServerConfigDeny *
1734 silc_server_config_find_denied(SilcServer server, char *host)
1735 {
1736   SilcServerConfig config = server->config;
1737   SilcServerConfigDeny *deny;
1738
1739   /* make sure we have a value for the matching parameters */
1740   if (!config || !host)
1741     return NULL;
1742
1743   for (deny = config->denied; deny; deny = deny->next) {
1744     if (deny->host && !silc_string_compare(deny->host, host))
1745       continue;
1746     break;
1747   }
1748
1749   /* if none matched, then deny is already NULL */
1750   return deny;
1751 }
1752
1753 /* Returns server connection info from server configuartion by host
1754    (name or ip). */
1755
1756 SilcServerConfigServer *
1757 silc_server_config_find_server_conn(SilcServer server, char *host)
1758 {
1759   SilcServerConfig config = server->config;
1760   SilcServerConfigServer *serv = NULL;
1761
1762   if (!host)
1763     return NULL;
1764
1765   if (!config->servers)
1766     return NULL;
1767
1768   for (serv = config->servers; serv; serv = serv->next) {
1769     if (!silc_string_compare(serv->host, host))
1770       continue;
1771     break;
1772   }
1773
1774   return serv;
1775 }
1776
1777 /* Returns router connection info from server configuration by
1778    host (name or ip). */
1779
1780 SilcServerConfigRouter *
1781 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1782 {
1783   SilcServerConfig config = server->config;
1784   SilcServerConfigRouter *serv = NULL;
1785
1786   if (!host)
1787     return NULL;
1788
1789   if (!config->routers)
1790     return NULL;
1791
1792   for (serv = config->routers; serv; serv = serv->next) {
1793     if (!silc_string_compare(serv->host, host))
1794       continue;
1795     if (port && serv->port && serv->port != port)
1796       continue;
1797     break;
1798   }
1799
1800   return serv;
1801 }
1802
1803 /* Returns TRUE if configuration for a router connection that we are
1804    initiating exists. */
1805
1806 bool silc_server_config_is_primary_route(SilcServer server)
1807 {
1808   SilcServerConfig config = server->config;
1809   SilcServerConfigRouter *serv = NULL;
1810   int i;
1811   bool found = FALSE;
1812
1813   serv = config->routers;
1814   for (i = 0; serv; i++) {
1815     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1816       found = TRUE;
1817       break;
1818     }
1819
1820     serv = serv->next;
1821   }
1822
1823   return found;
1824 }
1825
1826 /* Returns our primary connection configuration or NULL if we do not
1827    have primary router configured. */
1828
1829 SilcServerConfigRouter *
1830 silc_server_config_get_primary_router(SilcServer server)
1831 {
1832   SilcServerConfig config = server->config;
1833   SilcServerConfigRouter *serv = NULL;
1834   int i;
1835
1836   serv = config->routers;
1837   for (i = 0; serv; i++) {
1838     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1839       return serv;
1840     serv = serv->next;
1841   }
1842
1843   return NULL;
1844 }