Merge branch 'shadow-h' into 'master'
Implement shadow.h and argon2 crypt See merge request redox-os/relibc!718
This commit is contained in:
Generated
+22
@@ -11,6 +11,18 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@@ -40,6 +52,15 @@ version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
@@ -498,6 +519,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
name = "relibc"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"base64ct",
|
||||
"bcrypt-pbkdf",
|
||||
"bitflags",
|
||||
|
||||
@@ -51,6 +51,7 @@ chrono = {version = "0.4", default-features = false, features = ["alloc"]}
|
||||
libm = "0.2"
|
||||
object = { version = "0.36.7", git = "https://gitlab.redox-os.org/andypython/object", default-features = false, features = ["elf", "read_core"] }
|
||||
spin = "0.9.8"
|
||||
argon2 = "0.5.3"
|
||||
|
||||
[dependencies.dlmalloc]
|
||||
path = "dlmalloc-rs"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use alloc::string::{String, ToString};
|
||||
use argon2::{
|
||||
password_hash::{PasswordHash, PasswordVerifier},
|
||||
Argon2,
|
||||
};
|
||||
|
||||
pub fn crypt_argon2(key: &str, setting: &str) -> Option<String> {
|
||||
let hash = PasswordHash::new(setting).ok()?;
|
||||
let argon2 = Argon2::default();
|
||||
|
||||
if argon2.verify_password(key.as_bytes(), &hash).is_ok() {
|
||||
Some(setting.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
+11
-8
@@ -19,6 +19,7 @@ use crate::{
|
||||
platform::{self, types::*},
|
||||
};
|
||||
|
||||
mod argon2;
|
||||
mod blowfish;
|
||||
mod md5;
|
||||
mod pbkdf2;
|
||||
@@ -26,6 +27,7 @@ mod scrypt;
|
||||
mod sha;
|
||||
|
||||
use self::{
|
||||
argon2::crypt_argon2,
|
||||
blowfish::crypt_blowfish,
|
||||
md5::crypt_md5,
|
||||
pbkdf2::crypt_pbkdf2,
|
||||
@@ -73,21 +75,22 @@ pub unsafe extern "C" fn crypt_r(
|
||||
let setting = unsafe { CStr::from_ptr(setting) }
|
||||
.to_str()
|
||||
.expect("setting must be utf-8");
|
||||
let setting_bytes = setting.as_bytes();
|
||||
|
||||
let encoded = if setting_bytes[0] == b'$' && setting_bytes[1] != 0 && setting_bytes[2] != 0 {
|
||||
if setting_bytes[1] == b'1' && setting_bytes[2] == b'$' {
|
||||
let encoded = if setting.starts_with('$') {
|
||||
if setting.starts_with("$1$") {
|
||||
crypt_md5(key, setting)
|
||||
} else if setting_bytes[1] == b'2' && setting_bytes[3] == b'$' {
|
||||
} else if setting.starts_with("$2") && setting.as_bytes().get(3) == Some(&b'$') {
|
||||
crypt_blowfish(key, setting)
|
||||
} else if setting_bytes[1] == b'5' && setting_bytes[2] == b'$' {
|
||||
} else if setting.starts_with("$5$") {
|
||||
crypt_sha(key, setting, Sha256)
|
||||
} else if setting_bytes[1] == b'6' && setting_bytes[2] == b'$' {
|
||||
} else if setting.starts_with("$6$") {
|
||||
crypt_sha(key, setting, Sha512)
|
||||
} else if setting_bytes[1] == b'7' && setting_bytes[2] == b'$' {
|
||||
} else if setting.starts_with("$7$") {
|
||||
crypt_scrypt(key, setting)
|
||||
} else if setting_bytes[1] == b'8' && setting_bytes[2] == b'$' {
|
||||
} else if setting.starts_with("$8$") {
|
||||
crypt_pbkdf2(key, setting)
|
||||
} else if setting.starts_with("$argon2") {
|
||||
crypt_argon2(key, setting)
|
||||
} else {
|
||||
platform::ERRNO.set(EINVAL);
|
||||
return ptr::null_mut();
|
||||
|
||||
@@ -38,6 +38,8 @@ const SEPARATOR: char = ':';
|
||||
#[cfg(target_os = "redox")]
|
||||
const SEPARATOR: char = ';';
|
||||
|
||||
const GROUP_FILE: &core::ffi::CStr = c"/etc/group";
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct DestBuffer {
|
||||
ptr: *mut u8,
|
||||
@@ -249,7 +251,7 @@ fn parse_grp(line: String, destbuf: Option<DestBuffer>) -> Result<OwnedGrp, Erro
|
||||
// MT-Unsafe race:grgid locale
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getgrgid(gid: gid_t) -> *mut group {
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
|
||||
@@ -272,7 +274,7 @@ pub unsafe extern "C" fn getgrgid(gid: gid_t) -> *mut group {
|
||||
// MT-Unsafe race:grnam locale
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getgrnam(name: *const c_char) -> *mut group {
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
|
||||
@@ -314,7 +316,7 @@ pub unsafe extern "C" fn getgrgid_r(
|
||||
*result = ptr::null_mut();
|
||||
}
|
||||
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ENOENT;
|
||||
};
|
||||
|
||||
@@ -368,7 +370,7 @@ pub unsafe extern "C" fn getgrnam_r(
|
||||
buflen: usize,
|
||||
result: *mut *mut group,
|
||||
) -> c_int {
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ENOENT;
|
||||
};
|
||||
|
||||
@@ -409,7 +411,7 @@ pub unsafe extern "C" fn getgrent() -> *mut group {
|
||||
let mut line_reader = unsafe { &mut *LINE_READER.get() };
|
||||
|
||||
if line_reader.is_none() {
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
*line_reader = Some(BufReader::new(db).lines());
|
||||
@@ -445,7 +447,7 @@ pub unsafe extern "C" fn endgrent() {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn setgrent() {
|
||||
let mut line_reader = unsafe { &mut *LINE_READER.get() };
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return;
|
||||
};
|
||||
*line_reader = Some(BufReader::new(db).lines());
|
||||
@@ -471,7 +473,7 @@ pub unsafe extern "C" fn getgrouplist(
|
||||
return 0;
|
||||
};
|
||||
|
||||
let Ok(db) = File::open(c"/etc/group".into(), fcntl::O_RDONLY) else {
|
||||
let Ok(db) = File::open(GROUP_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ pub mod sched;
|
||||
pub mod semaphore;
|
||||
pub mod setjmp;
|
||||
pub mod sgtty;
|
||||
pub mod shadow;
|
||||
pub mod signal;
|
||||
// TODO: spawn.h
|
||||
// TODO: stdalign.h (likely C implementation)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
sys_includes = ["sys/types.h", "stdint.h", "stdio.h"]
|
||||
include_guard = "_RELIBC_SHADOW_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
no_includes = true
|
||||
cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
|
||||
[export]
|
||||
include = ["group"]
|
||||
@@ -0,0 +1,271 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use core::{
|
||||
cell::SyncUnsafeCell,
|
||||
convert::TryInto,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
ptr,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
fs::File,
|
||||
header::{errno, fcntl, string::strlen},
|
||||
io::{prelude::*, BufReader, Lines},
|
||||
platform,
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
use super::errno::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const SEPARATOR: char = ':';
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
const SEPARATOR: char = ';';
|
||||
|
||||
const SHADOW_FILE: &core::ffi::CStr = c"/etc/shadow";
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct DestBuffer {
|
||||
ptr: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MaybeAllocated {
|
||||
Owned(Pin<Box<[u8]>>),
|
||||
Borrowed(DestBuffer),
|
||||
}
|
||||
impl Deref for MaybeAllocated {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
MaybeAllocated::Owned(boxed) => boxed,
|
||||
MaybeAllocated::Borrowed(dst) => unsafe {
|
||||
core::slice::from_raw_parts(dst.ptr, dst.len)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DerefMut for MaybeAllocated {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self {
|
||||
MaybeAllocated::Owned(boxed) => boxed,
|
||||
MaybeAllocated::Borrowed(dst) => unsafe {
|
||||
core::slice::from_raw_parts_mut(dst.ptr, dst.len)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static mut SHADOW_BUF: Option<MaybeAllocated> = None;
|
||||
static mut SHADOW: spwd = spwd {
|
||||
sp_namp: ptr::null_mut(),
|
||||
sp_pwdp: ptr::null_mut(),
|
||||
sp_lstchg: -1,
|
||||
sp_min: -1,
|
||||
sp_max: -1,
|
||||
sp_warn: -1,
|
||||
sp_inact: -1,
|
||||
sp_expire: -1,
|
||||
sp_flag: 0,
|
||||
};
|
||||
|
||||
static LINE_READER: SyncUnsafeCell<Option<Lines<BufReader<File>>>> = SyncUnsafeCell::new(None);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct spwd {
|
||||
pub sp_namp: *mut c_char,
|
||||
pub sp_pwdp: *mut c_char,
|
||||
pub sp_lstchg: c_long,
|
||||
pub sp_min: c_long,
|
||||
pub sp_max: c_long,
|
||||
pub sp_warn: c_long,
|
||||
pub sp_inact: c_long,
|
||||
pub sp_expire: c_long,
|
||||
pub sp_flag: c_ulong,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
EOF,
|
||||
BufTooSmall,
|
||||
Syntax,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OwnedSpwd {
|
||||
buffer: MaybeAllocated,
|
||||
reference: spwd,
|
||||
}
|
||||
|
||||
impl OwnedSpwd {
|
||||
fn into_global(self) -> *mut spwd {
|
||||
unsafe {
|
||||
SHADOW_BUF = Some(self.buffer);
|
||||
SHADOW = self.reference;
|
||||
&mut SHADOW
|
||||
}
|
||||
}
|
||||
}
|
||||
fn to_long(s: &str) -> c_long {
|
||||
c_long::from_str(s).unwrap_or(-1)
|
||||
}
|
||||
fn to_ulong(s: &str) -> c_ulong {
|
||||
c_ulong::from_str(s).unwrap_or(0)
|
||||
}
|
||||
|
||||
fn parse_spwd(line: String, destbuf: Option<DestBuffer>) -> Result<OwnedSpwd, Error> {
|
||||
let mut parts = line.split(SEPARATOR);
|
||||
|
||||
let sp_namp_str = parts.next().ok_or(Error::Syntax)?;
|
||||
let sp_pwdp_str = parts.next().ok_or(Error::Syntax)?;
|
||||
|
||||
//TODO: these are not implemented redox-users crate
|
||||
let sp_lstchg = to_long(parts.next().unwrap_or(""));
|
||||
let sp_min = to_long(parts.next().unwrap_or(""));
|
||||
let sp_max = to_long(parts.next().unwrap_or(""));
|
||||
let sp_warn = to_long(parts.next().unwrap_or(""));
|
||||
let sp_inact = to_long(parts.next().unwrap_or(""));
|
||||
let sp_expire = to_long(parts.next().unwrap_or(""));
|
||||
let sp_flag = to_ulong(parts.next().unwrap_or(""));
|
||||
|
||||
let string_data_len = sp_namp_str.len() + 1 + sp_pwdp_str.len() + 1;
|
||||
|
||||
let mut buffer = match destbuf {
|
||||
Some(buf) => {
|
||||
if buf.len < string_data_len {
|
||||
platform::ERRNO.set(ERANGE);
|
||||
return Err(Error::BufTooSmall);
|
||||
}
|
||||
MaybeAllocated::Borrowed(buf)
|
||||
}
|
||||
None => {
|
||||
let mut vec = Vec::with_capacity(string_data_len);
|
||||
vec.resize(string_data_len, 0);
|
||||
MaybeAllocated::Owned(Box::into_pin(vec.into_boxed_slice()))
|
||||
}
|
||||
};
|
||||
|
||||
let (name_slice, rest) = buffer.split_at_mut(sp_namp_str.len() + 1);
|
||||
name_slice[..sp_namp_str.len()].copy_from_slice(sp_namp_str.as_bytes());
|
||||
name_slice[sp_namp_str.len()] = 0;
|
||||
|
||||
let (pwd_slice, _) = rest.split_at_mut(sp_pwdp_str.len() + 1);
|
||||
pwd_slice[..sp_pwdp_str.len()].copy_from_slice(sp_pwdp_str.as_bytes());
|
||||
pwd_slice[sp_pwdp_str.len()] = 0;
|
||||
|
||||
let sp_namp = name_slice.as_mut_ptr() as *mut c_char;
|
||||
let sp_pwdp = pwd_slice.as_mut_ptr() as *mut c_char;
|
||||
|
||||
let reference = spwd {
|
||||
sp_namp,
|
||||
sp_pwdp,
|
||||
sp_lstchg,
|
||||
sp_min,
|
||||
sp_max,
|
||||
sp_warn,
|
||||
sp_inact,
|
||||
sp_expire,
|
||||
sp_flag,
|
||||
};
|
||||
|
||||
Ok(OwnedSpwd { buffer, reference })
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getspnam(name: *const c_char) -> *mut spwd {
|
||||
let Ok(db) = File::open(SHADOW_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
let c_name = unsafe { CStr::from_ptr(name) };
|
||||
|
||||
for line in BufReader::new(db).lines() {
|
||||
let Ok(line) = line else { continue };
|
||||
if line.starts_with(c_name.to_str().unwrap_or("\0")) {
|
||||
if let Ok(pwd) = parse_spwd(line, None) {
|
||||
return pwd.into_global();
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getspnam_r(
|
||||
name: *const c_char,
|
||||
result_buf: *mut spwd,
|
||||
buffer: *mut c_char,
|
||||
buflen: size_t,
|
||||
result: *mut *mut spwd,
|
||||
) -> c_int {
|
||||
unsafe { *result = ptr::null_mut() };
|
||||
|
||||
let Ok(db) = File::open(SHADOW_FILE.into(), fcntl::O_RDONLY) else {
|
||||
return ENOENT;
|
||||
};
|
||||
let c_name = unsafe { CStr::from_ptr(name).to_str().unwrap_or("\0") };
|
||||
|
||||
for line in BufReader::new(db).lines() {
|
||||
let Ok(line) = line else { continue };
|
||||
if line.starts_with(c_name) {
|
||||
let dest_buf = Some(DestBuffer {
|
||||
ptr: buffer as *mut u8,
|
||||
len: buflen,
|
||||
});
|
||||
return match parse_spwd(line, dest_buf) {
|
||||
Ok(sp) => {
|
||||
unsafe {
|
||||
*result_buf = sp.reference;
|
||||
*result = result_buf;
|
||||
}
|
||||
0
|
||||
}
|
||||
Err(Error::BufTooSmall) => ERANGE,
|
||||
_ => ENOENT,
|
||||
};
|
||||
}
|
||||
}
|
||||
ENOENT
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn setspent() {
|
||||
let mut line_reader = unsafe { &mut *LINE_READER.get() };
|
||||
if let Ok(db) = File::open(SHADOW_FILE.into(), fcntl::O_RDONLY) {
|
||||
*line_reader = Some(BufReader::new(db).lines());
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn endspent() {
|
||||
unsafe {
|
||||
*LINE_READER.get() = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getspent() -> *mut spwd {
|
||||
let line_reader = unsafe { &mut *LINE_READER.get() };
|
||||
if line_reader.is_none() {
|
||||
unsafe {
|
||||
setspent();
|
||||
}
|
||||
}
|
||||
if let Some(lines) = line_reader {
|
||||
if let Some(Ok(line)) = lines.next() {
|
||||
if let Ok(sp) = parse_spwd(line, None) {
|
||||
return sp.into_global();
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
Reference in New Issue
Block a user