Merge branch 'getpass' into 'master'
Implement getpass() See merge request redox-os/relibc!488
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]
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
use core::ptr;
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
fs::File,
|
||||
header::{
|
||||
fcntl::{O_CLOEXEC, O_RDWR},
|
||||
limits::PASS_MAX,
|
||||
termios,
|
||||
},
|
||||
io::{self, Read, Write},
|
||||
};
|
||||
|
||||
use crate::platform::types::*;
|
||||
|
||||
fn getpass_rs(prompt: CStr, passbuff: &mut [u8]) -> Result<*mut c_char, io::Error> {
|
||||
let mut f = File::open(c_str!("/dev/tty"), O_RDWR | O_CLOEXEC)?;
|
||||
|
||||
let mut term = termios::termios::default();
|
||||
|
||||
unsafe {
|
||||
termios::tcgetattr(f.fd, &mut term as *mut termios::termios);
|
||||
}
|
||||
|
||||
let old_term = 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;
|
||||
|
||||
unsafe {
|
||||
termios::tcsetattr(f.fd, termios::TCSAFLUSH, &term as *const termios::termios);
|
||||
}
|
||||
|
||||
f.write(&prompt.to_bytes())?;
|
||||
f.flush()?;
|
||||
|
||||
let mut len = f.read(passbuff)?;
|
||||
|
||||
if len > 0 {
|
||||
if passbuff[len - 1] == b'\n' || passbuff.len() == len {
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
passbuff[len] = 0;
|
||||
|
||||
unsafe {
|
||||
termios::tcsetattr(
|
||||
f.fd,
|
||||
termios::TCSAFLUSH,
|
||||
&old_term as *const termios::termios,
|
||||
);
|
||||
}
|
||||
|
||||
f.write(b"\n")?;
|
||||
f.flush()?;
|
||||
|
||||
Ok(passbuff.as_mut_ptr() as *mut c_char)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getpass(prompt: *const c_char) -> *mut c_char {
|
||||
static mut PASSBUFF: [u8; PASS_MAX] = [0; PASS_MAX];
|
||||
|
||||
unsafe { getpass_rs(CStr::from_ptr(prompt), &mut PASSBUFF).unwrap_or(ptr::null_mut()) }
|
||||
}
|
||||
@@ -19,14 +19,16 @@ use crate::{
|
||||
platform::{self, types::*, Pal, Sys},
|
||||
pthread::ResultExt,
|
||||
};
|
||||
|
||||
use alloc::collections::LinkedList;
|
||||
|
||||
pub use self::{brk::*, getopt::*, pathconf::*, sysconf::*};
|
||||
pub use self::{brk::*, getopt::*, getpass::getpass, pathconf::*, sysconf::*};
|
||||
|
||||
use super::errno::{E2BIG, ENOMEM};
|
||||
|
||||
mod brk;
|
||||
mod getopt;
|
||||
mod getpass;
|
||||
mod pathconf;
|
||||
mod sysconf;
|
||||
|
||||
@@ -450,11 +452,6 @@ 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 extern "C" fn getpgid(pid: pid_t) -> pid_t {
|
||||
Sys::getpgid(pid)
|
||||
|
||||
+17
-1
@@ -196,6 +196,11 @@ NAMES=\
|
||||
# resource/getrusage
|
||||
# time/times
|
||||
|
||||
# Tests run with `expect` (require a .c file and an .exp file
|
||||
# that takes the produced binary as the first argument)
|
||||
EXPECT_INPUT_NAMES=\
|
||||
unistd/getpass
|
||||
|
||||
#TODO: dynamic tests currently broken
|
||||
BINS=$(patsubst %,$(BUILD)/bins_static/%,$(NAMES))
|
||||
#BINS+=$(patsubst %,bins_dynamic/%,$(NAMES))
|
||||
@@ -203,6 +208,7 @@ BINS=$(patsubst %,$(BUILD)/bins_static/%,$(NAMES))
|
||||
EXPECT_BINS=$(patsubst %,$(BUILD)/bins_static/%,$(EXPECT_NAMES))
|
||||
#EXPECT_BINS+=$(patsubst %,bins_dynamic/%,$(EXPECT_NAMES))
|
||||
#EXPECT_BINS+=$(patsubst %,bins_dynamic/%,$(DYNAMIC_ONLY_NAMES))
|
||||
EXPECT_INPUT_BINS=$(patsubst %,$(BUILD)/bins_expect_input/%,$(EXPECT_INPUT_NAMES))
|
||||
|
||||
CARGO_TEST?=cargo
|
||||
TEST_RUNNER?=
|
||||
@@ -214,12 +220,17 @@ all: $(BINS)
|
||||
clean:
|
||||
rm -rf bins_* gen *.out
|
||||
|
||||
run: | $(BINS)
|
||||
run: | $(BINS) $(EXPECT_INPUT_BINS)
|
||||
for bin in $(BINS); \
|
||||
do \
|
||||
echo "# $${bin} #"; \
|
||||
${TEST_RUNNER} "$${bin}" test args || exit $$?; \
|
||||
done
|
||||
for exp in $(EXPECT_INPUT_BINS); \
|
||||
do \
|
||||
echo "# expect $$(readlink -e $${exp}.exp) $$(readlink -e $${exp}) #"; \
|
||||
expect "$$(readlink -e $${exp}.exp)" "$$(readlink -e $${exp})" test args || exit $$?; \
|
||||
done
|
||||
|
||||
expected: | $(EXPECT_BINS)
|
||||
rm -rf expected
|
||||
@@ -289,6 +300,11 @@ $(BUILD)/bins_static/%: %.c $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
|
||||
|
||||
$(BUILD)/bins_expect_input/%: %.c %.exp $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
|
||||
cp $(word 2, "$^") $(addsuffix .exp,"$@")
|
||||
|
||||
$(BUILD)/bins_dynamic/%.so: %.c $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" -shared -fpic $(FLAGS) $(DYNAMIC_FLAGS)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// #include "test_helpers.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *pass = "pass";
|
||||
const char *prompt = "Enter password: ";
|
||||
|
||||
char *result = getpass(prompt);
|
||||
|
||||
if(strcmp(pass, result)) {
|
||||
printf("incorrect password\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *pass_127_chars = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
result = getpass(prompt);
|
||||
|
||||
if(strcmp(pass_127_chars, result)) {
|
||||
printf("incorrect password\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *pass_empty = "";
|
||||
result = getpass(prompt);
|
||||
|
||||
if(strcmp(pass_empty, result)) {
|
||||
printf("incorrect password\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("matching passwords\n", result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/expect
|
||||
|
||||
set testgetpass [lindex $argv 0];
|
||||
|
||||
spawn $testgetpass
|
||||
expect "Enter password: "
|
||||
send -- "pass\r"
|
||||
|
||||
expect "Enter password: "
|
||||
send -- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r"
|
||||
|
||||
expect "Enter password: "
|
||||
send -- "\r"
|
||||
|
||||
expect {
|
||||
"incorrect password" { exit 123 }
|
||||
eof
|
||||
}
|
||||
Reference in New Issue
Block a user