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