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