2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2005 Ivo Timmermans
5 2000-2009 Guus Sliepen <guus@tinc-vpn.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "splay_tree.h"
30 #include "netutl.h" /* for str2address */
31 #include "utils.h" /* for cp */
34 splay_tree_t *config_tree;
36 int pinginterval = 0; /* seconds between pings */
37 int pingtimeout = 0; /* seconds to wait for response */
38 char *confbase = NULL; /* directory in which all config files are */
39 char *netname = NULL; /* name of the vpn network */
41 static int config_compare(const config_t *a, const config_t *b) {
44 result = strcasecmp(a->variable, b->variable);
49 result = a->line - b->line;
54 return strcmp(a->file, b->file);
57 void init_configuration(splay_tree_t ** config_tree) {
60 *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
63 void exit_configuration(splay_tree_t ** config_tree) {
66 splay_delete_tree(*config_tree);
70 config_t *new_config(void) {
73 return xmalloc_and_zero(sizeof(config_t));
76 void free_config(config_t *cfg) {
91 void config_add(splay_tree_t *config_tree, config_t *cfg) {
94 splay_insert(config_tree, cfg);
97 config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
102 cfg.variable = variable;
106 found = splay_search_closest_greater(config_tree, &cfg);
111 if(strcasecmp(found->variable, variable))
117 config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
123 node = splay_search_node(config_tree, cfg);
127 found = node->next->data;
129 if(!strcasecmp(found->variable, cfg->variable))
137 bool get_config_bool(const config_t *cfg, bool *result) {
143 if(!strcasecmp(cfg->value, "yes")) {
146 } else if(!strcasecmp(cfg->value, "no")) {
151 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
152 cfg->variable, cfg->file, cfg->line);
157 bool get_config_int(const config_t *cfg, int *result) {
163 if(sscanf(cfg->value, "%d", result) == 1)
166 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
167 cfg->variable, cfg->file, cfg->line);
172 bool get_config_string(const config_t *cfg, char **result) {
178 *result = xstrdup(cfg->value);
183 bool get_config_address(const config_t *cfg, struct addrinfo **result) {
191 ai = str2addrinfo(cfg->value, NULL, 0);
198 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
199 cfg->variable, cfg->file, cfg->line);
204 bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
205 subnet_t subnet = {0};
212 if(!str2net(&subnet, cfg->value)) {
213 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
214 cfg->variable, cfg->file, cfg->line);
218 /* Teach newbies what subnets are... */
220 if(((subnet.type == SUBNET_IPV4)
221 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
222 || ((subnet.type == SUBNET_IPV6)
223 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) {
224 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
225 cfg->variable, cfg->file, cfg->line);
229 *(*result = new_subnet()) = subnet;
235 Read exactly one line and strip the trailing newline if any. If the
236 file was on EOF, return NULL. Otherwise, return all the data in a
237 dynamically allocated buffer.
239 If line is non-NULL, it will be used as an initial buffer, to avoid
240 unnecessary mallocing each time this function is called. If buf is
241 given, and buf needs to be expanded, the var pointed to by buflen
244 static char *readline(FILE * fp, char **buf, size_t *buflen) {
245 char *newline = NULL;
247 char *line; /* The array that contains everything that has been read so far */
248 char *idx; /* Read into this pointer, which points to an offset within line */
249 size_t size, newsize; /* The size of the current array pointed to by line */
250 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
260 line = xmalloc(size);
269 p = fgets(idx, maxlen, fp);
271 if(!p) { /* EOF or error */
275 /* otherwise: error; let the calling function print an error message if applicable */
280 newline = strchr(p, '\n');
282 if(!newline) { /* We haven't yet read everything to the end of the line */
284 line = xrealloc(line, newsize);
285 idx = &line[size - 1];
286 maxlen = newsize - size + 1;
289 *newline = '\0'; /* kill newline */
290 if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
305 Parse a configuration file and put the results in the configuration tree
308 int read_config_file(splay_tree_t *config_tree, const char *fname) {
309 int err = -2; /* Parse error */
312 char *variable, *value, *eol;
321 fp = fopen(fname, "r");
324 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
330 buffer = xmalloc(bufsize);
338 line = readline(fp, &buffer, &bufsize);
347 if(!*line || *line == '#')
351 if(!strncmp(line, "-----END", 8))
356 if(!strncmp(line, "-----BEGIN", 10)) {
361 variable = value = line;
363 eol = line + strlen(line);
364 while(strchr("\t ", *--eol))
367 len = strcspn(value, "\t =");
369 value += strspn(value, "\t ");
372 value += strspn(value, "\t ");
374 variable[len] = '\0';
378 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
379 variable, lineno, fname);
384 cfg->variable = xstrdup(variable);
385 cfg->value = xstrdup(value);
386 cfg->file = xstrdup(fname);
389 config_add(config_tree, cfg);
398 bool read_server_config() {
404 asprintf(&fname, "%s/tinc.conf", confbase);
405 x = read_config_file(config_tree, fname);
407 if(x == -1) { /* System error: complain */
408 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));