--- openssh-4.5p1/ssh-keygen.c.bak 2007-07-30 17:50:25.271067000 +0300 +++ openssh-4.5p1/ssh-keygen.c 2007-08-21 03:46:15.630784067 +0300 @@ -788,7 +788,14 @@ do_known_hosts(struct passwd *pw, const } if (inplace) { - fclose(out); + if ((fflush(out) == EOF) || + (fsync(fileno(out)) == -1 && errno != EINVAL) || + (fclose(out) == EOF)) { + fprintf(stderr, "Failed to write to %s: %s\n", + tmp, strerror(errno)); + unlink(tmp); + exit(1); + } /* Backup existing file */ if (unlink(old) == -1 && errno != ENOENT) @@ -1014,14 +1021,18 @@ do_change_comment(struct passwd *pw) } f = fdopen(fd, "w"); if (f == NULL) { - printf("fdopen %s failed", identity_file); + printf("fdopen %s failed\n", identity_file); exit(1); } if (!key_write(public, f)) fprintf(stderr, "write key failed"); key_free(public); fprintf(f, " %s\n", new_comment); - fclose(f); + if ((fflush(f) == EOF) || (fsync(fileno(f)) == -1 && errno != EINVAL) || + fclose(f) == EOF) { + printf("sorry, %s is destroyed: %s\n", identity_file, strerror(errno)); + exit(1); + } xfree(comment); @@ -1078,6 +1089,7 @@ main(int ac, char **av) { char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; char out_file[MAXPATHLEN], *reader_id = NULL; + char tmpfn[MAXPATHLEN]; char *rr_hostname = NULL; Key *private, *public; struct passwd *pw; @@ -1334,7 +1346,11 @@ main(int ac, char **av) bits = DEFAULT_BITS; if (gen_candidates(out, memory, bits, start) != 0) fatal("modulus candidate generation failed"); - + if ((fflush(out) == EOF) || + (fsync(fileno(out)) == -1 && errno != EINVAL) || + (fclose(out) == EOF)) { + fatal("writing modulus candidate to %s failed", out_file); + } return (0); } @@ -1357,6 +1373,11 @@ main(int ac, char **av) } if (prime_test(in, out, trials, generator_wanted) != 0) fatal("modulus screening failed"); + if ((fflush(out) == EOF) || + (fsync(fileno(out)) == -1 && errno != EINVAL) || + (fclose(out) == EOF)) { + fatal("writing modulus screening to %s failed", out_file); + } return (0); } @@ -1461,20 +1482,32 @@ passphrase_again: printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); - fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + fd = create_tmpfn(identity_file, tmpfn, sizeof(tmpfn), 0644); if (fd == -1) { - printf("Could not save your public key in %s\n", identity_file); + printf("Could not create your public key file %s: %s\n", + identity_file, strerror(errno)); exit(1); } f = fdopen(fd, "w"); if (f == NULL) { - printf("fdopen %s failed", identity_file); + printf("fdopen %s failed: %s\n", tmpfn, strerror(errno)); exit(1); } if (!key_write(public, f)) fprintf(stderr, "write key failed"); fprintf(f, " %s\n", comment); - fclose(f); + if (fflush(f) == EOF || (fsync(fileno(f)) == -1 && errno != EINVAL) || + fclose(f) == EOF) { + printf("Could not write your public key in %s: %s\n", + tmpfn, strerror(errno)); + exit(1); + } + + if (rename(tmpfn, identity_file) == -1) { + printf("Could not rename %s to %s: %s\n", + tmpfn, identity_file, strerror(errno)); + exit(1); + } if (!quiet) { char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); --- openssh-4.5p1/authfile.c.bak 2006-09-01 08:38:36.000000000 +0300 +++ openssh-4.5p1/authfile.c 2007-08-21 03:24:46.296193624 +0300 @@ -70,6 +70,28 @@ static const char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1\n"; +int create_tmpfn(const char *filename, char *tmpfn, size_t tmpfnlen, mode_t mode) +{ + int fd; + int saved; + + if (snprintf(tmpfn, tmpfnlen, "%s.tmp.XXXXXX", filename) >= tmpfnlen) { + errno = ENAMETOOLONG; + return -1; + } + + fd = mkstemp(tmpfn); + if (fd != -1) { + if (fchmod(fd, mode) == -1) { + saved = errno; + close(fd); + errno = saved; + return -1; + } + } + return fd; +} + /* * Saves the authentication (private) key in a file, encrypting it with * passphrase. The identification of the file (lowest 64 bits of n) will @@ -87,6 +109,7 @@ key_save_private_rsa1(Key *key, const ch CipherContext ciphercontext; Cipher *cipher; u_int32_t rnd; + char tmpfn[MAXPATHLEN]; /* * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting @@ -154,24 +177,46 @@ key_save_private_rsa1(Key *key, const ch memset(buf, 0, sizeof(buf)); buffer_free(&buffer); - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) { - error("open %s failed: %s.", filename, strerror(errno)); + fd = create_tmpfn(filename, tmpfn, sizeof(tmpfn), 0600); + if (fd == -1) { + error("open %s failed: %s.", tmpfn, strerror(errno)); buffer_free(&encrypted); return 0; } + if (atomicio(vwrite, fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != buffer_len(&encrypted)) { - error("write to key file %s failed: %s", filename, + error("write to temp key file %s failed: %s", tmpfn, strerror(errno)); - buffer_free(&encrypted); - close(fd); - unlink(filename); - return 0; + goto close_error; } - close(fd); + + if (fsync(fd) == -1) { + error("fsync to temp key file %s failed: %s", tmpfn, + strerror(errno)); + goto close_error; + } + if (close(fd) == -1) { + error("write to temp key file %s failed: %s", tmpfn, + strerror(errno)); + goto close_error2; + } + + if (rename(tmpfn, filename) == -1) { + error("failed to rename %s to %s: %s", tmpfn, filename, + strerror(errno)); + goto close_error2; + } + buffer_free(&encrypted); return 1; + +close_error: + close(fd); +close_error2: + buffer_free(&encrypted); + unlink(tmpfn); + return 0; } /* save SSH v2 key in OpenSSL PEM format */ @@ -185,12 +230,13 @@ key_save_private_pem(Key *key, const cha int len = strlen(_passphrase); u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; + char tmpfn[MAXPATHLEN]; if (len > 0 && len <= 4) { error("passphrase too short: have %d bytes, need > 4", len); return 0; } - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = create_tmpfn(filename, tmpfn, sizeof(tmpfn), 0600); if (fd < 0) { error("open %s failed: %s.", filename, strerror(errno)); return 0; @@ -211,7 +257,19 @@ key_save_private_pem(Key *key, const cha cipher, passphrase, len, NULL, NULL); break; } - fclose(fp); + if (fflush(fp) == EOF || (fsync(fileno(fp)) == -1 && errno != EINVAL) || + fclose(fp) == EOF) { + error("failed to write to %s: %s", tmpfn, strerror(errno)); + unlink(tmpfn); + return 0; + } + if (rename(tmpfn, filename) == -1) { + error("failed to rename %s to %s: %s", tmpfn, filename, + strerror(errno)); + unlink(tmpfn); + return 0; + } + return success; }