aboutsummaryrefslogtreecommitdiff
path: root/nitrocli
diff options
context:
space:
mode:
Diffstat (limited to 'nitrocli')
-rw-r--r--nitrocli/CHANGELOG.md2
-rw-r--r--nitrocli/doc/nitrocli.19
-rw-r--r--nitrocli/doc/nitrocli.1.pdfbin17751 -> 18096 bytes
-rw-r--r--nitrocli/src/args.rs2
-rw-r--r--nitrocli/src/commands.rs13
-rw-r--r--nitrocli/src/main.rs4
-rw-r--r--nitrocli/src/pinentry.rs19
-rw-r--r--nitrocli/src/tests/mod.rs1
8 files changed, 38 insertions, 12 deletions
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md
index 0170fb7..fe3ac74 100644
--- a/nitrocli/CHANGELOG.md
+++ b/nitrocli/CHANGELOG.md
@@ -3,6 +3,8 @@ Unreleased
- Added the `reset` command to perform a factory reset
- Added the `-V`/`--version` option to print the program's version
- Check the status of a PWS slot before accessing it in `pws get`
+- Added `NITROCLI_NO_CACHE` environment variable to bypass caching of
+ secrets
- Bumped `libc` dependency to `0.2.55`
- Bumped `cc` dependency to `1.0.37`
diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1
index 66d73f9..9029335 100644
--- a/nitrocli/doc/nitrocli.1
+++ b/nitrocli/doc/nitrocli.1
@@ -1,4 +1,4 @@
-.TH NITROCLI 1 2019-01-21
+.TH NITROCLI 1 2019-05-26
.SH NAME
nitrocli \- access Nitrokey devices
.SH SYNOPSIS
@@ -279,6 +279,13 @@ for the \fBuser\fR type.
.TP
.B NITROCLI_PASSWORD
A password used by commands that require one (e.g., \fBstorage hidden open\fR).
+.TP
+.B NITROCLI_NO_CACHE
+If this variable is present in the environment, do not cache any inquired
+secrets using \fBgpg\-agent\fR(1) but ask for them each time they are needed.
+Note that this variable does not cause any cached secrets to be cleared. If a
+secret is already in the cache it will be ignored, but left otherwise untouched.
+Use the \fBpin clear\fR command to clear secrets from the cache.
.SH EXAMPLES
.SS Storage
diff --git a/nitrocli/doc/nitrocli.1.pdf b/nitrocli/doc/nitrocli.1.pdf
index ff72f94..fa4e4bc 100644
--- a/nitrocli/doc/nitrocli.1.pdf
+++ b/nitrocli/doc/nitrocli.1.pdf
Binary files differ
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs
index 82e9c2a..10a097e 100644
--- a/nitrocli/src/args.rs
+++ b/nitrocli/src/args.rs
@@ -91,6 +91,7 @@ pub struct ExecCtx<'io> {
pub new_admin_pin: Option<ffi::OsString>,
pub new_user_pin: Option<ffi::OsString>,
pub password: Option<ffi::OsString>,
+ pub no_cache: bool,
pub verbosity: u64,
}
@@ -929,6 +930,7 @@ pub(crate) fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec<String>) -> Resul
new_admin_pin: ctx.new_admin_pin.take(),
new_user_pin: ctx.new_user_pin.take(),
password: ctx.password.take(),
+ no_cache: ctx.no_cache,
verbosity,
};
command.execute(&mut ctx, subargs)
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs
index 82d6240..a81859c 100644
--- a/nitrocli/src/commands.rs
+++ b/nitrocli/src/commands.rs
@@ -166,7 +166,7 @@ fn get_volume_status(status: &nitrokey::VolumeStatus) -> &'static str {
///
/// This function will query the pin of the given type from the user
/// using pinentry. It will then execute the given function. If this
-/// function returns a result, the result will be passed it on. If it
+/// function returns a result, the result will be passed on. If it
/// returns a `CommandError::WrongPassword`, the user will be asked
/// again to enter the pin. Otherwise, this function returns an error
/// containing the given error message. The user will have at most
@@ -177,6 +177,7 @@ fn get_volume_status(status: &nitrokey::VolumeStatus) -> &'static str {
/// second or third try, it will call `op` with the data returned by the
/// previous call to `op`.
fn try_with_pin_and_data_with_pinentry<D, F, R>(
+ ctx: &mut args::ExecCtx<'_>,
pin_entry: &pinentry::PinEntry,
msg: &'static str,
data: D,
@@ -189,7 +190,7 @@ where
let mut retry = 3;
let mut error_msg = None;
loop {
- let pin = pinentry::inquire(pin_entry, pinentry::Mode::Query, error_msg)?;
+ let pin = pinentry::inquire(ctx, pin_entry, pinentry::Mode::Query, error_msg)?;
match op(data, &pin) {
Ok(result) => return Ok(result),
Err((new_data, err)) => match err {
@@ -235,7 +236,7 @@ where
})?;
op(data, &pin).map_err(|(_, err)| get_error(msg, err))
} else {
- try_with_pin_and_data_with_pinentry(pin_entry, msg, data, op)
+ try_with_pin_and_data_with_pinentry(ctx, pin_entry, msg, data, op)
}
}
@@ -359,7 +360,7 @@ pub fn storage_hidden_create(
.ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
.map(ToOwned::to_owned)
} else {
- pinentry::choose(&pwd_entry)
+ pinentry::choose(ctx, &pwd_entry)
}?;
device
@@ -377,7 +378,7 @@ pub fn storage_hidden_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
.ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
.map(ToOwned::to_owned)
} else {
- pinentry::inquire(&pwd_entry, pinentry::Mode::Query, None)
+ pinentry::inquire(ctx, &pwd_entry, pinentry::Mode::Query, None)
}?;
// We may forcefully close an encrypted volume, if active, so be sure
@@ -706,7 +707,7 @@ fn choose_pin(
.ok_or_else(|| Error::from("Failed to read PIN: invalid Unicode data found"))
.map(ToOwned::to_owned)
} else {
- pinentry::choose(pin_entry)
+ pinentry::choose(ctx, pin_entry)
}
}
diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs
index 1629167..5cb3faf 100644
--- a/nitrocli/src/main.rs
+++ b/nitrocli/src/main.rs
@@ -102,6 +102,7 @@ const NITROCLI_USER_PIN: &str = "NITROCLI_USER_PIN";
const NITROCLI_NEW_ADMIN_PIN: &str = "NITROCLI_NEW_ADMIN_PIN";
const NITROCLI_NEW_USER_PIN: &str = "NITROCLI_NEW_USER_PIN";
const NITROCLI_PASSWORD: &str = "NITROCLI_PASSWORD";
+const NITROCLI_NO_CACHE: &str = "NITROCLI_NO_CACHE";
/// The context used when running the program.
pub(crate) struct RunCtx<'io> {
@@ -123,6 +124,8 @@ pub(crate) struct RunCtx<'io> {
pub new_user_pin: Option<ffi::OsString>,
/// A password used by some commands, if provided through an environment variable.
pub password: Option<ffi::OsString>,
+ /// Whether to bypass the cache for all secrets or not.
+ pub no_cache: bool,
}
fn run<'ctx, 'io: 'ctx>(ctx: &'ctx mut RunCtx<'io>, args: Vec<String>) -> i32 {
@@ -157,6 +160,7 @@ fn main() {
new_admin_pin: env::var_os(NITROCLI_NEW_ADMIN_PIN),
new_user_pin: env::var_os(NITROCLI_NEW_USER_PIN),
password: env::var_os(NITROCLI_PASSWORD),
+ no_cache: env::var_os(NITROCLI_NO_CACHE).is_some(),
};
let rc = run(ctx, args);
diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs
index 7bba6b9..d8a77d4 100644
--- a/nitrocli/src/pinentry.rs
+++ b/nitrocli/src/pinentry.rs
@@ -22,6 +22,7 @@ use std::fmt;
use std::process;
use std::str;
+use crate::args;
use crate::error::Error;
type CowStr = borrow::Cow<'static, str>;
@@ -223,19 +224,27 @@ where
/// Inquire a secret from the user.
///
/// This function inquires a secret from the user or returns a cached
-/// entry, if available. If an error message is set, it is displayed in
+/// entry, if available (and if caching is not disabled for the given
+/// execution context). If an error message is set, it is displayed in
/// the entry dialog. The mode describes the context of the pinentry
/// dialog. It is used to choose an appropriate description and to
/// decide whether a quality bar is shown in the dialog.
-pub fn inquire<E>(entry: &E, mode: Mode, error_msg: Option<&str>) -> crate::Result<String>
+pub fn inquire<E>(
+ ctx: &mut args::ExecCtx<'_>,
+ entry: &E,
+ mode: Mode,
+ error_msg: Option<&str>,
+) -> crate::Result<String>
where
E: SecretEntry,
{
let cache_id = entry
.cache_id()
+ .and_then(|id| if ctx.no_cache { None } else { Some(id) })
// "X" is a sentinel value indicating that no caching is desired.
.unwrap_or_else(|| "X".into())
.into();
+
let error_msg = error_msg
.map(|msg| msg.replace(" ", "+"))
.unwrap_or_else(|| String::from("+"));
@@ -272,16 +281,16 @@ where
}
}
-pub fn choose<E>(entry: &E) -> crate::Result<String>
+pub fn choose<E>(ctx: &mut args::ExecCtx<'_>, entry: &E) -> crate::Result<String>
where
E: SecretEntry,
{
clear(entry)?;
- let chosen = inquire(entry, Mode::Choose, None)?;
+ let chosen = inquire(ctx, entry, Mode::Choose, None)?;
clear(entry)?;
check(entry, &chosen)?;
- let confirmed = inquire(entry, Mode::Confirm, None)?;
+ let confirmed = inquire(ctx, entry, Mode::Confirm, None)?;
clear(entry)?;
if chosen != confirmed {
diff --git a/nitrocli/src/tests/mod.rs b/nitrocli/src/tests/mod.rs
index e2e6ce0..b1e1618 100644
--- a/nitrocli/src/tests/mod.rs
+++ b/nitrocli/src/tests/mod.rs
@@ -157,6 +157,7 @@ impl Nitrocli {
new_admin_pin: self.new_admin_pin.clone(),
new_user_pin: self.new_user_pin.clone(),
password: self.password.clone(),
+ no_cache: true,
};
(f(ctx, args), stdout, stderr)