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