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>
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.
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.
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.
22 $Id: conf.c,v 1.9.4.33 2000/12/05 08:56:44 zarq Exp $
36 #include <sys/types.h>
40 #include <utils.h> /* for cp */
43 #include "netutl.h" /* for strtoip */
47 config_t *config = NULL;
49 int timeout = 0; /* seconds before timeout */
50 char *confbase = NULL; /* directory in which all config files are */
51 char *netname = NULL; /* name of the vpn network */
53 /* Will be set if HUP signal is received. It will be processed when it is safe. */
57 These are all the possible configurable values
59 static internal_config_t hazahaza[] = {
60 /* Main configuration file keywords */
61 { "ConnectTo", config_connectto, TYPE_NAME },
62 { "Hostnames", config_hostnames, TYPE_BOOL },
63 { "Interface", config_interface, TYPE_NAME },
64 { "InterfaceIP", config_interfaceip, TYPE_IP },
65 { "KeyExpire", config_keyexpire, TYPE_INT },
66 { "Name", config_name, TYPE_NAME },
67 { "PingTimeout", config_pingtimeout, TYPE_INT },
68 { "PrivateKey", config_privatekey, TYPE_NAME },
69 { "TapDevice", config_tapdevice, TYPE_NAME },
70 /* Host configuration file keywords */
71 { "Address", config_address, TYPE_NAME },
72 { "IndirectData", config_indirectdata, TYPE_BOOL },
73 { "Port", config_port, TYPE_INT },
74 { "PublicKey", config_publickey, TYPE_NAME },
75 { "RestrictAddress", config_restrictaddress, TYPE_BOOL },
76 { "RestrictHosts", config_restricthosts, TYPE_BOOL },
77 { "RestrictPort", config_restrictport, TYPE_BOOL },
78 { "RestrictSubnets", config_restrictsubnets, TYPE_BOOL },
79 { "Subnet", config_subnet, TYPE_IP }, /* Use IPv4 subnets only for now */
80 { "TCPonly", config_tcponly, TYPE_BOOL },
85 Add given value to the list of configs cfg
88 add_config_val(config_t **cfg, int argtype, char *val)
93 p = (config_t*)xmalloc(sizeof(*p));
99 p->data.val = strtol(val, &q, 0);
104 p->data.ptr = xmalloc(strlen(val) + 1);
105 strcpy(p->data.ptr, val);
108 p->data.ip = strtoip(val);
111 if(!strcasecmp("yes", val))
112 p->data.val = stupid_true;
113 else if(!strcasecmp("no", val))
114 p->data.val = stupid_false;
119 p->argtype = argtype;
137 Read exactly one line and strip the trailing newline if any. If the
138 file was on EOF, return NULL. Otherwise, return all the data in a
139 dynamically allocated buffer.
141 If line is non-NULL, it will be used as an initial buffer, to avoid
142 unnecessary mallocing each time this function is called. If buf is
143 given, and buf needs to be expanded, the var pointed to by buflen
146 char *readline(FILE *fp, char **buf, size_t *buflen)
148 char *newline = NULL;
150 char *line; /* The array that contains everything that has been read
152 char *idx; /* Read into this pointer, which points to an offset
154 size_t size, newsize; /* The size of the current array pointed to by
156 size_t maxlen; /* Maximum number of characters that may be read with
157 fgets. This is newsize - oldsize. */
162 if((buf != NULL) && (buflen != NULL))
170 line = xmalloc(size);
179 p = fgets(idx, maxlen, fp);
180 if(p == NULL) /* EOF or error */
185 /* otherwise: error; let the calling function print an error
186 message if applicable */
191 newline = strchr(p, '\n');
193 /* We haven't yet read everything to the end of the line */
196 line = xrealloc(line, newsize);
197 idx = &line[size - 1];
198 maxlen = newsize - size + 1;
203 *newline = '\0'; /* kill newline */
208 if((buf != NULL) && (buflen != NULL))
217 Parse a configuration file and put the results in the configuration tree
220 int read_config_file(config_t **base, const char *fname)
222 int err = -2; /* Parse error */
231 if((fp = fopen (fname, "r")) == NULL)
235 buffer = xmalloc(bufsize);
240 if((line = readline(fp, &buffer, &bufsize)) == NULL)
254 if((p = strtok(line, "\t =")) == NULL)
255 continue; /* no tokens on this line */
258 continue; /* comment: ignore */
260 for(i = 0; hazahaza[i].name != NULL; i++)
261 if(!strcasecmp(hazahaza[i].name, p))
264 if(!hazahaza[i].name)
266 syslog(LOG_ERR, _("Invalid variable name `%s' on line %d while reading config file %s"),
271 if(((q = strtok(NULL, "\t\n\r =")) == NULL) || q[0] == '#')
273 fprintf(stderr, _("No value for variable `%s' on line %d while reading config file %s"),
274 hazahaza[i].name, lineno, fname);
278 cfg = add_config_val(base, hazahaza[i].argtype, q);
281 fprintf(stderr, _("Invalid value for variable `%s' on line %d while reading config file %s"),
282 hazahaza[i].name, lineno, fname);
286 cfg->which = hazahaza[i].which;
297 int read_server_config()
302 asprintf(&fname, "%s/tinc.conf", confbase);
303 x = read_config_file(&config, fname);
304 if(x == -1) /* System error */
306 fprintf(stderr, _("Failed to read `%s': %m\n"),
315 Look up the value of the config option type
317 const config_t *get_config_val(config_t *p, which_t type)
320 for(; p != NULL; p = p->next)
328 Remove the complete configuration tree.
330 void clear_config(config_t **base)
334 for(p = *base; p != NULL; p = next)
337 if(p->data.ptr && (p->argtype == TYPE_NAME))
347 int isadir(const char* f)
353 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
358 return S_ISDIR(s.st_mode);
361 int is_safe_path(const char *file)
366 p = strrchr(file, '/');
367 assert(p); /* p has to contain a / */
369 if(stat(file, &s) < 0)
371 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
375 if(s.st_uid != geteuid())
377 fprintf(stderr, _("`%s' is owned by UID %d instead of %d.\n"),
378 file, s.st_uid, geteuid());
381 if(S_ISLNK(s.st_mode))
383 fprintf(stderr, _("Warning: `%s' is a symlink\n"),
385 /* fixme: read the symlink and start again */
389 if(stat(file, &s) < 0 && errno != ENOENT)
391 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
397 if(s.st_uid != geteuid())
399 fprintf(stderr, _("`%s' is owned by UID %d instead of %d.\n"),
400 file, s.st_uid, geteuid());
403 if(S_ISLNK(s.st_mode))
405 fprintf(stderr, _("Warning: `%s' is a symlink\n"),
407 /* fixme: read the symlink and start again */
411 /* Accessible by others */
412 fprintf(stderr, _("`%s' has unsecure permissions.\n"),
420 FILE *ask_and_safe_open(const char* filename, const char* what)
427 /* Check stdin and stdout */
428 if(!isatty(0) || !isatty(1))
430 /* Argh, they are running us from a script or something. Write
431 the files to the current directory and let them burn in hell
433 fn = xstrdup(filename);
437 /* Ask for a file and/or directory name. */
438 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
440 fflush(stdout); /* Don't wait for a newline */
441 if((fn = readline(stdin, NULL, NULL)) == NULL)
443 fprintf(stderr, _("Error while reading stdin: %m\n"));
447 /* User just pressed enter. */
448 fn = xstrdup(filename);
451 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
453 /* The directory is a relative path or a filename. */
456 directory = get_current_dir_name();
457 len = strlen(fn) + strlen(directory) + 2; /* 1 for the / */
459 snprintf(p, len, "%s/%s", directory, fn);
465 if(isadir(fn) > 0) /* -1 is error */
469 len = strlen(fn) + strlen(filename) + 2; /* 1 for the / */
471 snprintf(p, len, "%s/%s", fn, filename);
476 umask(0077); /* Disallow everything for group and other */
478 /* Open it first to keep the inode busy */
479 if((r = fopen(fn, "w")) == NULL)
481 fprintf(stderr, _("Error opening file `%s': %m\n"),
487 /* Then check the file for nasty attacks */
488 if(!is_safe_path(fn)) /* Do not permit any directories that are
489 readable or writeable by other users. */
491 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
492 "I will not create or overwrite this file.\n"),