Skip to content

Commit a176913

Browse files
committed
zfs load-key: accept -e for executable
Given a `password.sh`: ```sh promptpass "$1" >&3 ``` prompt for each password with: ``` zfs load-key -e ./password.sh -a ``` Most of the complicated parts of this code are lifted from openzfs#11731 Co-authored-by: <[email protected]>
1 parent f24c7c3 commit a176913

File tree

4 files changed

+123
-12
lines changed

4 files changed

+123
-12
lines changed

cmd/zfs/zfs_main.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8098,6 +8098,7 @@ typedef struct loadkey_cbdata {
80988098
boolean_t cb_recursive;
80998099
boolean_t cb_noop;
81008100
char *cb_keylocation;
8101+
char *cb_executable;
81018102
uint64_t cb_numfailed;
81028103
uint64_t cb_numattempted;
81038104
} loadkey_cbdata_t;
@@ -8130,7 +8131,7 @@ load_key_callback(zfs_handle_t *zhp, void *data)
81308131
cb->cb_numattempted++;
81318132

81328133
if (cb->cb_loadkey)
8133-
ret = zfs_crypto_load_key(zhp, cb->cb_noop, cb->cb_keylocation);
8134+
ret = zfs_crypto_load_key(zhp, cb->cb_noop, cb->cb_keylocation, cb->cb_executable);
81348135
else
81358136
ret = zfs_crypto_unload_key(zhp);
81368137

@@ -8151,7 +8152,7 @@ load_unload_keys(int argc, char **argv, boolean_t loadkey)
81518152

81528153
cb.cb_loadkey = loadkey;
81538154

