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).
This commit is contained in:
Matt Robinson 2020-03-14 14:37:35 +00:00 committed by GitHub
parent 002b79e2f9
commit a26ad21c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -9,14 +9,21 @@
#include "dbrandom.h" #include "dbrandom.h"
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ /* 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 ret = DROPBEAR_FAILURE;
int fd = -1; int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) { if (fd < 0) {
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s", /* If generating keys on connection (skip_exist) it's OK to get EEXIST
filename, strerror(errno)); - 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; 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); fn_temp = m_malloc(strlen(filename) + 30);
snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid()); 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) { if (ret == DROPBEAR_FAILURE) {
goto out; 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 /* 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 */ - we probably just lost a race with another connection to generate the key */
if (!(skip_exist && errno == EEXIST)) { if (!(skip_exist && errno == EEXIST)) {
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename, if (errno == EPERM || errno == EACCES) {
strerror(errno)); /* Non-atomic fallback when hard-links not allowed or unsupported */
/* XXX fallback to non-atomic copy for some filesystems? */ buf_setpos(buf, 0);
ret = DROPBEAR_FAILURE; 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; goto out;
} }
} }