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 Pekka Riikonen
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 && auth_data_len) {
117       if (!silc_utf8_valid(p, strlen(p))) {
118         *auth_data_len = silc_utf8_encoded_len(p, strlen(p), 0);
119         *auth_data = silc_calloc(*auth_data_len, sizeof(unsigned char));
120         silc_utf8_encode(p, strlen(p), SILC_STRING_ASCII, *auth_data,
121                          *auth_data_len);
122       } else {
123         *auth_data = (void *) strdup(p);
124         *auth_data_len = (SilcUInt32) strlen(p);
125       }
126     }
127   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
128     /* p is a public key file name */
129     SilcPublicKey public_key;
130
131     if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
132       if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
133         SILC_SERVER_LOG_ERROR(("\nError while parsing config file at line "
134                                "%lu: Could not load public key file!\n", 
135                                line));
136         return FALSE;
137       }
138
139     /* The auth_data is a pointer to the hash table of public keys. */
140     if (auth_data) {
141       if (*auth_data == NULL)
142         *auth_data = silc_hash_table_alloc(1, silc_hash_public_key, NULL,
143                                            NULL, NULL,
144                                            my_free_public_key, NULL,
145                                            TRUE);
146       silc_hash_table_add(*auth_data, public_key, public_key);
147     }
148   } else {
149     SILC_SERVER_LOG_ERROR(("\nError while parsing config file at line %lu: "
150                            "Unknown authentication method.\n", line));
151     return FALSE;
152   }
153   return TRUE;
154 }
155
156 /* Callbacks */
157
158 SILC_CONFIG_CALLBACK(fetch_generic)
159 {
160   SilcServerConfig config = (SilcServerConfig) context;
161   int got_errno = 0;
162
163   if (!strcmp(name, "module_path")) {
164     CONFIG_IS_DOUBLE(config->module_path);
165     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
166   }
167   else if (!strcmp(name, "prefer_passphrase_auth")) {
168     config->prefer_passphrase_auth = *(bool *)val;
169   }
170   else if (!strcmp(name, "require_reverse_lookup")) {
171     config->require_reverse_lookup = *(bool *)val;
172   }
173   else if (!strcmp(name, "connections_max")) {
174     config->param.connections_max = (SilcUInt32) *(int *)val;
175   }
176   else if (!strcmp(name, "connections_max_per_host")) {
177     config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
178   }
179   else if (!strcmp(name, "keepalive_secs")) {
180     config->param.keepalive_secs = (SilcUInt32) *(int *)val;
181   }
182   else if (!strcmp(name, "reconnect_count")) {
183     config->param.reconnect_count = (SilcUInt32) *(int *)val;
184   }
185   else if (!strcmp(name, "reconnect_interval")) {
186     config->param.reconnect_interval = (SilcUInt32) *(int *)val;
187   }
188   else if (!strcmp(name, "reconnect_interval_max")) {
189     config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
190   }
191   else if (!strcmp(name, "reconnect_keep_trying")) {
192     config->param.reconnect_keep_trying = *(bool *)val;
193   }
194   else if (!strcmp(name, "key_exchange_rekey")) {
195     config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
196   }
197   else if (!strcmp(name, "key_exchange_pfs")) {
198     config->param.key_exchange_pfs = *(bool *)val;
199   }
200   else if (!strcmp(name, "channel_rekey_secs")) {
201     config->channel_rekey_secs = (SilcUInt32) *(int *)val;
202   }
203   else if (!strcmp(name, "key_exchange_timeout")) {
204     config->key_exchange_timeout = (SilcUInt32) *(int *)val;
205   }
206   else if (!strcmp(name, "conn_auth_timeout")) {
207     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
208   }
209   else if (!strcmp(name, "version_protocol")) {
210     CONFIG_IS_DOUBLE(config->param.version_protocol);
211     config->param.version_protocol = 
212       (*(char *)val ? strdup((char *) val) : NULL);
213   }
214   else if (!strcmp(name, "version_software")) {
215     CONFIG_IS_DOUBLE(config->param.version_software);
216     config->param.version_software = 
217       (*(char *)val ? strdup((char *) val) : NULL);
218   }
219   else if (!strcmp(name, "version_software_vendor")) {
220     CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
221     config->param.version_software_vendor = 
222       (*(char *)val ? strdup((char *) val) : NULL);
223   }
224   else
225     return SILC_CONFIG_EINTERNAL;
226
227   return SILC_CONFIG_OK;
228
229  got_err:
230   return got_errno;
231 }
232
233 SILC_CONFIG_CALLBACK(fetch_cipher)
234 {
235   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher);
236
237   SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)",
238                        type, name, context));
239   if (type == SILC_CONFIG_ARG_BLOCK) {
240     /* check the temporary struct's fields */
241     if (!tmp) /* empty sub-block? */
242       return SILC_CONFIG_OK;
243     if (!tmp->name) {
244       got_errno = SILC_CONFIG_EMISSFIELDS;
245       goto got_err;
246     }
247     /* the temporary struct is ok, append it to the list */
248     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
249     config->tmp = NULL;
250     return SILC_CONFIG_OK;
251   }
252   /* if there isn't a temporary struct alloc one */
253   if (!tmp) {
254     config->tmp = silc_calloc(1, sizeof(*findtmp));
255     tmp = (SilcServerConfigCipher *) config->tmp;
256   }
257
258   /* Identify and save this value */
259   if (!strcmp(name, "name")) {
260     CONFIG_IS_DOUBLE(tmp->name);
261     tmp->name = strdup((char *) val);
262   }
263   else if (!strcmp(name, "module")) {
264     CONFIG_IS_DOUBLE(tmp->module);
265     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
266   }
267   else if (!strcmp(name, "keylength")) {
268     tmp->key_length = *(SilcUInt32 *)val;
269   }
270   else if (!strcmp(name, "blocklength")) {
271     tmp->block_length = *(SilcUInt32 *)val;
272   }
273   else
274     return SILC_CONFIG_EINTERNAL;
275   return SILC_CONFIG_OK;
276
277  got_err:
278   silc_free(tmp->name);
279   silc_free(tmp->module);
280   silc_free(tmp);
281   config->tmp = NULL;
282   return got_errno;
283 }
284
285 SILC_CONFIG_CALLBACK(fetch_hash)
286 {
287   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash);
288
289   SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)",
290                        type, name, context));
291   if (type == SILC_CONFIG_ARG_BLOCK) {
292     /* check the temporary struct's fields */
293     if (!tmp) /* empty sub-block? */
294       return SILC_CONFIG_OK;
295     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
296       got_errno = SILC_CONFIG_EMISSFIELDS;
297       goto got_err;
298     }
299     /* the temporary struct in tmp is ok */
300     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
301     config->tmp = NULL;
302     return SILC_CONFIG_OK;
303   }
304
305   /* if there isn't a temporary struct alloc one */
306   if (!tmp) {
307     config->tmp = silc_calloc(1, sizeof(*findtmp));
308     tmp = (SilcServerConfigHash *) config->tmp;
309   }
310
311   /* Identify and save this value */
312   if (!strcmp(name, "name")) {
313     CONFIG_IS_DOUBLE(tmp->name);
314     tmp->name = strdup((char *) val);
315   }
316   else if (!strcmp(name, "module")) {
317     CONFIG_IS_DOUBLE(tmp->module);
318     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
319   }
320   else if (!strcmp(name, "blocklength")) {
321     tmp->block_length = *(int *)val;
322   }
323   else if (!strcmp(name, "digestlength")) {
324     tmp->digest_length = *(int *)val;
325   }
326   else
327     return SILC_CONFIG_EINTERNAL;
328   return SILC_CONFIG_OK;
329
330  got_err:
331   silc_free(tmp->name);
332   silc_free(tmp->module);
333   silc_free(tmp);
334   config->tmp = NULL;
335   return got_errno;
336 }
337
338 SILC_CONFIG_CALLBACK(fetch_hmac)
339 {
340   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac);
341
342   SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)",
343                        type, name, context));
344   if (type == SILC_CONFIG_ARG_BLOCK) {
345     /* check the temporary struct's fields */
346     if (!tmp) /* empty sub-block? */
347       return SILC_CONFIG_OK;
348     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
349       got_errno = SILC_CONFIG_EMISSFIELDS;
350       goto got_err;
351     }
352     /* the temporary struct is ok, append it to the list */
353     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
354     config->tmp = NULL;
355     return SILC_CONFIG_OK;
356   }
357   /* if there isn't a temporary struct alloc one */
358   if (!tmp) {
359     config->tmp = silc_calloc(1, sizeof(*findtmp));
360     tmp = (SilcServerConfigHmac *) config->tmp;
361   }
362
363   /* Identify and save this value */
364   if (!strcmp(name, "name")) {
365     CONFIG_IS_DOUBLE(tmp->name);
366     tmp->name = strdup((char *) val);
367   }
368   else if (!strcmp(name, "hash")) {
369     CONFIG_IS_DOUBLE(tmp->hash);
370     tmp->hash = strdup((char *) val);
371   }
372   else if (!strcmp(name, "maclength")) {
373     tmp->mac_length = *(int *)val;
374   }
375   else
376     return SILC_CONFIG_EINTERNAL;
377   return SILC_CONFIG_OK;
378
379  got_err:
380   silc_free(tmp->name);
381   silc_free(tmp->hash);
382   silc_free(tmp);
383   config->tmp = NULL;
384   return got_errno;
385 }
386
387 SILC_CONFIG_CALLBACK(fetch_pkcs)
388 {
389   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs);
390
391   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
392                        type, name, context));
393   if (type == SILC_CONFIG_ARG_BLOCK) {
394     /* check the temporary struct's fields */
395     if (!tmp) /* empty sub-block? */
396       return SILC_CONFIG_OK;
397     if (!tmp->name) {
398       got_errno = SILC_CONFIG_EMISSFIELDS;
399       goto got_err;
400     }
401     /* the temporary struct is ok, append it to the list */
402     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
403     config->tmp = NULL;
404     return SILC_CONFIG_OK;
405   }
406   /* if there isn't a temporary struct alloc one */
407   if (!tmp) {
408     config->tmp = silc_calloc(1, sizeof(*findtmp));
409     tmp = (SilcServerConfigPkcs *) config->tmp;
410   }
411
412   /* Identify and save this value */
413   if (!strcmp(name, "name")) {
414     CONFIG_IS_DOUBLE(tmp->name);
415     tmp->name = strdup((char *) val);
416   }
417   else
418     return SILC_CONFIG_EINTERNAL;
419   return SILC_CONFIG_OK;
420
421  got_err:
422   silc_free(tmp->name);
423   silc_free(tmp);
424   config->tmp = NULL;
425   return got_errno;
426 }
427
428 SILC_CONFIG_CALLBACK(fetch_serverinfo)
429 {
430   SilcServerConfig config = (SilcServerConfig) context;
431   SilcServerConfigServerInfo *server_info = config->server_info;
432   int got_errno = 0;
433
434   /* if there isn't the struct alloc it */
435   if (!server_info)
436     config->server_info = server_info = (SilcServerConfigServerInfo *)
437                 silc_calloc(1, sizeof(*server_info));
438
439   if (type == SILC_CONFIG_ARG_BLOCK) {
440     /* check for mandatory inputs */
441     if (!server_info->public_key || !server_info->private_key) {
442       got_errno = SILC_CONFIG_EMISSFIELDS;
443       goto got_err;
444     }
445     return SILC_CONFIG_OK;
446   }
447   if (!strcmp(name, "hostname")) {
448     CONFIG_IS_DOUBLE(server_info->server_name);
449     server_info->server_name = strdup((char *) val);
450   }
451   else if (!strcmp(name, "ip")) {
452     CONFIG_IS_DOUBLE(server_info->server_ip);
453     server_info->server_ip = strdup((char *) val);
454   }
455   else if (!strcmp(name, "port")) {
456     int port = *(int *)val;
457     if ((port <= 0) || (port > 65535)) {
458       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
459       return SILC_CONFIG_ESILENT;
460     }
461     server_info->port = (SilcUInt16) port;
462   }
463   else if (!strcmp(name, "servertype")) {
464     CONFIG_IS_DOUBLE(server_info->server_type);
465     server_info->server_type = strdup((char *) val);
466   }
467   else if (!strcmp(name, "admin")) {
468     CONFIG_IS_DOUBLE(server_info->admin);
469     server_info->admin = strdup((char *) val);
470   }
471   else if (!strcmp(name, "adminemail")) {
472     CONFIG_IS_DOUBLE(server_info->email);
473     server_info->email = strdup((char *) val);
474   }
475   else if (!strcmp(name, "location")) {
476     CONFIG_IS_DOUBLE(server_info->location);
477     server_info->location = strdup((char *) val);
478   }
479   else if (!strcmp(name, "user")) {
480     CONFIG_IS_DOUBLE(server_info->user);
481     server_info->user = strdup((char *) val);
482   }
483   else if (!strcmp(name, "group")) {
484     CONFIG_IS_DOUBLE(server_info->group);
485     server_info->group = strdup((char *) val);
486   }
487   else if (!strcmp(name, "motdfile")) {
488     CONFIG_IS_DOUBLE(server_info->motd_file);
489     server_info->motd_file = strdup((char *) val);
490   }
491   else if (!strcmp(name, "pidfile")) {
492     CONFIG_IS_DOUBLE(server_info->pid_file);
493     server_info->pid_file = strdup((char *) val);
494   }
495   else if (!strcmp(name, "publickey")) {
496     char *file_tmp = (char *) val;
497
498     /* try to load specified file, if fail stop config parsing */
499     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
500                                    SILC_PKCS_FILE_PEM))
501       if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
502                                      SILC_PKCS_FILE_BIN)) {
503         SILC_SERVER_LOG_ERROR(("Error: Could not load public key file.\n"));
504         SILC_SERVER_LOG_ERROR(("   line %lu: file \"%s\"\n", line, file_tmp));
505         return SILC_CONFIG_ESILENT;
506       }
507   }
508   else if (!strcmp(name, "privatekey")) {
509     char *file_tmp = (char *) val;
510
511     /* try to load specified file, if fail stop config parsing */
512     if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
513                                     SILC_PKCS_FILE_BIN))
514       if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
515                                       SILC_PKCS_FILE_PEM)) {
516         SILC_SERVER_LOG_ERROR(("Error: Could not load private key file.\n"));
517         SILC_SERVER_LOG_ERROR(("   line %lu: file \"%s\"\n", line, file_tmp));
518         return SILC_CONFIG_ESILENT;
519       }
520   }
521   else
522     return SILC_CONFIG_EINTERNAL;
523   return SILC_CONFIG_OK;
524
525  got_err:
526   return got_errno;
527 }
528
529 SILC_CONFIG_CALLBACK(fetch_logging)
530 {
531   SilcServerConfig config = (SilcServerConfig) context;
532   SilcServerConfigLogging *tmp =
533         (SilcServerConfigLogging *) config->tmp;
534   int got_errno;
535
536   if (!strcmp(name, "quicklogs")) {
537     config->logging_quick = *(bool *)val;
538   }
539   else if (!strcmp(name, "flushdelay")) {
540     int flushdelay = *(int *)val;
541     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
542       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid flushdelay value, use "
543                         "quicklogs if you want real-time logging.\n", line));
544       return SILC_CONFIG_ESILENT;
545     }
546     config->logging_flushdelay = (long) flushdelay;
547   }
548 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
549   else if (!strcmp(name, __chan__)) {                           \
550     if (!tmp) return SILC_CONFIG_OK;                            \
551     if (!tmp->file) {                                           \
552       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
553     }                                                           \
554     config->__member__ = tmp;                                   \
555     config->tmp = NULL;                                         \
556   }
557   FETCH_LOGGING_CHAN("info", logging_info)
558   FETCH_LOGGING_CHAN("warnings", logging_warnings)
559   FETCH_LOGGING_CHAN("errors", logging_errors)
560   FETCH_LOGGING_CHAN("fatals", logging_fatals)
561 #undef FETCH_LOGGING_CHAN
562   else if (!strcmp(name, "file")) {
563     if (!tmp) { /* FIXME: what the fuck is this? */
564       config->tmp = silc_calloc(1, sizeof(*tmp));
565       tmp = (SilcServerConfigLogging *) config->tmp;
566     }
567     if (tmp->file) {
568       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
569     }
570     tmp->file = strdup((char *) val);
571   }
572   else if (!strcmp(name, "size")) {
573     if (!tmp) {
574       config->tmp = silc_calloc(1, sizeof(*tmp));
575       tmp = (SilcServerConfigLogging *) config->tmp;
576     }
577     tmp->maxsize = *(SilcUInt32 *) val;
578   }
579   else
580     return SILC_CONFIG_EINTERNAL;
581   return SILC_CONFIG_OK;
582
583  got_err:
584   silc_free(tmp->file);
585   silc_free(tmp);
586   config->tmp = NULL;
587   return got_errno;
588 }
589
590 SILC_CONFIG_CALLBACK(fetch_connparam)
591 {
592   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
593
594   SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)", 
595                        type, name, context));
596
597   if (type == SILC_CONFIG_ARG_BLOCK) {
598     if (!tmp)
599       return SILC_CONFIG_OK;
600
601     if (!tmp->name) {
602       got_errno = SILC_CONFIG_EMISSFIELDS;
603       goto got_err;
604     }
605
606     /* Set defaults */
607     my_set_param_defaults(tmp, &config->param);
608
609     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
610     config->tmp = NULL;
611     return SILC_CONFIG_OK;
612   }
613
614   /* if there isn't a temporary struct alloc one */
615   if (!tmp) {
616     config->tmp = silc_calloc(1, sizeof(*findtmp));
617     tmp = (SilcServerConfigConnParams *) config->tmp;
618   }
619
620   if (!strcmp(name, "name")) {
621     CONFIG_IS_DOUBLE(tmp->name);
622     tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
623   }
624   else if (!strcmp(name, "connections_max")) {
625     tmp->connections_max = *(SilcUInt32 *)val;
626   }
627   else if (!strcmp(name, "connections_max_per_host")) {
628     tmp->connections_max_per_host = *(SilcUInt32 *)val;
629   }
630   else if (!strcmp(name, "keepalive_secs")) {
631     tmp->keepalive_secs = *(SilcUInt32 *)val;
632   }
633   else if (!strcmp(name, "reconnect_count")) {
634     tmp->reconnect_count = *(SilcUInt32 *)val;
635   }
636   else if (!strcmp(name, "reconnect_interval")) {
637     tmp->reconnect_interval = *(SilcUInt32 *)val;
638   }
639   else if (!strcmp(name, "reconnect_interval_max")) {
640     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
641   }
642   else if (!strcmp(name, "reconnect_keep_trying")) {
643     tmp->reconnect_keep_trying = *(bool *)val;
644   }
645   else if (!strcmp(name, "key_exchange_rekey")) {
646     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
647   }
648   else if (!strcmp(name, "key_exchange_pfs")) {
649     tmp->key_exchange_pfs = *(bool *)val;
650   }
651   else if (!strcmp(name, "version_protocol")) {
652     CONFIG_IS_DOUBLE(tmp->version_protocol);
653     tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
654   }
655   else if (!strcmp(name, "version_software")) {
656     CONFIG_IS_DOUBLE(tmp->version_software);
657     tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
658   }
659   else if (!strcmp(name, "version_software_vendor")) {
660     CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
661     tmp->version_software_vendor = 
662       (*(char *)val ? strdup((char *) val) : NULL);
663   }
664   else
665     return SILC_CONFIG_EINTERNAL;
666
667   return SILC_CONFIG_OK;
668
669  got_err:
670   silc_free(tmp->name);
671   silc_free(tmp);
672   config->tmp = NULL;
673   return got_errno;
674 }
675
676 SILC_CONFIG_CALLBACK(fetch_client)
677 {
678   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
679
680   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
681                        type, name, context));
682
683   /* alloc tmp before block checking (empty sub-blocks are welcome here) */
684   if (!tmp) {
685     config->tmp = silc_calloc(1, sizeof(*findtmp));
686     tmp = (SilcServerConfigClient *) config->tmp;
687   }
688
689   if (type == SILC_CONFIG_ARG_BLOCK) {
690     /* closing the block */
691     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
692     config->tmp = NULL;
693     return SILC_CONFIG_OK;
694   }
695
696   /* Identify and save this value */
697   if (!strcmp(name, "host")) {
698     CONFIG_IS_DOUBLE(tmp->host);
699     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
700   }
701   else if (!strcmp(name, "passphrase")) {
702     CONFIG_IS_DOUBLE(tmp->passphrase);
703     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
704                            (void **)&tmp->passphrase,
705                            &tmp->passphrase_len)) {
706       got_errno = SILC_CONFIG_ESILENT;
707       goto got_err;
708     }
709   }
710   else if (!strcmp(name, "publickey")) {
711     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
712                            (void **)&tmp->publickeys, NULL)) {
713       got_errno = SILC_CONFIG_ESILENT;
714       goto got_err;
715     }
716   }
717   else if (!strcmp(name, "params")) {
718     CONFIG_IS_DOUBLE(tmp->param);
719     tmp->param = my_find_param(config, (char *) val, line);
720     if (!tmp->param) { /* error already output */
721       got_errno = SILC_CONFIG_ESILENT;
722       goto got_err;
723     }
724   }
725   else
726     return SILC_CONFIG_EINTERNAL;
727   return SILC_CONFIG_OK;
728
729  got_err:
730   silc_free(tmp->host);
731   CONFIG_FREE_AUTH(tmp);
732   silc_free(tmp);
733   config->tmp = NULL;
734   return got_errno;
735 }
736
737 SILC_CONFIG_CALLBACK(fetch_admin)
738 {
739   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
740
741   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
742                        type, name, context));
743
744   if (type == SILC_CONFIG_ARG_BLOCK) {
745     /* check the temporary struct's fields */
746     if (!tmp) /* empty sub-block? */
747       return SILC_CONFIG_OK;
748
749     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
750     config->tmp = NULL;
751     return SILC_CONFIG_OK;
752   }
753
754   /* if there isn't a temporary struct alloc one */
755   if (!tmp) {
756     config->tmp = silc_calloc(1, sizeof(*findtmp));
757     tmp = (SilcServerConfigAdmin *) config->tmp;
758   }
759
760   /* Identify and save this value */
761   if (!strcmp(name, "host")) {
762     CONFIG_IS_DOUBLE(tmp->host);
763     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
764   }
765   else if (!strcmp(name, "user")) {
766     CONFIG_IS_DOUBLE(tmp->user);
767     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
768   }
769   else if (!strcmp(name, "nick")) {
770     CONFIG_IS_DOUBLE(tmp->nick);
771     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
772   }
773   else if (!strcmp(name, "passphrase")) {
774     CONFIG_IS_DOUBLE(tmp->passphrase);
775     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
776                            (void **)&tmp->passphrase,
777                            &tmp->passphrase_len)) {
778       got_errno = SILC_CONFIG_ESILENT;
779       goto got_err;
780     }
781   }
782   else if (!strcmp(name, "publickey")) {
783     CONFIG_IS_DOUBLE(tmp->publickeys);
784     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
785                            (void **)&tmp->publickeys, NULL)) {
786       got_errno = SILC_CONFIG_ESILENT;
787       goto got_err;
788     }
789   }
790   else
791     return SILC_CONFIG_EINTERNAL;
792   return SILC_CONFIG_OK;
793
794  got_err:
795   silc_free(tmp->host);
796   silc_free(tmp->user);
797   silc_free(tmp->nick);
798   CONFIG_FREE_AUTH(tmp);
799   silc_free(tmp);
800   config->tmp = NULL;
801   return got_errno;
802 }
803
804 SILC_CONFIG_CALLBACK(fetch_deny)
805 {
806   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
807
808   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
809                        type, name, context));
810   if (type == SILC_CONFIG_ARG_BLOCK) {
811     /* check the temporary struct's fields */
812     if (!tmp) /* empty sub-block? */
813       return SILC_CONFIG_OK;
814     if (!tmp->reason) {
815       got_errno = SILC_CONFIG_EMISSFIELDS;
816       goto got_err;
817     }
818     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
819     config->tmp = NULL;
820     return SILC_CONFIG_OK;
821   }
822   /* if there isn't a temporary struct alloc one */
823   if (!tmp) {
824     config->tmp = silc_calloc(1, sizeof(*findtmp));
825     tmp = (SilcServerConfigDeny *) config->tmp;
826   }
827
828   /* Identify and save this value */
829   if (!strcmp(name, "host")) {
830     CONFIG_IS_DOUBLE(tmp->host);
831     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
832   }
833   else if (!strcmp(name, "reason")) {
834     CONFIG_IS_DOUBLE(tmp->reason);
835     tmp->reason = strdup((char *) val);
836   }
837   else
838     return SILC_CONFIG_EINTERNAL;
839   return SILC_CONFIG_OK;
840
841  got_err:
842   silc_free(tmp->host);
843   silc_free(tmp->reason);
844   silc_free(tmp);
845   config->tmp = NULL;
846   return got_errno;
847 }
848
849 SILC_CONFIG_CALLBACK(fetch_server)
850 {
851   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
852
853   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
854                        type, name, context));
855
856   if (type == SILC_CONFIG_ARG_BLOCK) {
857     /* check the temporary struct's fields */
858     if (!tmp) /* empty sub-block? */
859       return SILC_CONFIG_OK;
860
861     /* the temporary struct is ok, append it to the list */
862     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
863     config->tmp = NULL;
864     return SILC_CONFIG_OK;
865   }
866
867   /* if there isn't a temporary struct alloc one */
868   if (!tmp) {
869     config->tmp = silc_calloc(1, sizeof(*findtmp));
870     tmp = (SilcServerConfigServer *) config->tmp;
871   }
872
873   /* Identify and save this value */
874   if (!strcmp(name, "host")) {
875     CONFIG_IS_DOUBLE(tmp->host);
876     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
877   }
878   else if (!strcmp(name, "passphrase")) {
879     CONFIG_IS_DOUBLE(tmp->passphrase);
880     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
881                            (void **)&tmp->passphrase,
882                            &tmp->passphrase_len)) {
883       got_errno = SILC_CONFIG_ESILENT;
884       goto got_err;
885     }
886   }
887   else if (!strcmp(name, "publickey")) {
888     CONFIG_IS_DOUBLE(tmp->publickeys);
889     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
890                            (void **)&tmp->publickeys, NULL)) {
891       got_errno = SILC_CONFIG_ESILENT;
892       goto got_err;
893     }
894   }
895   else if (!strcmp(name, "params")) {
896     CONFIG_IS_DOUBLE(tmp->param);
897     tmp->param = my_find_param(config, (char *) val, line);
898     if (!tmp->param) { /* error already output */
899       got_errno = SILC_CONFIG_ESILENT;
900       goto got_err;
901     }
902   }
903   else if (!strcmp(name, "backup")) {
904     tmp->backup_router = *(bool *)val;
905   }
906   else
907     return SILC_CONFIG_EINTERNAL;
908
909   return SILC_CONFIG_OK;
910
911  got_err:
912   silc_free(tmp->host);
913   CONFIG_FREE_AUTH(tmp);
914   silc_free(tmp);
915   config->tmp = NULL;
916   return got_errno;
917 }
918
919 SILC_CONFIG_CALLBACK(fetch_router)
920 {
921   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
922
923   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
924                        type, name, context));
925
926   if (type == SILC_CONFIG_ARG_BLOCK) {
927     if (!tmp) /* empty sub-block? */
928       return SILC_CONFIG_OK;
929
930     /* the temporary struct is ok, append it to the list */
931     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
932     config->tmp = NULL;
933     return SILC_CONFIG_OK;
934   }
935
936   /* if there isn't a temporary struct alloc one */
937   if (!tmp) {
938     config->tmp = silc_calloc(1, sizeof(*findtmp));
939     tmp = (SilcServerConfigRouter *) config->tmp;
940   }
941
942   /* Identify and save this value */
943   if (!strcmp(name, "host")) {
944     CONFIG_IS_DOUBLE(tmp->host);
945     tmp->host = strdup((char *) val);
946   }
947   else if (!strcmp(name, "port")) {
948     int port = *(int *)val;
949     if ((port <= 0) || (port > 65535)) {
950       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
951       return SILC_CONFIG_ESILENT;
952     }
953     tmp->port = (SilcUInt16) port;
954   }
955   else if (!strcmp(name, "passphrase")) {
956     CONFIG_IS_DOUBLE(tmp->passphrase);
957     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
958                            (void **)&tmp->passphrase,
959                            &tmp->passphrase_len)) {
960       got_errno = SILC_CONFIG_ESILENT;
961       goto got_err;
962     }
963   }
964   else if (!strcmp(name, "publickey")) {
965     CONFIG_IS_DOUBLE(tmp->publickeys);
966     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
967                            (void **)&tmp->publickeys, NULL)) {
968       got_errno = SILC_CONFIG_ESILENT;
969       goto got_err;
970     }
971   }
972   else if (!strcmp(name, "params")) {
973     CONFIG_IS_DOUBLE(tmp->param);
974     tmp->param = my_find_param(config, (char *) val, line);
975     if (!tmp->param) { /* error already output */
976       got_errno = SILC_CONFIG_ESILENT;
977       goto got_err;
978     }
979   }
980   else if (!strcmp(name, "initiator")) {
981     tmp->initiator = *(bool *)val;
982   }
983   else if (!strcmp(name, "backuphost")) {
984     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
985     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
986                               strdup("*"));
987   }
988   else if (!strcmp(name, "backupport")) {
989     int port = *(int *)val;
990     if ((port <= 0) || (port > 65535)) {
991       SILC_SERVER_LOG_ERROR(("Error: line %lu: Invalid port number!\n", line));
992       return SILC_CONFIG_ESILENT;
993     }
994     tmp->backup_replace_port = (SilcUInt16) port;
995   }
996   else if (!strcmp(name, "backuplocal")) {
997     tmp->backup_local = *(bool *)val;
998   }
999   else
1000     return SILC_CONFIG_EINTERNAL;
1001
1002   return SILC_CONFIG_OK;
1003
1004  got_err:
1005   silc_free(tmp->host);
1006   silc_free(tmp->backup_replace_ip);
1007   CONFIG_FREE_AUTH(tmp);
1008   silc_free(tmp);
1009   config->tmp = NULL;
1010   return got_errno;
1011 }
1012
1013 /* known config options tables */
1014 static const SilcConfigTable table_general[] = {
1015   { "module_path",              SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1016   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1017   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1018   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1019   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1020   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1021   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1022   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1023   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1024   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1025   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1026   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1027   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1028   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1029   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1030   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1031   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1032   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1033   { 0, 0, 0, 0 }
1034 };
1035
1036 static const SilcConfigTable table_cipher[] = {
1037   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1038   { "module",           SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
1039   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1040   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1041   { 0, 0, 0, 0 }
1042 };
1043
1044 static const SilcConfigTable table_hash[] = {
1045   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1046   { "module",           SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
1047   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1048   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1049   { 0, 0, 0, 0 }
1050 };
1051
1052 static const SilcConfigTable table_hmac[] = {
1053   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1054   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1055   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1056   { 0, 0, 0, 0 }
1057 };
1058
1059 static const SilcConfigTable table_pkcs[] = {
1060   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1061   { 0, 0, 0, 0 }
1062 };
1063
1064 static const SilcConfigTable table_serverinfo[] = {
1065   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1066   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1067   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1068   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1069   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1070   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1071   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1072   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1073   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1074   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1075   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1076   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1077   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1078   { 0, 0, 0, 0 }
1079 };
1080
1081 static const SilcConfigTable table_logging_c[] = {
1082   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1083   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1084 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1085   { 0, 0, 0, 0 }
1086 };
1087
1088 static const SilcConfigTable table_logging[] = {
1089   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1090   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1091   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1092   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1093   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1094   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1095   { 0, 0, 0, 0 }
1096 };
1097
1098 static const SilcConfigTable table_connparam[] = {
1099   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1100   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1101   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1102   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1103   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1104   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1105   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1106   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1107   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1108   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1109   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1110   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1111   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1112   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1113   { 0, 0, 0, 0 }
1114 };
1115
1116 static const SilcConfigTable table_client[] = {
1117   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1118   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1119   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1120   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1121   { 0, 0, 0, 0 }
1122 };
1123
1124 static const SilcConfigTable table_admin[] = {
1125   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1126   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1127   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1128   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1129   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1130   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1131   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1132   { 0, 0, 0, 0 }
1133 };
1134
1135 static const SilcConfigTable table_deny[] = {
1136   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1137   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1138   { 0, 0, 0, 0 }
1139 };
1140
1141 static const SilcConfigTable table_serverconn[] = {
1142   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1143   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1144   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1145   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1146   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1147   { 0, 0, 0, 0 }
1148 };
1149
1150 static const SilcConfigTable table_routerconn[] = {
1151   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1152   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1153   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1154   { "publickey",        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   config_new->refcount = 1;
1213   if (!config_new)
1214     return NULL;
1215
1216   /* obtain a config file object */
1217   file = silc_config_open(filename);
1218   if (!file) {
1219     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n",
1220                            filename));
1221     return NULL;
1222   }
1223
1224   /* obtain a SilcConfig entity, we can use it to start the parsing */
1225   ent = silc_config_init(file);
1226
1227   /* load the known configuration options, give our empty object as context */
1228   silc_config_register_table(ent, table_main, (void *) config_new);
1229
1230   /* enter the main parsing loop.  When this returns, we have the parsing
1231    * result and the object filled (or partially, in case of errors). */
1232   ret = silc_config_main(ent);
1233   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1234                   silc_config_strerror(ret)));
1235
1236   /* Check if the parser returned errors */
1237   if (ret) {
1238     /* handle this special error return which asks to quietly return */
1239     if (ret != SILC_CONFIG_ESILENT) {
1240       char *linebuf, *filename = silc_config_get_filename(file);
1241       SilcUInt32 line = silc_config_get_line(file);
1242       SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.\n",
1243                              silc_config_strerror(ret)));
1244       linebuf = silc_config_read_line(file, line);
1245       SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1246                              line, linebuf));
1247       silc_free(linebuf);
1248     }
1249     silc_server_config_destroy(config_new);
1250     return NULL;
1251   }
1252
1253   /* close (destroy) the file object */
1254   silc_config_close(file);
1255
1256   /* If config_new is incomplete, abort the object and return NULL */
1257   if (!config_new->server_info) {
1258     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block "
1259                            "`server_info'\n"));
1260     silc_server_config_destroy(config_new);
1261     return NULL;
1262   }
1263
1264   /* XXX are there any other mandatory sections in the config file? */
1265
1266   /* Set default to configuration parameters */
1267   silc_server_config_set_defaults(config_new);
1268
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 %d->%d", 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 %d->%d", config,
1303                   config->refcount + 1, config->refcount));
1304   if (config->refcount > 0)
1305     return;
1306
1307   SILC_LOG_DEBUG(("Freeing config context"));
1308
1309   /* Destroy general config stuff */
1310   silc_free(config->module_path);
1311   silc_free(config->param.version_protocol);
1312   silc_free(config->param.version_software);
1313   silc_free(config->param.version_software_vendor);
1314
1315   /* Destroy Logging channels */
1316   if (config->logging_info)
1317     silc_free(config->logging_info->file);
1318   if (config->logging_warnings)
1319     silc_free(config->logging_warnings->file);
1320   if (config->logging_errors)
1321     silc_free(config->logging_errors->file);
1322   if (config->logging_fatals)
1323     silc_free(config->logging_fatals->file);
1324
1325   /* Destroy the ServerInfo struct */
1326   if (config->server_info) {
1327     register SilcServerConfigServerInfo *si = config->server_info;
1328     silc_free(si->server_name);
1329     silc_free(si->server_ip);
1330     silc_free(si->server_type);
1331     silc_free(si->location);
1332     silc_free(si->admin);
1333     silc_free(si->email);
1334     silc_free(si->user);
1335     silc_free(si->group);
1336     silc_free(si->motd_file);
1337     silc_free(si->pid_file);
1338     silc_pkcs_public_key_free(si->public_key);
1339     silc_pkcs_private_key_free(si->private_key);
1340   }
1341
1342   /* Now let's destroy the lists */
1343
1344   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1345                                   config->cipher)
1346     silc_free(di->name);
1347     silc_free(di->module);
1348     silc_free(di);
1349   }
1350   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1351     silc_free(di->name);
1352     silc_free(di->module);
1353     silc_free(di);
1354   }
1355   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1356     silc_free(di->name);
1357     silc_free(di->hash);
1358     silc_free(di);
1359   }
1360   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1361     silc_free(di->name);
1362     silc_free(di);
1363   }
1364   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1365                                   config->conn_params)
1366     silc_free(di->name);
1367     silc_free(di->version_protocol);
1368     silc_free(di->version_software);
1369     silc_free(di->version_software_vendor);
1370     silc_free(di);
1371   }
1372   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1373     silc_free(di->host);
1374     CONFIG_FREE_AUTH(di);
1375     silc_free(di);
1376   }
1377   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1378     silc_free(di->host);
1379     silc_free(di->user);
1380     silc_free(di->nick);
1381     CONFIG_FREE_AUTH(di);
1382     silc_free(di);
1383   }
1384   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1385     silc_free(di->host);
1386     silc_free(di->reason);
1387     silc_free(di);
1388   }
1389   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1390                                   config->servers)
1391     silc_free(di->host);
1392     CONFIG_FREE_AUTH(di);
1393     silc_free(di);
1394   }
1395   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1396                                   config->routers)
1397     silc_free(di->host);
1398     silc_free(di->backup_replace_ip);
1399     CONFIG_FREE_AUTH(di);
1400     silc_free(di);
1401   }
1402
1403   memset(config, 'F', sizeof(*config));
1404   silc_free(config);
1405 }
1406
1407 /* Registers configured ciphers. These can then be allocated by the
1408    server when needed. */
1409
1410 bool silc_server_config_register_ciphers(SilcServer server)
1411 {
1412   SilcServerConfig config = server->config;
1413   SilcServerConfigCipher *cipher = config->cipher;
1414   char *module_path = config->module_path;
1415
1416   SILC_LOG_DEBUG(("Registering configured ciphers"));
1417
1418   if (!cipher) /* any cipher in the config file? */
1419     return FALSE;
1420
1421   while (cipher) {
1422     /* if there isn't a module_path OR there isn't a module sim name try to
1423      * use buil-in functions */
1424     if (!module_path || !cipher->module) {
1425       int i;
1426       for (i = 0; silc_default_ciphers[i].name; i++)
1427         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1428           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1429           break;
1430         }
1431       if (!silc_cipher_is_supported(cipher->name)) {
1432         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1433         silc_server_stop(server);
1434         exit(1);
1435       }
1436     } else {
1437 #ifdef SILC_SIM
1438       /* Load (try at least) the crypto SIM module */
1439       char buf[1023], *alg_name;
1440       SilcCipherObject cipher_obj;
1441       SilcSim sim;
1442
1443       memset(&cipher_obj, 0, sizeof(cipher_obj));
1444       cipher_obj.name = cipher->name;
1445       cipher_obj.block_len = cipher->block_length;
1446       cipher_obj.key_len = cipher->key_length * 8;
1447
1448       /* build the libname */
1449       snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
1450                 cipher->module);
1451       sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
1452
1453       alg_name = strdup(cipher->name);
1454       if (strchr(alg_name, '-'))
1455         *strchr(alg_name, '-') = '\0';
1456
1457       if (silc_sim_load(sim)) {
1458         cipher_obj.set_key =
1459           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1460                                                 SILC_CIPHER_SIM_SET_KEY));
1461         SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
1462         cipher_obj.set_key_with_string =
1463           silc_sim_getsym(sim, 
1464             silc_sim_symname(alg_name,
1465               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1466         SILC_LOG_DEBUG(("set_key_with_string=%p",
1467           cipher_obj.set_key_with_string));
1468         cipher_obj.encrypt =
1469           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1470                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1471         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
1472         cipher_obj.decrypt =
1473           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1474                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1475         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
1476         cipher_obj.context_len =
1477           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1478                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1479         SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
1480
1481         /* Put the SIM to the list of all SIM's in server */
1482         silc_dlist_add(server->sim, sim);
1483
1484         silc_free(alg_name);
1485       } else {
1486         SILC_LOG_ERROR(("Error configuring ciphers"));
1487         silc_server_stop(server);
1488         exit(1);
1489       }
1490
1491       /* Register the cipher */
1492       silc_cipher_register(&cipher_obj);
1493 #else
1494       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1495                         "can't load modules!"));
1496       silc_server_stop(server);
1497       exit(1);
1498 #endif
1499     }
1500     cipher = cipher->next;
1501   } /* while */
1502
1503   return TRUE;
1504 }
1505
1506 /* Registers configured hash functions. These can then be allocated by the
1507    server when needed. */
1508
1509 bool silc_server_config_register_hashfuncs(SilcServer server)
1510 {
1511   SilcServerConfig config = server->config;
1512   SilcServerConfigHash *hash = config->hash;
1513   char *module_path = config->module_path;
1514
1515   SILC_LOG_DEBUG(("Registering configured hash functions"));
1516
1517   if (!hash) /* any hash func in the config file? */
1518     return FALSE;
1519
1520   while (hash) {
1521     /* if there isn't a module_path OR there isn't a module sim name try to
1522      * use buil-in functions */
1523     if (!module_path || !hash->module) {
1524       int i;
1525       for (i = 0; silc_default_hash[i].name; i++)
1526         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1527           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1528           break;
1529         }
1530       if (!silc_hash_is_supported(hash->name)) {
1531         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1532         silc_server_stop(server);
1533         exit(1);
1534       }
1535     } else {
1536 #ifdef SILC_SIM
1537       /* Load (try at least) the hash SIM module */
1538       SilcHashObject hash_obj;
1539       SilcSim sim;
1540
1541       memset(&hash_obj, 0, sizeof(hash_obj));
1542       hash_obj.name = hash->name;
1543       hash_obj.block_len = hash->block_length;
1544       hash_obj.hash_len = hash->digest_length;
1545
1546       sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
1547
1548       if ((silc_sim_load(sim))) {
1549         hash_obj.init =
1550           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1551                                                 SILC_HASH_SIM_INIT));
1552         SILC_LOG_DEBUG(("init=%p", hash_obj.init));
1553         hash_obj.update =
1554           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1555                                                 SILC_HASH_SIM_UPDATE));
1556         SILC_LOG_DEBUG(("update=%p", hash_obj.update));
1557         hash_obj.final =
1558           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1559                                                 SILC_HASH_SIM_FINAL));
1560         SILC_LOG_DEBUG(("final=%p", hash_obj.final));
1561         hash_obj.context_len =
1562           silc_sim_getsym(sim, silc_sim_symname(hash->name,
1563                                                 SILC_HASH_SIM_CONTEXT_LEN));
1564         SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
1565
1566         /* Put the SIM to the table of all SIM's in server */
1567         silc_dlist_add(server->sim, sim);
1568       } else {
1569         SILC_LOG_ERROR(("Error configuring hash functions"));
1570         silc_server_stop(server);
1571         exit(1);
1572       }
1573
1574       /* Register the hash function */
1575       silc_hash_register(&hash_obj);
1576 #else
1577       SILC_LOG_ERROR(("Dynamic module support not compiled, "
1578                         "can't load modules!"));
1579       silc_server_stop(server);
1580       exit(1);
1581 #endif
1582     }
1583     hash = hash->next;
1584   } /* while */
1585
1586   return TRUE;
1587 }
1588
1589 /* Registers configure HMACs. These can then be allocated by the server
1590    when needed. */
1591
1592 bool silc_server_config_register_hmacs(SilcServer server)
1593 {
1594   SilcServerConfig config = server->config;
1595   SilcServerConfigHmac *hmac = config->hmac;
1596
1597   SILC_LOG_DEBUG(("Registering configured HMACs"));
1598
1599   if (!hmac)
1600     return FALSE;
1601
1602   while (hmac) {
1603     SilcHmacObject hmac_obj;
1604     if (!silc_hash_is_supported(hmac->hash)) {
1605       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1606       silc_server_stop(server);
1607       exit(1);
1608     }
1609
1610     /* Register the HMAC */
1611     memset(&hmac_obj, 0, sizeof(hmac_obj));
1612     hmac_obj.name = hmac->name;
1613     hmac_obj.len = hmac->mac_length;
1614     silc_hmac_register(&hmac_obj);
1615
1616     hmac = hmac->next;
1617   } /* while */
1618
1619   return TRUE;
1620 }
1621
1622 /* Registers configured PKCS's. */
1623
1624 bool silc_server_config_register_pkcs(SilcServer server)
1625 {
1626   SilcServerConfig config = server->config;
1627   SilcServerConfigPkcs *pkcs = config->pkcs;
1628
1629   SILC_LOG_DEBUG(("Registering configured PKCS"));
1630
1631   if (!pkcs)
1632     return FALSE;
1633
1634   while (pkcs) {
1635     int i;
1636     for (i = 0; silc_default_pkcs[i].name; i++)
1637       if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
1638         silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
1639         break;
1640       }
1641     if (!silc_pkcs_is_supported(pkcs->name)) {
1642       SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
1643       silc_server_stop(server);
1644       exit(1);
1645     }
1646     pkcs = pkcs->next;
1647   } /* while */
1648
1649   return TRUE;
1650 }
1651
1652 /* Sets log files where log messages are saved by the server logger. */
1653
1654 void silc_server_config_setlogfiles(SilcServer server)
1655 {
1656   SilcServerConfig config = server->config;
1657   SilcServerConfigLogging *this;
1658
1659   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1660
1661   silc_log_quick = config->logging_quick;
1662   silc_log_flushdelay = (config->logging_flushdelay ? 
1663                          config->logging_flushdelay :
1664                          SILC_SERVER_LOG_FLUSH_DELAY);
1665
1666   if ((this = config->logging_fatals))
1667     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1668                       server->schedule);
1669   if ((this = config->logging_errors))
1670     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1671                       server->schedule);
1672   if ((this = config->logging_warnings))
1673     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1674                       server->schedule);
1675   if ((this = config->logging_info))
1676     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1677                       server->schedule);
1678 }
1679
1680 /* Returns client authentication information from configuration file by host
1681    (name or ip) */
1682
1683 SilcServerConfigClient *
1684 silc_server_config_find_client(SilcServer server, char *host)
1685 {
1686   SilcServerConfig config = server->config;
1687   SilcServerConfigClient *client;
1688
1689   if (!config || !host)
1690     return NULL;
1691
1692   for (client = config->clients; client; client = client->next) {
1693     if (client->host && !silc_string_compare(client->host, host))
1694       continue;
1695     break;
1696   }
1697
1698   /* if none matched, then client is already NULL */
1699   return client;
1700 }
1701
1702 /* Returns admin connection configuration by host, username and/or
1703    nickname. */
1704
1705 SilcServerConfigAdmin *
1706 silc_server_config_find_admin(SilcServer server, char *host, char *user, 
1707                               char *nick)
1708 {
1709   SilcServerConfig config = server->config;
1710   SilcServerConfigAdmin *admin;
1711
1712   /* make sure we have a value for the matching parameters */
1713   if (!host)
1714     host = "*";
1715   if (!user)
1716     user = "*";
1717   if (!nick)
1718     nick = "*";
1719
1720   for (admin = config->admins; admin; admin = admin->next) {
1721     if (admin->host && !silc_string_compare(admin->host, host))
1722       continue;
1723     if (admin->user && !silc_string_compare(admin->user, user))
1724       continue;
1725     if (admin->nick && !silc_string_compare(admin->nick, nick))
1726       continue;
1727     /* no checks failed -> this entry matches */
1728     break;
1729   }
1730
1731   /* if none matched, then admin is already NULL */
1732   return admin;
1733 }
1734
1735 /* Returns the denied connection configuration entry by host. */
1736
1737 SilcServerConfigDeny *
1738 silc_server_config_find_denied(SilcServer server, char *host)
1739 {
1740   SilcServerConfig config = server->config;
1741   SilcServerConfigDeny *deny;
1742
1743   /* make sure we have a value for the matching parameters */
1744   if (!config || !host)
1745     return NULL;
1746
1747   for (deny = config->denied; deny; deny = deny->next) {
1748     if (deny->host && !silc_string_compare(deny->host, host))
1749       continue;
1750     break;
1751   }
1752
1753   /* if none matched, then deny is already NULL */
1754   return deny;
1755 }
1756
1757 /* Returns server connection info from server configuartion by host
1758    (name or ip). */
1759
1760 SilcServerConfigServer *
1761 silc_server_config_find_server_conn(SilcServer server, char *host)
1762 {
1763   SilcServerConfig config = server->config;
1764   SilcServerConfigServer *serv = NULL;
1765
1766   if (!host)
1767     return NULL;
1768
1769   if (!config->servers)
1770     return NULL;
1771
1772   for (serv = config->servers; serv; serv = serv->next) {
1773     if (!silc_string_compare(serv->host, host))
1774       continue;
1775     break;
1776   }
1777
1778   return serv;
1779 }
1780
1781 /* Returns router connection info from server configuration by
1782    host (name or ip). */
1783
1784 SilcServerConfigRouter *
1785 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1786 {
1787   SilcServerConfig config = server->config;
1788   SilcServerConfigRouter *serv = NULL;
1789
1790   if (!host)
1791     return NULL;
1792
1793   if (!config->routers)
1794     return NULL;
1795
1796   for (serv = config->routers; serv; serv = serv->next) {
1797     if (!silc_string_compare(serv->host, host))
1798       continue;
1799     if (port && serv->port && serv->port != port)
1800       continue;
1801     break;
1802   }
1803
1804   return serv;
1805 }
1806
1807 /* Returns TRUE if configuration for a router connection that we are
1808    initiating exists. */
1809
1810 bool silc_server_config_is_primary_route(SilcServer server)
1811 {
1812   SilcServerConfig config = server->config;
1813   SilcServerConfigRouter *serv = NULL;
1814   int i;
1815   bool found = FALSE;
1816
1817   serv = config->routers;
1818   for (i = 0; serv; i++) {
1819     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
1820       found = TRUE;
1821       break;
1822     }
1823
1824     serv = serv->next;
1825   }
1826
1827   return found;
1828 }
1829
1830 /* Returns our primary connection configuration or NULL if we do not
1831    have primary router configured. */
1832
1833 SilcServerConfigRouter *
1834 silc_server_config_get_primary_router(SilcServer server)
1835 {
1836   SilcServerConfig config = server->config;
1837   SilcServerConfigRouter *serv = NULL;
1838   int i;
1839
1840   serv = config->routers;
1841   for (i = 0; serv; i++) {
1842     if (serv->initiator == TRUE && serv->backup_router == FALSE)
1843       return serv;
1844     serv = serv->next;
1845   }
1846
1847   return NULL;
1848 }