The SILC Project

source navigation ]
identifier search ]
freetext search ]
file search ]

silc/silcd/serverconfig.c

  1 /*
  2 
  3   serverconfig.c
  4 
  5   Author: Giovanni Giacobbi <giovanni@giacobbi.net>
  6 
  7   Copyright (C) 1997 - 2004 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: serverconfig.c,v 1.73 2005/04/23 13:32:25 priikone Exp $ */
 21 
 22 #include "serverincludes.h"
 23 #include "server_internal.h"
 24 #include <dirent.h>
 25 
 26 #if 0
 27 #define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
 28 #else
 29 #define SERVER_CONFIG_DEBUG(fmt)
 30 #endif
 31 
 32 /* auto-declare needed variables for the common list parsing */
 33 #define SILC_SERVER_CONFIG_SECTION_INIT(__type__)                       \
 34   SilcServerConfig config = (SilcServerConfig) context;                 \
 35   __type__ *findtmp, *tmp = (__type__ *) config->tmp;                   \
 36   int got_errno = 0
 37 
 38 /* allocate the tmp field for fetching data */
 39 #define SILC_SERVER_CONFIG_ALLOCTMP(__type__)                           \
 40   if (!tmp) {                                                           \
 41     config->tmp = silc_calloc(1, sizeof(*findtmp));                     \
 42     tmp = (__type__ *) config->tmp;                                     \
 43   }
 44 
 45 /* append the tmp field to the specified list */
 46 #define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__)                     \
 47   if (!__list__) {                                                      \
 48     __list__ = tmp;                                                     \
 49   } else {                                                              \
 50     for (findtmp = __list__; findtmp->next; findtmp = findtmp->next);   \
 51     findtmp->next = tmp;                                                \
 52   }
 53 
 54 /* loops all elements in a list and provides a di struct pointer of the
 55  * specified type containing the current element */
 56 #define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__)             \
 57   for (tmp = (void *) __list__; tmp;) {                                 \
 58     __type__ *di = (__type__ *) tmp;                                    \
 59     tmp = (void *) di->next;
 60 
 61 /* Set EDOUBLE error value and bail out if necessary */
 62 #define CONFIG_IS_DOUBLE(__x__)                                         \
 63   if ((__x__)) {                                                        \
 64     got_errno = SILC_CONFIG_EDOUBLE;                                    \
 65     goto got_err;                                                       \
 66   }
 67 
 68 /* Free the authentication fields in the specified struct
 69  * Expands to two instructions */
 70 #define CONFIG_FREE_AUTH(__section__)                   \
 71   silc_free(__section__->passphrase);                   \
 72   if (__section__->publickeys)                          \
 73     silc_hash_table_free(__section__->publickeys);
 74 
 75 static void my_free_public_key(void *key, void *context, void *user_data)
 76 {
 77   silc_pkcs_public_key_free(context);
 78 }
 79 
 80 /* Set default values to those parameters that have not been defined */
 81 static void
 82 my_set_param_defaults(SilcServerConfigConnParams *params,
 83                       SilcServerConfigConnParams *defaults)
 84 {
 85 #define SET_PARAM_DEFAULT(p, d) params->p =                             \
 86   (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
 87 
 88   SET_PARAM_DEFAULT(connections_max, SILC_SERVER_MAX_CONNECTIONS);
 89   SET_PARAM_DEFAULT(connections_max_per_host,
 90                     SILC_SERVER_MAX_CONNECTIONS_SINGLE);
 91   SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_KEEPALIVE);
 92   SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_RETRY_COUNT);
 93   SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_RETRY_INTERVAL_MIN);
 94   SET_PARAM_DEFAULT(reconnect_interval_max, SILC_SERVER_RETRY_INTERVAL_MAX);
 95   SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_REKEY);
 96   SET_PARAM_DEFAULT(qos_rate_limit, SILC_SERVER_QOS_RATE_LIMIT);
 97   SET_PARAM_DEFAULT(qos_bytes_limit, SILC_SERVER_QOS_BYTES_LIMIT);
 98   SET_PARAM_DEFAULT(qos_limit_sec, SILC_SERVER_QOS_LIMIT_SEC);
 99   SET_PARAM_DEFAULT(qos_limit_usec, SILC_SERVER_QOS_LIMIT_USEC);
