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