feature: better login program
This commit is contained in:
parent
bd3d4e964d
commit
b97db3a0c4
4
Makefile
4
Makefile
@ -92,7 +92,9 @@ initrd:
|
|||||||
--target=../etc/$(ARCH)-osdev5.json \
|
--target=../etc/$(ARCH)-osdev5.json \
|
||||||
-Z build-std=core,alloc,compiler_builtins \
|
-Z build-std=core,alloc,compiler_builtins \
|
||||||
$(CARGO_COMMON_OPTS)
|
$(CARGO_COMMON_OPTS)
|
||||||
mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev
|
mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev $(O)/rootfs/etc
|
||||||
|
cp etc/initrd/passwd $(O)/rootfs/etc
|
||||||
|
cp etc/initrd/shadow $(O)/rootfs/etc
|
||||||
touch $(O)/rootfs/dev/.do_no_remove
|
touch $(O)/rootfs/dev/.do_no_remove
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
||||||
|
2
etc/initrd/passwd
Normal file
2
etc/initrd/passwd
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
root:0:0:root:/:/bin/shell
|
||||||
|
alnyan:1000:1000:alnyan:/:/bin/shell
|
2
etc/initrd/shadow
Normal file
2
etc/initrd/shadow
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
root:toor
|
||||||
|
alnyan:
|
@ -24,6 +24,55 @@ pub struct ProgramArgs {
|
|||||||
pub size: usize
|
pub size: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO utils
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FixedStr<const N: usize> {
|
||||||
|
len: usize,
|
||||||
|
data: [u8; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> FixedStr<N> {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
len: 0,
|
||||||
|
data: [0; N]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_from_str(&mut self, src: &str) {
|
||||||
|
if src.len() > self.data.len() {
|
||||||
|
panic!("copy_from_str: src len > data len");
|
||||||
|
}
|
||||||
|
self.len = src.len();
|
||||||
|
self.data[..self.len].copy_from_slice(src.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
unsafe {
|
||||||
|
core::str::from_utf8_unchecked(&self.data[..self.len])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> fmt::Debug for FixedStr<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "\"")?;
|
||||||
|
fmt::Display::fmt(self, f)?;
|
||||||
|
write!(f, "\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> fmt::Display for FixedStr<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
for &byte in &self.data[..self.len] {
|
||||||
|
write!(f, "{}", byte as char)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "user")]
|
#[cfg(feature = "user")]
|
||||||
pub mod calls;
|
pub mod calls;
|
||||||
#[cfg(feature = "user")]
|
#[cfg(feature = "user")]
|
||||||
|
12
libusr/src/env.rs → libusr/src/env/mod.rs
vendored
12
libusr/src/env.rs → libusr/src/env/mod.rs
vendored
@ -1,6 +1,14 @@
|
|||||||
use libsys::{debug::TraceLevel, ProgramArgs};
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use crate::trace;
|
use crate::trace;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use libsys::{
|
||||||
|
debug::TraceLevel,
|
||||||
|
ProgramArgs,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod passwd;
|
||||||
|
pub use passwd::UserInfo;
|
||||||
|
mod shadow;
|
||||||
|
pub use shadow::UserShadow;
|
||||||
|
|
||||||
static mut PROGRAM_ARGS: Vec<&'static str> = Vec::new();
|
static mut PROGRAM_ARGS: Vec<&'static str> = Vec::new();
|
||||||
|
|
99
libusr/src/env/passwd.rs
vendored
Normal file
99
libusr/src/env/passwd.rs
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use crate::io::{Read, read_line};
|
||||||
|
use core::str::FromStr;
|
||||||
|
use core::fmt;
|
||||||
|
use crate::trace_debug;
|
||||||
|
use crate::file::File;
|
||||||
|
use libsys::{FixedStr, stat::{UserId, GroupId}};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct UserInfo {
|
||||||
|
name: FixedStr<32>,
|
||||||
|
uid: UserId,
|
||||||
|
gid: GroupId,
|
||||||
|
home: FixedStr<64>,
|
||||||
|
shell: FixedStr<64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserInfo {
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn home(&self) -> &str {
|
||||||
|
self.home.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shell(&self) -> &str {
|
||||||
|
self.shell.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uid(&self) -> UserId {
|
||||||
|
self.uid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gid(&self) -> GroupId {
|
||||||
|
self.gid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find<F: Fn(&Self) -> bool>(pred: F) -> Result<Self, ()> {
|
||||||
|
let mut file = File::open("/etc/passwd").map_err(|_| ())?;
|
||||||
|
let mut buf = [0; 128];
|
||||||
|
loop {
|
||||||
|
let line = read_line(&mut file, &mut buf).map_err(|_| ())?;
|
||||||
|
if let Some(line) = line {
|
||||||
|
let ent = UserInfo::from_str(line)?;
|
||||||
|
if pred(&ent) {
|
||||||
|
return Ok(ent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_name(name: &str) -> Result<Self, ()> {
|
||||||
|
Self::find(|ent| ent.name() == name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for UserInfo {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, ()> {
|
||||||
|
let mut iter = s.split(":");
|
||||||
|
|
||||||
|
let name = iter.next().ok_or(())?;
|
||||||
|
let uid = iter
|
||||||
|
.next()
|
||||||
|
.ok_or(())
|
||||||
|
.and_then(|e| u32::from_str(e).map_err(|_| ()))
|
||||||
|
.map(UserId::from)?;
|
||||||
|
let gid = iter
|
||||||
|
.next()
|
||||||
|
.ok_or(())
|
||||||
|
.and_then(|e| u32::from_str(e).map_err(|_| ()))
|
||||||
|
.map(GroupId::from)?;
|
||||||
|
let comment = iter.next().ok_or(())?;
|
||||||
|
let home = iter.next().ok_or(())?;
|
||||||
|
let shell = iter.next().ok_or(())?;
|
||||||
|
|
||||||
|
if iter.next().is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Self {
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
|
name: FixedStr::empty(),
|
||||||
|
home: FixedStr::empty(),
|
||||||
|
shell: FixedStr::empty(),
|
||||||
|
};
|
||||||
|
|
||||||
|
res.name.copy_from_str(&name);
|
||||||
|
res.home.copy_from_str(&home);
|
||||||
|
res.shell.copy_from_str(&shell);
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
67
libusr/src/env/shadow.rs
vendored
Normal file
67
libusr/src/env/shadow.rs
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use crate::file::File;
|
||||||
|
use crate::io::{Read, read_line};
|
||||||
|
use core::str::FromStr;
|
||||||
|
use libsys::FixedStr;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct UserShadow {
|
||||||
|
name: FixedStr<32>,
|
||||||
|
password: FixedStr<64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserShadow {
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn password(&self) -> &str {
|
||||||
|
self.password.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn find<F: Fn(&Self) -> bool>(pred: F) -> Result<Self, ()> {
|
||||||
|
let mut file = File::open("/etc/shadow").map_err(|_| ())?;
|
||||||
|
let mut buf = [0; 128];
|
||||||
|
loop {
|
||||||
|
let line = read_line(&mut file, &mut buf).map_err(|_| ())?;
|
||||||
|
if let Some(line) = line {
|
||||||
|
let ent = UserShadow::from_str(line)?;
|
||||||
|
if pred(&ent) {
|
||||||
|
return Ok(ent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_name(name: &str) -> Result<Self, ()> {
|
||||||
|
Self::find(|ent| ent.name() == name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for UserShadow {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, ()> {
|
||||||
|
let mut iter = s.split(':');
|
||||||
|
|
||||||
|
let name = iter.next().ok_or(())?;
|
||||||
|
let password = iter.next().ok_or(())?;
|
||||||
|
|
||||||
|
if iter.next().is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Self {
|
||||||
|
name: FixedStr::empty(),
|
||||||
|
password: FixedStr::empty(),
|
||||||
|
};
|
||||||
|
|
||||||
|
res.name.copy_from_str(name);
|
||||||
|
res.password.copy_from_str(password);
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
@ -42,3 +42,27 @@ pub fn stat(pathname: &str) -> Result<Stat, Error> {
|
|||||||
sys_fstatat(None, pathname, &mut buf, 0).unwrap();
|
sys_fstatat(None, pathname, &mut buf, 0).unwrap();
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO use BufRead instead once it's implemented
|
||||||
|
pub(crate) fn read_line<'a, F: Read>(f: &mut F, buf: &'a mut [u8]) -> Result<Option<&'a str>, ()> {
|
||||||
|
let mut pos = 0;
|
||||||
|
loop {
|
||||||
|
if pos == buf.len() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = f.read(&mut buf[pos..=pos]).map_err(|_| ())?;
|
||||||
|
if count == 0 {
|
||||||
|
if pos == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if buf[pos] == b'\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
core::str::from_utf8(&buf[..pos]).map_err(|_| ()).map(Some)
|
||||||
|
}
|
||||||
|
@ -14,7 +14,8 @@ use libsys::{
|
|||||||
stat::{FileDescriptor, FileMode, GroupId, OpenFlags, UserId},
|
stat::{FileDescriptor, FileMode, GroupId, OpenFlags, UserId},
|
||||||
termios::{Termios, TermiosLflag},
|
termios::{Termios, TermiosLflag},
|
||||||
};
|
};
|
||||||
use libusr::{env, io};
|
use libusr::{env::{self, UserInfo, UserShadow}, io};
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
struct HiddenInput {
|
struct HiddenInput {
|
||||||
fd: FileDescriptor,
|
fd: FileDescriptor,
|
||||||
@ -73,7 +74,7 @@ fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, Errno> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> {
|
fn login(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> {
|
||||||
if let Some(pid) = unsafe { sys_fork() }? {
|
if let Some(pid) = unsafe { sys_fork() }? {
|
||||||
let mut status = 0;
|
let mut status = 0;
|
||||||
sys_waitpid(pid, &mut status).ok();
|
sys_waitpid(pid, &mut status).ok();
|
||||||
@ -90,6 +91,11 @@ fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn login_as(name: &str) -> Result<(), Errno> {
|
||||||
|
let ent = UserInfo::by_name(name).map_err(|_| Errno::DoesNotExist)?;
|
||||||
|
login(ent.uid(), ent.gid(), ent.shell())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO baud rate and misc port settings
|
// TODO baud rate and misc port settings
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@ -132,15 +138,26 @@ fn main() -> i32 {
|
|||||||
loop {
|
loop {
|
||||||
print!("login: ");
|
print!("login: ");
|
||||||
let username = readline(FileDescriptor::STDIN, &mut user_buf).expect("Login read failed");
|
let username = readline(FileDescriptor::STDIN, &mut user_buf).expect("Login read failed");
|
||||||
print!("password: ");
|
|
||||||
let password = {
|
|
||||||
let mut input = HiddenInput::open(FileDescriptor::STDIN).unwrap();
|
|
||||||
input.readline(&mut password_buf)
|
|
||||||
}
|
|
||||||
.expect("Password read failed");
|
|
||||||
|
|
||||||
if username == "root" && password == "toor" {
|
let shadow = match UserShadow::by_name(username) {
|
||||||
login_as(UserId::from(0), GroupId::from(0), "/bin/shell").unwrap();
|
Ok(e) => e,
|
||||||
|
Err(_) => continue
|
||||||
|
};
|
||||||
|
|
||||||
|
if !shadow.password().is_empty() {
|
||||||
|
print!("password: ");
|
||||||
|
let password = {
|
||||||
|
let mut input = HiddenInput::open(FileDescriptor::STDIN).unwrap();
|
||||||
|
input.readline(&mut password_buf)
|
||||||
|
}
|
||||||
|
.expect("Password read failed");
|
||||||
|
|
||||||
|
if password != shadow.password() {
|
||||||
|
eprintln!("Incorrect password");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
login_as(username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user