100 
101 #undef SET_PARAM_DEFAULT
102 }
103 
104 /* Find connection parameters by the parameter block name. */
105 static SilcServerConfigConnParams *
106 my_find_param(SilcServerConfig config, const char *name)
107 {
108   SilcServerConfigConnParams *param;
109 
110   for (param = config->conn_params; param; param = param->next) {
111     if (!strcasecmp(param->name, name))
112       return param;
113   }
114 
115   SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
116                          "Cannot find Params \"%s\".", name));
117 
118   return NULL;
119 }
120 
121 /* parse an authdata according to its auth method */
122 static bool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
123                               void **auth_data, SilcUInt32 *auth_data_len)
124 {
125   if (auth_meth == SILC_AUTH_PASSWORD) {
126     /* p is a plain text password */
127     if (auth_data && auth_data_len) {
128       if (!silc_utf8_valid(p, strlen(p))) {
129         *auth_data_len = silc_utf8_encoded_len(p, strlen(p),
130                                                SILC_STRING_LOCALE);
131         *auth_data = silc_calloc(*auth_data_len, sizeof(unsigned char));
132         silc_utf8_encode(p, strlen(p), SILC_STRING_LOCALE, *auth_data,
133                          *auth_data_len);
134       } else {
135         *auth_data = (void *) strdup(p);
136         *auth_data_len = (SilcUInt32) strlen(p);
137       }
138     }
139   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
140     /* p is a public key file name */
141     SilcPublicKey public_key;
142     SilcPublicKey cached_key;
143 
144     if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
145       if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
146         SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
147                                "Could not load public key file!"));
148         return FALSE;
149       }
150 
151     if (*auth_data &&
152         silc_hash_table_find_ext(*auth_data, public_key, (void *)&cached_key,
153                                  NULL, silc_hash_public_key, NULL,
154                                  silc_hash_public_key_compare, NULL)) {
155       silc_pkcs_public_key_free(public_key);
156       SILC_SERVER_LOG_WARNING(("Warning: public key file \"%s\" already "
157                                "configured, ignoring this key", p));
158       return TRUE; /* non fatal error */
159     }
160 
161     /* The auth_data is a pointer to the hash table of public keys. */
162     if (auth_data) {
163       if (*auth_data == NULL)
164         *auth_data = silc_hash_table_alloc(1, silc_hash_public_key, NULL,
165                                            NULL, NULL,
166                                            my_free_public_key, NULL,
167                                            TRUE);
168       SILC_LOG_DEBUG(("Adding public key '%s' to authentication cache",
169                      public_key->identifier));
170       silc_hash_table_add(*auth_data, public_key, public_key);
171     }
172   } else
173     abort();
174 
175   return TRUE;
176 }
177 
178 static bool my_parse_publickeydir(const char *dirname, void **auth_data)
179 {
180   int total = 0;
181   struct dirent *get_file;
182   DIR *dp;
183 
184   if (!(dp = opendir(dirname))) {
185     SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
186                            "Could not open directory \"%s\"", dirname));
187     return FALSE;
188   }
189 
190   /* errors are not considered fatal */
191   while ((get_file = readdir(dp))) {
192     const char *filename = get_file->d_name;
193     char buf[1024];
194     int dirname_len = strlen(dirname), filename_len = strlen(filename);
195     struct stat check_file;
196 
197     /* Ignore "." and "..", and take files only with ".pub" suffix. */
198     if (!strcmp(filename, ".") || !strcmp(filename, "..") ||
199         (filename_len < 5) || strcmp(filename + filename_len - 4, ".pub"))
200       continue;
201 
202     memset(buf, 0, sizeof(buf));
203     snprintf(buf, sizeof(buf) - 1, "%s%s%s", dirname,
204              (dirname[dirname_len - 1] == '/' ? "" : "/"), filename);
205 
206     if (stat(buf, &check_file) < 0) {
207       SILC_SERVER_LOG_ERROR(("Error stating file %s: %s", buf,
208                              strerror(errno)));
209     } else if (S_ISREG(check_file.st_mode)) {
210       my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL);
211       total++;
212     }
213   }
214 
215   SILC_LOG_DEBUG(("Tried to load %d public keys in \"%s\"", total, dirname));
216   return TRUE;
217 }
218 
219 /* Callbacks */
220 
221 SILC_CONFIG_CALLBACK(fetch_generic)
222 {
223   SilcServerConfig config = (SilcServerConfig) context;
224   int got_errno = 0;
225 
226   if (!strcmp(name, "module_path")) {
227     CONFIG_IS_DOUBLE(config->module_path);
228     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
229   }
230   else if (!strcmp(name, "prefer_passphrase_auth")) {
231     config->prefer_passphrase_auth = *(bool *)val;
232   }
233   else if (!strcmp(name, "require_reverse_lookup")) {
234     config->require_reverse_lookup = *(bool *)val;
235   }
236   else if (!strcmp(name, "connections_max")) {
237     config->param.connections_max = (SilcUInt32) *(int *)val;
238   }
239   else if (!strcmp(name, "connections_max_per_host")) {
240     config->param.connections_max_per_host = (SilcUInt32) *(int *)val;
241   }
242   else if (!strcmp(name, "keepalive_secs")) {
243     config->param.keepalive_secs = (SilcUInt32) *(int *)val;
244   }
245   else if (!strcmp(name, "reconnect_count")) {
246     config->param.reconnect_count = (SilcUInt32) *(int *)val;
247   }
248   else if (!strcmp(name, "reconnect_interval")) {
249     config->param.reconnect_interval = (SilcUInt32) *(int *)val;
250   }
251   else if (!strcmp(name, "reconnect_interval_max")) {
252     config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
253   }
254   else if (!strcmp(name, "reconnect_keep_trying")) {
255     config->param.reconnect_keep_trying = *(bool *)val;
256   }
257   else if (!strcmp(name, "key_exchange_rekey")) {
258     config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
259   }
260   else if (!strcmp(name, "key_exchange_pfs")) {
261     config->param.key_exchange_pfs = *(bool *)val;
262   }
263   else if (!strcmp(name, "channel_rekey_secs")) {
264     config->channel_rekey_secs = (SilcUInt32) *(int *)val;
265   }
266   else if (!strcmp(name, "key_exchange_timeout")) {
267     config->key_exchange_timeout = (SilcUInt32) *(int *)val;
268   }
269   else if (!strcmp(name, "conn_auth_timeout")) {
270     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
271   }
272   else if (!strcmp(name, "version_protocol")) {
273     CONFIG_IS_DOUBLE(config->param.version_protocol);
274     config->param.version_protocol =
275       (*(char *)val ? strdup((char *) val) : NULL);
276   }
277   else if (!strcmp(name, "version_software")) {
278     CONFIG_IS_DOUBLE(config->param.version_software);
279     config->param.version_software =
280       (*(char *)val ? strdup((char *) val) : NULL);
281   }
282   else if (!strcmp(name, "version_software_vendor")) {
283     CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
284     config->param.version_software_vendor =
285       (*(char *)val ? strdup((char *) val) : NULL);
286   }
287   else if (!strcmp(name, "detach_disabled")) {
288     config->detach_disabled = *(bool *)val;
289   }
290   else if (!strcmp(name, "detach_timeout")) {
291     config->detach_timeout = (SilcUInt32) *(int *)val;
292   }
293   else if (!strcmp(name, "qos")) {
294     config->param.qos = *(bool *)val;
295   }
296   else if (!strcmp(name, "qos_rate_limit")) {
297     config->param.qos_rate_limit = *(SilcUInt32 *)val;
298   }
299   else if (!strcmp(name, "qos_bytes_limit")) {
300     config->param.qos_bytes_limit = *(SilcUInt32 *)val;
301   }
302   else if (!strcmp(name, "qos_limit_sec")) {
303     config->param.qos_limit_sec = *(SilcUInt32 *)val;
304   }
305   else if (!strcmp(name, "qos_limit_usec")) {
306     config->param.qos_limit_usec = *(SilcUInt32 *)val;
307   }
308   else if (!strcmp(name, "debug_string")) {
309     CONFIG_IS_DOUBLE(config->debug_string);
310     config->debug_string = (*(char *)val ? strdup((char *) val) : NULL);
311   }
312   else
313     return SILC_CONFIG_EINTERNAL;
314 
315   return SILC_CONFIG_OK;
316 
317  got_err:
318   return got_errno;
319 }
320 
321 SILC_CONFIG_CALLBACK(fetch_cipher)
322 {
323   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigCipher);
324 
325   SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)",
326                        type, name, context));
327   if (type == SILC_CONFIG_ARG_BLOCK) {
328     /* check the temporary struct's fields */
329     if (!tmp) /* discard empty sub-blocks */
330       return SILC_CONFIG_OK;
331     if (!tmp->name) {
332       got_errno = SILC_CONFIG_EMISSFIELDS;
333       goto got_err;
334     }
335 
336     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
337     config->tmp = NULL;
338     return SILC_CONFIG_OK;
339   }
340   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigCipher);
341 
342   /* Identify and save this value */
343   if (!strcmp(name, "name")) {
344     CONFIG_IS_DOUBLE(tmp->name);
345     tmp->name = strdup((char *) val);
346   }
347   else if (!strcmp(name, "module")) {
348     CONFIG_IS_DOUBLE(tmp->module);
349     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
350   }
351   else if (!strcmp(name, "keylength")) {
352     tmp->key_length = *(SilcUInt32 *)val;
353   }
354   else if (!strcmp(name, "blocklength")) {
355     tmp->block_length = *(SilcUInt32 *)val;
356   }
357   else
358     return SILC_CONFIG_EINTERNAL;
359   return SILC_CONFIG_OK;
360 
361  got_err:
362   silc_free(tmp->name);
363   silc_free(tmp->module);
364   silc_free(tmp);
365   config->tmp = NULL;
366   return got_errno;
367 }
368 
369 SILC_CONFIG_CALLBACK(fetch_hash)
370 {
371   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHash);
372 
373   SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)",
374                        type, name, context));
375   if (type == SILC_CONFIG_ARG_BLOCK) {
376     /* check the temporary struct's fields */
377     if (!tmp) /* discard empty sub-blocks */
378       return SILC_CONFIG_OK;
379     if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
380       got_errno = SILC_CONFIG_EMISSFIELDS;
381       goto got_err;
382     }
383 
384     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
385     config->tmp = NULL;
386     return SILC_CONFIG_OK;
387   }
388   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHash);
389 
390   /* Identify and save this value */
391   if (!strcmp(name, "name")) {
392     CONFIG_IS_DOUBLE(tmp->name);
393     tmp->name = strdup((char *) val);
394   }
395   else if (!strcmp(name, "module")) {
396     CONFIG_IS_DOUBLE(tmp->module);
397     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
398   }
399   else if (!strcmp(name, "blocklength")) {
400     tmp->block_length = *(int *)val;
401   }
402   else if (!strcmp(name, "digestlength")) {
403     tmp->digest_length = *(int *)val;
404   }
405   else
406     return SILC_CONFIG_EINTERNAL;
407   return SILC_CONFIG_OK;
408 
409  got_err:
410   silc_free(tmp->name);
411   silc_free(tmp->module);
412   silc_free(tmp);
413   config->tmp = NULL;
414   return got_errno;
415 }
416 
417 SILC_CONFIG_CALLBACK(fetch_hmac)
418 {
419   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigHmac);
420 
421   SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)",
422                        type, name, context));
423   if (type == SILC_CONFIG_ARG_BLOCK) {
424     /* check the temporary struct's fields */
425     if (!tmp) /* discard empty sub-blocks */
426       return SILC_CONFIG_OK;
427     if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
428       got_errno = SILC_CONFIG_EMISSFIELDS;
429       goto got_err;
430     }
431 
432     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
433     config->tmp = NULL;
434     return SILC_CONFIG_OK;
435   }
436   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigHmac);
437 
438   /* Identify and save this value */
439   if (!strcmp(name, "name")) {
440     CONFIG_IS_DOUBLE(tmp->name);
441     tmp->name = strdup((char *) val);
442   }
443   else if (!strcmp(name, "hash")) {
444     CONFIG_IS_DOUBLE(tmp->hash);
445     tmp->hash = strdup((char *) val);
446   }
447   else if (!strcmp(name, "maclength")) {
448     tmp->mac_length = *(int *)val;
449   }
450   else
451     return SILC_CONFIG_EINTERNAL;
452   return SILC_CONFIG_OK;
453 
454  got_err:
455   silc_free(tmp->name);
456   silc_free(tmp->hash);
457   silc_free(tmp);
458   config->tmp = NULL;
459   return got_errno;
460 }
461 
462 SILC_CONFIG_CALLBACK(fetch_pkcs)
463 {
464   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigPkcs);
465 
466   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
467                        type, name, context));
468   if (type == SILC_CONFIG_ARG_BLOCK) {
469     /* Check the temporary struct's fields */
470     if (!tmp) /* discard empty sub-blocks */
471       return SILC_CONFIG_OK;
472     if (!tmp->name) {
473       got_errno = SILC_CONFIG_EMISSFIELDS;
474       goto got_err;
475     }
476 
477     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
478     config->tmp = NULL;
479     return SILC_CONFIG_OK;
480   }
481   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigPkcs);
482 
483   /* Identify and save this value */
484   if (!strcmp(name, "name")) {
485     CONFIG_IS_DOUBLE(tmp->name);
486     tmp->name = strdup((char *) val);
487   }
488   else
489     return SILC_CONFIG_EINTERNAL;
490   return SILC_CONFIG_OK;
491 
492  got_err:
493   silc_free(tmp->name);
494   silc_free(tmp);
495   config->tmp = NULL;
496   return got_errno;
497 }
498 
499 SILC_CONFIG_CALLBACK(fetch_serverinfo)
500 {
501   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServerInfoInterface);
502   SilcServerConfigServerInfo *server_info = config->server_info;
503 
504   SERVER_CONFIG_DEBUG(("Received SERVERINFO type=%d name=\"%s\" (val=%x)",
505                        type, name, context));
506 
507   /* If there isn't the main struct alloc it */
508   if (!server_info)
509     config->server_info = server_info = (SilcServerConfigServerInfo *)
510                 silc_calloc(1, sizeof(*server_info));
511 
512   if (type == SILC_CONFIG_ARG_BLOCK) {
513     if (!strcmp(name, "primary")) {
514       if (server_info->primary) {
515         SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
516                                "Double primary specification."));
517         got_errno = SILC_CONFIG_EPRINTLINE;
518         goto got_err;
519       }
520       CONFIG_IS_DOUBLE(server_info->primary);
521 
522       /* now check the temporary struct, don't accept empty block and
523          make sure all fields are there */
524       if (!tmp || !tmp->server_ip || !tmp->port) {
525         got_errno = SILC_CONFIG_EMISSFIELDS;
526         goto got_err;
527       }
528       server_info->primary = tmp;
529       config->tmp = NULL;
530       return SILC_CONFIG_OK;
531     } else if (!strcmp(name, "secondary")) {
532       if (!tmp)
533         return SILC_CONFIG_OK;
534       if (!tmp || !tmp->server_ip || !tmp->port) {
535         got_errno = SILC_CONFIG_EMISSFIELDS;
536         goto got_err;
537       }
538       SILC_SERVER_CONFIG_LIST_APPENDTMP(server_info->secondary);
539       config->tmp = NULL;
540       return SILC_CONFIG_OK;
541     } else if (!server_info->public_key || !server_info->private_key) {
542       got_errno = SILC_CONFIG_EMISSFIELDS;
543       goto got_err;
544     }
545     return SILC_CONFIG_OK;
546   }
547   if (!strcmp(name, "hostname")) {
548     CONFIG_IS_DOUBLE(server_info->server_name);
549     server_info->server_name = strdup((char *) val);
550   }
551   else if (!strcmp(name, "ip")) {
552     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
553     CONFIG_IS_DOUBLE(tmp->server_ip);
554     tmp->server_ip = strdup((char *) val);
555   }
556   else if (!strcmp(name, "port")) {
557     int port = *(int *)val;
558     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServerInfoInterface);
559     if ((port <= 0) || (port > 65535)) {
560       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
561                              "Invalid port number!"));
562       got_errno = SILC_CONFIG_EPRINTLINE;
563       goto got_err;
564     }
565     tmp->port = (SilcUInt16) port;
566   }
567   else if (!strcmp(name, "servertype")) {
568     CONFIG_IS_DOUBLE(server_info->server_type);
569     server_info->server_type = strdup((char *) val);
570   }
571   else if (!strcmp(name, "admin")) {
572     CONFIG_IS_DOUBLE(server_info->admin);
573     server_info->admin = strdup((char *) val);
574   }
575   else if (!strcmp(name, "adminemail")) {
576     CONFIG_IS_DOUBLE(server_info->email);
577     server_info->email = strdup((char *) val);
578   }
579   else if (!strcmp(name, "location")) {
580     CONFIG_IS_DOUBLE(server_info->location);
581     server_info->location = strdup((char *) val);
582   }
583   else if (!strcmp(name, "user")) {
584     CONFIG_IS_DOUBLE(server_info->user);
585     server_info->user = strdup((char *) val);
586   }
587   else if (!strcmp(name, "group")) {
588     CONFIG_IS_DOUBLE(server_info->group);
589     server_info->group = strdup((char *) val);
590   }
591   else if (!strcmp(name, "motdfile")) {
592     CONFIG_IS_DOUBLE(server_info->motd_file);
593     server_info->motd_file = strdup((char *) val);
594   }
595   else if (!strcmp(name, "pidfile")) {
596     CONFIG_IS_DOUBLE(server_info->pid_file);
597     server_info->pid_file = strdup((char *) val);
598   }
599   else if (!strcmp(name, "publickey")) {
600     char *file_tmp = (char *) val;
601     CONFIG_IS_DOUBLE(server_info->public_key);
602 
603     /* Try to load specified file, if fail stop config parsing */
604     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
605                                    SILC_PKCS_FILE_PEM))
606       if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
607                                      SILC_PKCS_FILE_BIN)) {
608         SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
609         return SILC_CONFIG_EPRINTLINE;
610       }
611   }
612   else if (!strcmp(name, "privatekey")) {
613     struct stat st;
614     char *file_tmp = (char *) val;
615     CONFIG_IS_DOUBLE(server_info->private_key);
616 
617     /* Check the private key file permissions. */
618     if ((stat(file_tmp, &st)) != -1) {
619       if ((st.st_mode & 0777) != 0600) {
620         SILC_SERVER_LOG_ERROR(("Wrong permissions in private key "
621                               "file \"%s\".  The permissions must be "
622                               "0600.", file_tmp));
623         return SILC_CONFIG_ESILENT;
624       }
625     }
626 
627     /* Try to load specified file, if fail stop config parsing */
628     if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
629                                     "", 0, SILC_PKCS_FILE_BIN))
630       if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
631                                       "", 0, SILC_PKCS_FILE_PEM)) {
632         SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
633         return SILC_CONFIG_EPRINTLINE;
634       }
635   }
636   else
637     return SILC_CONFIG_EINTERNAL;
638   return SILC_CONFIG_OK;
639 
640  got_err:
641   /* Here we need to check if tmp exists because this function handles
642    * misc data (multiple fields and single-only fields) */
643   if (tmp) {
644     silc_free(tmp->server_ip);
645     silc_free(tmp);
646     config->tmp = NULL;
647   }
648   return got_errno;
649 }
650 
651 SILC_CONFIG_CALLBACK(fetch_logging)
652 {
653   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
654 
655   if (!strcmp(name, "timestamp")) {
656     config->logging_timestamp = *(bool *)val;
657   }
658   else if (!strcmp(name, "quicklogs")) {
659     config->logging_quick = *(bool *)val;
660   }
661   else if (!strcmp(name, "flushdelay")) {
662     int flushdelay = *(int *)val;
663     if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
664       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
665                             "Invalid flushdelay value, use quicklogs if you "
666                             "want real-time logging."));
667       return SILC_CONFIG_EPRINTLINE;
668     }
669     config->logging_flushdelay = (long) flushdelay;
670   }
671 
672   /* The following istances happens only in Logging's sub-blocks, a match
673      for the sub-block name means that you should store the filename/maxsize
674      temporary struct to the proper logging channel.
675      If we get a match for "file" or "maxsize" this means that we are inside
676      a sub-sub-block and it is safe to alloc a new tmp. */
677 #define FETCH_LOGGING_CHAN(__chan__, __member__)                \
678   else if (!strcmp(name, __chan__)) {                           \
679     if (!tmp) return SILC_CONFIG_OK;                            \
680     if (!tmp->file) {                                           \
681       got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;        \
682     }                                                           \
683     config->__member__ = tmp;                                   \
684     config->tmp = NULL;                                         \
685   }
686   FETCH_LOGGING_CHAN("info", logging_info)
687   FETCH_LOGGING_CHAN("warnings", logging_warnings)
688   FETCH_LOGGING_CHAN("errors", logging_errors)
689   FETCH_LOGGING_CHAN("fatals", logging_fatals)
690 #undef FETCH_LOGGING_CHAN
691   else if (!strcmp(name, "file")) {
692     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigLogging);
693     CONFIG_IS_DOUBLE(tmp->file);
694     tmp->file = strdup((char *) val);
695   }
696   else if (!strcmp(name, "size")) {
697     if (!tmp) {
698       config->tmp = silc_calloc(1, sizeof(*tmp));
699       tmp = (SilcServerConfigLogging *) config->tmp;
700     }
701     tmp->maxsize = *(SilcUInt32 *) val;
702   }
703   else
704     return SILC_CONFIG_EINTERNAL;
705   return SILC_CONFIG_OK;
706 
707  got_err:
708   silc_free(tmp->file);
709   silc_free(tmp);
710   config->tmp = NULL;
711   return got_errno;
712 }
713 
714 SILC_CONFIG_CALLBACK(fetch_connparam)
715 {
716   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigConnParams);
717 
718   SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)",
719                        type, name, context));
720   if (type == SILC_CONFIG_ARG_BLOCK) {
721     /* check the temporary struct's fields */
722     if (!tmp) /* discard empty sub-blocks */
723       return SILC_CONFIG_OK;
724     if (!tmp->name) {
725       got_errno = SILC_CONFIG_EMISSFIELDS;
726       goto got_err;
727     }
728     /* Set defaults */
729     my_set_param_defaults(tmp, &config->param);
730 
731     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
732     config->tmp = NULL;
733     return SILC_CONFIG_OK;
734   }
735   if (!tmp) {
736     SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigConnParams);
737     tmp->reconnect_keep_trying = TRUE;
738   }
739 
740   if (!strcmp(name, "name")) {
741     CONFIG_IS_DOUBLE(tmp->name);
742     tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
743   }
744   else if (!strcmp(name, "connections_max")) {
745     tmp->connections_max = *(SilcUInt32 *)val;
746   }
747   else if (!strcmp(name, "connections_max_per_host")) {
748     tmp->connections_max_per_host = *(SilcUInt32 *)val;
749   }
750   else if (!strcmp(name, "keepalive_secs")) {
751     tmp->keepalive_secs = *(SilcUInt32 *)val;
752   }
753   else if (!strcmp(name, "reconnect_count")) {
754     tmp->reconnect_count = *(SilcUInt32 *)val;
755   }
756   else if (!strcmp(name, "reconnect_interval")) {
757     tmp->reconnect_interval = *(SilcUInt32 *)val;
758   }
759   else if (!strcmp(name, "reconnect_interval_max")) {
760     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
761   }
762   else if (!strcmp(name, "reconnect_keep_trying")) {
763     tmp->reconnect_keep_trying = *(bool *)val;
764   }
765   else if (!strcmp(name, "key_exchange_rekey")) {
766     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
767   }
768   else if (!strcmp(name, "key_exchange_pfs")) {
769     tmp->key_exchange_pfs = *(bool *)val;
770   }
771   else if (!strcmp(name, "version_protocol")) {
772     CONFIG_IS_DOUBLE(tmp->version_protocol);
773     tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
774   }
775   else if (!strcmp(name, "version_software")) {
776     CONFIG_IS_DOUBLE(tmp->version_software);
777     tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
778   }
779   else if (!strcmp(name, "version_software_vendor")) {
780     CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
781     tmp->version_software_vendor =
782       (*(char *)val ? strdup((char *) val) : NULL);
783   }
784   else if (!strcmp(name, "anonymous")) {
785     tmp->anonymous = *(bool *)val;
786   }
787   else if (!strcmp(name, "qos")) {
788     tmp->qos = *(bool *)val;
789   }
790   else if (!strcmp(name, "qos_rate_limit")) {
791     tmp->qos_rate_limit = *(SilcUInt32 *)val;
792   }
793   else if (!strcmp(name, "qos_bytes_limit")) {
794     tmp->qos_bytes_limit = *(SilcUInt32 *)val;
795   }
796   else if (!strcmp(name, "qos_limit_sec")) {
797     tmp->qos_limit_sec = *(SilcUInt32 *)val;
798   }
799   else if (!strcmp(name, "qos_limit_usec")) {
800     tmp->qos_limit_usec = *(SilcUInt32 *)val;
801   }
802   else
803     return SILC_CONFIG_EINTERNAL;
804 
805   return SILC_CONFIG_OK;
806 
807  got_err:
808   silc_free(tmp->name);
809   silc_free(tmp);
810   config->tmp = NULL;
811   return got_errno;
812 }
813 
814 SILC_CONFIG_CALLBACK(fetch_client)
815 {
816   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigClient);
817 
818   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
819                        type, name, context));
820 
821   /* Alloc before block checking, because empty sub-blocks are welcome here */
822   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigClient);
823 
824   if (type == SILC_CONFIG_ARG_BLOCK) {
825     /* empty sub-blocks are welcome */
826     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
827     config->tmp = NULL;
828     return SILC_CONFIG_OK;
829   }
830 
831   /* Identify and save this value */
832   if (!strcmp(name, "host")) {
833     CONFIG_IS_DOUBLE(tmp->host);
834     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
835   }
836   else if (!strcmp(name, "passphrase")) {
837     CONFIG_IS_DOUBLE(tmp->passphrase);
838     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
839                            (void *)&tmp->passphrase,
840                            &tmp->passphrase_len)) {
841       got_errno = SILC_CONFIG_EPRINTLINE;
842       goto got_err;
843     }
844   }
845   else if (!strcmp(name, "publickey")) {
846     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
847                            (void *)&tmp->publickeys, NULL)) {
848       got_errno = SILC_CONFIG_EPRINTLINE;
849       goto got_err;
850     }
851   }
852   else if (!strcmp(name, "publickeydir")) {
853     if (!my_parse_publickeydir((char *) val, (void *)&tmp->publickeys)) {
854       got_errno = SILC_CONFIG_EPRINTLINE;
855       goto got_err;
856     }
857   }
858   else if (!strcmp(name, "params")) {
859     CONFIG_IS_DOUBLE(tmp->param);
860     tmp->param = my_find_param(config, (char *) val);
861     if (!tmp->param) { /* error message already output */
862       got_errno = SILC_CONFIG_EPRINTLINE;
863       goto got_err;
864     }
865   }
866   else
867     return SILC_CONFIG_EINTERNAL;
868   return SILC_CONFIG_OK;
869 
870  got_err:
871   silc_free(tmp->host);
872   CONFIG_FREE_AUTH(tmp);
873   silc_free(tmp);
874   config->tmp = NULL;
875   return got_errno;
876 }
877 
878 SILC_CONFIG_CALLBACK(fetch_admin)
879 {
880   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigAdmin);
881 
882   SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)",
883                        type, name, context));
884   if (type == SILC_CONFIG_ARG_BLOCK) {
885     /* check the temporary struct's fields */
886     if (!tmp) /* discard empty sub-blocks */
887       return SILC_CONFIG_OK;
888 
889     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
890     config->tmp = NULL;
891     return SILC_CONFIG_OK;
892   }
893   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigAdmin);
894 
895   /* Identify and save this value */
896   if (!strcmp(name, "host")) {
897     CONFIG_IS_DOUBLE(tmp->host);
898     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
899   }
900   else if (!strcmp(name, "user")) {
901     CONFIG_IS_DOUBLE(tmp->user);
902     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
903   }
904   else if (!strcmp(name, "nick")) {
905     CONFIG_IS_DOUBLE(tmp->nick);
906     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
907   }
908   else if (!strcmp(name, "passphrase")) {
909     CONFIG_IS_DOUBLE(tmp->passphrase);
910     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
911                            (void *)&tmp->passphrase,
912                            &tmp->passphrase_len)) {
913       got_errno = SILC_CONFIG_EPRINTLINE;
914       goto got_err;
915     }
916   }
917   else if (!strcmp(name, "publickey")) {
918     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
919                            (void *)&tmp->publickeys, NULL)) {
920       got_errno = SILC_CONFIG_EPRINTLINE;
921       goto got_err;
922     }
923   }
924   else
925     return SILC_CONFIG_EINTERNAL;
926   return SILC_CONFIG_OK;
927 
928  got_err:
929   silc_free(tmp->host);
930   silc_free(tmp->user);
931   silc_free(tmp->nick);
932   CONFIG_FREE_AUTH(tmp);
933   silc_free(tmp);
934   config->tmp = NULL;
935   return got_errno;
936 }
937 
938 SILC_CONFIG_CALLBACK(fetch_deny)
939 {
940   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigDeny);
941 
942   SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)",
943                        type, name, context));
944   if (type == SILC_CONFIG_ARG_BLOCK) {
945     /* check the temporary struct's fields */
946     if (!tmp) /* discard empty sub-blocks */
947       return SILC_CONFIG_OK;
948     if (!tmp->reason) {
949       got_errno = SILC_CONFIG_EMISSFIELDS;
950       goto got_err;
951     }
952 
953     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
954     config->tmp = NULL;
955     return SILC_CONFIG_OK;
956   }
957   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigDeny);
958 
959   /* Identify and save this value */
960   if (!strcmp(name, "host")) {
961     CONFIG_IS_DOUBLE(tmp->host);
962     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
963   }
964   else if (!strcmp(name, "reason")) {
965     CONFIG_IS_DOUBLE(tmp->reason);
966     tmp->reason = strdup((char *) val);
967   }
968   else
969     return SILC_CONFIG_EINTERNAL;
970   return SILC_CONFIG_OK;
971 
972  got_err:
973   silc_free(tmp->host);
974   silc_free(tmp->reason);
975   silc_free(tmp);
976   config->tmp = NULL;
977   return got_errno;
978 }
979 
980 SILC_CONFIG_CALLBACK(fetch_server)
981 {
982   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigServer);
983 
984   SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)",
985                        type, name, context));
986   if (type == SILC_CONFIG_ARG_BLOCK) {
987     /* check the temporary struct's fields */
988     if (!tmp) /* discard empty sub-blocks */
989       return SILC_CONFIG_OK;
990     if (!tmp->host) {
991       got_errno = SILC_CONFIG_EMISSFIELDS;
992       goto got_err;
993     }
994 
995     /* the temporary struct is ok, append it to the list */
996     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
997     config->tmp = NULL;
998     return SILC_CONFIG_OK;
999   }
1000   SILC_SERVER_CONFIG_ALLOCTMP(SilcServerConfigServer);
1001 
1002   /* Identify and save this value */
1003   if (!strcmp(name, "host")) {
1004     CONFIG_IS_DOUBLE(tmp->host);
1005     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
1006   }
1007   else if (!strcmp(name, "passphrase")) {
1008     CONFIG_IS_DOUBLE(tmp->passphrase);
1009     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
1010                            (void *)&tmp->passphrase,
1011                            &tmp->passphrase_len)) {
1012       got_errno = SILC_CONFIG_EPRINTLINE;
1013       goto got_err;
1014     }
1015   }
1016   else if (!strcmp(name, "publickey")) {
1017     CONFIG_IS_DOUBLE(tmp->publickeys);
1018     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
1019                            (void *)&tmp->publickeys, NULL)) {
1020       got_errno = SILC_CONFIG_EPRINTLINE;
1021       goto got_err;
1022     }
1023   }
1024   else if (!strcmp(name, "params")) {
1025     CONFIG_IS_DOUBLE(tmp->param);
1026     tmp->param = my_find_param(config, (char *) val);
1027     if (!tmp->param) { /* error message already output */
1028       got_errno = SILC_CONFIG_EPRINTLINE;
1029       goto got_err;
1030     }
1031   }
1032   else if (!strcmp(name, "backup")) {
1033     tmp->backup_router = *(bool *)val;
1034   }
1035   else
1036     return SILC_CONFIG_EINTERNAL;
1037 
1038   return SILC_CONFIG_OK;
1039 
1040  got_err:
1041   silc_free(tmp->host);
1042   CONFIG_FREE_AUTH(tmp);
1043   silc_free(tmp);
1044   config->tmp = NULL;
1045   return got_errno;
1046 }
1047 
1048 SILC_CONFIG_CALLBACK(fetch_router)
1049 {
1050   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigRouter);
1051 
1052   SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)",
1053                        type, name, context));
1054   if (type == SILC_CONFIG_ARG_BLOCK) {
1055     if (!tmp) /* discard empty sub-blocks */