Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a9a04d7
WIP
LeChatP Nov 2, 2025
7a0bfb2
feat: add umask in configuration
LeChatP Nov 16, 2025
9a4a21c
feat: update version to 3.3.0 and add umask configuration in docs
LeChatP Nov 16, 2025
6918309
Format Rust code using rustfmt
github-actions[bot] Nov 16, 2025
d35f0fa
feat: add landlock support and enhance user/group credential handling
LeChatP Nov 30, 2025
a94ca7d
fix: regression due to refactoring
LeChatP Dec 24, 2025
5483732
test: update test after new feat
LeChatP Dec 24, 2025
9245db3
fmt: cargo fmt
LeChatP Dec 24, 2025
6decb65
fix: test uid for github copilot
LeChatP Dec 24, 2025
4259b51
Format Rust code using rustfmt
github-actions[bot] Dec 24, 2025
acc6833
feat: add string conversion methods for SGenericActorType and SUserType
LeChatP Jan 11, 2026
1620ff8
refactor: simplify error handling in convert_string_to_duration function
LeChatP Jan 11, 2026
d2063a4
test: add as_str method to SGroupType and SUserType; enhance tests fo…
LeChatP Jan 11, 2026
53c8e94
refactor: config editor for testability and add unit tests
LeChatP Jan 11, 2026
60e9f7e
Format Rust code using rustfmt
github-actions[bot] Jan 11, 2026
b1798ab
refactor: enhance warning handling in configuration functions and imp…
LeChatP Jan 11, 2026
3ae835e
test: add error handling tests for edit_config and enhance mock edito…
LeChatP Jan 11, 2026
dc8750f
refactor: extract landlock access logic into a separate function and …
LeChatP Jan 11, 2026
b8af5ad
Format Rust code using rustfmt
github-actions[bot] Jan 11, 2026
0eb80dc
refactor: add tarpaulin ignore attributes for test coverage in editor…
LeChatP Jan 11, 2026
4cdc190
Merge branch 'dev' of github.com:LeChatP/RootAsRole into dev
LeChatP Jan 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ RAR_AUTHENTICATION = "perform"
RAR_EXEC_INFO_DISPLAY = "hide"
RAR_USER_CONSIDERED = "user"
RAR_BOUNDING = "strict"
RAR_UMASK = "0022"
RAR_MAX_LOCKFILE_RETRIES = "10"
RAR_LOCKFILE_RETRY_INTERVAL = "1"
RAR_TIMEOUT_STORAGE = "/var/run/rar/ts"
7 changes: 4 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["xtask", "rar-common"]

[package]
name = "rootasrole"
version = "3.2.4"
version = "3.3.0"
rust-version = "1.83.0"
authors = ["Eddie Billoir <lechatp@outlook.fr>"]
edition = "2021"
Expand Down Expand Up @@ -51,14 +51,15 @@ path = "tests/integration_tests.rs"
required-features = ["finder"]

[features]
finder = ["plugins", "timeout", "pcre2", "glob", "rar-common/finder", "dep:nonstick", "dep:libpam-sys", "dep:pty-process", "dep:once_cell"]
finder = ["plugins", "timeout", "pcre2", "glob", "landlock", "rar-common/finder", "dep:nonstick", "dep:libpam-sys", "dep:pty-process", "dep:once_cell"]
glob = ["rar-common/glob"]
pcre2 = ["dep:pcre2", "rar-common/pcre2"]
plugins = ["hashchecker", "ssd", "hierarchy"]
hashchecker = ["dep:hex", "dep:sha2"]
ssd = []
hierarchy = []
timeout = []
landlock = ["dep:landlock", "dep:bitflags"]
editor = ["dep:landlock", "dep:libseccomp", "dep:pest", "dep:pest_derive", "dep:linked_hash_set"]

[lints.rust]
Expand All @@ -68,7 +69,7 @@ unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] }
toml = { version = "0.8", default-features = false, features = ["parse", "display", "preserve_order"] }

