mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-13 09:37:13 +03:00
Explode out the implementation. Add bin/unlock. Trim extraneous NEEDEDs
This commit is contained in:
parent
c6e322e2ba
commit
bff67ccaa6
1
Makefile
1
Makefile
@ -65,6 +65,7 @@ $(OUTDIR)%$(EXE) : $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(SRCDIR)bin/
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CXXAR) -o$@ $^ $(PIC) $(LDAR)
|
||||
$(STRIP) $(STRIPAR) $@
|
||||
$(LDD) --unused $@ | $(AWK) -F/ 'BEGIN {args = ""} /^\t/ {args = args " --remove-needed " $$NF} END { if(!args) exit; print "$(PATCHELF)" args " $@"}' | sh -x
|
||||
|
||||
$(OBJDIR)%$(OBJ) : $(SRCDIR)%.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
|
@ -52,6 +52,9 @@ TZPFMS_VERSION := "0.0.0-$(shell git rev-list HEAD --count)"
|
||||
INCCMAKEAR := CXXFLAGS="$(INCCXXAR)"
|
||||
LNCMAKEAR := LDFLAGS="$(LNCXXAR)"
|
||||
|
||||
LDD ?= ldd
|
||||
AWK ?= awk
|
||||
PATCHELF ?= patchelf
|
||||
OBJ := .o
|
||||
CXXAR := -O3 -std=c++17 -fno-exceptions -Wall -Wextra $(CXXSPECIFIC) -pipe $(INCCXXAR) $(PIC)
|
||||
STRIP ?= strip
|
||||
|
@ -1,139 +0,0 @@
|
||||
#include <libnvpair.h>
|
||||
#include <libzfs.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
// #include <sys/zio_crypt.h>
|
||||
#define WRAPPING_KEY_LEN 32
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// clang++ -Wall -Wextra -pedantic -Wno-gnu-{statement-expression,include-next} -fno-exceptions -O3 -std=c++17 getprop.cpp -ogetprop $(pkg-config --cflags --libs libzfs{,_core}) -lrt
|
||||
|
||||
|
||||
template <class F>
|
||||
struct quickscope_wrapper {
|
||||
F func;
|
||||
|
||||
~quickscope_wrapper() { func(); }
|
||||
};
|
||||
|
||||
template <class F>
|
||||
quickscope_wrapper(F)->quickscope_wrapper<F>;
|
||||
|
||||
|
||||
static const constexpr uint8_t our_test_key[WRAPPING_KEY_LEN] = {
|
||||
0xe2, 0xac, 0xf7, 0x89, 0x32, 0x37, 0xcb, 0x94, 0x67, 0xeb, 0x2b, 0xe9, 0xa3, 0x48, 0x83, 0x72,
|
||||
0xd5, 0x4c, 0xc5, 0x1c, 0x99, 0x65, 0xb0, 0x8d, 0x05, 0xa6, 0xd5, 0xff, 0x7a, 0xf7, 0xeb, 0xfc,
|
||||
};
|
||||
|
||||
|
||||
#define RETERR (__COUNTER__ + 1)
|
||||
#define TRY_GENERIC(what, cond_pre, cond_post, err_src, ...) \
|
||||
({ \
|
||||
auto _try_ret = (__VA_ARGS__); \
|
||||
if(cond_pre _try_ret cond_post) { \
|
||||
if constexpr(what != nullptr) \
|
||||
fprintf(stderr, "Couldn't %s: %s\n", static_cast<const char *>(what), strerror(err_src)); \
|
||||
return RETERR; \
|
||||
} \
|
||||
_try_ret; \
|
||||
})
|
||||
#define TRY(what, ...) TRY_GENERIC(what, , == -1, errno, __VA_ARGS__)
|
||||
#define TRY_PTR(what, ...) TRY_GENERIC(what, !, , errno, __VA_ARGS__)
|
||||
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, __VA_ARGS__)
|
||||
#define TRY_MAIN(...) \
|
||||
do { \
|
||||
if(auto _try_ret = (__VA_ARGS__)) \
|
||||
return _try_ret; \
|
||||
} while(0)
|
||||
|
||||
|
||||
template <class F>
|
||||
static int with_stdin_at(int fd, F && what) {
|
||||
auto stdin_saved = TRY("dup() stdin", dup(0));
|
||||
quickscope_wrapper stdin_saved_deleter{[=] { close(stdin_saved); }};
|
||||
|
||||
TRY("dup2() onto stdin", dup2(fd, 0));
|
||||
|
||||
if(int ret = what()) {
|
||||
dup2(stdin_saved, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TRY("dup2() stdin back onto stdin", dup2(stdin_saved, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// with_len may not exceed pipe capacity (64k by default)
|
||||
static int filled_fd(int & fd, const void * with, size_t with_len) {
|
||||
int pipes[2];
|
||||
TRY("create buffer pipe", pipe(pipes));
|
||||
quickscope_wrapper pipes_w_deleter{[=] { close(pipes[1]); }};
|
||||
fd = pipes[0];
|
||||
|
||||
auto ret = write(pipes[1], with, with_len);
|
||||
if(ret >= 0 && ret < WRAPPING_KEY_LEN) {
|
||||
ret = -1;
|
||||
errno = ENODATA;
|
||||
}
|
||||
TRY("write to buffer pipe", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int, char ** argv) {
|
||||
const auto libz = TRY_PTR("initialise libzfs", libzfs_init());
|
||||
quickscope_wrapper libz_deleter{[=] { libzfs_fini(libz); }};
|
||||
|
||||
libzfs_print_on_error(libz, B_TRUE);
|
||||
|
||||
auto dataset = TRY_PTR(nullptr, zfs_open(libz, argv[1], ZFS_TYPE_FILESYSTEM));
|
||||
quickscope_wrapper dataset_deleter{[&] { zfs_close(dataset); }};
|
||||
|
||||
{
|
||||
char encryption_root[MAXNAMELEN];
|
||||
boolean_t dataset_is_root;
|
||||
TRY("get encryption root", zfs_crypto_get_encryption_root(dataset, &dataset_is_root, encryption_root));
|
||||
|
||||
if(!dataset_is_root && !strlen(encryption_root)) {
|
||||
fprintf(stderr, "Dataset %s not encrypted?\n", zfs_get_name(dataset));
|
||||
return RETERR;
|
||||
} else if(!dataset_is_root) {
|
||||
printf("Using dataset %s's encryption root %s instead.\n", zfs_get_name(dataset), encryption_root);
|
||||
// TODO: disallow maybe? or require force option?
|
||||
zfs_close(dataset);
|
||||
dataset = TRY_PTR(nullptr, zfs_open(libz, encryption_root, ZFS_TYPE_FILESYSTEM));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY;
|
||||
/// this user-proofs the set-up, and means we don't have to touch the filesysten:
|
||||
/// instead, get an FD, write the raw key data there, dup() it onto stdin,
|
||||
/// let libzfs read it, then restore stdin
|
||||
|
||||
int key_fd;
|
||||
TRY_MAIN(filled_fd(key_fd, (void *)our_test_key, WRAPPING_KEY_LEN));
|
||||
quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }};
|
||||
|
||||
TRY_MAIN(with_stdin_at(key_fd, [&] {
|
||||
nvlist_t * rewrap_args;
|
||||
TRY_NVL("allocate rewrap nvlist", nvlist_alloc(&rewrap_args, NV_UNIQUE_NAME, 0));
|
||||
quickscope_wrapper rewrap_args_deleter{[=] { nvlist_free(rewrap_args); }};
|
||||
TRY_NVL("add keyformat to rewrap nvlist",
|
||||
nvlist_add_string(rewrap_args, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), "raw")); // Why can't this be uint64 and ZFS_KEYFORMAT_RAW?
|
||||
TRY_NVL("add keylocation to rewrap nvlist", nvlist_add_string(rewrap_args, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt"));
|
||||
if(zfs_crypto_rewrap(dataset, rewrap_args, B_FALSE))
|
||||
return RETERR; // Error printed by libzfs
|
||||
else
|
||||
printf("Key for %s changed\n", zfs_get_name(dataset));
|
||||
|
||||
return 0;
|
||||
}));
|
||||
|
||||
const auto props = zfs_get_all_props(dataset);
|
||||
dump_nvlist(props, 2);
|
||||
}
|
46
src/bin/rewrap.cpp
Normal file
46
src/bin/rewrap.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include <libzfs.h>
|
||||
// #include <sys/zio_crypt.h>
|
||||
#define WRAPPING_KEY_LEN 32
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../fd.hpp"
|
||||
#include "../main.hpp"
|
||||
#include "../zfs.hpp"
|
||||
|
||||
|
||||
static const constexpr uint8_t our_test_key[WRAPPING_KEY_LEN] = {
|
||||
0xe2, 0xac, 0xf7, 0x89, 0x32, 0x37, 0xcb, 0x94, 0x67, 0xeb, 0x2b, 0xe9, 0xa3, 0x48, 0x83, 0x72,
|
||||
0xd5, 0x4c, 0xc5, 0x1c, 0x99, 0x65, 0xb0, 0x8d, 0x05, 0xa6, 0xd5, 0xff, 0x7a, 0xf7, 0xeb, 0xfc,
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
return do_main(
|
||||
argc, argv, "", [](auto) {},
|
||||
[](auto dataset) {
|
||||
/// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY;
|
||||
/// this user-proofs the set-up, and means we don't have to touch the filesysten:
|
||||
/// instead, get an FD, write the raw key data there, dup() it onto stdin,
|
||||
/// let libzfs read it, then restore stdin
|
||||
|
||||
int key_fd;
|
||||
TRY_MAIN(filled_fd(key_fd, (void *)our_test_key, WRAPPING_KEY_LEN));
|
||||
quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }};
|
||||
|
||||
|
||||
TRY_MAIN(with_stdin_at(key_fd, [&] {
|
||||
if(zfs_crypto_rewrap(dataset, TRY_PTR("get rewrap args", rewrap_args()), B_FALSE))
|
||||
return __LINE__; // Error printed by libzfs
|
||||
else
|
||||
printf("Key for %s changed\n", zfs_get_name(dataset));
|
||||
|
||||
return 0;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
41
src/bin/unlock.cpp
Normal file
41
src/bin/unlock.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include <libzfs.h>
|
||||
// #include <sys/zio_crypt.h>
|
||||
#define WRAPPING_KEY_LEN 32
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../fd.hpp"
|
||||
#include "../main.hpp"
|
||||
|
||||
|
||||
static const constexpr uint8_t our_test_key[WRAPPING_KEY_LEN] = {
|
||||
0xe2, 0xac, 0xf7, 0x89, 0x32, 0x37, 0xcb, 0x94, 0x67, 0xeb, 0x2b, 0xe9, 0xa3, 0x48, 0x83, 0x72,
|
||||
0xd5, 0x4c, 0xc5, 0x1c, 0x99, 0x65, 0xb0, 0x8d, 0x05, 0xa6, 0xd5, 0xff, 0x7a, 0xf7, 0xeb, 0xfc,
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
auto noop = B_FALSE;
|
||||
return do_main(
|
||||
argc, argv, "n", [&](char) { noop = B_TRUE; },
|
||||
[&](auto dataset) {
|
||||
int key_fd;
|
||||
TRY_MAIN(filled_fd(key_fd, (void *)our_test_key, WRAPPING_KEY_LEN));
|
||||
quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }};
|
||||
|
||||
|
||||
TRY_MAIN(with_stdin_at(key_fd, [&] {
|
||||
if(zfs_crypto_load_key(dataset, noop, nullptr))
|
||||
return __LINE__; // Error printed by libzfs
|
||||
else
|
||||
printf("Key for %s loaded\n", zfs_get_name(dataset));
|
||||
|
||||
return 0;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
33
src/common.hpp
Normal file
33
src/common.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define TRY_GENERIC(what, cond_pre, cond_post, err_src, err_ret, ...) \
|
||||
({ \
|
||||
auto _try_ret = (__VA_ARGS__); \
|
||||
if(cond_pre _try_ret cond_post) { \
|
||||
if constexpr(what != nullptr) \
|
||||
fprintf(stderr, "Couldn't %s: %s\n", static_cast<const char *>(what), strerror(err_src)); \
|
||||
return err_ret; \
|
||||
} \
|
||||
_try_ret; \
|
||||
})
|
||||
#define TRY(what, ...) TRY_GENERIC(what, , == -1, errno, __LINE__, __VA_ARGS__)
|
||||
|
||||
|
||||
template <class F>
|
||||
struct quickscope_wrapper {
|
||||
F func;
|
||||
|
||||
~quickscope_wrapper() { func(); }
|
||||
};
|
||||
|
||||
template <class F>
|
||||
quickscope_wrapper(F)->quickscope_wrapper<F>;
|
21
src/fd.cpp
Normal file
21
src/fd.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include "fd.hpp"
|
||||
|
||||
|
||||
int filled_fd(int & fd, const void * with, size_t with_len) {
|
||||
int pipes[2];
|
||||
TRY("create buffer pipe", pipe(pipes));
|
||||
quickscope_wrapper pipes_w_deleter{[=] { close(pipes[1]); }};
|
||||
fd = pipes[0];
|
||||
|
||||
auto ret = write(pipes[1], with, with_len);
|
||||
if(ret >= 0 && static_cast<size_t>(ret) < with_len) {
|
||||
ret = -1;
|
||||
errno = ENODATA;
|
||||
}
|
||||
TRY("write to buffer pipe", ret);
|
||||
|
||||
return 0;
|
||||
}
|
28
src/fd.hpp
Normal file
28
src/fd.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "common.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
template <class F>
|
||||
int with_stdin_at(int fd, F && what) {
|
||||
auto stdin_saved = TRY("dup() stdin", dup(0));
|
||||
quickscope_wrapper stdin_saved_deleter{[=] { close(stdin_saved); }};
|
||||
|
||||
TRY("dup2() onto stdin", dup2(fd, 0));
|
||||
|
||||
if(int ret = what()) {
|
||||
dup2(stdin_saved, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TRY("dup2() stdin back onto stdin", dup2(stdin_saved, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// with_len may not exceed pipe capacity (64k by default)
|
||||
extern int filled_fd(int & fd, const void * with, size_t with_len);
|
62
src/main.hpp
Normal file
62
src/main.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "common.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define TRY_PTR(what, ...) TRY_GENERIC(what, !, , errno, __LINE__, __VA_ARGS__)
|
||||
#define TRY_MAIN(...) \
|
||||
do { \
|
||||
if(auto _try_ret = (__VA_ARGS__)) \
|
||||
return _try_ret; \
|
||||
} while(0)
|
||||
|
||||
|
||||
template <class G, class M>
|
||||
int do_main(int argc, char ** argv, const char * getoptions, G && getoptfn, M && main) {
|
||||
const auto libz = TRY_PTR("initialise libzfs", libzfs_init());
|
||||
quickscope_wrapper libz_deleter{[=] { libzfs_fini(libz); }};
|
||||
|
||||
libzfs_print_on_error(libz, B_TRUE);
|
||||
|
||||
#if __GLIBC__
|
||||
setenv("POSIXLY_CORRECT", "1", true);
|
||||
#endif
|
||||
for(int opt; (opt = getopt(argc, argv, getoptions)) != -1;)
|
||||
if(opt == '?')
|
||||
return __LINE__;
|
||||
else
|
||||
getoptfn(opt);
|
||||
|
||||
if(optind >= argc) {
|
||||
fprintf(stderr, "No dataset to act on?\n");
|
||||
return __LINE__;
|
||||
}
|
||||
auto dataset = TRY_PTR(nullptr, zfs_open(libz, argv[optind], ZFS_TYPE_FILESYSTEM));
|
||||
quickscope_wrapper dataset_deleter{[&] { zfs_close(dataset); }};
|
||||
|
||||
{
|
||||
char encryption_root[MAXNAMELEN];
|
||||
boolean_t dataset_is_root;
|
||||
TRY("get encryption root", zfs_crypto_get_encryption_root(dataset, &dataset_is_root, encryption_root));
|
||||
|
||||
if(!dataset_is_root && !strlen(encryption_root)) {
|
||||
fprintf(stderr, "Dataset %s not encrypted?\n", zfs_get_name(dataset));
|
||||
return __LINE__;
|
||||
} else if(!dataset_is_root) {
|
||||
printf("Using dataset %s's encryption root %s instead.\n", zfs_get_name(dataset), encryption_root);
|
||||
// TODO: disallow maybe? or require force option?
|
||||
strcpy(argv[1], encryption_root);
|
||||
zfs_close(dataset);
|
||||
dataset = TRY_PTR(nullptr, zfs_open(libz, encryption_root, ZFS_TYPE_FILESYSTEM));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return main(dataset);
|
||||
}
|
33
src/zfs.cpp
Normal file
33
src/zfs.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include "zfs.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
|
||||
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, _try_ret, __VA_ARGS__)
|
||||
|
||||
|
||||
nvlist_t * rewrap_args() {
|
||||
static nvlist_t * ret{};
|
||||
static quickscope_wrapper ret_deleter{[&] { nvlist_free(ret); }};
|
||||
|
||||
if(!ret)
|
||||
if(auto err =
|
||||
[&] {
|
||||
TRY_NVL("allocate rewrap nvlist", nvlist_alloc(&ret, NV_UNIQUE_NAME, 0));
|
||||
TRY_NVL("add keyformat to rewrap nvlist",
|
||||
nvlist_add_string(ret, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), "raw")); // Why can't this be uint64 and ZFS_KEYFORMAT_RAW?
|
||||
TRY_NVL("add keylocation to rewrap nvlist", nvlist_add_string(ret, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt"));
|
||||
return 0;
|
||||
}();
|
||||
err && ret) {
|
||||
nvlist_free(ret);
|
||||
ret = nullptr;
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
15
src/zfs.hpp
Normal file
15
src/zfs.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <libnvpair.h>
|
||||
// #include <libzfs.h>
|
||||
// #include <sys/fs/zfs.h>
|
||||
//// #include <sys/zio_crypt.h>
|
||||
// #define WRAPPING_KEY_LEN 32
|
||||
|
||||
|
||||
/// Static nvlist with {keyformat=raw, keylocation=prompt}
|
||||
extern nvlist_t * rewrap_args();
|
Loading…
x
Reference in New Issue
Block a user