Moving files, first attempt at gcrypt compatibility, more interface
[tinc] / src / read_conf.c
1 /*
2     read_conf.c -- read the configuration files
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: read_conf.c,v 1.1 2002/04/28 12:46:26 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 /*
49   Read exactly one line and strip the trailing newline if any.  If the
50   file was on EOF, return NULL. Otherwise, return all the data in a
51   dynamically allocated buffer.
52
53   If line is non-NULL, it will be used as an initial buffer, to avoid
54   unnecessary mallocing each time this function is called.  If buf is
55   given, and buf needs to be expanded, the var pointed to by buflen
56   will be increased.
57 */
58 char *readline(FILE *fp, char **buf, size_t *buflen)
59 {
60   char *newline = NULL;
61   char *p;
62   char *line; /* The array that contains everything that has been read
63                  so far */
64   char *idx; /* Read into this pointer, which points to an offset
65                 within line */
66   size_t size, newsize; /* The size of the current array pointed to by
67                            line */
68   size_t maxlen; /* Maximum number of characters that may be read with
69                     fgets.  This is newsize - oldsize. */
70
71   if(feof(fp))
72     return NULL;
73
74   if((buf != NULL) && (buflen != NULL))
75     {
76       size = *buflen;
77       line = *buf;
78     }
79   else
80     {
81       size = 100;
82       line = xmalloc(size);
83     }
84
85   maxlen = size;
86   idx = line;
87   *idx = 0;
88   for(;;)
89     {
90       errno = 0;
91       p = fgets(idx, maxlen, fp);
92       if(p == NULL)  /* EOF or error */
93         {
94           if(feof(fp))
95             break;
96
97           /* otherwise: error; let the calling function print an error
98              message if applicable */
99           free(line);
100           return NULL;
101         }
102
103       newline = strchr(p, '\n');
104       if(newline == NULL)
105         /* We haven't yet read everything to the end of the line */
106         {
107           newsize = size << 1;
108           line = xrealloc(line, newsize);
109           idx = &line[size - 1];
110           maxlen = newsize - size + 1;
111           size = newsize;
112         }
113       else
114         {
115           *newline = '\0'; /* kill newline */
116           break;  /* yay */
117         }
118     }
119
120   if((buf != NULL) && (buflen != NULL))
121     {
122       *buflen = size;
123       *buf = line;
124     }
125   return line;
126 }
127
128 /*
129   Parse a configuration file and put the results in the configuration tree
130   starting at *base.
131 */
132 int read_config_file(avl_tree_t *config_tree, const char *fname)
133 {
134   int err = -2; /* Parse error */
135   FILE *fp;
136   char *buffer, *line;
137   char *variable, *value;
138   int lineno = 0, ignore = 0;
139   config_t *cfg;
140   size_t bufsize;
141
142 cp
143   if((fp = fopen (fname, "r")) == NULL)
144     {
145       syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
146       return -3;
147     }
148
149   bufsize = 100;
150   buffer = xmalloc(bufsize);
151
152   for(;;)
153     {
154       if((line = readline(fp, &buffer, &bufsize)) == NULL)
155         {
156           err = -1;
157           break;
158         }
159
160       if(feof(fp))
161         {
162           err = 0;
163           break;
164         }
165
166       lineno++;
167
168       if((variable = strtok(line, "\t =")) == NULL)
169         continue; /* no tokens on this line */
170
171       if(variable[0] == '#')
172         continue; /* comment: ignore */
173
174       if(!strcmp(variable, "-----BEGIN"))
175         ignore = 1;
176
177       if(!ignore)
178         {
179           if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
180             {
181               syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
182                       variable, lineno, fname);
183               break;
184             }
185
186           cfg = new_config();
187           cfg->variable = xstrdup(variable);
188           cfg->value = xstrdup(value);
189           cfg->file = xstrdup(fname);
190           cfg->line = lineno;
191
192           config_add(config_tree, cfg);
193        }
194
195       if(!strcmp(variable, "-----END"))
196         ignore = 0;
197     }
198
199   free(buffer);
200   fclose (fp);
201 cp
202   return err;
203 }
204
205 int read_server_config()
206 {
207   char *fname;
208   int x;
209 cp
210   asprintf(&fname, "%s/tinc.conf", confbase);
211   x = read_config_file(config_tree, fname);
212   if(x == -1) /* System error: complain */
213     {
214       syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
215     }
216   free(fname);
217 cp
218   return x;
219 }
220
221 int isadir(const char* f)
222 {
223   struct stat s;
224
225   if(stat(f, &s) < 0)
226     return 0;
227   else
228     return S_ISDIR(s.st_mode);
229 }
230
231 int is_safe_path(const char *file)
232 {
233   char *p;
234   const char *f;
235   char x;
236   struct stat s;
237   char l[MAXBUFSIZE];
238
239   if(*file != '/')
240     {
241       syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
242       return 0;
243     }
244
245   p = strrchr(file, '/');
246
247   if(p == file)         /* It's in the root */
248     p++;
249
250   x = *p;
251   *p = '\0';
252
253   f = file;
254 check1:
255   if(lstat(f, &s) < 0)
256     {
257       syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
258       return 0;
259     }
260
261   if(s.st_uid != geteuid())
262     {
263       syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
264               f, s.st_uid, geteuid());
265       return 0;
266     }
267
268   if(S_ISLNK(s.st_mode))
269     {
270       syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
271               f);
272
273       if(readlink(f, l, MAXBUFSIZE) < 0)
274         {
275           syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
276           return 0;
277         }
278
279       f = l;
280       goto check1;
281     }
282
283   *p = x;
284   f = file;
285
286 check2:
287   if(lstat(f, &s) < 0 && errno != ENOENT)
288     {
289       syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
290       return 0;
291     }
292
293   if(errno == ENOENT)
294     return 1;
295
296   if(s.st_uid != geteuid())
297     {
298       syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
299               f, s.st_uid, geteuid());
300       return 0;
301     }
302
303   if(S_ISLNK(s.st_mode))
304     {
305       syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
306               f);
307
308       if(readlink(f, l, MAXBUFSIZE) < 0)
309         {
310           syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
311           return 0;
312         }
313
314       f = l;
315       goto check2;
316     }
317
318   if(s.st_mode & 0007)
319     {
320       /* Accessible by others */
321       syslog(LOG_ERR, _("`%s' has unsecure permissions"),
322               f);
323       return 0;
324     }
325
326   return 1;
327 }
328
329 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
330 {
331   FILE *r;
332   char *directory;
333   char *fn;
334
335   /* Check stdin and stdout */
336   if(!isatty(0) || !isatty(1))
337     {
338       /* Argh, they are running us from a script or something.  Write
339          the files to the current directory and let them burn in hell
340          for ever. */
341       fn = xstrdup(filename);
342     }
343   else
344     {
345       /* Ask for a file and/or directory name. */
346       fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
347               what, filename);
348       fflush(stdout);
349
350       if((fn = readline(stdin, NULL, NULL)) == NULL)
351         {
352           fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
353           return NULL;
354         }
355
356       if(strlen(fn) == 0)
357         /* User just pressed enter. */
358         fn = xstrdup(filename);
359     }
360
361   if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
362     {
363       /* The directory is a relative path or a filename. */
364       char *p;
365
366       directory = get_current_dir_name();
367       asprintf(&p, "%s/%s", directory, fn);
368       free(fn);
369       free(directory);
370       fn = p;
371     }
372
373   umask(0077); /* Disallow everything for group and other */
374
375   /* Open it first to keep the inode busy */
376   if((r = fopen(fn, mode)) == NULL)
377     {
378       fprintf(stderr, _("Error opening file `%s': %s\n"),
379               fn, strerror(errno));
380       free(fn);
381       return NULL;
382     }
383
384   /* Then check the file for nasty attacks */
385   if(!is_safe_path(fn))  /* Do not permit any directories that are
386                             readable or writeable by other users. */
387     {
388       fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
389                         "I will not create or overwrite this file.\n"),
390                         fn);
391       fclose(r);
392       free(fn);
393       return NULL;
394     }
395
396   free(fn);
397
398   return r;
399 }
400
401 int read_connection_config(connection_t *c)
402 {
403   char *fname;
404   int x;
405 cp
406   asprintf(&fname, "%s/hosts/%s", confbase, c->name);
407   x = read_config_file(c->config_tree, fname);
408   free(fname);
409 cp
410   return x;
411 }