/*
conf.c -- configuration code
Copyright (C) 1998 Robert van der Meulen
- 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
- 2000-2002 Guus Sliepen <guus@sliepen.warande.net>
+ 1998-2002 Ivo Timmermans <ivo@o2w.nl>
+ 2000-2002 Guus Sliepen <guus@sliepen.eu.org>
2000 Cris van Pelt <tribbel@arise.dhs.org>
This program is free software; you can redistribute it and/or modify
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: conf.c,v 1.9.4.52 2002/02/10 21:57:53 guus Exp $
+ $Id: conf.c,v 1.9.4.58 2002/09/09 19:39:55 guus Exp $
*/
#include "config.h"
int config_compare(config_t *a, config_t *b)
{
int result;
-
- result = strcmp(a->variable, b->variable);
-
+
+ result = strcasecmp(a->variable, b->variable);
+
if(result)
return result;
result = a->line - b->line;
-
+
if(result)
return result;
else
void init_configuration(avl_tree_t **config_tree)
{
-cp
+ cp();
*config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
-cp
+ cp();
}
void exit_configuration(avl_tree_t **config_tree)
{
-cp
+ cp();
avl_delete_tree(*config_tree);
*config_tree = NULL;
-cp
+ cp();
}
config_t *new_config(void)
{
config_t *cfg;
-cp
+ cp();
cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
-
+
return cfg;
}
void free_config(config_t *cfg)
{
-cp
+ cp();
if(cfg->variable)
free(cfg->variable);
if(cfg->value)
if(cfg->file)
free(cfg->file);
free(cfg);
-cp
+ cp();
}
void config_add(avl_tree_t *config_tree, config_t *cfg)
{
-cp
+ cp();
avl_insert(config_tree, cfg);
-cp
+ cp();
}
config_t *lookup_config(avl_tree_t *config_tree, char *variable)
{
config_t cfg, *found;
-cp
+ cp();
cfg.variable = variable;
cfg.file = "";
cfg.line = 0;
if(!found)
return NULL;
-
- if(strcmp(found->variable, variable))
+
+ if(strcasecmp(found->variable, variable))
return NULL;
return found;
{
avl_node_t *node;
config_t *found;
-cp
+ cp();
node = avl_search_node(config_tree, cfg);
-
+
if(node)
{
if(node->next)
{
found = (config_t *)node->next->data;
- if(!strcmp(found->variable, cfg->variable))
+ if(!strcasecmp(found->variable, cfg->variable))
return found;
}
}
-
+
return NULL;
}
-
+
int get_config_bool(config_t *cfg, int *result)
{
-cp
+ cp();
if(!cfg)
return 0;
int get_config_int(config_t *cfg, int *result)
{
-cp
+ cp();
if(!cfg)
return 0;
if(sscanf(cfg->value, "%d", result) == 1)
return 1;
-
+
syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
int get_config_string(config_t *cfg, char **result)
{
-cp
+ cp();
if(!cfg)
return 0;
- *result = cfg->value;
+ *result = xstrdup(cfg->value);
return 1;
}
-int get_config_address(config_t *cfg, ipv4_t **result)
+int get_config_address(config_t *cfg, struct addrinfo **result)
{
- ipv4_t *ip;
-cp
+ struct addrinfo *ai;
+ cp();
if(!cfg)
return 0;
- ip = xmalloc(sizeof(*ip));
- *ip = str2address(cfg->value);
+ ai = str2addrinfo(cfg->value, NULL, 0);
- if(ip)
+ if(ai)
{
- *result = ip;
+ *result = ai;
return 1;
}
- syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
+ syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
}
int get_config_port(config_t *cfg, port_t *result)
{
-cp
+ cp();
if(!cfg)
return 0;
if(sscanf(cfg->value, "%hu", result) == 1)
- return 1;
-
+ {
+ *result = htons(*result);
+ return 1;
+ }
+
syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
int get_config_subnet(config_t *cfg, subnet_t **result)
{
subnet_t *subnet;
-cp
+ cp();
if(!cfg)
return 0;
cfg->variable, cfg->file, cfg->line);
return 0;
}
-
+
/* Teach newbies what subnets are... */
- if(subnet->type == SUBNET_IPV4)
- if((subnet->net.ipv4.address & subnet->net.ipv4.mask) != subnet->net.ipv4.address)
- {
- syslog(LOG_ERR, _("Network address and mask length do not match for configuration variable %s in %s line %d"),
- cfg->variable, cfg->file, cfg->line);
- free(subnet);
- return 0;
- }
+ if(((subnet->type == SUBNET_IPV4) && maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
+ || ((subnet->type == SUBNET_IPV6) && maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))))
+ {
+ syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"),
+ cfg->variable, cfg->file, cfg->line);
+ free(subnet);
+ return 0;
+ }
*result = subnet;
-
+
return 1;
}
Read exactly one line and strip the trailing newline if any. If the
file was on EOF, return NULL. Otherwise, return all the data in a
dynamically allocated buffer.
-
+
If line is non-NULL, it will be used as an initial buffer, to avoid
unnecessary mallocing each time this function is called. If buf is
given, and buf needs to be expanded, the var pointed to by buflen
if(feof(fp))
return NULL;
- if((buf != NULL) && (buflen != NULL))
+ if(buf && buflen)
{
size = *buflen;
line = *buf;
{
errno = 0;
p = fgets(idx, maxlen, fp);
- if(p == NULL) /* EOF or error */
+ if(!p) /* EOF or error */
{
if(feof(fp))
break;
}
newline = strchr(p, '\n');
- if(newline == NULL)
+ if(!newline)
/* We haven't yet read everything to the end of the line */
{
newsize = size << 1;
}
}
- if((buf != NULL) && (buflen != NULL))
+ if(buf && buflen)
{
*buflen = size;
*buf = line;
int lineno = 0, ignore = 0;
config_t *cfg;
size_t bufsize;
-
-cp
- if((fp = fopen (fname, "r")) == NULL)
+
+ cp();
+ fp = fopen (fname, "r");
+
+ if(!fp)
{
- syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
+ syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
return -3;
}
bufsize = 100;
buffer = xmalloc(bufsize);
-
+
for(;;)
{
- if((line = readline(fp, &buffer, &bufsize)) == NULL)
+ line = readline(fp, &buffer, &bufsize);
+
+ if(!line)
{
err = -1;
break;
lineno++;
- if((variable = strtok(line, "\t =")) == NULL)
+ variable = strtok(line, "\t =");
+
+ if(!variable)
continue; /* no tokens on this line */
if(variable[0] == '#')
if(!strcmp(variable, "-----BEGIN"))
ignore = 1;
-
+
if(!ignore)
{
- if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
+ value = strtok(NULL, "\t\n\r =");
+
+ if(!value || value[0] == '#')
{
syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
variable, lineno, fname);
free(buffer);
fclose (fp);
-cp
+ cp();
return err;
}
{
char *fname;
int x;
-cp
+ cp();
asprintf(&fname, "%s/tinc.conf", confbase);
x = read_config_file(config_tree, fname);
if(x == -1) /* System error: complain */
{
- syslog(LOG_ERR, _("Failed to read `%s': %m"),
- fname);
+ syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
}
free(fname);
-cp
- return x;
+ cp();
+ return x;
}
int isadir(const char* f)
}
p = strrchr(file, '/');
-
+
if(p == file) /* It's in the root */
p++;
-
+
x = *p;
*p = '\0';
check1:
if(lstat(f, &s) < 0)
{
- syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
- f);
+ syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
return 0;
}
if(readlink(f, l, MAXBUFSIZE) < 0)
{
- syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
+ syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
return 0;
}
-
+
f = l;
goto check1;
}
*p = x;
f = file;
-
+
check2:
if(lstat(f, &s) < 0 && errno != ENOENT)
{
- syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
- f);
+ syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
return 0;
}
-
+
if(errno == ENOENT)
return 1;
if(readlink(f, l, MAXBUFSIZE) < 0)
{
- syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
+ syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
return 0;
}
-
+
f = l;
goto check2;
}
f);
return 0;
}
-
+
return 1;
}
what, filename);
fflush(stdout);
- if((fn = readline(stdin, NULL, NULL)) == NULL)
+ fn = readline(stdin, NULL, NULL);
+
+ if(!fn)
{
fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
return NULL;
}
- if(strlen(fn) == 0)
+ if(!strlen(fn))
/* User just pressed enter. */
fn = xstrdup(filename);
}
- if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
+ if(!strchr(fn, '/') || fn[0] != '/')
{
/* The directory is a relative path or a filename. */
char *p;
-
+
directory = get_current_dir_name();
asprintf(&p, "%s/%s", directory, fn);
free(fn);
}
umask(0077); /* Disallow everything for group and other */
-
+
/* Open it first to keep the inode busy */
- if((r = fopen(fn, mode)) == NULL)
+
+ r = fopen(fn, mode);
+
+ if(!r)
{
fprintf(stderr, _("Error opening file `%s': %s\n"),
fn, strerror(errno));
free(fn);
return NULL;
}
-
+
/* Then check the file for nasty attacks */
if(!is_safe_path(fn)) /* Do not permit any directories that are
readable or writeable by other users. */