Add the ListenAddress option.
[tinc] / src / tincctl.c
index 16fa4b1..c6d7582 100644 (file)
 #include "tincctl.h"
 #include "top.h"
 
-#ifdef HAVE_MINGW
-#define SCRIPTEXTENSION ".bat"
-#else
-#define SCRIPTEXTENSION ""
-#endif
-
 static char **orig_argv;
 static int orig_argc;
 
@@ -71,10 +65,8 @@ static bool force = false;
 bool tty = true;
 bool confbasegiven = false;
 bool netnamegiven = false;
-
-#ifdef HAVE_MINGW
-static struct WSAData wsa_state;
-#endif
+char *scriptinterpreter = NULL;
+char *scriptextension = "";
 
 static struct option const long_options[] = {
        {"config", required_argument, NULL, 'c'},
@@ -211,6 +203,23 @@ static bool parse_options(int argc, char **argv) {
        return true;
 }
 
+/* Open a file with the desired permissions, minus the umask.
+   Also, if we want to create an executable file, we call fchmod()
+   to set the executable bits. */
+
+FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
+       mode_t mask = umask(0);
+       perms &= ~mask;
+       umask(~perms);
+       FILE *f = fopen(filename, mode);
+#ifdef HAVE_FCHMOD
+       if((perms & 0444) && f)
+               fchmod(fileno(f), perms);
+#endif
+       umask(mask);
+       return f;
+}
+
 static void disable_old_keys(const char *filename, const char *what) {
        char tmpfile[PATH_MAX] = "";
        char buf[1024];
@@ -225,17 +234,9 @@ static void disable_old_keys(const char *filename, const char *what) {
 
        snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename);
 
-       w = fopen(tmpfile, "w");
-
-#ifdef HAVE_FCHMOD
-       /* Let the temporary file have the same permissions as the original. */
-
-       if(w) {
-               struct stat st = {.st_mode = 0600};
-               fstat(fileno(r), &st);
-               fchmod(fileno(w), st.st_mode);
-       }
-#endif
+       struct stat st = {.st_mode = 0600};
+       fstat(fileno(r), &st);
+       w = fopenmask(tmpfile, "w", st.st_mode);
 
        while(fgets(buf, sizeof buf, r)) {
                if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
@@ -298,7 +299,7 @@ static void disable_old_keys(const char *filename, const char *what) {
        unlink(tmpfile);
 }
 
-static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask) {
+static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
        FILE *r;
        char *directory;
        char buf[PATH_MAX];
@@ -338,7 +339,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
 
        /* Open it first to keep the inode busy */
 
-       r = fopen(filename, mode);
+       r = fopenmask(filename, mode, perms);
 
        if(!r) {
                fprintf(stderr, "Error opening file `%s': %s\n", filename, strerror(errno));
@@ -366,17 +367,12 @@ static bool ecdsa_keygen(bool ask) {
                fprintf(stderr, "Done.\n");
 
        xasprintf(&privname, "%s" SLASH "ecdsa_key.priv", confbase);
-       f = ask_and_open(privname, "private ECDSA key", "a", ask);
+       f = ask_and_open(privname, "private ECDSA key", "a", ask, 0600);
        free(privname);
 
        if(!f)
                return false;
 
-#ifdef HAVE_FCHMOD
-       /* Make it unreadable for others. */
-       fchmod(fileno(f), 0600);
-#endif
-
        if(!ecdsa_write_pem_private_key(key, f)) {
                fprintf(stderr, "Error writing private key!\n");
                ecdsa_free(key);
@@ -391,7 +387,7 @@ static bool ecdsa_keygen(bool ask) {
        else
                xasprintf(&pubname, "%s" SLASH "ecdsa_key.pub", confbase);
 
-       f = ask_and_open(pubname, "public ECDSA key", "a", ask);
+       f = ask_and_open(pubname, "public ECDSA key", "a", ask, 0666);
        free(pubname);
 
        if(!f)
@@ -425,17 +421,12 @@ static bool rsa_keygen(int bits, bool ask) {
                fprintf(stderr, "Done.\n");
 
        xasprintf(&privname, "%s" SLASH "rsa_key.priv", confbase);
-       f = ask_and_open(privname, "private RSA key", "a", ask);
+       f = ask_and_open(privname, "private RSA key", "a", ask, 0600);
        free(privname);
 
        if(!f)
                return false;
 
-#ifdef HAVE_FCHMOD
-       /* Make it unreadable for others. */
-       fchmod(fileno(f), 0600);
-#endif
-
        if(!rsa_write_pem_private_key(key, f)) {
                fprintf(stderr, "Error writing private key!\n");
                fclose(f);
@@ -450,7 +441,7 @@ static bool rsa_keygen(int bits, bool ask) {
        else
                xasprintf(&pubname, "%s" SLASH "rsa_key.pub", confbase);
 
-       f = ask_and_open(pubname, "public RSA key", "a", ask);
+       f = ask_and_open(pubname, "public RSA key", "a", ask, 0666);
        free(pubname);
 
        if(!f)
@@ -687,14 +678,6 @@ bool connect_tincd(bool verbose) {
 
        fclose(f);
 
-#ifdef HAVE_MINGW
-       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
-               if(verbose)
-                       fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
-               return false;
-       }
-#endif
-
 #ifndef HAVE_MINGW
        struct sockaddr_un sa;
        sa.sun_family = AF_UNIX;
@@ -1309,6 +1292,7 @@ const var_t variables[] = {
        {"IffOneQueue", VAR_SERVER},
        {"Interface", VAR_SERVER},
        {"KeyExpire", VAR_SERVER},
+       {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
        {"LocalDiscovery", VAR_SERVER},
        {"MACExpire", VAR_SERVER},
        {"MaxConnectionBurst", VAR_SERVER},
@@ -1623,7 +1607,7 @@ static int cmd_config(int argc, char *argv[]) {
        if(action < 0 && !removed) {
                remove(tmpfile);
                fprintf(stderr, "No configuration variables deleted.\n");
-               return *value;
+               return *value != 0;
        }
 
        // Replace the configuration file with the new one
@@ -1686,6 +1670,35 @@ static bool try_bind(int port) {
        return true;
 }
 
+int check_port(char *name) {
+       if(try_bind(655))
+               return 655;
+
+       fprintf(stderr, "Warning: could not bind to port 655. ");
+
+       for(int i = 0; i < 100; i++) {
+               int port = 0x1000 + (rand() & 0x7fff);
+               if(try_bind(port)) {
+                       char *filename;
+                       xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
+                       FILE *f = fopen(filename, "a");
+                       free(filename);
+                       if(!f) {
+                               fprintf(stderr, "Please change tinc's Port manually.\n");
+                               return 0;
+                       }
+
+                       fprintf(f, "Port = %d\n", port);
+                       fclose(f);
+                       fprintf(stderr, "Tinc will instead listen on port %d.\n", port);
+                       return port;
+               }
+       }
+
+       fprintf(stderr, "Please change tinc's Port manually.\n");
+       return 0;
+}
+
 static int cmd_init(int argc, char *argv[]) {
        if(!access(tinc_conf, F_OK)) {
                fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
@@ -1727,17 +1740,17 @@ static int cmd_init(int argc, char *argv[]) {
                return 1;
        }
 
-       if(mkdir(confdir, 0755) && errno != EEXIST) {
-               fprintf(stderr, "Could not create directory %s: %s\n", CONFDIR, strerror(errno));
+       if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
+               fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
                return 1;
        }
 
-       if(mkdir(confbase, 0755) && errno != EEXIST) {
+       if(mkdir(confbase, 0777) && errno != EEXIST) {
                fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
                return 1;
        }
 
-       if(mkdir(hosts_dir, 0755) && errno != EEXIST) {
+       if(mkdir(hosts_dir, 0777) && errno != EEXIST) {
                fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
                return 1;
        }
@@ -1754,48 +1767,18 @@ static int cmd_init(int argc, char *argv[]) {
        if(!rsa_keygen(2048, false) || !ecdsa_keygen(false))
                return 1;
 
-
-       if(!try_bind(655)) {
-               srand(time(NULL));
-               int port = 0;
-               for(int i = 0; i < 100; i++) {
-                       port = 0x1000 + (rand() & 0x7fff);
-                       if(try_bind(port))
-                               break;
-                       port = 0;
-               }
-               if(port) {
-                       char *filename;
-                       xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
-                       FILE *f = fopen(filename, "a");
-                       free(filename);
-                       if(!f) {
-                               port = 0;
-                       } else {
-                               fprintf(f, "Port = %d\n", port);
-                               fclose(f);
-                       }
-               }
-
-               if(!port)
-                       fprintf(stderr, "Warning: could not bind to port 655. Please change tinc's Port manually.\n");
-               else
-                       fprintf(stderr, "Warning: could not bind to port 655. Tinc will instead listen on port %d.\n", port);
-       }
+       check_port(name);
 
 #ifndef HAVE_MINGW
        char *filename;
        xasprintf(&filename, "%s" SLASH "tinc-up", confbase);
        if(access(filename, F_OK)) {
-               FILE *f = fopen(filename, "w");
+               FILE *f = fopenmask(filename, "w", 0777);
                if(!f) {
                        fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
                        return 1;
                }
-               mode_t mask = umask(0);
-               umask(mask);
-               fchmod(fileno(f), 0755 & ~mask);
-               fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
+               fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
                fclose(f);
        }
 #endif
@@ -2372,6 +2355,16 @@ int main(int argc, char *argv[]) {
                return 0;
        }
 
+#ifdef HAVE_MINGW
+       static struct WSAData wsa_state;
+
+       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
+               fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
+               return false;
+       }
+#endif
+
+       srand(time(NULL));
        crypto_init();
 
        tty = isatty(0) && isatty(1);