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