From 6f838f280108f5f07b41ae0e0634e71ec6f26c9a Mon Sep 17 00:00:00 2001 From: nikstur Date: Fri, 11 Oct 2024 00:02:56 +0200 Subject: [PATCH 1/2] make nologin path configurable via USERBORN_NO_LOGIN_PATH --- CHANGELOG.md | 4 ++++ rust/userborn/src/main.rs | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad45780..fae5c26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ generating a new salt. Please note that this changes nothing about the security posture of Userborn. If you provide a plaintext password to Userborn, there is nothing Userborn can do to protect it from leaking. +- You can now configure the path to the `nologin` binary via the compile-time + environment variable `USERBORN_NO_LOGIN_DEFAULT_PATH` and the runtime + variable `USERBORN_NO_LOGIN_PATH`. These values are used when no explicit + shell is provided in the user config. ## 0.2.0 diff --git a/rust/userborn/src/main.rs b/rust/userborn/src/main.rs index 7f40ef6..5aed6df 100644 --- a/rust/userborn/src/main.rs +++ b/rust/userborn/src/main.rs @@ -17,8 +17,15 @@ use passwd::Passwd; use password::HashedPassword; use shadow::Shadow; -/// Path to the nologin binary. -const NO_LOGIN: &str = "/run/current-system/sw/bin/nologin"; +/// Fallback path to the nologin binary. +/// +/// This is used when `USERBORN_NO_LOGIN_PATH` is not set during runtime and +/// `USERBORN_NO_LOGIN_DEFAULT_PATH` hasn't been set during compilation. +const NO_LOGIN_FALLBACK: &str = "/run/current-system/sw/bin/nologin"; +/// Default path to the nolign binary. +/// +/// This can be configured via a compile-time environment variable. +const NO_LOGIN_DEFAULT: Option<&'static str> = option_env!("USERBORN_NO_LOGIN_DEFAULT_PATH"); const DEFAULT_DIRECTORY: &str = "/etc"; fn main() -> ExitCode { @@ -192,7 +199,10 @@ fn create_user( gid, user_config.description.clone().unwrap_or_default(), user_config.home.clone().unwrap_or_default(), - user_config.shell.clone().unwrap_or(NO_LOGIN.into()), + user_config.shell.clone().unwrap_or( + std::env::var("USERBORN_NO_LOGIN_PATH") + .unwrap_or(NO_LOGIN_DEFAULT.unwrap_or(NO_LOGIN_FALLBACK).into()), + ), ); let description = new_entry.describe(); @@ -391,6 +401,9 @@ mod tests { #[test] fn update_users_and_groups_across_generations() -> Result<()> { + // Explitly set this because the expected values depend on this. + std::env::set_var("USERBORN_NO_LOGIN_PATH", NO_LOGIN_FALLBACK); + let mut group_db = Group::default(); let mut passwd_db = Passwd::default(); let mut shadow_db = Shadow::default(); From 64830a4aa24c1b2a9086e78fe67a5f98572bd0f8 Mon Sep 17 00:00:00 2001 From: nikstur Date: Fri, 11 Oct 2024 00:03:13 +0200 Subject: [PATCH 2/2] readme: add instructions on building the library --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 66f1292..000fcfb 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,33 @@ re-use is best illustrated by an example. Imagine the following scenario: - Userborn will discard entries in the shadow database that are not present in the passwd database. It will warn about these inconsistent entries. +## Configuration + +You can configure Userborn during runtime via the provided config file and via +environment variables. + +### Environment Variables + +- `USERBORN_NO_LOGIN_PATH`: Set this to the path of the `nologin` binary on + your system. This path is used when the user config doesn't specify a + `shell`. If this enviroment variable is set, its value overrides + `USERBORN_NO_LOGIN_DEFAULT_PATH`. + +## Building Userborn + +Runtime dependencies: + +- `libxcrypt` + +### Build-Time Parameters + +You can configure Userborn via compile-time environment variables: + +- `USERBORN_NO_LOGIN_DEFAULT_PATH`: Set this to the default path of the + `nologin` binary in your distro or system. If this is not set, the value + `/run/current-system/sw/bin/nologin` is used which will only make sense on + NixOS. + ## Comparison With Other Tools for Declarative User Management ### systemd-sysusers