796242a6aaa55532320d378f0de72f2d786ebbf2
[silc.git] / apps / silcd / serverconfig.c
1 /*
2
3   serverconfig.c
4
5   Author: Giovanni Giacobbi <giovanni@giacobbi.net>
6
7   Copyright (C) 1997 - 2007 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23 #include <dirent.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
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   SET_PARAM_DEFAULT(qos_rate_limit, SILC_SERVER_QOS_RATE_LIMIT);
89   SET_PARAM_DEFAULT(qos_bytes_limit, SILC_SERVER_QOS_BYTES_LIMIT);
90   SET_PARAM_DEFAULT(qos_limit_sec, SILC_SERVER_QOS_LIMIT_SEC);
91   SET_PARAM_DEFAULT(qos_limit_usec, SILC_SERVER_QOS_LIMIT_USEC);
92   SET_PARAM_DEFAULT(chlimit, SILC_SERVER_CH_JOIN_LIMIT);
93
94 #undef SET_PARAM_DEFAULT
95 }
96
97 /* Find connection parameters by the parameter block name. */
98 static SilcServerConfigConnParams *
99 my_find_param(SilcServerConfig config, const char *name)
100 {
101   SilcServerConfigConnParams *param;
102
103   for (param = config->conn_params; param; param = param->next) {
104     if (!strcasecmp(param->name, name))
105       return param;
106   }
107
108   SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
109                          "Cannot find Params \"%s\".", name));
110
111   return NULL;
112 }
113
114 /* SKR find callbcak */
115
116 static void my_find_callback(SilcSKR skr, SilcSKRFind find,
117                              SilcSKRStatus status, SilcDList keys,
118                              void *context)
119 {
120   SilcSKRStatus *s = context;
121
122   *s = status;
123   if (keys)
124     silc_dlist_uninit(keys);
125
126   silc_skr_find_free(find);
127 }
128
129 /* parse an authdata according to its auth method */
130 static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
131                                   void **auth_data, SilcUInt32 *auth_data_len,
132                                   SilcSKRKeyUsage usage, void *key_context)
133 {
134   if (auth_meth == SILC_AUTH_PASSWORD) {
135     /* p is a plain text password */
136     if (auth_data && auth_data_len) {
137       if (!silc_utf8_valid(p, strlen(p))) {
138         *auth_data_len = silc_utf8_encoded_len(p, strlen(p),
139                                                SILC_STRING_LOCALE);
140         *auth_data = silc_calloc(*auth_data_len, sizeof(unsigned char));
141         silc_utf8_encode(p, strlen(p), SILC_STRING_LOCALE, *auth_data,
142                          *auth_data_len);
143       } else {
144         *auth_data = (void *) strdup(p);
145         *auth_data_len = (SilcUInt32) strlen(p);
146       }
147     }
148   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
149     /* p is a public key file name */
150     SilcPublicKey public_key;
151     SilcSKR skr = *auth_data;
152     SilcSKRFind find;
153     SilcSKRStatus status = SILC_SKR_NOT_FOUND;
154
155     if (!silc_pkcs_load_public_key(p, &public_key)) {
156       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
157                              "Could not load public key file!"));
158       return FALSE;
159     }
160
161     find = silc_skr_find_alloc();
162     silc_skr_find_set_public_key(find, public_key);
163     silc_skr_find_set_usage(find, usage);
164     if (!key_context)
165       silc_skr_find_set_context(find, SILC_32_TO_PTR(usage));
166     silc_skr_find(skr, NULL, find, my_find_callback, &status);
167     if (status == SILC_SKR_OK) {
168       /* Already added, ignore error */
169       silc_pkcs_public_key_free(public_key);
170       return TRUE;
171     }
172
173     /* Add the public key to repository */
174     status = silc_skr_add_public_key(skr, public_key, usage,
175                                      key_context ? key_context :
176                                      (void *)usage, NULL);
177     if (status != SILC_SKR_OK) {
178       SILC_SERVER_LOG_ERROR(("Error while adding public key \"%s\"", p));
179       return FALSE;
180     }
181   }
182
183   return TRUE;
184 }
185
186 static int my_parse_publickeydir(const char *dirname, void **auth_data,
187                                  SilcSKRKeyUsage usage)
188 {
189   int total = 0;
190   struct dirent *get_file;
191   DIR *dp;
192
193   if (!(dp = opendir(dirname))) {
194     SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
195                            "Could not open directory \"%s\"", dirname));
196     return -1;
197   }
198
199   /* errors are not considered fatal */
200   while ((get_file = readdir(dp))) {
201     const char *filename = get_file->d_name;
202     char buf[1024];
203     int dirname_len = strlen(dirname), filename_len = strlen(filename);
204     struct stat check_file;
205
206     /* Ignore "." and "..", and take files only with ".pub" suffix. */
207     if (!strcmp(filename, ".") || !strcmp(filename, "..") ||
208         (filename_len < 5) || strcmp(filename + filename_len - 4, ".pub"))
209       continue;
210
211     memset(buf, 0, sizeof(buf));
212     snprintf(buf, sizeof(buf) - 1, "%s%s%s", dirname,
213              (dirname[dirname_len - 1] == '/' ? "" : "/"), filename);
214
215     if (stat(buf, &check_file) < 0) {
216       SILC_SERVER_LOG_ERROR(("Error stating file %s: %s", buf,
217                              strerror(errno)));
218     } else if (S_ISREG(check_file.st_mode)) {
219       if (my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL,
220                             usage, NULL))
221         total++;
222     }
223   }
224
225   SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname));
226   return total;
227 }
228
229 /* Callbacks */
230
231 SILC_CONFIG_CALLBACK(fetch_generic)
232 {
233   SilcServerConfig config = (SilcServerConfig) context;
234   int got_errno = 0;
235
236   if (!strcmp(name, "prefer_passphrase_auth")) {
237     config->prefer_passphrase_auth = *(SilcBool *)val;
238   }
239   else if (!strcmp(name, "require_reverse_lookup")) {
240     config->require_reverse_lookup = *(SilcBool *)val;
241   }
242   else if (!strcmp(name, "connections_max")) {
243     config->param.connections_max = (SilcUInt32) *(int *)val;
244   }
245   else if (!strcmp(name, "connections_max_per_host")) {
246     config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
247   }
248   else if (!strcmp(name, "keepalive_secs")) {
249     config->param.keepalive_secs = (SilcUInt32) *(int *)val;
250   }
251   else if (!strcmp(name, "reconnect_count")) {
252     config->param.reconnect_count = (SilcUInt32) *(int *)val;
253   }
254   else if (!strcmp(name, "reconnect_interval")) {
255     config->param.reconnect_interval = (SilcUInt32) *(int *)val;
256   }
257   else if (!strcmp(name, "reconnect_interval_max")) {
258     config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
259   }
260   else if (!strcmp(name, "reconnect_keep_trying")) {
261     config->param.reconnect_keep_trying = *(SilcBool *)val;
262   }
263   else if (!strcmp(name, "key_exchange_rekey")) {
264     config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
265   }
266   else if (!strcmp(name, "key_exchange_pfs")) {
267     config->param.key_exchange_pfs = *(SilcBool *)val;
268   }
269   else if (!strcmp(name, "channel_rekey_secs")) {
270     config->channel_rekey_secs = (SilcUInt32) *(int *)val;
271   }
272   else if (!strcmp(name, "key_exchange_timeout")) {
273     config->key_exchange_timeout = (SilcUInt32) *(int *)val;
274   }
275   else if (!strcmp(name, "conn_auth_timeout")) {
276     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
277   }
278   else if (!strcmp(name, "version_protocol")) {
279     CONFIG_IS_DOUBLE(config->param.version_protocol);
280     config->param.version_protocol =
281       (*(char *)val ? strdup((char *) val) : NULL);
282   }
283   else if (!strcmp(name, "version_software")) {
284     CONFIG_IS_DOUBLE(config->param.version_software);
285     config->param.version_software =
286       (*(char *)val ? strdup((char *) val) : NULL);
287   }
288   else if (!strcmp(name, "version_software_vendor")) {
289     CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
290     config->param.version_software_vendor =
291       (*(char *)val ? strdup((char *) val) : NULL);
292   }
293   else if (!strcmp(name, "detach_disabled")) {
294     config->detach_disabled = *(SilcBool *)val;
295   }
296   else if (!strcmp(name, "detach_timeout")) {
297     config->detach_timeout = (SilcUInt32) *(int *)val;
298   }
299   else if (!strcmp(name, "qos")) {
300     config->param.qos = *(SilcBool *)val;
301   }
302   else if (!strcmp(name, "qos_rate_limit")) {
303     config->param.qos_rate_limit = *(SilcUInt32 *)val;
304   }
305   else if (!strcmp(name, "qos_bytes_limit")) {
306     config->param.qos_bytes_limit = *(SilcUInt32 *)val;
307   }
308   else if (!strcmp(name, "qos_limit_sec")) {
309     config->param.qos_limit_sec = *(SilcUInt32 *)val;
310   }
311   else if (!strcmp(name, "qos_limit_usec")) {
312     config->param.qos_limit_usec = *(SilcUInt32 *)val;
313   }
314   else if (!strcmp(name, "channel_join_limit")) {
315     config->param.chlimit = *(SilcUInt32 *)val;
316   }
317   else if (!strcmp(name, "debug_string")) {
318     CONFIG_IS_DOUBLE(config->debug_string);
319     config->debug_string = (*(char *)val ? strdup((char *) val) : NULL);
320   }
321   else if (!strcmp(name, "http_server")) {
322     config->httpd = *(SilcBool *)val;
323   }
324   else if (!strcmp(name, "http_server_ip")) {
325     CONFIG_IS_DOUBLE(config->httpd_ip);
326     config->httpd_ip = (*(char *)val ? strdup((char *) val) : NULL);
327   }
328   else if (!strcmp(name, "http_server_port")) {
329     int port = *(int *)val;
330     if ((port <= 0) || (port > 65535)) {
331       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
332                              "Invalid port number!"));
333       got_errno = SILC_CONFIG_EPRINTLINE;
334       goto got_err;
335     }
336     config->httpd_port = (SilcUInt16)port;
337   }
338   else if (!strcmp(name, "dynamic_server")) {
339     config->dynamic_server = *(SilcBool *)val;
340   }
341   else if (!strcmp(name, "local_channels")) {
342     config->local_channels = *(SilcBool *)val;
343   }
344   else
345     return SILC_CONFIG_EINTERNAL;
346
347   return SILC_CONFIG_OK;
348
349  got_err:
350   return got_errno;
351 }
352
353 SILC_CONFIG_CALLBACK(fetch_cipher)
354 {
355   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher);
356
357   SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)",
358                        type, name, context));
359   if (type == SILC_CONFIG_ARG_BLOCK) {
360     /* check the temporary struct's fields */
361     if (!tmp) /* discard empty sub-blocks */
362       return SILC_CONFIG_OK;
363     if (!tmp->name) {
364       got_errno = SILC_CONFIG_EMISSFIELDS;
365       goto got_err;
366     }
367
368     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
369     config->tmp = NULL;
370     return SILC_CONFIG_OK;
371   }
372   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigCipher);
373
374   /* Identify and save this value */
375   if (!strcmp(name, "name")) {
376     CONFIG_IS_DOUBLE(tmp->name);
377     tmp->name = strdup((char *) val);
378   }
379   else if (!strcmp(name, "keylength")) {
380     tmp->key_length = *(SilcUInt32 *)val;
381   }
382   else if (!strcmp(name, "blocklength")) {
383     tmp->block_length = *(SilcUInt32 *)val;
384   }
385   else
386     return SILC_CONFIG_EINTERNAL;
387   return SILC_CONFIG_OK;
388
389  got_err:
390   silc_free(tmp->name);
391   silc_free(tmp);
392   config->tmp = NULL;
393   return got_errno;
394 }
395
396 SILC_CONFIG_CALLBACK(fetch_hash)
397 {
398   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash);
399
400   SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)",
401                        type, name, context));
402   if (type == SILC_CONFIG_ARG_BLOCK) {
403     /* check the temporary struct's fields */
404     if (!tmp) /* discard empty sub-blocks */
405       return SILC_CONFIG_OK;
406     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
407       got_errno = SILC_CONFIG_EMISSFIELDS;
408       goto got_err;
409     }
410
411     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
412     config->tmp = NULL;
413     return SILC_CONFIG_OK;
414   }
415   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHash);
416
417   /* Identify and save this value */
418   if (!strcmp(name, "name")) {
419     CONFIG_IS_DOUBLE(tmp->name);
420     tmp->name = strdup((char *) val);
421   }
422   else if (!strcmp(name, "blocklength")) {
423     tmp->block_length = *(int *)val;
424   }
425   else if (!strcmp(name, "digestlength")) {
426     tmp->digest_length = *(int *)val;
427   }
428   else
429     return SILC_CONFIG_EINTERNAL;
430   return SILC_CONFIG_OK;
431
432  got_err:
433   silc_free(tmp->name);
434   silc_free(tmp);
435   config->tmp = NULL;
436   return got_errno;
437 }
438
439 SILC_CONFIG_CALLBACK(fetch_hmac)
440 {
441   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac);
442
443   SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)",
444                        type, name, context));
445   if (type == SILC_CONFIG_ARG_BLOCK) {
446     /* check the temporary struct's fields */
447     if (!tmp) /* discard empty sub-blocks */
448       return SILC_CONFIG_OK;
449     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
450       got_errno = SILC_CONFIG_EMISSFIELDS;
451       goto got_err;
452     }
453
454     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
455     config->tmp = NULL;
456     return SILC_CONFIG_OK;
457   }
458   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHmac);
459
460   /* Identify and save this value */
461   if (!strcmp(name, "name")) {
462     CONFIG_IS_DOUBLE(tmp->name);
463     tmp->name = strdup((char *) val);
464   }
465   else if (!strcmp(name, "hash")) {
466     CONFIG_IS_DOUBLE(tmp->hash);
467     tmp->hash = strdup((char *) val);
468   }
469   else if (!strcmp(name, "maclength")) {
470     tmp->mac_length = *(int *)val;
471   }
472   else
473     return SILC_CONFIG_EINTERNAL;
474   return SILC_CONFIG_OK;
475
476  got_err:
477   silc_free(tmp->name);
478   silc_free(tmp->hash);
479   silc_free(tmp);
480   config->tmp = NULL;
481   return got_errno;
482 }
483
484 SILC_CONFIG_CALLBACK(fetch_pkcs)
485 {
486   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs);
487
488   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
489                        type, name, context));
490   if (type == SILC_CONFIG_ARG_BLOCK) {
491     /* Check the temporary struct's fields */
492     if (!tmp) /* discard empty sub-blocks */
493       return SILC_CONFIG_OK;
494     if (!tmp->name) {
495       got_errno = SILC_CONFIG_EMISSFIELDS;
496       goto got_err;
497     }
498
499     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
500     config->tmp = NULL;
501     return SILC_CONFIG_OK;
502   }
503   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigPkcs);
504
505   /* Identify and save this value */
506   if (!strcmp(name, "name")) {
507     CONFIG_IS_DOUBLE(tmp->name);
508     tmp->name = strdup((char *) val);
509   }
510   else
511     return SILC_CONFIG_EINTERNAL;
512   return SILC_CONFIG_OK;
513
514  got_err:
515   silc_free(tmp->name);
516   silc_free(tmp);
517   config->tmp = NULL;
518   return got_errno;
519 }
520
521 SILC_CONFIG_CALLBACK(fetch_serverinfo)
522 {
523   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServerInfoInterface);
524   SilcServerConfigServerInfo *server_info = config->server_info;
525
526   SERVER_CONFIG_DEBUG(("Received SERVERINFO type=%d name=\"%s\" (val=%x)",
527                        type, name, context));
528
529   /* If there isn't the main struct alloc it */
530   if (!server_info)
531     config->server_info = server_info = (SilcServerConfigServerInfo *)
532                 silc_calloc(1, sizeof(*server_info));
533
534   if (type == SILC_CONFIG_ARG_BLOCK) {
535     if (!strcmp(name, "primary")) {
536       if (server_info->primary) {
537         SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
538                                "Double primary specification."));
539         got_errno = SILC_CONFIG_EPRINTLINE;
540         goto got_err;
541       }
542       CONFIG_IS_DOUBLE(server_info->primary);
543
544       /* now check the temporary struct, don't accept empty block and
545          make sure all fields are there */
546       if (!tmp || !tmp->server_ip || !tmp->port) {
547         got_errno = SILC_CONFIG_EMISSFIELDS;
548         goto got_err;
549       }
550       server_info->primary = tmp;
551       config->tmp = NULL;
552       return SILC_CONFIG_OK;
553     } else if (!strcmp(name, "secondary")) {
554       if (!tmp)
555         return SILC_CONFIG_OK;
556       if (!tmp || !tmp->server_ip || !tmp->port) {
557         got_errno = SILC_CONFIG_EMISSFIELDS;
558         goto got_err;
559       }
560       SILC_SERVER_CONFIG_LIST_APPENDTMP(server_info->secondary);
561       config->tmp = NULL;
562       return SILC_CONFIG_OK;
563     } else if (!server_info->public_key || !server_info->private_key) {
564       got_errno = SILC_CONFIG_EMISSFIELDS;
565       goto got_err;
566     }
567     return SILC_CONFIG_OK;
568   }
569   if (!strcmp(name, "hostname")) {
570     CONFIG_IS_DOUBLE(server_info->server_name);
571     server_info->server_name = strdup((char *) val);
572   }
573   else if (!strcmp(name, "ip")) {
574     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
575     CONFIG_IS_DOUBLE(tmp->server_ip);
576     tmp->server_ip = strdup((char *) val);
577   }
578   else if (!strcmp(name, "public_ip")) {
579     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
580     CONFIG_IS_DOUBLE(tmp->public_ip);
581     tmp->public_ip = strdup((char *) val);
582   }
583   else if (!strcmp(name, "port")) {
584     int port = *(int *)val;
585     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
586     if ((port <= 0) || (port > 65535)) {
587       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
588                              "Invalid port number!"));
589       got_errno = SILC_CONFIG_EPRINTLINE;
590       goto got_err;
591     }
592     tmp->port = (SilcUInt16) port;
593   }
594   else if (!strcmp(name, "servertype")) {
595     CONFIG_IS_DOUBLE(server_info->server_type);
596     server_info->server_type = strdup((char *) val);
597   }
598   else if (!strcmp(name, "admin")) {
599     CONFIG_IS_DOUBLE(server_info->admin);
600     server_info->admin = strdup((char *) val);
601   }
602   else if (!strcmp(name, "adminemail")) {
603     CONFIG_IS_DOUBLE(server_info->email);
604     server_info->email = strdup((char *) val);
605   }
606   else if (!strcmp(name, "location")) {
607     CONFIG_IS_DOUBLE(server_info->location);
608     server_info->location = strdup((char *) val);
609   }
610   else if (!strcmp(name, "user")) {
611     CONFIG_IS_DOUBLE(server_info->user);
612     server_info->user = strdup((char *) val);
613   }
614   else if (!strcmp(name, "group")) {
615     CONFIG_IS_DOUBLE(server_info->group);
616     server_info->group = strdup((char *) val);
617   }
618   else if (!strcmp(name, "motdfile")) {
619     CONFIG_IS_DOUBLE(server_info->motd_file);
620     server_info->motd_file = strdup((char *) val);
621   }
622   else if (!strcmp(name, "pidfile")) {
623     CONFIG_IS_DOUBLE(server_info->pid_file);
624     server_info->pid_file = strdup((char *) val);
625   }
626   else if (!strcmp(name, "publickey")) {
627     char *file_tmp = (char *) val;
628     CONFIG_IS_DOUBLE(server_info->public_key);
629
630     /* Try to load specified file, if fail stop config parsing */
631     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key)) {
632       SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
633       return SILC_CONFIG_EPRINTLINE;
634     }
635   }
636   else if (!strcmp(name, "privatekey")) {
637     struct stat st;
638     char *file_tmp = (char *) val;
639     CONFIG_IS_DOUBLE(server_info->private_key);
640
641     /* Check the private key file permissions. */
642     if ((stat(file_tmp, &st)) != -1) {
643       if ((st.st_mode & 0777) != 0600) {
644         SILC_SERVER_LOG_ERROR(("Wrong permissions in private key "
645                               "file \"%s\".  The permissions must be "
646                               "0600.", file_tmp));
647         return SILC_CONFIG_ESILENT;
648       }
649     }
650
651     /* Try to load specified file, if fail stop config parsing */
652     if (!silc_pkcs_load_private_key(file_tmp, "", 0,
653                                     &server_info->private_key)) {
654       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
655       return SILC_CONFIG_EPRINTLINE;
656     }
657   }
658   else
659     return SILC_CONFIG_EINTERNAL;
660   return SILC_CONFIG_OK;
661
662  got_err:
663   /* Here we need to check if tmp exists because this function handles
664    * misc data (multiple fields and single-only fields) */
665   if (tmp) {
666     silc_free(tmp->server_ip);
667     silc_free(tmp);
668     config->tmp = NULL;
669   }
670   return got_errno;
671 }
672
673 SILC_CONFIG_CALLBACK(fetch_logging)
674 {
675   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
676
677   if (!strcmp(name, "timestamp")) {
678     config->logging_timestamp = *(SilcBool *)val;
679   }
680   else if (!strcmp(name, "quicklogs")) {
681     config->logging_quick = *(SilcBool *)val;
682   }
683   else if (!strcmp(name, "flushdelay")) {
684     int flushdelay = *(int *)val;
685     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
686       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
687                             "Invalid flushdelay value, use quicklogs if you "
688                             "want real-time logging."));
689       return SILC_CONFIG_EPRINTLINE;
690     }
691     config->logging_flushdelay = (long) flushdelay;
692   }
693
694   /* The following istances happens only in Logging's sub-blocks, a match
695      for the sub-block name means that you should store the filename/maxsize
696      temporary struct to the proper logging channel.
697      If we get a match for "file" or "maxsize" this means that we are inside
698      a sub-sub-block and it is safe to alloc a new tmp. */
699 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
700   else if (!strcmp(name, __chan__)) {                           \
701     if (!tmp) return SILC_CONFIG_OK;                            \
702     if (!tmp->file) {                                           \
703       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
704     }                                                           \
705     config->__member__ = tmp;                                   \
706     config->tmp = NULL;                                         \
707   }
708   FETCH_LOGGING_CHAN("info", logging_info)
709   FETCH_LOGGING_CHAN("warnings", logging_warnings)
710   FETCH_LOGGING_CHAN("errors", logging_errors)
711   FETCH_LOGGING_CHAN("fatals", logging_fatals)
712 #undef FETCH_LOGGING_CHAN
713   else if (!strcmp(name, "file")) {
714     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigLogging);
715     CONFIG_IS_DOUBLE(tmp->file);
716     tmp->file = strdup((char *) val);
717   }
718   else if (!strcmp(name, "size")) {
719     if (!tmp) {
720       config->tmp = silc_calloc(1, sizeof(*tmp));
721       tmp = (SilcServerConfigLogging *) config->tmp;
722     }
723     tmp->maxsize = *(SilcUInt32 *) val;
724   }
725   else
726     return SILC_CONFIG_EINTERNAL;
727   return SILC_CONFIG_OK;
728
729  got_err:
730   silc_free(tmp->file);
731   silc_free(tmp);
732   config->tmp = NULL;
733   return got_errno;
734 }
735
736 SILC_CONFIG_CALLBACK(fetch_connparam)
737 {
738   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
739
740   SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)",
741                        type, name, context));
742   if (type == SILC_CONFIG_ARG_BLOCK) {
743     /* check the temporary struct's fields */
744     if (!tmp) /* discard empty sub-blocks */
745       return SILC_CONFIG_OK;
746     if (!tmp->name) {
747       got_errno = SILC_CONFIG_EMISSFIELDS;
748       goto got_err;
749     }
750     /* Set defaults */
751     my_set_param_defaults(tmp, &config->param);
752
753     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
754     config->tmp = NULL;
755     return SILC_CONFIG_OK;
756   }
757   if (!tmp) {
758     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigConnParams);
759     tmp->reconnect_keep_trying = TRUE;
760   }
761
762   if (!strcmp(name, "name")) {
763     CONFIG_IS_DOUBLE(tmp->name);
764     tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
765   }
766   else if (!strcmp(name, "connections_max")) {
767     tmp->connections_max = *(SilcUInt32 *)val;
768   }
769   else if (!strcmp(name, "connections_max_per_host")) {
770     tmp->connections_max_per_host = *(SilcUInt32 *)val;
771   }
772   else if (!strcmp(name, "keepalive_secs")) {
773     tmp->keepalive_secs = *(SilcUInt32 *)val;
774   }
775   else if (!strcmp(name, "reconnect_count")) {
776     tmp->reconnect_count = *(SilcUInt32 *)val;
777   }
778   else if (!strcmp(name, "reconnect_interval")) {
779     tmp->reconnect_interval = *(SilcUInt32 *)val;
780   }
781   else if (!strcmp(name, "reconnect_interval_max")) {
782     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
783   }
784   else if (!strcmp(name, "reconnect_keep_trying")) {
785     tmp->reconnect_keep_trying = *(SilcBool *)val;
786   }
787   else if (!strcmp(name, "key_exchange_rekey")) {
788     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
789   }
790   else if (!strcmp(name, "key_exchange_pfs")) {
791     tmp->key_exchange_pfs = *(SilcBool *)val;
792   }
793   else if (!strcmp(name, "version_protocol")) {
794     CONFIG_IS_DOUBLE(tmp->version_protocol);
795     tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
796   }
797   else if (!strcmp(name, "version_software")) {
798     CONFIG_IS_DOUBLE(tmp->version_software);
799     tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
800   }
801   else if (!strcmp(name, "version_software_vendor")) {
802     CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
803     tmp->version_software_vendor =
804       (*(char *)val ? strdup((char *) val) : NULL);
805   }
806   else if (!strcmp(name, "anonymous")) {
807     tmp->anonymous = *(SilcBool *)val;
808   }
809   else if (!strcmp(name, "qos")) {
810     tmp->qos = *(SilcBool *)val;
811   }
812   else if (!strcmp(name, "qos_rate_limit")) {
813     tmp->qos_rate_limit = *(SilcUInt32 *)val;
814   }
815   else if (!strcmp(name, "qos_bytes_limit")) {
816     tmp->qos_bytes_limit = *(SilcUInt32 *)val;
817   }
818   else if (!strcmp(name, "qos_limit_sec")) {
819     tmp->qos_limit_sec = *(SilcUInt32 *)val;
820   }
821   else if (!strcmp(name, "qos_limit_usec")) {
822     tmp->qos_limit_usec = *(SilcUInt32 *)val;
823   }
824   else
825     return SILC_CONFIG_EINTERNAL;
826
827   return SILC_CONFIG_OK;
828
829  got_err:
830   silc_free(tmp->name);
831   silc_free(tmp);
832   config->tmp = NULL;
833   return got_errno;
834 }
835
836 SILC_CONFIG_CALLBACK(fetch_client)
837 {
838   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
839
840   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
841                        type, name, context));
842
843   /* Alloc before block checking, because empty sub-blocks are welcome here */
844   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigClient);
845
846   if (type == SILC_CONFIG_ARG_BLOCK) {
847     /* empty sub-blocks are welcome */
848     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
849     config->tmp = NULL;
850     return SILC_CONFIG_OK;
851   }
852
853   /* Identify and save this value */
854   if (!strcmp(name, "host")) {
855     CONFIG_IS_DOUBLE(tmp->host);
856     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
857   }
858   else if (!strcmp(name, "passphrase")) {
859     CONFIG_IS_DOUBLE(tmp->passphrase);
860     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
861                            (void *)&tmp->passphrase,
862                            &tmp->passphrase_len, 0, NULL)) {
863       got_errno = SILC_CONFIG_EPRINTLINE;
864       goto got_err;
865     }
866   }
867   else if (!strcmp(name, "publickey")) {
868     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
869                            (void *)&config->server->repository, NULL,
870                            SILC_SKR_USAGE_AUTH |
871                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
872       got_errno = SILC_CONFIG_EPRINTLINE;
873       goto got_err;
874     }
875     tmp->publickeys = TRUE;
876   }
877   else if (!strcmp(name, "publickeydir")) {
878     if (my_parse_publickeydir((char *) val,
879                               (void *)&config->server->repository,
880                               SILC_SKR_USAGE_AUTH |
881                               SILC_SKR_USAGE_KEY_AGREEMENT) < 0) {
882       got_errno = SILC_CONFIG_EPRINTLINE;
883       goto got_err;
884     }
885     tmp->publickeys = TRUE;
886   }
887   else if (!strcmp(name, "params")) {
888     CONFIG_IS_DOUBLE(tmp->param);
889     tmp->param = my_find_param(config, (char *) val);
890     if (!tmp->param) { /* error message already output */
891       got_errno = SILC_CONFIG_EPRINTLINE;
892       goto got_err;
893     }
894   }
895   else
896     return SILC_CONFIG_EINTERNAL;
897   return SILC_CONFIG_OK;
898
899  got_err:
900   silc_free(tmp->host);
901   CONFIG_FREE_AUTH(tmp);
902   silc_free(tmp);
903   config->tmp = NULL;
904   return got_errno;
905 }
906
907 SILC_CONFIG_CALLBACK(fetch_admin)
908 {
909   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
910
911   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
912                        type, name, context));
913   if (type == SILC_CONFIG_ARG_BLOCK) {
914     /* check the temporary struct's fields */
915     if (!tmp) /* discard empty sub-blocks */
916       return SILC_CONFIG_OK;
917
918     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
919     config->tmp = NULL;
920     return SILC_CONFIG_OK;
921   }
922   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigAdmin);
923
924   /* Identify and save this value */
925   if (!strcmp(name, "host")) {
926     CONFIG_IS_DOUBLE(tmp->host);
927     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
928   }
929   else if (!strcmp(name, "user")) {
930     CONFIG_IS_DOUBLE(tmp->user);
931     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
932   }
933   else if (!strcmp(name, "nick")) {
934     CONFIG_IS_DOUBLE(tmp->nick);
935     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
936   }
937   else if (!strcmp(name, "passphrase")) {
938     CONFIG_IS_DOUBLE(tmp->passphrase);
939     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
940                            (void *)&tmp->passphrase,
941                            &tmp->passphrase_len, 0, NULL)) {
942       got_errno = SILC_CONFIG_EPRINTLINE;
943       goto got_err;
944     }
945   }
946   else if (!strcmp(name, "publickey")) {
947     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
948                            (void *)&config->server->repository, NULL,
949                            SILC_SKR_USAGE_SERVICE_AUTHORIZATION, tmp)) {
950       got_errno = SILC_CONFIG_EPRINTLINE;
951       goto got_err;
952     }
953     tmp->publickeys = TRUE;
954   }
955   else
956     return SILC_CONFIG_EINTERNAL;
957   return SILC_CONFIG_OK;
958
959  got_err:
960   silc_free(tmp->host);
961   silc_free(tmp->user);
962   silc_free(tmp->nick);
963   CONFIG_FREE_AUTH(tmp);
964   silc_free(tmp);
965   config->tmp = NULL;
966   return got_errno;
967 }
968
969 SILC_CONFIG_CALLBACK(fetch_deny)
970 {
971   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
972
973   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
974                        type, name, context));
975   if (type == SILC_CONFIG_ARG_BLOCK) {
976     /* check the temporary struct's fields */
977     if (!tmp) /* discard empty sub-blocks */
978       return SILC_CONFIG_OK;
979     if (!tmp->reason) {
980       got_errno = SILC_CONFIG_EMISSFIELDS;
981       goto got_err;
982     }
983
984     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
985     config->tmp = NULL;
986     return SILC_CONFIG_OK;
987   }
988   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny);
989
990   /* Identify and save this value */
991   if (!strcmp(name, "host")) {
992     CONFIG_IS_DOUBLE(tmp->host);
993     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
994   }
995   else if (!strcmp(name, "reason")) {
996     CONFIG_IS_DOUBLE(tmp->reason);
997     tmp->reason = strdup((char *) val);
998   }
999   else
1000     return SILC_CONFIG_EINTERNAL;
1001   return SILC_CONFIG_OK;
1002
1003  got_err:
1004   silc_free(tmp->host);
1005   silc_free(tmp->reason);
1006   silc_free(tmp);
1007   config->tmp = NULL;
1008   return got_errno;
1009 }
1010
1011 SILC_CONFIG_CALLBACK(fetch_server)
1012 {
1013   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
1014
1015   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
1016                        type, name, context));
1017   if (type == SILC_CONFIG_ARG_BLOCK) {
1018     /* check the temporary struct's fields */
1019     if (!tmp) /* discard empty sub-blocks */
1020       return SILC_CONFIG_OK;
1021     if (!tmp->host) {
1022       got_errno = SILC_CONFIG_EMISSFIELDS;
1023       goto got_err;
1024     }
1025
1026     /* the temporary struct is ok, append it to the list */
1027     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
1028     config->tmp = NULL;
1029     return SILC_CONFIG_OK;
1030   }
1031   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer);
1032
1033   /* Identify and save this value */
1034   if (!strcmp(name, "host")) {
1035     CONFIG_IS_DOUBLE(tmp->host);
1036     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
1037   }
1038   else if (!strcmp(name, "passphrase")) {
1039     CONFIG_IS_DOUBLE(tmp->passphrase);
1040     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1041                            (void *)&tmp->passphrase,
1042                            &tmp->passphrase_len, 0, NULL)) {
1043       got_errno = SILC_CONFIG_EPRINTLINE;
1044       goto got_err;
1045     }
1046   }
1047   else if (!strcmp(name, "publickey")) {
1048     CONFIG_IS_DOUBLE(tmp->publickeys);
1049     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1050                            (void *)&config->server->repository, NULL,
1051                            SILC_SKR_USAGE_AUTH |
1052                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
1053       got_errno = SILC_CONFIG_EPRINTLINE;
1054       goto got_err;
1055     }
1056     tmp->publickeys = TRUE;
1057   }
1058   else if (!strcmp(name, "params")) {
1059     CONFIG_IS_DOUBLE(tmp->param);
1060     tmp->param = my_find_param(config, (char *) val);
1061     if (!tmp->param) { /* error message already output */
1062       got_errno = SILC_CONFIG_EPRINTLINE;
1063       goto got_err;
1064     }
1065   }
1066   else if (!strcmp(name, "backup")) {
1067     tmp->backup_router = *(SilcBool *)val;
1068   }
1069   else
1070     return SILC_CONFIG_EINTERNAL;
1071
1072   return SILC_CONFIG_OK;
1073
1074  got_err:
1075   silc_free(tmp->host);
1076   CONFIG_FREE_AUTH(tmp);
1077   silc_free(tmp);
1078   config->tmp = NULL;
1079   return got_errno;
1080 }
1081
1082 SILC_CONFIG_CALLBACK(fetch_router)
1083 {
1084   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
1085
1086   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
1087                        type, name, context));
1088   if (type == SILC_CONFIG_ARG_BLOCK) {
1089     if (!tmp) /* discard empty sub-blocks */
1090       return SILC_CONFIG_OK;
1091     if (!tmp->host) {
1092       got_errno = SILC_CONFIG_EMISSFIELDS;
1093       goto got_err;
1094     }
1095
1096     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
1097     config->tmp = NULL;
1098     return SILC_CONFIG_OK;
1099   }
1100   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigRouter);
1101
1102   /* Identify and save this value */
1103   if (!strcmp(name, "host")) {
1104     CONFIG_IS_DOUBLE(tmp->host);
1105     tmp->host = strdup((char *) val);
1106   }
1107   else if (!strcmp(name, "port")) {
1108     int port = *(int *)val;
1109     if ((port <= 0) || (port > 65535)) {
1110       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1111                              "Invalid port number!"));
1112       got_errno = SILC_CONFIG_EPRINTLINE;
1113       goto got_err;
1114     }
1115     tmp->port = (SilcUInt16) port;
1116   }
1117   else if (!strcmp(name, "passphrase")) {
1118     CONFIG_IS_DOUBLE(tmp->passphrase);
1119     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1120                            (void *)&tmp->passphrase,
1121                            &tmp->passphrase_len, 0, NULL)) {
1122       got_errno = SILC_CONFIG_EPRINTLINE;
1123       goto got_err;
1124     }
1125   }
1126   else if (!strcmp(name, "publickey")) {
1127     CONFIG_IS_DOUBLE(tmp->publickeys);
1128     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1129                            (void *)&config->server->repository, NULL,
1130                            SILC_SKR_USAGE_AUTH |
1131                            SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
1132       got_errno = SILC_CONFIG_EPRINTLINE;
1133       goto got_err;
1134     }
1135     tmp->publickeys = TRUE;
1136   }
1137   else if (!strcmp(name, "params")) {
1138     CONFIG_IS_DOUBLE(tmp->param);
1139     tmp->param = my_find_param(config, (char *) val);
1140     if (!tmp->param) { /* error message already output */
1141       got_errno = SILC_CONFIG_EPRINTLINE;
1142       goto got_err;
1143     }
1144   }
1145   else if (!strcmp(name, "initiator")) {
1146     tmp->initiator = *(SilcBool *)val;
1147   }
1148   else if (!strcmp(name, "backuphost")) {
1149     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
1150     tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) :
1151                               strdup("*"));
1152     tmp->backup_router = TRUE;
1153   }
1154   else if (!strcmp(name, "backupport")) {
1155     int port = *(int *)val;
1156     if ((port <= 0) || (port > 65535)) {
1157       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
1158                              "Invalid port number!"));
1159       got_errno = SILC_CONFIG_EPRINTLINE;
1160       goto got_err;
1161     }
1162     tmp->backup_replace_port = (SilcUInt16) port;
1163   }
1164   else if (!strcmp(name, "backuplocal")) {
1165     tmp->backup_local = *(SilcBool *)val;
1166   }
1167   else if (!strcmp(name, "dynamic_connection")) {
1168     tmp->dynamic_connection = *(SilcBool *)val;
1169   }
1170   else
1171     return SILC_CONFIG_EINTERNAL;
1172
1173   return SILC_CONFIG_OK;
1174
1175  got_err:
1176   silc_free(tmp->host);
1177   silc_free(tmp->backup_replace_ip);
1178   CONFIG_FREE_AUTH(tmp);
1179   silc_free(tmp);
1180   config->tmp = NULL;
1181   return got_errno;
1182 }
1183
1184 /* known config options tables */
1185 static const SilcConfigTable table_general[] = {
1186   { "prefer_passphrase_auth",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1187   { "require_reverse_lookup",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1188   { "connections_max",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1189   { "connections_max_per_host", SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1190   { "keepalive_secs",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1191   { "reconnect_count",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1192   { "reconnect_interval",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1193   { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1194   { "reconnect_keep_trying",    SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1195   { "key_exchange_rekey",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1196   { "key_exchange_pfs",         SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1197   { "channel_rekey_secs",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1198   { "key_exchange_timeout",     SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1199   { "conn_auth_timeout",        SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1200   { "version_protocol",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1201   { "version_software",         SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1202   { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1203   { "detach_disabled",          SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1204   { "detach_timeout",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1205   { "qos",                      SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1206   { "qos_rate_limit",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1207   { "qos_bytes_limit",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1208   { "qos_limit_sec",            SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1209   { "qos_limit_usec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1210   { "channel_join_limit",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1211   { "debug_string",             SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
1212   { "http_server",              SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1213   { "http_server_ip",           SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
1214   { "http_server_port",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
1215   { "dynamic_server",           SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1216   { "local_channels",           SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
1217   { 0, 0, 0, 0 }
1218 };
1219
1220 static const SilcConfigTable table_cipher[] = {
1221   { "name",             SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
1222   { "keylength",        SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1223   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
1224   { 0, 0, 0, 0 }
1225 };
1226
1227 static const SilcConfigTable table_hash[] = {
1228   { "name",             SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
1229   { "blocklength",      SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1230   { "digestlength",     SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
1231   { 0, 0, 0, 0 }
1232 };
1233
1234 static const SilcConfigTable table_hmac[] = {
1235   { "name",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1236   { "hash",             SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
1237   { "maclength",        SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
1238   { 0, 0, 0, 0 }
1239 };
1240
1241 static const SilcConfigTable table_pkcs[] = {
1242   { "name",             SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
1243   { 0, 0, 0, 0 }
1244 };
1245
1246 static const SilcConfigTable table_serverinfo_c[] = {
1247   { "ip",               SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1248   { "public_ip",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1249   { "port",             SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
1250   { 0, 0, 0, 0 }
1251 };
1252
1253 static const SilcConfigTable table_serverinfo[] = {
1254   { "hostname",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1255   { "primary",          SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1256   { "secondary",        SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo_c},
1257   { "servertype",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1258   { "location",         SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1259   { "admin",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1260   { "adminemail",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1261   { "user",             SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1262   { "group",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1263   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1264   { "privatekey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
1265   { "motdfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1266   { "pidfile",          SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
1267   { 0, 0, 0, 0 }
1268 };
1269
1270 static const SilcConfigTable table_logging_c[] = {
1271   { "file",             SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
1272   { "size",             SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
1273 /*{ "quicklog",         SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
1274   { 0, 0, 0, 0 }
1275 };
1276
1277 static const SilcConfigTable table_logging[] = {
1278   { "timestamp",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1279   { "quicklogs",        SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
1280   { "flushdelay",       SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
1281   { "info",             SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1282   { "warnings",         SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1283   { "errors",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1284   { "fatals",           SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
1285   { 0, 0, 0, 0 }
1286 };
1287
1288 static const SilcConfigTable table_connparam[] = {
1289   { "name",                    SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1290   { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1291   { "connections_max",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1292   { "connections_max_per_host",SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1293   { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1294   { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1295   { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1296   { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1297   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1298   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1299   { "key_exchange_pfs",        SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1300   { "version_protocol",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1301   { "version_software",        SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1302   { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
1303   { "anonymous",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1304   { "qos",                     SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
1305   { "qos_rate_limit",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1306   { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1307   { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1308   { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
1309   { 0, 0, 0, 0 }
1310 };
1311
1312 static const SilcConfigTable table_client[] = {
1313   { "host",             SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
1314   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1315   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1316   { "publickeydir",     SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1317   { "params",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
1318   { 0, 0, 0, 0 }
1319 };
1320
1321 static const SilcConfigTable table_admin[] = {
1322   { "host",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1323   { "user",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1324   { "nick",             SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
1325   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1326   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1327   { "port",             SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
1328   { "params",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
1329   { 0, 0, 0, 0 }
1330 };
1331
1332 static const SilcConfigTable table_deny[] = {
1333   { "host",             SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
1334   { "reason",           SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
1335   { 0, 0, 0, 0 }
1336 };
1337
1338 static const SilcConfigTable table_serverconn[] = {
1339   { "host",             SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
1340   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1341   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1342   { "params",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
1343   { "backup",           SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
1344   { 0, 0, 0, 0 }
1345 };
1346
1347 static const SilcConfigTable table_routerconn[] = {
1348   { "host",             SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1349   { "port",             SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1350   { "passphrase",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1351   { "publickey",        SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1352   { "params",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
1353   { "initiator",        SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1354   { "backuphost",       SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
1355   { "backupport",       SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
1356   { "backuplocal",      SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1357   { "dynamic_connection",       SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
1358   { 0, 0, 0, 0 }
1359 };
1360
1361 static const SilcConfigTable table_main[] = {
1362   { "cipher",           SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
1363   { "hash",             SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
1364   { "hmac",             SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
1365   { "pkcs",             SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
1366   { "general",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
1367   { "serverinfo",       SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
1368   { "logging",          SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
1369   { "connectionparams", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
1370   { "client",           SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
1371   { "admin",            SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
1372   { "deny",             SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
1373   { "serverconnection", SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
1374   { "routerconnection", SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
1375   { 0, 0, 0, 0 }
1376 };
1377
1378 /* Set default values to stuff that was not configured. */
1379
1380 static void silc_server_config_set_defaults(SilcServerConfig config)
1381 {
1382   my_set_param_defaults(&config->param, NULL);
1383
1384   config->channel_rekey_secs = (config->channel_rekey_secs ?
1385                                 config->channel_rekey_secs :
1386                                 SILC_SERVER_CHANNEL_REKEY);
1387   config->key_exchange_timeout = (config->key_exchange_timeout ?
1388                                   config->key_exchange_timeout :
1389                                   SILC_SERVER_SKE_TIMEOUT);
1390   config->conn_auth_timeout = (config->conn_auth_timeout ?
1391                                config->conn_auth_timeout :
1392                                SILC_SERVER_CONNAUTH_TIMEOUT);
1393 }
1394
1395 /* Check for correctness of the configuration */
1396
1397 static SilcBool silc_server_config_check(SilcServerConfig config)
1398 {
1399   SilcBool ret = TRUE;
1400   SilcServerConfigServer *s;
1401   SilcServerConfigRouter *r;
1402   SilcBool b = FALSE;
1403
1404   /* ServerConfig is mandatory */
1405   if (!config->server_info) {
1406     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `ServerInfo'"));
1407     ret = FALSE;
1408   }
1409
1410   if (!config->server_info->public_key ||
1411       !config->server_info->private_key) {
1412     SILC_SERVER_LOG_ERROR(("\nError: Server keypair is missing"));
1413     ret = FALSE;
1414   }
1415
1416   if (!config->server_info->primary) {
1417     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `Primary' "
1418                            "in `ServerInfo'"));
1419     ret = FALSE;
1420   }
1421
1422   if (!config->server_info->primary->server_ip) {
1423     SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory field `Ip' "
1424                            "in `Primary' in `ServerInfo'"));
1425     ret = FALSE;
1426   }
1427
1428   /* RouterConnection sanity checks */
1429
1430   if (config->routers && config->routers->backup_router == TRUE &&
1431       !config->servers) {
1432     SILC_SERVER_LOG_ERROR((
1433          "\nError: First RouterConnection block must be primary router "
1434          "connection. You have marked it incorrectly as backup router."));
1435     ret = FALSE;
1436   }
1437   if (config->routers && config->routers->backup_router == TRUE &&
1438       !config->servers && !config->routers->next) {
1439     SILC_SERVER_LOG_ERROR((
1440          "\nError: You have configured backup router but not primary router. "
1441          "If backup router is configured also primary router must be "
1442          "configured."));
1443     ret = FALSE;
1444   }
1445
1446   /* Backup router sanity checks */
1447
1448   for (r = config->routers; r; r = r->next) {
1449     if (r->backup_router && !strcmp(r->host, r->backup_replace_ip)) {
1450       SILC_SERVER_LOG_ERROR((
1451           "\nError: Backup router connection incorrectly configured to use "
1452           "primary and backup router as same host `%s'. They must not be "
1453           "same host.", r->host));
1454       ret = FALSE;
1455     }
1456
1457     if (r->initiator == FALSE && r->port != 0) {
1458       SILC_SERVER_LOG_WARNING(("\nWarning: Initiator is FALSE and Port is "
1459                                "specified. Ignoring Port value."));
1460       r->port = 0;
1461     }
1462   }
1463
1464   /* ServerConnection sanity checks */
1465
1466   for (s = config->servers; s; s = s->next) {
1467     if (s->backup_router) {
1468       b = TRUE;
1469       break;
1470     }
1471   }
1472   if (b) {
1473     for (s = config->servers; s; s = s->next) {
1474       if (!s->backup_router) {
1475         SILC_SERVER_LOG_ERROR((
1476           "\nError: Your server is backup router but not all ServerConnection "
1477           "blocks were marked as backup connections. They all must be "
1478           "marked as backup connections."));
1479         ret = FALSE;
1480         break;
1481       }
1482     }
1483   }
1484
1485   return ret;
1486 }
1487
1488 /* Allocates a new configuration object, opens configuration file and
1489    parses it. The parsed data is returned to the newly allocated
1490    configuration object. The SilcServerConfig must be freed by calling
1491    the silc_server_config_destroy function. */
1492
1493 SilcServerConfig silc_server_config_alloc(const char *filename,
1494                                           SilcServer server)
1495 {
1496   SilcServerConfig config_new;
1497   SilcConfigEntity ent;
1498   SilcConfigFile *file;
1499   int ret;
1500   SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
1501
1502   /* alloc a config object */
1503   config_new = silc_calloc(1, sizeof(*config_new));
1504   if (!config_new)
1505     return NULL;
1506
1507   /* general config defaults */
1508   config_new->refcount = 1;
1509   config_new->logging_timestamp = TRUE;
1510   config_new->param.reconnect_keep_trying = TRUE;
1511   config_new->server = server;
1512
1513   /* obtain a config file object */
1514   file = silc_config_open(filename);
1515   if (!file) {
1516     SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'",
1517                            filename));
1518     return NULL;
1519   }
1520
1521   /* obtain a SilcConfig entity, we can use it to start the parsing */
1522   ent = silc_config_init(file);
1523
1524   /* load the known configuration options, give our empty object as context */
1525   silc_config_register_table(ent, table_main, (void *) config_new);
1526
1527   /* enter the main parsing loop.  When this returns, we have the parsing
1528    * result and the object filled (or partially, in case of errors). */
1529   ret = silc_config_main(ent);
1530   SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret,
1531                   silc_config_strerror(ret)));
1532
1533   /* Check if the parser returned errors */
1534   if (ret) {
1535     /* handle this special error return which asks to quietly return */
1536     if (ret != SILC_CONFIG_ESILENT) {
1537       char *linebuf, *filename = silc_config_get_filename(file);
1538       SilcUInt32 line = silc_config_get_line(file);
1539       if (ret != SILC_CONFIG_EPRINTLINE)
1540         SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.",
1541                                silc_config_strerror(ret)));
1542       linebuf = silc_config_read_line(file, line);
1543       if (linebuf) {
1544         SILC_SERVER_LOG_ERROR(("  file %s line %lu:  %s\n", filename,
1545                                line, linebuf));
1546         silc_free(linebuf);
1547       }
1548     }
1549     silc_server_config_destroy(config_new);
1550     silc_config_close(file);
1551     return NULL;
1552   }
1553
1554   /* close (destroy) the file object */
1555   silc_config_close(file);
1556
1557   /* Check the configuration */
1558   if (!silc_server_config_check(config_new)) {
1559     silc_server_config_destroy(config_new);
1560     return NULL;
1561   }
1562
1563   /* Set default to configuration parameters */
1564   silc_server_config_set_defaults(config_new);
1565
1566   return config_new;
1567 }
1568
1569 /* Increments the reference counter of a config object */
1570
1571 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
1572                             void *ref_ptr)
1573 {
1574   if (ref_ptr) {
1575     config->refcount++;
1576     ref->config = config;
1577     ref->ref_ptr = ref_ptr;
1578     SILC_LOG_DEBUG(("Referencing config [%p] refcnt %d->%d", config,
1579                     config->refcount - 1, config->refcount));
1580   }
1581 }
1582
1583 /* Decrements the reference counter of a config object.  If the counter
1584    reaches 0, the config object is destroyed. */
1585
1586 void silc_server_config_unref(SilcServerConfigRef *ref)
1587 {
1588   if (ref->ref_ptr)
1589     silc_server_config_destroy(ref->config);
1590 }
1591
1592 /* Destroy a config object with all his children lists */
1593
1594 void silc_server_config_destroy(SilcServerConfig config)
1595 {
1596   void *tmp;
1597
1598   config->refcount--;
1599   SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %d->%d", config,
1600                   config->refcount + 1, config->refcount));
1601   if (config->refcount > 0)
1602     return;
1603
1604   SILC_LOG_DEBUG(("Freeing config context"));
1605
1606   /* Destroy general config stuff */
1607   silc_free(config->debug_string);
1608   silc_free(config->param.version_protocol);
1609   silc_free(config->param.version_software);
1610   silc_free(config->param.version_software_vendor);
1611   silc_free(config->httpd_ip);
1612
1613   /* Destroy Logging channels */
1614   if (config->logging_info)
1615     silc_free(config->logging_info->file);
1616   if (config->logging_warnings)
1617     silc_free(config->logging_warnings->file);
1618   if (config->logging_errors)
1619     silc_free(config->logging_errors->file);
1620   if (config->logging_fatals)
1621     silc_free(config->logging_fatals->file);
1622   silc_free(config->logging_info);
1623   silc_free(config->logging_warnings);
1624   silc_free(config->logging_errors);
1625   silc_free(config->logging_fatals);
1626
1627   /* Destroy the ServerInfo struct */
1628   if (config->server_info) {
1629     register SilcServerConfigServerInfo *si = config->server_info;
1630     silc_free(si->server_name);
1631     if (si->primary) {
1632       silc_free(si->primary->server_ip);
1633       silc_free(si->primary);
1634     }
1635     SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServerInfoInterface,
1636                                   si->secondary)
1637       silc_free(di->server_ip);
1638       silc_free(di);
1639     }
1640     silc_free(si->server_type);
1641     silc_free(si->location);
1642     silc_free(si->admin);
1643     silc_free(si->email);
1644     silc_free(si->user);
1645     silc_free(si->group);
1646     silc_free(si->motd_file);
1647     silc_free(si->pid_file);
1648     if (si->public_key)
1649       silc_pkcs_public_key_free(si->public_key);
1650     if (si->private_key)
1651       silc_pkcs_private_key_free(si->private_key);
1652     silc_free(si);
1653   }
1654
1655   /* Now let's destroy the lists */
1656
1657   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigCipher,
1658                                   config->cipher)
1659     silc_free(di->name);
1660     silc_free(di);
1661   }
1662   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHash, config->hash)
1663     silc_free(di->name);
1664     silc_free(di);
1665   }
1666   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigHmac, config->hmac)
1667     silc_free(di->name);
1668     silc_free(di->hash);
1669     silc_free(di);
1670   }
1671   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigPkcs, config->pkcs)
1672     silc_free(di->name);
1673     silc_free(di);
1674   }
1675   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigConnParams,
1676                                   config->conn_params)
1677     silc_free(di->name);
1678     silc_free(di->version_protocol);
1679     silc_free(di->version_software);
1680     silc_free(di->version_software_vendor);
1681     silc_free(di);
1682   }
1683   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigClient, config->clients)
1684     silc_free(di->host);
1685     CONFIG_FREE_AUTH(di);
1686     silc_free(di);
1687   }
1688   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigAdmin, config->admins)
1689     silc_free(di->host);
1690     silc_free(di->user);
1691     silc_free(di->nick);
1692     CONFIG_FREE_AUTH(di);
1693     silc_free(di);
1694   }
1695   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigDeny, config->denied)
1696     silc_free(di->host);
1697     silc_free(di->reason);
1698     silc_free(di);
1699   }
1700   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigServer,
1701                                   config->servers)
1702     silc_free(di->host);
1703     CONFIG_FREE_AUTH(di);
1704     silc_free(di);
1705   }
1706   SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigRouter,
1707                                   config->routers)
1708     silc_free(di->host);
1709     silc_free(di->backup_replace_ip);
1710     CONFIG_FREE_AUTH(di);
1711     silc_free(di);
1712   }
1713
1714   memset(config, 'F', sizeof(*config));
1715   silc_free(config);
1716 }
1717
1718 /* Registers configured ciphers. These can then be allocated by the
1719    server when needed. */
1720
1721 SilcBool silc_server_config_register_ciphers(SilcServer server)
1722 {
1723   SilcServerConfig config = server->config;
1724   SilcServerConfigCipher *cipher = config->cipher;
1725   char *module_path = config->module_path;
1726
1727   SILC_LOG_DEBUG(("Registering configured ciphers"));
1728
1729   if (!cipher) /* any cipher in the config file? */
1730     return FALSE;
1731
1732   while (cipher) {
1733     /* if there isn't a module_path OR there isn't a module sim name try to
1734      * use buil-in functions */
1735     if (!module_path || !cipher->module) {
1736       int i;
1737       for (i = 0; silc_default_ciphers[i].name; i++)
1738         if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
1739           silc_cipher_register((SilcCipherObject *)&silc_default_ciphers[i]);
1740           break;
1741         }
1742       if (!silc_cipher_is_supported(cipher->name)) {
1743         SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
1744         silc_server_stop(server);
1745         exit(1);
1746       }
1747     }
1748     cipher = cipher->next;
1749   } /* while */
1750
1751   return TRUE;
1752 }
1753
1754 /* Registers configured hash functions. These can then be allocated by the
1755    server when needed. */
1756
1757 SilcBool silc_server_config_register_hashfuncs(SilcServer server)
1758 {
1759   SilcServerConfig config = server->config;
1760   SilcServerConfigHash *hash = config->hash;
1761   char *module_path = config->module_path;
1762
1763   SILC_LOG_DEBUG(("Registering configured hash functions"));
1764
1765   if (!hash) /* any hash func in the config file? */
1766     return FALSE;
1767
1768   while (hash) {
1769     /* if there isn't a module_path OR there isn't a module sim name try to
1770      * use buil-in functions */
1771     if (!module_path || !hash->module) {
1772       int i;
1773       for (i = 0; silc_default_hash[i].name; i++)
1774         if (!strcmp(silc_default_hash[i].name, hash->name)) {
1775           silc_hash_register((SilcHashObject *)&silc_default_hash[i]);
1776           break;
1777         }
1778       if (!silc_hash_is_supported(hash->name)) {
1779         SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
1780         silc_server_stop(server);
1781         exit(1);
1782       }
1783     }
1784     hash = hash->next;
1785   } /* while */
1786
1787   return TRUE;
1788 }
1789
1790 /* Registers configure HMACs. These can then be allocated by the server
1791    when needed. */
1792
1793 SilcBool silc_server_config_register_hmacs(SilcServer server)
1794 {
1795   SilcServerConfig config = server->config;
1796   SilcServerConfigHmac *hmac = config->hmac;
1797
1798   SILC_LOG_DEBUG(("Registering configured HMACs"));
1799
1800   if (!hmac)
1801     return FALSE;
1802
1803   while (hmac) {
1804     SilcHmacObject hmac_obj;
1805     if (!silc_hash_is_supported(hmac->hash)) {
1806       SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
1807       silc_server_stop(server);
1808       exit(1);
1809     }
1810
1811     /* Register the HMAC */
1812     memset(&hmac_obj, 0, sizeof(hmac_obj));
1813     hmac_obj.name = hmac->name;
1814     hmac_obj.len = hmac->mac_length;
1815     silc_hmac_register(&hmac_obj);
1816
1817     hmac = hmac->next;
1818   } /* while */
1819
1820   return TRUE;
1821 }
1822
1823 /* Registers configured PKCS's. */
1824
1825 SilcBool silc_server_config_register_pkcs(SilcServer server)
1826 {
1827   return FALSE;
1828 }
1829
1830 /* Sets log files where log messages are saved by the server logger. */
1831
1832 void silc_server_config_setlogfiles(SilcServer server)
1833 {
1834   SilcServerConfig config = server->config;
1835   SilcServerConfigLogging *this;
1836
1837   SILC_LOG_DEBUG(("Setting configured log file names and options"));
1838
1839   silc_log_timestamp(config->logging_timestamp);
1840   silc_log_quick(config->logging_quick);
1841   silc_log_flushdelay(config->logging_flushdelay ?
1842                       config->logging_flushdelay :
1843                       SILC_SERVER_LOG_FLUSH_DELAY);
1844
1845   if ((this = config->logging_fatals))
1846     silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,
1847                       server->schedule);
1848   if ((this = config->logging_errors))
1849     silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize,
1850                       server->schedule);
1851   if ((this = config->logging_warnings))
1852     silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize,
1853                       server->schedule);
1854   if ((this = config->logging_info))
1855     silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize,
1856                       server->schedule);
1857 }
1858
1859 /* Returns client authentication information from configuration file by host
1860    (name or ip) */
1861
1862 SilcServerConfigClient *
1863 silc_server_config_find_client(SilcServer server, char *host)
1864 {
1865   SilcServerConfig config = server->config;
1866   SilcServerConfigClient *client;
1867
1868   if (!config || !host)
1869     return NULL;
1870
1871   for (client = config->clients; client; client = client->next) {
1872     if (client->host && !silc_string_compare(client->host, host))
1873       continue;
1874     break;
1875   }
1876
1877   /* if none matched, then client is already NULL */
1878   return client;
1879 }
1880
1881 /* Returns admin connection configuration by host, username and/or
1882    nickname. */
1883
1884 SilcServerConfigAdmin *
1885 silc_server_config_find_admin(SilcServer server, char *host, char *user,
1886                               char *nick)
1887 {
1888   SilcServerConfig config = server->config;
1889   SilcServerConfigAdmin *admin;
1890
1891   /* make sure we have a value for the matching parameters */
1892   if (!host)
1893     host = "*";
1894   if (!user)
1895     user = "*";
1896   if (!nick)
1897     nick = "*";
1898
1899   for (admin = config->admins; admin; admin = admin->next) {
1900     if (admin->host && !silc_string_compare(admin->host, host))
1901       continue;
1902     if (admin->user && !silc_string_compare(admin->user, user))
1903       continue;
1904     if (admin->nick && !silc_string_compare(admin->nick, nick))
1905       continue;
1906     /* no checks failed -> this entry matches */
1907     break;
1908   }
1909
1910   /* if none matched, then admin is already NULL */
1911   return admin;
1912 }
1913
1914 /* Returns the denied connection configuration entry by host. */
1915
1916 SilcServerConfigDeny *
1917 silc_server_config_find_denied(SilcServer server, char *host)
1918 {
1919   SilcServerConfig config = server->config;
1920   SilcServerConfigDeny *deny;
1921
1922   /* make sure we have a value for the matching parameters */
1923   if (!config || !host)
1924     return NULL;
1925
1926   for (deny = config->denied; deny; deny = deny->next) {
1927     if (deny->host && !silc_string_compare(deny->host, host))
1928       continue;
1929     break;
1930   }
1931
1932   /* if none matched, then deny is already NULL */
1933   return deny;
1934 }
1935
1936 /* Returns server connection info from server configuartion by host
1937    (name or ip). */
1938
1939 SilcServerConfigServer *
1940 silc_server_config_find_server_conn(SilcServer server, char *host)
1941 {
1942   SilcServerConfig config = server->config;
1943   SilcServerConfigServer *serv = NULL;
1944
1945   if (!host)
1946     return NULL;
1947
1948   if (!config->servers)
1949     return NULL;
1950
1951   for (serv = config->servers; serv; serv = serv->next) {
1952     if (!silc_string_compare(serv->host, host))
1953       continue;
1954     break;
1955   }
1956
1957   return serv;
1958 }
1959
1960 /* Returns router connection info from server configuration by
1961    host (name or ip). */
1962
1963 SilcServerConfigRouter *
1964 silc_server_config_find_router_conn(SilcServer server, char *host, int port)
1965 {
1966   SilcServerConfig config = server->config;
1967   SilcServerConfigRouter *serv = NULL;
1968
1969   if (!host)
1970     return NULL;
1971
1972   if (!config->routers)
1973     return NULL;
1974
1975   for (serv = config->routers; serv; serv = serv->next) {
1976     if (!silc_string_compare(serv->host, host))
1977       continue;
1978     if (port && serv->port && serv->port != port)
1979       continue;
1980     break;
1981   }
1982
1983   return serv;
1984 }
1985
1986 /* Find backup router connection by host (name or ip) */
1987
1988 SilcServerConfigRouter *
1989 silc_server_config_find_backup_conn(SilcServer server, char *host)
1990 {
1991   SilcServerConfig config = server->config;
1992   SilcServerConfigRouter *serv = NULL;
1993
1994   if (!host)
1995     return NULL;
1996
1997   if (!config->routers)
1998     return NULL;
1999
2000   for (serv = config->routers; serv; serv = serv->next) {
2001     if (!serv->backup_router)
2002       continue;
2003     if (!silc_string_compare(serv->host, host))
2004       continue;
2005     break;
2006   }
2007
2008   return serv;
2009 }
2010
2011 /* Returns TRUE if configuration for a router connection that we are
2012    initiating exists. */
2013
2014 SilcBool silc_server_config_is_primary_route(SilcServer server)
2015 {
2016   SilcServerConfig config = server->config;
2017   SilcServerConfigRouter *serv = NULL;
2018   int i;
2019   SilcBool found = FALSE;
2020
2021   serv = config->routers;
2022   for (i = 0; serv; i++) {
2023     if (serv->initiator == TRUE && serv->backup_router == FALSE) {
2024       found = TRUE;
2025       break;
2026     }
2027
2028     serv = serv->next;
2029   }
2030
2031   return found;
2032 }
2033
2034 /* Returns our primary connection configuration or NULL if we do not
2035    have primary router configured. */
2036
2037 SilcServerConfigRouter *
2038 silc_server_config_get_primary_router(SilcServer server)
2039 {
2040   SilcServerConfig config = server->config;
2041   SilcServerConfigRouter *serv = NULL;
2042   int i;
2043
2044   serv = config->routers;
2045   for (i = 0; serv; i++) {
2046     if (serv->initiator == TRUE && serv->backup_router == FALSE)
2047       return serv;
2048     serv = serv->next;
2049   }
2050
2051   return NULL;
2052 }
2053
2054 /* If we have backup router configured that is going to replace us this
2055    function returns it. */
2056
2057 SilcServerConfigRouter *
2058 silc_server_config_get_backup_router(SilcServer server)
2059 {
2060   SilcServerConfig config = server->config;
2061   SilcServerConfigRouter *serv = NULL;
2062   int i;
2063
2064   if (server->server_type != SILC_ROUTER)
2065     return NULL;
2066
2067   serv = config->routers;
2068   for (i = 0; serv; i++) {
2069     if (serv->initiator == FALSE && serv->backup_router == TRUE &&
2070         serv->backup_local == TRUE &&
2071         !strcmp(server->config->server_info->primary->server_ip,
2072                 serv->backup_replace_ip) &&
2073         server->config->server_info->primary->port ==
2074         serv->backup_replace_port)
2075       return serv;
2076     serv = serv->next;
2077   }
2078
2079   return NULL;
2080 }