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