updates.
[silc.git] / apps / silcd / serverconfig.c
1 /*
2
3   serverconfig.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "serverincludes.h"
23 #include "server_internal.h"
24
25 SilcServerConfigSection silc_server_config_sections[] = {
26   { "[Cipher]", 
27     SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
28   { "[PKCS]", 
29     SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 2 },
30   { "[Hash]", 
31     SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
32   { "[hmac]", 
33     SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, 3 },
34   { "[ServerInfo]", 
35     SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
36   { "[AdminInfo]", 
37     SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
38   { "[ListenPort]", 
39     SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
40   { "[Identity]", 
41     SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 },
42   { "[Logging]", 
43     SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
44   { "[ConnectionClass]", 
45     SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
46   { "[ClientConnection]", 
47     SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
48   { "[ServerConnection]", 
49     SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
50   { "[RouterConnection]", 
51     SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 7 },
52   { "[AdminConnection]", 
53     SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
54   { "[DenyConnection]", 
55     SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
56   { "[RedirectClient]", 
57     SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
58   { "[motd]", 
59     SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 },
60   
61   { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
62 };
63
64 /* Allocates a new configuration object, opens configuration file and
65    parses the file. The parsed data is returned to the newly allocated
66    configuration object. */
67
68 SilcServerConfig silc_server_config_alloc(char *filename)
69 {
70   SilcServerConfig new;
71   SilcBuffer buffer;
72   SilcServerConfigParse config_parse;
73
74   SILC_LOG_DEBUG(("Allocating new configuration object"));
75
76   new = silc_calloc(1, sizeof(*new));
77   if (!new) {
78     fprintf(stderr, "Could not allocate new configuration object");
79     return NULL;
80   }
81
82   new->filename = filename;
83
84   /* Open configuration file and parse it */
85   config_parse = NULL;
86   buffer = NULL;
87   silc_config_open(filename, &buffer);
88   if (!buffer)
89     goto fail;
90   if ((silc_server_config_parse(new, buffer, &config_parse)) == FALSE)
91     goto fail;
92   if ((silc_server_config_parse_lines(new, config_parse)) == FALSE)
93     goto fail;
94
95   silc_free(buffer);
96
97   return new;
98
99  fail:
100   silc_free(new);
101   return NULL;
102 }
103
104 /* Free's a configuration object. */
105
106 void silc_server_config_free(SilcServerConfig config)
107 {
108   if (config) {
109     silc_free(config->filename);
110     silc_free(config->server_info);
111     silc_free(config->admin_info);
112     silc_free(config->listen_port);
113     silc_free(config->identity);
114     silc_free(config->conn_class);
115     silc_free(config->clients);
116     silc_free(config->admins);
117     silc_free(config->servers);
118     silc_free(config->routers);
119     silc_free(config->denied);
120     silc_free(config->redirect);
121     silc_free(config->motd);
122     silc_free(config);
123   }
124 }
125
126 /* Parses the the buffer and returns the parsed lines into return_config
127    argument. The return_config argument doesn't have to be initialized 
128    before calling this. It will be initialized during the parsing. The
129    buffer sent as argument can be safely free'd after this function has
130    succesfully returned. */
131
132 int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, 
133                              SilcServerConfigParse *return_config)
134 {
135   int i, begin;
136   unsigned int linenum;
137   char line[1024], *cp;
138   SilcServerConfigSection *cptr = NULL;
139   SilcServerConfigParse parse = *return_config, first = NULL;
140
141   SILC_LOG_DEBUG(("Parsing configuration file"));
142
143   begin = 0;
144   linenum = 0;
145   while((begin = silc_gets(line, sizeof(line), 
146                            buffer->data, buffer->len, begin)) != EOF) {
147     cp = line;
148     linenum++;
149
150     /* Check for bad line */
151     if (silc_check_line(cp))
152       continue;
153
154     /* Remove tabs and whitespaces from the line */
155     if (strchr(cp, '\t')) {
156       i = 0;
157       while(strchr(cp + i, '\t')) {
158         *strchr(cp + i, '\t') = ' ';
159         i++;
160       }
161     }
162     for (i = 0; i < strlen(cp); i++) {
163       if (cp[i] != ' ') {
164         if (i)
165           cp++;
166         break;
167       }
168       cp++;
169     }
170
171     /* Parse line */
172     switch(cp[0]) {
173     case '[':
174       /*
175        * Start of a section
176        */
177
178       /* Remove new line sign */
179       if (strchr(cp, '\n'))
180         *strchr(cp, '\n') = '\0';
181       
182       /* Check for matching sections */
183       for (cptr = silc_server_config_sections; cptr->section; cptr++)
184         if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
185           break;
186
187       if (!cptr->section) {
188         fprintf(stderr, "%s:%d: Unknown section `%s'\n", 
189                         config->filename, linenum, cp);
190         return FALSE;
191       }
192
193       break;
194     default:
195       /*
196        * Start of a configuration line
197        */
198
199       if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
200         
201         if (strchr(cp, '\n'))
202             *strchr(cp, '\n') = ':';
203
204         if (parse == NULL) {
205           parse = silc_calloc(1, sizeof(*parse));
206           parse->line = NULL;
207           parse->section = NULL;
208           parse->next = NULL;
209           parse->prev = NULL;
210         } else {
211           if (parse->next == NULL) {
212             parse->next = silc_calloc(1, sizeof(*parse->next));
213             parse->next->line = NULL;
214             parse->next->section = NULL;
215             parse->next->next = NULL;
216             parse->next->prev = parse;
217             parse = parse->next;
218           }
219         }
220         
221         if (first == NULL)
222           first = parse;
223
224         /* Add the line to parsing structure for further parsing. */
225         if (parse) {
226           parse->section = cptr;
227           parse->line = silc_buffer_alloc(strlen(cp) + 1);
228           parse->linenum = linenum;
229           silc_buffer_pull_tail(parse->line, strlen(cp));
230           silc_buffer_put(parse->line, cp, strlen(cp));
231         }
232       }
233       break;
234     }
235   }
236   
237   /* Set the return_config argument to its first value so that further
238      parsing can be started from the first line. */
239   *return_config = first;
240
241   return TRUE;
242 }
243
244 /* Parses the lines earlier read from configuration file. The config object
245    must not be initialized, it will be initialized in this function. The
246    parse_config argument is uninitialized automatically during this
247    function. */
248
249 int silc_server_config_parse_lines(SilcServerConfig config, 
250                                    SilcServerConfigParse parse_config)
251 {
252   int ret, check = FALSE;
253   unsigned int checkmask;
254   char *tmp;
255   SilcServerConfigParse pc = parse_config;
256   SilcBuffer line;
257
258   SILC_LOG_DEBUG(("Parsing configuration lines"));
259   
260   if (!config)
261     return FALSE;
262   
263   checkmask = 0;
264   while(pc) {
265     check = FALSE;
266     line = pc->line;
267
268     /* Get number of tokens in line */
269     ret = silc_config_check_num_token(line);
270     if (ret != pc->section->maxfields) {
271       /* Bad line */
272       fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
273               config->filename, pc->linenum, ret, 
274               pc->section->maxfields);
275       break;
276     }
277
278     /* Parse the line */
279     switch(pc->section->type) {
280     case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
281
282       SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
283
284       /* Get cipher name */
285       ret = silc_config_get_token(line, &config->cipher->alg_name);
286       if (ret < 0)
287         break;
288       if (ret == 0) {
289         fprintf(stderr, "%s:%d: Cipher name not defined\n",
290                 config->filename, pc->linenum);
291         break;
292       }
293
294       /* Get module name */
295       config->cipher->sim_name = NULL;
296       ret = silc_config_get_token(line, &config->cipher->sim_name);
297       if (ret < 0)
298         break;
299
300       /* Get key length */
301       ret = silc_config_get_token(line, &tmp);
302       if (ret < 0)
303         break;
304       if (ret == 0) {
305         fprintf(stderr, "%s:%d: Cipher key length not defined\n",
306                 config->filename, pc->linenum);
307         break;
308       }
309       config->cipher->key_len = atoi(tmp);
310       silc_free(tmp);
311
312       /* Get block length */
313       ret = silc_config_get_token(line, &tmp);
314       if (ret < 0)
315         break;
316       if (ret == 0) {
317         fprintf(stderr, "%s:%d: Cipher block length not defined\n",
318                 config->filename, pc->linenum);
319         break;
320       }
321       config->cipher->block_len = atoi(tmp);
322       silc_free(tmp);
323
324       check = TRUE;
325       checkmask |= (1L << pc->section->type);
326       break;
327
328     case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
329
330       SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
331
332       /* Get PKCS name */
333       ret = silc_config_get_token(line, &config->pkcs->alg_name);
334       if (ret < 0)
335         break;
336       if (ret == 0) {
337         fprintf(stderr, "%s:%d: PKCS name not defined\n",
338                 config->filename, pc->linenum);
339         break;
340       }
341
342       /* Get key length */
343       ret = silc_config_get_token(line, &tmp);
344       if (ret < 0)
345         break;
346       if (ret == 0) {
347         fprintf(stderr, "%s:%d: PKCS key length not defined\n",
348                 config->filename, pc->linenum);
349         break;
350       }
351       config->pkcs->key_len = atoi(tmp);
352       silc_free(tmp);
353
354       check = TRUE;
355       checkmask |= (1L << pc->section->type);
356       break;
357
358     case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
359
360       SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
361
362       /* Get Hash function name */
363       ret = silc_config_get_token(line, &config->hash_func->alg_name);
364       if (ret < 0)
365         break;
366       if (ret == 0) {
367         fprintf(stderr, "%s:%d: Hash function name not defined\n",
368                 config->filename, pc->linenum);
369         break;
370       }
371       
372       /* Get Hash function module name */
373       config->hash_func->sim_name = NULL;
374       ret = silc_config_get_token(line, &config->hash_func->sim_name);
375       if (ret < 0)
376         break;
377
378       /* Get block length */
379       ret = silc_config_get_token(line, &tmp);
380       if (ret < 0)
381         break;
382       if (ret == 0) {
383         fprintf(stderr, "%s:%d: Hash function block length not defined\n",
384                 config->filename, pc->linenum);
385         break;
386       }
387       config->hash_func->block_len = atoi(tmp);
388       silc_free(tmp);
389
390       /* Get hash length */
391       ret = silc_config_get_token(line, &tmp);
392       if (ret < 0)
393         break;
394       if (ret == 0) {
395         fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
396                 config->filename, pc->linenum);
397         break;
398       }
399       config->hash_func->key_len = atoi(tmp);
400       silc_free(tmp);
401
402       check = TRUE;
403       checkmask |= (1L << pc->section->type);
404       break;
405
406     case SILC_CONFIG_SERVER_SECTION_TYPE_HMAC:
407
408       SILC_SERVER_CONFIG_LIST_ALLOC(config->hmac);
409
410       /* Get HMAC name */
411       ret = silc_config_get_token(line, &config->hmac->alg_name);
412       if (ret < 0)
413         break;
414       if (ret == 0) {
415         fprintf(stderr, "%s:%d: HMAC name not defined\n",
416                 config->filename, pc->linenum);
417         break;
418       }
419
420       /* Get hash name */
421       ret = silc_config_get_token(line, &config->hmac->sim_name);
422       if (ret < 0)
423         break;
424       if (ret == 0) {
425         fprintf(stderr, "%s:%d: Hash function name not defined\n",
426                 config->filename, pc->linenum);
427         break;
428       }
429       
430       /* Get MAC length */
431       ret = silc_config_get_token(line, &tmp);
432       if (ret < 0)
433         break;
434       if (ret == 0) {
435         fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
436                 config->filename, pc->linenum);
437         break;
438       }
439       config->hmac->key_len = atoi(tmp);
440       silc_free(tmp);
441
442       check = TRUE;
443       checkmask |= (1L << pc->section->type);
444       break;
445
446     case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
447
448       if (!config->server_info)
449         config->server_info = silc_calloc(1, sizeof(*config->server_info));
450
451       /* Get server name */
452       ret = silc_config_get_token(line, &config->server_info->server_name);
453       if (ret < 0)
454         break;
455       if (ret == 0) {
456         /* Server name not defined */
457
458       }
459       
460       /* Get server IP */
461       ret = silc_config_get_token(line, &config->server_info->server_ip);
462       if (ret < 0)
463         break;
464       if (ret == 0) {
465         /* Server IP not defined */
466
467       }
468
469       /* Get server location */
470       ret = silc_config_get_token(line, &config->server_info->location);
471       if (ret < 0)
472         break;
473
474       /* Get server port */
475       /* XXX: Need port here??? */
476       ret = silc_config_get_token(line, &tmp);
477       if (ret < 0)
478         break;
479       if (ret == 0) {
480         /* Port not defined */
481
482       }
483       config->server_info->port = atoi(tmp);
484       silc_free(tmp);
485
486       check = TRUE;
487       checkmask |= (1L << pc->section->type);
488       break;
489
490     case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
491
492       if (!config->admin_info)
493         config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
494
495       /* Get location */
496       ret = silc_config_get_token(line, &config->admin_info->location);
497       if (ret < 0)
498         break;
499
500       /* Get server type */
501       ret = silc_config_get_token(line, &config->admin_info->server_type);
502       if (ret < 0)
503         break;
504
505       /* Get admins name */
506       ret = silc_config_get_token(line, &config->admin_info->admin_name);
507       if (ret < 0)
508         break;
509
510       /* Get admins email address */
511       ret = silc_config_get_token(line, &config->admin_info->admin_email);
512       if (ret < 0)
513         break;
514
515       check = TRUE;
516       checkmask |= (1L << pc->section->type);
517       break;
518
519     case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
520
521       SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
522
523       /* Get host */
524       ret = silc_config_get_token(line, &config->listen_port->host);
525       if (ret < 0)
526         break;
527
528       /* Get remote IP */
529       ret = silc_config_get_token(line, &config->listen_port->remote_ip);
530       if (ret < 0)
531         break;
532
533       /* Get port */
534       ret = silc_config_get_token(line, &tmp);
535       if (ret < 0)
536         break;
537       if (ret == 0) {
538         /* Any port */
539         config->listen_port->port = 0;
540       } else {
541         config->listen_port->port = atoi(tmp);
542         silc_free(tmp);
543       }
544
545       check = TRUE;
546       checkmask |= (1L << pc->section->type);
547       break;
548
549     case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY:
550
551       if (!config->identity)
552         config->identity = silc_calloc(1, sizeof(*config->identity));
553
554       /* Get user */
555       ret = silc_config_get_token(line, &config->identity->user);
556       if (ret < 0)
557         break;
558       /* Get group */
559       ret = silc_config_get_token(line, &config->identity->group);
560       if (ret < 0)
561         break;
562
563       check = TRUE;
564       checkmask |= (1L << pc->section->type);
565
566     case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
567
568       SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
569
570       /* Get class number */
571       ret = silc_config_get_token(line, &tmp);
572       if (ret < 0)
573         break;
574       if (ret == 0) {
575         /* Class number not defined */
576
577       }
578       config->conn_class->class = atoi(tmp);
579       silc_free(tmp);
580
581       /* Get ping frequency */
582       ret = silc_config_get_token(line, &tmp);
583       if (ret < 0)
584         break;
585       config->conn_class->ping_freq = atoi(tmp);
586       silc_free(tmp);
587
588       /* Get connect frequency */
589       ret = silc_config_get_token(line, &tmp);
590       if (ret < 0)
591         break;
592       config->conn_class->connect_freq = atoi(tmp);
593       silc_free(tmp);
594
595       /* Get max links */
596       ret = silc_config_get_token(line, &tmp);
597       if (ret < 0)
598         break;
599       config->conn_class->max_links = atoi(tmp);
600       silc_free(tmp);
601
602       check = TRUE;
603       checkmask |= (1L << pc->section->type);
604       break;
605
606     case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
607
608       SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
609
610       /* Get log section type and check it */
611       ret = silc_config_get_token(line, &config->logging->logtype);
612       if (ret < 0)
613         break;
614       if (ret == 0) {
615         fprintf(stderr, "%s:%d: Log file section not defined\n", 
616                 config->filename, pc->linenum);
617         break;
618       }
619       if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
620           && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
621           && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
622           && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
623         fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
624                 config->filename, pc->linenum, config->logging->logtype);
625         break;
626       }
627
628       /* Get log filename */
629       ret = silc_config_get_token(line, &config->logging->filename);
630       if (ret < 0)
631         break;
632       if (ret == 0) {
633         fprintf(stderr, "%s:%d: Log file name not defined\n",
634                 config->filename, pc->linenum);
635         break;
636       }
637
638       /* Get max byte size */
639       ret = silc_config_get_token(line, &tmp);
640       if (ret < 0)
641         break;
642       if (ret) {
643         config->logging->maxsize = atoi(tmp);
644         silc_free(tmp);
645       }
646
647       check = TRUE;
648       checkmask |= (1L << pc->section->type);
649       break;
650
651     case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
652
653       SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
654
655       /* Get host */
656       ret = silc_config_get_token(line, &config->clients->host);
657       if (ret < 0)
658         break;
659       if (ret == 0)
660         /* Any host */
661         config->clients->host = strdup("*");
662
663       /* Get authentication method */
664       ret = silc_config_get_token(line, &tmp);
665       if (ret < 0)
666         break;
667       if (ret) {
668         if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
669             strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
670           fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
671                   config->filename, pc->linenum, tmp);
672           break;
673         }
674
675         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
676           config->clients->auth_meth = SILC_AUTH_PASSWORD;
677
678         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
679           config->clients->auth_meth = SILC_AUTH_PUBLIC_KEY;
680
681         silc_free(tmp);
682       }
683
684       /* Get authentication data */
685       ret = silc_config_get_token(line, &config->clients->auth_data);
686       if (ret < 0)
687         break;
688       if (ret == 0)
689         /* Any host */
690         config->clients->host = strdup("*");
691
692       /* Get port */
693       ret = silc_config_get_token(line, &tmp);
694       if (ret < 0)
695         break;
696       if (ret == 0) {
697         config->clients->port = atoi(tmp);
698         silc_free(tmp);
699       }
700
701       /* Get class number */
702       ret = silc_config_get_token(line, &tmp);
703       if (ret < 0)
704         break;
705       if (ret) {
706         config->clients->class = atoi(tmp);
707         silc_free(tmp);
708       }
709
710       check = TRUE;
711       checkmask |= (1L << pc->section->type);
712       break;
713
714     case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
715
716       SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
717
718       /* Get host */
719       ret = silc_config_get_token(line, &config->servers->host);
720       if (ret < 0)
721         break;
722       if (ret == 0)
723         /* Any host */
724         config->servers->host = strdup("*");
725
726       /* Get authentication method */
727       ret = silc_config_get_token(line, &tmp);
728       if (ret < 0)
729         break;
730       if (ret) {
731         if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
732             strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
733           fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
734                   config->filename, pc->linenum, tmp);
735           break;
736         }
737
738         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
739           config->servers->auth_meth = SILC_AUTH_PASSWORD;
740
741         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
742           config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY;
743
744         silc_free(tmp);
745       }
746
747       /* Get authentication data */
748       ret = silc_config_get_token(line, &config->servers->auth_data);
749       if (ret < 0)
750         break;
751
752       /* Get port */
753       ret = silc_config_get_token(line, &tmp);
754       if (ret < 0)
755         break;
756       if (ret) {
757         config->servers->port = atoi(tmp);
758         silc_free(tmp);
759       }
760
761       /* Get version */
762       ret = silc_config_get_token(line, &config->servers->version);
763       if (ret < 0)
764         break;
765
766       /* Get class number */
767       ret = silc_config_get_token(line, &tmp);
768       if (ret < 0)
769         break;
770       if (ret) {
771         config->servers->class = atoi(tmp);
772         silc_free(tmp);
773       }
774
775       check = TRUE;
776       checkmask |= (1L << pc->section->type);
777       break;
778
779     case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
780
781       SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
782
783       /* Get host */
784       ret = silc_config_get_token(line, &config->routers->host);
785       if (ret < 0)
786         break;
787       //      if (ret == 0)
788       ///* Any host */
789       //        config->routers->host = strdup("*");
790
791       /* Get authentication method */
792       ret = silc_config_get_token(line, &tmp);
793       if (ret < 0)
794         break;
795       if (ret) {
796         if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
797             strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
798           fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
799                   config->filename, pc->linenum, tmp);
800           break;
801         }
802
803         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
804           config->routers->auth_meth = SILC_AUTH_PASSWORD;
805
806         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
807           config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY;
808
809         silc_free(tmp);
810       }
811
812       /* Get authentication data */
813       ret = silc_config_get_token(line, &config->routers->auth_data);
814       if (ret < 0)
815         break;
816
817       /* Get port */
818       ret = silc_config_get_token(line, &tmp);
819       if (ret < 0)
820         break;
821       if (ret) {
822         config->routers->port = atoi(tmp);
823         silc_free(tmp);
824       }
825
826       /* Get version */
827       ret = silc_config_get_token(line, &config->routers->version);
828       if (ret < 0)
829         break;
830
831       /* Get class number */
832       ret = silc_config_get_token(line, &tmp);
833       if (ret < 0)
834         break;
835       if (ret) {
836         config->routers->class = atoi(tmp);
837         silc_free(tmp);
838       }
839
840       /* Get whether we are initiator or not */
841       ret = silc_config_get_token(line, &tmp);
842       if (ret < 0)
843         break;
844       if (ret) {
845         config->routers->initiator = atoi(tmp);
846         if (config->routers->initiator != 0)
847           config->routers->initiator = TRUE;
848         silc_free(tmp);
849       }
850
851       check = TRUE;
852       checkmask |= (1L << pc->section->type);
853       break;
854
855     case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
856
857       SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
858
859       /* Get host */
860       ret = silc_config_get_token(line, &config->admins->host);
861       if (ret < 0)
862         break;
863       if (ret == 0)
864         /* Any host */
865         config->admins->host = strdup("*");
866
867       /* Get authentication method */
868       ret = silc_config_get_token(line, &tmp);
869       if (ret < 0)
870         break;
871       if (ret) {
872         if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
873             strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
874           fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
875                   config->filename, pc->linenum, tmp);
876           break;
877         }
878
879         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
880           config->admins->auth_meth = SILC_AUTH_PASSWORD;
881
882         if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
883           config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY;
884
885         silc_free(tmp);
886       }
887
888       /* Get authentication data */
889       ret = silc_config_get_token(line, &config->admins->auth_data);
890       if (ret < 0)
891         break;
892
893       /* Get nickname */
894       ret = silc_config_get_token(line, &config->admins->nickname);
895       if (ret < 0)
896         break;
897
898       /* Get class number */
899       ret = silc_config_get_token(line, &tmp);
900       if (ret < 0)
901         break;
902       if (ret) {
903         config->admins->class = atoi(tmp);
904         silc_free(tmp);
905       }
906
907       check = TRUE;
908       checkmask |= (1L << pc->section->type);
909       break;
910
911     case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
912       /* Not implemented yet */
913       check = TRUE;
914       break;
915
916     case SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT:
917       /* Not implemented yet */
918       check = TRUE;
919       break;
920
921     case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD:
922
923       if (!config->motd)
924         config->motd = silc_calloc(1, sizeof(*config->motd));
925
926       /* Get motd file */
927       ret = silc_config_get_token(line, &config->motd->motd_file);
928       if (ret < 0)
929         break;
930
931       check = TRUE;
932       checkmask |= (1L << pc->section->type);
933       break;
934
935     case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
936     default:
937       /* Error */
938       break;
939     }
940
941     /* Check for error */
942     if (check == FALSE) {
943       /* Line could not be parsed */
944       fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
945       break;
946     }
947
948     pc = pc->next;
949     /* XXXX */
950     //    silc_free(pc->prev);
951     //    pc->prev = NULL;
952   }
953
954   if (check == FALSE)
955     return FALSE;;
956
957   /* Check that all mandatory sections really were found. If not, the server
958      cannot function and we return error. */
959   ret = silc_server_config_check_sections(checkmask);
960   if (ret == FALSE) {
961     /* XXX */
962
963   }
964   
965   /* Before returning all the lists in the config object must be set
966      to their first values (the last value is first here). */
967   while (config->cipher && config->cipher->prev)
968     config->cipher = config->cipher->prev;
969   while (config->pkcs && config->pkcs->prev)
970     config->pkcs = config->pkcs->prev;
971   while (config->hash_func && config->hash_func->prev)
972     config->hash_func = config->hash_func->prev;
973   while (config->hmac && config->hmac->prev)
974     config->hmac = config->hmac->prev;
975   while (config->listen_port && config->listen_port->prev)
976     config->listen_port = config->listen_port->prev;
977   while (config->logging && config->logging->prev)
978     config->logging = config->logging->prev;
979   while (config->conn_class && config->conn_class->prev)
980     config->conn_class = config->conn_class->prev;
981   while (config->clients && config->clients->prev)
982     config->clients = config->clients->prev;
983   while (config->servers && config->servers->prev)
984     config->servers = config->servers->prev;
985   while (config->routers && config->routers->prev)
986     config->routers = config->routers->prev;
987   
988   SILC_LOG_DEBUG(("Done"));
989   
990   return TRUE;
991 }
992
993 /* This function checks that the mask sent as argument includes all the 
994    sections that are mandatory in SILC server. */
995
996 int silc_server_config_check_sections(unsigned int checkmask)
997 {
998   if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
999     
1000     return FALSE;
1001   }
1002   if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) {
1003     
1004     return FALSE;
1005   }
1006   if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) {
1007     
1008     return FALSE;
1009   }
1010   if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
1011     
1012     return FALSE;
1013   }
1014   if (!(checkmask 
1015         & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) {
1016     
1017     return FALSE;
1018   }
1019   if (!(checkmask 
1020         & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) {
1021     
1022     return FALSE;
1023   }
1024
1025   return TRUE;
1026 }
1027
1028 /* Sets log files where log messages is saved by the server. */
1029
1030 void silc_server_config_setlogfiles(SilcServerConfig config)
1031 {
1032   SilcServerConfigSectionLogging *log;
1033   char *info, *warning, *error, *fatal;
1034   unsigned int info_size, warning_size, error_size, fatal_size;
1035
1036   SILC_LOG_DEBUG(("Setting configured log file names"));
1037
1038   /* Set default files before checking configuration */
1039   info = SILC_LOG_FILE_INFO;
1040   warning = SILC_LOG_FILE_WARNING;
1041   error = SILC_LOG_FILE_ERROR;
1042   fatal = SILC_LOG_FILE_FATAL;
1043   info_size = 0;
1044   warning_size = 0;
1045   error_size = 0;
1046   fatal_size = 0;
1047
1048   log = config->logging;
1049   while(log) {
1050     if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO)) {
1051       info = log->filename;
1052       info_size = log->maxsize;
1053     }
1054     if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING)) {
1055       warning = log->filename;
1056       warning_size = log->maxsize;
1057     }
1058     if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR)) {
1059       error = log->filename;
1060       error_size = log->maxsize;
1061     }
1062     if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
1063       fatal = log->filename;
1064       fatal_size = log->maxsize;
1065     }
1066
1067     log = log->next;
1068   }
1069
1070   silc_log_set_files(info, info_size, warning, warning_size,
1071                      error, error_size, fatal, fatal_size);
1072 }
1073
1074 /* Registers configured ciphers. These can then be allocated by the
1075    server when needed. */
1076
1077 void silc_server_config_register_ciphers(SilcServerConfig config)
1078 {
1079   SilcServerConfigSectionAlg *alg;
1080   SilcServer server = (SilcServer)config->server;
1081
1082   SILC_LOG_DEBUG(("Registering configured ciphers"));
1083
1084   alg = config->cipher;
1085   while(alg) {
1086
1087     if (!alg->sim_name) {
1088       /* Crypto module is supposed to be built in. Nothing to be done
1089          here except to test that the cipher really is built in. */
1090       SilcCipher tmp = NULL;
1091
1092       if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
1093         SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
1094         silc_server_stop(server);
1095         exit(1);
1096       }
1097       silc_cipher_free(tmp);
1098
1099 #ifdef SILC_SIM
1100     } else {
1101       /* Load (try at least) the crypto SIM module */
1102       SilcCipherObject cipher;
1103       SilcSimContext *sim;
1104       char *alg_name;
1105
1106       memset(&cipher, 0, sizeof(cipher));
1107       cipher.name = alg->alg_name;
1108       cipher.block_len = alg->block_len;
1109       cipher.key_len = alg->key_len * 8;
1110
1111       sim = silc_sim_alloc();
1112       sim->type = SILC_SIM_CIPHER;
1113       sim->libname = alg->sim_name;
1114
1115       alg_name = strdup(alg->alg_name);
1116       if (strchr(alg_name, '-'))
1117         *strchr(alg_name, '-') = '\0';
1118
1119       if ((silc_sim_load(sim))) {
1120         cipher.set_key = 
1121           silc_sim_getsym(sim, silc_sim_symname(alg_name, 
1122                                                 SILC_CIPHER_SIM_SET_KEY));
1123         SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
1124         cipher.set_key_with_string = 
1125           silc_sim_getsym(sim, silc_sim_symname(alg_name, 
1126                                                 SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
1127         SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
1128         cipher.encrypt = 
1129           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1130                                                 SILC_CIPHER_SIM_ENCRYPT_CBC));
1131         SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
1132         cipher.decrypt = 
1133           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1134                                                 SILC_CIPHER_SIM_DECRYPT_CBC));
1135         SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
1136         cipher.context_len = 
1137           silc_sim_getsym(sim, silc_sim_symname(alg_name,
1138                                                 SILC_CIPHER_SIM_CONTEXT_LEN));
1139         SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
1140
1141         /* Put the SIM to the list of all SIM's in server */
1142         silc_dlist_add(server->sim, sim);
1143
1144         silc_free(alg_name);
1145       } else {
1146         SILC_LOG_ERROR(("Error configuring ciphers"));
1147         silc_server_stop(server);
1148         exit(1);
1149       }
1150
1151       /* Register the cipher */
1152       silc_cipher_register(&cipher);
1153 #endif
1154     }
1155
1156     alg = alg->next;
1157   }
1158 }
1159
1160 /* Registers configured PKCS's. */
1161 /* XXX: This really doesn't do anything now since we have statically
1162    registered our PKCS's. This should be implemented when PKCS works
1163    as SIM's. This checks now only that the PKCS user requested is 
1164    really out there. */
1165
1166 void silc_server_config_register_pkcs(SilcServerConfig config)
1167 {
1168   SilcServerConfigSectionAlg *alg = config->pkcs;
1169   SilcServer server = (SilcServer)config->server;
1170   SilcPKCS tmp = NULL;
1171
1172   SILC_LOG_DEBUG(("Registering configured PKCS"));
1173
1174   while(alg) {
1175
1176     if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
1177       SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
1178       silc_server_stop(server);
1179       exit(1);
1180     }
1181     silc_free(tmp);
1182
1183     alg = alg->next;
1184   }
1185 }
1186
1187 /* Registers configured hash functions. These can then be allocated by the
1188    server when needed. */
1189
1190 void silc_server_config_register_hashfuncs(SilcServerConfig config)
1191 {
1192   SilcServerConfigSectionAlg *alg;
1193   SilcServer server = (SilcServer)config->server;
1194
1195   SILC_LOG_DEBUG(("Registering configured hash functions"));
1196
1197   alg = config->hash_func;
1198   while(alg) {
1199
1200     if (!alg->sim_name) {
1201       /* Hash module is supposed to be built in. Nothing to be done
1202          here except to test that the hash function really is built in. */
1203       SilcHash tmp = NULL;
1204
1205       if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
1206         SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
1207         silc_server_stop(server);
1208         exit(1);
1209       }
1210       silc_hash_free(tmp);
1211
1212 #ifdef SILC_SIM
1213     } else {
1214       /* Load (try at least) the hash SIM module */
1215       SilcHashObject hash;
1216       SilcSimContext *sim;
1217
1218       memset(&hash, 0, sizeof(hash));
1219       hash.name = alg->alg_name;
1220       hash.block_len = alg->block_len;
1221       hash.hash_len = alg->key_len;
1222
1223       sim = silc_sim_alloc();
1224       sim->type = SILC_SIM_HASH;
1225       sim->libname = alg->sim_name;
1226
1227       if ((silc_sim_load(sim))) {
1228         hash.init = 
1229           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
1230                                                 SILC_HASH_SIM_INIT));
1231         SILC_LOG_DEBUG(("init=%p", hash.init));
1232         hash.update = 
1233           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
1234                                                 SILC_HASH_SIM_UPDATE));
1235         SILC_LOG_DEBUG(("update=%p", hash.update));
1236         hash.final = 
1237           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
1238                                                 SILC_HASH_SIM_FINAL));
1239         SILC_LOG_DEBUG(("final=%p", hash.final));
1240         hash.context_len = 
1241           silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
1242                                                 SILC_HASH_SIM_CONTEXT_LEN));
1243         SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
1244
1245         /* Put the SIM to the table of all SIM's in server */
1246         silc_dlist_add(server->sim, sim);
1247       } else {
1248         SILC_LOG_ERROR(("Error configuring hash functions"));
1249         silc_server_stop(server);
1250         exit(1);
1251       }
1252
1253       /* Register the hash function */
1254       silc_hash_register(&hash);
1255 #endif
1256     }
1257
1258     alg = alg->next;
1259   }
1260 }
1261
1262 /* Registers configure HMACs. These can then be allocated by the server
1263    when needed. */
1264
1265 void silc_server_config_register_hmacs(SilcServerConfig config)
1266 {
1267   SilcServerConfigSectionAlg *alg;
1268   SilcServer server = (SilcServer)config->server;
1269
1270   SILC_LOG_DEBUG(("Registering configured HMACs"));
1271
1272   if (!config->hmac) {
1273     SILC_LOG_ERROR(("HMACs are not configured. SILC cannot work without "
1274                     "HMACs"));
1275     silc_server_stop(server);
1276     exit(1);
1277   }
1278
1279   alg = config->hmac;
1280   while(alg) {
1281     SilcHmacObject hmac;
1282     
1283     if (!silc_hash_is_supported(alg->sim_name)) {
1284       SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->sim_name));
1285       silc_server_stop(server);
1286       exit(1);
1287     }
1288     
1289     /* Register the HMAC */
1290     memset(&hmac, 0, sizeof(hmac));
1291     hmac.name = alg->alg_name;
1292     hmac.len = alg->key_len;
1293     silc_hmac_register(&hmac);
1294
1295     alg = alg->next;
1296   }
1297 }
1298
1299 /* Returns client authentication information from server configuration
1300    by host (name or ip). */
1301
1302 SilcServerConfigSectionClientConnection *
1303 silc_server_config_find_client_conn(SilcServerConfig config, 
1304                                     char *host, int port)
1305 {
1306   int i;
1307   SilcServerConfigSectionClientConnection *client = NULL;
1308
1309   if (!host)
1310     return NULL;
1311
1312   if (!config->clients)
1313     return NULL;
1314
1315   client = config->clients;
1316
1317   for (i = 0; client; i++) {
1318     if (silc_string_compare(client->host, host))
1319       break;
1320     client = client->next;
1321   }
1322
1323   if (!client)
1324     return NULL;
1325
1326   return client;
1327 }
1328
1329 /* Returns server connection info from server configuartion by host 
1330    (name or ip). */
1331
1332 SilcServerConfigSectionServerConnection *
1333 silc_server_config_find_server_conn(SilcServerConfig config, 
1334                                     char *host, int port)
1335 {
1336   int i;
1337   SilcServerConfigSectionServerConnection *serv = NULL;
1338
1339   if (!host)
1340     return NULL;
1341
1342   if (!config->servers)
1343     return NULL;
1344
1345   serv = config->servers;
1346   for (i = 0; serv; i++) {
1347     if (silc_string_compare(serv->host, host))
1348       break;
1349     serv = serv->next;
1350   }
1351
1352   if (!serv)
1353     return NULL;
1354
1355   return serv;
1356 }
1357
1358 /* Returns router connection info from server configuartion by
1359    host (name or ip). */
1360
1361 SilcServerConfigSectionServerConnection *
1362 silc_server_config_find_router_conn(SilcServerConfig config, 
1363                                     char *host, int port)
1364 {
1365   int i;
1366   SilcServerConfigSectionServerConnection *serv = NULL;
1367
1368   if (!host)
1369     return NULL;
1370
1371   if (!config->routers)
1372     return NULL;
1373
1374   serv = config->routers;
1375   for (i = 0; serv; i++) {
1376     if (silc_string_compare(serv->host, host))
1377       break;
1378     serv = serv->next;
1379   }
1380
1381   if (!serv)
1382     return NULL;
1383
1384   return serv;
1385 }
1386
1387 /* Prints out example configuration file with default built in
1388    configuration values. */
1389
1390 void silc_server_config_print()
1391 {
1392   char *buf;
1393
1394   buf = "\
1395 #\n\
1396 # Automatically generated example SILCd configuration file with default\n\
1397 # built in values. Use this as a guide to configure your SILCd configuration\n\
1398 # file for your system. For detailed description of different configuration\n\
1399 # sections refer to silcd(8) manual page.\n\
1400 #\n";
1401   /*
1402 #<Cipher>
1403 #+blowfish
1404 #+twofish
1405 #+rc5
1406 #+rc6
1407 #+3des
1408
1409 #<HashFunction>
1410 #+md5
1411 #+sha1
1412
1413 <ServerInfo>
1414 +lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
1415
1416 <AdminInfo>
1417 +Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
1418
1419 <ListenPort>
1420 +10.2.1.6:10.2.1.6:1333
1421
1422 <Logging>
1423 +infologfile:silcd.log:10000
1424 #+warninglogfile:/var/log/silcd_warning.log:10000
1425 #+errorlogfile:ERROR.log:10000
1426 #+fatallogfile:/var/log/silcd_error.log:
1427
1428 <ConnectionClass>
1429                 +1:100:100:100
1430                         +2:200:300:400
1431
1432 <ClientAuth>
1433 +10.2.1.199:priikone:333:1
1434
1435 <AdminAuth>
1436 +10.2.1.199:priikone:priikone:1
1437
1438 <ServerConnection>
1439
1440 <RouterConnection>
1441
1442 <DenyConnection>
1443 <RedirectClient>
1444   */
1445
1446   fprintf(stdout, "%s\n", buf);
1447 }