Skip to content
Snippets Groups Projects
Commit 3359d4a0 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Merge branch 'master' into 'master'

Groups

See merge request !407
parents 3327bc82 2f887ae4
No related branches found
No related tags found
1 merge request!407Groups
Pipeline #12815 failed
//! grp implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/grp.h.html //! grp implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/grp.h.html
use crate::platform::types::*; use core::{
convert::{TryFrom, TryInto},
mem,
ops::{Deref, DerefMut},
pin::Pin,
primitive::str,
ptr, slice, num::ParseIntError, str::Matches,
};
use lazy_static::lazy_static;
use alloc::{borrow::ToOwned, string::{String, FromUtf8Error}};
use libc::strncmp;
use crate::{
c_str::CStr,
fs::File,
header::{errno, fcntl, string::strlen},
io,
io::{prelude::*, BufReader, Lines},
platform::types::*,
platform,
sync::Mutex
};
use super::errno::*;
#[derive(Clone, Copy, Debug)]
struct DestBuffer {
ptr: *mut u8,
len: usize,
}
// Shamelessly stolen from pwd/mod.rs
#[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 GROUP_BUF: Option<MaybeAllocated> = None;
static mut GROUP: group = group {
gr_name: ptr::null_mut(),
gr_passwd: ptr::null_mut(),
gr_gid: 0,
gr_mem: ptr::null_mut(),
};
lazy_static! { static ref LINE_READER: Mutex<Option<Lines<BufReader<File>>>> = Mutex::new(None); }
#[repr(C)] #[repr(C)]
#[derive(Debug)]
pub struct group { pub struct group {
pub gr_name: *mut c_char, pub gr_name: *mut c_char,
pub gr_passwd: *mut c_char, pub gr_passwd: *mut c_char,
...@@ -10,56 +81,264 @@ pub struct group { ...@@ -10,56 +81,264 @@ pub struct group {
pub gr_mem: *mut *mut c_char, pub gr_mem: *mut *mut c_char,
} }
// #[no_mangle] #[derive(Debug)]
enum Error {
EOF,
SyntaxError,
BufTooSmall,
Misc(io::Error),
FromUtf8Error(FromUtf8Error),
ParseIntError(ParseIntError),
Other
}
#[derive(Debug)]
struct OwnedGrp {
buffer: MaybeAllocated,
reference: group,
}
impl OwnedGrp {
fn into_global(self) -> *mut group {
unsafe {
GROUP_BUF = Some(self.buffer);
GROUP = self.reference;
&mut GROUP
}
}
}
fn split(buf: &mut [u8]) -> Option<group> {
let gid = match buf[0..mem::size_of::<gid_t>()].try_into() {
Ok(buf) => gid_t::from_ne_bytes(buf),
Err(err) => return None
};
// We moved the gid to the beginning of the byte buffer so we can do this.
let mut parts = buf[mem::size_of::<gid_t>()..].split_mut(|&c| c == b'\0');
Some(group {
gr_name: parts.next()?.as_mut_ptr() as *mut i8,
gr_passwd: parts.next()?.as_mut_ptr() as *mut i8,
gr_gid: gid,
gr_mem: parts.next()?.as_mut_ptr() as *mut *mut c_char
// this will work because this points to the first string, which also happens to be the start of the array. The two are equivalent, just need to by typecast.
})
}
fn parse_grp(line: String, destbuf: Option<DestBuffer>) -> Result<OwnedGrp, Error> {
let mut buffer = line.to_owned().into_bytes();
let mut buffer = buffer
.into_iter()
.map(|i| if i == b':' { b'\0' } else { i })
.chain([b'\0'])
.collect::<Vec<_>>();
let mut buffer = buffer
.split_mut(|i| *i == b'\0');
let mut gr_gid: gid_t = 0;
let strings = {
let mut vec: Vec<u8> = Vec::new();
let gr_name = buffer.next().ok_or(Error::EOF)?.to_vec();
let gr_passwd = buffer.next().ok_or(Error::EOF)?.to_vec();
gr_gid = String::from_utf8(buffer.next().ok_or(Error::EOF)?.to_vec())
.map_err(|err| Error::FromUtf8Error(err))?
.parse::<gid_t>()
.map_err(|err| Error::ParseIntError(err))?;
// Place the gid at the beginning of the byte buffer to make getting it back out again later, much faster.
vec.extend(gr_gid.to_ne_bytes());
vec.extend(gr_name);
vec.push(0);
vec.extend(gr_passwd);
vec.push(0);
for i in buffer.next().ok_or(Error::EOF)?
.split(|b| *b == b',')
.filter(|i| i.len() > 0) {
vec.extend(i.to_vec());
vec.push(0);
}
vec.extend(0usize.to_ne_bytes());
vec
};
let mut buffer = match destbuf {
None => MaybeAllocated::Owned(Box::into_pin(strings.into_boxed_slice())),
Some(buf) => {
let mut buf = MaybeAllocated::Borrowed(buf);
if buf.len() < buf.len() {
unsafe { platform::errno = errno::ERANGE; }
return Err(Error::BufTooSmall);
}
buf[..strings.len()].copy_from_slice(&strings);
buf
}
};
let reference = split(&mut buffer).ok_or(Error::Other)?;
Ok(OwnedGrp {
buffer,
reference
})
}
#[no_mangle]
pub extern "C" fn getgrgid(gid: gid_t) -> *mut group { pub extern "C" fn getgrgid(gid: gid_t) -> *mut group {
unimplemented!(); let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return ptr::null_mut() };
for line in BufReader::new(db).lines() {
let Ok(line) = line else { return ptr::null_mut() };
let Ok(grp) = parse_grp(line, None) else { return ptr::null_mut() };
if grp.reference.gr_gid == gid {
return grp.into_global();
}
}
return ptr::null_mut();
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn getgrnam(name: *const c_char) -> *mut group { pub extern "C" fn getgrnam(name: *const c_char) -> *mut group {
unimplemented!(); let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return ptr::null_mut() };
for line in BufReader::new(db).lines() {
let Ok(line) = line else { return ptr::null_mut() };
let Ok(grp) = parse_grp(line, None) else { return ptr::null_mut() };
// Attempt to prevent BO vulnerabilities
if unsafe { strncmp(grp.reference.gr_name, name, strlen(grp.reference.gr_name).min(strlen(name))) > 0 } {
return grp.into_global();
}
}
return ptr::null_mut();
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn getgrgid_r( pub extern "C" fn getgrgid_r(gid: gid_t, result_buf: *mut group, buffer: *mut c_char, buflen: usize, result: *mut *mut group) -> c_int {
gid: gid_t, let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return ENOENT };
grp: *mut group,
buffer: *mut c_char, for line in BufReader::new(db).lines() {
bufsize: usize, let Ok(line) = line else { return EINVAL };
result: *mut *mut group, let Ok(mut grp) = parse_grp(line, Some(DestBuffer { ptr: buffer as *mut u8, len: buflen })) else { return EINVAL };
) -> c_int {
unimplemented!(); if grp.reference.gr_gid == gid {
unsafe {
*result_buf = grp.reference;
*result = result_buf;
};
return 0;
}
}
return ENOENT;
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn getgrnam_r( pub extern "C" fn getgrnam_r(name: *const c_char, result_buf: *mut group, buffer: *mut c_char, buflen: usize, result: *mut *mut group) -> c_int {
name: *const c_char, let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return ENOENT };
grp: *mut group,
buffer: *mut c_char, for line in BufReader::new(db).lines() {
bufsize: usize, let Ok(line) = line else { return EINVAL };
result: *mut *mut group, let Ok(mut grp) = parse_grp(line, Some(DestBuffer { ptr: buffer as *mut u8, len: buflen })) else { return EINVAL };
) -> c_int {
unimplemented!(); if unsafe { strncmp(grp.reference.gr_name, name, strlen(grp.reference.gr_name).min(strlen(name))) > 0 } {
unsafe {
*result_buf = grp.reference;
*result = result_buf;
};
return 0;
}
}
return ENOENT;
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn getgrent() -> *mut group { pub extern "C" fn getgrent() -> *mut group {
unimplemented!(); let mut line_reader = LINE_READER.lock();
if line_reader.is_none() {
let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return ptr::null_mut() };
*line_reader = Some(BufReader::new(db).lines());
}
if let Some(lines) = line_reader.deref_mut() {
let Some(line) = lines.next() else { return ptr::null_mut() };
let Ok(line) = line else { return ptr::null_mut() };
if let Ok(grp) = parse_grp(line, None) {
return grp.into_global();
} else { return ptr::null_mut(); }
} else {
return ptr::null_mut();
}
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn endgrent() { pub extern "C" fn endgrent() {
unimplemented!(); let mut line_reader = LINE_READER.lock();
*line_reader = None;
} }
// #[no_mangle] #[no_mangle]
pub extern "C" fn setgrent() { pub extern "C" fn setgrent() {
unimplemented!(); let mut line_reader = LINE_READER.lock();
let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return };
*line_reader = Some(BufReader::new(db).lines());
} }
/*
#[no_mangle] #[no_mangle]
pub extern "C" fn func(args) -> c_int { pub extern "C" fn getgrouplist(user: *const c_char, group: gid_t, groups: *mut gid_t, ngroups: i32) -> i32 {
unimplemented!(); let mut grps = unsafe { Vec::<gid_t>::from_raw_parts(groups, 0, ngroups as usize) };
let Ok(usr) = (unsafe { crate::c_str::CStr::from_ptr(user).to_str() }) else { return 0 };
let Ok(db) = File::open(c_str!("/etc/group"), fcntl::O_RDONLY) else { return 0; };
for line in BufReader::new(db).lines() {
if grps.len() >= ngroups as usize {
return ngroups;
}
match line {
Err(_) => return 0,
Ok(line) => {
let mut parts = line.split(':');
let group_name = parts.next().unwrap_or("");
let group_password = parts.next().unwrap_or("");
let group_id = parts.next().unwrap_or("-1").parse::<i32>().unwrap();
let members = parts
.next()
.unwrap_or("")
.split(",")
.map(|i| i.trim())
.collect::<Vec<_>>();
if members.iter().any(|i| *i == usr) {
grps.push(group_id);
}
}
};
}
if grps.len() <= 0 {
grps.push(group);
}
return grps.len() as i32;
} }
*/
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(str_internals)] #![feature(str_internals)]
#![feature(thread_local)] #![feature(thread_local)]
#![feature(vec_into_raw_parts)]
#![allow(clippy::cast_lossless)] #![allow(clippy::cast_lossless)]
#![allow(clippy::cast_ptr_alignment)] #![allow(clippy::cast_ptr_alignment)]
#![allow(clippy::derive_hash_xor_eq)] #![allow(clippy::derive_hash_xor_eq)]
......
...@@ -166,7 +166,11 @@ NAMES=\ ...@@ -166,7 +166,11 @@ NAMES=\
pthread/barrier \ pthread/barrier \
pthread/rwlock_trylock \ pthread/rwlock_trylock \
pthread/rwlock_randtest \ pthread/rwlock_randtest \
pthread/mutex_recursive pthread/mutex_recursive \
grp/getgrouplist \
grp/getgrgid_r \
grp/getgrnam_r \
grp/gr_iter \
# resource/getrusage # resource/getrusage
# time/times # time/times
......
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <grp.h>
bool test_getgrgid(gid_t gid) {
struct group* out = getgrgid(gid);
if (out == NULL) {
printf("Did not find a group %d", gid);
return false;
}
printf("getgrgid\n");
char* start = out->gr_name;
int len = strlen(out->gr_name);
printf(" %d = %s, GID: %d\n", gid, out->gr_name, out->gr_gid);
return true;
}
bool test_getgrgid_r(gid_t gid) {
char* buf[100];
struct group grp;
struct group* out = &grp;
struct group* tmp;
int status = getgrgid_r(gid, out, buf, sizeof(buf), &tmp);
if (out == NULL) {
printf("Did not find a group %d", gid);
return false;
}
printf("getgrgid_r\n");
char* start = grp.gr_name;
int len = strlen(grp.gr_name);
printf(" %d = %s, GID: %d\n", gid, grp.gr_name, grp.gr_gid);
return true;
}
int main(void) {
test_getgrgid(1050);
test_getgrgid_r(1050);
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <grp.h>
bool test_getgrnam(char* gr_name) {
struct group* out = getgrnam(gr_name);
if (out == NULL) {
printf("Did not find a group '%s'", gr_name);
return false;
}
printf("getgrnam\n");
char* start = out->gr_name;
int len = strlen(out->gr_name);
printf(" '%s' = %d\n", gr_name, out->gr_gid);
return true;
}
bool test_getgrnam_r(char* gr_name) {
char* buf[100];
struct group grp;
struct group* out = &grp;
struct group* tmp;
int status = getgrnam_r(gr_name, out, buf, sizeof(buf), &tmp);
if (out == NULL) {
printf("Did not find a group '%s'", gr_name);
return false;
}
printf("getgrnam_r\n");
char* start = grp.gr_name;
int len = strlen(grp.gr_name);
printf(" '%s' = %d\n", gr_name, out->gr_gid);
return true;
}
int main(void) {
test_getgrnam("lcake");
test_getgrnam_r("lcake");
}
\ No newline at end of file
#include <stdio.h>
#include <grp.h>
int main(void) {
gid_t groups[20];
int ngroup = 20;
int num_groups = getgrouplist("user", 1000, groups, &ngroup);
printf("Num Groups: %d\n", num_groups);
for (int i = 0; i < num_groups; i++)
printf("i: %d\n", groups[i]);
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <grp.h>
#include <string.h>
int main(int argc, char** argv) {
printf("getgrent\n");
for (struct group* grp = getgrent(); grp != NULL; grp = getgrent())
printf(" %s = %d\n", grp->gr_name, grp->gr_gid);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment