#include "tincctl.h"
#include "top.h"
+#ifdef HAVE_MINGW
+#define mkdir(a, b) mkdir(a)
+#endif
+
/* The name this program was run with. */
static char *program_name = NULL;
}
}
- if(!netname) {
- netname = getenv("NETNAME");
- if(netname)
- netname = xstrdup(netname);
- }
+ if(!netname && (netname = getenv("NETNAME")))
+ netname = xstrdup(netname);
+
+ /* netname "." is special: a "top-level name" */
+
+ if(netname && !strcmp(netname, ".")) {
+ free(netname);
+ netname = NULL;
+ }
return true;
}
slash = c;
#endif
- if (slash++) {
- c = xmalloc((slash - argv[0]) + sizeof("tincd"));
- sprintf(c, "%.*stincd", (int)(slash - argv[0]), argv[0]);
- }
+ if (slash++)
+ xasprintf(&c, "%.*stincd", (int)(slash - argv[0]), argv[0]);
else
c = "tincd";
return NULL;
}
-static char *hostvariables[] = {
- "Address",
- "Port",
- "PublicKey",
- "Subnet",
- NULL,
+#define VAR_SERVER 1 /* Should be in tinc.conf */
+#define VAR_HOST 2 /* Can be in host config file */
+#define VAR_MULTIPLE 4 /* Multiple statements allowed */
+#define VAR_OBSOLETE 8 /* Should not be used anymore */
+
+static struct {
+ const char *name;
+ int type;
+} const variables[] = {
+ /* Server configuration */
+ {"AddressFamily", VAR_SERVER},
+ {"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
+ {"BindToInterface", VAR_SERVER},
+ {"Broadcast", VAR_SERVER},
+ {"ConnectTo", VAR_SERVER | VAR_MULTIPLE},
+ {"DecrementTTL", VAR_SERVER},
+ {"Device", VAR_SERVER},
+ {"DeviceType", VAR_SERVER},
+ {"DirectOnly", VAR_SERVER},
+ {"ECDSAPrivateKeyFile", VAR_SERVER},
+ {"ExperimentalProtocol", VAR_SERVER},
+ {"Forwarding", VAR_SERVER},
+ {"GraphDumpFile", VAR_SERVER},
+ {"Hostnames", VAR_SERVER},
+ {"IffOneQueue", VAR_SERVER},
+ {"Interface", VAR_SERVER},
+ {"KeyExpire", VAR_SERVER},
+ {"LocalDiscovery", VAR_SERVER},
+ {"MACExpire", VAR_SERVER},
+ {"MaxTimeout", VAR_SERVER},
+ {"Mode", VAR_SERVER},
+ {"Name", VAR_SERVER},
+ {"PingInterval", VAR_SERVER},
+ {"PingTimeout", VAR_SERVER},
+ {"PriorityInheritance", VAR_SERVER},
+ {"PrivateKey", VAR_SERVER | VAR_OBSOLETE},
+ {"PrivateKeyFile", VAR_SERVER},
+ {"ProcessPriority", VAR_SERVER},
+ {"ReplayWindow", VAR_SERVER},
+ {"StrictSubnets", VAR_SERVER},
+ {"TunnelServer", VAR_SERVER},
+ {"UDPRcvBuf", VAR_SERVER},
+ {"UDPSndBuf", VAR_SERVER},
+ /* Host configuration */
+ {"Address", VAR_HOST | VAR_MULTIPLE},
+ {"Cipher", VAR_SERVER | VAR_HOST},
+ {"ClampMSS", VAR_SERVER | VAR_HOST},
+ {"Compression", VAR_SERVER | VAR_HOST},
+ {"Digest", VAR_SERVER | VAR_HOST},
+ {"IndirectData", VAR_SERVER | VAR_HOST},
+ {"MACLength", VAR_SERVER | VAR_HOST},
+ {"PMTU", VAR_SERVER | VAR_HOST},
+ {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
+ {"Port", VAR_HOST},
+ {"PublicKey", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
+ {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
+ {"Subnet", VAR_HOST | VAR_MULTIPLE},
+ {"TCPOnly", VAR_SERVER | VAR_HOST},
+ {NULL, 0}
};
static int cmd_config(int argc, char *argv[]) {
return 1;
}
- // Should this go into our own host config file?
- if(!node) {
- for(int i = 0; hostvariables[i]; i++) {
- if(!strcasecmp(hostvariables[i], variable)) {
- node = get_my_name();
- if(!node)
- return 1;
- break;
+ /* Some simple checks. */
+ bool found = false;
+
+ for(int i = 0; variables[i].name; i++) {
+ if(strcasecmp(variables[i].name, variable))
+ continue;
+
+ found = true;
+ variable = (char *)variables[i].name;
+
+ /* Discourage use of obsolete variables. */
+
+ if(variables[i].type & VAR_OBSOLETE && action >= 0) {
+ if(force) {
+ fprintf(stderr, "Warning: %s is an obsolete variable!\n", variable);
+ } else {
+ fprintf(stderr, "%s is an obsolete variable! Use --force to use it anyway.\n", variable);
+ return 1;
+ }
+ }
+
+ /* Don't put server variables in host config files */
+
+ if(node && !(variables[i].type & VAR_HOST) && action >= 0) {
+ if(force) {
+ fprintf(stderr, "Warning: %s is not a host configuration variable!\n", variable);
+ } else {
+ fprintf(stderr, "%s is not a host configuration variable! Use --force to use it anyway.\n", variable);
+ return 1;
}
}
+
+ /* Should this go into our own host config file? */
+
+ if(!node && !(variables[i].type & VAR_SERVER)) {
+ node = get_my_name();
+ if(!node)
+ return 1;
+ }
+
+ break;
}
if(node && !check_id(node)) {
return 1;
}
+ if(!found && action >= 0) {
+ if(force) {
+ fprintf(stderr, "Warning: %s is not a known configuration variable!\n", variable);
+ } else {
+ fprintf(stderr, "%s: is not a known configuration variable! Use --force to use it anyway.\n", variable);
+ return 1;
+ }
+ }
+
// Open the right configuration file.
char *filename;
if(node)
while(fgets(buf1, sizeof buf1, f)) {
buf1[sizeof buf1 - 1] = 0;
- strcpy(buf2, buf1);
+ strncpy(buf2, buf1, sizeof buf2);
// Parse line in a simple way
char *bvalue;
fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
return 1;
}
+
+ // Add newline if it is missing...
+ if(*buf1 && buf1[strlen(buf1) - 1] != '\n') {
+ if(fputc('\n', tf) < 0) {
+ fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
+ return 1;
+ }
+ }
}
// Make sure we read everything...
#ifndef HAVE_MINGW
char *editor = getenv("VISUAL") ?: getenv("EDITOR") ?: "vi";
#else
- char *editor = "edit"
+ char *editor = "edit";
#endif
char *command;
fprintf(out, "Name = %s\n", name);
char buf[4096];
- while(fgets(buf, sizeof buf, in))
- fputs(buf, out);
+ while(fgets(buf, sizeof buf, in)) {
+ if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4))
+ fputs(buf, out);
+ }
if(ferror(in)) {
fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));