diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c8604a..9a030c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- `make install` failed on any system without a `shadow` group -- Fedora, + Arch, or a packager's chroot -- because `expiry` was installed setgid to a + group that was not there. On such systems `/etc/shadow` is readable by root + alone and the GNU tool that reads it on a user's behalf, `chage`, is setuid + root; `expiry` now follows that convention where the group is absent, and + `SHADOW_GROUP=` names one that goes by another name. Reported by the Arch + packager (#306) + ### Added - `make verify-release TAG=` runs the three published archives of a diff --git a/Makefile b/Makefile index dcae177..c62c695 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,24 @@ USER_BIN_TOOLS = chage login # expiry reads the caller's own /etc/shadow line and nothing else, and the GNU # suite ships it setgid shadow -- enough to read the file, no more. SETGID_SHADOW_TOOLS = expiry + +# The group allowed to read /etc/shadow. Debian and Ubuntu have one, `shadow`, +# and that is what the tools above are made setgid to. Fedora and Arch have no +# such group: /etc/shadow there is readable by root alone, and the GNU tool +# that reads it on a user's behalf, chage, is setuid root instead. Where the +# group does not exist at install time -- those systems, or a packager's +# chroot -- the tools above follow that convention and are installed setuid +# root; they check the caller's real uid, so the extra privilege buys a user +# nothing beyond reading their own line. Packagers whose target has the group +# under another name set SHADOW_GROUP. +SHADOW_GROUP ?= shadow +ifneq ($(shell getent group '$(SHADOW_GROUP)' >/dev/null 2>&1 && echo yes),) +SETGID_INSTALL = install -Dm2755 -g '$(SHADOW_GROUP)' +SETGID_LABEL = setgid $(SHADOW_GROUP) (2755) +else +SETGID_INSTALL = install -Dm4755 +SETGID_LABEL = setuid (4755; no group '$(SHADOW_GROUP)' on this system) +endif USER_TOOLS = $(SETUID_TOOLS) $(USER_BIN_TOOLS) $(SETGID_SHADOW_TOOLS) ALL_TOOLS = $(SETUID_TOOLS) $(ROOT_TOOLS) $(USER_BIN_TOOLS) $(SETGID_SHADOW_TOOLS) @@ -158,7 +176,7 @@ install: build install -Dm0755 target/release/$$tool $(DESTDIR)$(BINDIR)/$$tool || exit 1; \ done @for tool in $(SETGID_SHADOW_TOOLS); do \ - install -Dm2755 -g shadow target/release/$$tool $(DESTDIR)$(BINDIR)/$$tool || exit 1; \ + $(SETGID_INSTALL) target/release/$$tool $(DESTDIR)$(BINDIR)/$$tool || exit 1; \ done @for tool in $(ROOT_TOOLS); do \ install -Dm0755 target/release/$$tool $(DESTDIR)$(SBINDIR)/$$tool || exit 1; \ @@ -166,7 +184,7 @@ install: build @echo "Installed $(words $(ALL_TOOLS)) standalone binaries" @echo " $(DESTDIR)$(BINDIR)/ setuid (4755): $(SETUID_TOOLS)" @echo " $(DESTDIR)$(BINDIR)/ user (0755): $(USER_BIN_TOOLS)" - @echo " $(DESTDIR)$(BINDIR)/ setgid shadow (2755): $(SETGID_SHADOW_TOOLS)" + @echo " $(DESTDIR)$(BINDIR)/ $(SETGID_LABEL): $(SETGID_SHADOW_TOOLS)" @echo " $(DESTDIR)$(SBINDIR)/ root (0755): $(ROOT_TOOLS)" # Opt-in install: single multicall binary with symlinks. Smaller footprint. diff --git a/README.md b/README.md index ccdba92..bd7c503 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ docker compose run --rm debian cargo build --release Default install: 28 standalone per-tool binaries with least-privilege setuid layout matching GNU shadow-utils. Only `passwd`, `chfn`, `chsh`, `newgrp`, `gpasswd`, `sg`, `newuidmap` and `newgidmap` are installed setuid-root, `expiry` is setgid `shadow`; the other 19 are plain `0755`. +On a system with no `shadow` group -- Fedora, Arch -- `expiry` is installed setuid-root instead, the way those systems ship the GNU tools that read `/etc/shadow` for a user; a group under another name is named with `SHADOW_GROUP=`. ```shell sudo make install PREFIX=/usr/local