mirror of
https://github.com/uutils/shadow.git
synced 2026-10-16 02:48:14 -07:00
* usermod: add and remove subordinate id ranges GNU usermod has -v/--add-subuids, -V/--del-subuids, -w/--add-subgids and -W/--del-subgids; ours had none of them, which came to light while writing the tests for newuidmap. The range helpers live in shadow_core::subid so whatever next touches /etc/subuid reads the same file the same way. The behaviour was established by running the GNU tool: a range the user already holds is not added twice; a removal trims an entry it overlaps, splits one it cuts through the middle of, deletes one it covers, and ignores a range never held; nothing checks other users' entries, since an administrator may share a range on purpose; and an invalid range -- reversed, not two numbers, above the 32-bit ids the kernel maps -- is exit 3 with the GNU wording, before any file is written. Entries are keyed by the login name given on the command line and are not renamed by -l, as GNU's are not: a range is a grant to a name. -V is GNU's letter for the deletion, so clap's own -V for --version had to go; --version stays. * expiry: check and enforce password expiration expiry is the twenty-eighth tool and the last the Scope table lists as in scope. It judges the caller's own /etc/shadow line as login would: silent when all is well, a warning inside warn_days, a forced change through PAM when the password has expired, a refusal when the account has. Shell profiles run it so a session that did not come through login -- a display manager, an ssh key -- still meets the aging policy. The rules are in shadow_core::shadow::Aging, one function over the aging fields with checked arithmetic, since every input is read from a file anyone who can write /etc/shadow chooses. Its order is login's: account expiry first, then a last change of 0 or an aged-out password, then the warning window, with a maximum age of 10000 or more meaning never as chage -l prints it. A locked password is a policy of its own and is not reported. The GNU tool is setgid shadow -- enough to read the file, no more -- and the change goes through PAM as the caller. The per-tool install ships it the same way, a new install class. The single setuid binary keeps euid 0 for it, having nothing narrower to offer. Under --prefix it reports and never changes anything, since a PAM change would act on this system's account of the same name; that is also what lets the required-change path be asserted in the integration tests without a prompt, while the e2e suite drives the prompt itself on a real user under a pty and checks the hash changed. groupmems is not coming. Debian 13 and Fedora do not ship it, and on Ubuntu 24.04 every action fails against PAM's default for want of a /etc/pam.d/groupmems: a tool one distribution ships and none can use. The Scope table says so. Verified: make check clean with the unprivileged run; 935 tests on alpine and 950 on fedora with PAM; 410 e2e assertions against a real install; 59 GNU comparisons; 35 arm64 assertions under emulation. * shadow-core: stop asking nscd to invalidate a shadow cache it never had Every passwd, chage and chpasswd ended with `nscd -i shadow`, and on a host running nscd that printed "nscd: 'shadow' is not a known database" on the user's terminal each time. nscd caches passwd, group, hosts, services and netgroup; the passwd entries it holds carry the `x` placeholder, so a password change leaves nothing of nscd's stale. Only the databases nscd knows are passed to it now. sss_cache still gets -U for a shadow change, which is right: sssd does cache what a password change affects.
73 lines
2.2 KiB
Rust
73 lines
2.2 KiB
Rust
// This file is part of the shadow-rs package.
|
|
//
|
|
// For the full copyright and license information, please view the LICENSE
|
|
// file that was distributed with this source code.
|
|
|
|
//! Integration tests for every shadow-rs utility.
|
|
//!
|
|
//! One test binary, not fourteen. Each of the fourteen used to link all
|
|
//! fourteen tool crates and carry its own copy of the helpers through a
|
|
//! `#[path = "../common/mod.rs"]` include; this is the layout the rest of
|
|
//! uutils uses. The `#[path]` attributes are needed only because the
|
|
//! directory name carries a hyphen, which is not a module name.
|
|
|
|
// The print macros are denied for the tools, where a panic on a closed stream
|
|
// would abandon a half-written account file. In a test a panic is a failed
|
|
// test, which is what one wants, and printing why a test skipped is useful.
|
|
#![allow(clippy::print_stdout, clippy::print_stderr)]
|
|
|
|
mod common;
|
|
|
|
#[path = "by-util/test_chage.rs"]
|
|
mod test_chage;
|
|
#[path = "by-util/test_chfn.rs"]
|
|
mod test_chfn;
|
|
#[path = "by-util/test_chgpasswd.rs"]
|
|
mod test_chgpasswd;
|
|
#[path = "by-util/test_chpasswd.rs"]
|
|
mod test_chpasswd;
|
|
#[path = "by-util/test_chsh.rs"]
|
|
mod test_chsh;
|
|
#[path = "by-util/test_expiry.rs"]
|
|
mod test_expiry;
|
|
#[path = "by-util/test_fuzz_corpus.rs"]
|
|
mod test_fuzz_corpus;
|
|
#[path = "by-util/test_gpasswd.rs"]
|
|
mod test_gpasswd;
|
|
#[path = "by-util/test_groupadd.rs"]
|
|
mod test_groupadd;
|
|
#[path = "by-util/test_groupdel.rs"]
|
|
mod test_groupdel;
|
|
#[path = "by-util/test_groupmod.rs"]
|
|
mod test_groupmod;
|
|
#[path = "by-util/test_grpck.rs"]
|
|
mod test_grpck;
|
|
#[path = "by-util/test_login.rs"]
|
|
mod test_login;
|
|
#[path = "by-util/test_multicall.rs"]
|
|
mod test_multicall;
|
|
#[path = "by-util/test_newgrp.rs"]
|
|
mod test_newgrp;
|
|
#[path = "by-util/test_newuidmap.rs"]
|
|
mod test_newuidmap;
|
|
#[path = "by-util/test_newusers.rs"]
|
|
mod test_newusers;
|
|
#[path = "by-util/test_passwd.rs"]
|
|
mod test_passwd;
|
|
#[path = "by-util/test_pwck.rs"]
|
|
mod test_pwck;
|
|
#[path = "by-util/test_pwconv.rs"]
|
|
mod test_pwconv;
|
|
#[path = "by-util/test_sg.rs"]
|
|
mod test_sg;
|
|
#[path = "by-util/test_useradd.rs"]
|
|
mod test_useradd;
|
|
#[path = "by-util/test_userdel.rs"]
|
|
mod test_userdel;
|
|
#[path = "by-util/test_usermod.rs"]
|
|
mod test_usermod;
|
|
#[path = "by-util/test_usermod_subid.rs"]
|
|
mod test_usermod_subid;
|
|
#[path = "by-util/test_vipw.rs"]
|
|
mod test_vipw;
|