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