[dependencies]
rar-common = { path = "rar-common", version = "3.2.4", package = "rootasrole-core" }
rar-common = { path = "rar-common", version = "3.3.0", package = "rootasrole-core" }
log = { version = "0.4", default-features = false, features = ["std"] }
libc = { version = "0.2", default-features = false, features = ["std"]}
strum = { version = "0.26", default-features = false, features = ["derive"] }
Expand Down Expand Up @@ -97,6 +98,7 @@ linked_hash_set = { version = "0.1", default-features = false, optional = true }
hex = { version = "0.4", default-features = false, optional = true, features = ["alloc"]}
landlock = { version = "0.4", optional = true }
libseccomp = { version = "0.3", optional = true }
bitflags = { version = "2.9", default-features = false, optional = true }

[dev-dependencies]
log = { version = "0.4", default-features = false, features = ["std"] }
Expand Down
7 changes: 5 additions & 2 deletions book/src/chsr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,12 @@ chsr role [role_name] options [option] [operation]
chsr role [role_name] task [task_name] options [option] [operation]
<b>path</b> Manage path settings (set, whitelist, blacklist).
<b>env</b> Manage environment variable settings (set, whitelist, blacklist, checklist).
<b>root</b> [policy] Defines when the root user (uid == 0) gets his privileges by default. (privileged, user, inherit)
<b>bounding</b> [policy] Defines when dropped capabilities are permanently removed in the instantiated process. (strict, ignore, inherit)
<b>root</b> [policy] Defines when the root user (uid == 0) gets his privileges by default. (del, privileged, user)
<b>bounding</b> [policy] Defines when dropped capabilities are permanently removed in the instantiated process. (del, strict, ignore)
<b>timeout</b> Manage timeout settings (set, unset).
<b>umask</b> [umask|del] Set the umask execution environment (in octal format, e.g., 022, or del for removing).
<b>authentication</b> [policy] Defines if user needs to authenticate (del, skip, perform).
<b>execinfo</b> [policy] Defines if user can see execution settings (del, show, hide).


<u><b>Path options:</b></u>
Expand Down
5 changes: 4 additions & 1 deletion book/src/chsr/file-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ The following example shows a RootAsRole config without plugins when almost ever
"type": "ppid", // Type of timeout: tty, ppid, uid
"duration": "15:30:30", // Duration of the timeout in HH:MM:SS format
"max_usage": 1 // Maximum usage before timeout expires
}
},
"umask": "022", // umask value for the executed command
"execinfo": "show", // Allow users to see execution context: show, hide
"authentication": "perform" // Authentication: perform, skip
},
"roles": [ // Role list
{
Expand Down
2 changes: 1 addition & 1 deletion rar-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rootasrole-core"
version = "3.2.4"
version = "3.3.0"
edition = "2021"
description = "This core crate for the RootAsRole project."
license = "LGPL-3.0-or-later"
Expand Down
59 changes: 55 additions & 4 deletions rar-common/src/database/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ pub enum SGenericActorType {
Name(String),
}

impl SGenericActorType {
fn as_str(&self) -> Cow<'_, str> {
match self {
SGenericActorType::Id(id) => Cow::Owned(id.to_string()),
SGenericActorType::Name(name) => Cow::Borrowed(name),
}
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct SUserType(SGenericActorType);

Expand Down Expand Up @@ -57,6 +66,11 @@ impl SUserType {
_ => false,
}
}
// Allowing dead code for RootAsRole-gensr project
#[allow(dead_code)]
pub fn as_str(&self) -> Cow<'_, str> {
self.0.as_str()
}
}

impl DUserType<'_> {
Expand All @@ -69,6 +83,12 @@ impl DUserType<'_> {
},
}
}
pub fn fetch_user(&self) -> Option<User> {
match &self.0 {
DGenericActorType::Id(id) => User::from_uid((*id).into()).ok().flatten(),
DGenericActorType::Name(name) => User::from_name(name).ok().flatten(),
}
}
}

