Add a better autoconf check for libevent.
[tinc] / src / conf.c
1 /*
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>
6                   2000 Cris van Pelt
7
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.
12
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.
17
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.
21
22     $Id$
23 */
24
25 #include "system.h"
26
27 #include "splay_tree.h"
28 #include "conf.h"
29 #include "logger.h"
30 #include "netutl.h"                             /* for str2address */
31 #include "utils.h"                              /* for cp */
32 #include "xalloc.h"
33
34 splay_tree_t *config_tree;
35
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 */
40
41 static int config_compare(const config_t *a, const config_t *b) {
42         int result;
43
44         result = strcasecmp(a->variable, b->variable);
45
46         if(result)
47                 return result;
48
49         result = a->line - b->line;
50
51         if(result)
52                 return result;
53         else
54                 return strcmp(a->file, b->file);
55 }
56
57 void init_configuration(splay_tree_t ** config_tree) {
58         cp();
59
60         *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
61 }
62
63 void exit_configuration(splay_tree_t ** config_tree) {
64         cp();
65
66         splay_delete_tree(*config_tree);
67         *config_tree = NULL;
68 }
69
70 config_t *new_config(void) {
71         cp();
72
73         return xmalloc_and_zero(sizeof(config_t));
74 }
75
76 void free_config(config_t *cfg) {
77         cp();
78
79         if(cfg->variable)
80                 free(cfg->variable);
81
82         if(cfg->value)
83                 free(cfg->value);
84
85         if(cfg->file)
86                 free(cfg->file);
87
88         free(cfg);
89 }
90
91 void config_add(splay_tree_t *config_tree, config_t *cfg) {
92         cp();
93
94         splay_insert(config_tree, cfg);
95 }
96
97 config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
98         config_t cfg, *found;
99
100         cp();
101
102         cfg.variable = variable;
103         cfg.file = "";
104         cfg.line = 0;
105
106         found = splay_search_closest_greater(config_tree, &cfg);
107
108         if(!found)
109                 return NULL;
110
111         if(strcasecmp(found->variable, variable))
112                 return NULL;
113
114         return found;
115 }
116
117 config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
118         splay_node_t *node;
119         config_t *found;
120
121         cp();
122
123         node = splay_search_node(config_tree, cfg);
124
125         if(node) {
126                 if(node->next) {
127                         found = node->next->data;
128
129                         if(!strcasecmp(found->variable, cfg->variable))
130                                 return found;
131                 }
132         }
133
134         return NULL;
135 }
136
137 bool get_config_bool(const config_t *cfg, bool *result) {
138         cp();
139
140         if(!cfg)
141                 return false;
142
143         if(!strcasecmp(cfg->value, "yes")) {
144                 *result = true;
145                 return true;
146         } else if(!strcasecmp(cfg->value, "no")) {
147                 *result = false;
148                 return true;
149         }
150
151         logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
152                    cfg->variable, cfg->file, cfg->line);
153
154         return false;
155 }
156
157 bool get_config_int(const config_t *cfg, int *result) {
158         cp();
159
160         if(!cfg)
161                 return false;
162
163         if(sscanf(cfg->value, "%d", result) == 1)
164                 return true;
165
166         logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
167                    cfg->variable, cfg->file, cfg->line);
168
169         return false;
170 }
171
172 bool get_config_string(const config_t *cfg, char **result) {
173         cp();
174
175         if(!cfg)
176                 return false;
177
178         *result = xstrdup(cfg->value);
179
180         return true;
181 }
182
183 bool get_config_address(const config_t *cfg, struct addrinfo **result) {
184         struct addrinfo *ai;
185
186         cp();
187
188         if(!cfg)
189                 return false;
190
191         ai = str2addrinfo(cfg->value, NULL, 0);
192
193         if(ai) {
194                 *result = ai;
195                 return true;
196         }
197
198         logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
199                    cfg->variable, cfg->file, cfg->line);
200
201         return false;
202 }
203
204 bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
205         subnet_t subnet = {0};
206
207         cp();
208
209         if(!cfg)
210                 return false;
211
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);
215                 return false;
216         }
217
218         /* Teach newbies what subnets are... */
219
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);
226                 return false;
227         }
228
229         *(*result = new_subnet()) = subnet;
230
231         return true;
232 }
233
234 /*
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.
238
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
242   will be increased.
243 */
244 static char *readline(FILE * fp, char **buf, size_t *buflen) {
245         char *newline = NULL;
246         char *p;
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. */
251
252         if(feof(fp))
253                 return NULL;
254
255         if(buf && buflen) {
256                 size = *buflen;
257                 line = *buf;
258         } else {
259                 size = 100;
260                 line = xmalloc(size);
261         }
262
263         maxlen = size;
264         idx = line;
265         *idx = 0;
266
267         for(;;) {
268                 errno = 0;
269                 p = fgets(idx, maxlen, fp);
270
271                 if(!p) {                                /* EOF or error */
272                         if(feof(fp))
273                                 break;
274
275                         /* otherwise: error; let the calling function print an error message if applicable */
276                         free(line);
277                         return NULL;
278                 }
279
280                 newline = strchr(p, '\n');
281
282                 if(!newline) {                  /* We haven't yet read everything to the end of the line */
283                         newsize = size << 1;
284                         line = xrealloc(line, newsize);
285                         idx = &line[size - 1];
286                         maxlen = newsize - size + 1;
287                         size = newsize;
288                 } else {
289                         *newline = '\0';        /* kill newline */
290                         if(newline > p && newline[-1] == '\r')  /* and carriage return if necessary */
291                                 newline[-1] = '\0';
292                         break;                          /* yay */
293                 }
294         }
295
296         if(buf && buflen) {
297                 *buflen = size;
298                 *buf = line;
299         }
300
301         return line;
302 }
303
304 /*
305   Parse a configuration file and put the results in the configuration tree
306   starting at *base.
307 */
308 int read_config_file(splay_tree_t *config_tree, const char *fname) {
309         int err = -2;                           /* Parse error */
310         FILE *fp;
311         char *buffer, *line;
312         char *variable, *value, *eol;
313         int lineno = 0;
314         int len;
315         bool ignore = false;
316         config_t *cfg;
317         size_t bufsize;
318
319         cp();
320
321         fp = fopen(fname, "r");
322
323         if(!fp) {
324                 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
325                            strerror(errno));
326                 return -3;
327         }
328
329         bufsize = 100;
330         buffer = xmalloc(bufsize);
331
332         for(;;) {
333                 if(feof(fp)) {
334                         err = 0;
335                         break;
336                 }
337
338                 line = readline(fp, &buffer, &bufsize);
339
340                 if(!line) {
341                         err = -1;
342                         break;
343                 }
344
345                 lineno++;
346
347                 if(!*line || *line == '#')
348                         continue;
349
350                 if(ignore) {
351                         if(!strncmp(line, "-----END", 8))
352                                 ignore = false;
353                         continue;
354                 }
355                 
356                 if(!strncmp(line, "-----BEGIN", 10)) {
357                         ignore = true;
358                         continue;
359                 }
360
361                 variable = value = line;
362
363                 eol = line + strlen(line);
364                 while(strchr("\t ", *--eol))
365                         *eol = '\0';
366
367                 len = strcspn(value, "\t =");
368                 value += len;
369                 value += strspn(value, "\t ");
370                 if(*value == '=') {
371                         value++;
372                         value += strspn(value, "\t ");
373                 }
374                 variable[len] = '\0';
375
376         
377                 if(!*value) {
378                         logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
379                                    variable, lineno, fname);
380                         break;
381                 }
382
383                 cfg = new_config();
384                 cfg->variable = xstrdup(variable);
385                 cfg->value = xstrdup(value);
386                 cfg->file = xstrdup(fname);
387                 cfg->line = lineno;
388
389                 config_add(config_tree, cfg);
390         }
391
392         free(buffer);
393         fclose(fp);
394
395         return err;
396 }
397
398 bool read_server_config() {
399         char *fname;
400         int x;
401
402         cp();
403
404         xasprintf(&fname, "%s/tinc.conf", confbase);
405         x = read_config_file(config_tree, fname);
406
407         if(x == -1) {                           /* System error: complain */
408                 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
409         }
410
411         free(fname);
412
413         return x == 0;
414 }