Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<version>` runs the three published archives of a
Expand Down
22 changes: 20 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -158,15 +176,15 @@ 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; \
done
@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.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down