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