8154-
while ((c = getopt(argc, argv, "anrL:")) != -1) {
8155+
while ((c = getopt(argc, argv, "anrL:e:")) != -1) {
81558156
/* noop and alternate keylocations only apply to zfs load-key */
81568157
if (loadkey) {
81578158
switch (c) {
@@ -8161,6 +8162,9 @@ load_unload_keys(int argc, char **argv, boolean_t loadkey)
81618162
case 'L':
81628163
cb.cb_keylocation = optarg;
81638164
continue;
8165+
case 'e':
8166+
cb.cb_executable = optarg;
8167+
continue;
81648168
default:
81658169
break;
81668170
}
@@ -8292,7 +8296,7 @@ zfs_do_change_key(int argc, char **argv)
82928296
if (loadkey) {
82938297
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
82948298
if (keystatus != ZFS_KEYSTATUS_AVAILABLE) {
8295-
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);
8299+
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL, NULL);
82968300
if (ret != 0) {
82978301
nvlist_free(props);
82988302
zfs_close(zhp);

include/libzfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ _LIBZFS_H int zfs_crypto_create(libzfs_handle_t *, char *, nvlist_t *,
535535
_LIBZFS_H int zfs_crypto_clone_check(libzfs_handle_t *, zfs_handle_t *, char *,
536536
nvlist_t *);
537537
_LIBZFS_H int zfs_crypto_attempt_load_keys(libzfs_handle_t *, char *);
538-
_LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, char *);
538+
_LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, char *, char *);
539539
_LIBZFS_H int zfs_crypto_unload_key(zfs_handle_t *);
540540
_LIBZFS_H int zfs_crypto_rewrap(zfs_handle_t *, nvlist_t *, boolean_t);
541541

lib/libzfs/libzfs_crypto.c

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <sys/zfs_context.h>
2222
#include <sys/fs/zfs.h>
2323
#include <sys/dsl_crypt.h>
24+
#include <sys/wait.h>
2425
#include <libintl.h>
2526
#include <termios.h>
2627
#include <signal.h>
@@ -471,6 +472,107 @@ get_key_material_raw(FILE *fd, zfs_keyformat_t keyformat,
471472
return (ret);
472473
}
473474

475+
static int
476+
execute_key_provider_exec(libzfs_handle_t *hdl, const char *executable,
477+
const char *fsname, zfs_keyformat_t keyformat, int *outfd)
478+
{
479+
int ret = 0, status, compipe[2];
480+
char * const argv[] =
481+
{(char *)executable, (char *)fsname, /*(char *)keyformat,*/ NULL};
482+
pid_t child;
483+
484+
if (pipe2(compipe, O_NONBLOCK | O_CLOEXEC) != 0) {
485+
ret = errno;
486+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
487+
"Failed to create key provider pipes: %s"), strerror(ret));
488+
return (ret);
489+
}
490+
491+
switch ((child = fork())) {
492+
case -1:
493+
ret = errno;
494+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
495+
"Failed to start key provider %s: %s"),
496+
executable, strerror(ret));
497+
(void) close(compipe[1]);
498+
goto end;
499+
case 0: /* child */
500+
(void) dup2(compipe[1], 3);
501+
502+
(void) execvp(executable, argv);
503+
504+
status = write(3, strerror(errno), strlen(strerror(errno)));
505+
_exit(-1);
506+
}
507+
508+
/* parent */
509+
(void) close(compipe[1]);
510+
511+
while (waitpid(child, &status, 0) == -1)
512+
if (errno != EINTR) {
513+
ret = errno;
514+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
515+
"Failed to wait for key provider %s (%d): %s"),
516+
executable, child, strerror(ret));
517+
518+
goto end;
519+
}
520+
521+
if (WIFSIGNALED(status)) {
522+
ret = EZFS_INTR;
523+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
524+
"Key provider %s killed by %s"),
525+
executable, strsignal(WTERMSIG(status)));
526+
} else if (WEXITSTATUS(status) == 0xff) {
527+
char errbuf[128] = {0};
528+
status = read(compipe[0], errbuf, sizeof (errbuf) - 1);
529+
530+
ret = ENOEXEC;
531+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
532+
"Failed to start key provider %s: %s"),
533+
executable, strlen(errbuf) ? errbuf : "(?)");
534+
} else if (WEXITSTATUS(status) != 0) {
535+
ret = ECANCELED;
536+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
537+
"Key provider %s failed with %d"),
538+
executable, WEXITSTATUS(status));
539+
}
540+
541+
end:
542+
if (ret == 0)
543+
*outfd = compipe[0];
544+
else
545+
(void) close(compipe[0]);
546+
errno = 0;
547+
return (ret);
548+
}
549+
550+
static int
551+
get_key_material_exec(libzfs_handle_t *hdl, char *executable,
552+
const char *fsname, zfs_keyformat_t keyformat,
553+
uint8_t **restrict buf, size_t *restrict len_out)
554+
{
555+
int ret = 0, rdpipe = -1;
556+
FILE *f;
557+
558+
if ((ret = execute_key_provider_exec(hdl, executable, fsname, keyformat, &rdpipe)) != 0)
559+
return (ret);
560+
561+
if ((f = fdopen(rdpipe, "r")) == NULL) {
562+
ret = errno;
563+
errno = 0;
564+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
565+
"Failed to fdopen key provider pipe"));
566+
567+
(void) close(rdpipe);
568+
return (ret);
569+
}
570+
571+
ret = get_key_material_raw(f, keyformat, buf, len_out);
572+
(void) fclose(f);
573+
return (ret);
574+
}
575+
474576
static int
475577
get_key_material_file(libzfs_handle_t *hdl, const char *uri,
476578
const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey,
@@ -677,8 +779,9 @@ get_key_material_https(libzfs_handle_t *hdl, const char *uri,
677779
*/
678780
static int
679781
get_key_material(libzfs_handle_t *hdl, boolean_t do_verify, boolean_t newkey,
680-
zfs_keyformat_t keyformat, char *keylocation, const char *fsname,
681-
uint8_t **km_out, size_t *kmlen_out, boolean_t *can_retry_out)
782+
zfs_keyformat_t keyformat, char *keylocation, char *executable,
783+
const char *fsname, uint8_t **km_out, size_t *kmlen_out,
784+
boolean_t *can_retry_out)
682785
{
683786
int ret;
684787
zfs_keylocation_t keyloc = ZFS_KEYLOCATION_NONE;
@@ -697,7 +800,11 @@ get_key_material(libzfs_handle_t *hdl, boolean_t do_verify, boolean_t newkey,
697800
/* open the appropriate file descriptor */
698801
switch (keyloc) {
699802
case ZFS_KEYLOCATION_PROMPT:
700-
if (isatty(fileno(stdin))) {
803+
if (executable != NULL) {
804+
can_retry = B_TRUE;
805+
ret = get_key_material_exec(hdl, executable, fsname,
806+
keyformat, &km, &kmlen);
807+
} else if (isatty(fileno(stdin))) {
701808
can_retry = keyformat != ZFS_KEYFORMAT_RAW;
702809
ret = get_key_interactive(hdl, fsname, keyformat,
703810
do_verify, newkey, &km, &kmlen);
@@ -854,7 +961,7 @@ populate_create_encryption_params_nvlists(libzfs_handle_t *hdl,
854961

855962
/* get key material from keyformat and keylocation */
856963
ret = get_key_material(hdl, B_TRUE, newkey, keyformat, keylocation,
857-
fsname, &key_material, &key_material_len, NULL);
964+
NULL, fsname, &key_material, &key_material_len, NULL);
858965
if (ret != 0)
859966
goto error;
860967

@@ -1214,7 +1321,7 @@ load_keys_cb(zfs_handle_t *zhp, void *arg)
12141321
/* Attempt to load the key. Record status in cb. */
12151322
cb->cb_numattempted++;
12161323

1217-
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);
1324+
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL, NULL);
12181325
if (ret)
12191326
cb->cb_numfailed++;
12201327

@@ -1266,7 +1373,7 @@ zfs_crypto_attempt_load_keys(libzfs_handle_t *hdl, char *fsname)
12661373
}
12671374

12681375
int
1269-
zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation)
1376+
zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation, char *executable)
12701377
{
12711378
int ret, attempts = 0;
12721379
char errbuf[1024];
@@ -1359,7 +1466,7 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation)
13591466

13601467
/* get key material from key format and location */
13611468
ret = get_key_material(zhp->zfs_hdl, B_FALSE, B_FALSE, keyformat,
1362-
keylocation, zfs_get_name(zhp), &key_material, &key_material_len,
1469+
keylocation, executable, zfs_get_name(zhp), &key_material, &key_material_len,
13631470
&can_retry);
13641471
if (ret != 0)
13651472
goto error;

lib/libzfs/libzfs_mount.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ zfs_mount_at(zfs_handle_t *zhp, const char *options, int flags,
463463
}
464464

465465
rc = zfs_crypto_load_key(encroot_hp,
466-
B_FALSE, NULL);
466+
B_FALSE, NULL, NULL);
467467

468468
if (!is_encroot)
469469
zfs_close(encroot_hp);

0 commit comments

Comments
 (0)