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