Generate a tinc-up script from an invitation.
[tinc] / src / invitation.c
index 415c237..07594ff 100644 (file)
 #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"
@@ -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))
@@ -598,7 +604,20 @@ make_names:
                return false;
        }
 
+       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;
+       }
+
+       fprintf(fup, "#!/bin/sh\n");
+       long fuppos = ftell(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 +656,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);
@@ -651,6 +688,8 @@ make_names:
        }
 
        fclose(f);
+       bool valid_tinc_up = ifconfig_footer(fup);
+       fclose(fup);
 
        while(l && !strcasecmp(l, "Name")) {
                if(!check_id(value)) {
@@ -704,6 +743,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 +766,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);
@@ -759,6 +804,60 @@ ask_netname:
                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);
 
        return true;