mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-17 09:42:19 +03:00
Just use pipe to read passphrase from helper instead of memfd weirdness
This commit is contained in:
parent
720a0103a7
commit
d2dcf95b0f
112
src/fd.cpp
112
src/fd.cpp
@ -5,14 +5,12 @@
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
|
||||
/// Matches libzfs
|
||||
@ -69,74 +67,64 @@ int write_exact(const char * path, const void * data, size_t len, mode_t mode) {
|
||||
|
||||
/// TRY_MAIN rules, plus -1 for ENOENT
|
||||
static int get_key_material_helper(const char * helper, const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) {
|
||||
#if __linux__ || __FreeBSD__
|
||||
auto outfd = TRY_HELPER("create helper output", memfd_create(whom, MFD_CLOEXEC));
|
||||
#else
|
||||
int outfd;
|
||||
char fname[8 + 10 + 1 + 20 + 1]; // 4294967296, 18446744073709551616
|
||||
auto pid = getpid();
|
||||
for(uint64_t i = 0; i < UINT64_MAX; ++i) {
|
||||
snprintf(fname, sizeof(fname), "/tzpfms:%" PRIu32 ":%" PRIu64 "", static_cast<uint32_t>(pid), i);
|
||||
if((outfd = shm_open(fname, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0000)) != -1 || errno != EEXIST)
|
||||
break;
|
||||
int pipes[2];
|
||||
TRY("create IPC pipe", pipe2(pipes, O_CLOEXEC));
|
||||
quickscope_wrapper pipes_r_deleter{[=] { close(pipes[0]); }};
|
||||
|
||||
if(auto pid = TRY_HELPER("create child", fork()); pid == 0) { // child
|
||||
dup2(pipes[1], 1);
|
||||
|
||||
char * msg;
|
||||
if(asprintf(&msg, "%sassphrase for %s%s", newkey ? "New p" : "P", whom, again ? " (again)" : "") == -1)
|
||||
msg = const_cast<char *>(whom);
|
||||
execl("/bin/sh", "sh", "-c", helper, helper, msg, whom, newkey ? "new" : "", again ? "again" : "", nullptr);
|
||||
|
||||
int exec_err = errno;
|
||||
fprintf(stderr, "exec(/bin/sh): %s\n", strerror(errno));
|
||||
_exit(exec_err == ENOENT ? 127 : 126);
|
||||
}
|
||||
TRY_HELPER("create helper output", outfd);
|
||||
shm_unlink(fname);
|
||||
#endif
|
||||
quickscope_wrapper outfd_deleter{[=] { close(outfd); }};
|
||||
close(pipes[1]);
|
||||
|
||||
switch(auto pid = TRY_HELPER("create child", fork())) {
|
||||
case 0: // child
|
||||
dup2(outfd, 1);
|
||||
|
||||
char * msg;
|
||||
if(asprintf(&msg, "%sassphrase for %s%s", newkey ? "New p" : "P", whom, again ? " (again)" : "") == -1)
|
||||
msg = const_cast<char *>(whom);
|
||||
execl("/bin/sh", "sh", "-c", helper, helper, msg, whom, newkey ? "new" : "", again ? "again" : "", nullptr);
|
||||
fprintf(stderr, "exec(/bin/sh): %s\n", strerror(errno));
|
||||
_exit(127);
|
||||
buf = nullptr;
|
||||
len_out = 0;
|
||||
for(size_t len_cap = 0;;) { // 99% of cases this is 1 allocation and 1 read
|
||||
if(len_out == len_cap) {
|
||||
len_cap += 120;
|
||||
buf = TRY_PTR("allocate passphrase", static_cast<uint8_t *>(realloc(buf, len_cap)));
|
||||
}
|
||||
|
||||
ssize_t rd;
|
||||
while((rd = read(pipes[0], buf + len_out, len_cap - len_out)) == -1 && errno == EINTR)
|
||||
;
|
||||
TRY("read passphrase from helper", rd);
|
||||
if(rd == 0)
|
||||
break;
|
||||
|
||||
default: // parent
|
||||
int err, ret;
|
||||
while((ret = waitpid(pid, &err, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
TRY("wait for helper", ret);
|
||||
len_out += rd;
|
||||
}
|
||||
if(len_out && buf[len_out - 1] == '\n')
|
||||
--len_out;
|
||||
|
||||
if(WIFEXITED(err)) {
|
||||
switch(WEXITSTATUS(err)) {
|
||||
case 0:
|
||||
struct stat sb;
|
||||
fstat(outfd, &sb);
|
||||
if(!sb.st_size) // unmmappable
|
||||
return buf = nullptr, len_out = 0, 0;
|
||||
else if(auto out = static_cast<uint8_t *>(mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, outfd, 0)); out != MAP_FAILED) {
|
||||
quickscope_wrapper out_deleter{[=] { munmap(out, sb.st_size); }};
|
||||
len_out = sb.st_size;
|
||||
if(out[len_out - 1] == '\n') // Trim ending newline, if any
|
||||
--len_out;
|
||||
if(!len_out)
|
||||
buf = nullptr;
|
||||
else {
|
||||
if(!(buf = static_cast<uint8_t *>(malloc(len_out))))
|
||||
len_out = 0, (void)TRY("allocate passphrase", -1);
|
||||
memcpy(buf, out, len_out);
|
||||
}
|
||||
return 0;
|
||||
} else
|
||||
TRY("read back passphrase", -1);
|
||||
|
||||
case 127: // ENOENT, error already written by shell or child
|
||||
return -1;
|
||||
int err, ret;
|
||||
while((ret = wait(&err)) == -1 && errno == EINTR)
|
||||
;
|
||||
TRY("wait for helper", ret);
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Helper '%s' failed with %d.\n", helper, WEXITSTATUS(err));
|
||||
return __LINE__;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Helper '%s' died to signal %d: %s.\n", helper, WTERMSIG(err), strsignal(WTERMSIG(err)));
|
||||
if(WIFEXITED(err))
|
||||
switch(WEXITSTATUS(err)) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 127: // ENOENT, error already written by shell or child
|
||||
return -1;
|
||||
default:
|
||||
fprintf(stderr, "Helper '%s' failed with %d.\n", helper, WEXITSTATUS(err));
|
||||
return __LINE__;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Helper '%s' died to signal %d: %s.\n", helper, WTERMSIG(err), strsignal(WTERMSIG(err)));
|
||||
return __LINE__;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user