Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 11 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
uses: dtolnay/rust-toolchain@stable

- name: Build tests
run: cargo test --no-run
Expand All @@ -36,3 +34,12 @@ jobs:

- name: Run tests
run: cargo test -- --show-output

- name: Check without logging feature
run: cargo check --no-default-features

- name: Run tests without logging feature
run: cargo test --no-default-features -- --show-output

- name: Run clippy
run: cargo clippy --all-targets -- -D warnings
14 changes: 12 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ readme = "README.md"
repository = "https://github.com/jhg/drop-root-rs"

exclude = [
".github",
".github/**",
".vscode/**",
".idea/**",
"tests/**",
"benches/**",
"Cargo.lock",
"LICENSE",
".gitignore",
]

[dependencies]
libc = "^0.2"
log = "^0.4"
log = { version = "^0.4", optional = true }

[features]
default = ["logging"]
logging = ["log"]
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ Set a user id and group id, using the names, to drop root privileges.
```rust
use drop_root::set_user_group;

fn main() {
// ...
set_user_group("nobody", "nogroup");
// ...
}
// ...
set_user_group("nobody", "nogroup");
// ...
```

## Features

- `logging` (default): Enable logging via the `log` crate
- To use without logging: `drop-root = { version = "1.0", default-features = false }`

## Testing

It's tested on Linux. Tests that require run as root are ignored by default, and executed
Expand Down
12 changes: 8 additions & 4 deletions src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ fn get_group_id_of(group_name: &str) -> Result<libc::gid_t, DropRootError> {
let group_record = unsafe { libc::getgrnam(CString::new(group_name)?.as_ptr()) };

if group_record.is_null() {
log::error!("Unable to getgrnam of the group {}", group_name);
#[cfg(feature = "logging")]
log::error!("Unable to getgrnam of the group {group_name}");
return Err(DropRootError::last_os_error());
}

Expand All @@ -19,15 +20,18 @@ pub fn set_group<T: AsRef<str>>(group_name: T) -> Result<(), DropRootError> {
let group_id = get_group_id_of(group_name)?;

if unsafe { libc::setgid(group_id) } != 0 {
log::error!("Unable to setgid of group {}", group_name);
#[cfg(feature = "logging")]
log::error!("Unable to setgid of group {group_name}");
return Err(DropRootError::last_os_error());
}

if unsafe { libc::setgroups(1, &group_id) } != 0 {
log::error!("Unable to setgid of group {}", group_name);
#[cfg(feature = "logging")]
log::error!("Unable to setgroups for group {group_name}");
return Err(DropRootError::last_os_error());
}

log::info!("Set process effective group to {}", group_name);
#[cfg(feature = "logging")]
log::info!("Set process effective group to {group_name}");
Ok(())
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![cfg(unix)]
#[doc = include_str!("../README.md")]
#![doc = include_str!("../README.md")]

mod error;
mod user;
Expand Down
11 changes: 7 additions & 4 deletions src/user.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::ffi::CString;
use crate::DropRootError;

fn get_user_id_of(user_name: &str) -> Result<libc::gid_t, DropRootError> {
fn get_user_id_of(user_name: &str) -> Result<libc::uid_t, DropRootError> {
let passwd_record = unsafe { libc::getpwnam(CString::new(user_name)?.as_ptr()) };

if passwd_record.is_null() {
log::error!("Unable to getpwnam of the user {}", user_name);
#[cfg(feature = "logging")]
log::error!("Unable to getpwnam of the user {user_name}");
return Err(DropRootError::last_os_error());
}

Expand All @@ -19,10 +20,12 @@ pub fn set_user<T: AsRef<str>>(user_name: T) -> Result<(), DropRootError> {
let user_id = get_user_id_of(user_name)?;

if unsafe { libc::setuid(user_id) } != 0 {
log::error!("Unable to setuid of user {}", user_name);
#[cfg(feature = "logging")]
log::error!("Unable to setuid of user {user_name}");
return Err(DropRootError::last_os_error());
}

log::info!("Set process effective user to {}", user_name);
#[cfg(feature = "logging")]
log::info!("Set process effective user to {user_name}");
Ok(())
}