shadow: update to 4.19.4
authorAlexandru Ardelean <redacted>
Wed, 22 Apr 2026 09:42:55 +0000 (12:42 +0300)
committerAlexandru Ardelean <redacted>
Fri, 22 May 2026 03:57:39 +0000 (06:57 +0300)
Large version jump from 4.8.1 to 4.19.4 (latest upstream LTS).

Build changes:
- Refresh patches/004-fix-su-controoling-term.patch: su.c moved the
  ioctl() call from line 1122 to 1169 and changed (char *) 0 to
  (char *) NULL; update patch context and re-canonicalise through
  quilt (blank context line spacing).
- New CONFIGURE_ARGS:
  * --disable-logind: 4.19.4 added an optional libsystemd-based
    logind integration which OpenWrt doesn't ship.
  * --without-libbsd: shadow's configure now hard-fails on missing
    readpassphrase() unless libbsd is found; the in-tree
    lib/readpassphrase.c fallback is enabled by --without-libbsd.
  * --without-sssd: avoid dragging in an sssd build dep.
  * --disable-subordinate-ids: 4.19.4 builds libsubid (subuid/subgid
    runtime API) unconditionally when subids are enabled, and its
    libtool -export-symbols-regex generates a version script that
    binutils 2.40+ rejects against libxcrypt's versioned
    crypt_checksalt@@XCRYPT_4.3 symbol. Disabling subordinate-ids
    skips libsubid entirely; OpenWrt doesn't ship libsubid.
- Drop newgidmap, newuidmap, lastlog and groups from SHADOW_APPLETS:
  newgidmap/newuidmap are only built when subordinate-ids are
  enabled, lastlog defaults to disabled in 4.19.4, and the groups
  binary was removed from shadow upstream (use coreutils).

Test coverage:
- Replace the per-applet --version check in test.sh with per-applet
  functional tests:
    pwck     -> 'pwck -r' read-only consistency check; accept
                 non-zero exit since the CI container's /etc/passwd
                 trips minor warnings.
    grpck    -> 'grpck -r' read-only consistency check.
    chage    -> 'chage -l root' lists password aging info.
    useradd  -> 'useradd -D' dumps defaults without modifying state.
    passwd   -> 'passwd -S root' prints the password status line.
    faillog  -> create empty /var/log/faillog then 'faillog -a'
                must emit a header line.
    login/su -> PAM-interactive; presence covered by generic tests.
    Other applets -> verify binary presence (CI's generic tests
                 already check stripped, no build paths, linked-libs).
- Add test-version.sh as a generic-version-check override: shadow
  tools don't honour --version (only --help), so the framework's
  probe finds no PKG_VERSION match in any binary and would otherwise
  fail Generic tests for every sub-package.

Signed-off-by: Alexandru Ardelean <redacted>
utils/shadow/Makefile
utils/shadow/patches/004-fix-su-controoling-term.patch
utils/shadow/test-version.sh [new file with mode: 0755]
utils/shadow/test.sh [new file with mode: 0644]

index 3260074a9ca3362e288d874d9c08796e5f8e1ad9..d195be3c77038a4203ecc469ff6d7aa24c021a0f 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=shadow
-PKG_VERSION:=4.8.1
-PKG_RELEASE:=3
+PKG_VERSION:=4.19.4
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://github.com/shadow-maint/shadow/releases/download/$(PKG_VERSION)
-PKG_HASH:=a3ad4630bdc41372f02a647278a8c3514844295d36eefe68ece6c3a641c1ae62
+PKG_HASH:=ce57a313e315a0a7cb04a8f50cc20753e994e487bbe9b78a2a824ca75cb486c0
 
 PKG_MAINTAINER:=Alexandru Ardelean <ardeleanalex@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
@@ -29,8 +29,8 @@ include $(INCLUDE_DIR)/nls.mk
 
 SHADOW_APPLETS := \
        chage chfn chgpasswd chpasswd chsh expiry faillog gpasswd \
-       groupadd groupdel groupmems groupmod groups grpck grpconv grpunconv \
-       lastlog login logoutd newgidmap newgrp newuidmap newusers nologin \
+       groupadd groupdel groupmems groupmod grpck grpconv grpunconv \
+       login logoutd newgrp newusers nologin \
        passwd pwck pwconv pwunconv su \
        useradd userdel usermod vipw
 
@@ -42,6 +42,10 @@ CONFIGURE_ARGS += \
        --without-attr \
        --without-tcb \
        --without-nscd \
+       --without-sssd \
+       --without-libbsd \
+       --disable-logind \
+       --disable-subordinate-ids \
        --with-bcrypt
 
 CONFIGURE_VARS += \
index 9644cf0aef5a0decfd633b22e846d6c10b1d8e0f..eb536c1cf59d6b20b9f3a578a2552867bd73774b 100644 (file)
@@ -1,9 +1,9 @@
 --- a/src/su.c
 +++ b/src/su.c
