expiry, and usermod's subordinate-id options - #299
Merged
Conversation
pierre-warnier
force-pushed
the
idmap-tool
branch
from
September 7, 2026 13:46
87294c9 to
a64c87b
Compare
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 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.
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.
pierre-warnier
force-pushed
the
expiry-subid
branch
from
September 7, 2026 13:47
053dc34 to
e71b06e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits:
usermodgains the four subordinate-id options GNU has and ours lacked, andexpiry— the twenty-eighth tool and the last the Scope table lists as in scope — is added.Stacked on #298. Base retargets to
mainas the stack merges.usermod -v/-V/-w/-WEstablished by running the GNU tool: a range already held is not added twice; a removal trims, splits or deletes the entries it touches and ignores a range never held; other users' entries are never consulted (an administrator may share a range on purpose); an invalid range is exit 3 with GNU's wording before anything is written. Entries are keyed by the login name given and not renamed by
-l, as GNU's are not.-Vis GNU's letter, so clap's own-Vgave way;--versionstays. Helpers live inshadow_core::subid.expiryJudges the caller's own shadow line as
loginwould — silent, warning, forced change through PAM, or refusal. The rules are one function,shadow_core::shadow::Aging, with checked arithmetic over fields anyone who can write/etc/shadowchooses; order islogin's; a maximum age ≥ 10000 means never, aschage -lprints it; a locked password is not reported.Privileges. GNU ships it setgid
shadow— enough to read the file, no more — and the change runs through PAM as the caller. The per-tool install does the same (a new install class,2755 root:shadow). The multicall binary keeps euid 0 for it, having nothing narrower to offer. Under--prefixit reports and never changes anything.groupmemsis out of scopeDebian 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 now says so.Verification
make checkpam, unprivileged run — exit 0cargo test --workspaceexpiry -fdriving a real PAM password change under a ptymake test-gnu-compatmake test-arm64