From 4ba830fc31c056aaada774ce29bb7d4e136b5dcd Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sat, 8 Nov 2014 22:15:16 +0800
Subject: [PATCH] Make sure hostkeys are flushed to disk to avoid empty files
 if the power fails. Based on patch from Peter Korsgaard

---
 gensignkey.c |  1 +
 svr-kex.c    | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/gensignkey.c b/gensignkey.c
index 338bbefe..06fdfd33 100644
--- a/gensignkey.c
+++ b/gensignkey.c
@@ -41,6 +41,7 @@ static int buf_writefile(buffer * buf, const char * filename) {
 
 out:
 	if (fd >= 0) {
+		fsync(fd);
 		m_close(fd);
 	}
 	return ret;
diff --git a/svr-kex.c b/svr-kex.c
index 337c377a..01c76e6a 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -84,7 +84,25 @@ void recv_msg_kexdh_init() {
 	TRACE(("leave recv_msg_kexdh_init"))
 }
 
+
 #ifdef DROPBEAR_DELAY_HOSTKEY
+
+static void fsync_parent_dir(const char* fn) {
+#ifdef HAVE_LIBGEN_H
+	char *fn_dir = m_strdup(fn);
+	char *dir = dirname(fn_dir);
+	/* some OSes need the fd to be writable for fsync */
+	int dirfd = open(dir, O_RDWR);
+
+	if (dirfd != -1) {
+		fsync(dirfd);
+		m_close(dirfd);
+	}
+
+	free(fn_dir);
+#endif
+}
+
 static void svr_ensure_hostkey() {
 
 	const char* fn = NULL;
@@ -142,6 +160,10 @@ static void svr_ensure_hostkey() {
 		}
 	}
 
+	/* ensure directory update is flushed to disk, otherwise we can end up
+	with zero-byte hostkey files if the power goes off */
+	fsync_parent_dir(fn);
+
 	ret = readhostkey(fn, svr_opts.hostkey, &type);
 
 	if (ret == DROPBEAR_SUCCESS) {
-- 
GitLab