Implement getpass()
Also make fields in `termios` public; required for modifying them. There's an new type of test: `EXPECT_INPUT_BINS`. These require a `.exp` file to be present along with the `.c` file. The `.exp` file takes the produced binary as an argument and sends input to the program. This is useful for testing functions like `getpass()`.
This commit is contained in:
@@ -2,3 +2,4 @@
|
||||
|
||||
pub const PATH_MAX: usize = 4096;
|
||||
pub const NGROUPS_MAX: usize = 65536;
|
||||
pub const PASS_MAX: usize = 128;
|
||||
|
||||
+15
-15
@@ -37,28 +37,28 @@ pub const TCSAFLUSH: c_int = 2;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct termios {
|
||||
c_iflag: tcflag_t,
|
||||
c_oflag: tcflag_t,
|
||||
c_cflag: tcflag_t,
|
||||
c_lflag: tcflag_t,
|
||||
c_line: cc_t,
|
||||
c_cc: [cc_t; NCCS],
|
||||
__c_ispeed: speed_t,
|
||||
__c_ospeed: speed_t,
|
||||
pub c_iflag: tcflag_t,
|
||||
pub c_oflag: tcflag_t,
|
||||
pub c_cflag: tcflag_t,
|
||||
pub c_lflag: tcflag_t,
|
||||
pub c_line: cc_t,
|
||||
pub c_cc: [cc_t; NCCS],
|
||||
pub __c_ispeed: speed_t,
|
||||
pub __c_ospeed: speed_t,
|
||||
}
|
||||
|
||||
// Must match structure in redox_termios
|
||||
#[cfg(target_os = "redox")]
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct termios {
|
||||
c_iflag: tcflag_t,
|
||||
c_oflag: tcflag_t,
|
||||
c_cflag: tcflag_t,
|
||||
c_lflag: tcflag_t,
|
||||
c_cc: [cc_t; NCCS],
|
||||
pub c_iflag: tcflag_t,
|
||||
pub c_oflag: tcflag_t,
|
||||
pub c_cflag: tcflag_t,
|
||||
pub c_lflag: tcflag_t,
|
||||
pub c_cc: [cc_t; NCCS],
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -11,7 +11,9 @@ use crate::{
|
||||
c_str::CStr,
|
||||
header::{
|
||||
crypt::{crypt_data, crypt_r},
|
||||
errno, fcntl, limits,
|
||||
errno, fcntl,
|
||||
limits::{self, PASS_MAX},
|
||||
stdio,
|
||||
stdlib::getenv,
|
||||
sys_ioctl, sys_resource, sys_time, sys_utsname, termios,
|
||||
time::timespec,
|
||||
@@ -450,9 +452,51 @@ pub extern "C" fn getpagesize() -> c_int {
|
||||
.expect("page size not representable as type `int`")
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn getpass(prompt: *const c_char) -> *mut c_char {
|
||||
unimplemented!();
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getpass(prompt: *const c_char) -> *mut c_char {
|
||||
let tty = stdio::fopen(c_str!("/dev/tty").as_ptr(), c_str!("w+e").as_ptr());
|
||||
|
||||
if tty.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let fd = stdio::fileno(tty);
|
||||
|
||||
let mut term = termios::termios::default();
|
||||
termios::tcgetattr(fd, &mut term as *mut termios::termios);
|
||||
let old_temr = term.clone();
|
||||
|
||||
term.c_iflag &= !(termios::IGNCR | termios::INLCR) as u32;
|
||||
term.c_iflag |= termios::ICRNL as u32;
|
||||
term.c_lflag &= !(termios::ECHO | termios::ISIG) as u32;
|
||||
term.c_lflag |= termios::ICANON as u32;
|
||||
|
||||
termios::tcsetattr(fd, termios::TCSAFLUSH, &term as *const termios::termios);
|
||||
stdio::fputs(prompt, tty);
|
||||
stdio::fflush(tty);
|
||||
|
||||
static mut PASSBUFF: [c_char; PASS_MAX] = [0; PASS_MAX];
|
||||
|
||||
let len = read(fd, PASSBUFF.as_mut_ptr() as *const c_void, PASSBUFF.len());
|
||||
|
||||
if len >= 0 {
|
||||
let mut l = len as usize;
|
||||
if PASSBUFF[l - 1] == b'\n' as c_char || PASSBUFF.len() == l {
|
||||
l -= 1;
|
||||
}
|
||||
|
||||
PASSBUFF[l] = 0;
|
||||
}
|
||||
|
||||
termios::tcsetattr(fd, termios::TCSAFLUSH, &old_temr as *const termios::termios);
|
||||
stdio::fputs(c_str!("\n").as_ptr(), tty);
|
||||
stdio::fclose(tty);
|
||||
|
||||
if len < 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
PASSBUFF.as_mut_ptr()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
Reference in New Issue
Block a user