depend on proxmox 0.1.13, use new tty helpers from there
This commit is contained in:
		| @ -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" | ||||
|  | ||||
| @ -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<String>) -> 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 | ||||
|  | ||||
| @ -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<Vec<u8>, 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<Value, Error> { | ||||
|  | ||||
|     // 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<u8> = 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 | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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::*; | ||||
|  | ||||
							
								
								
									
										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()) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user