From 4d38963f85b49c4374ff596f6b3d758e6a71a30b Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 29 Mar 2022 14:08:18 -0400 Subject: [PATCH] import shadow-utils-4.6-16.el8 --- SOURCES/shadow-4.6-getsubids.patch | 244 ++ ...x-sigsegv-when-passwd-does-not-exist.patch | 13 + SOURCES/shadow-4.6-install_subid_h.patch | 28 + SOURCES/shadow-4.6-libsubid_creation.patch | 1306 +++++++++ ...bid_fix_newusers_nss_provides_subids.patch | 151 ++ ...bsubid_init_not_print_error_messages.patch | 40 + ...hadow-4.6-libsubid_init_return_false.patch | 37 + ...w-4.6-libsubid_make_logfd_not_extern.patch | 41 + ....6-libsubid_not_print_error_messages.patch | 2382 +++++++++++++++++ ...shadow-4.6-libsubid_nsswitch_support.patch | 1758 ++++++++++++ ....6-libsubid_simplify_ranges_variable.patch | 264 ++ ...dow-4.6-man-mention-nss-in-newuidmap.patch | 44 + ...dow-4.6-man_clarify_subid_delegation.patch | 166 ++ .../shadow-4.6-respect_enable_static_no.patch | 24 + .../shadow-4.6-useradd_SUB_UID_COUNT-0.patch | 44 + ...useradd_dont_try_to_create_0_subuids.patch | 21 + SPECS/shadow-utils.spec | 113 +- 17 files changed, 6674 insertions(+), 2 deletions(-) create mode 100644 SOURCES/shadow-4.6-getsubids.patch create mode 100644 SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch create mode 100644 SOURCES/shadow-4.6-install_subid_h.patch create mode 100644 SOURCES/shadow-4.6-libsubid_creation.patch create mode 100644 SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch create mode 100644 SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch create mode 100644 SOURCES/shadow-4.6-libsubid_init_return_false.patch create mode 100644 SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch create mode 100644 SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch create mode 100644 SOURCES/shadow-4.6-libsubid_nsswitch_support.patch create mode 100644 SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch create mode 100644 SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch create mode 100644 SOURCES/shadow-4.6-man_clarify_subid_delegation.patch create mode 100644 SOURCES/shadow-4.6-respect_enable_static_no.patch create mode 100644 SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch create mode 100644 SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch diff --git a/SOURCES/shadow-4.6-getsubids.patch b/SOURCES/shadow-4.6-getsubids.patch new file mode 100644 index 0000000..12030cb --- /dev/null +++ b/SOURCES/shadow-4.6-getsubids.patch @@ -0,0 +1,244 @@ +diff -up shadow-4.6/man/getsubids.1.xml.getsubids shadow-4.6/man/getsubids.1.xml +--- shadow-4.6/man/getsubids.1.xml.getsubids 2021-12-09 10:40:50.730275761 +0100 ++++ shadow-4.6/man/getsubids.1.xml 2021-12-09 10:40:50.730275761 +0100 +@@ -0,0 +1,141 @@ ++ ++ ++ ++]> ++ ++ ++ ++ ++ Iker ++ Pedrosa ++ Creation, 2021 ++ ++ ++ ++ getsubids ++ 1 ++ User Commands ++ shadow-utils ++ &SHADOW_UTILS_VERSION; ++ ++ ++ getsubids ++ get the subordinate id ranges for a user ++ ++ ++ ++ ++ getsubids ++ ++ options ++ ++ ++ USER ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ The getsubids command lists the subordinate user ID ++ ranges for a given user. The subordinate group IDs can be listed using ++ the option. ++ ++ ++ ++ ++ OPTIONS ++ ++ The options which apply to the getsubids command are: ++ ++ ++ ++ ++ ++ ++ ++ ++ List the subordinate group ID ranges. ++ ++ ++ ++ ++ ++ ++ ++ EXAMPLE ++ ++ For example, to obtain the subordinate UIDs of the testuser: ++ ++ ++ ++$ getsubids testuser ++0: testuser 100000 65536 ++ ++ ++ ++ This command output provides (in order from left to right) the list ++ index, username, UID range start, and number of UIDs in range. ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ login.defs5 ++ , ++ ++ newgidmap1 ++ , ++ ++ newuidmap1 ++ , ++ ++ subgid5 ++ , ++ ++ subuid5 ++ , ++ ++ useradd8 ++ , ++ ++ userdel8 ++ . ++ ++ usermod8 ++ , ++ ++ ++ +diff -up shadow-4.6/man/Makefile.am.getsubids shadow-4.6/man/Makefile.am +--- shadow-4.6/man/Makefile.am.getsubids 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/Makefile.am 2021-12-09 10:40:50.730275761 +0100 +@@ -59,6 +59,7 @@ man_MANS += $(man_nopam) + endif + + man_subids = \ ++ man1/getsubids.1 \ + man1/newgidmap.1 \ + man1/newuidmap.1 \ + man5/subgid.5 \ +@@ -77,6 +78,7 @@ man_XMANS = \ + expiry.1.xml \ + faillog.5.xml \ + faillog.8.xml \ ++ getsubids.1.xml \ + gpasswd.1.xml \ + groupadd.8.xml \ + groupdel.8.xml \ +diff -up shadow-4.6/src/getsubids.c.getsubids shadow-4.6/src/getsubids.c +--- shadow-4.6/src/getsubids.c.getsubids 2021-12-09 10:40:50.730275761 +0100 ++++ shadow-4.6/src/getsubids.c 2021-12-09 10:40:50.730275761 +0100 +@@ -0,0 +1,46 @@ ++#include ++#include ++#include ++#include "subid.h" ++#include "prototypes.h" ++ ++const char *Prog; ++FILE *shadow_logfd = NULL; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user\n", Prog); ++ fprintf(stderr, " list subuid ranges for user\n"); ++ fprintf(stderr, " pass -g to list subgid ranges\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i, count=0; ++ struct subid_range *ranges; ++ const char *owner; ++ ++ Prog = Basename (argv[0]); ++ shadow_logfd = stderr; ++ if (argc < 2) ++ usage(); ++ owner = argv[1]; ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) { ++ owner = argv[2]; ++ count = get_subgid_ranges(owner, &ranges); ++ } else if (argc == 2 && strcmp(argv[1], "-h") == 0) { ++ usage(); ++ } else { ++ count = get_subuid_ranges(owner, &ranges); ++ } ++ if (!ranges) { ++ fprintf(stderr, "Error fetching ranges\n"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) { ++ printf("%d: %s %lu %lu\n", i, owner, ++ ranges[i].start, ranges[i].count); ++ } ++ return 0; ++} +diff -up shadow-4.6/src/Makefile.am.getsubids shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.getsubids 2021-12-09 10:40:50.710275627 +0100 ++++ shadow-4.6/src/Makefile.am 2021-12-09 10:45:04.465985510 +0100 +@@ -140,8 +140,8 @@ if WITH_TCB + endif + + if ENABLE_SUBIDS +-noinst_PROGRAMS += list_subid_ranges \ +- get_subid_owners \ ++bin_PROGRAMS += getsubids ++noinst_PROGRAMS += get_subid_owners \ + new_subid_range \ + free_subid_range \ + check_subid_range +@@ -156,13 +156,13 @@ MISCLIBS = \ + $(LIBCRYPT) \ + $(LIBTCB) + +-list_subid_ranges_LDADD = \ ++getsubids_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) -ldl + +-list_subid_ranges_CPPFLAGS = \ ++getsubids_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid diff --git a/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch b/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch new file mode 100644 index 0000000..658156a --- /dev/null +++ b/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch @@ -0,0 +1,13 @@ +diff -up shadow-4.9/libmisc/prefix_flag.c.groupdel-fix-sigsegv-when-passwd-does-not-exist shadow-4.9/libmisc/prefix_flag.c +--- shadow-4.9/libmisc/prefix_flag.c.groupdel-fix-sigsegv-when-passwd-does-not-exist 2021-11-19 09:21:36.997091941 +0100 ++++ shadow-4.9/libmisc/prefix_flag.c 2021-11-19 09:22:19.001341010 +0100 +@@ -288,6 +288,9 @@ extern struct passwd* prefix_getpwent() + if(!passwd_db_file) { + return getpwent(); + } ++ if (!fp_pwent) { ++ return NULL; ++ } + return fgetpwent(fp_pwent); + } + extern void prefix_endpwent() diff --git a/SOURCES/shadow-4.6-install_subid_h.patch b/SOURCES/shadow-4.6-install_subid_h.patch new file mode 100644 index 0000000..cee2e03 --- /dev/null +++ b/SOURCES/shadow-4.6-install_subid_h.patch @@ -0,0 +1,28 @@ +From 77e39de1e6cbd6925f16bb260abb7d216296886b Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 4 May 2021 09:21:11 -0500 +Subject: [PATCH] Install subid.h + +Now subid.h gets installed under /usr/include/shadow/subid.h + +Signed-off-by: Serge Hallyn +--- + libsubid/Makefile.am | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libsubid/Makefile.am b/libsubid/Makefile.am +index f543b5eb..189165b0 100644 +--- a/libsubid/Makefile.am ++++ b/libsubid/Makefile.am +@@ -3,6 +3,8 @@ libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ + -shared -version-info @LIBSUBID_ABI_MAJOR@ + libsubid_la_SOURCES = api.c + ++pkginclude_HEADERS = subid.h ++ + MISCLIBS = \ + $(LIBAUDIT) \ + $(LIBSELINUX) \ +-- +2.31.1 + diff --git a/SOURCES/shadow-4.6-libsubid_creation.patch b/SOURCES/shadow-4.6-libsubid_creation.patch new file mode 100644 index 0000000..bd4b5bc --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_creation.patch @@ -0,0 +1,1306 @@ +diff -up shadow-4.6/configure.ac.libsubid_creation shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.libsubid_creation 2021-10-19 16:12:02.663748272 +0200 ++++ shadow-4.6/configure.ac 2021-10-19 16:13:07.194697194 +0200 +@@ -1,11 +1,21 @@ + dnl Process this file with autoconf to produce a configure script. +-AC_PREREQ([2.64]) ++AC_PREREQ([2.69]) ++m4_define([libsubid_abi_major], 1) ++m4_define([libsubid_abi_minor], 0) ++m4_define([libsubid_abi_micro], 0) ++m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) + AC_INIT([shadow], [4.6], [pkg-shadow-devel@lists.alioth.debian.org], [], + [https://github.com/shadow-maint/shadow]) + AM_INIT_AUTOMAKE([1.11 foreign dist-xz]) ++AC_CONFIG_MACRO_DIRS([m4]) + AM_SILENT_RULES([yes]) + AC_CONFIG_HEADERS([config.h]) + ++AC_SUBST([LIBSUBID_ABI_MAJOR], [libsubid_abi_major]) ++AC_SUBST([LIBSUBID_ABI_MINOR], [libsubid_abi_minor]) ++AC_SUBST([LIBSUBID_ABI_MICRO], [libsubid_abi_micro]) ++AC_SUBST([LIBSUBID_ABI], [libsubid_abi]) ++ + dnl Some hacks... + test "$prefix" = "NONE" && prefix="/usr" + test "$prefix" = "/usr" && exec_prefix="" +@@ -22,8 +22,8 @@ test "$prefix" = "/usr" && exec_prefix="" + + AC_GNU_SOURCE + +-AM_DISABLE_SHARED + AM_ENABLE_STATIC ++AM_ENABLE_SHARED + + AM_MAINTAINER_MODE + +@@ -725,6 +725,7 @@ AC_CONFIG_FILES([ + man/zh_TW/Makefile + libmisc/Makefile + lib/Makefile ++ libsubid/Makefile + src/Makefile + contrib/Makefile + etc/Makefile +diff -up shadow-4.6/libsubid/api.c.libsubid_creation shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/api.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (c) 2020 Serge Hallyn ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the copyright holders or contributors may not be used to ++ * endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "subordinateio.h" ++#include "idmapping.h" ++#include "api.h" ++ ++static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type) ++{ ++ struct subordinate_range **ranges = NULL; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return NULL; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return NULL; ++ } ++ break; ++ default: ++ return NULL; ++ } ++ ++ ranges = list_owner_ranges(owner, id_type); ++ ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ return ranges; ++} ++ ++struct subordinate_range **get_subuid_ranges(const char *owner) ++{ ++ return get_subid_ranges(owner, ID_TYPE_UID); ++} ++ ++struct subordinate_range **get_subgid_ranges(const char *owner) ++{ ++ return get_subid_ranges(owner, ID_TYPE_GID); ++} ++ ++void subid_free_ranges(struct subordinate_range **ranges) ++{ ++ return free_subordinate_ranges(ranges); ++} ++ ++int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type) ++{ ++ int ret = -1; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } ++ break; ++ default: ++ return -1; ++ } ++ ++ ret = find_subid_owners(id, owner, id_type); ++ ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ return ret; ++} ++ ++int get_subuid_owners(uid_t uid, uid_t **owner) ++{ ++ return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID); ++} ++ ++int get_subgid_owners(gid_t gid, uid_t **owner) ++{ ++ return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID); ++} ++ ++bool grant_subid_range(struct subordinate_range *range, bool reuse, ++ enum subid_type id_type) ++{ ++ bool ret; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ ret = new_subid_range(range, id_type, reuse); ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; ++} ++ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse) ++{ ++ return grant_subid_range(range, reuse, ID_TYPE_UID); ++} ++ ++bool grant_subgid_range(struct subordinate_range *range, bool reuse) ++{ ++ return grant_subid_range(range, reuse, ID_TYPE_GID); ++} ++ ++bool free_subid_range(struct subordinate_range *range, enum subid_type id_type) ++{ ++ bool ret; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ ret = release_subid_range(range, id_type); ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; ++} ++ ++bool free_subuid_range(struct subordinate_range *range) ++{ ++ return free_subid_range(range, ID_TYPE_UID); ++} ++ ++bool free_subgid_range(struct subordinate_range *range) ++{ ++ return free_subid_range(range, ID_TYPE_GID); ++} +diff -up shadow-4.6/libsubid/api.h.libsubid_creation shadow-4.6/libsubid/api.h +--- shadow-4.6/libsubid/api.h.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/api.h 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,17 @@ ++#include "subid.h" ++#include ++ ++struct subordinate_range **get_subuid_ranges(const char *owner); ++struct subordinate_range **get_subgid_ranges(const char *owner); ++void subid_free_ranges(struct subordinate_range **ranges); ++ ++int get_subuid_owners(uid_t uid, uid_t **owner); ++int get_subgid_owners(gid_t gid, uid_t **owner); ++ ++/* range should be pre-allocated with owner and count filled in, start is ++ * ignored, can be 0 */ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse); ++bool grant_subgid_range(struct subordinate_range *range, bool reuse); ++ ++bool free_subuid_range(struct subordinate_range *range); ++bool free_subgid_range(struct subordinate_range *range); +diff -up shadow-4.6/libsubid/Makefile.am.libsubid_creation shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/Makefile.am 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,24 @@ ++lib_LTLIBRARIES = libsubid.la ++libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ ++ -shared -version-info @LIBSUBID_ABI_MAJOR@ ++libsubid_la_SOURCES = api.c ++ ++MISCLIBS = \ ++ $(LIBAUDIT) \ ++ $(LIBSELINUX) \ ++ $(LIBSEMANAGE) \ ++ $(LIBCRYPT_NOPAM) \ ++ $(LIBSKEY) \ ++ $(LIBMD) \ ++ $(LIBCRYPT) \ ++ $(LIBTCB) ++ ++libsubid_la_LIBADD = \ ++ $(top_srcdir)/lib/libshadow.la \ ++ $(MISCLIBS) \ ++ $(top_srcdir)/libmisc/libmisc.a ++ ++AM_CPPFLAGS = \ ++ -I${top_srcdir}/lib \ ++ -I${top_srcdir}/libmisc \ ++ -DLOCALEDIR=\"$(datadir)/locale\" +diff -up shadow-4.6/libsubid/subid.h.libsubid_creation shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/subid.h 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,17 @@ ++#include ++ ++#ifndef SUBID_RANGE_DEFINED ++#define SUBID_RANGE_DEFINED 1 ++struct subordinate_range { ++ const char *owner; ++ unsigned long start; ++ unsigned long count; ++}; ++ ++enum subid_type { ++ ID_TYPE_UID = 1, ++ ID_TYPE_GID = 2 ++}; ++ ++#define SUBID_NFIELDS 3 ++#endif +diff -up shadow-4.6/lib/subordinateio.c.libsubid_creation shadow-4.6/lib/subordinateio.c +--- shadow-4.6/lib/subordinateio.c.libsubid_creation 2021-10-19 16:12:02.654748139 +0200 ++++ shadow-4.6/lib/subordinateio.c 2021-10-19 16:12:02.661748243 +0200 +@@ -13,14 +13,7 @@ + #include "subordinateio.h" + #include + #include +- +-struct subordinate_range { +- const char *owner; +- unsigned long start; +- unsigned long count; +-}; +- +-#define NFIELDS 3 ++#include + + /* + * subordinate_dup: create a duplicate range +@@ -78,7 +71,7 @@ static void *subordinate_parse (const ch + static char rangebuf[1024]; + int i; + char *cp; +- char *fields[NFIELDS]; ++ char *fields[SUBID_NFIELDS]; + + /* + * Copy the string to a temporary buffer so the substrings can +@@ -93,7 +86,7 @@ static void *subordinate_parse (const ch + * field. The fields are converted into NUL terminated strings. + */ + +- for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) { ++ for (cp = rangebuf, i = 0; (i < SUBID_NFIELDS) && (NULL != cp); i++) { + fields[i] = cp; + while (('\0' != *cp) && (':' != *cp)) { + cp++; +@@ -108,10 +101,10 @@ static void *subordinate_parse (const ch + } + + /* +- * There must be exactly NFIELDS colon separated fields or ++ * There must be exactly SUBID_NFIELDS colon separated fields or + * the entry is invalid. Also, fields must be non-blank. + */ +- if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') ++ if (i != SUBID_NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') + return NULL; + range.owner = fields[0]; + if (getulong (fields[1], &range.start) == 0) +@@ -319,6 +312,39 @@ static bool have_range(struct commonio_d + return false; + } + ++static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n) ++{ ++ struct subordinate_range *tmp; ++ if (!*ranges) { ++ *ranges = malloc(2 * sizeof(struct subordinate_range **)); ++ if (!*ranges) ++ return false; ++ } else { ++ struct subordinate_range **new; ++ new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **))); ++ if (!new) ++ return false; ++ *ranges = new; ++ } ++ (*ranges)[n] = (*ranges)[n+1] = NULL; ++ tmp = subordinate_dup(new); ++ if (!tmp) ++ return false; ++ (*ranges)[n] = tmp; ++ return true; ++} ++ ++void free_subordinate_ranges(struct subordinate_range **ranges) ++{ ++ int i; ++ ++ if (!ranges) ++ return; ++ for (i = 0; ranges[i]; i++) ++ subordinate_free(ranges[i]); ++ free(ranges); ++} ++ + /* + * subordinate_range_cmp: compare uid ranges + * +@@ -697,6 +723,160 @@ gid_t sub_gid_find_free_range(gid_t min, + start = find_free_range (&subordinate_gid_db, min, max, count); + return start == ULONG_MAX ? (gid_t) -1 : start; + } ++ ++/* ++ struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++ * ++ * @owner: username ++ * @id_type: UID or GUID ++ * ++ * Returns the subuid or subgid ranges which are owned by the specified ++ * user. Username may be a username or a string representation of a ++ * UID number. If id_type is UID, then subuids are returned, else ++ * subgids are returned. If there is an error, < 0 is returned. ++ * ++ * The caller must free the subordinate range list. ++ */ ++struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++{ ++ // TODO - need to handle owner being either uid or username ++ const struct subordinate_range *range; ++ struct subordinate_range **ranges = NULL; ++ struct commonio_db *db; ++ int size = 0; ++ ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ ++ commonio_rewind(db); ++ while ((range = commonio_next(db)) != NULL) { ++ if (0 == strcmp(range->owner, owner)) { ++ if (!append_range(&ranges, range, size++)) { ++ free_subordinate_ranges(ranges); ++ return NULL; ++ } ++ } ++ } ++ ++ return ranges; ++} ++ ++static bool all_digits(const char *str) ++{ ++ int i; ++ ++ for (i = 0; str[i] != '\0'; i++) ++ if (!isdigit(str[i])) ++ return false; ++ return true; ++} ++ ++static int append_uids(uid_t **uids, const char *owner, int n) ++{ ++ uid_t owner_uid; ++ uid_t *ret; ++ int i; ++ ++ if (all_digits(owner)) { ++ i = sscanf(owner, "%d", &owner_uid); ++ if (i != 1) { ++ // should not happen ++ free(*uids); ++ *uids = NULL; ++ return -1; ++ } ++ } else { ++ struct passwd *pwd = getpwnam(owner); ++ if (NULL == pwd) { ++ /* Username not defined in /etc/passwd, or error occured during lookup */ ++ free(*uids); ++ *uids = NULL; ++ return -1; ++ } ++ owner_uid = pwd->pw_uid; ++ } ++ ++ for (i = 0; i < n; i++) { ++ if (owner_uid == (*uids)[i]) ++ return n; ++ } ++ ++ ret = realloc(*uids, (n + 1) * sizeof(uid_t)); ++ if (!ret) { ++ free(*uids); ++ return -1; ++ } ++ ret[n] = owner_uid; ++ *uids = ret; ++ return n+1; ++} ++ ++int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type) ++{ ++ const struct subordinate_range *range; ++ struct commonio_db *db; ++ int n = 0; ++ ++ *uids = NULL; ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ ++ commonio_rewind(db); ++ while ((range = commonio_next(db)) != NULL) { ++ if (id >= range->start && id < range->start + range-> count) { ++ n = append_uids(uids, range->owner, n); ++ if (n < 0) ++ break; ++ } ++ } ++ ++ return n; ++} ++ ++bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse) ++{ ++ struct commonio_db *db; ++ const struct subordinate_range *r; ++ ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ commonio_rewind(db); ++ if (reuse) { ++ while ((r = commonio_next(db)) != NULL) { ++ // TODO account for username vs uid_t ++ if (0 != strcmp(r->owner, range->owner)) ++ continue; ++ if (r->count >= range->count) { ++ range->count = r->count; ++ range->start = r->start; ++ return true; ++ } ++ } ++ } ++ ++ range->start = find_free_range(db, range->start, ULONG_MAX, range->count); ++ if (range->start == ULONG_MAX) ++ return false; ++ ++ return add_range(db, range->owner, range->start, range->count) == 1; ++} ++ ++bool release_subid_range(struct subordinate_range *range, enum subid_type id_type) ++{ ++ struct commonio_db *db; ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ return remove_range(db, range->owner, range->start, range->count) == 1; ++} ++ + #else /* !ENABLE_SUBIDS */ + extern int errno; /* warning: ANSI C forbids an empty source file */ + #endif /* !ENABLE_SUBIDS */ +diff -up shadow-4.6/lib/subordinateio.h.libsubid_creation shadow-4.6/lib/subordinateio.h +--- shadow-4.6/lib/subordinateio.h.libsubid_creation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/subordinateio.h 2021-10-19 16:12:02.661748243 +0200 +@@ -11,6 +11,8 @@ + + #include + ++#include "../libsubid/subid.h" ++ + extern int sub_uid_close(void); + extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count); + extern bool sub_uid_file_present (void); +@@ -23,6 +25,11 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); ++extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type); ++extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); ++extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); ++extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type); ++extern void free_subordinate_ranges(struct subordinate_range **ranges); + + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); +diff -up shadow-4.6/Makefile.am.libsubid_creation shadow-4.6/Makefile.am +--- shadow-4.6/Makefile.am.libsubid_creation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/Makefile.am 2021-10-19 16:12:02.660748228 +0200 +@@ -2,5 +2,14 @@ + + EXTRA_DIST = NEWS README TODO shadow.spec.in + +-SUBDIRS = po man libmisc lib src \ +- contrib doc etc ++SUBDIRS = libmisc lib ++ ++if ENABLE_SUBIDS ++SUBDIRS += libsubid ++endif ++ ++SUBDIRS += src po contrib doc etc ++ ++if ENABLE_REGENERATE_MAN ++SUBDIRS += man ++endif +diff -up shadow-4.6/src/free_subid_range.c.libsubid_creation shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/free_subid_range.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,50 @@ ++#include ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++/* Test program for the subid freeing routine */ ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user start count\n", Prog); ++ fprintf(stderr, " Release a user's subuid (or with -g, subgid) range\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c; ++ bool ok; ++ struct subordinate_range range; ++ bool group = false; // get subuids by default ++ ++ Prog = Basename (argv[0]); ++ while ((c = getopt(argc, argv, "g")) != EOF) { ++ switch(c) { ++ case 'g': group = true; break; ++ default: usage(); ++ } ++ } ++ argv = &argv[optind]; ++ argc = argc - optind; ++ if (argc < 3) ++ usage(); ++ range.owner = argv[0]; ++ range.start = atoi(argv[1]); ++ range.count = atoi(argv[2]); ++ if (group) ++ ok = free_subgid_range(&range); ++ else ++ ok = free_subuid_range(&range); ++ ++ if (!ok) { ++ fprintf(stderr, "Failed freeing id range\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ return 0; ++} +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_creation shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/get_subid_owners.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,40 @@ ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: [-g] %s subuid\n", Prog); ++ fprintf(stderr, " list uids who own the given subuid\n"); ++ fprintf(stderr, " pass -g to query a subgid\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i, n; ++ uid_t *uids; ++ ++ Prog = Basename (argv[0]); ++ if (argc < 2) { ++ usage(); ++ } ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) ++ n = get_subgid_owners(atoi(argv[2]), &uids); ++ else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ usage(); ++ else ++ n = get_subuid_owners(atoi(argv[1]), &uids); ++ if (n < 0) { ++ fprintf(stderr, "No owners found\n"); ++ exit(1); ++ } ++ for (i = 0; i < n; i++) { ++ printf("%d\n", uids[i]); ++ } ++ free(uids); ++ return 0; ++} +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_creation shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/list_subid_ranges.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,41 @@ ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user\n", Prog); ++ fprintf(stderr, " list subuid ranges for user\n"); ++ fprintf(stderr, " pass -g to list subgid ranges\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i; ++ struct subordinate_range **ranges; ++ ++ Prog = Basename (argv[0]); ++ if (argc < 2) { ++ usage(); ++ } ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) ++ ranges = get_subgid_ranges(argv[2]); ++ else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ usage(); ++ else ++ ranges = get_subuid_ranges(argv[1]); ++ if (!ranges) { ++ fprintf(stderr, "Error fetching ranges\n"); ++ exit(1); ++ } ++ for (i = 0; ranges[i]; i++) { ++ printf("%d: %s %lu %lu\n", i, ranges[i]->owner, ++ ranges[i]->start, ranges[i]->count); ++ } ++ subid_free_ranges(ranges); ++ return 0; ++} +diff -up shadow-4.6/src/new_subid_range.c.libsubid_creation shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/new_subid_range.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,57 @@ ++#include ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++/* Test program for the subid creation routine */ ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] [-n] user count\n", Prog); ++ fprintf(stderr, " Find a subuid (or with -g, subgid) range for user\n"); ++ fprintf(stderr, " If -n is given, a new range will be created even if one exists\n"); ++ fprintf(stderr, " count defaults to 65536\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c; ++ struct subordinate_range range; ++ bool makenew = false; // reuse existing by default ++ bool group = false; // get subuids by default ++ bool ok; ++ ++ Prog = Basename (argv[0]); ++ while ((c = getopt(argc, argv, "gn")) != EOF) { ++ switch(c) { ++ case 'n': makenew = true; break; ++ case 'g': group = true; break; ++ default: usage(); ++ } ++ } ++ argv = &argv[optind]; ++ argc = argc - optind; ++ if (argc == 0) ++ usage(); ++ range.owner = argv[0]; ++ range.start = 0; ++ range.count = 65536; ++ if (argc > 1) ++ range.count = atoi(argv[1]); ++ if (group) ++ ok = grant_subgid_range(&range, !makenew); ++ else ++ ok = grant_subuid_range(&range, !makenew); ++ ++ if (!ok) { ++ fprintf(stderr, "Failed creating new id range\n"); ++ exit(EXIT_FAILURE); ++ } ++ printf("Subuid range %lu:%lu\n", range.start, range.count); ++ ++ return 0; ++} +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid +--- shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid +--- shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,3 @@ ++foo:300000:10000 ++foo:400000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config.txt.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config.txt +diff -up shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test +--- shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,38 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "list_ranges shows subid ranges" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "list foo's ranges..." ++${build_path}/src/list_subid_ranges foo > /tmp/subuidlistout ++${build_path}/src/list_subid_ranges -g foo > /tmp/subgidlistout ++echo "OK" ++ ++echo -n "Check the subuid ranges..." ++[ $(wc -l /tmp/subuidlistout | awk '{ print $1 }') -eq 2 ] ++grep "0: foo 300000 10000" /tmp/subuidlistout ++grep "1: foo 400000 10000" /tmp/subuidlistout ++echo "OK" ++ ++echo -n "Check the subgid ranges..." ++[ $(wc -l /tmp/subgidlistout | awk '{ print $1 }') -eq 1 ] ++grep "0: foo 200000 10000" /tmp/subgidlistout ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,20 @@ ++root:x:0:0:root:/root:/bin/bash ++daemon:x:1:1:daemon:/usr/sbin:/bin/sh ++bin:x:2:2:bin:/bin:/bin/sh ++sys:x:3:3:sys:/dev:/bin/sh ++sync:x:4:65534:sync:/bin:/bin/sync ++games:x:5:60:games:/usr/games:/bin/sh ++man:x:6:12:man:/var/cache/man:/bin/sh ++lp:x:7:7:lp:/var/spool/lpd:/bin/sh ++mail:x:8:8:mail:/var/mail:/bin/sh ++news:x:9:9:news:/var/spool/news:/bin/sh ++uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh ++proxy:x:13:13:proxy:/bin:/bin/sh ++www-data:x:33:33:www-data:/var/www:/bin/sh ++backup:x:34:34:backup:/var/backups:/bin/sh ++list:x:38:38:Mailing List Manager:/var/list:/bin/sh ++irc:x:39:39:ircd:/var/run/ircd:/bin/sh ++gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh ++nobody:x:65534:65534:nobody:/nonexistent:/bin/sh ++Debian-exim:x:102:102::/var/spool/exim4:/bin/false ++foo:x:1000:1000::/home/foo:/bin/false +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,4 @@ ++foo:300000:10000 ++foo:400000:10000 ++foo:500000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config.txt.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config.txt +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test +--- shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,52 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "get subid owners" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "Noone owns 0 as a subid..." ++[ -z "$(${build_path}/src/get_subid_owners 0)" ] ++echo "OK" ++ ++echo -n "foo owns subuid 300000..." ++[ "$(${build_path}/src/get_subid_owners 300000)" = "1000" ] ++echo "OK" ++ ++echo -n "foo owns subgid 200000..." ++[ "$(${build_path}/src/get_subid_owners -g 200000)" = "1000" ] ++echo "OK" ++ ++echo -n "Noone owns subuid 200000..." ++[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] ++echo "OK" ++ ++echo -n "Noone owns subgid 300000..." ++[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] ++echo "OK" ++ ++echo -n "Both foo and root own subuid 500000..." ++cat > /tmp/expected << EOF ++1000 ++0 ++EOF ++${build_path}/src/get_subid_owners 500000 > /tmp/actual ++diff /tmp/expected /tmp/actual ++ ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test +--- shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,59 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "add and remove subid ranges" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "Existing ranges returned when possible..." ++res=$(${build_path}/src/new_subid_range foo 500) ++echo "debug" ++echo "res is $res" ++echo "wanted Subuid range 300000:10000" ++echo "end debug" ++[ "$res" = "Subuid range 300000:10000" ] ++[ $(grep -c foo /etc/subuid) -eq 1 ] ++echo "OK" ++ ++echo -n "New range returned if requested..." ++res=$(${build_path}/src/new_subid_range foo 500 -n) ++[ "$res" = "Subuid range 310000:500" ] ++[ $(grep -c foo /etc/subuid) -eq 2 ] ++echo "OK" ++ ++echo -n "Free works..." ++res=$(${build_path}/src/free_subid_range foo 310000 500) ++[ $(grep -c foo /etc/subuid) -eq 1 ] ++echo "OK" ++ ++echo -n "Subgids work too..." ++res=$(${build_path}/src/new_subid_range -g foo 100000) ++echo "DEBUG: res is ${res}" ++[ "$res" = "Subuid range 501000:100000" ] ++echo "DEBUG: subgid is:" ++cat /etc/subgid ++[ $(grep -c foo /etc/subgid) -eq 2 ] ++ ++echo -n "Subgid free works..." ++res=$(${build_path}/src/free_subid_range -g foo 501000 100000) ++echo "DEBUG: res is ${res}" ++echo "DEBUG: subgid is:" ++cat /etc/subgid ++[ $(grep -c foo /etc/subgid) -eq 1 ] ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,20 @@ ++root:x:0:0:root:/root:/bin/bash ++daemon:x:1:1:daemon:/usr/sbin:/bin/sh ++bin:x:2:2:bin:/bin:/bin/sh ++sys:x:3:3:sys:/dev:/bin/sh ++sync:x:4:65534:sync:/bin:/bin/sync ++games:x:5:60:games:/usr/games:/bin/sh ++man:x:6:12:man:/var/cache/man:/bin/sh ++lp:x:7:7:lp:/var/spool/lpd:/bin/sh ++mail:x:8:8:mail:/var/mail:/bin/sh ++news:x:9:9:news:/var/spool/news:/bin/sh ++uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh ++proxy:x:13:13:proxy:/bin:/bin/sh ++www-data:x:33:33:www-data:/var/www:/bin/sh ++backup:x:34:34:backup:/var/backups:/bin/sh ++list:x:38:38:Mailing List Manager:/var/list:/bin/sh ++irc:x:39:39:ircd:/var/run/ircd:/bin/sh ++gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh ++nobody:x:65534:65534:nobody:/nonexistent:/bin/sh ++Debian-exim:x:102:102::/var/spool/exim4:/bin/false ++foo:x:1000:1000::/home/foo:/bin/false +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1 @@ ++foo:300000:10000 +diff -up shadow-4.6/tests/libsubid/03_add_remove/config.txt.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config.txt +diff -up shadow-4.6/tests/run_some.libsubid_creation shadow-4.6/tests/run_some +--- shadow-4.6/tests/run_some.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/run_some 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,136 @@ ++#!/bin/sh ++ ++set -e ++ ++export LC_ALL=C ++unset LANG ++unset LANGUAGE ++. common/config.sh ++ ++USE_PAM="yes" ++FAILURE_TESTS="yes" ++ ++succeeded=0 ++failed=0 ++failed_tests="" ++ ++run_test() ++{ ++ [ -f RUN_TEST.STOP ] && exit 1 ++ ++ if $1 > $1.log ++ then ++ succeeded=$((succeeded+1)) ++ echo -n "+" ++ else ++ failed=$((failed+1)) ++ failed_tests="$failed_tests $1" ++ echo -n "-" ++ fi ++ cat $1.log >> testsuite.log ++ [ -f /etc/passwd.lock ] && echo $1 /etc/passwd.lock || true ++ [ -f /etc/group.lock ] && echo $1 /etc/group.lock || true ++ [ -f /etc/shadow.lock ] && echo $1 /etc/shadow.lock || true ++ [ -f /etc/gshadow.lock ] && echo $1 /etc/gshadow.lock || true ++ if [ "$(stat -c"%G" /etc/shadow)" != "shadow" ] ++ then ++ echo $1 ++ ls -l /etc/shadow ++ chgrp shadow /etc/shadow ++ fi ++ if [ -d /nonexistent ] ++ then ++ echo $1 /nonexistent ++ rmdir /nonexistent ++ fi ++} ++ ++echo "+: test passed" ++echo "-: test failed" ++ ++# Empty the complete log. ++> testsuite.log ++ ++find ${build_path} -name "*.gcda" -delete ++run_test ./su/01/su_root.test ++run_test ./su/01/su_user.test ++find ${build_path} -name "*.gcda" -exec chmod a+rw {} \; ++run_test ./su/02/env_FOO-options_--login ++run_test ./su/02/env_FOO-options_--login_bash ++run_test ./su/02/env_FOO-options_--preserve-environment ++run_test ./su/02/env_FOO-options_--preserve-environment_bash ++run_test ./su/02/env_FOO-options_- ++run_test ./su/02/env_FOO-options_-_bash ++run_test ./su/02/env_FOO-options_-l-m ++run_test ./su/02/env_FOO-options_-l-m_bash ++run_test ./su/02/env_FOO-options_-l ++run_test ./su/02/env_FOO-options_-l_bash ++run_test ./su/02/env_FOO-options_-m_bash ++run_test ./su/02/env_FOO-options_-m ++run_test ./su/02/env_FOO-options_-p ++run_test ./su/02/env_FOO-options_-p_bash ++run_test ./su/02/env_FOO-options__bash ++run_test ./su/02/env_FOO-options_ ++run_test ./su/02/env_FOO-options_-p- ++run_test ./su/02/env_FOO-options_-p-_bash ++run_test ./su/02/env_special-options_-l-p ++run_test ./su/02/env_special-options_-l ++run_test ./su/02/env_special-options_-l-p_bash ++run_test ./su/02/env_special-options_-l_bash ++run_test ./su/02/env_special-options_-p ++run_test ./su/02/env_special-options_-p_bash ++run_test ./su/02/env_special-options_ ++run_test ./su/02/env_special-options__bash ++run_test ./su/02/env_special_root-options_-l-p ++run_test ./su/02/env_special_root-options_-l-p_bash ++run_test ./su/02/env_special_root-options_-l ++run_test ./su/02/env_special_root-options_-l_bash ++run_test ./su/02/env_special_root-options_-p ++run_test ./su/02/env_special_root-options_-p_bash ++run_test ./su/02/env_special_root-options_ ++run_test ./su/02/env_special_root-options__bash ++run_test ./su/03/su_run_command01.test ++run_test ./su/03/su_run_command02.test ++run_test ./su/03/su_run_command03.test ++run_test ./su/03/su_run_command04.test ++run_test ./su/03/su_run_command05.test ++run_test ./su/03/su_run_command06.test ++run_test ./su/03/su_run_command07.test ++run_test ./su/03/su_run_command08.test ++run_test ./su/03/su_run_command09.test ++run_test ./su/03/su_run_command10.test ++run_test ./su/03/su_run_command11.test ++run_test ./su/03/su_run_command12.test ++run_test ./su/03/su_run_command13.test ++run_test ./su/03/su_run_command14.test ++run_test ./su/03/su_run_command15.test ++run_test ./su/03/su_run_command16.test ++run_test ./su/03/su_run_command17.test ++run_test ./su/04/su_wrong_user.test ++run_test ./su/04/su_user_wrong_passwd.test ++run_test ./su/04/su_user_wrong_passwd_syslog.test ++run_test ./su/05/su_user_wrong_passwd_syslog.test ++run_test ./su/06/su_user_syslog.test ++run_test ./su/07/su_user_syslog.test ++run_test ./su/08/env_special-options_ ++run_test ./su/08/env_special_root-options_ ++run_test ./su/09/env_special-options_ ++run_test ./su/09/env_special_root-options_ ++run_test ./su/10_su_sulog_success/su.test ++run_test ./su/11_su_sulog_failure/su.test ++run_test ./su/12_su_child_failure/su.test ++run_test ./su/13_su_child_success/su.test ++run_test ./libsubid/01_list_ranges/list_ranges.test ++run_test ./libsubid/02_get_subid_owners/get_subid_owners.test ++run_test ./libsubid/03_add_remove/add_remove_subids.test ++ ++echo ++echo "$succeeded test(s) passed" ++echo "$failed test(s) failed" ++echo "log written in 'testsuite.log'" ++if [ "$failed" != "0" ] ++then ++ echo "the following tests failed:" ++ echo $failed_tests ++fi ++ +diff -up shadow-4.6/src/Makefile.am.libsubid_creation shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.bp 2021-10-19 13:13:14.132503541 +0200 ++++ shadow-4.6/src/Makefile.am 2021-10-19 13:14:40.055871030 +0200 +@@ -138,3 +138,64 @@ + chmod $(sgidperms) $(DESTDIR)$(ubindir)/$$i; \ + done + endif ++ ++if ENABLE_SUBIDS ++noinst_PROGRAMS += list_subid_ranges \ ++ get_subid_owners \ ++ new_subid_range \ ++ free_subid_range ++ ++MISCLIBS = \ ++ $(LIBAUDIT) \ ++ $(LIBSELINUX) \ ++ $(LIBSEMANAGE) \ ++ $(LIBCRYPT_NOPAM) \ ++ $(LIBSKEY) \ ++ $(LIBMD) \ ++ $(LIBCRYPT) \ ++ $(LIBTCB) ++ ++list_subid_ranges_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++list_subid_ranges_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++get_subid_owners_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++get_subid_owners_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++new_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++new_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++free_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++free_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++endif diff --git a/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch b/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch new file mode 100644 index 0000000..c0ca905 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch @@ -0,0 +1,151 @@ +diff -up shadow-4.8.1/lib/nss.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/nss.c +--- shadow-4.8.1/lib/nss.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.772741048 +0200 ++++ shadow-4.8.1/lib/nss.c 2021-05-25 09:37:14.782741188 +0200 +@@ -116,14 +116,6 @@ void nss_init(char *nsswitch_path) { + subid_nss = NULL; + goto done; + } +- subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); +- if (!subid_nss->has_any_range) { +- fprintf(shadow_logfd, "%s did not provide @has_any_range@\n", libname); +- dlclose(h); +- free(subid_nss); +- subid_nss = NULL; +- goto done; +- } + subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); + if (!subid_nss->find_subid_owners) { + fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname); +diff -up shadow-4.8.1/lib/prototypes.h.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/prototypes.h +--- shadow-4.8.1/lib/prototypes.h.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/prototypes.h 2021-05-25 09:37:14.782741188 +0200 +@@ -279,18 +279,6 @@ extern bool nss_is_initialized(); + + struct subid_nss_ops { + /* +- * nss_has_any_range: does a user own any subid range +- * +- * @owner: username +- * @idtype: subuid or subgid +- * @result: true if a subid allocation was found for @owner +- * +- * returns success if the module was able to determine an answer (true or false), +- * else an error status. +- */ +- enum subid_status (*has_any_range)(const char *owner, enum subid_type idtype, bool *result); +- +- /* + * nss_has_range: does a user own a given subid range + * + * @owner: username +diff -up shadow-4.8.1/lib/subordinateio.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/subordinateio.c +--- shadow-4.8.1/lib/subordinateio.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/subordinateio.c 2021-05-25 09:37:14.782741188 +0200 +@@ -598,19 +598,8 @@ int sub_uid_open (int mode) + return commonio_open (&subordinate_uid_db, mode); + } + +-bool sub_uid_assigned(const char *owner) ++bool local_sub_uid_assigned(const char *owner) + { +- struct subid_nss_ops *h; +- bool found; +- enum subid_status status; +- h = get_subid_nss_handle(); +- if (h) { +- status = h->has_any_range(owner, ID_TYPE_UID, &found); +- if (status == SUBID_STATUS_SUCCESS && found) +- return true; +- return false; +- } +- + return range_exists (&subordinate_uid_db, owner); + } + +@@ -720,18 +709,8 @@ bool have_sub_gids(const char *owner, gi + return have_range(&subordinate_gid_db, owner, start, count); + } + +-bool sub_gid_assigned(const char *owner) ++bool local_sub_gid_assigned(const char *owner) + { +- struct subid_nss_ops *h; +- bool found; +- enum subid_status status; +- h = get_subid_nss_handle(); +- if (h) { +- status = h->has_any_range(owner, ID_TYPE_GID, &found); +- if (status == SUBID_STATUS_SUCCESS && found) +- return true; +- return false; +- } + return range_exists (&subordinate_gid_db, owner); + } + +diff -up shadow-4.8.1/lib/subordinateio.h.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/subordinateio.h +--- shadow-4.8.1/lib/subordinateio.h.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/subordinateio.h 2021-05-25 09:37:14.782741188 +0200 +@@ -16,7 +16,7 @@ + extern int sub_uid_close(void); + extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count); + extern bool sub_uid_file_present (void); +-extern bool sub_uid_assigned(const char *owner); ++extern bool local_sub_uid_assigned(const char *owner); + extern int sub_uid_lock (void); + extern int sub_uid_setdbname (const char *filename); + extern /*@observer@*/const char *sub_uid_dbname (void); +@@ -34,7 +34,7 @@ extern void free_subordinate_ranges(stru + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); + extern bool sub_gid_file_present (void); +-extern bool sub_gid_assigned(const char *owner); ++extern bool local_sub_gid_assigned(const char *owner); + extern int sub_gid_lock (void); + extern int sub_gid_setdbname (const char *filename); + extern /*@observer@*/const char *sub_gid_dbname (void); +diff -up shadow-4.8.1/src/newusers.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/src/newusers.c +--- shadow-4.8.1/src/newusers.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.776741104 +0200 ++++ shadow-4.8.1/src/newusers.c 2021-05-25 09:37:25.955897160 +0200 +@@ -1021,6 +1021,24 @@ static void close_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++static bool want_subuids(void) ++{ ++ if (get_subid_nss_handle() != NULL) ++ return false; ++ if (getdef_ulong ("SUB_UID_COUNT", 65536) == 0) ++ return false; ++ return true; ++} ++ ++static bool want_subgids(void) ++{ ++ if (get_subid_nss_handle() != NULL) ++ return false; ++ if (getdef_ulong ("SUB_GID_COUNT", 65536) == 0) ++ return false; ++ return true; ++} ++ + int main (int argc, char **argv) + { + char buf[BUFSIZ]; +@@ -1250,7 +1268,7 @@ int main (int argc, char **argv) + /* + * Add subordinate uids if the user does not have them. + */ +- if (is_sub_uid && !sub_uid_assigned(fields[0])) { ++ if (is_sub_uid && want_subuids() && !local_sub_uid_assigned(fields[0])) { + uid_t sub_uid_start = 0; + unsigned long sub_uid_count = 0; + if (find_new_sub_uids(fields[0], &sub_uid_start, &sub_uid_count) == 0) { +@@ -1270,7 +1288,7 @@ int main (int argc, char **argv) + /* + * Add subordinate gids if the user does not have them. + */ +- if (is_sub_gid && !sub_gid_assigned(fields[0])) { ++ if (is_sub_gid && want_subgids() && !local_sub_gid_assigned(fields[0])) { + gid_t sub_gid_start = 0; + unsigned long sub_gid_count = 0; + if (find_new_sub_gids(fields[0], &sub_gid_start, &sub_gid_count) == 0) { diff --git a/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch b/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch new file mode 100644 index 0000000..820a043 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch @@ -0,0 +1,40 @@ +From b0e86b959fe5c086ffb5e7eaf3c1b1e9219411e9 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Sun, 23 May 2021 08:03:10 -0500 +Subject: [PATCH] libsubid_init: don't print messages on error + +Signed-off-by: Serge Hallyn +--- + libsubid/api.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index c4848142..b477b271 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -46,12 +46,10 @@ bool libsubid_init(const char *progname, FILE * logfd) + { + if (progname) { + progname = strdup(progname); +- if (progname) { ++ if (progname) + Prog = progname; +- } else { +- fprintf(stderr, "Out of memory"); ++ else + return false; +- } + } + + if (logfd) { +@@ -60,7 +58,6 @@ bool libsubid_init(const char *progname, FILE * logfd) + } + shadow_logfd = fopen("/dev/null", "w"); + if (!shadow_logfd) { +- fprintf(stderr, "ERROR opening /dev/null for error messages. Using stderr."); + shadow_logfd = stderr; + return false; + } +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-libsubid_init_return_false.patch b/SOURCES/shadow-4.6-libsubid_init_return_false.patch new file mode 100644 index 0000000..4d02d0d --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_init_return_false.patch @@ -0,0 +1,37 @@ +From e34f49c1966fcaa9390a544a0136ec189a3c870e Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Mon, 17 May 2021 08:48:03 -0500 +Subject: [PATCH] libsubid_init: return false if out of memory + +The rest of the run isn't likely to get much better, is it? + +Thanks to Alexey for pointing this out. + +Signed-off-by: Serge Hallyn +Cc: Alexey Tikhonov +--- + libsubid/api.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index 8ca09859..8618e500 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -46,10 +46,12 @@ bool libsubid_init(const char *progname, FILE * logfd) + { + if (progname) { + progname = strdup(progname); +- if (progname) ++ if (progname) { + Prog = progname; +- else ++ } else { + fprintf(stderr, "Out of memory"); ++ return false; ++ } + } + + if (logfd) { +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch b/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch new file mode 100644 index 0000000..2994442 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch @@ -0,0 +1,41 @@ +From 1d767fb779d7b203ad609540d1dc605cf62d1050 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Fri, 28 May 2021 22:02:16 -0500 +Subject: [PATCH] libsubid/api.c: make shadow_logfd not extern + +Closes #346 + +Also #include stdio.h + +Signed-off-by: Serge Hallyn +--- + libsubid/api.c | 2 +- + libsubid/subid.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index b477b271..a7b904d0 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -40,7 +40,7 @@ + #include "subid.h" + + const char *Prog = "(libsubid)"; +-extern FILE * shadow_logfd; ++FILE *shadow_logfd; + + bool libsubid_init(const char *progname, FILE * logfd) + { +diff --git a/libsubid/subid.h b/libsubid/subid.h +index 5fef2572..eabafe4d 100644 +--- a/libsubid/subid.h ++++ b/libsubid/subid.h +@@ -1,4 +1,5 @@ + #include ++#include + #include + + #ifndef SUBID_RANGE_DEFINED +-- +2.31.1 + diff --git a/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch b/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch new file mode 100644 index 0000000..2d4faa3 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch @@ -0,0 +1,2382 @@ +diff -up shadow-4.6/lib/commonio.c.libsubid_not_print_error_messages shadow-4.6/lib/commonio.c +--- shadow-4.6/lib/commonio.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.668172672 +0100 ++++ shadow-4.6/lib/commonio.c 2021-11-03 09:28:20.444277611 +0100 +@@ -147,7 +147,7 @@ static int do_lock_file (const char *fil + fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (-1 == fd) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, file, strerror (errno)); + } +@@ -159,7 +159,7 @@ static int do_lock_file (const char *fil + len = (ssize_t) strlen (buf) + 1; + if (write (fd, buf, (size_t) len) != len) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, file, strerror (errno)); + } +@@ -172,7 +172,7 @@ static int do_lock_file (const char *fil + if (link (file, lock) == 0) { + retval = check_link_count (file); + if ((0==retval) && log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: lock file already used\n", + Prog, file); + } +@@ -183,7 +183,7 @@ static int do_lock_file (const char *fil + fd = open (lock, O_RDWR); + if (-1 == fd) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -195,7 +195,7 @@ static int do_lock_file (const char *fil + close (fd); + if (len <= 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: existing lock file %s without a PID\n", + Prog, lock); + } +@@ -206,7 +206,7 @@ static int do_lock_file (const char *fil + buf[len] = '\0'; + if (get_pid (buf, &pid) == 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: existing lock file %s with an invalid PID '%s'\n", + Prog, lock, buf); + } +@@ -216,7 +216,7 @@ static int do_lock_file (const char *fil + } + if (kill (pid, 0) == 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: lock %s already used by PID %lu\n", + Prog, lock, (unsigned long) pid); + } +@@ -226,7 +226,7 @@ static int do_lock_file (const char *fil + } + if (unlink (lock) != 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: cannot get lock %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -238,13 +238,13 @@ static int do_lock_file (const char *fil + if (link (file, lock) == 0) { + retval = check_link_count (file); + if ((0==retval) && log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: lock file already used\n", + Prog, file); + } + } else { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: cannot get lock %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -435,7 +435,7 @@ int commonio_lock (struct commonio_db *d + if (0 == lock_count) { + if (lckpwdf () == -1) { + if (geteuid () != 0) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: Permission denied.\n", + Prog); + } +@@ -471,7 +471,7 @@ int commonio_lock (struct commonio_db *d + } + /* no unnecessary retries on "permission denied" errors */ + if (geteuid () != 0) { +- (void) fprintf (stderr, "%s: Permission denied.\n", ++ (void) fprintf (shadow_logfd, "%s: Permission denied.\n", + Prog); + return 0; + } +@@ -1101,7 +1101,7 @@ int commonio_update (struct commonio_db + p = find_entry_by_name (db, db->ops->getname (eptr)); + if (NULL != p) { + if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) { +- fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename); ++ fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename); + db->ops->free (nentry); + return 0; + } +@@ -1206,7 +1206,7 @@ int commonio_remove (struct commonio_db + return 0; + } + if (next_entry_by_name (db, p->next, name) != NULL) { +- fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename); ++ fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename); + return 0; + } + +diff -up shadow-4.6/lib/encrypt.c.libsubid_not_print_error_messages shadow-4.6/lib/encrypt.c +--- shadow-4.6/lib/encrypt.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/encrypt.c 2021-11-03 09:24:05.681172775 +0100 +@@ -78,7 +78,7 @@ + method = &nummethod[0]; + } + } +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("crypt method not supported by libcrypt? (%s)\n"), + method); + exit (EXIT_FAILURE); +diff -up shadow-4.6/lib/getdef.c.libsubid_not_print_error_messages shadow-4.6/lib/getdef.c +--- shadow-4.6/lib/getdef.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.670172687 +0100 ++++ shadow-4.6/lib/getdef.c 2021-11-03 09:24:05.681172775 +0100 +@@ -233,7 +233,7 @@ int getdef_num (const char *item, int df + if ( (getlong (d->value, &val) == 0) + || (val > INT_MAX) + || (val < INT_MIN)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -268,7 +268,7 @@ unsigned int getdef_unum (const char *it + if ( (getlong (d->value, &val) == 0) + || (val < 0) + || (val > INT_MAX)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -301,7 +301,7 @@ long getdef_long (const char *item, long + } + + if (getlong (d->value, &val) == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -334,7 +334,7 @@ unsigned long getdef_ulong (const char * + + if (getulong (d->value, &val) == 0) { + /* FIXME: we should have a getulong */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -372,7 +372,7 @@ int putdef_str (const char *name, const + cp = strdup (value); + if (NULL == cp) { + (void) fputs (_("Could not allocate space for config info.\n"), +- stderr); ++ shadow_logfd); + SYSLOG ((LOG_ERR, "could not allocate space for config info")); + return -1; + } +@@ -417,7 +417,7 @@ static /*@observer@*/ /*@null@*/struct i + goto out; + } + } +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - unknown item '%s' (notify administrator)\n"), + name); + SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name)); +diff -up shadow-4.6/libmisc/addgrps.c.libsubid_not_print_error_messages shadow-4.6/libmisc/addgrps.c +--- shadow-4.6/libmisc/addgrps.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/addgrps.c 2021-11-03 09:24:05.681172775 +0100 +@@ -93,7 +93,7 @@ int add_groups (const char *list) + + grp = getgrnam (token); /* local, no need for xgetgrnam */ + if (NULL == grp) { +- fprintf (stderr, _("Warning: unknown group %s\n"), ++ fprintf (shadow_logfd, _("Warning: unknown group %s\n"), + token); + continue; + } +@@ -105,7 +105,7 @@ int add_groups (const char *list) + } + + if (ngroups >= sysconf (_SC_NGROUPS_MAX)) { +- fputs (_("Warning: too many groups\n"), stderr); ++ fputs (_("Warning: too many groups\n"), shadow_logfd); + break; + } + tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T)); +diff -up shadow-4.6/libmisc/audit_help.c.libsubid_not_print_error_messages shadow-4.6/libmisc/audit_help.c +--- shadow-4.6/libmisc/audit_help.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/audit_help.c 2021-11-03 09:24:05.681172775 +0100 +@@ -59,7 +59,7 @@ void audit_help_open (void) + return; + } + (void) fputs (_("Cannot open audit interface - aborting.\n"), +- stderr); ++ shadow_logfd); + exit (EXIT_FAILURE); + } + } +diff -up shadow-4.6/libmisc/chowntty.c.libsubid_not_print_error_messages shadow-4.6/libmisc/chowntty.c +--- shadow-4.6/libmisc/chowntty.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/chowntty.c 2021-11-03 09:24:05.681172775 +0100 +@@ -75,7 +75,7 @@ void chown_tty (const struct passwd *inf + || (fchmod (STDIN_FILENO, (mode_t)getdef_num ("TTYPERM", 0600)) != 0)) { + int err = errno; + +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Unable to change owner or mode of tty stdin: %s"), + strerror (err)); + SYSLOG ((LOG_WARN, +diff -up shadow-4.6/libmisc/cleanup_group.c.libsubid_not_print_error_messages shadow-4.6/libmisc/cleanup_group.c +--- shadow-4.6/libmisc/cleanup_group.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/cleanup_group.c 2021-11-03 09:24:05.681172775 +0100 +@@ -203,7 +203,7 @@ void cleanup_report_del_group_gshadow (v + void cleanup_unlock_group (unused void *arg) + { + if (gr_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, gr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); +@@ -223,7 +223,7 @@ void cleanup_unlock_group (unused void * + void cleanup_unlock_gshadow (unused void *arg) + { + if (sgr_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, sgr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); +diff -up shadow-4.6/libmisc/cleanup_user.c.libsubid_not_print_error_messages shadow-4.6/libmisc/cleanup_user.c +--- shadow-4.6/libmisc/cleanup_user.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/cleanup_user.c 2021-11-03 09:24:05.682172783 +0100 +@@ -120,7 +120,7 @@ void cleanup_report_add_user_shadow (voi + void cleanup_unlock_passwd (unused void *arg) + { + if (pw_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, pw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); +@@ -139,7 +139,7 @@ void cleanup_unlock_passwd (unused void + void cleanup_unlock_shadow (unused void *arg) + { + if (spw_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, spw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); +diff -up shadow-4.6/libmisc/copydir.c.libsubid_not_print_error_messages shadow-4.6/libmisc/copydir.c +--- shadow-4.6/libmisc/copydir.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.642172465 +0100 ++++ shadow-4.6/libmisc/copydir.c 2021-11-03 09:24:05.682172783 +0100 +@@ -125,11 +125,11 @@ static void error_acl (struct error_cont + } + + va_start (ap, fmt); +- (void) fprintf (stderr, _("%s: "), Prog); +- if (vfprintf (stderr, fmt, ap) != 0) { +- (void) fputs (_(": "), stderr); ++ (void) fprintf (shadow_logfd, _("%s: "), Prog); ++ if (vfprintf (shadow_logfd, fmt, ap) != 0) { ++ (void) fputs (_(": "), shadow_logfd); + } +- (void) fprintf (stderr, "%s\n", strerror (errno)); ++ (void) fprintf (shadow_logfd, "%s\n", strerror (errno)); + va_end (ap); + } + +@@ -248,7 +248,7 @@ int copy_tree (const char *src_root, con + } + + if (!S_ISDIR (sb.st_mode)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + "%s: %s is not a directory", + Prog, src_root); + return -1; +diff -up shadow-4.6/libmisc/env.c.libsubid_not_print_error_messages shadow-4.6/libmisc/env.c +--- shadow-4.6/libmisc/env.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/env.c 2021-11-03 09:24:05.682172783 +0100 +@@ -171,7 +171,7 @@ void addenv (const char *string, /*@null + } + newenvp = __newenvp; + } else { +- (void) fputs (_("Environment overflow\n"), stderr); ++ (void) fputs (_("Environment overflow\n"), shadow_logfd); + newenvc--; + free (newenvp[newenvc]); + } +diff -up shadow-4.6/libmisc/find_new_gid.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_gid.c +--- shadow-4.6/libmisc/find_new_gid.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.665172648 +0100 ++++ shadow-4.6/libmisc/find_new_gid.c 2021-11-03 09:24:05.682172783 +0100 +@@ -74,7 +74,7 @@ static int get_ranges (bool sys_group, g + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SYS_GID_MIN (%lu), " + "GID_MIN (%lu), SYS_GID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -104,7 +104,7 @@ static int get_ranges (bool sys_group, g + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: GID_MIN (%lu), " + "GID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -220,7 +220,7 @@ int find_new_gid (bool sys_group, + * more likely to want to stop and address the + * issue. + */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Encountered error attempting to use " + "preferred GID: %s\n"), + Prog, strerror (result)); +@@ -250,7 +250,7 @@ int find_new_gid (bool sys_group, + /* Create an array to hold all of the discovered GIDs */ + used_gids = malloc (sizeof (bool) * (gid_max +1)); + if (NULL == used_gids) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + return -1; +@@ -330,7 +330,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -373,7 +373,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -433,7 +433,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -476,7 +476,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -495,7 +495,7 @@ int find_new_gid (bool sys_group, + } + + /* The code reached here and found no available IDs in the range */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (no more available GIDs)\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available GIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_sub_gids.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_sub_gids.c +--- shadow-4.6/libmisc/find_new_sub_gids.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/find_new_sub_gids.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,7 +61,7 @@ int find_new_sub_gids (const char *owner + count = getdef_ulong ("SUB_GID_COUNT", 65536); + + if (min > max || count >= max || (min + count - 1) > max) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SUB_GID_MIN (%lu)," + " SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"), + Prog, min, max, count); +@@ -70,7 +70,7 @@ int find_new_sub_gids (const char *owner + + start = sub_gid_find_free_range(min, max, count); + if (start == (gid_t)-1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique subordinate GID range\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available subordinate GIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_sub_uids.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_sub_uids.c +--- shadow-4.6/libmisc/find_new_sub_uids.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/find_new_sub_uids.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,7 +61,7 @@ int find_new_sub_uids (const char *owner + count = getdef_ulong ("SUB_UID_COUNT", 65536); + + if (min > max || count >= max || (min + count - 1) > max) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SUB_UID_MIN (%lu)," + " SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"), + Prog, min, max, count); +@@ -70,7 +70,7 @@ int find_new_sub_uids (const char *owner + + start = sub_uid_find_free_range(min, max, count); + if (start == (uid_t)-1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique subordinate UID range\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available subordinate UIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_uid.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_uid.c +--- shadow-4.6/libmisc/find_new_uid.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.665172648 +0100 ++++ shadow-4.6/libmisc/find_new_uid.c 2021-11-03 09:24:05.682172783 +0100 +@@ -74,7 +74,7 @@ static int get_ranges (bool sys_user, ui + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SYS_UID_MIN (%lu), " + "UID_MIN (%lu), SYS_UID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -104,7 +104,7 @@ static int get_ranges (bool sys_user, ui + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: UID_MIN (%lu), " + "UID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -220,7 +220,7 @@ int find_new_uid(bool sys_user, + * more likely to want to stop and address the + * issue. + */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Encountered error attempting to use " + "preferred UID: %s\n"), + Prog, strerror (result)); +@@ -250,7 +250,7 @@ int find_new_uid(bool sys_user, + /* Create an array to hold all of the discovered UIDs */ + used_uids = malloc (sizeof (bool) * (uid_max +1)); + if (NULL == used_uids) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + return -1; +@@ -330,7 +330,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -373,7 +373,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -433,7 +433,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -476,7 +476,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -495,7 +495,7 @@ int find_new_uid(bool sys_user, + } + + /* The code reached here and found no available IDs in the range */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (no more available UIDs)\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available UIDs on the system")); +diff -up shadow-4.6/libmisc/gettime.c.libsubid_not_print_error_messages shadow-4.6/libmisc/gettime.c +--- shadow-4.6/libmisc/gettime.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/gettime.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,23 +61,23 @@ + epoch = strtoull (source_date_epoch, &endptr, 10); + if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) + || (errno != 0 && epoch == 0)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"), + strerror(errno)); + } else if (endptr == source_date_epoch) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"), + endptr); + } else if (*endptr != '\0') { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"), + endptr); + } else if (epoch > ULONG_MAX) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu\n"), + ULONG_MAX, epoch); + } else if (epoch > fallback) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to the current time (%lu) but was found to be: %llu\n"), + fallback, epoch); + } else { +diff -up shadow-4.6/libmisc/idmapping.c.libsubid_not_print_error_messages shadow-4.6/libmisc/idmapping.c +--- shadow-4.6/libmisc/idmapping.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/idmapping.c 2021-11-03 09:24:05.682172783 +0100 +@@ -43,19 +43,19 @@ struct map_range *get_map_ranges(int ran + int idx, argidx; + + if (ranges < 0 || argc < 0) { +- fprintf(stderr, "%s: error calculating number of arguments\n", Prog); ++ fprintf(shadow_logfd, "%s: error calculating number of arguments\n", Prog); + return NULL; + } + + if (ranges != ((argc + 2) / 3)) { +- fprintf(stderr, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc); ++ fprintf(shadow_logfd, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc); + return NULL; + } + + if ((ranges * 3) > argc) { +- fprintf(stderr, "ranges: %u argc: %d\n", ++ fprintf(shadow_logfd, "ranges: %u argc: %d\n", + ranges, argc); +- fprintf(stderr, ++ fprintf(shadow_logfd, + _( "%s: Not enough arguments to form %u mappings\n"), + Prog, ranges); + return NULL; +@@ -63,7 +63,7 @@ struct map_range *get_map_ranges(int ran + + mappings = calloc(ranges, sizeof(*mappings)); + if (!mappings) { +- fprintf(stderr, _( "%s: Memory allocation failure\n"), ++ fprintf(shadow_logfd, _( "%s: Memory allocation failure\n"), + Prog); + exit(EXIT_FAILURE); + } +@@ -84,24 +84,24 @@ struct map_range *get_map_ranges(int ran + return NULL; + } + if (ULONG_MAX - mapping->upper <= mapping->count || ULONG_MAX - mapping->lower <= mapping->count) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->upper > UINT_MAX || + mapping->lower > UINT_MAX || + mapping->count > UINT_MAX) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->lower + mapping->count > UINT_MAX || + mapping->upper + mapping->count > UINT_MAX) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->lower + mapping->count < mapping->lower || + mapping->upper + mapping->count < mapping->upper) { + /* this one really shouldn't be possible given previous checks */ +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + } +@@ -142,7 +142,7 @@ void write_mapping(int proc_dir_fd, int + mapping->lower, + mapping->count); + if ((written <= 0) || (written >= (bufsize - (pos - buf)))) { +- fprintf(stderr, _("%s: snprintf failed!\n"), Prog); ++ fprintf(shadow_logfd, _("%s: snprintf failed!\n"), Prog); + exit(EXIT_FAILURE); + } + pos += written; +@@ -151,12 +151,12 @@ void write_mapping(int proc_dir_fd, int + /* Write the mapping to the mapping file */ + fd = openat(proc_dir_fd, map_file, O_WRONLY); + if (fd < 0) { +- fprintf(stderr, _("%s: open of %s failed: %s\n"), ++ fprintf(shadow_logfd, _("%s: open of %s failed: %s\n"), + Prog, map_file, strerror(errno)); + exit(EXIT_FAILURE); + } + if (write(fd, buf, pos - buf) != (pos - buf)) { +- fprintf(stderr, _("%s: write to %s failed: %s\n"), ++ fprintf(shadow_logfd, _("%s: write to %s failed: %s\n"), + Prog, map_file, strerror(errno)); + exit(EXIT_FAILURE); + } +diff -up shadow-4.6/libmisc/limits.c.libsubid_not_print_error_messages shadow-4.6/libmisc/limits.c +--- shadow-4.6/libmisc/limits.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/limits.c 2021-11-03 09:24:05.682172783 +0100 +@@ -548,7 +548,7 @@ void setup_limits (const struct passwd * + #ifdef LIMITS + if (info->pw_uid != 0) { + if ((setup_user_limits (info->pw_name) & LOGIN_ERROR_LOGIN) != 0) { +- (void) fputs (_("Too many logins.\n"), stderr); ++ (void) fputs (_("Too many logins.\n"), shadow_logfd); + (void) sleep (2); /* XXX: Should be FAIL_DELAY */ + exit (EXIT_FAILURE); + } +diff -up shadow-4.6/libmisc/pam_pass.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pam_pass.c +--- shadow-4.6/libmisc/pam_pass.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pam_pass.c 2021-11-03 09:24:05.682172783 +0100 +@@ -59,20 +59,20 @@ void do_pam_passwd (const char *user, bo + + ret = pam_start ("passwd", user, &conv, &pamh); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("passwd: pam_start() failed, error %d\n"), ret); + exit (10); /* XXX */ + } + + ret = pam_chauthtok (pamh, flags); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, _("passwd: %s\n"), pam_strerror (pamh, ret)); +- fputs (_("passwd: password unchanged\n"), stderr); ++ fprintf (shadow_logfd, _("passwd: %s\n"), pam_strerror (pamh, ret)); ++ fputs (_("passwd: password unchanged\n"), shadow_logfd); + pam_end (pamh, ret); + exit (10); /* XXX */ + } + +- fputs (_("passwd: password updated successfully\n"), stderr); ++ fputs (_("passwd: password updated successfully\n"), shadow_logfd); + (void) pam_end (pamh, PAM_SUCCESS); + } + #else /* !USE_PAM */ +diff -up shadow-4.6/libmisc/pam_pass_non_interactive.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pam_pass_non_interactive.c +--- shadow-4.6/libmisc/pam_pass_non_interactive.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pam_pass_non_interactive.c 2021-11-03 09:24:05.683172791 +0100 +@@ -76,7 +76,7 @@ static int ni_conv (int num_msg, + + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: PAM modules requesting echoing are not supported.\n"), + Prog); + goto failed_conversation; +@@ -88,7 +88,7 @@ static int ni_conv (int num_msg, + break; + case PAM_ERROR_MSG: + if ( (NULL == msg[count]->msg) +- || (fprintf (stderr, "%s\n", msg[count]->msg) <0)) { ++ || (fprintf (shadow_logfd, "%s\n", msg[count]->msg) <0)) { + goto failed_conversation; + } + responses[count].resp = NULL; +@@ -101,7 +101,7 @@ static int ni_conv (int num_msg, + responses[count].resp = NULL; + break; + default: +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: conversation type %d not supported.\n"), + Prog, msg[count]->msg_style); + goto failed_conversation; +@@ -143,7 +143,7 @@ int do_pam_passwd_non_interactive (const + + ret = pam_start (pam_service, username, &non_interactive_pam_conv, &pamh); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: (user %s) pam_start failure %d\n"), + Prog, username, ret); + return 1; +@@ -152,7 +152,7 @@ int do_pam_passwd_non_interactive (const + non_interactive_password = password; + ret = pam_chauthtok (pamh, 0); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: (user %s) pam_chauthtok() failed, error:\n" + "%s\n"), + Prog, username, pam_strerror (pamh, ret)); +diff -up shadow-4.6/libmisc/prefix_flag.c.libsubid_not_print_error_messages shadow-4.6/libmisc/prefix_flag.c +--- shadow-4.6/libmisc/prefix_flag.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.658172592 +0100 ++++ shadow-4.6/libmisc/prefix_flag.c 2021-11-03 09:24:05.683172791 +0100 +@@ -80,14 +80,14 @@ extern const char* process_prefix_flag ( + if ( (strcmp (argv[i], "--prefix") == 0) + || (strcmp (argv[i], short_opt) == 0)) { + if (NULL != prefix) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: multiple --prefix options\n"), + Prog); + exit (E_BAD_ARG); + } + + if (i + 1 == argc) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: option '%s' requires an argument\n"), + Prog, argv[i]); + exit (E_BAD_ARG); +diff -up shadow-4.6/libmisc/pwdcheck.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pwdcheck.c +--- shadow-4.6/libmisc/pwdcheck.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pwdcheck.c 2021-11-03 09:24:05.683172791 +0100 +@@ -51,7 +51,7 @@ void passwd_check (const char *user, con + if (pw_auth (passwd, user, PW_LOGIN, (char *) 0) != 0) { + SYSLOG ((LOG_WARN, "incorrect password for `%s'", user)); + (void) sleep (1); +- fprintf (stderr, _("Incorrect password for %s.\n"), user); ++ fprintf (shadow_logfd, _("Incorrect password for %s.\n"), user); + exit (EXIT_FAILURE); + } + } +diff -up shadow-4.6/libmisc/root_flag.c.libsubid_not_print_error_messages shadow-4.6/libmisc/root_flag.c +--- shadow-4.6/libmisc/root_flag.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/root_flag.c 2021-11-03 09:24:05.683172791 +0100 +@@ -62,14 +62,14 @@ extern void process_root_flag (const cha + if ( (strcmp (argv[i], "--root") == 0) + || (strcmp (argv[i], short_opt) == 0)) { + if (NULL != newroot) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: multiple --root options\n"), + Prog); + exit (E_BAD_ARG); + } + + if (i + 1 == argc) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: option '%s' requires an argument\n"), + Prog, argv[i]); + exit (E_BAD_ARG); +@@ -88,34 +88,34 @@ static void change_root (const char* new + /* Drop privileges */ + if ( (setregid (getgid (), getgid ()) != 0) + || (setreuid (getuid (), getuid ()) != 0)) { +- fprintf (stderr, _("%s: failed to drop privileges (%s)\n"), ++ fprintf (shadow_logfd, _("%s: failed to drop privileges (%s)\n"), + Prog, strerror (errno)); + exit (EXIT_FAILURE); + } + + if ('/' != newroot[0]) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: invalid chroot path '%s'\n"), + Prog, newroot); + exit (E_BAD_ARG); + } + + if (access (newroot, F_OK) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: cannot access chroot directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); + } + + if (chdir (newroot) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: cannot chdir to chroot directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); + } + + if (chroot (newroot) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: unable to chroot to directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); +diff -up shadow-4.6/libmisc/salt.c.libsubid_not_print_error_messages shadow-4.6/libmisc/salt.c +--- shadow-4.6/libmisc/salt.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/salt.c 2021-11-03 09:24:05.683172791 +0100 +@@ -241,7 +241,7 @@ static /*@observer@*/const char *gensalt + salt_len = (size_t) shadow_random (8, 16); + #endif /* USE_SHA_CRYPT */ + } else if (0 != strcmp (method, "DES")) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Invalid ENCRYPT_METHOD value: '%s'.\n" + "Defaulting to DES.\n"), + method); +diff -up shadow-4.6/libmisc/setupenv.c.libsubid_not_print_error_messages shadow-4.6/libmisc/setupenv.c +--- shadow-4.6/libmisc/setupenv.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/setupenv.c 2021-11-03 09:24:05.683172791 +0100 +@@ -219,7 +219,7 @@ void setup_env (struct passwd *info) + static char temp_pw_dir[] = "/"; + + if (!getdef_bool ("DEFAULT_HOME") || chdir ("/") == -1) { +- fprintf (stderr, _("Unable to cd to '%s'\n"), ++ fprintf (shadow_logfd, _("Unable to cd to '%s'\n"), + info->pw_dir); + SYSLOG ((LOG_WARN, + "unable to cd to `%s' for user `%s'\n", +diff -up shadow-4.6/libmisc/user_busy.c.libsubid_not_print_error_messages shadow-4.6/libmisc/user_busy.c +--- shadow-4.6/libmisc/user_busy.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.669172680 +0100 ++++ shadow-4.6/libmisc/user_busy.c 2021-11-03 09:24:05.683172791 +0100 +@@ -96,7 +96,7 @@ static int user_busy_utmp (const char *n + continue; + } + +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently logged in\n"), + Prog, name); + return 1; +@@ -249,7 +249,7 @@ static int user_busy_processes (const ch + #ifdef ENABLE_SUBIDS + sub_uid_close(); + #endif +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently used by process %d\n"), + Prog, name, pid); + return 1; +@@ -272,7 +272,7 @@ static int user_busy_processes (const ch + #ifdef ENABLE_SUBIDS + sub_uid_close(); + #endif +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently used by process %d\n"), + Prog, name, pid); + return 1; +diff -up shadow-4.6/libmisc/xgetXXbyYY.c.libsubid_not_print_error_messages shadow-4.6/libmisc/xgetXXbyYY.c +--- shadow-4.6/libmisc/xgetXXbyYY.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/xgetXXbyYY.c 2021-11-03 09:24:05.683172791 +0100 +@@ -74,7 +74,7 @@ + + result = malloc(sizeof(LOOKUP_TYPE)); + if (NULL == result) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +@@ -84,7 +84,7 @@ + LOOKUP_TYPE *resbuf = NULL; + buffer = (char *)realloc (buffer, length); + if (NULL == buffer) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +@@ -132,7 +132,7 @@ + if (result) { + result = DUP_FUNCTION(result); + if (NULL == result) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +diff -up shadow-4.6/libmisc/xmalloc.c.libsubid_not_print_error_messages shadow-4.6/libmisc/xmalloc.c +--- shadow-4.6/libmisc/xmalloc.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/xmalloc.c 2021-11-03 09:24:05.683172791 +0100 +@@ -54,7 +54,7 @@ + + ptr = (char *) malloc (size); + if (NULL == ptr) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + exit (13); +diff -up shadow-4.6/lib/nscd.c.libsubid_not_print_error_messages shadow-4.6/lib/nscd.c +--- shadow-4.6/lib/nscd.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/nscd.c 2021-11-03 09:24:05.683172791 +0100 +@@ -25,13 +25,13 @@ int nscd_flush_cache (const char *servic + + if (run_command (cmd, spawnedArgs, spawnedEnv, &status) != 0) { + /* run_command writes its own more detailed message. */ +- (void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); ++ (void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); + return -1; + } + + code = WEXITSTATUS (status); + if (!WIFEXITED (status)) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: nscd did not terminate normally (signal %d)\n"), + Prog, WTERMSIG (status)); + return -1; +@@ -43,9 +43,9 @@ int nscd_flush_cache (const char *servic + /* nscd is installed, but it isn't active. */ + return 0; + } else if (code != 0) { +- (void) fprintf (stderr, _("%s: nscd exited with status %d\n"), ++ (void) fprintf (shadow_logfd, _("%s: nscd exited with status %d\n"), + Prog, code); +- (void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); ++ (void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); + return -1; + } + +diff -up shadow-4.6/lib/nss.c.libsubid_not_print_error_messages shadow-4.6/lib/nss.c +--- shadow-4.6/lib/nss.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/lib/nss.c 2021-11-03 09:24:05.683172791 +0100 +@@ -56,7 +56,7 @@ void nss_init(char *nsswitch_path) { + // subid: files + nssfp = fopen(nsswitch_path, "r"); + if (!nssfp) { +- fprintf(stderr, "Failed opening %s: %m", nsswitch_path); ++ fprintf(shadow_logfd, "Failed opening %s: %m", nsswitch_path); + atomic_store(&nss_init_completed, true); + return; + } +@@ -82,16 +82,16 @@ void nss_init(char *nsswitch_path) { + goto done; + } + if (strlen(token) > 50) { +- fprintf(stderr, "Subid NSS module name too long (longer than 50 characters): %s\n", token); +- fprintf(stderr, "Using files\n"); ++ fprintf(shadow_logfd, "Subid NSS module name too long (longer than 50 characters): %s\n", token); ++ fprintf(shadow_logfd, "Using files\n"); + subid_nss = NULL; + goto done; + } + snprintf(libname, 64, "libsubid_%s.so", token); + h = dlopen(libname, RTLD_LAZY); + if (!h) { +- fprintf(stderr, "Error opening %s: %s\n", libname, dlerror()); +- fprintf(stderr, "Using files\n"); ++ fprintf(shadow_logfd, "Error opening %s: %s\n", libname, dlerror()); ++ fprintf(shadow_logfd, "Using files\n"); + subid_nss = NULL; + goto done; + } +@@ -102,7 +102,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->has_range = dlsym(h, "shadow_subid_has_range"); + if (!subid_nss->has_range) { +- fprintf(stderr, "%s did not provide @has_range@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @has_range@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -110,7 +110,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); + if (!subid_nss->list_owner_ranges) { +- fprintf(stderr, "%s did not provide @list_owner_ranges@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @list_owner_ranges@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -118,7 +118,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); + if (!subid_nss->has_any_range) { +- fprintf(stderr, "%s did not provide @has_any_range@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @has_any_range@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -126,7 +126,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); + if (!subid_nss->find_subid_owners) { +- fprintf(stderr, "%s did not provide @find_subid_owners@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -135,7 +135,7 @@ void nss_init(char *nsswitch_path) { + subid_nss->handle = h; + goto done; + } +- fprintf(stderr, "No usable subid NSS module found, using files\n"); ++ fprintf(shadow_logfd, "No usable subid NSS module found, using files\n"); + // subid_nss has to be null here, but to ease reviews: + free(subid_nss); + subid_nss = NULL; +diff -up shadow-4.6/lib/prototypes.h.libsubid_not_print_error_messages shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/lib/prototypes.h 2021-11-03 09:24:05.683172791 +0100 +@@ -59,7 +59,8 @@ + #include "defines.h" + #include "commonio.h" + +-extern /*@observer@*/ const char *Prog; ++extern /*@observer@*/ const char *Prog; /* Program name showed in error messages */ ++extern FILE *shadow_logfd; /* file descripter to which error messages are printed */ + + /* addgrps.c */ + #if defined (HAVE_SETGROUPS) && ! defined (USE_PAM) +diff -up shadow-4.6/lib/selinux.c.libsubid_not_print_error_messages shadow-4.6/lib/selinux.c +diff -up shadow-4.6/lib/semanage.c.libsubid_not_print_error_messages shadow-4.6/lib/semanage.c +--- shadow-4.6/lib/semanage.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.644172481 +0100 ++++ shadow-4.6/lib/semanage.c 2021-11-03 09:24:05.691172854 +0100 +@@ -69,7 +69,7 @@ static void semanage_error_callback (unu + switch (semanage_msg_get_level (handle)) { + case SEMANAGE_MSG_ERR: + case SEMANAGE_MSG_WARN: +- fprintf (stderr, _("[libsemanage]: %s\n"), message); ++ fprintf (shadow_logfd, _("[libsemanage]: %s\n"), message); + break; + case SEMANAGE_MSG_INFO: + /* nop */ +@@ -87,7 +87,7 @@ static semanage_handle_t *semanage_init + + handle = semanage_handle_create (); + if (NULL == handle) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot create SELinux management handle\n")); + return NULL; + } +@@ -96,26 +96,26 @@ static semanage_handle_t *semanage_init + + ret = semanage_is_managed (handle); + if (ret != 1) { +- fprintf (stderr, _("SELinux policy not managed\n")); ++ fprintf (shadow_logfd, _("SELinux policy not managed\n")); + goto fail; + } + + ret = semanage_access_check (handle); + if (ret < SEMANAGE_CAN_READ) { +- fprintf (stderr, _("Cannot read SELinux policy store\n")); ++ fprintf (shadow_logfd, _("Cannot read SELinux policy store\n")); + goto fail; + } + + ret = semanage_connect (handle); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot establish SELinux management connection\n")); + goto fail; + } + + ret = semanage_begin_transaction (handle); + if (ret != 0) { +- fprintf (stderr, _("Cannot begin SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot begin SELinux transaction\n")); + goto fail; + } + +@@ -137,7 +137,7 @@ static int semanage_user_mod (semanage_h + + semanage_seuser_query (handle, key, &seuser); + if (NULL == seuser) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not query seuser for %s\n"), login_name); + ret = 1; + goto done; +@@ -146,7 +146,7 @@ static int semanage_user_mod (semanage_h + #if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set serange for %s\n"), login_name); + ret = 1; + goto done; +@@ -155,7 +155,7 @@ static int semanage_user_mod (semanage_h + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set sename for %s\n"), + login_name); + ret = 1; +@@ -164,7 +164,7 @@ static int semanage_user_mod (semanage_h + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not modify login mapping for %s\n"), + login_name); + ret = 1; +@@ -188,7 +188,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_create (handle, &seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot create SELinux login mapping for %s\n"), + login_name); + ret = 1; +@@ -197,7 +197,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_set_name (handle, seuser, login_name); + if (ret != 0) { +- fprintf (stderr, _("Could not set name for %s\n"), login_name); ++ fprintf (shadow_logfd, _("Could not set name for %s\n"), login_name); + ret = 1; + goto done; + } +@@ -205,7 +205,7 @@ static int semanage_user_add (semanage_h + #if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set serange for %s\n"), + login_name); + ret = 1; +@@ -215,7 +215,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set SELinux user for %s\n"), + login_name); + ret = 1; +@@ -224,7 +224,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not add login mapping for %s\n"), + login_name); + ret = 1; +@@ -252,21 +252,21 @@ int set_seuser (const char *login_name, + + handle = semanage_init (); + if (NULL == handle) { +- fprintf (stderr, _("Cannot init SELinux management\n")); ++ fprintf (shadow_logfd, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { +- fprintf (stderr, _("Cannot create SELinux user key\n")); ++ fprintf (shadow_logfd, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &seuser_exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } +@@ -274,7 +274,7 @@ int set_seuser (const char *login_name, + if (0 != seuser_exists) { + ret = semanage_user_mod (handle, key, login_name, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot modify SELinux user mapping\n")); + ret = 1; + goto done; +@@ -282,7 +282,7 @@ int set_seuser (const char *login_name, + } else { + ret = semanage_user_add (handle, key, login_name, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot add SELinux user mapping\n")); + ret = 1; + goto done; +@@ -291,7 +291,7 @@ int set_seuser (const char *login_name, + + ret = semanage_commit (handle); + if (ret < 0) { +- fprintf (stderr, _("Cannot commit SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } +@@ -317,27 +317,27 @@ int del_seuser (const char *login_name) + + handle = semanage_init (); + if (NULL == handle) { +- fprintf (stderr, _("Cannot init SELinux management\n")); ++ fprintf (shadow_logfd, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { +- fprintf (stderr, _("Cannot create SELinux user key\n")); ++ fprintf (shadow_logfd, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Login mapping for %s is not defined, OK if default mapping was used\n"), + login_name); + ret = 0; /* probably default mapping */ +@@ -346,13 +346,13 @@ int del_seuser (const char *login_name) + + ret = semanage_seuser_exists_local (handle, key, &exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Login mapping for %s is defined in policy, cannot be deleted\n"), + login_name); + ret = 0; /* Login mapping defined in policy can't be deleted */ +@@ -361,7 +361,7 @@ int del_seuser (const char *login_name) + + ret = semanage_seuser_del_local (handle, key); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not delete login mapping for %s"), + login_name); + ret = 1; +@@ -370,7 +370,7 @@ int del_seuser (const char *login_name) + + ret = semanage_commit (handle); + if (ret < 0) { +- fprintf (stderr, _("Cannot commit SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } +diff -up shadow-4.6/lib/spawn.c.libsubid_not_print_error_messages shadow-4.6/lib/spawn.c +--- shadow-4.6/lib/spawn.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.660172608 +0100 ++++ shadow-4.6/lib/spawn.c 2021-11-03 09:24:05.692172863 +0100 +@@ -48,7 +48,7 @@ int run_command (const char *cmd, const + } + + (void) fflush (stdout); +- (void) fflush (stderr); ++ (void) fflush (shadow_logfd); + + pid = fork (); + if (0 == pid) { +@@ -57,11 +57,11 @@ int run_command (const char *cmd, const + if (ENOENT == errno) { + exit (E_CMD_NOTFOUND); + } +- fprintf (stderr, "%s: cannot execute %s: %s\n", ++ fprintf (shadow_logfd, "%s: cannot execute %s: %s\n", + Prog, cmd, strerror (errno)); + exit (E_CMD_NOEXEC); + } else if ((pid_t)-1 == pid) { +- fprintf (stderr, "%s: cannot execute %s: %s\n", ++ fprintf (shadow_logfd, "%s: cannot execute %s: %s\n", + Prog, cmd, strerror (errno)); + return -1; + } +@@ -72,7 +72,7 @@ int run_command (const char *cmd, const + || ((pid_t)-1 != wpid && wpid != pid)); + + if ((pid_t)-1 == wpid) { +- fprintf (stderr, "%s: waitpid (status: %d): %s\n", ++ fprintf (shadow_logfd, "%s: waitpid (status: %d): %s\n", + Prog, *status, strerror (errno)); + return -1; + } +diff -up shadow-4.6/libsubid/api.c.libsubid_not_print_error_messages shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/libsubid/api.c 2021-11-03 09:24:05.692172863 +0100 +@@ -32,12 +32,39 @@ + #include + #include + #include ++#include + #include + #include + #include "subordinateio.h" + #include "idmapping.h" + #include "subid.h" + ++const char *Prog = "(libsubid)"; ++extern FILE * shadow_logfd; ++ ++bool libsubid_init(const char *progname, FILE * logfd) ++{ ++ if (progname) { ++ progname = strdup(progname); ++ if (progname) ++ Prog = progname; ++ else ++ fprintf(stderr, "Out of memory"); ++ } ++ ++ if (logfd) { ++ shadow_logfd = logfd; ++ return true; ++ } ++ shadow_logfd = fopen("/dev/null", "w"); ++ if (!shadow_logfd) { ++ fprintf(stderr, "ERROR opening /dev/null for error messages. Using stderr."); ++ shadow_logfd = stderr; ++ return false; ++ } ++ return true; ++} ++ + static + int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + { +diff -up shadow-4.6/libsubid/subid.h.libsubid_not_print_error_messages shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/libsubid/subid.h 2021-11-03 09:24:05.692172863 +0100 +@@ -22,6 +22,22 @@ enum subid_status { + }; + + /* ++ * libsubid_init: initialize libsubid ++ * ++ * @progname: Name to display as program. If NULL, then "(libsubid)" will be ++ * shown in error messages. ++ * @logfd: Open file pointer to pass error messages to. If NULL, then ++ * /dev/null will be opened and messages will be sent there. The ++ * default if libsubid_init() is not called is stderr (2). ++ * ++ * This function does not need to be called. If not called, then the defaults ++ * will be used. ++ * ++ * Returns false if an error occurred. ++ */ ++bool libsubid_init(const char *progname, FILE *logfd); ++ ++/* + * get_subuid_ranges: return a list of UID ranges for a user + * + * @owner: username being queried +diff -up shadow-4.6/lib/tcbfuncs.c.libsubid_not_print_error_messages shadow-4.6/lib/tcbfuncs.c +--- shadow-4.6/lib/tcbfuncs.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/tcbfuncs.c 2021-11-03 09:24:05.693172870 +0100 +@@ -72,8 +72,8 @@ shadowtcb_status shadowtcb_gain_priv (vo + * to exit soon. + */ + #define OUT_OF_MEMORY do { \ +- fprintf (stderr, _("%s: out of memory\n"), Prog); \ +- (void) fflush (stderr); \ ++ fprintf (shadow_logfd, _("%s: out of memory\n"), Prog); \ ++ (void) fflush (shadow_logfd); \ + } while (false) + + /* Returns user's tcb directory path relative to TCB_DIR. */ +@@ -116,7 +116,7 @@ static /*@null@*/ char *shadowtcb_path_r + return NULL; + } + if (lstat (path, &st) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, path, strerror (errno)); + free (path); +@@ -132,7 +132,7 @@ static /*@null@*/ char *shadowtcb_path_r + return rval; + } + if (!S_ISLNK (st.st_mode)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: %s is neither a directory, nor a symlink.\n"), + Prog, path); + free (path); +@@ -140,7 +140,7 @@ static /*@null@*/ char *shadowtcb_path_r + } + ret = readlink (path, link, sizeof (link) - 1); + if (-1 == ret) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot read symbolic link %s: %s\n"), + Prog, path, strerror (errno)); + free (path); +@@ -149,7 +149,7 @@ static /*@null@*/ char *shadowtcb_path_r + free (path); + if ((size_t)ret >= sizeof(link) - 1) { + link[sizeof(link) - 1] = '\0'; +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Suspiciously long symlink: %s\n"), + Prog, link); + return NULL; +@@ -207,7 +207,7 @@ static shadowtcb_status mkdir_leading (c + } + ptr = path; + if (stat (TCB_DIR, &st) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, TCB_DIR, strerror (errno)); + goto out_free_path; +@@ -219,19 +219,19 @@ static shadowtcb_status mkdir_leading (c + return SHADOWTCB_FAILURE; + } + if ((mkdir (dir, 0700) != 0) && (errno != EEXIST)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot create directory %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; + } + if (chown (dir, 0, st.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; + } + if (chmod (dir, 0711) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; +@@ -261,7 +261,7 @@ static shadowtcb_status unlink_suffs (co + return SHADOWTCB_FAILURE; + } + if ((unlink (tmp) != 0) && (errno != ENOENT)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: unlink: %s: %s\n"), + Prog, tmp, strerror (errno)); + free (tmp); +@@ -286,7 +286,7 @@ static shadowtcb_status rmdir_leading (c + } + if (rmdir (dir) != 0) { + if (errno != ENOTEMPTY) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot remove directory %s: %s\n"), + Prog, dir, strerror (errno)); + ret = SHADOWTCB_FAILURE; +@@ -315,7 +315,7 @@ static shadowtcb_status move_dir (const + goto out_free_nomem; + } + if (stat (olddir, &oldmode) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, olddir, strerror (errno)); + goto out_free; +@@ -342,7 +342,7 @@ static shadowtcb_status move_dir (const + goto out_free; + } + if (rename (real_old_dir, real_new_dir) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot rename %s to %s: %s\n"), + Prog, real_old_dir, real_new_dir, strerror (errno)); + goto out_free; +@@ -351,7 +351,7 @@ static shadowtcb_status move_dir (const + goto out_free; + } + if ((unlink (olddir) != 0) && (errno != ENOENT)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot remove %s: %s\n"), + Prog, olddir, strerror (errno)); + goto out_free; +@@ -365,7 +365,7 @@ static shadowtcb_status move_dir (const + } + if ( (strcmp (real_new_dir, newdir) != 0) + && (symlink (real_new_dir_rel, newdir) != 0)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot create symbolic link %s: %s\n"), + Prog, real_new_dir_rel, strerror (errno)); + goto out_free; +@@ -464,37 +464,37 @@ shadowtcb_status shadowtcb_move (/*@NULL + return SHADOWTCB_FAILURE; + } + if (stat (tcbdir, &dirmode) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (chown (tcbdir, 0, 0) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owners of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (chmod (tcbdir, 0700) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (lstat (shadow, &filemode) != 0) { + if (errno != ENOENT) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot lstat %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Warning, user %s has no tcb shadow file.\n"), + Prog, user_newname); + } else { + if (!S_ISREG (filemode.st_mode) || + filemode.st_nlink != 1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Emergency: %s's tcb shadow is not a " + "regular file with st_nlink=1.\n" + "The account is left locked.\n"), +@@ -502,13 +502,13 @@ shadowtcb_status shadowtcb_move (/*@NULL + goto out_free; + } + if (chown (shadow, user_newid, filemode.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chmod (shadow, filemode.st_mode & 07777) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; +@@ -518,7 +518,7 @@ shadowtcb_status shadowtcb_move (/*@NULL + goto out_free; + } + if (chown (tcbdir, user_newid, dirmode.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; +@@ -543,7 +543,7 @@ shadowtcb_status shadowtcb_create (const + return SHADOWTCB_SUCCESS; + } + if (stat (TCB_DIR, &tcbdir_stat) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, TCB_DIR, strerror (errno)); + return SHADOWTCB_FAILURE; +@@ -563,39 +563,39 @@ shadowtcb_status shadowtcb_create (const + return SHADOWTCB_FAILURE; + } + if (mkdir (dir, 0700) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: mkdir: %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; + } + fd = open (shadow, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot open %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + close (fd); + if (chown (shadow, 0, authgid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chmod (shadow, (mode_t) ((authgid == shadowgid) ? 0600 : 0640)) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chown (dir, 0, authgid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; + } + if (chmod (dir, (mode_t) ((authgid == shadowgid) ? 02700 : 02710)) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; +diff -up shadow-4.6/src/chage.c.libsubid_not_print_error_messages shadow-4.6/src/chage.c +--- shadow-4.6/src/chage.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/chage.c 2021-11-03 09:24:05.694172878 +0100 +@@ -66,6 +66,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool + dflg = false, /* set last password change date */ +@@ -806,6 +807,7 @@ int main (int argc, char **argv) + * Get the program name so that error messages can use it. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + (void) setlocale (LC_ALL, ""); +diff -up shadow-4.6/src/check_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/check_subid_range.c +--- shadow-4.6/src/check_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/check_subid_range.c 2021-11-03 09:24:05.694172878 +0100 +@@ -18,6 +18,7 @@ + #include "idmapping.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + int main(int argc, char **argv) + { +@@ -25,6 +26,7 @@ int main(int argc, char **argv) + unsigned long start, count; + bool check_uids; + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (argc != 5) + exit(1); +diff -up shadow-4.6/src/chfn.c.libsubid_not_print_error_messages shadow-4.6/src/chfn.c +--- shadow-4.6/src/chfn.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chfn.c 2021-11-03 09:24:05.695172886 +0100 +@@ -61,6 +61,7 @@ + * Global variables. + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static char fullnm[BUFSIZ]; + static char roomno[BUFSIZ]; + static char workph[BUFSIZ]; +@@ -639,6 +640,7 @@ int main (int argc, char **argv) + * prefix to most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + (void) setlocale (LC_ALL, ""); +diff -up shadow-4.6/src/chgpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/chgpasswd.c +--- shadow-4.6/src/chgpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chgpasswd.c 2021-11-03 09:32:53.937617545 +0100 +@@ -66,6 +66,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool eflg = false; + static bool md5flg = false; + #ifdef USE_SHA_CRYPT +@@ -466,6 +467,7 @@ int main (int argc, char **argv) + int line = 0; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/chpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/chpasswd.c +--- shadow-4.6/src/chpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chpasswd.c 2021-11-03 09:33:19.029832153 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool eflg = false; + static bool md5flg = false; + #ifdef USE_SHA_CRYPT +@@ -453,6 +454,7 @@ int main (int argc, char **argv) + int line = 0; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/chsh.c.libsubid_not_print_error_messages shadow-4.6/src/chsh.c +--- shadow-4.6/src/chsh.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chsh.c 2021-11-03 09:24:05.697172902 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static bool amroot; /* Real UID is root */ + static char loginsh[BUFSIZ]; /* Name of new login shell */ + /* command line options */ +@@ -446,6 +447,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/expiry.c.libsubid_not_print_error_messages shadow-4.6/src/expiry.c +--- shadow-4.6/src/expiry.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/expiry.c 2021-11-03 09:24:05.698172910 +0100 +@@ -46,6 +46,7 @@ + + /* Global variables */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool cflg = false; + + /* local function prototypes */ +@@ -144,6 +145,7 @@ int main (int argc, char **argv) + struct spwd *spwd; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + +diff -up shadow-4.6/src/faillog.c.libsubid_not_print_error_messages shadow-4.6/src/faillog.c +--- shadow-4.6/src/faillog.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/faillog.c 2021-11-03 09:24:05.698172910 +0100 +@@ -62,6 +62,7 @@ static void reset (void); + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static FILE *fail; /* failure file stream */ + static time_t seconds; /* that number of days in seconds */ + static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ +@@ -573,6 +574,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/free_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/free_subid_range.c 2021-11-03 09:24:05.698172910 +0100 +@@ -7,6 +7,7 @@ + /* Test program for the subid freeing routine */ + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -23,6 +24,7 @@ int main(int argc, char *argv[]) + bool group = false; // get subuids by default + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + while ((c = getopt(argc, argv, "g")) != EOF) { + switch(c) { + case 'g': group = true; break; +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_not_print_error_messages shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/get_subid_owners.c 2021-11-03 09:24:05.699172918 +0100 +@@ -4,6 +4,7 @@ + #include "prototypes.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -19,6 +20,7 @@ int main(int argc, char *argv[]) + uid_t *uids; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + if (argc < 2) { + usage(); + } +diff -up shadow-4.6/src/gpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/gpasswd.c +--- shadow-4.6/src/gpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/gpasswd.c 2021-11-03 09:24:05.699172918 +0100 +@@ -58,6 +58,7 @@ + */ + /* The name of this command, as it is invoked */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifdef SHADOWGRP + /* Indicate if shadow groups are enabled on the system +@@ -926,6 +927,7 @@ int main (int argc, char **argv) + */ + bywho = getuid (); + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + OPENLOG ("gpasswd"); + setbuf (stdout, NULL); +diff -up shadow-4.6/src/groupadd.c.libsubid_not_print_error_messages shadow-4.6/src/groupadd.c +--- shadow-4.6/src/groupadd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupadd.c 2021-11-03 09:24:05.700172926 +0100 +@@ -72,6 +72,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static /*@null@*/char *group_name; + static gid_t group_id; +@@ -582,6 +583,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupdel.c.libsubid_not_print_error_messages shadow-4.6/src/groupdel.c +--- shadow-4.6/src/groupdel.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupdel.c 2021-11-03 09:24:05.700172926 +0100 +@@ -58,6 +58,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *group_name; + static gid_t group_id = -1; +@@ -377,6 +378,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupmems.c.libsubid_not_print_error_messages shadow-4.6/src/groupmems.c +--- shadow-4.6/src/groupmems.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groupmems.c 2021-11-03 09:24:05.701172934 +0100 +@@ -65,6 +65,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *adduser = NULL; + static char *deluser = NULL; +@@ -595,6 +596,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupmod.c.libsubid_not_print_error_messages shadow-4.6/src/groupmod.c +--- shadow-4.6/src/groupmod.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupmod.c 2021-11-03 09:24:05.702172942 +0100 +@@ -76,6 +76,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifdef SHADOWGRP + static bool is_shadow_grp; +@@ -799,6 +800,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groups.c.libsubid_not_print_error_messages shadow-4.6/src/groups.c +--- shadow-4.6/src/groups.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groups.c 2021-11-03 09:24:05.702172942 +0100 +@@ -43,6 +43,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + /* local function prototypes */ + static void print_groups (const char *member); +@@ -126,6 +127,7 @@ int main (int argc, char **argv) + * Get the program name so that error messages can use it. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (argc == 1) { + +diff -up shadow-4.6/src/grpck.c.libsubid_not_print_error_messages shadow-4.6/src/grpck.c +--- shadow-4.6/src/grpck.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/grpck.c 2021-11-03 09:24:05.703172950 +0100 +@@ -68,6 +68,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *grp_file = GROUP_FILE; + static bool use_system_grp_file = true; +@@ -836,6 +837,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/grpconv.c.libsubid_not_print_error_messages shadow-4.6/src/grpconv.c +--- shadow-4.6/src/grpconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/grpconv.c 2021-11-03 09:24:05.703172950 +0100 +@@ -59,6 +59,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool gr_locked = false; + static bool sgr_locked = false; +@@ -146,6 +147,7 @@ int main (int argc, char **argv) + struct sgrp sgent; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/grpunconv.c.libsubid_not_print_error_messages shadow-4.6/src/grpunconv.c +--- shadow-4.6/src/grpunconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/grpunconv.c 2021-11-03 09:24:05.704172958 +0100 +@@ -59,6 +59,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool gr_locked = false; + static bool sgr_locked = false; +@@ -145,6 +146,7 @@ int main (int argc, char **argv) + const struct sgrp *sg; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/lastlog.c.libsubid_not_print_error_messages shadow-4.6/src/lastlog.c +--- shadow-4.6/src/lastlog.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/lastlog.c 2021-11-03 09:24:05.704172958 +0100 +@@ -58,6 +58,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static FILE *lastlogfile; /* lastlog file stream */ + static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ + static bool has_umin = false; +@@ -283,6 +284,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_not_print_error_messages shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.679172759 +0100 ++++ shadow-4.6/src/list_subid_ranges.c 2021-11-03 09:24:05.704172958 +0100 +@@ -4,6 +4,7 @@ + #include "prototypes.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -19,6 +20,7 @@ int main(int argc, char *argv[]) + struct subordinate_range **ranges; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + if (argc < 2) { + usage(); + } +diff -up shadow-4.6/src/login.c.libsubid_not_print_error_messages shadow-4.6/src/login.c +--- shadow-4.6/src/login.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/login.c 2021-11-03 09:24:05.705172966 +0100 +@@ -83,6 +83,7 @@ static pam_handle_t *pamh = NULL; + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *hostname = ""; + static /*@null@*/ /*@only@*/char *username = NULL; +@@ -562,6 +563,7 @@ int main (int argc, char **argv) + + amroot = (getuid () == 0); + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (geteuid() != 0) { + fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog); +diff -up shadow-4.6/src/logoutd.c.libsubid_not_print_error_messages shadow-4.6/src/logoutd.c +--- shadow-4.6/src/logoutd.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/logoutd.c 2021-11-03 09:24:05.706172974 +0100 +@@ -44,6 +44,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifndef DEFAULT_HUP_MESG + #define DEFAULT_HUP_MESG _("login time exceeded\n\n") +@@ -187,6 +188,7 @@ int main (int argc, char **argv) + * Start syslogging everything + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + OPENLOG ("logoutd"); + +diff -up shadow-4.6/src/newgidmap.c.libsubid_not_print_error_messages shadow-4.6/src/newgidmap.c +--- shadow-4.6/src/newgidmap.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/newgidmap.c 2021-11-03 09:24:05.706172974 +0100 +@@ -45,6 +45,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + + static bool verify_range(struct passwd *pw, struct map_range *range, bool *allow_setgroups) +@@ -175,6 +176,7 @@ int main(int argc, char **argv) + bool allow_setgroups = false; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + /* + * The valid syntax are +diff -up shadow-4.6/src/newgrp.c.libsubid_not_print_error_messages shadow-4.6/src/newgrp.c +--- shadow-4.6/src/newgrp.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.650172528 +0100 ++++ shadow-4.6/src/newgrp.c 2021-11-03 09:24:05.707172982 +0100 +@@ -49,6 +49,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + extern char **newenvp; + extern char **environ; +@@ -443,6 +444,7 @@ int main (int argc, char **argv) + * don't need to re-exec anything. -- JWP + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + is_newgrp = (strcmp (Prog, "newgrp") == 0); + OPENLOG (is_newgrp ? "newgrp" : "sg"); + gid = getgid (); +diff -up shadow-4.6/src/new_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.679172759 +0100 ++++ shadow-4.6/src/new_subid_range.c 2021-11-03 09:24:05.707172982 +0100 +@@ -7,6 +7,7 @@ + /* Test program for the subid creation routine */ + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -26,6 +27,7 @@ int main(int argc, char *argv[]) + bool ok; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + while ((c = getopt(argc, argv, "gn")) != EOF) { + switch(c) { + case 'n': makenew = true; break; +diff -up shadow-4.6/src/newuidmap.c.libsubid_not_print_error_messages shadow-4.6/src/newuidmap.c +--- shadow-4.6/src/newuidmap.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/newuidmap.c 2021-11-03 09:24:05.707172982 +0100 +@@ -45,6 +45,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool verify_range(struct passwd *pw, struct map_range *range) + { +@@ -105,6 +106,7 @@ int main(int argc, char **argv) + int written; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + /* + * The valid syntax are +diff -up shadow-4.6/src/newusers.c.libsubid_not_print_error_messages shadow-4.6/src/newusers.c +--- shadow-4.6/src/newusers.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.670172687 +0100 ++++ shadow-4.6/src/newusers.c 2021-11-03 09:24:05.708172990 +0100 +@@ -75,6 +75,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool rflg = false; /* create a system account */ + #ifndef USE_PAM +@@ -970,6 +971,7 @@ int main (int argc, char **argv) + #endif /* USE_PAM */ + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/passwd.c.libsubid_not_print_error_messages shadow-4.6/src/passwd.c +--- shadow-4.6/src/passwd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/passwd.c 2021-11-03 09:24:05.709172998 +0100 +@@ -72,6 +72,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + + static char *name; /* The name of user whose password is being changed */ + static char *myname; /* The current user's name */ +@@ -808,6 +809,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/pwck.c.libsubid_not_print_error_messages shadow-4.6/src/pwck.c +--- shadow-4.6/src/pwck.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwck.c 2021-11-03 09:24:05.709172998 +0100 +@@ -70,6 +70,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool use_system_pw_file = true; + static bool use_system_spw_file = true; +diff -up shadow-4.6/src/pwconv.c.libsubid_not_print_error_messages shadow-4.6/src/pwconv.c +--- shadow-4.6/src/pwconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwconv.c 2021-11-03 09:24:05.709172998 +0100 +@@ -89,6 +89,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool spw_locked = false; + static bool pw_locked = false; +@@ -176,6 +177,7 @@ int main (int argc, char **argv) + struct spwd spent; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/pwunconv.c.libsubid_not_print_error_messages shadow-4.6/src/pwunconv.c +--- shadow-4.6/src/pwunconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwunconv.c 2021-11-03 09:24:05.710173006 +0100 +@@ -53,6 +53,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool spw_locked = false; + static bool pw_locked = false; +@@ -137,6 +138,7 @@ int main (int argc, char **argv) + const struct spwd *spwd; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/su.c.libsubid_not_print_error_messages shadow-4.6/src/su.c +--- shadow-4.6/src/su.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/su.c 2021-11-03 09:24:05.710173006 +0100 +@@ -82,6 +82,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static /*@observer@*/const char *caller_tty = NULL; /* Name of tty SU is run from */ + static bool caller_is_root = false; + static uid_t caller_uid; +@@ -699,6 +700,7 @@ static void save_caller_context (char ** + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + caller_uid = getuid (); + caller_is_root = (caller_uid == 0); +diff -up shadow-4.6/src/sulogin.c.libsubid_not_print_error_messages shadow-4.6/src/sulogin.c +--- shadow-4.6/src/sulogin.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/sulogin.c 2021-11-03 09:24:05.710173006 +0100 +@@ -50,6 +50,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char name[BUFSIZ]; + static char pass[BUFSIZ]; +@@ -106,6 +107,7 @@ static RETSIGTYPE catch_signals (unused + #endif + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); +diff -up shadow-4.6/src/useradd.c.libsubid_not_print_error_messages shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.672172703 +0100 ++++ shadow-4.6/src/useradd.c 2021-11-03 09:24:05.711173014 +0100 +@@ -92,6 +92,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + /* + * These defaults are used if there is no defaults file. +@@ -2176,6 +2177,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/userdel.c.libsubid_not_print_error_messages shadow-4.6/src/userdel.c +--- shadow-4.6/src/userdel.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/userdel.c 2021-11-03 09:24:05.712173022 +0100 +@@ -89,6 +89,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *user_name; + static uid_t user_id; +@@ -939,6 +940,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); +diff -up shadow-4.6/src/usermod.c.libsubid_not_print_error_messages shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.674172719 +0100 ++++ shadow-4.6/src/usermod.c 2021-11-03 09:24:05.712173022 +0100 +@@ -102,6 +102,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *user_name; + static char *user_newname; +@@ -2125,6 +2126,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/vipw.c.libsubid_not_print_error_messages shadow-4.6/src/vipw.c +--- shadow-4.6/src/vipw.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.664172640 +0100 ++++ shadow-4.6/src/vipw.c 2021-11-03 09:24:05.713173030 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *filename, *fileeditname; + static bool filelocked = false; +@@ -438,6 +439,7 @@ int main (int argc, char **argv) + bool do_vipw; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); diff --git a/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch b/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch new file mode 100644 index 0000000..4348d0e --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch @@ -0,0 +1,1758 @@ +diff -up shadow-4.6/configure.ac.libsubid_nsswitch_support shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/configure.ac 2021-10-19 13:19:07.743131310 +0200 +@@ -1,6 +1,6 @@ + dnl Process this file with autoconf to produce a configure script. + AC_PREREQ([2.69]) +-m4_define([libsubid_abi_major], 1) ++m4_define([libsubid_abi_major], 2) + m4_define([libsubid_abi_minor], 0) + m4_define([libsubid_abi_micro], 0) + m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) +diff -up shadow-4.6/lib/Makefile.am.libsubid_nsswitch_support shadow-4.6/lib/Makefile.am +--- shadow-4.6/lib/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.973493060 +0200 ++++ shadow-4.6/lib/Makefile.am 2021-10-19 13:16:21.989493315 +0200 +@@ -28,6 +28,7 @@ libshadow_la_SOURCES = \ + groupio.h \ + gshadow.c \ + lockpw.c \ ++ nss.c \ + nscd.c \ + nscd.h \ + sssd.c \ +diff -up shadow-4.6/libmisc/idmapping.h.libsubid_nsswitch_support shadow-4.6/libmisc/idmapping.h +--- shadow-4.6/libmisc/idmapping.h.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/libmisc/idmapping.h 2021-10-19 13:19:50.629813857 +0200 +@@ -40,5 +40,7 @@ extern struct map_range *get_map_ranges( + extern void write_mapping(int proc_dir_fd, int ranges, + struct map_range *mappings, const char *map_file); + ++extern void nss_init(char *nsswitch_path); ++ + #endif /* _ID_MAPPING_H_ */ + +diff -up shadow-4.6/libmisc/Makefile.am.libsubid_nsswitch_support shadow-4.6/libmisc/Makefile.am +--- shadow-4.6/libmisc/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.988493299 +0200 ++++ shadow-4.6/libmisc/Makefile.am 2021-10-19 13:17:03.356151673 +0200 +@@ -3,9 +3,9 @@ EXTRA_DIST = .indent.pro xgetXXbyYY.c + + AM_CPPFLAGS = -I$(top_srcdir)/lib + +-noinst_LIBRARIES = libmisc.a ++noinst_LTLIBRARIES = libmisc.la + +-libmisc_a_SOURCES = \ ++libmisc_la_SOURCES = \ + addgrps.c \ + age.c \ + audit_help.c \ +diff -up shadow-4.6/lib/nss.c.libsubid_nsswitch_support shadow-4.6/lib/nss.c +--- shadow-4.6/lib/nss.c.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/lib/nss.c 2021-10-19 13:16:21.989493315 +0200 +@@ -0,0 +1,157 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "prototypes.h" ++#include "../libsubid/subid.h" ++ ++#define NSSWITCH "/etc/nsswitch.conf" ++ ++// NSS plugin handling for subids ++// If nsswitch has a line like ++// subid: sssd ++// then sssd will be consulted for subids. Unlike normal NSS dbs, ++// only one db is supported at a time. That's open to debate, but ++// the subids are a pretty limited resource, and local files seem ++// bound to step on any other allocations leading to insecure ++// conditions. ++static atomic_flag nss_init_started; ++static atomic_bool nss_init_completed; ++ ++static struct subid_nss_ops *subid_nss; ++ ++bool nss_is_initialized() { ++ return atomic_load(&nss_init_completed); ++} ++ ++void nss_exit() { ++ if (nss_is_initialized() && subid_nss) { ++ dlclose(subid_nss->handle); ++ free(subid_nss); ++ subid_nss = NULL; ++ } ++} ++ ++// nsswitch_path is an argument only to support testing. ++void nss_init(char *nsswitch_path) { ++ FILE *nssfp = NULL; ++ char *line = NULL, *p, *token, *saveptr; ++ size_t len = 0; ++ ++ if (atomic_flag_test_and_set(&nss_init_started)) { ++ // Another thread has started nss_init, wait for it to complete ++ while (!atomic_load(&nss_init_completed)) ++ usleep(100); ++ return; ++ } ++ ++ if (!nsswitch_path) ++ nsswitch_path = NSSWITCH; ++ ++ // read nsswitch.conf to check for a line like: ++ // subid: files ++ nssfp = fopen(nsswitch_path, "r"); ++ if (!nssfp) { ++ fprintf(stderr, "Failed opening %s: %m", nsswitch_path); ++ atomic_store(&nss_init_completed, true); ++ return; ++ } ++ while ((getline(&line, &len, nssfp)) != -1) { ++ if (line[0] == '\0' || line[0] == '#') ++ continue; ++ if (strlen(line) < 8) ++ continue; ++ if (strncasecmp(line, "subid:", 6) != 0) ++ continue; ++ p = &line[6]; ++ while ((*p) && isspace(*p)) ++ p++; ++ if (!*p) ++ continue; ++ for (token = strtok_r(p, " \n\t", &saveptr); ++ token; ++ token = strtok_r(NULL, " \n\t", &saveptr)) { ++ char libname[65]; ++ void *h; ++ if (strcmp(token, "files") == 0) { ++ subid_nss = NULL; ++ goto done; ++ } ++ if (strlen(token) > 50) { ++ fprintf(stderr, "Subid NSS module name too long (longer than 50 characters): %s\n", token); ++ fprintf(stderr, "Using files\n"); ++ subid_nss = NULL; ++ goto done; ++ } ++ snprintf(libname, 64, "libsubid_%s.so", token); ++ h = dlopen(libname, RTLD_LAZY); ++ if (!h) { ++ fprintf(stderr, "Error opening %s: %s\n", libname, dlerror()); ++ fprintf(stderr, "Using files\n"); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss = malloc(sizeof(*subid_nss)); ++ if (!subid_nss) { ++ dlclose(h); ++ goto done; ++ } ++ subid_nss->has_range = dlsym(h, "shadow_subid_has_range"); ++ if (!subid_nss->has_range) { ++ fprintf(stderr, "%s did not provide @has_range@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); ++ if (!subid_nss->list_owner_ranges) { ++ fprintf(stderr, "%s did not provide @list_owner_ranges@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); ++ if (!subid_nss->has_any_range) { ++ fprintf(stderr, "%s did not provide @has_any_range@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); ++ if (!subid_nss->find_subid_owners) { ++ fprintf(stderr, "%s did not provide @find_subid_owners@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->handle = h; ++ goto done; ++ } ++ fprintf(stderr, "No usable subid NSS module found, using files\n"); ++ // subid_nss has to be null here, but to ease reviews: ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ ++done: ++ atomic_store(&nss_init_completed, true); ++ free(line); ++ if (nssfp) { ++ atexit(nss_exit); ++ fclose(nssfp); ++ } ++} ++ ++struct subid_nss_ops *get_subid_nss_handle() { ++ nss_init(NULL); ++ return subid_nss; ++} +diff -up shadow-4.6/lib/prototypes.h.libsubid_nsswitch_support shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.libsubid_nsswitch_support 2021-10-19 13:16:21.961492869 +0200 ++++ shadow-4.6/lib/prototypes.h 2021-10-19 13:16:21.989493315 +0200 +@@ -263,6 +263,75 @@ extern void motd (void); + /* myname.c */ + extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void); + ++/* nss.c */ ++#include ++extern void nss_init(char *nsswitch_path); ++extern bool nss_is_initialized(); ++ ++struct subid_nss_ops { ++ /* ++ * nss_has_any_range: does a user own any subid range ++ * ++ * @owner: username ++ * @idtype: subuid or subgid ++ * @result: true if a subid allocation was found for @owner ++ * ++ * returns success if the module was able to determine an answer (true or false), ++ * else an error status. ++ */ ++ enum subid_status (*has_any_range)(const char *owner, enum subid_type idtype, bool *result); ++ ++ /* ++ * nss_has_range: does a user own a given subid range ++ * ++ * @owner: username ++ * @start: first subid in queried range ++ * @count: number of subids in queried range ++ * @idtype: subuid or subgid ++ * @result: true if @owner has been allocated the subid range. ++ * ++ * returns success if the module was able to determine an answer (true or false), ++ * else an error status. ++ */ ++ enum subid_status (*has_range)(const char *owner, unsigned long start, unsigned long count, enum subid_type idtype, bool *result); ++ ++ /* ++ * nss_list_owner_ranges: list the subid ranges delegated to a user. ++ * ++ * @owner - string representing username being queried ++ * @id_type - subuid or subgid ++ * @ranges - pointer to an array of struct subordinate_range pointers, or ++ * NULL. The returned array of struct subordinate_range and its ++ * members must be freed by the caller. ++ * @count - pointer to an integer into which the number of returned ranges ++ * is written. ++ ++ * returns success if the module was able to determine an answer, ++ * else an error status. ++ */ ++ enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges, int *count); ++ ++ /* ++ * nss_find_subid_owners: find uids who own a given subuid or subgid. ++ * ++ * @id - the delegated id (subuid or subgid) being queried ++ * @id_type - subuid or subgid ++ * @uids - pointer to an array of uids which will be allocated by ++ * nss_find_subid_owners() ++ * @count - number of uids found ++ * ++ * returns success if the module was able to determine an answer, ++ * else an error status. ++ */ ++ enum subid_status (*find_subid_owners)(unsigned long id, enum subid_type id_type, uid_t **uids, int *count); ++ ++ /* The dlsym handle to close */ ++ void *handle; ++}; ++ ++extern struct subid_nss_ops *get_subid_nss_handle(); ++ ++ + /* pam_pass_non_interactive.c */ + #ifdef USE_PAM + extern int do_pam_passwd_non_interactive (const char *pam_service, +diff -up shadow-4.6/libsubid/api.c.libsubid_nsswitch_support shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/api.c 2021-10-19 13:16:21.991493347 +0200 +@@ -36,134 +36,50 @@ + #include + #include "subordinateio.h" + #include "idmapping.h" +-#include "api.h" ++#include "subid.h" + +-static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type) ++static ++int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + { +- struct subordinate_range **ranges = NULL; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_open(O_RDONLY)) { +- return NULL; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_open(O_RDONLY)) { +- return NULL; +- } +- break; +- default: +- return NULL; +- } +- +- ranges = list_owner_ranges(owner, id_type); +- +- if (id_type == ID_TYPE_UID) +- sub_uid_close(); +- else +- sub_gid_close(); +- +- return ranges; ++ return list_owner_ranges(owner, id_type, ranges); + } + +-struct subordinate_range **get_subuid_ranges(const char *owner) ++int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges) + { +- return get_subid_ranges(owner, ID_TYPE_UID); ++ return get_subid_ranges(owner, ID_TYPE_UID, ranges); + } + +-struct subordinate_range **get_subgid_ranges(const char *owner) ++int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges) + { +- return get_subid_ranges(owner, ID_TYPE_GID); ++ return get_subid_ranges(owner, ID_TYPE_GID, ranges); + } + +-void subid_free_ranges(struct subordinate_range **ranges) ++void subid_free_ranges(struct subordinate_range **ranges, int count) + { +- return free_subordinate_ranges(ranges); ++ return free_subordinate_ranges(ranges, count); + } + +-int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type) ++static ++int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner) + { +- int ret = -1; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_open(O_RDONLY)) { +- return -1; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_open(O_RDONLY)) { +- return -1; +- } +- break; +- default: +- return -1; +- } +- +- ret = find_subid_owners(id, owner, id_type); +- +- if (id_type == ID_TYPE_UID) +- sub_uid_close(); +- else +- sub_gid_close(); +- +- return ret; ++ return find_subid_owners(id, id_type, owner); + } + + int get_subuid_owners(uid_t uid, uid_t **owner) + { +- return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID); ++ return get_subid_owner((unsigned long)uid, ID_TYPE_UID, owner); + } + + int get_subgid_owners(gid_t gid, uid_t **owner) + { +- return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID); ++ return get_subid_owner((unsigned long)gid, ID_TYPE_GID, owner); + } + ++static + bool grant_subid_range(struct subordinate_range *range, bool reuse, + enum subid_type id_type) + { +- bool ret; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_lock()) { +- printf("Failed loging subuids (errno %d)\n", errno); +- return false; +- } +- if (!sub_uid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subuids (errno %d)\n", errno); +- sub_uid_unlock(); +- return false; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_lock()) { +- printf("Failed loging subgids (errno %d)\n", errno); +- return false; +- } +- if (!sub_gid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subgids (errno %d)\n", errno); +- sub_gid_unlock(); +- return false; +- } +- break; +- default: +- return false; +- } +- +- ret = new_subid_range(range, id_type, reuse); +- +- if (id_type == ID_TYPE_UID) { +- sub_uid_close(); +- sub_uid_unlock(); +- } else { +- sub_gid_close(); +- sub_gid_unlock(); +- } +- +- return ret; ++ return new_subid_range(range, id_type, reuse); + } + + bool grant_subuid_range(struct subordinate_range *range, bool reuse) +@@ -176,56 +92,18 @@ bool grant_subgid_range(struct subordina + return grant_subid_range(range, reuse, ID_TYPE_GID); + } + +-bool free_subid_range(struct subordinate_range *range, enum subid_type id_type) ++static ++bool ungrant_subid_range(struct subordinate_range *range, enum subid_type id_type) + { +- bool ret; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_lock()) { +- printf("Failed loging subuids (errno %d)\n", errno); +- return false; +- } +- if (!sub_uid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subuids (errno %d)\n", errno); +- sub_uid_unlock(); +- return false; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_lock()) { +- printf("Failed loging subgids (errno %d)\n", errno); +- return false; +- } +- if (!sub_gid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subgids (errno %d)\n", errno); +- sub_gid_unlock(); +- return false; +- } +- break; +- default: +- return false; +- } +- +- ret = release_subid_range(range, id_type); +- +- if (id_type == ID_TYPE_UID) { +- sub_uid_close(); +- sub_uid_unlock(); +- } else { +- sub_gid_close(); +- sub_gid_unlock(); +- } +- +- return ret; ++ return release_subid_range(range, id_type); + } + +-bool free_subuid_range(struct subordinate_range *range) ++bool ungrant_subuid_range(struct subordinate_range *range) + { +- return free_subid_range(range, ID_TYPE_UID); ++ return ungrant_subid_range(range, ID_TYPE_UID); + } + +-bool free_subgid_range(struct subordinate_range *range) ++bool ungrant_subgid_range(struct subordinate_range *range) + { +- return free_subid_range(range, ID_TYPE_GID); ++ return ungrant_subid_range(range, ID_TYPE_GID); + } +diff -up shadow-4.6/libsubid/api.h.libsubid_nsswitch_support shadow-4.6/libsubid/api.h +diff -up shadow-4.6/libsubid/Makefile.am.libsubid_nsswitch_support shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/Makefile.am 2021-10-19 13:16:21.989493315 +0200 +@@ -12,12 +12,14 @@ MISCLIBS = \ + $(LIBSKEY) \ + $(LIBMD) \ + $(LIBCRYPT) \ ++ $(LIBACL) \ ++ $(LIBATTR) \ + $(LIBTCB) + + libsubid_la_LIBADD = \ + $(top_srcdir)/lib/libshadow.la \ +- $(MISCLIBS) \ +- $(top_srcdir)/libmisc/libmisc.a ++ $(top_srcdir)/libmisc/libmisc.la \ ++ $(MISCLIBS) -ldl + + AM_CPPFLAGS = \ + -I${top_srcdir}/lib \ +diff -up shadow-4.6/libsubid/subid.h.libsubid_nsswitch_support shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/subid.h 2021-10-19 13:16:21.991493347 +0200 +@@ -1,4 +1,5 @@ + #include ++#include + + #ifndef SUBID_RANGE_DEFINED + #define SUBID_RANGE_DEFINED 1 +@@ -13,5 +14,117 @@ enum subid_type { + ID_TYPE_GID = 2 + }; + ++enum subid_status { ++ SUBID_STATUS_SUCCESS = 0, ++ SUBID_STATUS_UNKNOWN_USER = 1, ++ SUBID_STATUS_ERROR_CONN = 2, ++ SUBID_STATUS_ERROR = 3, ++}; ++ ++/* ++ * get_subuid_ranges: return a list of UID ranges for a user ++ * ++ * @owner: username being queried ++ * @ranges: a pointer to a subordinate range ** in which the result will be ++ * returned. ++ * ++ * returns: number of ranges found, ir < 0 on error. ++ */ ++int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges); ++ ++/* ++ * get_subgid_ranges: return a list of GID ranges for a user ++ * ++ * @owner: username being queried ++ * @ranges: a pointer to a subordinate range ** in which the result will be ++ * returned. ++ * ++ * returns: number of ranges found, ir < 0 on error. ++ */ ++int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges); ++ ++/* ++ * subid_free_ranges: free an array of subordinate_ranges returned by either ++ * get_subuid_ranges() or get_subgid_ranges(). ++ * ++ * @ranges: the ranges to free ++ * @count: the number of ranges in @ranges ++ */ ++void subid_free_ranges(struct subordinate_range **ranges, int count); ++ ++/* ++ * get_subuid_owners: return a list of uids to which the given uid has been ++ * delegated. ++ * ++ * @uid: The subuid being queried ++ * @owners: a pointer to an array of uids into which the results are placed. ++ * The returned array must be freed by the caller. ++ * ++ * Returns the number of uids returned, or < 0 on error. ++ */ ++int get_subuid_owners(uid_t uid, uid_t **owner); ++ ++/* ++ * get_subgid_owners: return a list of uids to which the given gid has been ++ * delegated. ++ * ++ * @uid: The subgid being queried ++ * @owners: a pointer to an array of uids into which the results are placed. ++ * The returned array must be freed by the caller. ++ * ++ * Returns the number of uids returned, or < 0 on error. ++ */ ++int get_subgid_owners(gid_t gid, uid_t **owner); ++ ++/* ++ * grant_subuid_range: assign a subuid range to a user ++ * ++ * @range: pointer to a struct subordinate_range detailing the UID range ++ * to allocate. ->owner must be the username, and ->count must be ++ * filled in. ->start is ignored, and will contain the start ++ * of the newly allocated range, upon success. ++ * ++ * Returns true if the delegation succeeded, false otherwise. If true, ++ * then the range from (range->start, range->start + range->count) will ++ * be delegated to range->owner. ++ */ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse); ++ ++/* ++ * grant_subsid_range: assign a subgid range to a user ++ * ++ * @range: pointer to a struct subordinate_range detailing the GID range ++ * to allocate. ->owner must be the username, and ->count must be ++ * filled in. ->start is ignored, and will contain the start ++ * of the newly allocated range, upon success. ++ * ++ * Returns true if the delegation succeeded, false otherwise. If true, ++ * then the range from (range->start, range->start + range->count) will ++ * be delegated to range->owner. ++ */ ++bool grant_subgid_range(struct subordinate_range *range, bool reuse); ++ ++/* ++ * ungrant_subuid_range: remove a subuid allocation. ++ * ++ * @range: pointer to a struct subordinate_range detailing the UID allocation ++ * to remove. ++ * ++ * Returns true if successful, false if it failed, for instance if the ++ * delegation did not exist. ++ */ ++bool ungrant_subuid_range(struct subordinate_range *range); ++ ++/* ++ * ungrant_subuid_range: remove a subgid allocation. ++ * ++ * @range: pointer to a struct subordinate_range detailing the GID allocation ++ * to remove. ++ * ++ * Returns true if successful, false if it failed, for instance if the ++ * delegation did not exist. ++ */ ++bool ungrant_subgid_range(struct subordinate_range *range); ++ + #define SUBID_NFIELDS 3 + #endif +diff -up shadow-4.6/lib/subordinateio.c.libsubid_nsswitch_support shadow-4.6/lib/subordinateio.c +--- shadow-4.6/lib/subordinateio.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/lib/subordinateio.c 2021-10-19 13:16:21.989493315 +0200 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* + * subordinate_dup: create a duplicate range +@@ -316,17 +317,17 @@ static bool append_range(struct subordin + { + struct subordinate_range *tmp; + if (!*ranges) { +- *ranges = malloc(2 * sizeof(struct subordinate_range **)); ++ *ranges = malloc(sizeof(struct subordinate_range *)); + if (!*ranges) + return false; + } else { + struct subordinate_range **new; +- new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **))); ++ new = realloc(*ranges, (n + 1) * (sizeof(struct subordinate_range *))); + if (!new) + return false; + *ranges = new; + } +- (*ranges)[n] = (*ranges)[n+1] = NULL; ++ (*ranges)[n] = NULL; + tmp = subordinate_dup(new); + if (!tmp) + return false; +@@ -334,13 +335,13 @@ static bool append_range(struct subordin + return true; + } + +-void free_subordinate_ranges(struct subordinate_range **ranges) ++void free_subordinate_ranges(struct subordinate_range **ranges, int count) + { + int i; + + if (!ranges) + return; +- for (i = 0; ranges[i]; i++) ++ for (i = 0; i < count; i++) + subordinate_free(ranges[i]); + free(ranges); + } +@@ -607,21 +608,46 @@ int sub_uid_open (int mode) + + bool sub_uid_assigned(const char *owner) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_any_range(owner, ID_TYPE_UID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } ++ + return range_exists (&subordinate_uid_db, owner); + } + + bool have_sub_uids(const char *owner, uid_t start, unsigned long count) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_range(owner, start, count, ID_TYPE_UID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return have_range (&subordinate_uid_db, owner, start, count); + } + + int sub_uid_add (const char *owner, uid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return add_range (&subordinate_uid_db, owner, start, count); + } + + int sub_uid_remove (const char *owner, uid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return remove_range (&subordinate_uid_db, owner, start, count); + } + +@@ -689,21 +715,45 @@ int sub_gid_open (int mode) + + bool have_sub_gids(const char *owner, gid_t start, unsigned long count) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_range(owner, start, count, ID_TYPE_GID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return have_range(&subordinate_gid_db, owner, start, count); + } + + bool sub_gid_assigned(const char *owner) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_any_range(owner, ID_TYPE_GID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return range_exists (&subordinate_gid_db, owner); + } + + int sub_gid_add (const char *owner, gid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return add_range (&subordinate_gid_db, owner, start, count); + } + + int sub_gid_remove (const char *owner, gid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return remove_range (&subordinate_gid_db, owner, start, count); + } + +@@ -725,42 +775,78 @@ gid_t sub_gid_find_free_range(gid_t min, + } + + /* +- struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++ * int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + * + * @owner: username + * @id_type: UID or GUID ++ * @ranges: pointer to array of ranges into which results will be placed. + * +- * Returns the subuid or subgid ranges which are owned by the specified ++ * Fills in the subuid or subgid ranges which are owned by the specified + * user. Username may be a username or a string representation of a + * UID number. If id_type is UID, then subuids are returned, else +- * subgids are returned. If there is an error, < 0 is returned. ++ * subgids are given. ++ ++ * Returns the number of ranges found, or < 0 on error. + * + * The caller must free the subordinate range list. + */ +-struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges) + { + // TODO - need to handle owner being either uid or username +- const struct subordinate_range *range; + struct subordinate_range **ranges = NULL; ++ const struct subordinate_range *range; + struct commonio_db *db; +- int size = 0; ++ enum subid_status status; ++ int count = 0; ++ struct subid_nss_ops *h; ++ ++ *in_ranges = NULL; ++ ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->list_owner_ranges(owner, id_type, in_ranges, &count); ++ if (status == SUBID_STATUS_SUCCESS) ++ return count; ++ return -1; ++ } + +- if (id_type == ID_TYPE_UID) ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return -1; ++ } + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { +- if (!append_range(&ranges, range, size++)) { +- free_subordinate_ranges(ranges); +- return NULL; ++ if (!append_range(&ranges, range, count++)) { ++ free_subordinate_ranges(ranges, count-1); ++ ranges = NULL; ++ count = -1; ++ goto out; + } + } + } + +- return ranges; ++out: ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ *in_ranges = ranges; ++ return count; + } + + static bool all_digits(const char *str) +@@ -813,17 +899,41 @@ static int append_uids(uid_t **uids, con + return n+1; + } + +-int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type) ++int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids) + { + const struct subordinate_range *range; ++ struct subid_nss_ops *h; ++ enum subid_status status; + struct commonio_db *db; + int n = 0; + +- *uids = NULL; +- if (id_type == ID_TYPE_UID) ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->find_subid_owners(id, id_type, uids, &n); ++ // Several ways we could handle the error cases here. ++ if (status != SUBID_STATUS_SUCCESS) ++ return -1; ++ return n; ++ } ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return -1; ++ } ++ ++ *uids = NULL; + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { +@@ -834,6 +944,11 @@ int find_subid_owners(unsigned long id, + } + } + ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ + return n; + } + +@@ -841,11 +956,40 @@ bool new_subid_range(struct subordinate_ + { + struct commonio_db *db; + const struct subordinate_range *r; ++ bool ret; + +- if (id_type == ID_TYPE_UID) ++ if (get_subid_nss_handle()) ++ return false; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return false; ++ } ++ + commonio_rewind(db); + if (reuse) { + while ((r = commonio_next(db)) != NULL) { +@@ -861,20 +1005,74 @@ bool new_subid_range(struct subordinate_ + } + + range->start = find_free_range(db, range->start, ULONG_MAX, range->count); +- if (range->start == ULONG_MAX) +- return false; + +- return add_range(db, range->owner, range->start, range->count) == 1; ++ if (range->start == ULONG_MAX) { ++ ret = false; ++ goto out; ++ } ++ ++ ret = add_range(db, range->owner, range->start, range->count) == 1; ++ ++out: ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; + } + + bool release_subid_range(struct subordinate_range *range, enum subid_type id_type) + { + struct commonio_db *db; +- if (id_type == ID_TYPE_UID) ++ bool ret; ++ ++ if (get_subid_nss_handle()) ++ return false; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } + db = &subordinate_gid_db; +- return remove_range(db, range->owner, range->start, range->count) == 1; ++ break; ++ default: ++ return false; ++ } ++ ++ ret = remove_range(db, range->owner, range->start, range->count) == 1; ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; + } + + #else /* !ENABLE_SUBIDS */ +diff -up shadow-4.6/lib/subordinateio.h.libsubid_nsswitch_support shadow-4.6/lib/subordinateio.h +--- shadow-4.6/lib/subordinateio.h.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/lib/subordinateio.h 2021-10-19 13:16:21.989493315 +0200 +@@ -25,11 +25,11 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); +-extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type); ++extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges); + extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); + extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); +-extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type); +-extern void free_subordinate_ranges(struct subordinate_range **ranges); ++extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids); ++extern void free_subordinate_ranges(struct subordinate_range **ranges, int count); + + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); +diff -up shadow-4.6/src/check_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/check_subid_range.c +--- shadow-4.6/src/check_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/src/check_subid_range.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,48 @@ ++// This program is for testing purposes only. ++// usage is "[program] owner [u|g] start count ++// Exits 0 if owner has subid range starting start, of size count ++// Exits 1 otherwise. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "defines.h" ++#include "prototypes.h" ++#include "subordinateio.h" ++#include "idmapping.h" ++ ++const char *Prog; ++ ++int main(int argc, char **argv) ++{ ++ char *owner; ++ unsigned long start, count; ++ bool check_uids; ++ Prog = Basename (argv[0]); ++ ++ if (argc != 5) ++ exit(1); ++ ++ owner = argv[1]; ++ check_uids = argv[2][0] == 'u'; ++ start = strtoul(argv[3], NULL, 10); ++ if (start == ULONG_MAX && errno == ERANGE) ++ exit(1); ++ count = strtoul(argv[4], NULL, 10); ++ if (count == ULONG_MAX && errno == ERANGE) ++ exit(1); ++ if (check_uids) { ++ if (have_sub_uids(owner, start, count)) ++ exit(0); ++ exit(1); ++ } ++ if (have_sub_gids(owner, start, count)) ++ exit(0); ++ exit(1); ++} +diff -up shadow-4.6/src/free_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/src/free_subid_range.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,6 +1,6 @@ + #include + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +@@ -37,9 +37,9 @@ int main(int argc, char *argv[]) + range.start = atoi(argv[1]); + range.count = atoi(argv[2]); + if (group) +- ok = free_subgid_range(&range); ++ ok = ungrant_subgid_range(&range); + else +- ok = free_subuid_range(&range); ++ ok = ungrant_subuid_range(&range); + + if (!ok) { + fprintf(stderr, "Failed freeing id range\n"); +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_nsswitch_support shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/src/get_subid_owners.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,5 +1,5 @@ + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_nsswitch_support shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/src/list_subid_ranges.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,5 +1,5 @@ + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +@@ -15,7 +15,7 @@ void usage(void) + + int main(int argc, char *argv[]) + { +- int i; ++ int i, count=0; + struct subordinate_range **ranges; + + Prog = Basename (argv[0]); +@@ -23,19 +23,19 @@ int main(int argc, char *argv[]) + usage(); + } + if (argc == 3 && strcmp(argv[1], "-g") == 0) +- ranges = get_subgid_ranges(argv[2]); ++ count = get_subgid_ranges(argv[2], &ranges); + else if (argc == 2 && strcmp(argv[1], "-h") == 0) + usage(); + else +- ranges = get_subuid_ranges(argv[1]); ++ count = get_subuid_ranges(argv[1], &ranges); + if (!ranges) { + fprintf(stderr, "Error fetching ranges\n"); + exit(1); + } +- for (i = 0; ranges[i]; i++) { ++ for (i = 0; i < count; i++) { + printf("%d: %s %lu %lu\n", i, ranges[i]->owner, + ranges[i]->start, ranges[i]->count); + } +- subid_free_ranges(ranges); ++ subid_free_ranges(ranges, count); + return 0; + } +diff -up shadow-4.6/src/Makefile.am.libsubid_nsswitch_support shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.988493299 +0200 ++++ shadow-4.6/src/Makefile.am 2021-10-19 13:20:47.920725652 +0200 +@@ -69,7 +69,7 @@ shadowsgidubins = passwd + endif + + LDADD = $(INTLLIBS) \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/lib/libshadow.la \ + $(LIBTCB) + +@@ -86,17 +86,17 @@ LIBCRYPT_NOPAM = $(LIBCRYPT) + endif + + chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +-newuidmap_LDADD = $(LDADD) $(LIBSELINUX) +-newgidmap_LDADD = $(LDADD) $(LIBSELINUX) ++newuidmap_LDADD = $(LDADD) $(LIBSELINUX) -ldl ++newgidmap_LDADD = $(LDADD) $(LIBSELINUX) -ldl + chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) +-groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +-groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) ++groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl ++groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl + groupmems_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) +-groupmod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) ++groupmod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl + grpck_LDADD = $(LDADD) $(LIBSELINUX) + grpconv_LDADD = $(LDADD) $(LIBSELINUX) + grpunconv_LDADD = $(LDADD) $(LIBSELINUX) +@@ -106,7 +106,7 @@ login_SOURCES = \ + login_nopam.c + login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) +-newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) ++newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) -ldl + nologin_LDADD = + passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) + pwck_LDADD = $(LDADD) $(LIBSELINUX) +@@ -117,9 +117,9 @@ su_SOURCES = \ + suauth.c + su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + sulogin_LDADD = $(LDADD) $(LIBCRYPT) +-useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) +-userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) +-usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) ++useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) -ldl ++userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) -ldl ++usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) -ldl + vipw_LDADD = $(LDADD) $(LIBSELINUX) + + install-am: all-am +@@ -143,7 +143,8 @@ if ENABLE_SUBIDS + noinst_PROGRAMS += list_subid_ranges \ + get_subid_owners \ + new_subid_range \ +- free_subid_range ++ free_subid_range \ ++ check_subid_range + + MISCLIBS = \ + $(LIBAUDIT) \ +@@ -158,9 +159,9 @@ MISCLIBS = \ + + list_subid_ranges_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + list_subid_ranges_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -169,9 +170,9 @@ list_subid_ranges_CPPFLAGS = \ + + get_subid_owners_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + get_subid_owners_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -185,9 +186,9 @@ new_subid_range_CPPFLAGS = \ + + new_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + free_subid_range_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -196,7 +197,16 @@ free_subid_range_CPPFLAGS = \ + + free_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl ++ ++check_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc ++ ++check_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.la \ ++ $(MISCLIBS) -ldl + endif +diff -up shadow-4.6/src/new_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/src/new_subid_range.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,6 +1,6 @@ + #include + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +diff -up shadow-4.6/tests/libsubid/04_nss/empty.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/empty +diff -up shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c +--- shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,146 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum subid_status shadow_subid_has_any_range(const char *owner, enum subid_type t, bool *result) ++{ ++ if (strcmp(owner, "ubuntu") == 0) { ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++ } ++ if (strcmp(owner, "error") == 0) { ++ *result = false; ++ return SUBID_STATUS_ERROR; ++ } ++ if (strcmp(owner, "unknown") == 0) { ++ *result = false; ++ return SUBID_STATUS_UNKNOWN_USER; ++ } ++ if (strcmp(owner, "conn") == 0) { ++ *result = false; ++ return SUBID_STATUS_ERROR_CONN; ++ } ++ if (t == ID_TYPE_UID) { ++ *result = strcmp(owner, "user1") == 0; ++ return SUBID_STATUS_SUCCESS; ++ } ++ ++ *result = strcmp(owner, "group1") == 0; ++ return SUBID_STATUS_SUCCESS; ++} ++ ++enum subid_status shadow_subid_has_range(const char *owner, unsigned long start, unsigned long count, enum subid_type t, bool *result) ++{ ++ if (strcmp(owner, "ubuntu") == 0 && ++ start >= 200000 && ++ count <= 100000) { ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++ } ++ *result = false; ++ if (strcmp(owner, "error") == 0) ++ return SUBID_STATUS_ERROR; ++ if (strcmp(owner, "unknown") == 0) ++ return SUBID_STATUS_UNKNOWN_USER; ++ if (strcmp(owner, "conn") == 0) ++ return SUBID_STATUS_ERROR_CONN; ++ ++ if (t == ID_TYPE_UID && strcmp(owner, "user1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ if (t == ID_TYPE_GID && strcmp(owner, "group1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ ++ if (start < 100000) ++ return SUBID_STATUS_SUCCESS; ++ if (count >= 65536) ++ return SUBID_STATUS_SUCCESS; ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++} ++ ++// So if 'user1' or 'ubuntu' is defined in passwd, we'll return those values, ++// to ease manual testing. For automated testing, if you return those values, ++// we'll return 1000 for ubuntu and 1001 otherwise. ++static uid_t getnamuid(const char *name) { ++ struct passwd *pw; ++ ++ pw = getpwnam(name); ++ if (pw) ++ return pw->pw_uid; ++ ++ // For testing purposes ++ return strcmp(name, "ubuntu") == 0 ? (uid_t)1000 : (uid_t)1001; ++} ++ ++static int alloc_uid(uid_t **uids, uid_t id) { ++ *uids = malloc(sizeof(uid_t)); ++ if (!*uids) ++ return -1; ++ *uids[0] = id; ++ return 1; ++} ++ ++enum subid_status shadow_subid_find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids, int *count) ++{ ++ if (id >= 100000 && id < 165536) { ++ *count = alloc_uid(uids, getnamuid("user1")); ++ if (*count == 1) ++ return SUBID_STATUS_SUCCESS; ++ return SUBID_STATUS_ERROR; // out of memory ++ } ++ if (id >= 200000 && id < 300000) { ++ *count = alloc_uid(uids, getnamuid("ubuntu")); ++ if (*count == 1) ++ return SUBID_STATUS_SUCCESS; ++ return SUBID_STATUS_ERROR; // out of memory ++ } ++ *count = 0; // nothing found ++ return SUBID_STATUS_SUCCESS; ++} ++ ++enum subid_status shadow_subid_list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges, int *count) ++{ ++ struct subordinate_range **ranges; ++ ++ *count = 0; ++ if (strcmp(owner, "error") == 0) ++ return SUBID_STATUS_ERROR; ++ if (strcmp(owner, "unknown") == 0) ++ return SUBID_STATUS_UNKNOWN_USER; ++ if (strcmp(owner, "conn") == 0) ++ return SUBID_STATUS_ERROR_CONN; ++ ++ *ranges = NULL; ++ if (strcmp(owner, "user1") != 0 && strcmp(owner, "ubuntu") != 0 && ++ strcmp(owner, "group1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ if (id_type == ID_TYPE_GID && strcmp(owner, "user1") == 0) ++ return SUBID_STATUS_SUCCESS; ++ if (id_type == ID_TYPE_UID && strcmp(owner, "group1") == 0) ++ return SUBID_STATUS_SUCCESS; ++ ranges = (struct subordinate_range **)malloc(sizeof(struct subordinate_range *)); ++ if (!*ranges) ++ return SUBID_STATUS_ERROR; ++ ranges[0] = (struct subordinate_range *)malloc(sizeof(struct subordinate_range)); ++ if (!ranges[0]) { ++ free(*ranges); ++ *ranges = NULL; ++ return SUBID_STATUS_ERROR; ++ } ++ ranges[0]->owner = strdup(owner); ++ if (strcmp(owner, "user1") == 0 || strcmp(owner, "group1") == 0) { ++ ranges[0]->start = 100000; ++ ranges[0]->count = 65536; ++ } else { ++ ranges[0]->start = 200000; ++ ranges[0]->count = 100000; ++ } ++ ++ *count = 1; ++ *in_ranges = ranges; ++ ++ return SUBID_STATUS_SUCCESS; ++} +diff -up shadow-4.6/tests/libsubid/04_nss/Makefile.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/Makefile +--- shadow-4.6/tests/libsubid/04_nss/Makefile.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/Makefile 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,12 @@ ++all: test_nss libsubid_zzz.so ++ ++test_nss: test_nss.c ../../../lib/nss.c ++ gcc -c -I../../../lib/ -I../../.. -o test_nss.o test_nss.c ++ gcc -o test_nss test_nss.o ../../../libmisc/.libs/libmisc.a ../../../lib/.libs/libshadow.a -ldl ++ ++libsubid_zzz.so: libsubid_zzz.c ++ gcc -c -I../../../lib/ -I../../.. -I../../../libmisc -I../../../libsubid libsubid_zzz.c ++ gcc -L../../../libsubid -shared -o libsubid_zzz.so libsubid_zzz.o ../../../lib/.libs/libshadow.a -ldl ++ ++clean: ++ rm -f *.o *.so test_nss +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,20 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis ++ ++subid: files +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis ++ ++subid: zzz +diff -up shadow-4.6/tests/libsubid/04_nss/subidnss.test.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/subidnss.test +--- shadow-4.6/tests/libsubid/04_nss/subidnss.test.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/subidnss.test 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++make ++ ++export LD_LIBRARY_PATH=.:../../../lib/.libs:$LD_LIBRARY_PATH ++ ++./test_nss 1 ++./test_nss 2 ++./test_nss 3 ++ ++unshare -Urm ./test_range ++ ++log_status "$0" "SUCCESS" ++ ++trap '' 0 +diff -up shadow-4.6/tests/libsubid/04_nss/test_nss.c.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/test_nss.c +--- shadow-4.6/tests/libsubid/04_nss/test_nss.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/test_nss.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,72 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern bool nss_is_initialized(); ++extern struct subid_nss_ops *get_subid_nss_handle(); ++ ++void test1() { ++ // nsswitch1 has no subid: entry ++ setenv("LD_LIBRARY_PATH", ".", 1); ++ printf("Test with no subid entry\n"); ++ nss_init("./nsswitch1.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("Test with no subid entry, second run\n"); ++ nss_init("./nsswitch1.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++} ++ ++void test2() { ++ // nsswitch2 has a subid: files entry ++ printf("test with 'files' subid entry\n"); ++ nss_init("./nsswitch2.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("test with 'files' subid entry, second run\n"); ++ nss_init("./nsswitch2.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++} ++ ++void test3() { ++ // nsswitch3 has a subid: testnss entry ++ printf("test with 'test' subid entry\n"); ++ nss_init("./nsswitch3.conf"); ++ if (!nss_is_initialized() || !get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("test with 'test' subid entry, second run\n"); ++ nss_init("./nsswitch3.conf"); ++ if (!nss_is_initialized() || !get_subid_nss_handle()) ++ exit(1); ++} ++ ++const char *Prog; ++ ++int main(int argc, char *argv[]) ++{ ++ int which; ++ ++ Prog = Basename(argv[0]); ++ ++ if (argc < 1) ++ exit(1); ++ ++ which = atoi(argv[1]); ++ switch(which) { ++ case 1: test1(); break; ++ case 2: test2(); break; ++ case 3: test3(); break; ++ default: exit(1); ++ } ++ ++ printf("nss parsing tests done\n"); ++ exit(0); ++} +diff -up shadow-4.6/tests/libsubid/04_nss/test_range.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/test_range +--- shadow-4.6/tests/libsubid/04_nss/test_range.libsubid_nsswitch_support 2021-10-19 13:16:21.991493347 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/test_range 2021-10-19 13:16:21.991493347 +0200 +@@ -0,0 +1,50 @@ ++#!/bin/sh ++ ++set -x ++ ++echo "starting check_range tests" ++ ++export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ++mount --bind ./nsswitch3.conf /etc/nsswitch.conf ++cleanup1() { ++ umount /etc/nsswitch.conf ++} ++trap cleanup1 EXIT HUP INT TERM ++../../../src/check_subid_range user1 u 100000 65535 ++if [ $? -ne 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range user2 u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range unknown u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range error u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range user1 u 1000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++ ++umount /etc/nsswitch.conf ++ ++mount --bind ./nsswitch1.conf /etc/nsswitch.conf ++mount --bind ./empty /etc/subuid ++ ++cleanup2() { ++ umount /etc/subuid ++ umount /etc/nsswitch.conf ++} ++trap cleanup2 EXIT HUP INT TERM ++../../../src/check_subid_range user1 u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++ ++echo "check_range tests complete" ++exit 0 +diff -up shadow-4.6/tests/run_some.libsubid_nsswitch_support shadow-4.6/tests/run_some +--- shadow-4.6/tests/run_some.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/tests/run_some 2021-10-19 13:16:21.991493347 +0200 +@@ -123,6 +123,7 @@ run_test ./su/13_su_child_success/su.tes + run_test ./libsubid/01_list_ranges/list_ranges.test + run_test ./libsubid/02_get_subid_owners/get_subid_owners.test + run_test ./libsubid/03_add_remove/add_remove_subids.test ++run_test ./libsubid/04_nss/subidnss.test + + echo + echo "$succeeded test(s) passed" diff --git a/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch b/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch new file mode 100644 index 0000000..4cd848b --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch @@ -0,0 +1,264 @@ +diff -up shadow-4.8.1/configure.ac.libsubid_simplify_ranges_variable shadow-4.8.1/configure.ac +--- shadow-4.8.1/configure.ac.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.165917066 +0200 ++++ shadow-4.8.1/configure.ac 2021-05-24 15:02:56.184917324 +0200 +@@ -1,6 +1,6 @@ + dnl Process this file with autoconf to produce a configure script. + AC_PREREQ([2.69]) +-m4_define([libsubid_abi_major], 2) ++m4_define([libsubid_abi_major], 3) + m4_define([libsubid_abi_minor], 0) + m4_define([libsubid_abi_micro], 0) + m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) +diff -up shadow-4.8.1/lib/prototypes.h.libsubid_simplify_ranges_variable shadow-4.8.1/lib/prototypes.h +--- shadow-4.8.1/lib/prototypes.h.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.184917324 +0200 ++++ shadow-4.8.1/lib/prototypes.h 2021-05-24 16:38:57.610619467 +0200 +@@ -309,16 +309,15 @@ struct subid_nss_ops { + * + * @owner - string representing username being queried + * @id_type - subuid or subgid +- * @ranges - pointer to an array of struct subordinate_range pointers, or +- * NULL. The returned array of struct subordinate_range and its +- * members must be freed by the caller. ++ * @ranges - pointer to an array of struct subid_range, or NULL. The ++ * returned array must be freed by the caller. + * @count - pointer to an integer into which the number of returned ranges + * is written. + + * returns success if the module was able to determine an answer, + * else an error status. + */ +- enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges, int *count); ++ enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subid_range **ranges, int *count); + + /* + * nss_find_subid_owners: find uids who own a given subuid or subgid. +diff -up shadow-4.8.1/libsubid/api.c.libsubid_simplify_ranges_variable shadow-4.8.1/libsubid/api.c +--- shadow-4.8.1/libsubid/api.c.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.467989079 +0200 ++++ shadow-4.8.1/libsubid/api.c 2021-05-24 16:42:32.091584531 +0200 +@@ -68,26 +68,21 @@ bool libsubid_init(const char *progname, + } + + static +-int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) ++int get_subid_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges) + { + return list_owner_ranges(owner, id_type, ranges); + } + +-int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges) ++int get_subuid_ranges(const char *owner, struct subid_range **ranges) + { + return get_subid_ranges(owner, ID_TYPE_UID, ranges); + } + +-int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges) ++int get_subgid_ranges(const char *owner, struct subid_range **ranges) + { + return get_subid_ranges(owner, ID_TYPE_GID, ranges); + } + +-void subid_free_ranges(struct subordinate_range **ranges, int count) +-{ +- return free_subordinate_ranges(ranges, count); +-} +- + static + int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner) + { +diff -up shadow-4.8.1/libsubid/subid.h.libsubid_simplify_ranges_variable shadow-4.8.1/libsubid/subid.h +--- shadow-4.8.1/libsubid/subid.h.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.468989093 +0200 ++++ shadow-4.8.1/libsubid/subid.h 2021-05-24 16:43:49.697657383 +0200 +@@ -3,6 +3,15 @@ + + #ifndef SUBID_RANGE_DEFINED + #define SUBID_RANGE_DEFINED 1 ++ ++/* subid_range is just a starting point and size of a range */ ++struct subid_range { ++ unsigned long start; ++ unsigned long count; ++}; ++ ++/* subordinage_range is a subid_range plus an owner, representing ++ * a range in /etc/subuid or /etc/subgid */ + struct subordinate_range { + const char *owner; + unsigned long start; +@@ -41,32 +50,27 @@ bool libsubid_init(const char *progname, + * get_subuid_ranges: return a list of UID ranges for a user + * + * @owner: username being queried +- * @ranges: a pointer to a subordinate range ** in which the result will be +- * returned. ++ * @ranges: a pointer to an array of subid_range structs in which the result ++ * will be returned. ++ * ++ * The caller must free(ranges) when done. + * + * returns: number of ranges found, ir < 0 on error. + */ +-int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges); ++int get_subuid_ranges(const char *owner, struct subid_range **ranges); + + /* + * get_subgid_ranges: return a list of GID ranges for a user + * + * @owner: username being queried +- * @ranges: a pointer to a subordinate range ** in which the result will be +- * returned. ++ * @ranges: a pointer to an array of subid_range structs in which the result ++ * will be returned. + * +- * returns: number of ranges found, ir < 0 on error. +- */ +-int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges); +- +-/* +- * subid_free_ranges: free an array of subordinate_ranges returned by either +- * get_subuid_ranges() or get_subgid_ranges(). ++ * The caller must free(ranges) when done. + * +- * @ranges: the ranges to free +- * @count: the number of ranges in @ranges ++ * returns: number of ranges found, ir < 0 on error. + */ +-void subid_free_ranges(struct subordinate_range **ranges, int count); ++int get_subgid_ranges(const char *owner, struct subid_range **ranges); + + /* + * get_subuid_owners: return a list of uids to which the given uid has been +diff -up shadow-4.8.1/lib/subordinateio.c.libsubid-simplify shadow-4.8.1/lib/subordinateio.c +--- shadow-4.8.1/lib/subordinateio.c.libsubid-simplify 2021-05-24 17:27:38.721035241 +0200 ++++ shadow-4.8.1/lib/subordinateio.c 2021-05-24 17:28:06.481420946 +0200 +@@ -11,6 +11,7 @@ + #include + #include "commonio.h" + #include "subordinateio.h" ++#include "../libsubid/subid.h" + #include + #include + #include +@@ -308,25 +309,21 @@ static bool have_range(struct commonio_d + return false; + } + +-static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n) ++static bool append_range(struct subid_range **ranges, const struct subordinate_range *new, int n) + { +- struct subordinate_range *tmp; + if (!*ranges) { +- *ranges = malloc(sizeof(struct subordinate_range *)); ++ *ranges = malloc(sizeof(struct subid_range)); + if (!*ranges) + return false; + } else { +- struct subordinate_range **new; +- new = realloc(*ranges, (n + 1) * (sizeof(struct subordinate_range *))); +- if (!new) ++ struct subid_range *alloced; ++ alloced = realloc(*ranges, (n + 1) * (sizeof(struct subid_range))); ++ if (!alloced) + return false; +- *ranges = new; ++ *ranges = alloced; + } +- (*ranges)[n] = NULL; +- tmp = subordinate_dup(new); +- if (!tmp) +- return false; +- (*ranges)[n] = tmp; ++ (*ranges)[n].start = new->start; ++ (*ranges)[n].count = new->count; + return true; + } + +@@ -785,10 +782,10 @@ gid_t sub_gid_find_free_range(gid_t min, + * + * The caller must free the subordinate range list. + */ +-int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges) ++int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **in_ranges) + { + // TODO - need to handle owner being either uid or username +- struct subordinate_range **ranges = NULL; ++ struct subid_range *ranges = NULL; + const struct subordinate_range *range; + struct commonio_db *db; + enum subid_status status; +@@ -826,7 +823,7 @@ int list_owner_ranges(const char *owner, + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { + if (!append_range(&ranges, range, count++)) { +- free_subordinate_ranges(ranges, count-1); ++ free(ranges); + ranges = NULL; + count = -1; + goto out; +diff -up shadow-4.8.1/lib/subordinateio.h.libsubid_simplify_ranges_variable shadow-4.8.1/lib/subordinateio.h +--- shadow-4.8.1/lib/subordinateio.h.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.467989079 +0200 ++++ shadow-4.8.1/lib/subordinateio.h 2021-05-24 16:40:56.978269647 +0200 +@@ -25,7 +25,7 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); +-extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges); ++extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges); + extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); + extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); + extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids); +diff -up shadow-4.8.1/src/list_subid_ranges.c.libsubid_simplify_ranges_variable shadow-4.8.1/src/list_subid_ranges.c +--- shadow-4.8.1/src/list_subid_ranges.c.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.468989093 +0200 ++++ shadow-4.8.1/src/list_subid_ranges.c 2021-05-24 16:45:10.884779740 +0200 +@@ -17,27 +17,29 @@ void usage(void) + int main(int argc, char *argv[]) + { + int i, count=0; +- struct subordinate_range **ranges; ++ struct subid_range *ranges; ++ const char *owner; + + Prog = Basename (argv[0]); + shadow_logfd = stderr; +- if (argc < 2) { ++ if (argc < 2) + usage(); +- } +- if (argc == 3 && strcmp(argv[1], "-g") == 0) +- count = get_subgid_ranges(argv[2], &ranges); +- else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ owner = argv[1]; ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) { ++ owner = argv[2]; ++ count = get_subgid_ranges(owner, &ranges); ++ } else if (argc == 2 && strcmp(argv[1], "-h") == 0) { + usage(); +- else +- count = get_subuid_ranges(argv[1], &ranges); ++ } else { ++ count = get_subuid_ranges(owner, &ranges); ++ } + if (!ranges) { + fprintf(stderr, "Error fetching ranges\n"); + exit(1); + } + for (i = 0; i < count; i++) { +- printf("%d: %s %lu %lu\n", i, ranges[i]->owner, +- ranges[i]->start, ranges[i]->count); ++ printf("%d: %s %lu %lu\n", i, owner, ++ ranges[i].start, ranges[i].count); + } +- subid_free_ranges(ranges, count); + return 0; + } +diff -up shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_simplify_ranges_variable shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c +--- shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.166917079 +0200 ++++ shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c 2021-05-24 15:03:01.469989106 +0200 +@@ -113,7 +113,7 @@ enum subid_status shadow_subid_list_owne + if (strcmp(owner, "conn") == 0) + return SUBID_STATUS_ERROR_CONN; + +- *ranges = NULL; ++ *in_ranges = NULL; + if (strcmp(owner, "user1") != 0 && strcmp(owner, "ubuntu") != 0 && + strcmp(owner, "group1") != 0) + return SUBID_STATUS_SUCCESS; diff --git a/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch b/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch new file mode 100644 index 0000000..e26cfa7 --- /dev/null +++ b/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch @@ -0,0 +1,44 @@ +From 186b1b7ac1a68d0fcc618a22da1a99232b420911 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 4 May 2021 14:39:26 -0500 +Subject: [PATCH] manpages: mention NSS in new[ug]idmap manpages + +Closes #328 + +Signed-off-by: Serge Hallyn +--- + man/newgidmap.1.xml | 3 ++- + man/newuidmap.1.xml | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/man/newgidmap.1.xml b/man/newgidmap.1.xml +index 71b03e56..76fc1e30 100644 +--- a/man/newgidmap.1.xml ++++ b/man/newgidmap.1.xml +@@ -88,7 +88,8 @@ + DESCRIPTION + + The newgidmap sets /proc/[pid]/gid_map based on its +- command line arguments and the gids allowed in /etc/subgid. ++ command line arguments and the gids allowed (either in /etc/subgid or ++ through the configured NSS subid module). + Note that the root user is not exempted from the requirement for a valid + /etc/subgid entry. + +diff --git a/man/newuidmap.1.xml b/man/newuidmap.1.xml +index a6f1f085..44eca50a 100644 +--- a/man/newuidmap.1.xml ++++ b/man/newuidmap.1.xml +@@ -88,7 +88,8 @@ + DESCRIPTION + + The newuidmap sets /proc/[pid]/uid_map based on its +- command line arguments and the uids allowed in /etc/subuid. ++ command line arguments and the uids allowed (either in /etc/subuid or ++ through the configured NSS subid module). + Note that the root user is not exempted from the requirement for a valid + /etc/subuid entry. + +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch b/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch new file mode 100644 index 0000000..47d4d46 --- /dev/null +++ b/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch @@ -0,0 +1,166 @@ +diff -up shadow-4.6/man/newgidmap.1.xml.man_clarify_subid_delegation shadow-4.6/man/newgidmap.1.xml +--- shadow-4.6/man/newgidmap.1.xml.man_clarify_subid_delegation 2021-11-03 09:58:34.176484342 +0100 ++++ shadow-4.6/man/newgidmap.1.xml 2021-11-03 09:58:34.191484452 +0100 +@@ -80,10 +80,15 @@ + + DESCRIPTION + +- The newgidmap sets /proc/[pid]/gid_map based on its +- command line arguments and the gids allowed (either in /etc/subgid or +- through the configured NSS subid module). +- Note that the root user is not exempted from the requirement for a valid ++ The newgidmap sets /proc/[pid]/gid_map ++ based on its command line arguments and the gids allowed. Subgid ++ delegation can either be managed via /etc/subgid ++ or through the configured NSS subid module. These options are mutually ++ exclusive. ++ ++ ++ ++ Note that the root group is not exempted from the requirement for a valid + /etc/subgid entry. + + +diff -up shadow-4.6/man/newuidmap.1.xml.man_clarify_subid_delegation shadow-4.6/man/newuidmap.1.xml +--- shadow-4.6/man/newuidmap.1.xml.man_clarify_subid_delegation 2021-11-03 09:58:34.176484342 +0100 ++++ shadow-4.6/man/newuidmap.1.xml 2021-11-03 09:58:34.191484452 +0100 +@@ -80,9 +80,14 @@ + + DESCRIPTION + +- The newuidmap sets /proc/[pid]/uid_map based on its +- command line arguments and the uids allowed (either in /etc/subuid or +- through the configured NSS subid module). ++ The newuidmap sets /proc/[pid]/uid_map ++ based on its command line arguments and the uids allowed. Subuid ++ delegation can either be managed via /etc/subuid or ++ through the configured NSS subid module. These options are mutually ++ exclusive. ++ ++ ++ + Note that the root user is not exempted from the requirement for a valid + /etc/subuid entry. + +diff -up shadow-4.6/man/subgid.5.xml.man_clarify_subid_delegation shadow-4.6/man/subgid.5.xml +--- shadow-4.6/man/subgid.5.xml.man_clarify_subid_delegation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/subgid.5.xml 2021-11-03 09:59:55.752084920 +0100 +@@ -32,6 +32,18 @@ + + ]> + ++ ++ ++ Eric ++ Biederman ++ Creation, 2013 ++ ++ ++ Iker ++ Pedrosa ++ Developer, 2021 ++ ++ + + subgid + 5 +@@ -41,12 +53,37 @@ + + + subgid +- the subordinate gid file ++ the configuration for subordinate group ids + + + + DESCRIPTION + ++ Subgid authorizes a group id to map ranges of group ids from its namespace ++ into child namespaces. ++ ++ ++ The delegation of the subordinate gids can be configured via the ++ subid field in ++ /etc/nsswitch.conf file. Only one value can be set ++ as the delegation source. Setting this field to ++ files configures the delegation of gids to ++ /etc/subgid. Setting any other value treats ++ the delegation as a plugin following with a name of the form ++ libsubid_$value.so. If the value or plugin is ++ missing, then the subordinate gid delegation falls back to ++ files. ++ ++ ++ Note, that groupadd will only create entries in ++ /etc/subgid if subid delegation is managed via subid ++ files. ++ ++ ++ ++ ++ LOCAL SUBORDINATE DELEGATION ++ + Each line in /etc/subgid contains + a user name and a range of subordinate group ids that user + is allowed to use. +diff -up shadow-4.6/man/subuid.5.xml.man_clarify_subid_delegation shadow-4.6/man/subuid.5.xml +--- shadow-4.6/man/subuid.5.xml.man_clarify_subid_delegation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/subuid.5.xml 2021-11-03 10:00:18.888255255 +0100 +@@ -32,6 +32,18 @@ + + ]> + ++ ++ ++ Eric ++ Biederman ++ Creation, 2013 ++ ++ ++ Iker ++ Pedrosa ++ Developer, 2021 ++ ++ + + subuid + 5 +@@ -41,12 +53,37 @@ + + + subuid +- the subordinate uid file ++ the configuration for subordinate user ids + + + + DESCRIPTION + ++ Subuid authorizes a user id to map ranges of user ids from its namespace ++ into child namespaces. ++ ++ ++ The delegation of the subordinate uids can be configured via the ++ subid field in ++ /etc/nsswitch.conf file. Only one value can be set ++ as the delegation source. Setting this field to ++ files configures the delegation of uids to ++ /etc/subuid. Setting any other value treats ++ the delegation as a plugin following with a name of the form ++ libsubid_$value.so. If the value or plugin is ++ missing, then the subordinate uid delegation falls back to ++ files. ++ ++ ++ Note, that useradd will only create entries in ++ /etc/subuid if subid delegation is managed via subid ++ files. ++ ++ ++ ++ ++ LOCAL SUBORDINATE DELEGATION ++ + Each line in /etc/subuid contains + a user name and a range of subordinate user ids that user + is allowed to use. diff --git a/SOURCES/shadow-4.6-respect_enable_static_no.patch b/SOURCES/shadow-4.6-respect_enable_static_no.patch new file mode 100644 index 0000000..ed62a08 --- /dev/null +++ b/SOURCES/shadow-4.6-respect_enable_static_no.patch @@ -0,0 +1,24 @@ +diff -up shadow-4.6/configure.ac.respect_enable_static_no shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.respect_enable_static_no 2021-11-03 12:09:39.852829632 +0100 ++++ shadow-4.6/configure.ac 2021-11-03 12:10:32.447203434 +0100 +@@ -311,6 +311,8 @@ if test "$with_sha_crypt" = "yes"; then + AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms]) + fi + ++AM_CONDITIONAL(ENABLE_SHARED, test "x$enable_shared" = "xyes") ++ + if test "$with_nscd" = "yes"; then + AC_CHECK_FUNC(posix_spawn, + [AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])], +diff -up shadow-4.6/libsubid/Makefile.am.respect_enable_static_no shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.respect_enable_static_no 2021-11-03 12:09:39.851829625 +0100 ++++ shadow-4.6/libsubid/Makefile.am 2021-11-03 12:09:39.852829632 +0100 +@@ -1,6 +1,8 @@ + lib_LTLIBRARIES = libsubid.la ++if ENABLE_SHARED + libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ + -shared -version-info @LIBSUBID_ABI_MAJOR@ ++endif + libsubid_la_SOURCES = api.c + + pkginclude_HEADERS = subid.h diff --git a/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch b/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch new file mode 100644 index 0000000..f393368 --- /dev/null +++ b/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch @@ -0,0 +1,44 @@ +From 663824ef4ca927aa2b4319b69e0bfa68282ec719 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Sat, 22 May 2021 11:42:02 -0500 +Subject: [PATCH] Fix useradd with SUB_UID_COUNT=0 + +Closes #298 + +Fix useradd when SUB_UID_COUNT=0 in login.defs. + +Signed-off-by: Serge Hallyn +--- + src/useradd.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/useradd.c b/src/useradd.c +index 06accb2f..9862ae55 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -2386,6 +2386,8 @@ int main (int argc, char **argv) + #ifdef ENABLE_SUBIDS + uid_t uid_min; + uid_t uid_max; ++ unsigned long subuid_count; ++ unsigned long subgid_count; + #endif + + /* +@@ -2427,9 +2429,11 @@ int main (int argc, char **argv) + #ifdef ENABLE_SUBIDS + uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL); + uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL); +- is_sub_uid = sub_uid_file_present () && !rflg && ++ subuid_count = getdef_ulong ("SUB_UID_COUNT", 65536); ++ subgid_count = getdef_ulong ("SUB_GID_COUNT", 65536); ++ is_sub_uid = subuid_count > 0 && sub_uid_file_present () && !rflg && + (!user_id || (user_id <= uid_max && user_id >= uid_min)); +- is_sub_gid = sub_gid_file_present () && !rflg && ++ is_sub_gid = subgid_count > 0 && sub_gid_file_present () && !rflg && + (!user_id || (user_id <= uid_max && user_id >= uid_min)); + #endif /* ENABLE_SUBIDS */ + +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch b/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch new file mode 100644 index 0000000..a53d724 --- /dev/null +++ b/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch @@ -0,0 +1,21 @@ +diff -up shadow-4.6/src/useradd.c.useradd_dont_try_to_create_0_subuids shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.useradd_dont_try_to_create_0_subuids 2021-11-03 11:55:00.189562187 +0100 ++++ shadow-4.6/src/useradd.c 2021-11-03 11:57:34.128658978 +0100 +@@ -2350,7 +2350,7 @@ int main (int argc, char **argv) + } + + #ifdef ENABLE_SUBIDS +- if (is_sub_uid) { ++ if (is_sub_uid && subuid_count != 0) { + if (find_new_sub_uids(user_name, &sub_uid_start, &sub_uid_count) < 0) { + fprintf (stderr, + _("%s: can't create subordinate user IDs\n"), +@@ -2358,7 +2358,7 @@ int main (int argc, char **argv) + fail_exit(E_SUB_UID_UPDATE); + } + } +- if (is_sub_gid) { ++ if (is_sub_gid && subgid_count != 0) { + if (find_new_sub_gids(user_name, &sub_gid_start, &sub_gid_count) < 0) { + fprintf (stderr, + _("%s: can't create subordinate group IDs\n"), diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec index 4a66b18..8426b53 100644 --- a/SPECS/shadow-utils.spec +++ b/SPECS/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.6 -Release: 14%{?dist} +Release: 16%{?dist} Epoch: 2 URL: http://pkg-shadow.alioth.debian.org/ Source0: https://github.com/shadow-maint/shadow/releases/download/%{version}/shadow-%{version}.tar.xz @@ -10,6 +10,11 @@ Source2: shadow-utils.useradd Source3: shadow-utils.login.defs Source4: shadow-bsd.txt Source5: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +### Globals ### +%global includesubiddir %{_includedir}/shadow + +### Patches ### Patch0: shadow-4.6-redhat.patch Patch1: shadow-4.6-goodname.patch Patch2: shadow-4.1.5.1-info-parent-dir.patch @@ -49,6 +54,44 @@ Patch45: shadow-4.6-sssd-redirect-warning.patch Patch46: shadow-4.6-remove-login-string-references.patch # https://github.com/shadow-maint/shadow/commit/e481437ab9ebe9a8bf8fbaabe986d42b2f765991 Patch47: shadow-4.6-usermod-allow-all-group-types.patch +# https://github.com/shadow-maint/shadow/commit/0a7888b1fad613a052b988b01a71933b67296e68 +# https://github.com/shadow-maint/shadow/commit/607f1dd549cf9abc87af1cf29275f0d2d11eea29 +# https://github.com/shadow-maint/shadow/commit/b5fb1b38eea2fb0489ed088c82daf6700e72363e +# https://github.com/shadow-maint/shadow/commit/43a917cce54019799a8de037fd63780a2b640afc +Patch48: shadow-4.6-libsubid_creation.patch +# https://github.com/shadow-maint/shadow/commit/514c1328b6c90d817ae0a9f7addfb3c9a11a275a +# https://github.com/shadow-maint/shadow/commit/8492dee6632e340dee76eee895c3e30877bebf45 +# https://github.com/shadow-maint/shadow/commit/0f4347d1483191b2142546416a9eefe0c9459600 +Patch49: shadow-4.6-libsubid_nsswitch_support.patch +# https://github.com/shadow-maint/shadow/commit/186b1b7ac1a68d0fcc618a22da1a99232b420911 +Patch50: shadow-4.6-man-mention-nss-in-newuidmap.patch +# https://github.com/shadow-maint/shadow/commit/f9831a4a1a20b0e8fe47cc72ec20018ec04dbb90 +Patch51: shadow-4.6-libsubid_not_print_error_messages.patch +# https://github.com/shadow-maint/shadow/commit/c6cab4a7bafa18d9d65a333cac1261e7b5e32bc9 +Patch52: shadow-4.6-libsubid_init_return_false.patch +# https://github.com/shadow-maint/shadow/commit/2f1f45d64fc7c10e7a3cbe00e89f63714343e526 +Patch53: shadow-4.6-useradd_SUB_UID_COUNT-0.patch +# https://github.com/shadow-maint/shadow/commit/ea7af4e1543c63590d4107ae075fea385028997d +Patch54: shadow-4.6-libsubid_simplify_ranges_variable.patch +# https://github.com/shadow-maint/shadow/commit/0fe42f571c69f0105d31305f995c9887aeb9525e +Patch55: shadow-4.6-libsubid_init_not_print_error_messages.patch +# https://github.com/shadow-maint/shadow/commit/ec1951c181faed188464396b2cfdd2efb726c7f3 +Patch56: shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch +# https://github.com/shadow-maint/shadow/commit/087112244327be50abc24f9ec8afbf60ae8b2dec +# https://github.com/shadow-maint/shadow/pull/353 +Patch57: shadow-4.6-man_clarify_subid_delegation.patch +# https://github.com/shadow-maint/shadow/commit/bd920ab36a6c641e4a8769f8c7f8ca738ec61820 +Patch58: shadow-4.6-libsubid_make_logfd_not_extern.patch +# https://github.com/shadow-maint/shadow/commit/0dffc7c61200f492eeac03c29fa7e93b62d3cead +Patch59: shadow-4.6-useradd_dont_try_to_create_0_subuids.patch +# https://github.com/shadow-maint/shadow/commit/77e39de1e6cbd6925f16bb260abb7d216296886b +Patch60: shadow-4.6-install_subid_h.patch +# https://github.com/shadow-maint/shadow/commit/fa986b1d73605ecca54a4f19249227aeab827bf6 +Patch61: shadow-4.6-respect_enable_static_no.patch +# https://github.com/shadow-maint/shadow/commit/3b6ccf642c6bb2b7db087f09ee563ae9318af734 +Patch62: shadow-4.6-getsubids.patch +# https://github.com/shadow-maint/shadow/commit/a757b458ffb4fb9a40bcbb4f7869449431c67f83 +Patch63: shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch License: BSD and GPLv2+ Group: System Environment/Base @@ -79,6 +122,23 @@ for all users. The useradd, userdel, and usermod commands are used for managing user accounts. The groupadd, groupdel, and groupmod commands are used for managing group accounts. + +### Subpackages ### +%package subid +Summary: A library to manage subordinate uid and gid ranges +License: BSD and GPLv2+ + +%description subid +Utility library that provides a way to manage subid ranges. + + +%package subid-devel +Summary: Development package for shadow-utils-subid +License: BSD and GPLv2+ + +%description subid-devel +Development files for shadow-utils-subid. + %prep %setup -q -n shadow-%{version} %patch0 -p1 -b .redhat @@ -114,6 +174,22 @@ are used for managing group accounts. %patch45 -p1 -b .sssd-redirect-warning %patch46 -p1 -b .remove-login-string-references %patch47 -p1 -b .usermod-allow-all-group-types +%patch48 -p1 -b .libsubid_creation +%patch49 -p1 -b .libsubid_nsswitch_support +%patch50 -p1 -b .man-mention-nss-in-newuidmap +%patch51 -p1 -b .libsubid_not_print_error_messages +%patch52 -p1 -b .libsubid_init_return_false +%patch53 -p1 -b .useradd_SUB_UID_COUNT-0 +%patch54 -p1 -b .libsubid_simplify_ranges_variable +%patch55 -p1 -b .libsubid_init_not_print_error_messages +%patch56 -p1 -b .libsubid_fix_newusers_nss_provides_subids +%patch57 -p1 -b .man_clarify_subid_delegation +%patch58 -p1 -b .libsubid_make_logfd_not_extern +%patch59 -p1 -b .useradd_dont_try_to_create_0_subuids +%patch60 -p1 -b .install_subid_h +%patch61 -p1 -b .respect_enable_static_no +%patch62 -p1 -b .getsubids +%patch63 -p1 -b .groupdel-fix-sigsegv-when-passwd-does-not-exist iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -142,7 +218,7 @@ autoreconf --with-selinux \ --without-libcrack \ --without-libpam \ - --disable-shared \ + --enable-shared \ --with-group-name-max-length=32 %make_build @@ -218,6 +294,13 @@ for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do echo "%%lang($lang) $dir/man*/*" >> shadow.lang done +# Move header files to its own folder +mkdir -p $RPM_BUILD_ROOT/%{includesubiddir} +install -m 644 libsubid/subid.h $RPM_BUILD_ROOT/%{includesubiddir}/ + +# Remove .la files created by libsubid +rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.la + %files -f shadow.lang %doc NEWS doc/HOWTO README %{!?_licensedir:%global license %%doc} @@ -267,7 +350,33 @@ done %{_mandir}/man8/vipw.8* %{_mandir}/man8/vigr.8* +%files subid +%{_libdir}/libsubid.so.* +%{_bindir}/getsubids +%{_mandir}/man1/getsubids.1* + +%files subid-devel +%{includesubiddir}/subid.h +%{_libdir}/libsubid.so + %changelog +* Thu Dec 9 2021 Iker Pedrosa - 2:4.6-16 +- getsubids: provide system binary and man page. Resolves: #2013016 +- groupdel: fix SIGSEGV when passwd does not exist. Resolves: #1986782 + +* Tue Oct 19 2021 Iker Pedrosa - 2:4.6-15 +- Creation of subid and subid-devel subpackages (#2013009) +- libsubid: creation and nsswitch support +- libsubid: don't print error messages on stderr by default +- libsubid: libsubid_init return false if out of memory +- libsubid: don't return owner in list_owner_ranges API call +- libsubid: libsubid_init don't print messages on error +- libsubid: fix newusers when nss provides subids +- libsubid: make shadow_logfd not extern +- useradd: fix SUB_UID_COUNT=0 +- man: mention NSS in new[ug]idmap manpages +- man: clarify subid delegation + * Thu Aug 12 2021 Iker Pedrosa - 2:4.6-14 - usermod: allow all group types with -G option (#1967641)