changeset 1663:c795520269f9

Fallback for key gen without hard link support (#89) Add a non-atomic fallback for key generation on platforms where link() is not permitted (such as most stock Android installs) or on filesystems without hard link support (such as FAT).
author Matt Robinson <git@nerdoftheherd.com>
date Sat, 14 Mar 2020 14:37:35 +0000
parents 26e07f7f682a
children 871484eac157
files gensignkey.c
diffstat 1 files changed, 21 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/gensignkey.c	Sat Mar 14 14:21:01 2020 +0000
+++ b/gensignkey.c	Sat Mar 14 14:37:35 2020 +0000
@@ -9,14 +9,21 @@
 #include "dbrandom.h"
 
 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-static int buf_writefile(buffer * buf, const char * filename) {
+static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
 	int ret = DROPBEAR_FAILURE;
 	int fd = -1;
 
 	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
 	if (fd < 0) {
-		dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
-			filename, strerror(errno));
+		/* If generating keys on connection (skip_exist) it's OK to get EEXIST
+		- we probably just lost a race with another connection to generate the key */
+		if (skip_exist && errno == EEXIST) {
+			ret = DROPBEAR_SUCCESS;
+		} else {
+			dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
+				filename, strerror(errno));
+		}
+
 		goto out;
 	}
 
@@ -144,7 +151,7 @@
 
 	fn_temp = m_malloc(strlen(filename) + 30);
 	snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
-	ret = buf_writefile(buf, fn_temp);
+	ret = buf_writefile(buf, fn_temp, 0);
 
 	if (ret == DROPBEAR_FAILURE) {
 		goto out;
@@ -154,10 +161,16 @@
 		/* If generating keys on connection (skipexist) it's OK to get EEXIST 
 		- we probably just lost a race with another connection to generate the key */
 		if (!(skip_exist && errno == EEXIST)) {
-			dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
-				strerror(errno));
-			/* XXX fallback to non-atomic copy for some filesystems? */
-			ret = DROPBEAR_FAILURE;
+			if (errno == EPERM || errno == EACCES) {
+				/* Non-atomic fallback when hard-links not allowed or unsupported */
+				buf_setpos(buf, 0);
+				ret = buf_writefile(buf, filename, skip_exist);
+			} else {
+				dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
+					strerror(errno));
+				ret = DROPBEAR_FAILURE;
+			}
+
 			goto out;
 		}
 	}