From a26ad21c0a80d38d3656a26c921d7e0f9d463ea2 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Sat, 14 Mar 2020 14:37:35 +0000 Subject: [PATCH] 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). --- gensignkey.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/gensignkey.c b/gensignkey.c index 674d81f..4be3d7d 100644 --- a/gensignkey.c +++ b/gensignkey.c @@ -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 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename, 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 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename, /* 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; } }