From 501f4fa2209641e20170581c439129b9db49a5ed Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 31 Jan 2020 08:16:00 +0100 Subject: [PATCH] depend on proxmox 0.1.13, use new tty helpers from there --- Cargo.toml | 2 +- src/backup/catalog_shell.rs | 31 ++------- src/bin/proxmox-backup-client.rs | 17 ++--- src/client/http_client.rs | 9 ++- src/tools.rs | 1 - src/tools/tty.rs | 104 ------------------------------- 6 files changed, 20 insertions(+), 144 deletions(-) delete mode 100644 src/tools/tty.rs diff --git a/Cargo.toml b/Cargo.toml index 2bae952c..788184f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ pam = "0.7" pam-sys = "0.5" percent-encoding = "2.1" 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 = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] } regex = "1.2" diff --git a/src/backup/catalog_shell.rs b/src/backup/catalog_shell.rs index bd8ce218..0c2827a0 100644 --- a/src/backup/catalog_shell.rs +++ b/src/backup/catalog_shell.rs @@ -7,11 +7,13 @@ use std::path::Path; use failure::*; +use proxmox::api::{cli::*, *}; +use proxmox::sys::linux::tty; + use super::catalog::{CatalogReader, DirEntry}; use crate::pxar::*; use crate::tools; -use proxmox::api::{cli::*, *}; const PROMPT_PREFIX: &str = "pxar:"; const PROMPT: &str = ">"; @@ -266,7 +268,7 @@ fn ls_command(path: Option) -> Result<(), Error> { None => 0, }; - let (_rows, mut cols) = Context::get_terminal_size(); + let (_rows, mut cols) = tty::stdout_terminal_size(); cols /= max; let mut out = std::io::stdout(); @@ -651,31 +653,6 @@ impl Context { 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. /// /// This will actively navigate the archive by calling the corresponding diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index e2f261aa..e38de32f 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -10,6 +10,7 @@ use std::os::unix::fs::OpenOptionsExt; use proxmox::{sortable, identity}; 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::schema::*; use proxmox::api::cli::*; @@ -1709,8 +1710,8 @@ fn get_encryption_key_password() -> Result, Error> { } // If we're on a TTY, query the user for a password - if crate::tools::tty::stdin_isatty() { - return Ok(crate::tools::tty::read_password("Encryption Key Password: ")?); + if tty::stdin_isatty() { + return Ok(tty::read_password("Encryption Key Password: ")?); } bail!("no password input mechanism available"); @@ -1731,11 +1732,11 @@ fn key_create( if kdf == "scrypt" { // always read passphrase from tty - if !crate::tools::tty::stdin_isatty() { + if !tty::stdin_isatty() { 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)?; @@ -1798,7 +1799,7 @@ fn key_create_master_key( ) -> Result { // 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"); } @@ -1806,7 +1807,7 @@ fn key_create_master_key( 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 = pkey.public_key_to_pem()?; let filename_pub = "master-public.pem"; @@ -1835,7 +1836,7 @@ fn key_change_passphrase( let kdf = param["kdf"].as_str().unwrap_or("scrypt"); // 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"); } @@ -1843,7 +1844,7 @@ fn key_change_passphrase( 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)?; new_key_config.created = created; // keep original value diff --git a/src/client/http_client.rs b/src/client/http_client.rs index 7472330c..cc86fc6a 100644 --- a/src/client/http_client.rs +++ b/src/client/http_client.rs @@ -15,13 +15,16 @@ use serde_json::{json, Value}; use percent_encoding::percent_encode; use xdg::BaseDirectories; -use proxmox::tools::{ - fs::{file_get_json, replace_file, CreateOptions}, +use proxmox::{ + sys::linux::tty, + tools::{ + fs::{file_get_json, replace_file, CreateOptions}, + } }; use super::pipe_to_stream::PipeToSendStream; 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)] pub struct AuthInfo { diff --git a/src/tools.rs b/src/tools.rs index 439252ab..e9e256c0 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -27,7 +27,6 @@ pub mod lru_cache; pub mod runtime; pub mod ticket; pub mod timer; -pub mod tty; mod wrapped_reader_stream; pub use wrapped_reader_stream::*; diff --git a/src/tools/tty.rs b/src/tools/tty.rs deleted file mode 100644 index e37863ac..00000000 --- a/src/tools/tty.rs +++ /dev/null @@ -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, 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::::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::::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, 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()) -}