1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

test: implement user, group ownership checks

closes #2337
This commit is contained in:
Daniel Rocco 2021-06-04 23:16:48 -04:00
parent 553f70b06a
commit 22fbf16b2c
2 changed files with 74 additions and 10 deletions

View file

@ -6,7 +6,7 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
// spell-checker:ignore (vars) FiletestOp StrlenOp // spell-checker:ignore (vars) egid euid FiletestOp StrlenOp
mod parser; mod parser;
@ -96,8 +96,10 @@ fn eval(stack: &mut Vec<Symbol>) -> Result<bool, String> {
"-e" => path(&f, PathCondition::Exists), "-e" => path(&f, PathCondition::Exists),
"-f" => path(&f, PathCondition::Regular), "-f" => path(&f, PathCondition::Regular),
"-g" => path(&f, PathCondition::GroupIdFlag), "-g" => path(&f, PathCondition::GroupIdFlag),
"-G" => path(&f, PathCondition::GroupOwns),
"-h" => path(&f, PathCondition::SymLink), "-h" => path(&f, PathCondition::SymLink),
"-L" => path(&f, PathCondition::SymLink), "-L" => path(&f, PathCondition::SymLink),
"-O" => path(&f, PathCondition::UserOwns),
"-p" => path(&f, PathCondition::Fifo), "-p" => path(&f, PathCondition::Fifo),
"-r" => path(&f, PathCondition::Readable), "-r" => path(&f, PathCondition::Readable),
"-S" => path(&f, PathCondition::Socket), "-S" => path(&f, PathCondition::Socket),
@ -166,7 +168,9 @@ enum PathCondition {
Exists, Exists,
Regular, Regular,
GroupIdFlag, GroupIdFlag,
GroupOwns,
SymLink, SymLink,
UserOwns,
Fifo, Fifo,
Readable, Readable,
Socket, Socket,
@ -190,18 +194,28 @@ fn path(path: &OsStr, condition: PathCondition) -> bool {
Execute = 0o1, Execute = 0o1,
} }
let perm = |metadata: Metadata, p: Permission| { let geteuid = || {
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
let (uid, gid) = unsafe { (libc::getuid(), libc::getgid()) }; let euid = unsafe { libc::geteuid() };
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
let (uid, gid) = ( let euid = syscall::geteuid().unwrap() as u32;
syscall::getuid().unwrap() as u32,
syscall::getgid().unwrap() as u32,
);
if uid == metadata.uid() { euid
};
let getegid = || {
#[cfg(not(target_os = "redox"))]
let egid = unsafe { libc::getegid() };
#[cfg(target_os = "redox")]
let egid = syscall::getegid().unwrap() as u32;
egid
};
let perm = |metadata: Metadata, p: Permission| {
if geteuid() == metadata.uid() {
metadata.mode() & ((p as u32) << 6) != 0 metadata.mode() & ((p as u32) << 6) != 0
} else if gid == metadata.gid() { } else if getegid() == metadata.gid() {
metadata.mode() & ((p as u32) << 3) != 0 metadata.mode() & ((p as u32) << 3) != 0
} else { } else {
metadata.mode() & (p as u32) != 0 metadata.mode() & (p as u32) != 0
@ -230,7 +244,9 @@ fn path(path: &OsStr, condition: PathCondition) -> bool {
PathCondition::Exists => true, PathCondition::Exists => true,
PathCondition::Regular => file_type.is_file(), PathCondition::Regular => file_type.is_file(),
PathCondition::GroupIdFlag => metadata.mode() & S_ISGID != 0, PathCondition::GroupIdFlag => metadata.mode() & S_ISGID != 0,
PathCondition::GroupOwns => metadata.gid() == getegid(),
PathCondition::SymLink => metadata.file_type().is_symlink(), PathCondition::SymLink => metadata.file_type().is_symlink(),
PathCondition::UserOwns => metadata.uid() == geteuid(),
PathCondition::Fifo => file_type.is_fifo(), PathCondition::Fifo => file_type.is_fifo(),
PathCondition::Readable => perm(metadata, Permission::Read), PathCondition::Readable => perm(metadata, Permission::Read),
PathCondition::Socket => file_type.is_socket(), PathCondition::Socket => file_type.is_socket(),
@ -257,7 +273,9 @@ fn path(path: &OsStr, condition: PathCondition) -> bool {
PathCondition::Exists => true, PathCondition::Exists => true,
PathCondition::Regular => stat.is_file(), PathCondition::Regular => stat.is_file(),
PathCondition::GroupIdFlag => false, PathCondition::GroupIdFlag => false,
PathCondition::GroupOwns => unimplemented!(),
PathCondition::SymLink => false, PathCondition::SymLink => false,
PathCondition::UserOwns => unimplemented!(),
PathCondition::Fifo => false, PathCondition::Fifo => false,
PathCondition::Readable => false, // TODO PathCondition::Readable => false, // TODO
PathCondition::Socket => false, PathCondition::Socket => false,

View file

@ -8,7 +8,7 @@
// file that was distributed with this source code. // file that was distributed with this source code.
// //
// spell-checker:ignore (words) pseudofloat // spell-checker:ignore (words) egid euid pseudofloat
use crate::common::util::*; use crate::common::util::*;
@ -476,6 +476,52 @@ fn test_nonexistent_file_is_not_symlink() {
.succeeds(); .succeeds();
} }
#[test]
#[cfg(not(windows))]
fn test_file_owned_by_euid() {
new_ucmd!().args(&["-O", "regular_file"]).succeeds();
}
#[test]
#[cfg(not(windows))]
fn test_nonexistent_file_not_owned_by_euid() {
new_ucmd!()
.args(&["-O", "nonexistent_file"])
.run()
.status_code(1);
}
#[test]
#[cfg(all(not(windows), not(target_os = "freebsd")))]
fn test_file_not_owned_by_euid() {
new_ucmd!()
.args(&["-f", "/bin/sh", "-a", "!", "-O", "/bin/sh"])
.succeeds();
}
#[test]
#[cfg(not(windows))]
fn test_file_owned_by_egid() {
new_ucmd!().args(&["-G", "regular_file"]).succeeds();
}
#[test]
#[cfg(not(windows))]
fn test_nonexistent_file_not_owned_by_egid() {
new_ucmd!()
.args(&["-G", "nonexistent_file"])
.run()
.status_code(1);
}
#[test]
#[cfg(all(not(windows), not(target_os = "freebsd")))]
fn test_file_not_owned_by_egid() {
new_ucmd!()
.args(&["-f", "/bin/sh", "-a", "!", "-G", "/bin/sh"])
.succeeds();
}
#[test] #[test]
fn test_op_precedence_and_or_1() { fn test_op_precedence_and_or_1() {
new_ucmd!().args(&[" ", "-o", "", "-a", ""]).succeeds(); new_ucmd!().args(&[" ", "-o", "", "-a", ""]).succeeds();