diff --git a/initrd/mount.h b/initrd/mount.h index 2bf4ff5..912da35 100644 --- a/initrd/mount.h +++ b/initrd/mount.h @@ -11,7 +11,7 @@ [ -s /run/tzpfms-err ] && plymouth display-message --text="$(cat /run/tzpfms-err)" elif [ -e /run/systemd/system ] && command -v systemd-ask-password > /dev/null; then # --no-tty matches zfs and actually works # shellcheck disable=SC2016 - TZPFMS_PASSPHRASE_HELPER='exec systemd-ask-password --no-tty --id="tzpfms:$2" "$1: "' "$@" 2>/run/tzpfms-err; ret="$?" + TZPFMS_PASSPHRASE_HELPER='exec systemd-ask-password --no-tty --id="tzpfms:$2" "$1:"' "$@" 2>/run/tzpfms-err; ret="$?" else # Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet" read -r printk _ < /proc/sys/kernel/printk diff --git a/man/passphrase.h b/man/passphrase.h index 399e40e..0addd2a 100644 --- a/man/passphrase.h +++ b/man/passphrase.h @@ -3,24 +3,33 @@ .Sh ENVIRONMENT VARIABLES .Bl -tag -compact -width "TZPFMS" .It Ev TZPFMS_PASSPHRASE_HELPER -If set and nonempty, will be run as -.Dl Pa /bin/ Ns Nm sh Fl c Li \&"$TZPFMS_PASSPHRASE_HELPER" \&"$TZPFMS_PASSPHRASE_HELPER" Qo Ar prepared prompt Qc Qo Ar target Qc Qo Oo Li new Oc Qc Qo Oo Li again Oc Qc -to provide a passphrase, instead of reading from the standard input. +If set and nonempty, will be run via +.Pa /bin/ Ns Nm sh Fl c +.\"Li \&"$TZPFMS_PASSPHRASE_HELPER" \&"$TZPFMS_PASSPHRASE_HELPER" Qo Ar prepared prompt Qc Qo Ar target Qc Qo Oo Li new Oc Qc Qo Oo Li again Oc Qc +to provide a passphrase, instead of reading from the standard input stream. .Pp The standard output stream of the helper is tied to an anonymous file and used in its entirety as the passphrase, except for a trailing new-line, if any. -The second argument contains either the dataset name or the element of the TPM hierarchy. -The third argument is -.Li new -if this is for a new passphrase, and the fourth is -.Li again -if it's the second prompt for that passphrase. -The first argument already contains all of this information, as a pre-formatted noun phrase. +The arguments are: +.Bl -enum -compact -offset "@@" -width "@" +.It +Pre-formatted noun phrase with all the information below +.It +Either the dataset name or the element of the TPM hierarchy. +.It +.Qq new +if this is for a new passphrase +.It +.Qq again +if it's the second prompt for that passphrase +.El .Pp If the helper doesn't exist .Pq the shell exits with Sy 127 , a diagnostic is issued and the normal prompt is used as fall-back. If it fails for any other reason, the prompting is aborted. .Pp -An example value would be: -.No ' Ns Nm systemd-ask-password Fl -id Ns Li = Ns Qo Li tzpfms:\& Ns Ar $2 Qc Qo Ar $1 Ns Li ": " Qc Ns ' . +An example value facilitating +.Xr systemd 1 +integration would be: +.No ' Ns Ic exec Nm systemd-ask-password Fl -id Ns Li = Ns Qo Li tzpfms:\& Ns Ar $2 Qc Qo Ar $1 Ns Li ": " Qc Ns ' . .El diff --git a/src/fd.cpp b/src/fd.cpp index 295f8ba..f151355 100644 --- a/src/fd.cpp +++ b/src/fd.cpp @@ -107,19 +107,25 @@ static int get_key_material_helper(const char * helper, const char * whom, bool case 0: struct stat sb; fstat(outfd, &sb); - if(auto out = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, outfd, 0); out != MAP_FAILED) { + if(!sb.st_size) // unmmappable + return buf = nullptr, len_out = 0, 0; + else if(auto out = static_cast(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); }}; - buf = static_cast(malloc(sb.st_size)); // TODO:if failed len_out = sb.st_size; - memcpy(buf, out, sb.st_size); - // Trim ending newline, if any - if(buf[len_out - 1] == '\n') - buf[--len_out] = '\0'; + if(out[len_out - 1] == '\n') // Trim ending newline, if any + --len_out; + if(!len_out) + buf = nullptr; + else { + if(!(buf = static_cast(malloc(len_out)))) + len_out = 0, (void)TRY("allocate passphrase", -1); + memcpy(buf, out, len_out); + } return 0; } else - ; // error + TRY("read back passphrase", -1); - case 127: // enoent, error already written by shell or child + case 127: // ENOENT, error already written by shell or child return -1; default: @@ -215,8 +221,8 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint static int get_key_material_dispatch(const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) { static const char * helper{}; if(!helper) - helper = getenv("TZPFMS_PASSPHRASE_HELPER"); - if(helper && *helper) { + helper = getenv("TZPFMS_PASSPHRASE_HELPER") ?: ""; + if(*helper) { if(auto err = get_key_material_helper(helper, whom, again, newkey, buf, len_out); err != -1) return err; else