Hm.
[tinc] / lib / conf.c
1 /*
2     conf.c -- configuration storage & retrieval code
3     Copyright (C) 1998 Robert van der Meulen
4                   1998-2002 Ivo Timmermans <ivo@o2w.nl>
5                   2000-2002 Guus Sliepen <guus@sliepen.warande.net>
6                   2000 Cris van Pelt <tribbel@arise.dhs.org>
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: conf.c,v 1.1 2002/04/28 12:46:25 zarq Exp $
23 */
24
25 #include "config.h"
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <netdb.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <string.h>
37
38 #include <xalloc.h>
39 #include <utils.h> /* for cp */
40 #include <avl_tree.h>
41
42 #include "conf.h"
43 #include "netutl.h" /* for str2address */
44 #include "logging.h"
45
46 #include "system.h"
47
48 avl_tree_t *config_tree;
49
50 int pingtimeout = 0;             /* seconds before timeout */
51 char *confbase = NULL;           /* directory in which all config files are */
52 char *netname = NULL;            /* name of the vpn network */
53
54 int config_compare(config_t *a, config_t *b)
55 {
56   int result;
57
58   result = strcasecmp(a->variable, b->variable);
59
60   if(result)
61     return result;
62
63   result = a->line - b->line;
64
65   if(result)
66     return result;
67   else
68     return strcmp(a->file, b->file);
69 }
70
71 void init_configuration(avl_tree_t **config_tree)
72 {
73 cp
74   *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
75 cp
76 }
77
78 void exit_configuration(avl_tree_t **config_tree)
79 {
80 cp
81   avl_delete_tree(*config_tree);
82   *config_tree = NULL;
83 cp
84 }
85
86 config_t *new_config(void)
87 {
88   config_t *cfg;
89 cp
90   cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
91
92   return cfg;
93 }
94
95 void free_config(config_t *cfg)
96 {
97 cp
98   if(cfg->variable)
99     free(cfg->variable);
100   if(cfg->value)
101     free(cfg->value);
102   if(cfg->file)
103     free(cfg->file);
104   free(cfg);
105 cp
106 }
107
108 void config_add(avl_tree_t *config_tree, config_t *cfg)
109 {
110 cp
111   avl_insert(config_tree, cfg);
112 cp
113 }
114
115 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
116 {
117   config_t cfg, *found;
118 cp
119   cfg.variable = variable;
120   cfg.file = "";
121   cfg.line = 0;
122
123   found = avl_search_closest_greater(config_tree, &cfg);
124
125   if(!found)
126     return NULL;
127
128   if(strcasecmp(found->variable, variable))
129     return NULL;
130
131   return found;
132 }
133
134 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
135 {
136   avl_node_t *node;
137   config_t *found;
138 cp
139   node = avl_search_node(config_tree, cfg);
140
141   if(node)
142     {
143       if(node->next)
144         {
145           found = (config_t *)node->next->data;
146           if(!strcasecmp(found->variable, cfg->variable))
147             return found;
148         }
149     }
150
151   return NULL;
152 }
153
154 int get_config_bool(config_t *cfg, int *result)
155 {
156 cp
157   if(!cfg)
158     return 0;
159
160   if(!strcasecmp(cfg->value, "yes"))
161     {
162       *result = 1;
163       return 1;
164     }
165   else if(!strcasecmp(cfg->value, "no"))
166     {
167       *result = 0;
168       return 1;
169     }
170
171   syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
172          cfg->variable, cfg->file, cfg->line);
173
174   return 0;
175 }
176
177 int get_config_int(config_t *cfg, int *result)
178 {
179 cp
180   if(!cfg)
181     return 0;
182
183   if(sscanf(cfg->value, "%d", result) == 1)
184     return 1;
185
186   syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
187          cfg->variable, cfg->file, cfg->line);
188   return 0;
189 }
190
191 int get_config_string(config_t *cfg, char **result)
192 {
193 cp
194   if(!cfg)
195     return 0;
196
197   *result = xstrdup(cfg->value);
198   return 1;
199 }
200
201 int get_config_address(config_t *cfg, struct addrinfo **result)
202 {
203   struct addrinfo *ai;
204 cp
205   if(!cfg)
206     return 0;
207
208   ai = str2addrinfo(cfg->value, NULL, 0);
209
210   if(ai)
211     {
212       *result = ai;
213       return 1;
214     }
215
216   syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
217          cfg->variable, cfg->file, cfg->line);
218   return 0;
219 }
220
221 int get_config_port(config_t *cfg, port_t *result)
222 {
223 cp
224   if(!cfg)
225     return 0;
226
227   if(sscanf(cfg->value, "%hu", result) == 1)
228     {
229       *result = htons(*result);
230       return 1;
231     }
232
233   syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
234          cfg->variable, cfg->file, cfg->line);
235   return 0;
236 }
237
238 int get_config_subnet(config_t *cfg, subnet_t **result)
239 {
240   subnet_t *subnet;
241 cp
242   if(!cfg)
243     return 0;
244
245   subnet = str2net(cfg->value);
246
247   if(!subnet)
248     {
249       syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
250              cfg->variable, cfg->file, cfg->line);
251       return 0;
252     }
253
254   /* Teach newbies what subnets are... */
255
256   if(((subnet->type == SUBNET_IPV4) && maskcheck((char *)&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
257      || ((subnet->type == SUBNET_IPV6) && maskcheck((char *)&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))))
258     {
259       syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"),
260              cfg->variable, cfg->file, cfg->line);
261       free(subnet);
262       return 0;
263     }
264
265   *result = subnet;
266
267   return 1;
268 }
269