depend on proxmox 0.1.13, use new tty helpers from there
This commit is contained in:
parent
f0188322ed
commit
501f4fa220
@ -34,7 +34,7 @@ pam = "0.7"
|
|||||||
pam-sys = "0.5"
|
pam-sys = "0.5"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pin-utils = "0.1.0-alpha"
|
pin-utils = "0.1.0-alpha"
|
||||||
proxmox = { version = "0.1.12", features = [ "sortable-macro", "api-macro" ] }
|
proxmox = { version = "0.1.13", features = [ "sortable-macro", "api-macro" ] }
|
||||||
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
|
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
|
||||||
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
|
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
|
@ -7,11 +7,13 @@ use std::path::Path;
|
|||||||
|
|
||||||
use failure::*;
|
use failure::*;
|
||||||
|
|
||||||
|
use proxmox::api::{cli::*, *};
|
||||||
|
use proxmox::sys::linux::tty;
|
||||||
|
|
||||||
use super::catalog::{CatalogReader, DirEntry};
|
use super::catalog::{CatalogReader, DirEntry};
|
||||||
use crate::pxar::*;
|
use crate::pxar::*;
|
||||||
use crate::tools;
|
use crate::tools;
|
||||||
|
|
||||||
use proxmox::api::{cli::*, *};
|
|
||||||
|
|
||||||
const PROMPT_PREFIX: &str = "pxar:";
|
const PROMPT_PREFIX: &str = "pxar:";
|
||||||
const PROMPT: &str = ">";
|
const PROMPT: &str = ">";
|
||||||
@ -266,7 +268,7 @@ fn ls_command(path: Option<String>) -> Result<(), Error> {
|
|||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_rows, mut cols) = Context::get_terminal_size();
|
let (_rows, mut cols) = tty::stdout_terminal_size();
|
||||||
cols /= max;
|
cols /= max;
|
||||||
|
|
||||||
let mut out = std::io::stdout();
|
let mut out = std::io::stdout();
|
||||||
@ -651,31 +653,6 @@ impl Context {
|
|||||||
Ok(prompt)
|
Ok(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current size of the terminal
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// uses unsafe call to tty_ioctl, see man tty_ioctl(2)
|
|
||||||
fn get_terminal_size() -> (usize, usize) {
|
|
||||||
const TIOCGWINSZ: libc::c_ulong = 0x5413;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct WinSize {
|
|
||||||
ws_row: libc::c_ushort,
|
|
||||||
ws_col: libc::c_ushort,
|
|
||||||
_ws_xpixel: libc::c_ushort, // unused
|
|
||||||
_ws_ypixel: libc::c_ushort, // unused
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut winsize = WinSize {
|
|
||||||
ws_row: 0,
|
|
||||||
ws_col: 0,
|
|
||||||
_ws_xpixel: 0,
|
|
||||||
_ws_ypixel: 0,
|
|
||||||
};
|
|
||||||
unsafe { libc::ioctl(libc::STDOUT_FILENO, TIOCGWINSZ, &mut winsize) };
|
|
||||||
(winsize.ws_row as usize, winsize.ws_col as usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Look up the entry given by a canonical absolute `path` in the archive.
|
/// Look up the entry given by a canonical absolute `path` in the archive.
|
||||||
///
|
///
|
||||||
/// This will actively navigate the archive by calling the corresponding
|
/// This will actively navigate the archive by calling the corresponding
|
||||||
|
@ -10,6 +10,7 @@ use std::os::unix::fs::OpenOptionsExt;
|
|||||||
|
|
||||||
use proxmox::{sortable, identity};
|
use proxmox::{sortable, identity};
|
||||||
use proxmox::tools::fs::{file_get_contents, file_get_json, replace_file, CreateOptions, image_size};
|
use proxmox::tools::fs::{file_get_contents, file_get_json, replace_file, CreateOptions, image_size};
|
||||||
|
use proxmox::sys::linux::tty;
|
||||||
use proxmox::api::{ApiHandler, ApiMethod, RpcEnvironment};
|
use proxmox::api::{ApiHandler, ApiMethod, RpcEnvironment};
|
||||||
use proxmox::api::schema::*;
|
use proxmox::api::schema::*;
|
||||||
use proxmox::api::cli::*;
|
use proxmox::api::cli::*;
|
||||||
@ -1709,8 +1710,8 @@ fn get_encryption_key_password() -> Result<Vec<u8>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we're on a TTY, query the user for a password
|
// If we're on a TTY, query the user for a password
|
||||||
if crate::tools::tty::stdin_isatty() {
|
if tty::stdin_isatty() {
|
||||||
return Ok(crate::tools::tty::read_password("Encryption Key Password: ")?);
|
return Ok(tty::read_password("Encryption Key Password: ")?);
|
||||||
}
|
}
|
||||||
|
|
||||||
bail!("no password input mechanism available");
|
bail!("no password input mechanism available");
|
||||||
@ -1731,11 +1732,11 @@ fn key_create(
|
|||||||
|
|
||||||
if kdf == "scrypt" {
|
if kdf == "scrypt" {
|
||||||
// always read passphrase from tty
|
// always read passphrase from tty
|
||||||
if !crate::tools::tty::stdin_isatty() {
|
if !tty::stdin_isatty() {
|
||||||
bail!("unable to read passphrase - no tty");
|
bail!("unable to read passphrase - no tty");
|
||||||
}
|
}
|
||||||
|
|
||||||
let password = crate::tools::tty::read_and_verify_password("Encryption Key Password: ")?;
|
let password = tty::read_and_verify_password("Encryption Key Password: ")?;
|
||||||
|
|
||||||
let key_config = encrypt_key_with_passphrase(&key, &password)?;
|
let key_config = encrypt_key_with_passphrase(&key, &password)?;
|
||||||
|
|
||||||
@ -1798,7 +1799,7 @@ fn key_create_master_key(
|
|||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
|
|
||||||
// we need a TTY to query the new password
|
// we need a TTY to query the new password
|
||||||
if !crate::tools::tty::stdin_isatty() {
|
if !tty::stdin_isatty() {
|
||||||
bail!("unable to create master key - no tty");
|
bail!("unable to create master key - no tty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1806,7 +1807,7 @@ fn key_create_master_key(
|
|||||||
let pkey = openssl::pkey::PKey::from_rsa(rsa)?;
|
let pkey = openssl::pkey::PKey::from_rsa(rsa)?;
|
||||||
|
|
||||||
|
|
||||||
let password = String::from_utf8(crate::tools::tty::read_and_verify_password("Master Key Password: ")?)?;
|
let password = String::from_utf8(tty::read_and_verify_password("Master Key Password: ")?)?;
|
||||||
|
|
||||||
let pub_key: Vec<u8> = pkey.public_key_to_pem()?;
|
let pub_key: Vec<u8> = pkey.public_key_to_pem()?;
|
||||||
let filename_pub = "master-public.pem";
|
let filename_pub = "master-public.pem";
|
||||||
@ -1835,7 +1836,7 @@ fn key_change_passphrase(
|
|||||||
let kdf = param["kdf"].as_str().unwrap_or("scrypt");
|
let kdf = param["kdf"].as_str().unwrap_or("scrypt");
|
||||||
|
|
||||||
// we need a TTY to query the new password
|
// we need a TTY to query the new password
|
||||||
if !crate::tools::tty::stdin_isatty() {
|
if !tty::stdin_isatty() {
|
||||||
bail!("unable to change passphrase - no tty");
|
bail!("unable to change passphrase - no tty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1843,7 +1844,7 @@ fn key_change_passphrase(
|
|||||||
|
|
||||||
if kdf == "scrypt" {
|
if kdf == "scrypt" {
|
||||||
|
|
||||||
let password = crate::tools::tty::read_and_verify_password("New Password: ")?;
|
let password = tty::read_and_verify_password("New Password: ")?;
|
||||||
|
|
||||||
let mut new_key_config = encrypt_key_with_passphrase(&key, &password)?;
|
let mut new_key_config = encrypt_key_with_passphrase(&key, &password)?;
|
||||||
new_key_config.created = created; // keep original value
|
new_key_config.created = created; // keep original value
|
||||||
|
@ -15,13 +15,16 @@ use serde_json::{json, Value};
|
|||||||
use percent_encoding::percent_encode;
|
use percent_encoding::percent_encode;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
use proxmox::tools::{
|
use proxmox::{
|
||||||
fs::{file_get_json, replace_file, CreateOptions},
|
sys::linux::tty,
|
||||||
|
tools::{
|
||||||
|
fs::{file_get_json, replace_file, CreateOptions},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::pipe_to_stream::PipeToSendStream;
|
use super::pipe_to_stream::PipeToSendStream;
|
||||||
use crate::tools::async_io::EitherStream;
|
use crate::tools::async_io::EitherStream;
|
||||||
use crate::tools::{self, tty, BroadcastFuture, DEFAULT_ENCODE_SET};
|
use crate::tools::{self, BroadcastFuture, DEFAULT_ENCODE_SET};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AuthInfo {
|
pub struct AuthInfo {
|
||||||
|
@ -27,7 +27,6 @@ pub mod lru_cache;
|
|||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod ticket;
|
pub mod ticket;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod tty;
|
|
||||||
|
|
||||||
mod wrapped_reader_stream;
|
mod wrapped_reader_stream;
|
||||||
pub use wrapped_reader_stream::*;
|
pub use wrapped_reader_stream::*;
|
||||||
|
104
src/tools/tty.rs
104
src/tools/tty.rs
@ -1,104 +0,0 @@
|
|||||||
//! Helpers for terminal interaction
|
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
|
|
||||||
use failure::*;
|
|
||||||
|
|
||||||
use proxmox::try_block;
|
|
||||||
|
|
||||||
/// Returns whether the current stdin is a tty .
|
|
||||||
pub fn stdin_isatty() -> bool {
|
|
||||||
unsafe { libc::isatty(std::io::stdin().as_raw_fd()) == 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a password from stdin, masking the echoed output with asterisks and writing a query first.
|
|
||||||
pub fn read_password(query: &str) -> Result<Vec<u8>, Error> {
|
|
||||||
let input = std::io::stdin();
|
|
||||||
if unsafe { libc::isatty(input.as_raw_fd()) } != 1 {
|
|
||||||
let mut out = String::new();
|
|
||||||
input.read_line(&mut out)?;
|
|
||||||
return Ok(out.into_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out = std::io::stdout();
|
|
||||||
let _ignore_error = out.write_all(query.as_bytes());
|
|
||||||
let _ignore_error = out.flush();
|
|
||||||
|
|
||||||
let infd = input.as_raw_fd();
|
|
||||||
let mut termios = MaybeUninit::<libc::termios>::uninit();
|
|
||||||
if unsafe { libc::tcgetattr(infd, &mut *termios.as_mut_ptr()) } != 0 {
|
|
||||||
bail!("tcgetattr() failed");
|
|
||||||
}
|
|
||||||
let mut termios = unsafe { termios.assume_init() };
|
|
||||||
let old_termios = termios; // termios is a 'Copy' type
|
|
||||||
unsafe {
|
|
||||||
libc::cfmakeraw(&mut termios);
|
|
||||||
}
|
|
||||||
if unsafe { libc::tcsetattr(infd, libc::TCSANOW, &termios) } != 0 {
|
|
||||||
bail!("tcsetattr() failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut password = Vec::<u8>::new();
|
|
||||||
let mut asterisks = true;
|
|
||||||
|
|
||||||
let ok: Result<(), Error> = try_block!({
|
|
||||||
for byte in input.bytes() {
|
|
||||||
let byte = byte?;
|
|
||||||
match byte {
|
|
||||||
3 => bail!("cancelled"), // ^C
|
|
||||||
4 => break, // ^D / EOF
|
|
||||||
9 => asterisks = false, // tab disables echo
|
|
||||||
0xA | 0xD => {
|
|
||||||
// newline, we're done
|
|
||||||
let _ignore_error = out.write_all("\r\n".as_bytes());
|
|
||||||
let _ignore_error = out.flush();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
0x7F => {
|
|
||||||
// backspace
|
|
||||||
if !password.is_empty() {
|
|
||||||
password.pop();
|
|
||||||
if asterisks {
|
|
||||||
let _ignore_error = out.write_all("\x08 \x08".as_bytes());
|
|
||||||
let _ignore_error = out.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
password.push(other);
|
|
||||||
if asterisks {
|
|
||||||
let _ignore_error = out.write_all(b"*");
|
|
||||||
let _ignore_error = out.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
if unsafe { libc::tcsetattr(infd, libc::TCSANOW, &old_termios) } != 0 {
|
|
||||||
// not fatal...
|
|
||||||
eprintln!("failed to reset terminal attributes!");
|
|
||||||
}
|
|
||||||
match ok {
|
|
||||||
Ok(_) => Ok(password),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_and_verify_password(prompt: &str) -> Result<Vec<u8>, Error> {
|
|
||||||
|
|
||||||
let password = String::from_utf8(crate::tools::tty::read_password(prompt)?)?;
|
|
||||||
let verify_password = String::from_utf8(crate::tools::tty::read_password("Verify Password: ")?)?;
|
|
||||||
|
|
||||||
if password != verify_password {
|
|
||||||
bail!("Passwords do not match!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if password.len() < 5 {
|
|
||||||
bail!("Password too short!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(password.into_bytes())
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user