4 Commits
Author SHA1 Message Date
Jocelyn Le SageandPierre Warnier 8361bf512b gpasswd: added implementation of gpasswd (#282)
* gpasswd: added implementation of gpasswd

* gpasswd: rebase onto main and port to the current APIs

Rebases jlesage's implementation onto a main that moved a long way under
it, and carries it onto the interfaces that landed since the branch was
cut. The tool's behaviour is unchanged and still matches GNU on every
path probed.

What the rebase had to resolve:

  - shadow-rs.spec and debian/ were revived by the merge; both were
    deleted because neither could build.
  - The standalone dispatch() and hand-written --list predate the single
    applets() table, which now drives both. gpasswd joins the table.
  - The five shadow-core parser features it asked for no longer exist.
  - The fourteen [[test]] targets are one; test_gpasswd joins it.
  - README, Makefile and PLATFORM-SUPPORT described the pre-#239
    privilege model, in which every applet ran with euid 0.

What changed beyond the rebase:

  - gpasswd keeps its privilege in the multicall build. It is setuid in
    GNU and the branch marks it setuid for the per-tool install, but
    SETUID_APPLETS still listed four names, so the multicall build would
    have dropped privilege and no group administrator could have used it
    -- silently.
  - Comments in /etc/group survive. It read entries only and wrote them
    back, which erases every comment, blank line and NIS compatibility
    line in the file. The locked-file transaction keeps them, and commits
    group and gshadow together so a bad value cannot leave the pair
    disagreeing.
  - The duplicated EchoGuard and password reader are gone, replaced by
    shadow_core::tty, which blocks interrupts for the read so Ctrl-C at
    the prompt cannot leave the terminal with echo off.
  - The print macros are replaced. They panic when the stream is closed,
    which a setuid-root tool must not do part way through a change.
    These were the only five in the repository and no lint caught them,
    so clippy::print_stdout and print_stderr are now denied
    workspace-wide, with the test crate exempt.

The GNU comparison suite gains gpasswd: the unknown-group, unknown-user
and non-member exit codes, all three of which match.

CONTRIBUTING's licence list also said ISC, BSD-2-Clause, CC0-1.0, Zlib
and MPL-2.0 were acceptable, which stopped being true when deny.toml was
narrowed to the graph. It now says what deny.toml enforces.

---------

Co-authored-by: Pierre Warnier <pierre@warnier.net>
2026-09-06 11:03:53 +02:00
Pierre Warnier 02fefda42c ci: compare against GNU for real, pin the actions by digest, one make check (#275)
* ci: pin the actions by digest

A tag is a moving pointer. Whoever controls the action's repository can
repoint v7 at any commit, and every workflow in the project runs it on
the next push with write access to the checkout. A digest cannot be
repointed.

The tag stays in a trailing comment so the version is still readable, and
Renovate's pinGitHubActionDigests preset is enabled so the digests are
kept current the same way every other dependency is -- as a pull request
that CI has run, rather than silently.

* tests: make the GNU comparison real, and run it in CI

The suite compared full output for exactly two commands and, for the
other twelve, only that both tools exit 0 on --help. It ran nowhere.

It now compares what is actually a contract. 'passwd -S' and 'chage -l'
are parsed by monitoring and provisioning scripts, so their output is
compared byte for byte across eleven aging configurations -- including
the cases this project got wrong until recently: a last change of 0, the
threshold above which a maximum age reads never, and cleared fields. Exit
codes are compared on ten error paths. --help output is deliberately not
compared: ours comes from clap and is meant to differ.

One difference is deliberate and now asserted as such, so it cannot be
mistaken for a regression the day it changes by accident. GNU parses
dates leniently and rolls them over -- 'chage -d 2025-02-29' stores 1
March and '-d 2025-13-01' stores 1 January 2026. An administrator who
typed one of those made a mistake, and silently storing a different date
than the one they wrote is a poor answer for a field that decides when an
account stops working. We refuse it; chage(1) says so.

38 comparisons, all as expected, and a CI job runs them.

'make check' is now the single definition of what CI gates on -- fmt,
clippy with and without pam, and the tests in both configurations. The
pre-push hook and CONTRIBUTING refer to it instead of each carrying their
own copy of the command list, and the two hook systems are documented as
the non-overlapping things they are.
2026-09-04 16:58:54 +02:00
Pierre Warnier 5d8ac9587d review: address all 13 Copilot review comments
- Fix cargo build --release --workspace in test scripts
- Document setuid-on-symlinks as intentional in Makefile
- Warn (not abort) on subid allocation failure in useradd
- Propagate subid file read errors instead of unwrap_or_default
- Update SELinux docs to describe best-effort behavior
- Add env_clear() to getfattr subprocess in selinux.rs
- Use hardening::sanitized_env() in nscd.rs instead of local reimpl
- Create testuser in pam-e2e.sh, add cleanup
- Document su-as-root limitation in pam-e2e.sh
- Fix set -e exit code capture in gnu-compat.sh
- Add 5 date validation unit tests in chage
- Wire audit::log_user_event into all 7 tools
2026-03-24 15:42:08 +01:00
Pierre Warnier 8ba8f940fd prod: GNU compat tests, PAM e2e, setuid, SELinux, audit, packaging
Fixes #93 — GNU compatibility test suite (tests/gnu-compat.sh)
Fixes #94 — PAM end-to-end test script (tests/pam-e2e.sh)
Fixes #95 — Setuid permissions in Makefile (chmod 4755)
Fixes #96 — nscd env_clear() on subprocess spawning
Fixes #97 — SELinux file context support (getfattr/chcon/restorecon)
Fixes #98 — Audit logging to syslog/auditd
Fixes #99 — subuid/subgid allocation in useradd
Fixes #100 — Debian packaging (debian/control, debian/rules)
Fixes #101 — Fedora packaging (shadow-rs.spec)
Fixes #103 — Recursive chown on usermod UID change
Fixes #104 — Proper date validation (Feb 31 rejected)

456 tests, zero clippy warnings. Binary: 894KB (release-small).
2026-03-24 15:15:21 +01:00