X-Git-Url: https://tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Finvitation.c;h=0dfd9eacf32f2cae5ab9a3a45256f74551af3c72;hb=00d81ee6236e76f80b84372ac5c635636ad48136;hp=cc6cbd4d36ec706f65c4d9abe78848fd95bfd3be;hpb=3ccdf50beb6b2d3f2730bdc66006b43190537cde;p=tinc diff --git a/src/invitation.c b/src/invitation.c index cc6cbd4d..0dfd9eac 100644 --- a/src/invitation.c +++ b/src/invitation.c @@ -1,6 +1,6 @@ /* invitation.c -- Create and accept invitations - Copyright (C) 2013-2015 Guus Sliepen + Copyright (C) 2013-2017 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,12 +23,14 @@ #include "crypto.h" #include "ecdsa.h" #include "ecdsagen.h" +#include "ifconfig.h" #include "invitation.h" #include "names.h" #include "netutl.h" #include "rsagen.h" #include "script.h" #include "sptps.h" +#include "subnet.h" #include "tincctl.h" #include "utils.h" #include "xalloc.h" @@ -84,7 +86,7 @@ char *get_my_hostname() { char *port = NULL; char *hostport = NULL; char *name = get_my_name(false); - char filename[PATH_MAX]; + char filename[PATH_MAX] = {0}; // Use first Address statement in own host config file if(check_id(name)) { @@ -182,7 +184,7 @@ again: hostname = xstrdup(line); save: - if(filename) { + if(*filename) { FILE *f = fopen(filename, "a"); if(f) { fprintf(f, "\nAddress = %s\n", hostname); @@ -237,7 +239,7 @@ int cmd_invite(int argc, char *argv[]) { return 1; } - char *myname = get_my_name(true); + myname = get_my_name(true); if(!myname) return 1; @@ -250,14 +252,14 @@ int cmd_invite(int argc, char *argv[]) { } // If a daemon is running, ensure no other nodes know about this name - bool found = false; if(connect_tincd(false)) { + bool found = false; sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES); while(recvline(fd, line, sizeof line)) { char node[4096]; int code, req; - if(sscanf(line, "%d %d %s", &code, &req, node) != 3) + if(sscanf(line, "%d %d %4095s", &code, &req, node) != 3) break; if(!strcmp(node, argv[1])) found = true; @@ -335,7 +337,11 @@ int cmd_invite(int argc, char *argv[]) { return 1; } chmod(filename, 0600); - ecdsa_write_pem_private_key(key, f); + if(!ecdsa_write_pem_private_key(key, f)) { + fprintf(stderr, "Could not write ECDSA private key\n"); + fclose(f); + return 1; + } fclose(f); if(connect_tincd(false)) @@ -386,7 +392,7 @@ int cmd_invite(int argc, char *argv[]) { // Fill in the details. fprintf(f, "Name = %s\n", argv[1]); - if(netname) + if(check_netname(netname, true)) fprintf(f, "NetName = %s\n", netname); fprintf(f, "ConnectTo = %s\n", myname); @@ -419,15 +425,13 @@ int cmd_invite(int argc, char *argv[]) { xasprintf(&url, "%s/%s%s", address, hash, cookie); // Call the inviation-created script - char *envp[6] = {}; - xasprintf(&envp[0], "NAME=%s", myname); - xasprintf(&envp[1], "NETNAME=%s", netname); - xasprintf(&envp[2], "NODE=%s", argv[1]); - xasprintf(&envp[3], "INVITATION_FILE=%s", filename); - xasprintf(&envp[4], "INVITATION_URL=%s", url); - execute_script("invitation-created", envp); - for(int i = 0; i < 6 && envp[i]; i++) - free(envp[i]); + environment_t env; + environment_init(&env); + environment_add(&env, "NODE=%s", argv[1]); + environment_add(&env, "INVITATION_FILE=%s", filename); + environment_add(&env, "INVITATION_URL=%s", url); + execute_script("invitation-created", &env); + environment_exit(&env); puts(url); free(url); @@ -535,12 +539,17 @@ static bool finalize_join(void) { } if(!check_id(name)) { - fprintf(stderr, "Invalid Name found in invitation: %s!\n", name); + fprintf(stderr, "Invalid Name found in invitation!\n"); return false; } - if(!netname) + if(!netname) { netname = grep(data, "NetName"); + if(netname && !check_netname(netname, true)) { + fprintf(stderr, "Unsafe NetName found in invitation!\n"); + return false; + } + } bool ask_netname = false; char temp_netname[32]; @@ -551,7 +560,7 @@ make_names: confbase = NULL; } - make_names(); + make_names(false); free(tinc_conf); free(hosts_dir); @@ -598,7 +607,30 @@ make_names: return false; } + snprintf(filename, sizeof filename, "%s" SLASH "invitation-data", confbase); + FILE *finv = fopen(filename, "w"); + if(!finv || fwrite(data, datalen, 1, finv) != 1) { + fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); + fclose(fh); + fclose(f); + fclose(finv); + return false; + } + fclose(finv); + + snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase); + FILE *fup = fopen(filename, "w"); + if(!fup) { + fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); + fclose(f); + fclose(fh); + return false; + } + + ifconfig_header(fup); + // Filter first chunk on approved keywords, split between tinc.conf and hosts/Name + // Generate a tinc-up script from Ifconfig and Route keywords. // Other chunks go unfiltered to their respective host config files const char *p = data; char *l, *value; @@ -637,6 +669,24 @@ make_names: break; } + // Handle Ifconfig and Route statements + if(!found) { + if(!strcasecmp(l, "Ifconfig")) { + if(!strcasecmp(value, "dhcp")) + ifconfig_dhcp(fup); + else if(!strcasecmp(value, "dhcp6")) + ifconfig_dhcp6(fup); + else if(!strcasecmp(value, "slaac")) + ifconfig_slaac(fup); + else + ifconfig_address(fup, value); + continue; + } else if(!strcasecmp(l, "Route")) { + ifconfig_route(fup, value); + continue; + } + } + // Ignore unknown and unsafe variables if(!found) { fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l); @@ -647,10 +697,12 @@ make_names: } // Copy the safe variable to the right config file - fprintf(variables[i].type & VAR_HOST ? fh : f, "%s = %s\n", l, value); + fprintf((variables[i].type & VAR_HOST) ? fh : f, "%s = %s\n", l, value); } fclose(f); + bool valid_tinc_up = ifconfig_footer(fup); + fclose(fup); while(l && !strcasecmp(l, "Name")) { if(!check_id(value)) { @@ -704,6 +756,8 @@ make_names: snprintf(filename, sizeof filename, "%s" SLASH "ed25519_key.priv", confbase); f = fopenmask(filename, "w", 0600); + if(!f) + return false; if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Error writing private key!\n"); @@ -725,10 +779,14 @@ make_names: snprintf(filename, sizeof filename, "%s" SLASH "rsa_key.priv", confbase); f = fopenmask(filename, "w", 0600); - rsa_write_pem_private_key(rsa, f); + if(!f || !rsa_write_pem_private_key(rsa, f)) { + fprintf(stderr, "Could not write private RSA key\n"); + } else if(!rsa_write_pem_public_key(rsa, fh)) { + fprintf(stderr, "Could not write public RSA key\n"); + } + fclose(f); - rsa_write_pem_public_key(rsa, fh); fclose(fh); rsa_free(rsa); @@ -756,7 +814,61 @@ ask_netname: } netname = line; - make_names(); + make_names(false); + } + + char filename2[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase); + snprintf(filename2, sizeof filename2, "%s" SLASH "tinc-up", confbase); + + if(valid_tinc_up) { + if(tty) { + FILE *fup = fopen(filename, "r"); + if(fup) { + fprintf(stderr, "\nPlease review the following tinc-up script:\n\n"); + + char buf[MAXSIZE]; + while(fgets(buf, sizeof buf, fup)) + fputs(buf, stderr); + fclose(fup); + + int response = 0; + do { + fprintf(stderr, "\nDo you want to use this script [y]es/[n]o/[e]dit? "); + response = tolower(getchar()); + } while(!strchr("yne", response)); + + fprintf(stderr, "\n"); + + if(response == 'e') { + char *command; +#ifndef HAVE_MINGW + xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename); +#else + xasprintf(&command, "edit \"%s\"", filename); +#endif + if(system(command)) + response = 'n'; + else + response = 'y'; + free(command); + } + + if(response == 'y') { + rename(filename, filename2); + chmod(filename2, 0755); + fprintf(stderr, "tinc-up enabled.\n"); + } else { + fprintf(stderr, "tinc-up has been left disabled.\n"); + } + } + } else { + fprintf(stderr, "A tinc-up script was generated, but has been left disabled.\n"); + } + } else { + // A placeholder was generated. + rename(filename, filename2); + chmod(filename2, 0755); } fprintf(stderr, "Configuration stored in: %s\n", confbase); @@ -943,7 +1055,7 @@ next: char hisname[4096] = ""; int code, hismajor, hisminor = 0; - if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) { + if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %4095s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) { fprintf(stderr, "Cannot read greeting from peer\n"); closesocket(sock); goto next;