-@@ -1122,8 +1122,12 @@ int main (int argc, char **argv)
+@@ -1169,8 +1169,12 @@ int main (int argc, char **argv)
  
                if (fd >= 0) {
-                       err = ioctl (fd, TIOCNOTTY, (char *) 0);
+                       err = ioctl (fd, TIOCNOTTY, (char *) NULL);
 +                      if (-1 == err && ENOTTY == errno) {
 +                              /* There are no controlling terminal already */
 +                              err = 0;
diff --git a/utils/shadow/test-version.sh b/utils/shadow/test-version.sh
new file mode 100755 (executable)
index 0000000..d5cc352
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Generic version-check override.
+#
+# Shadow's tools accept --help but not --version, so the framework's generic
+# version probe (--version / -v / -V / --help) doesn't find the PKG_VERSION
+# string in any of them and would otherwise mark every sub-package as missing
+# a version match. The companion test.sh exercises actual functionality of
+# each applet (pwck, grpck, chage, useradd, passwd, faillog, ...), so the
+# generic version check has no value here.
+
+exit 0
diff --git a/utils/shadow/test.sh b/utils/shadow/test.sh
new file mode 100644 (file)
index 0000000..e05d6a0
--- /dev/null
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+applet="${1#shadow-}"
+
+find_bin() {
+       for d in /usr/sbin /usr/bin; do
+               [ -x "$d/$1" ] && echo "$d/$1" && return 0
+       done
+       return 1
+}
+
+case "$1" in
+shadow-common)
+       [ -f /etc/login.defs ] || {
+               echo "FAIL: /etc/login.defs not installed"
+               exit 1
+       }
+       echo "login.defs: OK"
+
+       grep -q "ENCRYPT_METHOD.*BCRYPT" /etc/login.defs || {
+               echo "FAIL: BCRYPT not configured as ENCRYPT_METHOD in login.defs"
+               exit 1
+       }
+       echo "BCRYPT encryption: OK"
+       ;;
+
+shadow-utils|shadow)
+       # meta-packages, no binaries to test
+       ;;
+
+shadow-login|shadow-su)
+       # PAM-interactive; presence is covered by generic CI tests.
+       ;;
+
+shadow-pwck)
+       bin=$(find_bin pwck) || { echo "FAIL: pwck not found"; exit 1; }
+       # -r is read-only mode. Exit status is non-zero whenever pwck spots any
+       # warning in /etc/passwd (which the runtime-test container's stock files
+       # routinely trigger), so we only check that pwck actually ran and reached
+       # its summary line.
+       out=$("$bin" -r 2>&1)
+       echo "$out" | grep -qE "no changes|pwck:" || {
+               echo "FAIL: pwck -r did not produce expected output"
+               echo "$out"
+               exit 1
+       }
+       echo "pwck -r: OK"
+       ;;
+
+shadow-grpck)
+       bin=$(find_bin grpck) || { echo "FAIL: grpck not found"; exit 1; }
+       "$bin" -r || {
+               echo "FAIL: grpck -r returned non-zero on /etc/group"
+               exit 1
+       }
+       echo "grpck -r: OK"
+       ;;
+
+shadow-chage)
+       bin=$(find_bin chage) || { echo "FAIL: chage not found"; exit 1; }
+       # -l lists password-aging info for a user; root always exists.
+       "$bin" -l root | grep -q "Last password change" || {
+               echo "FAIL: chage -l root did not print expected output"
+               exit 1
+       }
+       echo "chage -l root: OK"
+       ;;
+
+shadow-useradd)
+       bin=$(find_bin useradd) || { echo "FAIL: useradd not found"; exit 1; }
+       # -D with no other args dumps defaults to stdout, no system modification.
+       "$bin" -D | grep -q "^GROUP=" || {
+               echo "FAIL: useradd -D did not dump defaults"
+               exit 1
+       }
+       echo "useradd -D: OK"
+       ;;
+
+shadow-passwd)
+       bin=$(find_bin passwd) || { echo "FAIL: passwd not found"; exit 1; }
+       # -S prints the password status line for a user without modifying it.
+       "$bin" -S root | grep -q "^root" || {
+               echo "FAIL: passwd -S root did not return root's status line"
+               exit 1
+       }
+       echo "passwd -S root: OK"
+       ;;
+
+shadow-faillog)
+       bin=$(find_bin faillog) || { echo "FAIL: faillog not found"; exit 1; }
+       # faillog reads /var/log/faillog; in the CI runtime container that file
+       # doesn't exist, so create an empty one. -a then dumps the database (just
+       # the header in our case).
+       [ -f /var/log/faillog ] || : > /var/log/faillog
+       "$bin" -a 2>&1 | grep -qE "Login|Username|Failures" || {
+               echo "FAIL: faillog -a did not produce a header line"
+               exit 1
+       }
+       echo "faillog -a: OK"
+       ;;
+
+shadow-*)
+       # Remaining applets (chfn, chsh, chgpasswd, chpasswd, expiry, gpasswd,
+       # groupadd, groupdel, groupmems, groupmod, grpconv, grpunconv, logoutd,
+       # newgrp, newusers, nologin, pwconv, pwunconv, userdel, usermod, vipw)
+       # either modify system state or are interactive.
+       # Generic CI tests already verify the binary is present, stripped, and
+       # links cleanly; that's the practical bar in this environment.
+       bin=$(find_bin "$applet") || {
+               echo "FAIL: $applet not found in /usr/sbin or /usr/bin"
+               exit 1
+       }
+       echo "$applet binary: OK ($bin)"
+       ;;
+esac
git clone https://git.99rst.org/PROJECT