comparison gensignkey.c @ 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 d32bcb5c557d
children 8b4274d34fe8
comparison
equal deleted inserted replaced
1660:26e07f7f682a 1663:c795520269f9
7 #include "gened25519.h" 7 #include "gened25519.h"
8 #include "signkey.h" 8 #include "signkey.h"
9 #include "dbrandom.h" 9 #include "dbrandom.h"
10 10
11 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ 11 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
12 static int buf_writefile(buffer * buf, const char * filename) { 12 static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
13 int ret = DROPBEAR_FAILURE; 13 int ret = DROPBEAR_FAILURE;
14 int fd = -1; 14 int fd = -1;
15 15
16 fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 16 fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
17 if (fd < 0) { 17 if (fd < 0) {
18 dropbear_log(LOG_ERR, "Couldn't create new file %s: %s", 18 /* If generating keys on connection (skip_exist) it's OK to get EEXIST
19 filename, strerror(errno)); 19 - we probably just lost a race with another connection to generate the key */
20 if (skip_exist && errno == EEXIST) {
21 ret = DROPBEAR_SUCCESS;
22 } else {
23 dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
24 filename, strerror(errno));
25 }
26
20 goto out; 27 goto out;
21 } 28 }
22 29
23 /* write the file now */ 30 /* write the file now */
24 while (buf->pos != buf->len) { 31 while (buf->pos != buf->len) {
142 key = NULL; 149 key = NULL;
143 buf_setpos(buf, 0); 150 buf_setpos(buf, 0);
144 151
145 fn_temp = m_malloc(strlen(filename) + 30); 152 fn_temp = m_malloc(strlen(filename) + 30);
146 snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid()); 153 snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
147 ret = buf_writefile(buf, fn_temp); 154 ret = buf_writefile(buf, fn_temp, 0);
148 155
149 if (ret == DROPBEAR_FAILURE) { 156 if (ret == DROPBEAR_FAILURE) {
150 goto out; 157 goto out;
151 } 158 }
152 159
153 if (link(fn_temp, filename) < 0) { 160 if (link(fn_temp, filename) < 0) {
154 /* If generating keys on connection (skipexist) it's OK to get EEXIST 161 /* If generating keys on connection (skipexist) it's OK to get EEXIST
155 - we probably just lost a race with another connection to generate the key */ 162 - we probably just lost a race with another connection to generate the key */
156 if (!(skip_exist && errno == EEXIST)) { 163 if (!(skip_exist && errno == EEXIST)) {
157 dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename, 164 if (errno == EPERM || errno == EACCES) {
158 strerror(errno)); 165 /* Non-atomic fallback when hard-links not allowed or unsupported */
159 /* XXX fallback to non-atomic copy for some filesystems? */ 166 buf_setpos(buf, 0);
160 ret = DROPBEAR_FAILURE; 167 ret = buf_writefile(buf, filename, skip_exist);
168 } else {
169 dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
170 strerror(errno));
171 ret = DROPBEAR_FAILURE;
172 }
173
161 goto out; 174 goto out;
162 } 175 }
163 } 176 }
164 177
165 /* ensure directory update is flushed to disk, otherwise we can end up 178 /* ensure directory update is flushed to disk, otherwise we can end up