impl fmt::Display for SUserType {
Expand Down Expand Up @@ -119,6 +139,9 @@ impl SGroupType {
SGenericActorType::Name(name) => Group::from_name(name).ok().flatten(),
}
}
pub fn as_str(&self) -> Cow<'_, str> {
self.0.as_str()
}
}

impl DGroupType<'_> {
Expand All @@ -131,6 +154,12 @@ impl DGroupType<'_> {
},
}
}
pub fn fetch_group(&self) -> Option<Group> {
match &self.0 {
DGenericActorType::Id(id) => Group::from_gid((*id).into()).ok().flatten(),
DGenericActorType::Name(name) => Group::from_name(name).ok().flatten(),
}
}
}

impl Display for DGroupType<'_> {
Expand Down Expand Up @@ -808,12 +837,20 @@ mod tests {
let group = SGroupType::from("unkown");
assert_eq!(group.fetch_id(), None);
}

#[test]
fn test_fetch_user() {
let user = SUserType::from("testuser");
assert!(user.fetch_user().is_none());
let user_by_id = SUserType::from(0);
assert!(user_by_id.fetch_user().is_some());
let user = DUserType::from("root");
assert_eq!(
user.fetch_user(),
Some(User::from_uid(0.into()).unwrap().unwrap())
);

let user = DUserType::from(0);
assert_eq!(
user.fetch_user(),
Some(User::from_uid(0.into()).unwrap().unwrap())
);
}

#[test]
Expand Down Expand Up @@ -1012,6 +1049,8 @@ mod tests {
assert!(group.is_single());
let group = SGroups::from(["test"]);
assert!(group.is_single());
let group = SGroups::from("test");
assert!(group.is_single());
let group = SGroups::from(["test", "test2"]);
assert!(!group.is_single());
let group = SGroups::from(vec![0, 1]);
Expand Down Expand Up @@ -1080,4 +1119,16 @@ mod tests {
let ids: Result<Vec<u32>, _> = (&groups).try_into();
assert!(ids.is_err());
}

#[test]
fn test_as_str() {
let group = SGroupType::from("test");
assert_eq!(group.as_str(), "test");
let group = SGroupType::from(100);
assert_eq!(group.as_str(), "100");
let user = SUserType::from("test");
assert_eq!(user.as_str(), "test");
let user = SUserType::from(100);
assert_eq!(user.as_str(), "100");
}
}
18 changes: 18 additions & 0 deletions rar-common/src/database/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,24 @@ mod tests {
assert!(serde_json::from_value::<SGenericActorType>(invalid_data).is_err());
}

#[test]
fn test_s_setgid_set_deserialization() {
let json_data = json!({
"default": "all",
"fallback": "group1",
"add": ["group2", "group3"],
"sub": ["group4"]
});
let setgid_set: SSetgidSet = serde_json::from_value(json_data).unwrap();
assert_eq!(setgid_set.default_behavior, SetBehavior::All);
assert_eq!(setgid_set.fallback, SGroups::from("group1"));
assert_eq!(setgid_set.add.len(), 2);
assert_eq!(setgid_set.add[0], SGroups::from("group2"));
assert_eq!(setgid_set.add[1], SGroups::from("group3"));
assert_eq!(setgid_set.sub.len(), 1);
assert_eq!(setgid_set.sub[0], SGroups::from("group4"));
}

#[test]
fn test_s_commands_deserialization_seq() {
let json_data = json!(["/bin/ls", "/bin/cat"]);
Expand Down
2 changes: 1 addition & 1 deletion rar-common/src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::error::Error;

use actor::{SGroups, SUserType};
use bon::{builder, Builder};
use bon::Builder;
use chrono::Duration;
use linked_hash_set::LinkedHashSet;
use options::EnvBehavior;
Expand Down
Loading
Loading