- Generalized config file parsing to support multiple configuration trees.
[oweals/tinc.git] / src / conf.c
1 /*
2     conf.c -- configuration code
3     Copyright (C) 1998 Emphyrio,
4     Copyright (C) 1998,1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>
5                             2000 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.9.4.11 2000/10/11 13:42:52 guus Exp $
23 */
24
25
26 #include "config.h"
27
28 #include <ctype.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <xalloc.h>
36
37 #include "conf.h"
38 #include "netutl.h" /* for strtoip */
39 #include <utils.h> /* for cp */
40
41 #include "system.h"
42
43 config_t *config;
44 int debug_lvl = 0;
45 int timeout = 0; /* seconds before timeout */
46 char *configfilename = NULL;
47
48 /* Will be set if HUP signal is received. It will be processed when it is safe. */
49 int sighup = 0;
50
51 /*
52   These are all the possible configurable values
53 */
54 static internal_config_t hazahaza[] = {
55 /* Main configuration file keywords */
56   { "Name",         tincname,       TYPE_NAME },
57   { "ConnectTo",    connectto,      TYPE_NAME },
58   { "PingTimeout",  pingtimeout,    TYPE_INT },
59   { "TapDevice",    tapdevice,      TYPE_NAME },
60   { "PrivateKey",   privatekey,     TYPE_NAME },
61   { "KeyExpire",    keyexpire,      TYPE_INT },
62   { "Hostnames",    resolve_dns,    TYPE_BOOL },
63   { "Interface",    interface,      TYPE_NAME },
64   { "InterfaceIP",  interfaceip,    TYPE_IP },
65 /* Host configuration file keywords */
66   { "Address",      address,        TYPE_NAME },
67   { "Port",         port,           TYPE_INT },
68   { "PublicKey",    publickey,      TYPE_NAME },
69   { "Subnet",       subnet,         TYPE_NAME },
70   { "RestrictHosts", restricthosts, TYPE_BOOL },
71   { "RestrictSubnets", restrictsubnets, TYPE_BOOL },
72   { "RestrictAddress", restrictaddress, TYPE_BOOL },
73   { "RestrictPort", restrictport,   TYPE_BOOL },
74   { "IndirectData", indirectdata,   TYPE_BOOL },
75   { "TCPonly",      tcponly,        TYPE_BOOL },
76   { NULL, 0, 0 }
77 };
78
79 /*
80   Add given value to the list of configs cfg
81 */
82 config_t *
83 add_config_val(config_t **cfg, int argtype, char *val)
84 {
85   config_t *p, *r;
86   char *q;
87 cp
88   p = (config_t*)xmalloc(sizeof(*p));
89   p->data.val = 0;
90   
91   switch(argtype)
92     {
93     case TYPE_INT:
94       p->data.val = strtol(val, &q, 0);
95       if(q && *q)
96         p->data.val = 0;
97       break;
98     case TYPE_NAME:
99       p->data.ptr = xmalloc(strlen(val) + 1);
100       strcpy(p->data.ptr, val);
101       break;
102     case TYPE_IP:
103       p->data.ip = strtoip(val);
104       break;
105     case TYPE_BOOL:
106       if(!strcasecmp("yes", val))
107         p->data.val = stupid_true;
108       else if(!strcasecmp("no", val))
109         p->data.val = stupid_false;
110       else
111         p->data.val = 0;
112     }
113
114   p->argtype = argtype;
115
116   if(p->data.val)
117     {
118       if(*cfg)
119         {
120           r = *cfg;
121           while(r->next)
122             r = r->next;
123           r->next = p;
124         }
125       else
126         *cfg = p;
127       p->next = NULL;
128       return p;
129     }
130
131   free(p);
132 cp
133   return NULL;
134 }
135
136 /*
137   Parse a configuration file and put the results in the configuration tree
138   starting at *base.
139 */
140 int read_config_file(config_t **base, const char *fname)
141 {
142   int err;
143   FILE *fp;
144   char line[MAXBUFSIZE];        /* There really should not be any line longer than this... */
145   char *p, *q;
146   int i, err = -1, lineno = 0;
147   config_t *cfg;
148 cp
149   if((fp = fopen (fname, "r")) == NULL)
150     {
151       return -1;
152     }
153
154   for(;;)
155     {
156       if(fgets(line, MAXBUFSIZE, fp) == NULL)
157         {
158           err = 0;
159           break;
160         }
161         
162       lineno++;
163
164       if(!index(line, '\n'))
165         {
166           syslog(LOG_ERR, _("Line %d too long while reading config file %s"), lineno, fname);
167           break;
168         }        
169
170       if((p = strtok(line, "\t\n\r =")) == NULL)
171         continue; /* no tokens on this line */
172
173       if(p[0] == '#')
174         continue; /* comment: ignore */
175
176       for(i = 0; hazahaza[i].name != NULL; i++)
177         if(!strcasecmp(hazahaza[i].name, p))
178           break;
179
180       if(!hazahaza[i].name)
181         {
182           syslog(LOG_ERR, _("Invalid variable name on line %d while reading config file %s"),
183                   lineno, fname);
184           break;
185         }
186
187       if(((q = strtok(NULL, "\t\n\r =")) == NULL) || q[0] == '#')
188         {
189           fprintf(stderr, _("No value for variable on line %d while reading config file %s"),
190                   lineno, fname);
191           break;
192         }
193
194       cfg = add_config_val(base, hazahaza[i].argtype, q);
195       if(cfg == NULL)
196         {
197           fprintf(stderr, _("Invalid value for variable on line %d while reading config file %s"),
198                   lineno, fname);
199           break;
200         }
201
202       cfg->which = hazahaza[i].which;
203       if(!config)
204         config = cfg;
205     }
206
207   fclose (fp);
208 cp
209   return err;
210 }
211
212 /*
213   Look up the value of the config option type
214 */
215 const config_t *get_config_val(config_t *p, which_t type)
216 {
217 cp
218   for(p = config; p != NULL; p = p->next)
219     if(p->which == type)
220       return p;
221 cp
222   /* Not found */
223   return NULL;
224 }
225
226 /*
227   Support for multiple config lines.
228   Index is used to get a specific value, 0 being the first, 1 the second etc.
229 */
230 const config_t *get_next_config_val(config_t *p, which_t type, int index)
231 {
232 cp  
233   for(p = config; p != NULL; p = p->next)
234     if(p->which == type)
235       if(--index < 0)
236         return p;
237 cp  
238   /* Not found */
239   return NULL;
240 }
241
242 /*
243   Remove the complete configuration tree.
244 */
245 void clear_config(config_t **base)
246 {
247   config_t *p, *next;
248 cp
249   for(p = *base; p != NULL; p = next)
250     {
251       next = p->next;
252       if(p->data.ptr && (p->argtype == TYPE_NAME))
253         {
254           free(p->data.ptr);
255         }
256       free(p);
257     }
258   *base = NULL;
259 cp
260 }