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.34 2000/12/06 13:33:48 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 { "MyVirtualIP", config_dummy, TYPE_IP },
67 { "MyOwnVPNIP", config_dummy, TYPE_IP },
68 { "Name", config_name, TYPE_NAME },
69 { "PingTimeout", config_pingtimeout, TYPE_INT },
70 { "PrivateKey", config_privatekey, TYPE_NAME },
71 { "TapDevice", config_tapdevice, TYPE_NAME },
72 { "VpnMask", config_dummy, TYPE_IP },
73 /* Host configuration file keywords */
74 { "Address", config_address, TYPE_NAME },
75 { "IndirectData", config_indirectdata, TYPE_BOOL },
76 { "Port", config_port, TYPE_INT },
77 { "PublicKey", config_publickey, TYPE_NAME },
78 { "RestrictAddress", config_restrictaddress, TYPE_BOOL },
79 { "RestrictHosts", config_restricthosts, TYPE_BOOL },
80 { "RestrictPort", config_restrictport, TYPE_BOOL },
81 { "RestrictSubnets", config_restrictsubnets, TYPE_BOOL },
82 { "Subnet", config_subnet, TYPE_IP }, /* Use IPv4 subnets only for now */
83 { "TCPonly", config_tcponly, TYPE_BOOL },
88 Add given value to the list of configs cfg
91 add_config_val(config_t **cfg, int argtype, char *val)
96 p = (config_t*)xmalloc(sizeof(*p));
102 p->data.val = strtol(val, &q, 0);
107 p->data.ptr = xmalloc(strlen(val) + 1);
108 strcpy(p->data.ptr, val);
111 p->data.ip = strtoip(val);
114 if(!strcasecmp("yes", val))
115 p->data.val = stupid_true;
116 else if(!strcasecmp("no", val))
117 p->data.val = stupid_false;
122 p->argtype = argtype;
140 Read exactly one line and strip the trailing newline if any. If the
141 file was on EOF, return NULL. Otherwise, return all the data in a
142 dynamically allocated buffer.
144 If line is non-NULL, it will be used as an initial buffer, to avoid
145 unnecessary mallocing each time this function is called. If buf is
146 given, and buf needs to be expanded, the var pointed to by buflen
149 char *readline(FILE *fp, char **buf, size_t *buflen)
151 char *newline = NULL;
153 char *line; /* The array that contains everything that has been read
155 char *idx; /* Read into this pointer, which points to an offset
157 size_t size, newsize; /* The size of the current array pointed to by
159 size_t maxlen; /* Maximum number of characters that may be read with
160 fgets. This is newsize - oldsize. */
165 if((buf != NULL) && (buflen != NULL))
173 line = xmalloc(size);
182 p = fgets(idx, maxlen, fp);
183 if(p == NULL) /* EOF or error */
188 /* otherwise: error; let the calling function print an error
189 message if applicable */
194 newline = strchr(p, '\n');
196 /* We haven't yet read everything to the end of the line */
199 line = xrealloc(line, newsize);
200 idx = &line[size - 1];
201 maxlen = newsize - size + 1;
206 *newline = '\0'; /* kill newline */
211 if((buf != NULL) && (buflen != NULL))
220 Parse a configuration file and put the results in the configuration tree
223 int read_config_file(config_t **base, const char *fname)
225 int err = -2; /* Parse error */
234 if((fp = fopen (fname, "r")) == NULL)
238 buffer = xmalloc(bufsize);
243 if((line = readline(fp, &buffer, &bufsize)) == NULL)
257 if((p = strtok(line, "\t =")) == NULL)
258 continue; /* no tokens on this line */
261 continue; /* comment: ignore */
263 for(i = 0; hazahaza[i].name != NULL; i++)
264 if(!strcasecmp(hazahaza[i].name, p))
267 if(!hazahaza[i].name)
269 syslog(LOG_ERR, _("Invalid variable name `%s' on line %d while reading config file %s"),
274 if(((q = strtok(NULL, "\t\n\r =")) == NULL) || q[0] == '#')
276 fprintf(stderr, _("No value for variable `%s' on line %d while reading config file %s"),
277 hazahaza[i].name, lineno, fname);
281 cfg = add_config_val(base, hazahaza[i].argtype, q);
284 fprintf(stderr, _("Invalid value for variable `%s' on line %d while reading config file %s"),
285 hazahaza[i].name, lineno, fname);
289 cfg->which = hazahaza[i].which;
300 int read_server_config()
305 asprintf(&fname, "%s/tinc.conf", confbase);
306 x = read_config_file(&config, fname);
307 if(x == -1) /* System error */
309 fprintf(stderr, _("Failed to read `%s': %m\n"),
318 Look up the value of the config option type
320 const config_t *get_config_val(config_t *p, which_t type)
323 for(; p != NULL; p = p->next)
331 Remove the complete configuration tree.
333 void clear_config(config_t **base)
337 for(p = *base; p != NULL; p = next)
340 if(p->data.ptr && (p->argtype == TYPE_NAME))
350 int isadir(const char* f)
356 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
361 return S_ISDIR(s.st_mode);
364 int is_safe_path(const char *file)
369 p = strrchr(file, '/');
370 assert(p); /* p has to contain a / */
372 if(stat(file, &s) < 0)
374 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
378 if(s.st_uid != geteuid())
380 fprintf(stderr, _("`%s' is owned by UID %d instead of %d.\n"),
381 file, s.st_uid, geteuid());
384 if(S_ISLNK(s.st_mode))
386 fprintf(stderr, _("Warning: `%s' is a symlink\n"),
388 /* fixme: read the symlink and start again */
392 if(stat(file, &s) < 0 && errno != ENOENT)
394 fprintf(stderr, _("Couldn't stat `%s': %m\n"),
400 if(s.st_uid != geteuid())
402 fprintf(stderr, _("`%s' is owned by UID %d instead of %d.\n"),
403 file, s.st_uid, geteuid());
406 if(S_ISLNK(s.st_mode))
408 fprintf(stderr, _("Warning: `%s' is a symlink\n"),
410 /* fixme: read the symlink and start again */
414 /* Accessible by others */
415 fprintf(stderr, _("`%s' has unsecure permissions.\n"),
423 FILE *ask_and_safe_open(const char* filename, const char* what)
430 /* Check stdin and stdout */
431 if(!isatty(0) || !isatty(1))
433 /* Argh, they are running us from a script or something. Write
434 the files to the current directory and let them burn in hell
436 fn = xstrdup(filename);
440 /* Ask for a file and/or directory name. */
441 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
443 fflush(stdout); /* Don't wait for a newline */
444 if((fn = readline(stdin, NULL, NULL)) == NULL)
446 fprintf(stderr, _("Error while reading stdin: %m\n"));
450 /* User just pressed enter. */
451 fn = xstrdup(filename);
454 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
456 /* The directory is a relative path or a filename. */
459 directory = get_current_dir_name();
460 len = strlen(fn) + strlen(directory) + 2; /* 1 for the / */
462 snprintf(p, len, "%s/%s", directory, fn);
468 if(isadir(fn) > 0) /* -1 is error */
472 len = strlen(fn) + strlen(filename) + 2; /* 1 for the / */
474 snprintf(p, len, "%s/%s", fn, filename);
479 umask(0077); /* Disallow everything for group and other */
481 /* Open it first to keep the inode busy */
482 if((r = fopen(fn, "w")) == NULL)
484 fprintf(stderr, _("Error opening file `%s': %m\n"),
490 /* Then check the file for nasty attacks */
491 if(!is_safe_path(fn)) /* Do not permit any directories that are
492 readable or writeable by other users. */
494 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
495 "I will not create or overwrite this file.\n"),