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