X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Ftincctl.c;h=f133e2def81086456033a59ea74cb1f28b47ccc7;hb=8f8424445810aa7d5e9d4d537494e64811a8e29f;hp=a49654847f158d74c0cbafce1e9307a45c768122;hpb=d1e01bc880a6970050e55f19bafe8eaf1f0b9be2;p=tinc diff --git a/src/tincctl.c b/src/tincctl.c index a4965484..f133e2de 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -39,12 +39,6 @@ #include "tincctl.h" #include "top.h" -#ifdef HAVE_MINGW -#define SCRIPTEXTENSION ".bat" -#else -#define SCRIPTEXTENSION "" -#endif - static char **orig_argv; static int orig_argc; @@ -211,6 +205,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 +236,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 +301,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 +341,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 +369,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 +389,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 +423,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 +443,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) @@ -1657,6 +1650,64 @@ bool check_id(const char *name) { return true; } +static bool try_bind(int port) { + struct addrinfo *ai = NULL; + struct addrinfo hint = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + + char portstr[16]; + snprintf(portstr, sizeof portstr, "%d", port); + + if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai) + return false; + + while(ai) { + int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); + if(!fd) + return false; + int result = bind(fd, ai->ai_addr, ai->ai_addrlen); + closesocket(fd); + if(result) + return false; + ai = ai->ai_next; + } + + 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); @@ -1698,17 +1749,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(strcmp(confdir, confbase) && 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; } @@ -1725,18 +1776,17 @@ static int cmd_init(int argc, char *argv[]) { if(!rsa_keygen(2048, false) || !ecdsa_keygen(false)) return 1; + 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 netmask \n"); fclose(f); } @@ -2314,6 +2364,7 @@ int main(int argc, char *argv[]) { return 0; } + srand(time(NULL)); crypto_init(); tty = isatty(0) && isatty(1);