Also free the pointer returned by readline().
[tinc] / src / conf.c
1 /*
2     conf.c -- configuration code
3     Copyright (C) 1998 Robert van der Meulen
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.26 2000/11/29 14:30:07 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 <syslog.h>
34
35 #include <xalloc.h>
36 #include <utils.h> /* for cp */
37
38 #include "conf.h"
39 #include "netutl.h" /* for strtoip */
40
41 #include "system.h"
42
43 config_t *config = NULL;
44 int debug_lvl = 0;
45 int timeout = 0; /* seconds before timeout */
46 char *confbase = NULL;           /* directory in which all config files are */
47 char *netname = NULL;            /* name of the vpn network */
48
49 /* Will be set if HUP signal is received. It will be processed when it is safe. */
50 int sighup = 0;
51
52 /*
53   These are all the possible configurable values
54 */
55 static internal_config_t hazahaza[] = {
56 /* Main configuration file keywords */
57   { "Name",         config_name,       TYPE_NAME },
58   { "ConnectTo",    config_connectto,      TYPE_NAME },
59   { "PingTimeout",  config_pingtimeout,    TYPE_INT },
60   { "TapDevice",    config_tapdevice,      TYPE_NAME },
61   { "PrivateKey",   config_privatekey,     TYPE_NAME },
62   { "KeyExpire",    config_keyexpire,      TYPE_INT },
63   { "Hostnames",    config_hostnames,    TYPE_BOOL },
64   { "Interface",    config_interface,      TYPE_NAME },
65   { "InterfaceIP",  config_interfaceip,    TYPE_IP },
66 /* Host configuration file keywords */
67   { "Address",      config_address,        TYPE_NAME },
68   { "Port",         config_port,           TYPE_INT },
69   { "PublicKey",    config_publickey,      TYPE_NAME },
70   { "Subnet",       config_subnet,         TYPE_IP },           /* Use IPv4 subnets only for now */
71   { "RestrictHosts", config_restricthosts, TYPE_BOOL },
72   { "RestrictSubnets", config_restrictsubnets, TYPE_BOOL },
73   { "RestrictAddress", config_restrictaddress, TYPE_BOOL },
74   { "RestrictPort", config_restrictport,   TYPE_BOOL },
75   { "IndirectData", config_indirectdata,   TYPE_BOOL },
76   { "TCPonly",      config_tcponly,        TYPE_BOOL },
77   { NULL, 0, 0 }
78 };
79
80 /*
81   Add given value to the list of configs cfg
82 */
83 config_t *
84 add_config_val(config_t **cfg, int argtype, char *val)
85 {
86   config_t *p;
87   char *q;
88 cp
89   p = (config_t*)xmalloc(sizeof(*p));
90   p->data.val = 0;
91
92   switch(argtype)
93     {
94     case TYPE_INT:
95       p->data.val = strtol(val, &q, 0);
96       if(q && *q)
97         p->data.val = 0;
98       break;
99     case TYPE_NAME:
100       p->data.ptr = xmalloc(strlen(val) + 1);
101       strcpy(p->data.ptr, val);
102       break;
103     case TYPE_IP:
104       p->data.ip = strtoip(val);
105       break;
106     case TYPE_BOOL:
107       if(!strcasecmp("yes", val))
108         p->data.val = stupid_true;
109       else if(!strcasecmp("no", val))
110         p->data.val = stupid_false;
111       else
112         p->data.val = 0;
113     }
114
115   p->argtype = argtype;
116
117   if(p->data.val)
118     {
119       p->next = *cfg;
120       *cfg = p;
121 cp
122       return p;
123     }
124   else
125     {
126       free(p);
127 cp
128       return NULL;
129     }
130 }
131
132 /*
133   Read exactly one line and strip the trailing newline if any.  If the
134   file was on EOF, return NULL. Otherwise, return all the data in a
135   dynamically allocated buffer.
136 */
137 char *readline(FILE *fp)
138 {
139   char *newline = NULL;
140   char *p;
141   char *line; /* The array that contains everything that has been read
142                  so far */
143   char *idx; /* Read into this pointer, which points to an offset
144                 within line */
145   size_t size, newsize; /* The size of the current array pointed to by
146                            line */
147   size_t maxlen; /* Maximum number of characters that may be read with
148                     fgets.  This is newsize - oldsize. */
149
150   if(feof(fp))
151     return NULL;
152   
153   size = 100;
154   maxlen = size;
155   line = xmalloc(size);
156   idx = line;
157   for(;;)
158     {
159       errno = 0;
160       p = fgets(idx, maxlen, fp);
161       if(p == NULL)  /* EOF or error */
162         {
163           if(feof(fp))
164             break;
165
166           /* otherwise: error; let the calling function print an error
167              message if applicable */
168           free(line);
169           return NULL;
170         }
171
172       newline = strchr(p, '\n');
173       if(newline == NULL)
174         /* We haven't yet read everything to the end of the line */
175         {
176           newsize = size << 1;
177           line = xrealloc(line, newsize);
178           idx = &line[size - 1];
179           maxlen = newsize - size + 1;
180           size = newsize;
181         }
182       else
183         {
184           *newline = '\0'; /* kill newline */
185           break;  /* yay */
186         }
187     }
188
189   return line;
190 }
191
192 /*
193   Parse a configuration file and put the results in the configuration tree
194   starting at *base.
195 */
196 int read_config_file(config_t **base, const char *fname)
197 {
198   int err = -1;
199   FILE *fp;
200   char *line;
201   char *p, *q;
202   int i, lineno = 0;
203   config_t *cfg;
204 cp
205   if((fp = fopen (fname, "r")) == NULL)
206     {
207       return -1;
208     }
209
210   for(;;)
211     {
212       if((line = readline(fp)) == NULL)
213         {
214           err = -1;
215           break;
216         }
217         
218       lineno++;
219
220       if((p = strtok(line, "\t =")) == NULL)
221         continue; /* no tokens on this line */
222
223       if(p[0] == '#')
224         continue; /* comment: ignore */
225
226       for(i = 0; hazahaza[i].name != NULL; i++)
227         if(!strcasecmp(hazahaza[i].name, p))
228           break;
229
230       if(!hazahaza[i].name)
231         {
232           syslog(LOG_ERR, _("Invalid variable name on line %d while reading config file %s"),
233                   lineno, fname);
234           break;
235         }
236
237       if(((q = strtok(NULL, "\t\n\r =")) == NULL) || q[0] == '#')
238         {
239           fprintf(stderr, _("No value for variable on line %d while reading config file %s"),
240                   lineno, fname);
241           break;
242         }
243
244       cfg = add_config_val(base, hazahaza[i].argtype, q);
245       if(cfg == NULL)
246         {
247           fprintf(stderr, _("Invalid value for variable on line %d while reading config file %s"),
248                   lineno, fname);
249           break;
250         }
251
252       cfg->which = hazahaza[i].which;
253       if(!config)
254         config = cfg;
255       free(line);
256     }
257
258   free(line);
259   fclose (fp);
260 cp
261   return err;
262 }
263
264 int read_server_config()
265 {
266   char *fname;
267   int x;
268 cp
269   asprintf(&fname, "%s/tinc.conf", confbase);
270   x = read_config_file(&config, fname);
271   if(x != 0)
272     {
273       fprintf(stderr, _("Failed to read `%s': %m\n"),
274               fname);
275     }
276   free(fname);
277 cp
278   return x;  
279 }
280
281 /*
282   Look up the value of the config option type
283 */
284 const config_t *get_config_val(config_t *p, which_t type)
285 {
286 cp
287   for(; p != NULL; p = p->next)
288     if(p->which == type)
289       break;
290 cp
291   return p;
292 }
293
294 /*
295   Remove the complete configuration tree.
296 */
297 void clear_config(config_t **base)
298 {
299   config_t *p, *next;
300 cp
301   for(p = *base; p != NULL; p = next)
302     {
303       next = p->next;
304       if(p->data.ptr && (p->argtype == TYPE_NAME))
305         {
306           free(p->data.ptr);
307         }
308       free(p);
309     }
310   *base = NULL;
311 cp
312 }
313
314 #define is_safe_file(p) 1
315
316 FILE *ask_and_safe_open(const char* filename, const char* what)
317 {
318   FILE *r;
319   char *directory;
320   char *fn;
321   int len;
322
323   /* Check stdin and stdout */
324   if(!isatty(0) || !isatty(1))
325     {
326       /* Argh, they are running us from a script or something.  Write
327          the files to the current directory and let them burn in hell
328          for ever. */
329       fn = xstrdup(filename);
330     }
331   else
332     {
333       /* Ask for a file and/or directory name. */
334       fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
335               what, filename);
336       fflush(stdout);  /* Don't wait for a newline */
337       if((fn = readline(stdin)) == NULL)
338         {
339           fprintf(stderr, _("Error while reading stdin: %m\n"));
340           return NULL;
341         }
342       if(strlen(fn) == 0)
343         /* User just pressed enter. */
344         fn = xstrdup(filename);
345     }
346
347   if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
348     {
349       /* The directory is a relative path or a filename. */
350       char *p;
351       
352       directory = get_current_dir_name();
353       len = strlen(fn) + strlen(directory) + 2; /* 1 for the / */
354       p = xmalloc(len);
355       snprintf(p, len, "%s/%s", directory, fn);
356       free(fn);
357       fn = p;
358     }
359
360   if(!is_safe_file(fn))
361     {
362       fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
363                         "I will not create or overwrite this file.\n"),
364                         fn);
365       return NULL;
366     }
367
368   if((r = fopen(fn, "w")) == NULL)
369     {
370       fprintf(stderr, _("Error opening file `%s': %m\n"),
371               fn);
372     }
373
374   free(fn);
375   free(directory);
376   
377   return r;
378 }