Make sure disabling old RSA keys works on Windows.
authorGuus Sliepen <guus@tinc-vpn.org>
Thu, 8 Mar 2012 22:23:39 +0000 (23:23 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Thu, 8 Mar 2012 22:23:39 +0000 (23:23 +0100)
Seeking in files and rewriting parts of them does not seem to work properly on
Windows. Instead, when old RSA keys are found when generating new ones, the
file containing the old keys is copied to a temporary file where the changes
are made, and that file is renamed back to the original filename. On Windows,
we cannot atomically replace files with a rename(), so we need to move the
original file out of the way first. If anything fails, the new code will warn
that the user has to solve the problem by hand.

src/conf.c
src/conf.h
src/tincd.c

index 1560541a101c315b63c2950eb48758cb56b2d515..b7c0179e180d26ae26e846410c088d2e2e6374e8 100644 (file)
@@ -400,6 +400,70 @@ bool read_connection_config(connection_t *c) {
        return x;
 }
 
        return x;
 }
 
+static void disable_old_keys(const char *filename) {
+       char tmpfile[PATH_MAX] = "";
+       char buf[1024];
+       bool disabled = false;
+       FILE *r, *w;
+
+       r = fopen(filename, "r");
+       if(!r)
+               return;
+
+       snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename);
+
+       w = fopen(tmpfile, "w");
+
+       while(fgets(buf, sizeof buf, r)) {
+               if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
+                       buf[11] = 'O';
+                       buf[12] = 'L';
+                       buf[13] = 'D';
+                       disabled = true;
+               }
+               else if(!strncmp(buf, "-----END RSA", 12)) {    
+                       buf[ 9] = 'O';
+                       buf[10] = 'L';
+                       buf[11] = 'D';
+                       disabled = true;
+               }
+               if(w && fputs(buf, w) < 0) {
+                       disabled = false;
+                       break;
+               }
+       }
+
+       if(w)
+               fclose(w);
+       fclose(r);
+
+       if(!w && disabled) {
+               fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
+               return;
+       }
+
+       if(disabled) {
+#ifdef HAVE_MINGW
+               // We cannot atomically replace files on Windows.
+               char bakfile[PATH_MAX] = "";
+               snprintf(bakfile, sizeof bakfile, "%s.bak", filename);
+               if(rename(filename, bakfile) || rename(tmpfile, filename)) {
+                       rename(bakfile, filename);
+#else
+               if(rename(tmpfile, filename)) {
+#endif
+                       fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
+               } else  {
+#ifdef HAVE_MINGW
+                       unlink(bakfile);
+#endif
+                       fprintf(stderr, "Warning: old key(s) found and disabled.\n");
+               }
+       }
+
+       unlink(tmpfile);
+}
+
 FILE *ask_and_open(const char *filename, const char *what) {
        FILE *r;
        char *directory;
 FILE *ask_and_open(const char *filename, const char *what) {
        FILE *r;
        char *directory;
@@ -447,9 +511,11 @@ FILE *ask_and_open(const char *filename, const char *what) {
 
        umask(0077);                            /* Disallow everything for group and other */
 
 
        umask(0077);                            /* Disallow everything for group and other */
 
+       disable_old_keys(fn);
+
        /* Open it first to keep the inode busy */
 
        /* Open it first to keep the inode busy */
 
-       r = fopen(fn, "r+") ?: fopen(fn, "w+");
+       r = fopen(fn, "a");
 
        if(!r) {
                fprintf(stderr, "Error opening file `%s': %s\n",
 
        if(!r) {
                fprintf(stderr, "Error opening file `%s': %s\n",
@@ -460,42 +526,4 @@ FILE *ask_and_open(const char *filename, const char *what) {
        return r;
 }
 
        return r;
 }
 
-bool disable_old_keys(FILE *f) {
-       char buf[100];
-       long pos;
-       bool disabled = false;
-
-       rewind(f);
-       pos = ftell(f);
-
-       if(pos < 0)
-               return false;
 
 
-       while(fgets(buf, sizeof buf, f)) {
-               if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
-                       buf[11] = 'O';
-                       buf[12] = 'L';
-                       buf[13] = 'D';
-                       if(fseek(f, pos, SEEK_SET))
-                               break;
-                       if(fputs(buf, f) <= 0)
-                               break;
-                       disabled = true;
-               }
-               else if(!strncmp(buf, "-----END RSA", 12)) {    
-                       buf[ 9] = 'O';
-                       buf[10] = 'L';
-                       buf[11] = 'D';
-                       if(fseek(f, pos, SEEK_SET))
-                               break;
-                       if(fputs(buf, f) <= 0)
-                               break;
-                       disabled = true;
-               }
-               pos = ftell(f);
-               if(pos < 0)
-                       break;
-       }
-
-       return disabled;
-}
index 5b0796e5bfbbf4fe5fb38f082a3a0c08390328f6..46a42b1d455b8ff7b048cfe8c151a9bfc15312f5 100644 (file)
@@ -63,6 +63,5 @@ extern bool read_server_config(void);
 extern bool read_connection_config(struct connection_t *);
 extern FILE *ask_and_open(const char *, const char *);
 extern bool is_safe_path(const char *);
 extern bool read_connection_config(struct connection_t *);
 extern FILE *ask_and_open(const char *, const char *);
 extern bool is_safe_path(const char *);
-extern bool disable_old_keys(FILE *);
 
 #endif                                                 /* __TINC_CONF_H__ */
 
 #endif                                                 /* __TINC_CONF_H__ */
index a1be971acf493406fb5fe60c5c0786a5a76ebf27..d0b00b0dda48ad7ac0aaa43f6b0bd9934ab69302 100644 (file)
@@ -362,9 +362,6 @@ static bool keygen(int bits) {
        if(!f)
                return false;
 
        if(!f)
                return false;
 
-       if(disable_old_keys(f))
-               fprintf(stderr, "Warning: old key(s) found and disabled.\n");
-  
 #ifdef HAVE_FCHMOD
        /* Make it unreadable for others. */
        fchmod(fileno(f), 0600);
 #ifdef HAVE_FCHMOD
        /* Make it unreadable for others. */
        fchmod(fileno(f), 0600);
@@ -385,9 +382,6 @@ static bool keygen(int bits) {
        if(!f)
                return false;
 
        if(!f)
                return false;
 
-       if(disable_old_keys(f))
-               fprintf(stderr, "Warning: old key(s) found and disabled.\n");
-
        fputc('\n', f);
        PEM_write_RSAPublicKey(f, rsa_key);
        fclose(f);
        fputc('\n', f);
        PEM_write_RSAPublicKey(f, rsa_key);
        fclose(f);