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