diff --git a/assert-pedantic.patch b/assert-pedantic.patch new file mode 100644 index 0000000..4d7c9d1 --- /dev/null +++ b/assert-pedantic.patch @@ -0,0 +1,192 @@ +2017-08-21 Florian Weimer + + [BZ #21972] + * assert/assert.h (assert): Use static_cast (bool) for C++. + Use the ternary operator in the warning branch for GNU C. + * assert/Makefile (tests): Add tst-assert-c++, tst-assert-g++. + (CFLAGS-tst-assert-c++.o): Compile in C++11 mode. + (CFLAGS-tst-assert-g++.o): Compile in GnU C++11 mode. + (LDLIBS-tst-assert-c++, LDLIBS-tst-assert-g++): Link with libstdc++. + * assert/tst-assert-c++.cc, assert/tst-assert-g++.cc: New files. + +2017-08-11 Florian Weimer + + [BZ #21242] + * assert/assert.h [__GNUC__ && !__STRICT_ANSI__] (assert): + Suppress pedantic warning resulting from statement expression. + (__ASSERT_FUNCTION): Add missing __extension__. + +Index: glibc-2.26/assert/Makefile +=================================================================== +--- glibc-2.26.orig/assert/Makefile ++++ glibc-2.26/assert/Makefile +@@ -25,6 +25,15 @@ include ../Makeconfig + headers := assert.h + + routines := assert assert-perr __assert +-tests := test-assert test-assert-perr ++tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++ + + include ../Rules ++ ++ifeq ($(have-cxx-thread_local),yes) ++CFLAGS-tst-assert-c++.o = -std=c++11 ++LDLIBS-tst-assert-c++ = -lstdc++ ++CFLAGS-tst-assert-g++.o = -std=gnu++11 ++LDLIBS-tst-assert-g++ = -lstdc++ ++else ++tests-unsupported += tst-assert-c++ tst-assert-g++ ++endif +Index: glibc-2.26/assert/assert.h +=================================================================== +--- glibc-2.26.orig/assert/assert.h ++++ glibc-2.26/assert/assert.h +@@ -85,19 +85,29 @@ __END_DECLS + /* When possible, define assert so that it does not add extra + parentheses around EXPR. Otherwise, those added parentheses would + suppress warnings we'd expect to be detected by gcc's -Wparentheses. */ +-# if !defined __GNUC__ || defined __STRICT_ANSI__ ++# if defined __cplusplus ++# define assert(expr) \ ++ (static_cast (expr) \ ++ ? void (0) \ ++ : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) ++# elif !defined __GNUC__ || defined __STRICT_ANSI__ + # define assert(expr) \ + ((expr) \ + ? __ASSERT_VOID_CAST (0) \ + : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) + # else ++/* The first occurrence of EXPR is not evaluated due to the sizeof, ++ but will trigger any pedantic warnings masked by the __extension__ ++ for the second occurrence. The ternary operator is required to ++ support function pointers and bit fields in this context, and to ++ suppress the evaluation of variable length arrays. */ + # define assert(expr) \ +- ({ \ ++ ((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \ + if (expr) \ + ; /* empty */ \ + else \ + __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION); \ +- }) ++ })) + # endif + + # ifdef __USE_GNU +@@ -113,7 +123,7 @@ __END_DECLS + C9x has a similar variable called __func__, but prefer the GCC one since + it demangles C++ function names. */ + # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4) +-# define __ASSERT_FUNCTION __PRETTY_FUNCTION__ ++# define __ASSERT_FUNCTION __extension__ __PRETTY_FUNCTION__ + # else + # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + # define __ASSERT_FUNCTION __func__ +Index: glibc-2.26/assert/tst-assert-c++.cc +=================================================================== +--- /dev/null ++++ glibc-2.26/assert/tst-assert-c++.cc +@@ -0,0 +1,78 @@ ++/* Tests for interactions between C++ and assert. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++/* The C++ standard requires that if the assert argument is a constant ++ subexpression, then the assert itself is one, too. */ ++constexpr int ++check_constexpr () ++{ ++ return (assert (true), 1); ++} ++ ++/* Objects of this class can be contextually converted to bool, but ++ cannot be compared to int. */ ++struct no_int ++{ ++ no_int () = default; ++ no_int (const no_int &) = delete; ++ ++ explicit operator bool () const ++ { ++ return true; ++ } ++ ++ bool operator! () const; /* No definition. */ ++ template bool operator== (T) const; /* No definition. */ ++ template bool operator!= (T) const; /* No definition. */ ++}; ++ ++/* This class tests that operator== is not used by assert. */ ++struct bool_and_int ++{ ++ bool_and_int () = default; ++ bool_and_int (const no_int &) = delete; ++ ++ explicit operator bool () const ++ { ++ return true; ++ } ++ ++ bool operator! () const; /* No definition. */ ++ template bool operator== (T) const; /* No definition. */ ++ template bool operator!= (T) const; /* No definition. */ ++}; ++ ++static int ++do_test () ++{ ++ { ++ no_int value; ++ assert (value); ++ } ++ ++ { ++ bool_and_int value; ++ assert (value); ++ } ++ ++ return 0; ++} ++ ++#include +Index: glibc-2.26/assert/tst-assert-g++.cc +=================================================================== +--- /dev/null ++++ glibc-2.26/assert/tst-assert-g++.cc +@@ -0,0 +1,19 @@ ++/* Tests for interactions between C++ and assert. GNU C++11 version. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include diff --git a/dynarray-allocation.patch b/dynarray-allocation.patch new file mode 100644 index 0000000..a67b56e --- /dev/null +++ b/dynarray-allocation.patch @@ -0,0 +1,127 @@ +2017-08-30 Florian Weimer + + * malloc/dynarray_emplace_enlarge.c + (__libc_dynarray_emplace_enlarge): Set errno on overflow. + * malloc/dynarray_resize.c (__libc_dynarray_resize): Likewise. + * malloc/tst-dynarray.c (test_long_overflow): New function. + (do_test): Call it. + +2017-09-06 Florian Weimer + + * malloc/dynarray_emplace_enlarge.c + (__libc_dynarray_emplace_enlarge): Add missing else. + +Index: glibc-2.26/malloc/dynarray_emplace_enlarge.c +=================================================================== +--- glibc-2.26.orig/malloc/dynarray_emplace_enlarge.c ++++ glibc-2.26/malloc/dynarray_emplace_enlarge.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + #include +@@ -32,7 +33,7 @@ __libc_dynarray_emplace_enlarge (struct + size. */ + if (element_size < 4) + new_allocated = 16; +- if (element_size < 8) ++ else if (element_size < 8) + new_allocated = 8; + else + new_allocated = 4; +@@ -43,8 +44,11 @@ __libc_dynarray_emplace_enlarge (struct + { + new_allocated = list->allocated + list->allocated / 2 + 1; + if (new_allocated <= list->allocated) +- /* Overflow. */ +- return false; ++ { ++ /* Overflow. */ ++ __set_errno (ENOMEM); ++ return false; ++ } + } + + size_t new_size; +Index: glibc-2.26/malloc/dynarray_resize.c +=================================================================== +--- glibc-2.26.orig/malloc/dynarray_resize.c ++++ glibc-2.26/malloc/dynarray_resize.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + #include +@@ -38,7 +39,11 @@ __libc_dynarray_resize (struct dynarray_ + + size_t new_size_bytes; + if (check_mul_overflow_size_t (size, element_size, &new_size_bytes)) +- return false; ++ { ++ /* Overflow. */ ++ __set_errno (ENOMEM); ++ return false; ++ } + void *new_array; + if (list->array == scratch) + { +Index: glibc-2.26/malloc/tst-dynarray.c +=================================================================== +--- glibc-2.26.orig/malloc/tst-dynarray.c ++++ glibc-2.26/malloc/tst-dynarray.c +@@ -18,6 +18,9 @@ + + #include "tst-dynarray-shared.h" + ++#include ++#include ++ + #define DYNARRAY_STRUCT dynarray_long + #define DYNARRAY_ELEMENT long + #define DYNARRAY_PREFIX dynarray_long_ +@@ -463,6 +466,31 @@ test_long_init (void) + } + } + ++/* Test overflow in resize. */ ++static void ++test_long_overflow (void) ++{ ++ { ++ struct dynarray_long dyn; ++ dynarray_long_init (&dyn); ++ errno = EINVAL; ++ TEST_VERIFY (!dynarray_long_resize ++ (&dyn, (SIZE_MAX / sizeof (long)) + 1)); ++ TEST_VERIFY (errno == ENOMEM); ++ TEST_VERIFY (dynarray_long_has_failed (&dyn)); ++ } ++ ++ { ++ struct dynarray_long_noscratch dyn; ++ dynarray_long_noscratch_init (&dyn); ++ errno = EINVAL; ++ TEST_VERIFY (!dynarray_long_noscratch_resize ++ (&dyn, (SIZE_MAX / sizeof (long)) + 1)); ++ TEST_VERIFY (errno == ENOMEM); ++ TEST_VERIFY (dynarray_long_noscratch_has_failed (&dyn)); ++ } ++} ++ + /* Test NUL-terminated string construction with the add function and + the simple finalize function. */ + static void +@@ -538,6 +566,7 @@ do_test (void) + test_int (); + test_str (); + test_long_init (); ++ test_long_overflow (); + test_zstr (); + return 0; + } diff --git a/eh-frame-zero-terminator.patch b/eh-frame-zero-terminator.patch new file mode 100644 index 0000000..28a4c16 --- /dev/null +++ b/eh-frame-zero-terminator.patch @@ -0,0 +1,31 @@ +2017-08-31 H.J. Lu + + [BZ #22051] + * Makerules (build-module-helper-objlist): Filter out + $(elf-objpfx)sofini.os. + (build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is + needed. + +Index: glibc-2.26/Makerules +=================================================================== +--- glibc-2.26.orig/Makerules ++++ glibc-2.26/Makerules +@@ -686,14 +686,17 @@ $(build-module-helper) -o $@ $(shlib-lds + $(call after-link,$@) + endef + ++# sofini.os must be placed last since it terminates .eh_frame section. + build-module-helper-objlist = \ + $(patsubst %_pic.a,$(whole-archive) %_pic.a $(no-whole-archive),\ + $(filter-out %.lds $(map-file) $(+preinit) $(+postinit) \ ++ $(elf-objpfx)sofini.os \ + $(link-libc-deps),$^)) + + build-module-objlist = $(build-module-helper-objlist) $(LDLIBS-$(@F:%.so=%).so) + build-shlib-objlist = $(build-module-helper-objlist) \ +- $(LDLIBS-$(@F:lib%.so=%).so) ++ $(LDLIBS-$(@F:lib%.so=%).so) \ ++ $(filter $(elf-objpfx)sofini.os,$^) + + # Don't try to use -lc when making libc.so itself. + # Also omits crti.o and crtn.o, which we do not want diff --git a/getaddrinfo-errno.patch b/getaddrinfo-errno.patch new file mode 100644 index 0000000..9b05528 --- /dev/null +++ b/getaddrinfo-errno.patch @@ -0,0 +1,649 @@ +2017-09-01 Florian Weimer + + [BZ #21915] + [BZ #21922] + * sysdeps/posix/getaddrinfo.c (gethosts): Look at NSS function + result to determine success or failure, not the errno value. + * nss/Makefile (tests): Add tst-nss-files-hosts-erange. + (tst-nss-files-hosts-erange): Link with -ldl. + * nss/tst-nss-files-hosts-erange.c: New file. + * nss/tst-resolv-basic.c (response): Handle nodata.example. + (do_test): Add NO_DATA tests. + * resolv/tst-resolv-basic.c (test_nodata_nxdomain): New function. + (do_test): Call it. + +2017-09-01 Florian Weimer + + [BZ #21922] + * sysdeps/posix/getaddrinfo.c (gaih_inet): Report EAI_NODATA error + coming from gethostbyname2_r. + +2017-09-01 Florian Weimer + + * sysdeps/posix/getaddrinfo.c (gaih_inet): Only use h_errno if + status indicates it is set. + +2017-09-01 Florian Weimer + + * sysdeps/posix/getaddrinfo.c (gaih_inet): Make reporting of NSS + function lookup failures more reliable. + +2017-09-01 Florian Weimer + + * sysdeps/posix/getaddrinfo.c (gethosts): Use h_errno directly. + (getcanonname): Likewise. + (gaih_inet): Likewise. + +2017-09-01 Florian Weimer + + * sysdeps/posix/getaddrinfo.c (gethosts): Use errno directly. + (getcanonname): Likewise. + (gaih_inet): Likewise. + +2017-08-08 Florian Weimer + + * sysdeps/posix/getaddrinfo.c (gaih_inet): Remove unreachable + return statement. + +Index: glibc-2.26/nss/Makefile +=================================================================== +--- glibc-2.26.orig/nss/Makefile ++++ glibc-2.26/nss/Makefile +@@ -58,6 +58,11 @@ tests = test-netdb test-digits-dots ts + tst-nss-test5 + xtests = bug-erange + ++# Tests which need libdl ++ifeq (yes,$(build-shared)) ++tests += tst-nss-files-hosts-erange ++endif ++ + # If we have a thread library then we can test cancellation against + # some routines like getpwuid_r. + ifeq (yes,$(have-thread-library)) +@@ -154,3 +159,5 @@ $(patsubst %,$(objpfx)%.out,$(tests)) : + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) + endif ++ ++$(objpfx)tst-nss-files-hosts-erange: $(libdl) +Index: glibc-2.26/nss/tst-nss-files-hosts-erange.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/tst-nss-files-hosts-erange.c +@@ -0,0 +1,109 @@ ++/* Parse /etc/hosts in multi mode with a trailing long line (bug 21915). ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct support_chroot *chroot_env; ++ ++#define X10 "XXXXXXXXXX" ++#define X100 X10 X10 X10 X10 X10 X10 X10 X10 X10 X10 ++#define X1000 X100 X100 X100 X100 X100 X100 X100 X100 X100 X100 ++ ++static void ++prepare (int argc, char **argv) ++{ ++ chroot_env = support_chroot_create ++ ((struct support_chroot_configuration) ++ { ++ .resolv_conf = "", ++ .hosts = ++ "127.0.0.1 localhost localhost.localdomain\n" ++ "::1 localhost localhost.localdomain\n" ++ "192.0.2.1 example.com\n" ++ "#" X1000 X100 "\n", ++ .host_conf = "multi on\n", ++ }); ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ if (!support_can_chroot ()) ++ return EXIT_UNSUPPORTED; ++ ++ __nss_configure_lookup ("hosts", "files"); ++ if (dlopen (LIBNSS_FILES_SO, RTLD_LAZY) == NULL) ++ FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ()); ++ ++ xchroot (chroot_env->path_chroot); ++ ++ errno = ERANGE; ++ h_errno = NETDB_INTERNAL; ++ check_hostent ("gethostbyname example.com", ++ gethostbyname ("example.com"), ++ "name: example.com\n" ++ "address: 192.0.2.1\n"); ++ errno = ERANGE; ++ h_errno = NETDB_INTERNAL; ++ check_hostent ("gethostbyname2 AF_INET example.com", ++ gethostbyname2 ("example.com", AF_INET), ++ "name: example.com\n" ++ "address: 192.0.2.1\n"); ++ { ++ struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ .ai_protocol = IPPROTO_TCP, ++ }; ++ errno = ERANGE; ++ h_errno = NETDB_INTERNAL; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("example.com", "80", &hints, &ai); ++ check_addrinfo ("example.com AF_UNSPEC", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ ++ hints.ai_family = AF_INET; ++ errno = ERANGE; ++ h_errno = NETDB_INTERNAL; ++ ret = getaddrinfo ("example.com", "80", &hints, &ai); ++ check_addrinfo ("example.com AF_INET", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++ ++ support_chroot_free (chroot_env); ++ return 0; ++} ++ ++#define PREPARE prepare ++#include +Index: glibc-2.26/resolv/tst-resolv-basic.c +=================================================================== +--- glibc-2.26.orig/resolv/tst-resolv-basic.c ++++ glibc-2.26/resolv/tst-resolv-basic.c +@@ -50,7 +50,7 @@ response (const struct resolv_response_c + qname_compare = qname + 2; + else + qname_compare = qname; +- enum {www, alias, nxdomain, long_name} requested_qname; ++ enum {www, alias, nxdomain, long_name, nodata} requested_qname; + if (strcmp (qname_compare, "www.example") == 0) + requested_qname = www; + else if (strcmp (qname_compare, "alias.example") == 0) +@@ -59,6 +59,8 @@ response (const struct resolv_response_c + requested_qname = nxdomain; + else if (strcmp (qname_compare, LONG_NAME) == 0) + requested_qname = long_name; ++ else if (strcmp (qname_compare, "nodata.example") == 0) ++ requested_qname = nodata; + else + { + support_record_failure (); +@@ -87,6 +89,8 @@ response (const struct resolv_response_c + resolv_response_close_record (b); + resolv_response_open_record (b, "www.example", qclass, qtype, 0); + break; ++ case nodata: ++ return; + case nxdomain: + FAIL_EXIT1 ("unreachable"); + } +@@ -267,6 +271,55 @@ test_bug_21295 (void) + } + } + ++/* Run tests which do not expect any data. */ ++static void ++test_nodata_nxdomain (void) ++{ ++ /* Iterate through different address families. */ ++ int families[] = { AF_UNSPEC, AF_INET, AF_INET6, -1 }; ++ for (int i = 0; families[i] >= 0; ++i) ++ /* If do_tcp, prepend "t." to the name to trigger TCP ++ fallback. */ ++ for (int do_tcp = 0; do_tcp < 2; ++do_tcp) ++ /* If do_nxdomain, trigger an NXDOMAIN error (DNS failure), ++ otherwise use a NODATA response (empty but successful ++ answer). */ ++ for (int do_nxdomain = 0; do_nxdomain < 2; ++do_nxdomain) ++ { ++ int family = families[i]; ++ char *name = xasprintf ("%s%s.example", ++ do_tcp ? "t." : "", ++ do_nxdomain ? "nxdomain" : "nodata"); ++ ++ if (family != AF_UNSPEC) ++ { ++ if (do_nxdomain) ++ check_h (name, family, "error: HOST_NOT_FOUND\n"); ++ else ++ check_h (name, family, "error: NO_ADDRESS\n"); ++ } ++ ++ const char *expected; ++ if (do_nxdomain) ++ expected = "error: Name or service not known\n"; ++ else ++ expected = "error: No address associated with hostname\n"; ++ ++ check_ai (name, "80", family, expected); ++ ++ struct addrinfo hints = ++ { ++ .ai_family = family, ++ .ai_flags = AI_V4MAPPED | AI_ALL, ++ }; ++ check_ai_hints (name, "80", hints, expected); ++ hints.ai_flags |= AI_CANONNAME; ++ check_ai_hints (name, "80", hints, expected); ++ ++ free (name); ++ } ++} ++ + static int + do_test (void) + { +@@ -439,29 +492,8 @@ do_test (void) + "address: DGRAM/UDP 2001:db8::4 80\n" + "address: RAW/IP 2001:db8::4 80\n"); + +- check_h ("nxdomain.example", AF_INET, +- "error: HOST_NOT_FOUND\n"); +- check_h ("nxdomain.example", AF_INET6, +- "error: HOST_NOT_FOUND\n"); +- check_ai ("nxdomain.example", "80", AF_UNSPEC, +- "error: Name or service not known\n"); +- check_ai ("nxdomain.example", "80", AF_INET, +- "error: Name or service not known\n"); +- check_ai ("nxdomain.example", "80", AF_INET6, +- "error: Name or service not known\n"); +- +- check_h ("t.nxdomain.example", AF_INET, +- "error: HOST_NOT_FOUND\n"); +- check_h ("t.nxdomain.example", AF_INET6, +- "error: HOST_NOT_FOUND\n"); +- check_ai ("t.nxdomain.example", "80", AF_UNSPEC, +- "error: Name or service not known\n"); +- check_ai ("t.nxdomain.example", "80", AF_INET, +- "error: Name or service not known\n"); +- check_ai ("t.nxdomain.example", "80", AF_INET6, +- "error: Name or service not known\n"); +- + test_bug_21295 (); ++ test_nodata_nxdomain (); + + resolv_test_end (aux); + +Index: glibc-2.26/support/namespace.h +=================================================================== +--- glibc-2.26.orig/support/namespace.h ++++ glibc-2.26/support/namespace.h +@@ -66,7 +66,9 @@ struct support_chroot_configuration + { + /* File contents. The files are not created if the field is + NULL. */ +- const char *resolv_conf; ++ const char *resolv_conf; /* /etc/resolv.conf. */ ++ const char *hosts; /* /etc/hosts. */ ++ const char *host_conf; /* /etc/host.conf. */ + }; + + /* The result of the creation of a chroot. */ +@@ -78,8 +80,11 @@ struct support_chroot + /* Path to the chroot directory. */ + char *path_chroot; + +- /* Path to the /etc/resolv.conf file. */ +- char *path_resolv_conf; ++ /* Paths to files in the chroot. These are absolute and outside of ++ the chroot. */ ++ char *path_resolv_conf; /* /etc/resolv.conf. */ ++ char *path_hosts; /* /etc/hosts. */ ++ char *path_host_conf; /* /etc/host.conf. */ + }; + + /* Create a chroot environment. The returned data should be freed +Index: glibc-2.26/support/support_chroot.c +=================================================================== +--- glibc-2.26.orig/support/support_chroot.c ++++ glibc-2.26/support/support_chroot.c +@@ -24,6 +24,23 @@ + #include + #include + ++/* If CONTENTS is not NULL, write it to the file at DIRECTORY/RELPATH, ++ and store the name in *ABSPATH. If CONTENTS is NULL, store NULL in ++ *ABSPATH. */ ++static void ++write_file (const char *directory, const char *relpath, const char *contents, ++ char **abspath) ++{ ++ if (contents != NULL) ++ { ++ *abspath = xasprintf ("%s/%s", directory, relpath); ++ add_temp_file (*abspath); ++ support_write_file_string (*abspath, contents); ++ } ++ else ++ *abspath = NULL; ++} ++ + struct support_chroot * + support_chroot_create (struct support_chroot_configuration conf) + { +@@ -39,15 +56,10 @@ support_chroot_create (struct support_ch + xmkdir (path_etc, 0777); + add_temp_file (path_etc); + +- if (conf.resolv_conf != NULL) +- { +- /* Create an empty resolv.conf file. */ +- chroot->path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc); +- add_temp_file (chroot->path_resolv_conf); +- support_write_file_string (chroot->path_resolv_conf, conf.resolv_conf); +- } +- else +- chroot->path_resolv_conf = NULL; ++ write_file (path_etc, "resolv.conf", conf.resolv_conf, ++ &chroot->path_resolv_conf); ++ write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts); ++ write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf); + + free (path_etc); + +@@ -67,5 +79,7 @@ support_chroot_free (struct support_chro + { + free (chroot->path_chroot); + free (chroot->path_resolv_conf); ++ free (chroot->path_hosts); ++ free (chroot->path_host_conf); + free (chroot); + } +Index: glibc-2.26/sysdeps/posix/getaddrinfo.c +=================================================================== +--- glibc-2.26.orig/sysdeps/posix/getaddrinfo.c ++++ glibc-2.26/sysdeps/posix/getaddrinfo.c +@@ -241,48 +241,43 @@ convert_hostent_to_gaih_addrtuple (const + + #define gethosts(_family, _type) \ + { \ +- int herrno; \ + struct hostent th; \ +- struct hostent *h; \ + char *localcanon = NULL; \ + no_data = 0; \ +- while (1) { \ +- rc = 0; \ +- status = DL_CALL_FCT (fct, (name, _family, &th, \ +- tmpbuf->data, tmpbuf->length, \ +- &rc, &herrno, NULL, &localcanon)); \ +- if (rc != ERANGE || herrno != NETDB_INTERNAL) \ +- break; \ +- if (!scratch_buffer_grow (tmpbuf)) \ +- { \ +- __resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \ +- __resolv_context_put (res_ctx); \ +- result = -EAI_MEMORY; \ +- goto free_and_return; \ +- } \ +- } \ +- if (status == NSS_STATUS_SUCCESS && rc == 0) \ +- h = &th; \ +- else \ +- h = NULL; \ +- if (rc != 0) \ ++ while (1) \ + { \ +- if (herrno == NETDB_INTERNAL) \ ++ status = DL_CALL_FCT (fct, (name, _family, &th, \ ++ tmpbuf->data, tmpbuf->length, \ ++ &errno, &h_errno, NULL, &localcanon)); \ ++ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \ ++ || errno != ERANGE) \ ++ break; \ ++ if (!scratch_buffer_grow (tmpbuf)) \ ++ { \ ++ __resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \ ++ __resolv_context_put (res_ctx); \ ++ result = -EAI_MEMORY; \ ++ goto free_and_return; \ ++ } \ ++ } \ ++ if (status == NSS_STATUS_NOTFOUND \ ++ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \ ++ { \ ++ if (h_errno == NETDB_INTERNAL) \ + { \ +- __set_h_errno (herrno); \ + __resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \ + __resolv_context_put (res_ctx); \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ +- if (herrno == TRY_AGAIN) \ ++ if (h_errno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ +- no_data = herrno == NO_DATA; \ ++ no_data = h_errno == NO_DATA; \ + } \ +- else if (h != NULL) \ ++ else if (status == NSS_STATUS_SUCCESS) \ + { \ +- if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \ ++ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \ + { \ + __resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \ + __resolv_context_put (res_ctx); \ +@@ -334,10 +329,8 @@ getcanonname (service_user *nip, struct + if (cfct != NULL) + { + char buf[256]; +- int herrno; +- int rc; + if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &rc, &herrno)) != NSS_STATUS_SUCCESS) ++ &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -353,7 +346,6 @@ gaih_inet (const char *name, const struc + const struct gaih_typeproto *tp = gaih_inet_typeproto; + struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; + struct gaih_addrtuple *at = NULL; +- int rc; + bool got_ipv6 = false; + const char *canon = NULL; + const char *orig_name = name; +@@ -395,7 +387,8 @@ gaih_inet (const char *name, const struc + st = (struct gaih_servtuple *) + alloca_account (sizeof (struct gaih_servtuple), alloca_used); + +- if ((rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf))) ++ int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf); ++ if (__glibc_unlikely (rc != 0)) + return rc; + } + else +@@ -420,13 +413,9 @@ gaih_inet (const char *name, const struc + alloca_account (sizeof (struct gaih_servtuple), + alloca_used); + +- if ((rc = gaih_inet_serv (service->name, +- tp, req, newp, tmpbuf))) +- { +- if (rc) +- continue; +- return rc; +- } ++ if (gaih_inet_serv (service->name, ++ tp, req, newp, tmpbuf) != 0) ++ continue; + + *pst = newp; + pst = &(newp->next); +@@ -499,7 +488,7 @@ gaih_inet (const char *name, const struc + idn_flags |= IDNA_USE_STD3_ASCII_RULES; + + char *p = NULL; +- rc = __idna_to_ascii_lz (name, &p, idn_flags); ++ int rc = __idna_to_ascii_lz (name, &p, idn_flags); + if (rc != IDNA_SUCCESS) + { + /* No need to jump to free_and_return here. */ +@@ -600,14 +589,13 @@ gaih_inet (const char *name, const struc + int rc; + struct hostent th; + struct hostent *h; +- int herrno; + + while (1) + { + rc = __gethostbyname2_r (name, AF_INET, &th, + tmpbuf->data, tmpbuf->length, +- &h, &herrno); +- if (rc != ERANGE || herrno != NETDB_INTERNAL) ++ &h, &h_errno); ++ if (rc != ERANGE || h_errno != NETDB_INTERNAL) + break; + if (!scratch_buffer_grow (tmpbuf)) + { +@@ -629,15 +617,20 @@ gaih_inet (const char *name, const struc + } + *pat = addrmem; + } ++ else ++ { ++ if (h_errno == NO_DATA) ++ result = -EAI_NODATA; ++ else ++ result = -EAI_NONAME; ++ goto free_and_return; ++ } + } + else + { +- if (herrno == NETDB_INTERNAL) +- { +- __set_h_errno (herrno); +- result = -EAI_SYSTEM; +- } +- else if (herrno == TRY_AGAIN) ++ if (h_errno == NETDB_INTERNAL) ++ result = -EAI_SYSTEM; ++ else if (h_errno == TRY_AGAIN) + result = -EAI_AGAIN; + else + /* We made requests but they turned out no data. +@@ -660,8 +653,7 @@ gaih_inet (const char *name, const struc + { + /* Try to use nscd. */ + struct nscd_ai_result *air = NULL; +- int herrno; +- int err = __nscd_getai (name, &air, &herrno); ++ int err = __nscd_getai (name, &air, &h_errno); + if (air != NULL) + { + /* Transform into gaih_addrtuple list. */ +@@ -752,9 +744,9 @@ gaih_inet (const char *name, const struc + goto free_and_return; + else if (__nss_not_use_nscd_hosts == 0) + { +- if (herrno == NETDB_INTERNAL && errno == ENOMEM) ++ if (h_errno == NETDB_INTERNAL && errno == ENOMEM) + result = -EAI_MEMORY; +- else if (herrno == TRY_AGAIN) ++ else if (h_errno == TRY_AGAIN) + result = -EAI_AGAIN; + else + result = -EAI_SYSTEM; +@@ -793,24 +785,21 @@ gaih_inet (const char *name, const struc + + if (fct4 != NULL) + { +- int herrno; +- + while (1) + { +- rc = 0; + status = DL_CALL_FCT (fct4, (name, pat, + tmpbuf->data, tmpbuf->length, +- &rc, &herrno, ++ &errno, &h_errno, + NULL)); + if (status == NSS_STATUS_SUCCESS) + break; + if (status != NSS_STATUS_TRYAGAIN +- || rc != ERANGE || herrno != NETDB_INTERNAL) ++ || errno != ERANGE || h_errno != NETDB_INTERNAL) + { +- if (herrno == TRY_AGAIN) ++ if (h_errno == TRY_AGAIN) + no_data = EAI_AGAIN; + else +- no_data = herrno == NO_DATA; ++ no_data = h_errno == NO_DATA; + break; + } + +@@ -940,13 +929,17 @@ gaih_inet (const char *name, const struc + } + else + { ++ /* Could not locate any of the lookup functions. ++ The NSS lookup code does not consistently set ++ errno, so we need to supply our own error ++ code here. The root cause could either be a ++ resource allocation failure, or a missing ++ service function in the DSO (so it should not ++ be listed in /etc/nsswitch.conf). Assume the ++ former, and return EBUSY. */ + status = NSS_STATUS_UNAVAIL; +- /* Could not load any of the lookup functions. Indicate +- an internal error if the failure was due to a system +- error other than the file not being found. We use the +- errno from the last failed callback. */ +- if (errno != 0 && errno != ENOENT) +- __set_h_errno (NETDB_INTERNAL); ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); + } + } + +@@ -962,7 +955,10 @@ gaih_inet (const char *name, const struc + __resolv_context_enable_inet6 (res_ctx, res_enable_inet6); + __resolv_context_put (res_ctx); + +- if (h_errno == NETDB_INTERNAL) ++ /* If we have a failure which sets errno, report it using ++ EAI_SYSTEM. */ ++ if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) ++ && h_errno == NETDB_INTERNAL) + { + result = -EAI_SYSTEM; + goto free_and_return; diff --git a/glibc-testsuite.changes b/glibc-testsuite.changes index f8c1b5d..fb3c08a 100644 --- a/glibc-testsuite.changes +++ b/glibc-testsuite.changes @@ -1,3 +1,48 @@ +------------------------------------------------------------------- +Wed Oct 4 12:14:30 UTC 2017 - schwab@suse.de + +- nss-compat.patch: Move nss_compat from nis to nss subdir and install it + unconditionally +- nsswitch.conf: switch back to compat for passwd, group, shadow + +------------------------------------------------------------------- +Thu Sep 28 07:57:52 UTC 2017 - schwab@suse.de + +- assert-pedantic.patch: Suppress pedantic warning caused by statement + expression (BZ #21242, BZ #21972) +- math-c++-compat.patch: Add more C++ compatibility +- getaddrinfo-errno.patch: Fix errno and h_errno handling in getaddrinfo + (BZ #21915, BZ #21922) +- resolv-conf-oom.patch: Fix memory handling in OOM situation during + resolv.conf parsing (BZ #22095, BZ #22096) +- dynarray-allocation.patch: Fix initial size of dynarray allocation and + set errno on overflow error +- nearbyint-inexact.patch: Avoid spurious inexact in nearbyint (BZ #22225) + +------------------------------------------------------------------- +Mon Sep 25 10:12:24 UTC 2017 - schwab@suse.de + +- math-c++-compat.patch: add more C++ compatibility (BZ #22146) + +------------------------------------------------------------------- +Tue Sep 12 06:37:36 UTC 2017 - schwab@suse.de + +- Remove rpcsvc/yppasswd.* from glibc-devel +- ld-so-hwcap-x86-64.patch: add x86_64 to hwcap (bsc#1056606, BZ #22093) + +------------------------------------------------------------------- +Thu Aug 31 13:43:07 UTC 2017 - schwab@suse.de + +- eh-frame-zero-terminator.patch: Properly terminate .eh_frame (BZ #22051) + +------------------------------------------------------------------- +Thu Aug 31 07:06:20 UTC 2017 - schwab@suse.de + +- Disable obsolete libnsl and NIS support +- remove-nss-nis-compat.patch: remove nis and compat from default NSS + configs +- nsswitch.conf: Likewise + ------------------------------------------------------------------- Tue Aug 29 07:13:42 UTC 2017 - schwab@suse.de diff --git a/glibc-testsuite.spec b/glibc-testsuite.spec index 54d1bef..2722f7f 100644 --- a/glibc-testsuite.spec +++ b/glibc-testsuite.spec @@ -269,7 +269,7 @@ Patch306: glibc-fix-double-loopback.diff ### # Patches from upstream ### -# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts +# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts (BZ #21885, BZ #21932) Patch1000: resolv-context-leak.patch # PATCH-FIX-UPSTREAM Use _dl_runtime_resolve_opt only with AVX512F (BZ #21871) Patch1001: dl-runtime-resolve-opt-avx512f.patch @@ -277,6 +277,24 @@ Patch1001: dl-runtime-resolve-opt-avx512f.patch Patch1002: libpthread-compat-wrappers.patch # PATCH-FIX-UPSTREAM Do not use __builtin_types_compatible_p in C++ mode (BZ #21930) Patch1003: math-c++-compat.patch +# PATCH-FIX-UPSTREAM Remove nis and compat from default NSS configs +Patch1004: remove-nss-nis-compat.patch +# PATCH-FIX-UPSTREAM Properly terminate .eh_frame (BZ #22051) +Patch1005: eh-frame-zero-terminator.patch +# PATCH-FIX-UPSTREAM x86: Add x86_64 to x86-64 HWCAP (BZ #22093) +Patch1006: ld-so-hwcap-x86-64.patch +# PATCH-FIX-UPSTREAM assert: Suppress pedantic warning caused by statement expression (BZ #21242, BZ #21972) +Patch1007: assert-pedantic.patch +# PATCH-FIX-UPSTREAM Fix errno and h_errno handling in getaddrinfo (BZ #21915, BZ #21922) +Patch1008: getaddrinfo-errno.patch +# PATCH-FIX-UPSTREAM Fix memory handling in OOM situation during resolv.conf parsing (BZ #22095, BZ #22096) +Patch1009: resolv-conf-oom.patch +# PATCH-FIX-UPSTREAM Fix initial size of dynarray allocation and set errno on overflow error +Patch1010: dynarray-allocation.patch +# PATCH-FIX-UPSTREAM Avoid spurious inexact in nearbyint (BZ #22225) +Patch1011: nearbyint-inexact.patch +# PATCH-FIX-UPSTREAM Move nss_compat from nis to nss subdir and install it unconditionally +Patch1012: nss-compat.patch ### # Patches awaiting upstream approval @@ -510,6 +528,15 @@ rm nscd/s-stamp %patch1001 -p1 %patch1002 -p1 %patch1003 -p1 +%patch1004 -p1 +%patch1005 -p1 +%patch1006 -p1 +%patch1007 -p1 +%patch1008 -p1 +%patch1009 -p1 +%patch1010 -p1 +%patch1011 -p1 +%patch1012 -p1 %patch2000 -p1 %patch2001 -p1 @@ -677,7 +704,7 @@ configure_and_build_glibc() { --enable-kernel=%{enablekernel} \ --with-bugurl=http://bugs.opensuse.org \ --enable-bind-now \ - --enable-obsolete-rpc --enable-obsolete-nsl \ + --enable-obsolete-rpc \ --disable-timezone-tools # Should we enable --enable-systemtap? # Should we enable --enable-nss-crypt to build use freebl3 hash functions? @@ -769,12 +796,6 @@ pushd crypt_blowfish-%{crypt_bf_version} make man popd -####################################################################### -### -### CHECK -### -####################################################################### - %check %if %{build_testsuite} # The testsuite will fail if asneeded is used @@ -916,6 +937,11 @@ export RPM_BUILD_ROOT mkdir -p %{buildroot}/%{_lib}/obsolete %endif +# remove nsl compat library +rm -f %{buildroot}%{_libdir}/libnsl* +# part of libnsl-devel +rm -f %{buildroot}%{_includedir}/rpcsvc/yppasswd.* + # Miscelanna: install -m 0700 glibc_post_upgrade %{buildroot}%{_sbindir} @@ -1202,10 +1228,6 @@ exit 0 /%{_lib}/libnss_files.so.2 /%{_lib}/libnss_hesiod-%{libversion}.so /%{_lib}/libnss_hesiod.so.2 -/%{_lib}/libnss_nis-%{libversion}.so -/%{_lib}/libnss_nis.so.2 -/%{_lib}/libnss_nisplus-%{libversion}.so -/%{_lib}/libnss_nisplus.so.2 /%{_lib}/libpthread-%{libversion}.so /%{_lib}/libpthread.so.0 /%{_lib}/libresolv-%{libversion}.so @@ -1318,7 +1340,6 @@ exit 0 %{_libdir}/libm-%{libversion}.a %{_libdir}/libmvec.a %endif -%{_libdir}/libnsl.a %{_libdir}/libpthread.a %{_libdir}/libresolv.a %{_libdir}/librt.a @@ -1374,7 +1395,6 @@ exit 0 %{_libdir}/libowcrypt_p.a %{_libdir}/libpthread_p.a %{_libdir}/libresolv_p.a -%{_libdir}/libnsl_p.a %{_libdir}/librt_p.a %{_libdir}/librpcsvc_p.a %{_libdir}/libutil_p.a diff --git a/glibc-utils.changes b/glibc-utils.changes index f8c1b5d..fb3c08a 100644 --- a/glibc-utils.changes +++ b/glibc-utils.changes @@ -1,3 +1,48 @@ +------------------------------------------------------------------- +Wed Oct 4 12:14:30 UTC 2017 - schwab@suse.de + +- nss-compat.patch: Move nss_compat from nis to nss subdir and install it + unconditionally +- nsswitch.conf: switch back to compat for passwd, group, shadow + +------------------------------------------------------------------- +Thu Sep 28 07:57:52 UTC 2017 - schwab@suse.de + +- assert-pedantic.patch: Suppress pedantic warning caused by statement + expression (BZ #21242, BZ #21972) +- math-c++-compat.patch: Add more C++ compatibility +- getaddrinfo-errno.patch: Fix errno and h_errno handling in getaddrinfo + (BZ #21915, BZ #21922) +- resolv-conf-oom.patch: Fix memory handling in OOM situation during + resolv.conf parsing (BZ #22095, BZ #22096) +- dynarray-allocation.patch: Fix initial size of dynarray allocation and + set errno on overflow error +- nearbyint-inexact.patch: Avoid spurious inexact in nearbyint (BZ #22225) + +------------------------------------------------------------------- +Mon Sep 25 10:12:24 UTC 2017 - schwab@suse.de + +- math-c++-compat.patch: add more C++ compatibility (BZ #22146) + +------------------------------------------------------------------- +Tue Sep 12 06:37:36 UTC 2017 - schwab@suse.de + +- Remove rpcsvc/yppasswd.* from glibc-devel +- ld-so-hwcap-x86-64.patch: add x86_64 to hwcap (bsc#1056606, BZ #22093) + +------------------------------------------------------------------- +Thu Aug 31 13:43:07 UTC 2017 - schwab@suse.de + +- eh-frame-zero-terminator.patch: Properly terminate .eh_frame (BZ #22051) + +------------------------------------------------------------------- +Thu Aug 31 07:06:20 UTC 2017 - schwab@suse.de + +- Disable obsolete libnsl and NIS support +- remove-nss-nis-compat.patch: remove nis and compat from default NSS + configs +- nsswitch.conf: Likewise + ------------------------------------------------------------------- Tue Aug 29 07:13:42 UTC 2017 - schwab@suse.de diff --git a/glibc-utils.spec b/glibc-utils.spec index a01e197..2a287c1 100644 --- a/glibc-utils.spec +++ b/glibc-utils.spec @@ -269,7 +269,7 @@ Patch306: glibc-fix-double-loopback.diff ### # Patches from upstream ### -# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts +# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts (BZ #21885, BZ #21932) Patch1000: resolv-context-leak.patch # PATCH-FIX-UPSTREAM Use _dl_runtime_resolve_opt only with AVX512F (BZ #21871) Patch1001: dl-runtime-resolve-opt-avx512f.patch @@ -277,6 +277,24 @@ Patch1001: dl-runtime-resolve-opt-avx512f.patch Patch1002: libpthread-compat-wrappers.patch # PATCH-FIX-UPSTREAM Do not use __builtin_types_compatible_p in C++ mode (BZ #21930) Patch1003: math-c++-compat.patch +# PATCH-FIX-UPSTREAM Remove nis and compat from default NSS configs +Patch1004: remove-nss-nis-compat.patch +# PATCH-FIX-UPSTREAM Properly terminate .eh_frame (BZ #22051) +Patch1005: eh-frame-zero-terminator.patch +# PATCH-FIX-UPSTREAM x86: Add x86_64 to x86-64 HWCAP (BZ #22093) +Patch1006: ld-so-hwcap-x86-64.patch +# PATCH-FIX-UPSTREAM assert: Suppress pedantic warning caused by statement expression (BZ #21242, BZ #21972) +Patch1007: assert-pedantic.patch +# PATCH-FIX-UPSTREAM Fix errno and h_errno handling in getaddrinfo (BZ #21915, BZ #21922) +Patch1008: getaddrinfo-errno.patch +# PATCH-FIX-UPSTREAM Fix memory handling in OOM situation during resolv.conf parsing (BZ #22095, BZ #22096) +Patch1009: resolv-conf-oom.patch +# PATCH-FIX-UPSTREAM Fix initial size of dynarray allocation and set errno on overflow error +Patch1010: dynarray-allocation.patch +# PATCH-FIX-UPSTREAM Avoid spurious inexact in nearbyint (BZ #22225) +Patch1011: nearbyint-inexact.patch +# PATCH-FIX-UPSTREAM Move nss_compat from nis to nss subdir and install it unconditionally +Patch1012: nss-compat.patch ### # Patches awaiting upstream approval @@ -510,6 +528,15 @@ rm nscd/s-stamp %patch1001 -p1 %patch1002 -p1 %patch1003 -p1 +%patch1004 -p1 +%patch1005 -p1 +%patch1006 -p1 +%patch1007 -p1 +%patch1008 -p1 +%patch1009 -p1 +%patch1010 -p1 +%patch1011 -p1 +%patch1012 -p1 %patch2000 -p1 %patch2001 -p1 @@ -677,7 +704,7 @@ configure_and_build_glibc() { --enable-kernel=%{enablekernel} \ --with-bugurl=http://bugs.opensuse.org \ --enable-bind-now \ - --enable-obsolete-rpc --enable-obsolete-nsl \ + --enable-obsolete-rpc \ --disable-timezone-tools # Should we enable --enable-systemtap? # Should we enable --enable-nss-crypt to build use freebl3 hash functions? @@ -769,12 +796,6 @@ pushd crypt_blowfish-%{crypt_bf_version} make man popd -####################################################################### -### -### CHECK -### -####################################################################### - %check %if %{build_testsuite} # The testsuite will fail if asneeded is used @@ -916,6 +937,11 @@ export RPM_BUILD_ROOT mkdir -p %{buildroot}/%{_lib}/obsolete %endif +# remove nsl compat library +rm -f %{buildroot}%{_libdir}/libnsl* +# part of libnsl-devel +rm -f %{buildroot}%{_includedir}/rpcsvc/yppasswd.* + # Miscelanna: install -m 0700 glibc_post_upgrade %{buildroot}%{_sbindir} @@ -1202,10 +1228,6 @@ exit 0 /%{_lib}/libnss_files.so.2 /%{_lib}/libnss_hesiod-%{libversion}.so /%{_lib}/libnss_hesiod.so.2 -/%{_lib}/libnss_nis-%{libversion}.so -/%{_lib}/libnss_nis.so.2 -/%{_lib}/libnss_nisplus-%{libversion}.so -/%{_lib}/libnss_nisplus.so.2 /%{_lib}/libpthread-%{libversion}.so /%{_lib}/libpthread.so.0 /%{_lib}/libresolv-%{libversion}.so @@ -1318,7 +1340,6 @@ exit 0 %{_libdir}/libm-%{libversion}.a %{_libdir}/libmvec.a %endif -%{_libdir}/libnsl.a %{_libdir}/libpthread.a %{_libdir}/libresolv.a %{_libdir}/librt.a @@ -1374,7 +1395,6 @@ exit 0 %{_libdir}/libowcrypt_p.a %{_libdir}/libpthread_p.a %{_libdir}/libresolv_p.a -%{_libdir}/libnsl_p.a %{_libdir}/librt_p.a %{_libdir}/librpcsvc_p.a %{_libdir}/libutil_p.a diff --git a/glibc.changes b/glibc.changes index f8c1b5d..fb3c08a 100644 --- a/glibc.changes +++ b/glibc.changes @@ -1,3 +1,48 @@ +------------------------------------------------------------------- +Wed Oct 4 12:14:30 UTC 2017 - schwab@suse.de + +- nss-compat.patch: Move nss_compat from nis to nss subdir and install it + unconditionally +- nsswitch.conf: switch back to compat for passwd, group, shadow + +------------------------------------------------------------------- +Thu Sep 28 07:57:52 UTC 2017 - schwab@suse.de + +- assert-pedantic.patch: Suppress pedantic warning caused by statement + expression (BZ #21242, BZ #21972) +- math-c++-compat.patch: Add more C++ compatibility +- getaddrinfo-errno.patch: Fix errno and h_errno handling in getaddrinfo + (BZ #21915, BZ #21922) +- resolv-conf-oom.patch: Fix memory handling in OOM situation during + resolv.conf parsing (BZ #22095, BZ #22096) +- dynarray-allocation.patch: Fix initial size of dynarray allocation and + set errno on overflow error +- nearbyint-inexact.patch: Avoid spurious inexact in nearbyint (BZ #22225) + +------------------------------------------------------------------- +Mon Sep 25 10:12:24 UTC 2017 - schwab@suse.de + +- math-c++-compat.patch: add more C++ compatibility (BZ #22146) + +------------------------------------------------------------------- +Tue Sep 12 06:37:36 UTC 2017 - schwab@suse.de + +- Remove rpcsvc/yppasswd.* from glibc-devel +- ld-so-hwcap-x86-64.patch: add x86_64 to hwcap (bsc#1056606, BZ #22093) + +------------------------------------------------------------------- +Thu Aug 31 13:43:07 UTC 2017 - schwab@suse.de + +- eh-frame-zero-terminator.patch: Properly terminate .eh_frame (BZ #22051) + +------------------------------------------------------------------- +Thu Aug 31 07:06:20 UTC 2017 - schwab@suse.de + +- Disable obsolete libnsl and NIS support +- remove-nss-nis-compat.patch: remove nis and compat from default NSS + configs +- nsswitch.conf: Likewise + ------------------------------------------------------------------- Tue Aug 29 07:13:42 UTC 2017 - schwab@suse.de diff --git a/glibc.spec b/glibc.spec index b0dbb5d..51c1ef3 100644 --- a/glibc.spec +++ b/glibc.spec @@ -275,7 +275,7 @@ Patch306: glibc-fix-double-loopback.diff ### # Patches from upstream ### -# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts +# PATCH-FIX-UPSTREAM Fix leaks of resolver contexts (BZ #21885, BZ #21932) Patch1000: resolv-context-leak.patch # PATCH-FIX-UPSTREAM Use _dl_runtime_resolve_opt only with AVX512F (BZ #21871) Patch1001: dl-runtime-resolve-opt-avx512f.patch @@ -283,6 +283,24 @@ Patch1001: dl-runtime-resolve-opt-avx512f.patch Patch1002: libpthread-compat-wrappers.patch # PATCH-FIX-UPSTREAM Do not use __builtin_types_compatible_p in C++ mode (BZ #21930) Patch1003: math-c++-compat.patch +# PATCH-FIX-UPSTREAM Remove nis and compat from default NSS configs +Patch1004: remove-nss-nis-compat.patch +# PATCH-FIX-UPSTREAM Properly terminate .eh_frame (BZ #22051) +Patch1005: eh-frame-zero-terminator.patch +# PATCH-FIX-UPSTREAM x86: Add x86_64 to x86-64 HWCAP (BZ #22093) +Patch1006: ld-so-hwcap-x86-64.patch +# PATCH-FIX-UPSTREAM assert: Suppress pedantic warning caused by statement expression (BZ #21242, BZ #21972) +Patch1007: assert-pedantic.patch +# PATCH-FIX-UPSTREAM Fix errno and h_errno handling in getaddrinfo (BZ #21915, BZ #21922) +Patch1008: getaddrinfo-errno.patch +# PATCH-FIX-UPSTREAM Fix memory handling in OOM situation during resolv.conf parsing (BZ #22095, BZ #22096) +Patch1009: resolv-conf-oom.patch +# PATCH-FIX-UPSTREAM Fix initial size of dynarray allocation and set errno on overflow error +Patch1010: dynarray-allocation.patch +# PATCH-FIX-UPSTREAM Avoid spurious inexact in nearbyint (BZ #22225) +Patch1011: nearbyint-inexact.patch +# PATCH-FIX-UPSTREAM Move nss_compat from nis to nss subdir and install it unconditionally +Patch1012: nss-compat.patch ### # Patches awaiting upstream approval @@ -516,6 +534,15 @@ rm nscd/s-stamp %patch1001 -p1 %patch1002 -p1 %patch1003 -p1 +%patch1004 -p1 +%patch1005 -p1 +%patch1006 -p1 +%patch1007 -p1 +%patch1008 -p1 +%patch1009 -p1 +%patch1010 -p1 +%patch1011 -p1 +%patch1012 -p1 %patch2000 -p1 %patch2001 -p1 @@ -683,7 +710,7 @@ configure_and_build_glibc() { --enable-kernel=%{enablekernel} \ --with-bugurl=http://bugs.opensuse.org \ --enable-bind-now \ - --enable-obsolete-rpc --enable-obsolete-nsl \ + --enable-obsolete-rpc \ --disable-timezone-tools # Should we enable --enable-systemtap? # Should we enable --enable-nss-crypt to build use freebl3 hash functions? @@ -775,12 +802,6 @@ pushd crypt_blowfish-%{crypt_bf_version} make man popd -####################################################################### -### -### CHECK -### -####################################################################### - %check %if %{build_testsuite} # The testsuite will fail if asneeded is used @@ -922,6 +943,11 @@ export RPM_BUILD_ROOT mkdir -p %{buildroot}/%{_lib}/obsolete %endif +# remove nsl compat library +rm -f %{buildroot}%{_libdir}/libnsl* +# part of libnsl-devel +rm -f %{buildroot}%{_includedir}/rpcsvc/yppasswd.* + # Miscelanna: install -m 0700 glibc_post_upgrade %{buildroot}%{_sbindir} @@ -1208,10 +1234,6 @@ exit 0 /%{_lib}/libnss_files.so.2 /%{_lib}/libnss_hesiod-%{libversion}.so /%{_lib}/libnss_hesiod.so.2 -/%{_lib}/libnss_nis-%{libversion}.so -/%{_lib}/libnss_nis.so.2 -/%{_lib}/libnss_nisplus-%{libversion}.so -/%{_lib}/libnss_nisplus.so.2 /%{_lib}/libpthread-%{libversion}.so /%{_lib}/libpthread.so.0 /%{_lib}/libresolv-%{libversion}.so @@ -1324,7 +1346,6 @@ exit 0 %{_libdir}/libm-%{libversion}.a %{_libdir}/libmvec.a %endif -%{_libdir}/libnsl.a %{_libdir}/libpthread.a %{_libdir}/libresolv.a %{_libdir}/librt.a @@ -1380,7 +1401,6 @@ exit 0 %{_libdir}/libowcrypt_p.a %{_libdir}/libpthread_p.a %{_libdir}/libresolv_p.a -%{_libdir}/libnsl_p.a %{_libdir}/librt_p.a %{_libdir}/librpcsvc_p.a %{_libdir}/libutil_p.a diff --git a/ld-so-hwcap-x86-64.patch b/ld-so-hwcap-x86-64.patch new file mode 100644 index 0000000..b99547a --- /dev/null +++ b/ld-so-hwcap-x86-64.patch @@ -0,0 +1,190 @@ +2017-09-11 H.J. Lu + + [BZ #22093] + * sysdeps/x86/cpu-features.c (init_cpu_features): Initialize + GLRO(dl_hwcap) to HWCAP_X86_64 for x86-64. + * sysdeps/x86/dl-hwcap.h (HWCAP_COUNT): Updated. + (HWCAP_IMPORTANT): Likewise. + (HWCAP_X86_64): New enum. + (HWCAP_X86_AVX512_1): Updated. + * sysdeps/x86/dl-procinfo.c (_dl_x86_hwcap_flags): Add "x86_64". + * sysdeps/x86_64/Makefile (tests): Add tst-x86_64-1. + (modules-names): Add x86_64/tst-x86_64mod-1. + (LDFLAGS-tst-x86_64mod-1.so): New. + ($(objpfx)tst-x86_64-1): Likewise. + ($(objpfx)x86_64/tst-x86_64mod-1.os): Likewise. + (tst-x86_64-1-clean): Likewise. + * sysdeps/x86_64/tst-x86_64-1.c: New file. + * sysdeps/x86_64/tst-x86_64mod-1.c: Likewise. + +Index: glibc-2.26/sysdeps/x86/cpu-features.c +=================================================================== +--- glibc-2.26.orig/sysdeps/x86/cpu-features.c ++++ glibc-2.26/sysdeps/x86/cpu-features.c +@@ -336,7 +336,6 @@ no_cpuid: + + /* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */ + GLRO(dl_platform) = NULL; +- GLRO(dl_hwcap) = 0; + #if !HAVE_TUNABLES && defined SHARED + /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do + this. */ +@@ -344,6 +343,7 @@ no_cpuid: + #endif + + #ifdef __x86_64__ ++ GLRO(dl_hwcap) = HWCAP_X86_64; + if (cpu_features->kind == arch_kind_intel) + { + if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) +@@ -374,6 +374,7 @@ no_cpuid: + GLRO(dl_platform) = "haswell"; + } + #else ++ GLRO(dl_hwcap) = 0; + if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) + GLRO(dl_hwcap) |= HWCAP_X86_SSE2; + +Index: glibc-2.26/sysdeps/x86/dl-hwcap.h +=================================================================== +--- glibc-2.26.orig/sysdeps/x86/dl-hwcap.h ++++ glibc-2.26/sysdeps/x86/dl-hwcap.h +@@ -24,15 +24,16 @@ + # define HWCAP_PLATFORMS_START 0 + # define HWCAP_PLATFORMS_COUNT 4 + # define HWCAP_START 0 +-# define HWCAP_COUNT 2 +-# define HWCAP_IMPORTANT (HWCAP_X86_SSE2 | HWCAP_X86_AVX512_1) ++# define HWCAP_COUNT 3 ++# define HWCAP_IMPORTANT \ ++ (HWCAP_X86_SSE2 | HWCAP_X86_64 | HWCAP_X86_AVX512_1) + #elif defined __x86_64__ + /* For 64 bit, only cover x86-64 platforms and capabilities. */ + # define HWCAP_PLATFORMS_START 2 + # define HWCAP_PLATFORMS_COUNT 4 + # define HWCAP_START 1 +-# define HWCAP_COUNT 2 +-# define HWCAP_IMPORTANT (HWCAP_X86_AVX512_1) ++# define HWCAP_COUNT 3 ++# define HWCAP_IMPORTANT (HWCAP_X86_64 | HWCAP_X86_AVX512_1) + #else + /* For 32 bit, only cover i586, i686 and SSE2. */ + # define HWCAP_PLATFORMS_START 0 +@@ -45,7 +46,8 @@ + enum + { + HWCAP_X86_SSE2 = 1 << 0, +- HWCAP_X86_AVX512_1 = 1 << 1 ++ HWCAP_X86_64 = 1 << 1, ++ HWCAP_X86_AVX512_1 = 1 << 2 + }; + + static inline const char * +Index: glibc-2.26/sysdeps/x86/dl-procinfo.c +=================================================================== +--- glibc-2.26.orig/sysdeps/x86/dl-procinfo.c ++++ glibc-2.26/sysdeps/x86/dl-procinfo.c +@@ -58,11 +58,11 @@ PROCINFO_CLASS struct cpu_features _dl_x + #if !defined PROCINFO_DECL && defined SHARED + ._dl_x86_hwcap_flags + #else +-PROCINFO_CLASS const char _dl_x86_hwcap_flags[2][9] ++PROCINFO_CLASS const char _dl_x86_hwcap_flags[3][9] + #endif + #ifndef PROCINFO_DECL + = { +- "sse2", "avx512_1" ++ "sse2", "x86_64", "avx512_1" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +Index: glibc-2.26/sysdeps/x86_64/Makefile +=================================================================== +--- glibc-2.26.orig/sysdeps/x86_64/Makefile ++++ glibc-2.26/sysdeps/x86_64/Makefile +@@ -52,6 +52,12 @@ $(objpfx)tst-quad2pie: $(objpfx)tst-quad + CFLAGS-tst-quad1pie.c = $(PIE-ccflag) + CFLAGS-tst-quad2pie.c = $(PIE-ccflag) + ++tests += tst-x86_64-1 ++modules-names += x86_64/tst-x86_64mod-1 ++LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so ++ ++$(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so ++ + tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ + tst-audit10 tst-sse tst-avx tst-avx512 + test-extras += tst-audit4-aux tst-audit10-aux \ +@@ -122,3 +128,14 @@ endif + ifeq ($(subdir),csu) + gen-as-const-headers += tlsdesc.sym rtld-offsets.sym + endif ++ ++$(objpfx)x86_64/tst-x86_64mod-1.os: $(objpfx)tst-x86_64mod-1.os ++ $(make-target-directory) ++ rm -f $@ ++ ln $< $@ ++ ++do-tests-clean common-mostlyclean: tst-x86_64-1-clean ++ ++.PHONY: tst-x86_64-1-clean ++tst-x86_64-1-clean: ++ -rm -rf $(objpfx)x86_64 +Index: glibc-2.26/sysdeps/x86_64/tst-x86_64-1.c +=================================================================== +--- /dev/null ++++ glibc-2.26/sysdeps/x86_64/tst-x86_64-1.c +@@ -0,0 +1,26 @@ ++/* Test searching the "x86_64" directory for shared libraries. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++extern void foo (void); ++ ++int ++main (void) ++{ ++ foo (); ++ return 0; ++} +Index: glibc-2.26/sysdeps/x86_64/tst-x86_64mod-1.c +=================================================================== +--- /dev/null ++++ glibc-2.26/sysdeps/x86_64/tst-x86_64mod-1.c +@@ -0,0 +1,22 @@ ++/* Test searching the "x86_64" directory for shared libraries. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++void ++foo (void) ++{ ++} diff --git a/math-c++-compat.patch b/math-c++-compat.patch index 4717366..8664d97 100644 --- a/math-c++-compat.patch +++ b/math-c++-compat.patch @@ -1,3 +1,9 @@ +2017-09-22 Gabriel F. T. Gomes + + [BZ #22146] + math/math.h: Let fpclassify use the builtin in C++ mode, even + when optimazing for size. + 2017-08-28 Gabriel F. T. Gomes [BZ #21930] @@ -26,11 +32,31 @@ * math/math.h (isinf): Check if in C or C++ mode before using __builtin_types_compatible_p, since this is a C mode feature. +2017-08-18 Gabriel F. T. Gomes + + * misc/sys/cdefs.h (__HAVE_GENERIC_SELECTION): Define to 0, if + in C++ mode. + Index: glibc-2.26/math/math.h =================================================================== --- glibc-2.26.orig/math/math.h +++ glibc-2.26/math/math.h -@@ -442,8 +442,12 @@ enum +@@ -402,7 +402,13 @@ enum + + /* Return number of classification appropriate for X. */ + # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ \ +- && !defined __OPTIMIZE_SIZE__ ++ && (!defined __OPTIMIZE_SIZE__ || defined __cplusplus) ++ /* The check for __cplusplus allows the use of the builtin, even ++ when optimization for size is on. This is provided for ++ libstdc++, only to let its configure test work when it is built ++ with -Os. No further use of this definition of fpclassify is ++ expected in C++ mode, since libstdc++ provides its own version ++ of fpclassify in cmath (which undefines fpclassify). */ + # define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \ + FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) + # else +@@ -442,8 +448,12 @@ enum /* Return nonzero value if X is positive or negative infinity. */ # if __HAVE_DISTINCT_FLOAT128 && !__GNUC_PREREQ (7,0) \ @@ -45,7 +71,7 @@ Index: glibc-2.26/math/math.h # define isinf(x) \ (__builtin_types_compatible_p (__typeof (x), _Float128) \ ? __isinff128 (x) : __builtin_isinf_sign (x)) -@@ -470,7 +474,32 @@ enum +@@ -470,7 +480,32 @@ enum # include /* Return nonzero value if X is a signaling NaN. */ @@ -79,7 +105,7 @@ Index: glibc-2.26/math/math.h /* Return nonzero value if X is subnormal. */ # define issubnormal(x) (fpclassify (x) == FP_SUBNORMAL) -@@ -484,15 +513,40 @@ enum +@@ -484,15 +519,40 @@ enum # endif # else /* __cplusplus */ extern "C++" { @@ -124,3 +150,35 @@ Index: glibc-2.26/math/math.h } /* extern C++ */ # endif /* __cplusplus */ #endif /* Use IEC_60559_BFP_EXT. */ +Index: glibc-2.26/misc/sys/cdefs.h +=================================================================== +--- glibc-2.26.orig/misc/sys/cdefs.h ++++ glibc-2.26/misc/sys/cdefs.h +@@ -464,17 +464,18 @@ + # define __glibc_macro_warning(msg) + #endif + +-/* Support for generic selection (ISO C11) is available in GCC since +- version 4.9. Previous versions do not provide generic selection, +- even though they might set __STDC_VERSION__ to 201112L, when in +- -std=c11 mode. Thus, we must check for !defined __GNUC__ when +- testing __STDC_VERSION__ for generic selection support. ++/* Generic selection (ISO C11) is a C-only feature, available in GCC ++ since version 4.9. Previous versions do not provide generic ++ selection, even though they might set __STDC_VERSION__ to 201112L, ++ when in -std=c11 mode. Thus, we must check for !defined __GNUC__ ++ when testing __STDC_VERSION__ for generic selection support. + On the other hand, Clang also defines __GNUC__, so a clang-specific + check is required to enable the use of generic selection. */ +-#if __GNUC_PREREQ (4, 9) \ +- || __glibc_clang_has_extension (c_generic_selections) \ +- || (!defined __GNUC__ && defined __STDC_VERSION__ \ +- && __STDC_VERSION__ >= 201112L) ++#if !defined __cplusplus \ ++ && (__GNUC_PREREQ (4, 9) \ ++ || __glibc_clang_has_extension (c_generic_selections) \ ++ || (!defined __GNUC__ && defined __STDC_VERSION__ \ ++ && __STDC_VERSION__ >= 201112L)) + # define __HAVE_GENERIC_SELECTION 1 + #else + # define __HAVE_GENERIC_SELECTION 0 diff --git a/nearbyint-inexact.patch b/nearbyint-inexact.patch new file mode 100644 index 0000000..aba9ec2 --- /dev/null +++ b/nearbyint-inexact.patch @@ -0,0 +1,107 @@ +2017-09-28 Joseph Myers + + [BZ #22225] + * sysdeps/ieee754/dbl-64/s_nearbyint.c (__nearbyint): Use + math_opt_barrier on argument when doing arithmetic on it. + * sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c (__nearbyint): + Likewise. Use math_force_eval not math_opt_barrier after + arithmetic. + * sysdeps/ieee754/flt-32/s_nearbyintf.c (__nearbyintf): Use + math_opt_barrier on argument when doing arithmetic on it. + * sysdeps/ieee754/ldbl-128/s_nearbyintl.c (__nearbyintl): + Likewise. + +Index: glibc-2.26/sysdeps/ieee754/dbl-64/s_nearbyint.c +=================================================================== +--- glibc-2.26.orig/sysdeps/ieee754/dbl-64/s_nearbyint.c ++++ glibc-2.26/sysdeps/ieee754/dbl-64/s_nearbyint.c +@@ -48,7 +48,7 @@ __nearbyint (double x) + if (j0 < 0) + { + libc_feholdexcept (&env); +- w = TWO52[sx] + x; ++ w = TWO52[sx] + math_opt_barrier (x); + t = w - TWO52[sx]; + math_force_eval (t); + libc_fesetenv (&env); +@@ -65,7 +65,7 @@ __nearbyint (double x) + return x; /* x is integral */ + } + libc_feholdexcept (&env); +- w = TWO52[sx] + x; ++ w = TWO52[sx] + math_opt_barrier (x); + t = w - TWO52[sx]; + math_force_eval (t); + libc_fesetenv (&env); +Index: glibc-2.26/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c +=================================================================== +--- glibc-2.26.orig/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c ++++ glibc-2.26/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c +@@ -42,9 +42,9 @@ __nearbyint(double x) + if(__builtin_expect(j0<52, 1)) { + if(j0<0) { + libc_feholdexcept (&env); +- double w = TWO52[sx]+x; ++ double w = TWO52[sx] + math_opt_barrier (x); + double t = w-TWO52[sx]; +- math_opt_barrier(t); ++ math_force_eval (t); + libc_fesetenv (&env); + return __copysign (t, x); + } +@@ -53,9 +53,9 @@ __nearbyint(double x) + else return x; /* x is integral */ + } + libc_feholdexcept (&env); +- double w = TWO52[sx]+x; ++ double w = TWO52[sx] + math_opt_barrier (x); + double t = w-TWO52[sx]; +- math_opt_barrier (t); ++ math_force_eval (t); + libc_fesetenv (&env); + return t; + } +Index: glibc-2.26/sysdeps/ieee754/flt-32/s_nearbyintf.c +=================================================================== +--- glibc-2.26.orig/sysdeps/ieee754/flt-32/s_nearbyintf.c ++++ glibc-2.26/sysdeps/ieee754/flt-32/s_nearbyintf.c +@@ -37,7 +37,7 @@ __nearbyintf(float x) + if(j0<23) { + if(j0<0) { + libc_feholdexceptf (&env); +- w = TWO23[sx]+x; ++ w = TWO23[sx] + math_opt_barrier (x); + t = w-TWO23[sx]; + math_force_eval (t); + libc_fesetenvf (&env); +@@ -50,7 +50,7 @@ __nearbyintf(float x) + else return x; /* x is integral */ + } + libc_feholdexceptf (&env); +- w = TWO23[sx]+x; ++ w = TWO23[sx] + math_opt_barrier (x); + t = w-TWO23[sx]; + math_force_eval (t); + libc_fesetenvf (&env); +Index: glibc-2.26/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +=================================================================== +--- glibc-2.26.orig/sysdeps/ieee754/ldbl-128/s_nearbyintl.c ++++ glibc-2.26/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +@@ -45,7 +45,7 @@ _Float128 __nearbyintl(_Float128 x) + if(j0<112) { + if(j0<0) { + feholdexcept (&env); +- w = TWO112[sx]+x; ++ w = TWO112[sx] + math_opt_barrier (x); + t = w-TWO112[sx]; + math_force_eval (t); + fesetenv (&env); +@@ -58,7 +58,7 @@ _Float128 __nearbyintl(_Float128 x) + else return x; /* x is integral */ + } + feholdexcept (&env); +- w = TWO112[sx]+x; ++ w = TWO112[sx] + math_opt_barrier (x); + t = w-TWO112[sx]; + math_force_eval (t); + fesetenv (&env); diff --git a/nss-compat.patch b/nss-compat.patch new file mode 100644 index 0000000..cc4819e --- /dev/null +++ b/nss-compat.patch @@ -0,0 +1,6745 @@ +2017-10-04 Andreas Schwab + + * nis/Makefile (services): Remove compat. + (libnss_compat-routines, libnss_compat-inhibit-o): Don't define. + ($(objpfx)libnss_compat.so): Remove rule. + * nis/Versions (libnss_compat): Remove. + * nss/Makefile (services): Add compat. + (libnss_compat-routines, libnss_compat-inhibit-o): Define. + * nss/Versions (libnss_compat): Define. + * nss/nss_compat/compat-grp.c: Moved here from nis/nss_compat. + Don't include . Replace bool_t by bool. + * nss/nss_compat/compat-initgroups.c: Likewise. + * nss/nss_compat/compat-pwd.c: Likewise. Include "nisdomain.h" + instead of . + (getpwent_next_nss_netgr): Use __nss_get_default_domain instead of + yp_get_default_domain. + * nss/nss_compat/compat-pwd.c: Likewise. + (getspent_next_nss_netgr): Use __nss_get_default_domain instead of + yp_get_default_domain. + * nss/nss_compat/nisdomain.c: New file. + * nss/nss_compat/nisdomain.h: Likewise. + +Index: glibc-2.26/nis/Makefile +=================================================================== +--- glibc-2.26.orig/nis/Makefile ++++ glibc-2.26/nis/Makefile +@@ -33,7 +33,7 @@ databases = proto service hosts network + spwd netgrp alias publickey + + # Specify rules for the nss_* modules. +-services := nis nisplus compat ++services := nis nisplus + endif + + extra-libs = libnsl +@@ -63,9 +63,6 @@ libnsl-routines = yp_xdr ypclnt ypupdate + nis_clone_res nss-default + + ifeq ($(build-obsolete-nsl),yes) +-libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) +-libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) +- + libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \ + nss-nis + libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) +@@ -79,7 +76,6 @@ include ../Rules + + + ifeq ($(build-obsolete-nsl),yes) +-$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version) + $(objpfx)libnss_nis.so: $(objpfx)libnsl.so$(libnsl.so-version) \ + $(common-objpfx)nss/libnss_files.so + $(objpfx)libnss_nisplus.so: $(objpfx)libnsl.so$(libnsl.so-version) +Index: glibc-2.26/nis/Versions +=================================================================== +--- glibc-2.26.orig/nis/Versions ++++ glibc-2.26/nis/Versions +@@ -63,17 +63,6 @@ libnsl { + } + } + +-libnss_compat { +- GLIBC_PRIVATE { +- _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent; +- _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r; +- _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r; +- _nss_compat_getspent_r; _nss_compat_getspnam_r; +- _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent; +- _nss_compat_initgroups_dyn; +- } +-} +- + libnss_nis { + GLIBC_PRIVATE { + _nss_nis_endaliasent; _nss_nis_endetherent; _nss_nis_endgrent; +Index: glibc-2.26/nis/nss_compat/compat-grp.c +=================================================================== +--- glibc-2.26.orig/nis/nss_compat/compat-grp.c ++++ /dev/null +@@ -1,683 +0,0 @@ +-/* Copyright (C) 1996-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Thorsten Kukuk , 1996. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-static service_user *ni; +-static enum nss_status (*nss_setgrent) (int stayopen); +-static enum nss_status (*nss_getgrnam_r) (const char *name, +- struct group * grp, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, +- char *buffer, size_t buflen, +- int *errnop); +-static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_endgrent) (void); +- +-/* Get the declaration of the parser function. */ +-#define ENTNAME grent +-#define STRUCTURE group +-#define EXTERN_PARSER +-#include +- +-/* Structure for remembering -group members ... */ +-#define BLACKLIST_INITIAL_SIZE 512 +-#define BLACKLIST_INCREMENT 256 +-struct blacklist_t +-{ +- char *data; +- int current; +- int size; +-}; +- +-struct ent_t +-{ +- bool_t files; +- enum nss_status setent_status; +- FILE *stream; +- struct blacklist_t blacklist; +-}; +-typedef struct ent_t ent_t; +- +-static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; +- +-/* Protect global state against multiple changers. */ +-__libc_lock_define_initialized (static, lock) +- +-/* Prototypes for local functions. */ +-static void blacklist_store_name (const char *, ent_t *); +-static int in_blacklist (const char *, int, ent_t *); +- +-/* Initialize the NSS interface/functions. The calling function must +- hold the lock. */ +-static void +-init_nss_interface (void) +-{ +- if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) +- { +- nss_setgrent = __nss_lookup_function (ni, "setgrent"); +- nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); +- nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); +- nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); +- nss_endgrent = __nss_lookup_function (ni, "endgrent"); +- } +-} +- +-static enum nss_status +-internal_setgrent (ent_t *ent, int stayopen, int needent) +-{ +- enum nss_status status = NSS_STATUS_SUCCESS; +- +- ent->files = TRUE; +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- if (ent->stream == NULL) +- { +- ent->stream = fopen ("/etc/group", "rme"); +- +- if (ent->stream == NULL) +- status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); +- } +- else +- rewind (ent->stream); +- +- if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent) +- ent->setent_status = nss_setgrent (stayopen); +- +- return status; +-} +- +- +-enum nss_status +-_nss_compat_setgrent (int stayopen) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- result = internal_setgrent (&ext_ent, stayopen, 1); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-static enum nss_status +-internal_endgrent (ent_t *ent) +-{ +- if (ent->stream != NULL) +- { +- fclose (ent->stream); +- ent->stream = NULL; +- } +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_endgrent (void) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (nss_endgrent) +- nss_endgrent (); +- +- result = internal_endgrent (&ext_ent); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +-/* get the next group from NSS (+ entry) */ +-static enum nss_status +-getgrent_next_nss (struct group *result, ent_t *ent, char *buffer, +- size_t buflen, int *errnop) +-{ +- if (!nss_getgrent_r) +- return NSS_STATUS_UNAVAIL; +- +- /* If the setgrent call failed, say so. */ +- if (ent->setent_status != NSS_STATUS_SUCCESS) +- return ent->setent_status; +- +- do +- { +- enum nss_status status; +- +- if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) != +- NSS_STATUS_SUCCESS) +- return status; +- } +- while (in_blacklist (result->gr_name, strlen (result->gr_name), ent)); +- +- return NSS_STATUS_SUCCESS; +-} +- +-/* This function handle the +group entrys in /etc/group */ +-static enum nss_status +-getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- if (!nss_getgrnam_r) +- return NSS_STATUS_UNAVAIL; +- +- enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen, +- errnop); +- if (status != NSS_STATUS_SUCCESS) +- return status; +- +- if (in_blacklist (result->gr_name, strlen (result->gr_name), ent)) +- return NSS_STATUS_NOTFOUND; +- +- /* We found the entry. */ +- return NSS_STATUS_SUCCESS; +-} +- +-static enum nss_status +-getgrent_next_file (struct group *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- while (1) +- { +- fpos_t pos; +- int parse_res = 0; +- char *p; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_grent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- if (result->gr_name[0] != '+' && result->gr_name[0] != '-') +- /* This is a real entry. */ +- break; +- +- /* -group */ +- if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' +- && result->gr_name[1] != '@') +- { +- blacklist_store_name (&result->gr_name[1], ent); +- continue; +- } +- +- /* +group */ +- if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' +- && result->gr_name[1] != '@') +- { +- size_t len = strlen (result->gr_name); +- char buf[len]; +- enum nss_status status; +- +- /* Store the group in the blacklist for the "+" at the end of +- /etc/group */ +- memcpy (buf, &result->gr_name[1], len); +- status = getgrnam_plusgroup (&result->gr_name[1], result, ent, +- buffer, buflen, errnop); +- blacklist_store_name (buf, ent); +- if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ +- break; +- else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry*/ +- || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ +- continue; +- else +- { +- if (status == NSS_STATUS_TRYAGAIN) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- return status; +- } +- } +- +- /* +:... */ +- if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') +- { +- ent->files = FALSE; +- +- return getgrent_next_nss (result, ent, buffer, buflen, errnop); +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-enum nss_status +-_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, +- int *errnop) +-{ +- enum nss_status result = NSS_STATUS_SUCCESS; +- +- __libc_lock_lock (lock); +- +- /* Be prepared that the setgrent function was not called before. */ +- if (ni == NULL) +- init_nss_interface (); +- +- if (ext_ent.stream == NULL) +- result = internal_setgrent (&ext_ent, 1, 1); +- +- if (result == NSS_STATUS_SUCCESS) +- { +- if (ext_ent.files) +- result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop); +- else +- result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop); +- } +- __libc_lock_unlock (lock); +- +- return result; +-} +- +-/* Searches in /etc/group and the NIS/NIS+ map for a special group */ +-static enum nss_status +-internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- while (1) +- { +- fpos_t pos; +- int parse_res = 0; +- char *p; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_grent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- /* This is a real entry. */ +- if (result->gr_name[0] != '+' && result->gr_name[0] != '-') +- { +- if (strcmp (result->gr_name, name) == 0) +- return NSS_STATUS_SUCCESS; +- else +- continue; +- } +- +- /* -group */ +- if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') +- { +- if (strcmp (&result->gr_name[1], name) == 0) +- return NSS_STATUS_NOTFOUND; +- else +- continue; +- } +- +- /* +group */ +- if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') +- { +- if (strcmp (name, &result->gr_name[1]) == 0) +- { +- enum nss_status status; +- +- status = getgrnam_plusgroup (name, result, ent, +- buffer, buflen, errnop); +- if (status == NSS_STATUS_RETURN) +- /* We couldn't parse the entry */ +- continue; +- else +- return status; +- } +- } +- /* +:... */ +- if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') +- { +- enum nss_status status; +- +- status = getgrnam_plusgroup (name, result, ent, +- buffer, buflen, errnop); +- if (status == NSS_STATUS_RETURN) +- /* We couldn't parse the entry */ +- continue; +- else +- return status; +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_getgrnam_r (const char *name, struct group *grp, +- char *buffer, size_t buflen, int *errnop) +-{ +- ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; +- enum nss_status result; +- +- if (name[0] == '-' || name[0] == '+') +- return NSS_STATUS_NOTFOUND; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- __libc_lock_unlock (lock); +- +- result = internal_setgrent (&ent, 0, 0); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); +- +- internal_endgrent (&ent); +- +- return result; +-} +- +-/* Searches in /etc/group and the NIS/NIS+ map for a special group id */ +-static enum nss_status +-internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- while (1) +- { +- fpos_t pos; +- int parse_res = 0; +- char *p; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_grent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- /* This is a real entry. */ +- if (result->gr_name[0] != '+' && result->gr_name[0] != '-') +- { +- if (result->gr_gid == gid) +- return NSS_STATUS_SUCCESS; +- else +- continue; +- } +- +- /* -group */ +- if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') +- { +- blacklist_store_name (&result->gr_name[1], ent); +- continue; +- } +- +- /* +group */ +- if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') +- { +- /* Yes, no +1, see the memcpy call below. */ +- size_t len = strlen (result->gr_name); +- char buf[len]; +- enum nss_status status; +- +- /* Store the group in the blacklist for the "+" at the end of +- /etc/group */ +- memcpy (buf, &result->gr_name[1], len); +- status = getgrnam_plusgroup (&result->gr_name[1], result, ent, +- buffer, buflen, errnop); +- blacklist_store_name (buf, ent); +- if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) +- break; +- else +- continue; +- } +- /* +:... */ +- if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') +- { +- if (!nss_getgrgid_r) +- return NSS_STATUS_UNAVAIL; +- +- enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen, +- errnop); +- if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_getgrgid_r (gid_t gid, struct group *grp, +- char *buffer, size_t buflen, int *errnop) +-{ +- ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- __libc_lock_unlock (lock); +- +- result = internal_setgrent (&ent, 0, 0); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); +- +- internal_endgrent (&ent); +- +- return result; +-} +- +- +-/* Support routines for remembering -@netgroup and -user entries. +- The names are stored in a single string with `|' as separator. */ +-static void +-blacklist_store_name (const char *name, ent_t *ent) +-{ +- int namelen = strlen (name); +- char *tmp; +- +- /* first call, setup cache */ +- if (ent->blacklist.size == 0) +- { +- ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); +- ent->blacklist.data = malloc (ent->blacklist.size); +- if (ent->blacklist.data == NULL) +- return; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- ent->blacklist.current = 1; +- } +- else +- { +- if (in_blacklist (name, namelen, ent)) +- return; /* no duplicates */ +- +- if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) +- { +- ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); +- tmp = realloc (ent->blacklist.data, ent->blacklist.size); +- if (tmp == NULL) +- { +- free (ent->blacklist.data); +- ent->blacklist.size = 0; +- return; +- } +- ent->blacklist.data = tmp; +- } +- } +- +- tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); +- *tmp++ = '|'; +- *tmp = '\0'; +- ent->blacklist.current += namelen + 1; +- +- return; +-} +- +-/* returns TRUE if ent->blacklist contains name, else FALSE */ +-static bool_t +-in_blacklist (const char *name, int namelen, ent_t *ent) +-{ +- char buf[namelen + 3]; +- char *cp; +- +- if (ent->blacklist.data == NULL) +- return FALSE; +- +- buf[0] = '|'; +- cp = stpcpy (&buf[1], name); +- *cp++ = '|'; +- *cp = '\0'; +- return strstr (ent->blacklist.data, buf) != NULL; +-} +Index: glibc-2.26/nis/nss_compat/compat-initgroups.c +=================================================================== +--- glibc-2.26.orig/nis/nss_compat/compat-initgroups.c ++++ /dev/null +@@ -1,576 +0,0 @@ +-/* Copyright (C) 1998-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Thorsten Kukuk , 1998. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-static service_user *ni; +-/* Type of the lookup function. */ +-static enum nss_status (*nss_initgroups_dyn) (const char *, gid_t, +- long int *, long int *, +- gid_t **, long int, int *); +-static enum nss_status (*nss_getgrnam_r) (const char *name, +- struct group * grp, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, +- char *buffer, size_t buflen, +- int *errnop); +-static enum nss_status (*nss_setgrent) (int stayopen); +-static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_endgrent) (void); +- +-/* Protect global state against multiple changers. */ +-__libc_lock_define_initialized (static, lock) +- +- +-/* Get the declaration of the parser function. */ +-#define ENTNAME grent +-#define STRUCTURE group +-#define EXTERN_PARSER +-#include +- +-/* Structure for remembering -group members ... */ +-#define BLACKLIST_INITIAL_SIZE 512 +-#define BLACKLIST_INCREMENT 256 +-struct blacklist_t +-{ +- char *data; +- int current; +- int size; +-}; +- +-struct ent_t +-{ +- bool files; +- bool need_endgrent; +- bool skip_initgroups_dyn; +- FILE *stream; +- struct blacklist_t blacklist; +-}; +-typedef struct ent_t ent_t; +- +-/* Prototypes for local functions. */ +-static void blacklist_store_name (const char *, ent_t *); +-static int in_blacklist (const char *, int, ent_t *); +- +-/* Initialize the NSS interface/functions. The calling function must +- hold the lock. */ +-static void +-init_nss_interface (void) +-{ +- __libc_lock_lock (lock); +- +- /* Retest. */ +- if (ni == NULL +- && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) +- { +- nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn"); +- nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); +- nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); +- nss_setgrent = __nss_lookup_function (ni, "setgrent"); +- nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); +- nss_endgrent = __nss_lookup_function (ni, "endgrent"); +- } +- +- __libc_lock_unlock (lock); +-} +- +-static enum nss_status +-internal_setgrent (ent_t *ent) +-{ +- enum nss_status status = NSS_STATUS_SUCCESS; +- +- ent->files = true; +- +- if (ni == NULL) +- init_nss_interface (); +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- ent->stream = fopen ("/etc/group", "rme"); +- +- if (ent->stream == NULL) +- status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); +- +- return status; +-} +- +- +-static enum nss_status +-internal_endgrent (ent_t *ent) +-{ +- if (ent->stream != NULL) +- { +- fclose (ent->stream); +- ent->stream = NULL; +- } +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- if (ent->need_endgrent && nss_endgrent != NULL) +- nss_endgrent (); +- +- return NSS_STATUS_SUCCESS; +-} +- +-/* Add new group record. */ +-static void +-add_group (long int *start, long int *size, gid_t **groupsp, long int limit, +- gid_t gid) +-{ +- gid_t *groups = *groupsp; +- +- /* Matches user. Insert this group. */ +- if (__glibc_unlikely (*start == *size)) +- { +- /* Need a bigger buffer. */ +- gid_t *newgroups; +- long int newsize; +- +- if (limit > 0 && *size == limit) +- /* We reached the maximum. */ +- return; +- +- if (limit <= 0) +- newsize = 2 * *size; +- else +- newsize = MIN (limit, 2 * *size); +- +- newgroups = realloc (groups, newsize * sizeof (*groups)); +- if (newgroups == NULL) +- return; +- *groupsp = groups = newgroups; +- *size = newsize; +- } +- +- groups[*start] = gid; +- *start += 1; +-} +- +-/* This function checks, if the user is a member of this group and if +- yes, add the group id to the list. Return nonzero is we couldn't +- handle the group because the user is not in the member list. */ +-static int +-check_and_add_group (const char *user, gid_t group, long int *start, +- long int *size, gid_t **groupsp, long int limit, +- struct group *grp) +-{ +- char **member; +- +- /* Don't add main group to list of groups. */ +- if (grp->gr_gid == group) +- return 0; +- +- for (member = grp->gr_mem; *member != NULL; ++member) +- if (strcmp (*member, user) == 0) +- { +- add_group (start, size, groupsp, limit, grp->gr_gid); +- return 0; +- } +- +- return 1; +-} +- +-/* Get the next group from NSS (+ entry). If the NSS module supports +- initgroups_dyn, get all entries at once. */ +-static enum nss_status +-getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user, +- gid_t group, long int *start, long int *size, +- gid_t **groupsp, long int limit, int *errnop) +-{ +- enum nss_status status; +- struct group grpbuf; +- +- /* Try nss_initgroups_dyn if supported. We also need getgrgid_r. +- If this function is not supported, step through the whole group +- database with getgrent_r. */ +- if (! ent->skip_initgroups_dyn) +- { +- long int mystart = 0; +- long int mysize = limit <= 0 ? *size : limit; +- gid_t *mygroups = malloc (mysize * sizeof (gid_t)); +- +- if (mygroups == NULL) +- return NSS_STATUS_TRYAGAIN; +- +- /* For every gid in the list we get from the NSS module, +- get the whole group entry. We need to do this, since we +- need the group name to check if it is in the blacklist. +- In worst case, this is as twice as slow as stepping with +- getgrent_r through the whole group database. But for large +- group databases this is faster, since the user can only be +- in a limited number of groups. */ +- if (nss_initgroups_dyn (user, group, &mystart, &mysize, &mygroups, +- limit, errnop) == NSS_STATUS_SUCCESS) +- { +- status = NSS_STATUS_NOTFOUND; +- +- /* If there is no blacklist we can trust the underlying +- initgroups implementation. */ +- if (ent->blacklist.current <= 1) +- for (int i = 0; i < mystart; i++) +- add_group (start, size, groupsp, limit, mygroups[i]); +- else +- { +- /* A temporary buffer. We use the normal buffer, until we find +- an entry, for which this buffer is to small. In this case, we +- overwrite the pointer with one to a bigger buffer. */ +- char *tmpbuf = buffer; +- size_t tmplen = buflen; +- bool use_malloc = false; +- +- for (int i = 0; i < mystart; i++) +- { +- while ((status = nss_getgrgid_r (mygroups[i], &grpbuf, +- tmpbuf, tmplen, errnop)) +- == NSS_STATUS_TRYAGAIN +- && *errnop == ERANGE) +- { +- if (__libc_use_alloca (tmplen * 2)) +- { +- if (tmpbuf == buffer) +- { +- tmplen *= 2; +- tmpbuf = __alloca (tmplen); +- } +- else +- tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2); +- } +- else +- { +- tmplen *= 2; +- char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen); +- +- if (newbuf == NULL) +- { +- status = NSS_STATUS_TRYAGAIN; +- goto done; +- } +- use_malloc = true; +- tmpbuf = newbuf; +- } +- } +- +- if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1)) +- { +- if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) +- goto done; +- +- if (!in_blacklist (grpbuf.gr_name, +- strlen (grpbuf.gr_name), ent) +- && check_and_add_group (user, group, start, size, +- groupsp, limit, &grpbuf)) +- { +- if (nss_setgrent != NULL) +- { +- nss_setgrent (1); +- ent->need_endgrent = true; +- } +- ent->skip_initgroups_dyn = true; +- +- goto iter; +- } +- } +- } +- +- status = NSS_STATUS_NOTFOUND; +- +- done: +- if (use_malloc) +- free (tmpbuf); +- } +- +- free (mygroups); +- +- return status; +- } +- +- free (mygroups); +- } +- +- /* If we come here, the NSS module does not support initgroups_dyn +- or we were confronted with a split group. In these cases we have +- to step through the whole list ourself. */ +- iter: +- do +- { +- if ((status = nss_getgrent_r (&grpbuf, buffer, buflen, errnop)) != +- NSS_STATUS_SUCCESS) +- break; +- } +- while (in_blacklist (grpbuf.gr_name, strlen (grpbuf.gr_name), ent)); +- +- if (status == NSS_STATUS_SUCCESS) +- check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); +- +- return status; +-} +- +-static enum nss_status +-internal_getgrent_r (ent_t *ent, char *buffer, size_t buflen, const char *user, +- gid_t group, long int *start, long int *size, +- gid_t **groupsp, long int limit, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- struct group grpbuf; +- +- if (!ent->files) +- return getgrent_next_nss (ent, buffer, buflen, user, group, +- start, size, groupsp, limit, errnop); +- +- while (1) +- { +- fpos_t pos; +- int parse_res = 0; +- char *p; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_grent (p, &grpbuf, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- if (grpbuf.gr_name[0] != '+' && grpbuf.gr_name[0] != '-') +- /* This is a real entry. */ +- break; +- +- /* -group */ +- if (grpbuf.gr_name[0] == '-' && grpbuf.gr_name[1] != '\0' +- && grpbuf.gr_name[1] != '@') +- { +- blacklist_store_name (&grpbuf.gr_name[1], ent); +- continue; +- } +- +- /* +group */ +- if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] != '\0' +- && grpbuf.gr_name[1] != '@') +- { +- if (in_blacklist (&grpbuf.gr_name[1], +- strlen (&grpbuf.gr_name[1]), ent)) +- continue; +- /* Store the group in the blacklist for the "+" at the end of +- /etc/group */ +- blacklist_store_name (&grpbuf.gr_name[1], ent); +- if (nss_getgrnam_r == NULL) +- return NSS_STATUS_UNAVAIL; +- else if (nss_getgrnam_r (&grpbuf.gr_name[1], &grpbuf, buffer, +- buflen, errnop) != NSS_STATUS_SUCCESS) +- continue; +- +- check_and_add_group (user, group, start, size, groupsp, +- limit, &grpbuf); +- +- return NSS_STATUS_SUCCESS; +- } +- +- /* +:... */ +- if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] == '\0') +- { +- /* If the selected module does not support getgrent_r or +- initgroups_dyn, abort. We cannot find the needed group +- entries. */ +- if (nss_initgroups_dyn == NULL || nss_getgrgid_r == NULL) +- { +- if (nss_setgrent != NULL) +- { +- nss_setgrent (1); +- ent->need_endgrent = true; +- } +- ent->skip_initgroups_dyn = true; +- +- if (nss_getgrent_r == NULL) +- return NSS_STATUS_UNAVAIL; +- } +- +- ent->files = false; +- +- return getgrent_next_nss (ent, buffer, buflen, user, group, +- start, size, groupsp, limit, errnop); +- } +- } +- +- check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-enum nss_status +-_nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, +- long int *size, gid_t **groupsp, long int limit, +- int *errnop) +-{ +- enum nss_status status; +- ent_t intern = { true, false, false, NULL, {NULL, 0, 0} }; +- +- status = internal_setgrent (&intern); +- if (status != NSS_STATUS_SUCCESS) +- return status; +- +- struct scratch_buffer tmpbuf; +- scratch_buffer_init (&tmpbuf); +- +- do +- { +- while ((status = internal_getgrent_r (&intern, tmpbuf.data, tmpbuf.length, +- user, group, start, size, +- groupsp, limit, errnop)) +- == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) +- if (!scratch_buffer_grow (&tmpbuf)) +- goto done; +- } +- while (status == NSS_STATUS_SUCCESS); +- +- status = NSS_STATUS_SUCCESS; +- +- done: +- scratch_buffer_free (&tmpbuf); +- +- internal_endgrent (&intern); +- +- return status; +-} +- +- +-/* Support routines for remembering -@netgroup and -user entries. +- The names are stored in a single string with `|' as separator. */ +-static void +-blacklist_store_name (const char *name, ent_t *ent) +-{ +- int namelen = strlen (name); +- char *tmp; +- +- /* First call, setup cache. */ +- if (ent->blacklist.size == 0) +- { +- ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); +- ent->blacklist.data = malloc (ent->blacklist.size); +- if (ent->blacklist.data == NULL) +- return; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- ent->blacklist.current = 1; +- } +- else +- { +- if (in_blacklist (name, namelen, ent)) +- return; /* no duplicates */ +- +- if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) +- { +- ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); +- tmp = realloc (ent->blacklist.data, ent->blacklist.size); +- if (tmp == NULL) +- { +- free (ent->blacklist.data); +- ent->blacklist.size = 0; +- return; +- } +- ent->blacklist.data = tmp; +- } +- } +- +- tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); +- *tmp++ = '|'; +- *tmp = '\0'; +- ent->blacklist.current += namelen + 1; +- +- return; +-} +- +-/* returns TRUE if ent->blacklist contains name, else FALSE */ +-static bool_t +-in_blacklist (const char *name, int namelen, ent_t *ent) +-{ +- char buf[namelen + 3]; +- char *cp; +- +- if (ent->blacklist.data == NULL) +- return FALSE; +- +- buf[0] = '|'; +- cp = stpcpy (&buf[1], name); +- *cp++ = '|'; +- *cp = '\0'; +- return strstr (ent->blacklist.data, buf) != NULL; +-} +Index: glibc-2.26/nis/nss_compat/compat-pwd.c +=================================================================== +--- glibc-2.26.orig/nis/nss_compat/compat-pwd.c ++++ /dev/null +@@ -1,1132 +0,0 @@ +-/* Copyright (C) 1996-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Thorsten Kukuk , 1996. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "netgroup.h" +- +-static service_user *ni; +-static enum nss_status (*nss_setpwent) (int stayopen); +-static enum nss_status (*nss_getpwnam_r) (const char *name, +- struct passwd * pwd, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_getpwuid_r) (uid_t uid, struct passwd * pwd, +- char *buffer, size_t buflen, +- int *errnop); +-static enum nss_status (*nss_getpwent_r) (struct passwd * pwd, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_endpwent) (void); +- +-/* Get the declaration of the parser function. */ +-#define ENTNAME pwent +-#define STRUCTURE passwd +-#define EXTERN_PARSER +-#include +- +-/* Structure for remembering -@netgroup and -user members ... */ +-#define BLACKLIST_INITIAL_SIZE 512 +-#define BLACKLIST_INCREMENT 256 +-struct blacklist_t +-{ +- char *data; +- int current; +- int size; +-}; +- +-struct ent_t +-{ +- bool netgroup; +- bool first; +- bool files; +- enum nss_status setent_status; +- FILE *stream; +- struct blacklist_t blacklist; +- struct passwd pwd; +- struct __netgrent netgrdata; +-}; +-typedef struct ent_t ent_t; +- +-static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, +- { NULL, 0, 0 }, +- { NULL, NULL, 0, 0, NULL, NULL, NULL }}; +- +-/* Protect global state against multiple changers. */ +-__libc_lock_define_initialized (static, lock) +- +-/* Prototypes for local functions. */ +-static void blacklist_store_name (const char *, ent_t *); +-static int in_blacklist (const char *, int, ent_t *); +- +-/* Initialize the NSS interface/functions. The calling function must +- hold the lock. */ +-static void +-init_nss_interface (void) +-{ +- if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0) +- { +- nss_setpwent = __nss_lookup_function (ni, "setpwent"); +- nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r"); +- nss_getpwuid_r = __nss_lookup_function (ni, "getpwuid_r"); +- nss_getpwent_r = __nss_lookup_function (ni, "getpwent_r"); +- nss_endpwent = __nss_lookup_function (ni, "endpwent"); +- } +-} +- +-static void +-give_pwd_free (struct passwd *pwd) +-{ +- free (pwd->pw_name); +- free (pwd->pw_passwd); +- free (pwd->pw_gecos); +- free (pwd->pw_dir); +- free (pwd->pw_shell); +- +- memset (pwd, '\0', sizeof (struct passwd)); +-} +- +-static size_t +-pwd_need_buflen (struct passwd *pwd) +-{ +- size_t len = 0; +- +- if (pwd->pw_passwd != NULL) +- len += strlen (pwd->pw_passwd) + 1; +- +- if (pwd->pw_gecos != NULL) +- len += strlen (pwd->pw_gecos) + 1; +- +- if (pwd->pw_dir != NULL) +- len += strlen (pwd->pw_dir) + 1; +- +- if (pwd->pw_shell != NULL) +- len += strlen (pwd->pw_shell) + 1; +- +- return len; +-} +- +-static void +-copy_pwd_changes (struct passwd *dest, struct passwd *src, +- char *buffer, size_t buflen) +-{ +- if (src->pw_passwd != NULL && strlen (src->pw_passwd)) +- { +- if (buffer == NULL) +- dest->pw_passwd = strdup (src->pw_passwd); +- else if (dest->pw_passwd && +- strlen (dest->pw_passwd) >= strlen (src->pw_passwd)) +- strcpy (dest->pw_passwd, src->pw_passwd); +- else +- { +- dest->pw_passwd = buffer; +- strcpy (dest->pw_passwd, src->pw_passwd); +- buffer += strlen (dest->pw_passwd) + 1; +- buflen = buflen - (strlen (dest->pw_passwd) + 1); +- } +- } +- +- if (src->pw_gecos != NULL && strlen (src->pw_gecos)) +- { +- if (buffer == NULL) +- dest->pw_gecos = strdup (src->pw_gecos); +- else if (dest->pw_gecos && +- strlen (dest->pw_gecos) >= strlen (src->pw_gecos)) +- strcpy (dest->pw_gecos, src->pw_gecos); +- else +- { +- dest->pw_gecos = buffer; +- strcpy (dest->pw_gecos, src->pw_gecos); +- buffer += strlen (dest->pw_gecos) + 1; +- buflen = buflen - (strlen (dest->pw_gecos) + 1); +- } +- } +- if (src->pw_dir != NULL && strlen (src->pw_dir)) +- { +- if (buffer == NULL) +- dest->pw_dir = strdup (src->pw_dir); +- else if (dest->pw_dir && strlen (dest->pw_dir) >= strlen (src->pw_dir)) +- strcpy (dest->pw_dir, src->pw_dir); +- else +- { +- dest->pw_dir = buffer; +- strcpy (dest->pw_dir, src->pw_dir); +- buffer += strlen (dest->pw_dir) + 1; +- buflen = buflen - (strlen (dest->pw_dir) + 1); +- } +- } +- +- if (src->pw_shell != NULL && strlen (src->pw_shell)) +- { +- if (buffer == NULL) +- dest->pw_shell = strdup (src->pw_shell); +- else if (dest->pw_shell && +- strlen (dest->pw_shell) >= strlen (src->pw_shell)) +- strcpy (dest->pw_shell, src->pw_shell); +- else +- { +- dest->pw_shell = buffer; +- strcpy (dest->pw_shell, src->pw_shell); +- buffer += strlen (dest->pw_shell) + 1; +- buflen = buflen - (strlen (dest->pw_shell) + 1); +- } +- } +-} +- +-static enum nss_status +-internal_setpwent (ent_t *ent, int stayopen, int needent) +-{ +- enum nss_status status = NSS_STATUS_SUCCESS; +- +- ent->first = ent->netgroup = false; +- ent->files = true; +- ent->setent_status = NSS_STATUS_SUCCESS; +- +- /* If something was left over free it. */ +- if (ent->netgroup) +- __internal_endnetgrent (&ent->netgrdata); +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- if (ent->stream == NULL) +- { +- ent->stream = fopen ("/etc/passwd", "rme"); +- +- if (ent->stream == NULL) +- status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); +- } +- else +- rewind (ent->stream); +- +- give_pwd_free (&ent->pwd); +- +- if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent) +- ent->setent_status = nss_setpwent (stayopen); +- +- return status; +-} +- +- +-enum nss_status +-_nss_compat_setpwent (int stayopen) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- result = internal_setpwent (&ext_ent, stayopen, 1); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-static enum nss_status +-internal_endpwent (ent_t *ent) +-{ +- if (ent->stream != NULL) +- { +- fclose (ent->stream); +- ent->stream = NULL; +- } +- +- if (ent->netgroup) +- __internal_endnetgrent (&ent->netgrdata); +- +- ent->first = ent->netgroup = false; +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- give_pwd_free (&ent->pwd); +- +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_endpwent (void) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (nss_endpwent) +- nss_endpwent (); +- +- result = internal_endpwent (&ext_ent); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-static enum nss_status +-getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent, +- char *group, char *buffer, size_t buflen, +- int *errnop) +-{ +- char *curdomain = NULL, *host, *user, *domain, *p2; +- int status; +- size_t p2len; +- +- /* Leave function if NSS module does not support getpwnam_r, +- we need this function here. */ +- if (!nss_getpwnam_r) +- return NSS_STATUS_UNAVAIL; +- +- if (ent->first) +- { +- memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); +- __internal_setnetgrent (group, &ent->netgrdata); +- ent->first = false; +- } +- +- while (1) +- { +- status = __internal_getnetgrent_r (&host, &user, &domain, +- &ent->netgrdata, buffer, buflen, +- errnop); +- if (status != 1) +- { +- __internal_endnetgrent (&ent->netgrdata); +- ent->netgroup = 0; +- give_pwd_free (&ent->pwd); +- return NSS_STATUS_RETURN; +- } +- +- if (user == NULL || user[0] == '-') +- continue; +- +- if (domain != NULL) +- { +- if (curdomain == NULL +- && yp_get_default_domain (&curdomain) != YPERR_SUCCESS) +- { +- __internal_endnetgrent (&ent->netgrdata); +- ent->netgroup = false; +- give_pwd_free (&ent->pwd); +- return NSS_STATUS_UNAVAIL; +- } +- if (strcmp (curdomain, domain) != 0) +- continue; +- } +- +- /* If name != NULL, we are called from getpwnam. */ +- if (name != NULL) +- if (strcmp (user, name) != 0) +- continue; +- +- p2len = pwd_need_buflen (&ent->pwd); +- if (p2len > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- p2 = buffer + (buflen - p2len); +- buflen -= p2len; +- +- if (nss_getpwnam_r (user, result, buffer, buflen, errnop) != +- NSS_STATUS_SUCCESS) +- continue; +- +- if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent)) +- { +- /* Store the User in the blacklist for possible the "+" at the +- end of /etc/passwd */ +- blacklist_store_name (result->pw_name, ent); +- copy_pwd_changes (result, &ent->pwd, p2, p2len); +- break; +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +-/* get the next user from NSS (+ entry) */ +-static enum nss_status +-getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, +- size_t buflen, int *errnop) +-{ +- enum nss_status status; +- char *p2; +- size_t p2len; +- +- /* Return if NSS module does not support getpwent_r. */ +- if (!nss_getpwent_r) +- return NSS_STATUS_UNAVAIL; +- +- /* If the setpwent call failed, say so. */ +- if (ent->setent_status != NSS_STATUS_SUCCESS) +- return ent->setent_status; +- +- p2len = pwd_need_buflen (&ent->pwd); +- if (p2len > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- p2 = buffer + (buflen - p2len); +- buflen -= p2len; +- +- if (ent->first) +- ent->first = false; +- +- do +- { +- if ((status = nss_getpwent_r (result, buffer, buflen, errnop)) != +- NSS_STATUS_SUCCESS) +- return status; +- } +- while (in_blacklist (result->pw_name, strlen (result->pw_name), ent)); +- +- copy_pwd_changes (result, &ent->pwd, p2, p2len); +- +- return NSS_STATUS_SUCCESS; +-} +- +-/* This function handle the +user entrys in /etc/passwd */ +-static enum nss_status +-getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- if (!nss_getpwnam_r) +- return NSS_STATUS_UNAVAIL; +- +- struct passwd pwd; +- memset (&pwd, '\0', sizeof (struct passwd)); +- +- copy_pwd_changes (&pwd, result, NULL, 0); +- +- size_t plen = pwd_need_buflen (&pwd); +- if (plen > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- char *p = buffer + (buflen - plen); +- buflen -= plen; +- +- enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen, +- errnop); +- if (status != NSS_STATUS_SUCCESS) +- return status; +- +- if (in_blacklist (result->pw_name, strlen (result->pw_name), ent)) +- return NSS_STATUS_NOTFOUND; +- +- copy_pwd_changes (result, &pwd, p, plen); +- give_pwd_free (&pwd); +- /* We found the entry. */ +- return NSS_STATUS_SUCCESS; +-} +- +-static enum nss_status +-getpwent_next_file (struct passwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- while (1) +- { +- fpos_t pos; +- char *p; +- int parse_res; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- if (result->pw_name[0] != '+' && result->pw_name[0] != '-') +- /* This is a real entry. */ +- break; +- +- /* -@netgroup */ +- if (result->pw_name[0] == '-' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- /* XXX Do not use fixed length buffer. */ +- char buf2[1024]; +- char *user, *host, *domain; +- struct __netgrent netgrdata; +- +- memset (&netgrdata, 0, sizeof (struct __netgrent)); +- __internal_setnetgrent (&result->pw_name[2], &netgrdata); +- while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata, +- buf2, sizeof (buf2), errnop)) +- { +- if (user != NULL && user[0] != '-') +- blacklist_store_name (user, ent); +- } +- __internal_endnetgrent (&netgrdata); +- continue; +- } +- +- /* +@netgroup */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- enum nss_status status; +- +- ent->netgroup = true; +- ent->first = true; +- copy_pwd_changes (&ent->pwd, result, NULL, 0); +- +- status = getpwent_next_nss_netgr (NULL, result, ent, +- &result->pw_name[2], +- buffer, buflen, errnop); +- if (status == NSS_STATUS_RETURN) +- continue; +- else +- return status; +- } +- +- /* -user */ +- if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- blacklist_store_name (&result->pw_name[1], ent); +- continue; +- } +- +- /* +user */ +- if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- size_t len = strlen (result->pw_name); +- char buf[len]; +- enum nss_status status; +- +- /* Store the User in the blacklist for the "+" at the end of +- /etc/passwd */ +- memcpy (buf, &result->pw_name[1], len); +- status = getpwnam_plususer (&result->pw_name[1], result, ent, +- buffer, buflen, errnop); +- blacklist_store_name (buf, ent); +- +- if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ +- break; +- else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ +- || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */ +- continue; +- else +- { +- if (status == NSS_STATUS_TRYAGAIN) +- { +- /* The parser ran out of space */ +- fsetpos (ent->stream, &pos); +- *errnop = ERANGE; +- } +- return status; +- } +- } +- +- /* +:... */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') +- { +- ent->files = false; +- ent->first = true; +- copy_pwd_changes (&ent->pwd, result, NULL, 0); +- +- return getpwent_next_nss (result, ent, buffer, buflen, errnop); +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-static enum nss_status +-internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, +- size_t buflen, int *errnop) +-{ +- if (ent->netgroup) +- { +- enum nss_status status; +- +- /* We are searching members in a netgroup */ +- /* Since this is not the first call, we don't need the group name */ +- status = getpwent_next_nss_netgr (NULL, pw, ent, NULL, buffer, buflen, +- errnop); +- if (status == NSS_STATUS_RETURN) +- return getpwent_next_file (pw, ent, buffer, buflen, errnop); +- else +- return status; +- } +- else if (ent->files) +- return getpwent_next_file (pw, ent, buffer, buflen, errnop); +- else +- return getpwent_next_nss (pw, ent, buffer, buflen, errnop); +- +-} +- +-enum nss_status +-_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, +- int *errnop) +-{ +- enum nss_status result = NSS_STATUS_SUCCESS; +- +- __libc_lock_lock (lock); +- +- /* Be prepared that the setpwent function was not called before. */ +- if (ni == NULL) +- init_nss_interface (); +- +- if (ext_ent.stream == NULL) +- result = internal_setpwent (&ext_ent, 1, 1); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +-/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +-static enum nss_status +-internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- +- while (1) +- { +- fpos_t pos; +- char *p; +- int parse_res; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- { +- return NSS_STATUS_NOTFOUND; +- } +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- /* This is a real entry. */ +- if (result->pw_name[0] != '+' && result->pw_name[0] != '-') +- { +- if (strcmp (result->pw_name, name) == 0) +- return NSS_STATUS_SUCCESS; +- else +- continue; +- } +- +- /* -@netgroup */ +- if (result->pw_name[0] == '-' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- if (innetgr (&result->pw_name[2], NULL, name, NULL)) +- return NSS_STATUS_NOTFOUND; +- continue; +- } +- +- /* +@netgroup */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- enum nss_status status; +- +- if (innetgr (&result->pw_name[2], NULL, name, NULL)) +- { +- status = getpwnam_plususer (name, result, ent, buffer, +- buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- continue; +- +- return status; +- } +- continue; +- } +- +- /* -user */ +- if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- if (strcmp (&result->pw_name[1], name) == 0) +- return NSS_STATUS_NOTFOUND; +- else +- continue; +- } +- +- /* +user */ +- if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- if (strcmp (name, &result->pw_name[1]) == 0) +- { +- enum nss_status status; +- +- status = getpwnam_plususer (name, result, ent, buffer, buflen, +- errnop); +- if (status == NSS_STATUS_RETURN) +- /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- +- /* +:... */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') +- { +- enum nss_status status; +- +- status = getpwnam_plususer (name, result, ent, +- buffer, buflen, errnop); +- if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ +- break; +- else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_getpwnam_r (const char *name, struct passwd *pwd, +- char *buffer, size_t buflen, int *errnop) +-{ +- enum nss_status result; +- ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, +- { NULL, NULL, 0, 0, NULL, NULL, NULL }}; +- +- if (name[0] == '-' || name[0] == '+') +- return NSS_STATUS_NOTFOUND; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- __libc_lock_unlock (lock); +- +- result = internal_setpwent (&ent, 0, 0); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); +- +- internal_endpwent (&ent); +- +- return result; +-} +- +-/* This function handle the + entry in /etc/passwd for getpwuid */ +-static enum nss_status +-getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer, +- size_t buflen, int *errnop) +-{ +- struct passwd pwd; +- char *p; +- size_t plen; +- +- if (!nss_getpwuid_r) +- return NSS_STATUS_UNAVAIL; +- +- memset (&pwd, '\0', sizeof (struct passwd)); +- +- copy_pwd_changes (&pwd, result, NULL, 0); +- +- plen = pwd_need_buflen (&pwd); +- if (plen > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- p = buffer + (buflen - plen); +- buflen -= plen; +- +- if (nss_getpwuid_r (uid, result, buffer, buflen, errnop) == +- NSS_STATUS_SUCCESS) +- { +- copy_pwd_changes (result, &pwd, p, plen); +- give_pwd_free (&pwd); +- /* We found the entry. */ +- return NSS_STATUS_SUCCESS; +- } +- else +- { +- /* Give buffer the old len back */ +- buflen += plen; +- give_pwd_free (&pwd); +- } +- return NSS_STATUS_RETURN; +-} +- +-/* Searches in /etc/passwd and the NSS subsystem for a special user id */ +-static enum nss_status +-internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- +- while (1) +- { +- fpos_t pos; +- char *p; +- int parse_res; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- /* This is a real entry. */ +- if (result->pw_name[0] != '+' && result->pw_name[0] != '-') +- { +- if (result->pw_uid == uid) +- return NSS_STATUS_SUCCESS; +- else +- continue; +- } +- +- /* -@netgroup */ +- if (result->pw_name[0] == '-' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- /* -1, because we remove first two character of pw_name. */ +- size_t len = strlen (result->pw_name) - 1; +- char buf[len]; +- enum nss_status status; +- +- memcpy (buf, &result->pw_name[2], len); +- +- status = getpwuid_plususer (uid, result, buffer, buflen, errnop); +- if (status == NSS_STATUS_SUCCESS && +- innetgr (buf, NULL, result->pw_name, NULL)) +- return NSS_STATUS_NOTFOUND; +- +- continue; +- } +- +- /* +@netgroup */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '@' +- && result->pw_name[2] != '\0') +- { +- /* -1, because we remove first two characters of pw_name. */ +- size_t len = strlen (result->pw_name) - 1; +- char buf[len]; +- enum nss_status status; +- +- memcpy (buf, &result->pw_name[2], len); +- +- status = getpwuid_plususer (uid, result, buffer, buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- continue; +- +- if (status == NSS_STATUS_SUCCESS) +- { +- if (innetgr (buf, NULL, result->pw_name, NULL)) +- return NSS_STATUS_SUCCESS; +- } +- else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- +- continue; +- } +- +- /* -user */ +- if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- size_t len = strlen (result->pw_name); +- char buf[len]; +- enum nss_status status; +- +- memcpy (buf, &result->pw_name[1], len); +- +- status = getpwuid_plususer (uid, result, buffer, buflen, errnop); +- if (status == NSS_STATUS_SUCCESS && +- innetgr (buf, NULL, result->pw_name, NULL)) +- return NSS_STATUS_NOTFOUND; +- continue; +- } +- +- /* +user */ +- if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' +- && result->pw_name[1] != '@') +- { +- size_t len = strlen (result->pw_name); +- char buf[len]; +- enum nss_status status; +- +- memcpy (buf, &result->pw_name[1], len); +- +- status = getpwuid_plususer (uid, result, buffer, buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- continue; +- +- if (status == NSS_STATUS_SUCCESS) +- { +- if (strcmp (buf, result->pw_name) == 0) +- return NSS_STATUS_SUCCESS; +- } +- else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- +- continue; +- } +- +- /* +:... */ +- if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') +- { +- enum nss_status status; +- +- status = getpwuid_plususer (uid, result, buffer, buflen, errnop); +- if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ +- break; +- else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, +- char *buffer, size_t buflen, int *errnop) +-{ +- enum nss_status result; +- ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, +- { NULL, NULL, 0, 0, NULL, NULL, NULL }}; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- __libc_lock_unlock (lock); +- +- result = internal_setpwent (&ent, 0, 0); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); +- +- internal_endpwent (&ent); +- +- return result; +-} +- +- +-/* Support routines for remembering -@netgroup and -user entries. +- The names are stored in a single string with `|' as separator. */ +-static void +-blacklist_store_name (const char *name, ent_t *ent) +-{ +- int namelen = strlen (name); +- char *tmp; +- +- /* first call, setup cache */ +- if (ent->blacklist.size == 0) +- { +- ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); +- ent->blacklist.data = malloc (ent->blacklist.size); +- if (ent->blacklist.data == NULL) +- return; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- ent->blacklist.current = 1; +- } +- else +- { +- if (in_blacklist (name, namelen, ent)) +- return; /* no duplicates */ +- +- if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) +- { +- ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); +- tmp = realloc (ent->blacklist.data, ent->blacklist.size); +- if (tmp == NULL) +- { +- free (ent->blacklist.data); +- ent->blacklist.size = 0; +- return; +- } +- ent->blacklist.data = tmp; +- } +- } +- +- tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); +- *tmp++ = '|'; +- *tmp = '\0'; +- ent->blacklist.current += namelen + 1; +- +- return; +-} +- +-/* Returns TRUE if ent->blacklist contains name, else FALSE. */ +-static bool_t +-in_blacklist (const char *name, int namelen, ent_t *ent) +-{ +- char buf[namelen + 3]; +- char *cp; +- +- if (ent->blacklist.data == NULL) +- return FALSE; +- +- buf[0] = '|'; +- cp = stpcpy (&buf[1], name); +- *cp++ = '|'; +- *cp = '\0'; +- return strstr (ent->blacklist.data, buf) != NULL; +-} +Index: glibc-2.26/nis/nss_compat/compat-spwd.c +=================================================================== +--- glibc-2.26.orig/nis/nss_compat/compat-spwd.c ++++ /dev/null +@@ -1,858 +0,0 @@ +-/* Copyright (C) 1996-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Thorsten Kukuk , 1996. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "netgroup.h" +- +-static service_user *ni; +-static enum nss_status (*nss_setspent) (int stayopen); +-static enum nss_status (*nss_getspnam_r) (const char *name, struct spwd * sp, +- char *buffer, size_t buflen, +- int *errnop); +-static enum nss_status (*nss_getspent_r) (struct spwd * sp, char *buffer, +- size_t buflen, int *errnop); +-static enum nss_status (*nss_endspent) (void); +- +-/* Get the declaration of the parser function. */ +-#define ENTNAME spent +-#define STRUCTURE spwd +-#define EXTERN_PARSER +-#include +- +-/* Structure for remembering -@netgroup and -user members ... */ +-#define BLACKLIST_INITIAL_SIZE 512 +-#define BLACKLIST_INCREMENT 256 +-struct blacklist_t +-{ +- char *data; +- int current; +- int size; +-}; +- +-struct ent_t +-{ +- bool netgroup; +- bool files; +- bool first; +- enum nss_status setent_status; +- FILE *stream; +- struct blacklist_t blacklist; +- struct spwd pwd; +- struct __netgrent netgrdata; +-}; +-typedef struct ent_t ent_t; +- +-static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, +- { NULL, 0, 0}, +- { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; +- +-/* Protect global state against multiple changers. */ +-__libc_lock_define_initialized (static, lock) +- +-/* Prototypes for local functions. */ +-static void blacklist_store_name (const char *, ent_t *); +-static int in_blacklist (const char *, int, ent_t *); +- +-/* Initialize the NSS interface/functions. The calling function must +- hold the lock. */ +-static void +-init_nss_interface (void) +-{ +- if (__nss_database_lookup ("shadow_compat", "passwd_compat", +- "nis", &ni) >= 0) +- { +- nss_setspent = __nss_lookup_function (ni, "setspent"); +- nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r"); +- nss_getspent_r = __nss_lookup_function (ni, "getspent_r"); +- nss_endspent = __nss_lookup_function (ni, "endspent"); +- } +-} +- +-static void +-give_spwd_free (struct spwd *pwd) +-{ +- free (pwd->sp_namp); +- free (pwd->sp_pwdp); +- +- memset (pwd, '\0', sizeof (struct spwd)); +- pwd->sp_warn = -1; +- pwd->sp_inact = -1; +- pwd->sp_expire = -1; +- pwd->sp_flag = ~0ul; +-} +- +-static int +-spwd_need_buflen (struct spwd *pwd) +-{ +- int len = 0; +- +- if (pwd->sp_pwdp != NULL) +- len += strlen (pwd->sp_pwdp) + 1; +- +- return len; +-} +- +-static void +-copy_spwd_changes (struct spwd *dest, struct spwd *src, +- char *buffer, size_t buflen) +-{ +- if (src->sp_pwdp != NULL && strlen (src->sp_pwdp)) +- { +- if (buffer == NULL) +- dest->sp_pwdp = strdup (src->sp_pwdp); +- else if (dest->sp_pwdp && +- strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp)) +- strcpy (dest->sp_pwdp, src->sp_pwdp); +- else +- { +- dest->sp_pwdp = buffer; +- strcpy (dest->sp_pwdp, src->sp_pwdp); +- buffer += strlen (dest->sp_pwdp) + 1; +- buflen = buflen - (strlen (dest->sp_pwdp) + 1); +- } +- } +- if (src->sp_lstchg != 0) +- dest->sp_lstchg = src->sp_lstchg; +- if (src->sp_min != 0) +- dest->sp_min = src->sp_min; +- if (src->sp_max != 0) +- dest->sp_max = src->sp_max; +- if (src->sp_warn != -1) +- dest->sp_warn = src->sp_warn; +- if (src->sp_inact != -1) +- dest->sp_inact = src->sp_inact; +- if (src->sp_expire != -1) +- dest->sp_expire = src->sp_expire; +- if (src->sp_flag != ~0ul) +- dest->sp_flag = src->sp_flag; +-} +- +-static enum nss_status +-internal_setspent (ent_t *ent, int stayopen, int needent) +-{ +- enum nss_status status = NSS_STATUS_SUCCESS; +- +- ent->first = ent->netgroup = 0; +- ent->files = true; +- +- /* If something was left over free it. */ +- if (ent->netgroup) +- __internal_endnetgrent (&ent->netgrdata); +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- if (ent->stream == NULL) +- { +- ent->stream = fopen ("/etc/shadow", "rme"); +- +- if (ent->stream == NULL) +- status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); +- } +- else +- rewind (ent->stream); +- +- give_spwd_free (&ent->pwd); +- +- if (needent && status == NSS_STATUS_SUCCESS && nss_setspent) +- ent->setent_status = nss_setspent (stayopen); +- +- return status; +-} +- +- +-enum nss_status +-_nss_compat_setspent (int stayopen) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- result = internal_setspent (&ext_ent, stayopen, 1); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-static enum nss_status +-internal_endspent (ent_t *ent) +-{ +- if (ent->stream != NULL) +- { +- fclose (ent->stream); +- ent->stream = NULL; +- } +- +- if (ent->netgroup) +- __internal_endnetgrent (&ent->netgrdata); +- +- ent->first = ent->netgroup = false; +- ent->files = true; +- +- if (ent->blacklist.data != NULL) +- { +- ent->blacklist.current = 1; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- } +- else +- ent->blacklist.current = 0; +- +- give_spwd_free (&ent->pwd); +- +- return NSS_STATUS_SUCCESS; +-} +- +-enum nss_status +-_nss_compat_endspent (void) +-{ +- enum nss_status result; +- +- __libc_lock_lock (lock); +- +- if (nss_endspent) +- nss_endspent (); +- +- result = internal_endspent (&ext_ent); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-static enum nss_status +-getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, +- char *group, char *buffer, size_t buflen, +- int *errnop) +-{ +- char *curdomain = NULL, *host, *user, *domain, *p2; +- size_t p2len; +- +- if (!nss_getspnam_r) +- return NSS_STATUS_UNAVAIL; +- +- /* If the setpwent call failed, say so. */ +- if (ent->setent_status != NSS_STATUS_SUCCESS) +- return ent->setent_status; +- +- if (ent->first) +- { +- memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); +- __internal_setnetgrent (group, &ent->netgrdata); +- ent->first = false; +- } +- +- while (1) +- { +- enum nss_status status; +- +- status = __internal_getnetgrent_r (&host, &user, &domain, +- &ent->netgrdata, buffer, buflen, +- errnop); +- if (status != 1) +- { +- __internal_endnetgrent (&ent->netgrdata); +- ent->netgroup = false; +- give_spwd_free (&ent->pwd); +- return NSS_STATUS_RETURN; +- } +- +- if (user == NULL || user[0] == '-') +- continue; +- +- if (domain != NULL) +- { +- if (curdomain == NULL +- && yp_get_default_domain (&curdomain) != YPERR_SUCCESS) +- { +- __internal_endnetgrent (&ent->netgrdata); +- ent->netgroup = false; +- give_spwd_free (&ent->pwd); +- return NSS_STATUS_UNAVAIL; +- } +- if (strcmp (curdomain, domain) != 0) +- continue; +- } +- +- /* If name != NULL, we are called from getpwnam */ +- if (name != NULL) +- if (strcmp (user, name) != 0) +- continue; +- +- p2len = spwd_need_buflen (&ent->pwd); +- if (p2len > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- p2 = buffer + (buflen - p2len); +- buflen -= p2len; +- +- if (nss_getspnam_r (user, result, buffer, buflen, errnop) != +- NSS_STATUS_SUCCESS) +- continue; +- +- if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) +- { +- /* Store the User in the blacklist for possible the "+" at the +- end of /etc/passwd */ +- blacklist_store_name (result->sp_namp, ent); +- copy_spwd_changes (result, &ent->pwd, p2, p2len); +- break; +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-static enum nss_status +-getspent_next_nss (struct spwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- enum nss_status status; +- char *p2; +- size_t p2len; +- +- if (!nss_getspent_r) +- return NSS_STATUS_UNAVAIL; +- +- p2len = spwd_need_buflen (&ent->pwd); +- if (p2len > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- p2 = buffer + (buflen - p2len); +- buflen -= p2len; +- do +- { +- if ((status = nss_getspent_r (result, buffer, buflen, errnop)) != +- NSS_STATUS_SUCCESS) +- return status; +- } +- while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)); +- +- copy_spwd_changes (result, &ent->pwd, p2, p2len); +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-/* This function handle the +user entrys in /etc/shadow */ +-static enum nss_status +-getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- if (!nss_getspnam_r) +- return NSS_STATUS_UNAVAIL; +- +- struct spwd pwd; +- memset (&pwd, '\0', sizeof (struct spwd)); +- pwd.sp_warn = -1; +- pwd.sp_inact = -1; +- pwd.sp_expire = -1; +- pwd.sp_flag = ~0ul; +- +- copy_spwd_changes (&pwd, result, NULL, 0); +- +- size_t plen = spwd_need_buflen (&pwd); +- if (plen > buflen) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- char *p = buffer + (buflen - plen); +- buflen -= plen; +- +- enum nss_status status = nss_getspnam_r (name, result, buffer, buflen, +- errnop); +- if (status != NSS_STATUS_SUCCESS) +- return status; +- +- if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) +- return NSS_STATUS_NOTFOUND; +- +- copy_spwd_changes (result, &pwd, p, plen); +- give_spwd_free (&pwd); +- /* We found the entry. */ +- return NSS_STATUS_SUCCESS; +-} +- +- +-static enum nss_status +-getspent_next_file (struct spwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- while (1) +- { +- fpos_t pos; +- int parse_res = 0; +- char *p; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- || !(parse_res = _nss_files_parse_spent (p, result, data, +- buflen, errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') +- /* This is a real entry. */ +- break; +- +- /* -@netgroup */ +- if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' +- && result->sp_namp[2] != '\0') +- { +- /* XXX Do not use fixed length buffers. */ +- char buf2[1024]; +- char *user, *host, *domain; +- struct __netgrent netgrdata; +- +- memset (&netgrdata, 0, sizeof (struct __netgrent)); +- __internal_setnetgrent (&result->sp_namp[2], &netgrdata); +- while (__internal_getnetgrent_r (&host, &user, &domain, +- &netgrdata, buf2, sizeof (buf2), +- errnop)) +- { +- if (user != NULL && user[0] != '-') +- blacklist_store_name (user, ent); +- } +- __internal_endnetgrent (&netgrdata); +- continue; +- } +- +- /* +@netgroup */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' +- && result->sp_namp[2] != '\0') +- { +- int status; +- +- ent->netgroup = true; +- ent->first = true; +- copy_spwd_changes (&ent->pwd, result, NULL, 0); +- +- status = getspent_next_nss_netgr (NULL, result, ent, +- &result->sp_namp[2], +- buffer, buflen, errnop); +- if (status == NSS_STATUS_RETURN) +- continue; +- else +- return status; +- } +- +- /* -user */ +- if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' +- && result->sp_namp[1] != '@') +- { +- blacklist_store_name (&result->sp_namp[1], ent); +- continue; +- } +- +- /* +user */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' +- && result->sp_namp[1] != '@') +- { +- size_t len = strlen (result->sp_namp); +- char buf[len]; +- enum nss_status status; +- +- /* Store the User in the blacklist for the "+" at the end of +- /etc/passwd */ +- memcpy (buf, &result->sp_namp[1], len); +- status = getspnam_plususer (&result->sp_namp[1], result, ent, +- buffer, buflen, errnop); +- blacklist_store_name (buf, ent); +- +- if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ +- break; +- /* We couldn't parse the entry */ +- else if (status == NSS_STATUS_RETURN +- /* entry doesn't exist */ +- || status == NSS_STATUS_NOTFOUND) +- continue; +- else +- { +- if (status == NSS_STATUS_TRYAGAIN) +- { +- fsetpos (ent->stream, &pos); +- *errnop = ERANGE; +- } +- return status; +- } +- } +- +- /* +:... */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') +- { +- ent->files = false; +- ent->first = true; +- copy_spwd_changes (&ent->pwd, result, NULL, 0); +- +- return getspent_next_nss (result, ent, buffer, buflen, errnop); +- } +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-static enum nss_status +-internal_getspent_r (struct spwd *pw, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- if (ent->netgroup) +- { +- enum nss_status status; +- +- /* We are searching members in a netgroup */ +- /* Since this is not the first call, we don't need the group name */ +- status = getspent_next_nss_netgr (NULL, pw, ent, NULL, buffer, +- buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- return getspent_next_file (pw, ent, buffer, buflen, errnop); +- else +- return status; +- } +- else if (ent->files) +- return getspent_next_file (pw, ent, buffer, buflen, errnop); +- else +- return getspent_next_nss (pw, ent, buffer, buflen, errnop); +-} +- +- +-enum nss_status +-_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, +- int *errnop) +-{ +- enum nss_status result = NSS_STATUS_SUCCESS; +- +- __libc_lock_lock (lock); +- +- /* Be prepared that the setpwent function was not called before. */ +- if (ni == NULL) +- init_nss_interface (); +- +- if (ext_ent.stream == NULL) +- result = internal_setspent (&ext_ent, 1, 1); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop); +- +- __libc_lock_unlock (lock); +- +- return result; +-} +- +- +-/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +-static enum nss_status +-internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct parser_data *data = (void *) buffer; +- +- while (1) +- { +- fpos_t pos; +- char *p; +- int parse_res; +- +- do +- { +- /* We need at least 3 characters for one line. */ +- if (__glibc_unlikely (buflen < 3)) +- { +- erange: +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- fgetpos (ent->stream, &pos); +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, ent->stream); +- if (p == NULL && feof_unlocked (ent->stream)) +- return NSS_STATUS_NOTFOUND; +- +- if (p == NULL || buffer[buflen - 1] != '\xff') +- { +- erange_reset: +- fsetpos (ent->stream, &pos); +- goto erange; +- } +- +- /* Terminate the line for any case. */ +- buffer[buflen - 1] = '\0'; +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } +- while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- !(parse_res = _nss_files_parse_spent (p, result, data, buflen, +- errnop))); +- +- if (__glibc_unlikely (parse_res == -1)) +- /* The parser ran out of space. */ +- goto erange_reset; +- +- /* This is a real entry. */ +- if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') +- { +- if (strcmp (result->sp_namp, name) == 0) +- return NSS_STATUS_SUCCESS; +- else +- continue; +- } +- +- /* -@netgroup */ +- /* If the loaded NSS module does not support this service, add +- all users from a +@netgroup entry to the blacklist, too. */ +- if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' +- && result->sp_namp[2] != '\0') +- { +- if (innetgr (&result->sp_namp[2], NULL, name, NULL)) +- return NSS_STATUS_NOTFOUND; +- continue; +- } +- +- /* +@netgroup */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' +- && result->sp_namp[2] != '\0') +- { +- enum nss_status status; +- +- if (innetgr (&result->sp_namp[2], NULL, name, NULL)) +- { +- status = getspnam_plususer (name, result, ent, buffer, +- buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- continue; +- +- return status; +- } +- continue; +- } +- +- /* -user */ +- if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' +- && result->sp_namp[1] != '@') +- { +- if (strcmp (&result->sp_namp[1], name) == 0) +- return NSS_STATUS_NOTFOUND; +- else +- continue; +- } +- +- /* +user */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' +- && result->sp_namp[1] != '@') +- { +- if (strcmp (name, &result->sp_namp[1]) == 0) +- { +- enum nss_status status; +- +- status = getspnam_plususer (name, result, ent, +- buffer, buflen, errnop); +- +- if (status == NSS_STATUS_RETURN) +- /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- +- /* +:... */ +- if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') +- { +- enum nss_status status; +- +- status = getspnam_plususer (name, result, ent, +- buffer, buflen, errnop); +- +- if (status == NSS_STATUS_SUCCESS) +- /* We found the entry. */ +- break; +- else if (status == NSS_STATUS_RETURN) +- /* We couldn't parse the entry */ +- return NSS_STATUS_NOTFOUND; +- else +- return status; +- } +- } +- return NSS_STATUS_SUCCESS; +-} +- +- +-enum nss_status +-_nss_compat_getspnam_r (const char *name, struct spwd *pwd, +- char *buffer, size_t buflen, int *errnop) +-{ +- enum nss_status result; +- ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0}, +- { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; +- +- if (name[0] == '-' || name[0] == '+') +- return NSS_STATUS_NOTFOUND; +- +- __libc_lock_lock (lock); +- +- if (ni == NULL) +- init_nss_interface (); +- +- __libc_lock_unlock (lock); +- +- result = internal_setspent (&ent, 0, 0); +- +- if (result == NSS_STATUS_SUCCESS) +- result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop); +- +- internal_endspent (&ent); +- +- return result; +-} +- +- +-/* Support routines for remembering -@netgroup and -user entries. +- The names are stored in a single string with `|' as separator. */ +-static void +-blacklist_store_name (const char *name, ent_t *ent) +-{ +- int namelen = strlen (name); +- char *tmp; +- +- /* first call, setup cache */ +- if (ent->blacklist.size == 0) +- { +- ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); +- ent->blacklist.data = malloc (ent->blacklist.size); +- if (ent->blacklist.data == NULL) +- return; +- ent->blacklist.data[0] = '|'; +- ent->blacklist.data[1] = '\0'; +- ent->blacklist.current = 1; +- } +- else +- { +- if (in_blacklist (name, namelen, ent)) +- return; /* no duplicates */ +- +- if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) +- { +- ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); +- tmp = realloc (ent->blacklist.data, ent->blacklist.size); +- if (tmp == NULL) +- { +- free (ent->blacklist.data); +- ent->blacklist.size = 0; +- return; +- } +- ent->blacklist.data = tmp; +- } +- } +- +- tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); +- *tmp++ = '|'; +- *tmp = '\0'; +- ent->blacklist.current += namelen + 1; +- +- return; +-} +- +- +-/* Returns TRUE if ent->blacklist contains name, else FALSE. */ +-static bool_t +-in_blacklist (const char *name, int namelen, ent_t *ent) +-{ +- char buf[namelen + 3]; +- char *cp; +- +- if (ent->blacklist.data == NULL) +- return false; +- +- buf[0] = '|'; +- cp = stpcpy (&buf[1], name); +- *cp++ = '|'; +- *cp = '\0'; +- return strstr (ent->blacklist.data, buf) != NULL; +-} +Index: glibc-2.26/nss/Makefile +=================================================================== +--- glibc-2.26.orig/nss/Makefile ++++ glibc-2.26/nss/Makefile +@@ -70,7 +70,7 @@ tests += tst-cancel-getpwuid_r + endif + + # Specify rules for the nss_* modules. We have some services. +-services := files db ++services := files db compat + + extra-libs = $(services:%=libnss_%) + # These libraries will be built in the `others' pass rather than +@@ -93,11 +93,15 @@ libnss_db-routines := $(libnss_db-dbs) d + generated += $(filter-out db-alias.c db-netgrp.c, \ + $(addsuffix .c,$(libnss_db-dbs))) + ++libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) \ ++ nisdomain ++ + install-others += $(inst_vardbdir)/Makefile + + # Build static module into libc if requested + libnss_files-inhibit-o = $(filter-out .os,$(object-suffixes)) + libnss_db-inhibit-o = $(filter-out .os,$(object-suffixes)) ++libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + ifeq ($(build-static-nss),yes) + routines += $(libnss_files-routines) + static-only-routines += $(libnss_files-routines) +Index: glibc-2.26/nss/Versions +=================================================================== +--- glibc-2.26.orig/nss/Versions ++++ glibc-2.26/nss/Versions +@@ -160,3 +160,14 @@ libnss_db { + _nss_db_init; + } + } ++ ++libnss_compat { ++ GLIBC_PRIVATE { ++ _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent; ++ _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r; ++ _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r; ++ _nss_compat_getspent_r; _nss_compat_getspnam_r; ++ _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent; ++ _nss_compat_initgroups_dyn; ++ } ++} +Index: glibc-2.26/nss/nss_compat/compat-grp.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/compat-grp.c +@@ -0,0 +1,682 @@ ++/* Copyright (C) 1996-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Thorsten Kukuk , 1996. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static service_user *ni; ++static enum nss_status (*nss_setgrent) (int stayopen); ++static enum nss_status (*nss_getgrnam_r) (const char *name, ++ struct group * grp, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, ++ char *buffer, size_t buflen, ++ int *errnop); ++static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_endgrent) (void); ++ ++/* Get the declaration of the parser function. */ ++#define ENTNAME grent ++#define STRUCTURE group ++#define EXTERN_PARSER ++#include ++ ++/* Structure for remembering -group members ... */ ++#define BLACKLIST_INITIAL_SIZE 512 ++#define BLACKLIST_INCREMENT 256 ++struct blacklist_t ++{ ++ char *data; ++ int current; ++ int size; ++}; ++ ++struct ent_t ++{ ++ bool files; ++ enum nss_status setent_status; ++ FILE *stream; ++ struct blacklist_t blacklist; ++}; ++typedef struct ent_t ent_t; ++ ++static ent_t ext_ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; ++ ++/* Protect global state against multiple changers. */ ++__libc_lock_define_initialized (static, lock) ++ ++/* Prototypes for local functions. */ ++static void blacklist_store_name (const char *, ent_t *); ++static bool in_blacklist (const char *, int, ent_t *); ++ ++/* Initialize the NSS interface/functions. The calling function must ++ hold the lock. */ ++static void ++init_nss_interface (void) ++{ ++ if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) ++ { ++ nss_setgrent = __nss_lookup_function (ni, "setgrent"); ++ nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); ++ nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); ++ nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); ++ nss_endgrent = __nss_lookup_function (ni, "endgrent"); ++ } ++} ++ ++static enum nss_status ++internal_setgrent (ent_t *ent, int stayopen, int needent) ++{ ++ enum nss_status status = NSS_STATUS_SUCCESS; ++ ++ ent->files = true; ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ if (ent->stream == NULL) ++ { ++ ent->stream = fopen ("/etc/group", "rme"); ++ ++ if (ent->stream == NULL) ++ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; ++ else ++ /* We take care of locking ourself. */ ++ __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); ++ } ++ else ++ rewind (ent->stream); ++ ++ if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent) ++ ent->setent_status = nss_setgrent (stayopen); ++ ++ return status; ++} ++ ++ ++enum nss_status ++_nss_compat_setgrent (int stayopen) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ result = internal_setgrent (&ext_ent, stayopen, 1); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++static enum nss_status ++internal_endgrent (ent_t *ent) ++{ ++ if (ent->stream != NULL) ++ { ++ fclose (ent->stream); ++ ent->stream = NULL; ++ } ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_endgrent (void) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (nss_endgrent) ++ nss_endgrent (); ++ ++ result = internal_endgrent (&ext_ent); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++/* get the next group from NSS (+ entry) */ ++static enum nss_status ++getgrent_next_nss (struct group *result, ent_t *ent, char *buffer, ++ size_t buflen, int *errnop) ++{ ++ if (!nss_getgrent_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ /* If the setgrent call failed, say so. */ ++ if (ent->setent_status != NSS_STATUS_SUCCESS) ++ return ent->setent_status; ++ ++ do ++ { ++ enum nss_status status; ++ ++ if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) != ++ NSS_STATUS_SUCCESS) ++ return status; ++ } ++ while (in_blacklist (result->gr_name, strlen (result->gr_name), ent)); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++/* This function handle the +group entrys in /etc/group */ ++static enum nss_status ++getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ if (!nss_getgrnam_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen, ++ errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; ++ ++ if (in_blacklist (result->gr_name, strlen (result->gr_name), ent)) ++ return NSS_STATUS_NOTFOUND; ++ ++ /* We found the entry. */ ++ return NSS_STATUS_SUCCESS; ++} ++ ++static enum nss_status ++getgrent_next_file (struct group *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ while (1) ++ { ++ fpos_t pos; ++ int parse_res = 0; ++ char *p; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_grent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ if (result->gr_name[0] != '+' && result->gr_name[0] != '-') ++ /* This is a real entry. */ ++ break; ++ ++ /* -group */ ++ if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' ++ && result->gr_name[1] != '@') ++ { ++ blacklist_store_name (&result->gr_name[1], ent); ++ continue; ++ } ++ ++ /* +group */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' ++ && result->gr_name[1] != '@') ++ { ++ size_t len = strlen (result->gr_name); ++ char buf[len]; ++ enum nss_status status; ++ ++ /* Store the group in the blacklist for the "+" at the end of ++ /etc/group */ ++ memcpy (buf, &result->gr_name[1], len); ++ status = getgrnam_plusgroup (&result->gr_name[1], result, ent, ++ buffer, buflen, errnop); ++ blacklist_store_name (buf, ent); ++ if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ ++ break; ++ else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry*/ ++ || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ ++ continue; ++ else ++ { ++ if (status == NSS_STATUS_TRYAGAIN) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ return status; ++ } ++ } ++ ++ /* +:... */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') ++ { ++ ent->files = false; ++ ++ return getgrent_next_nss (result, ent, buffer, buflen, errnop); ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++enum nss_status ++_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, ++ int *errnop) ++{ ++ enum nss_status result = NSS_STATUS_SUCCESS; ++ ++ __libc_lock_lock (lock); ++ ++ /* Be prepared that the setgrent function was not called before. */ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ if (ext_ent.stream == NULL) ++ result = internal_setgrent (&ext_ent, 1, 1); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ { ++ if (ext_ent.files) ++ result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop); ++ else ++ result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop); ++ } ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++/* Searches in /etc/group and the NIS/NIS+ map for a special group */ ++static enum nss_status ++internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ while (1) ++ { ++ fpos_t pos; ++ int parse_res = 0; ++ char *p; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_grent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ /* This is a real entry. */ ++ if (result->gr_name[0] != '+' && result->gr_name[0] != '-') ++ { ++ if (strcmp (result->gr_name, name) == 0) ++ return NSS_STATUS_SUCCESS; ++ else ++ continue; ++ } ++ ++ /* -group */ ++ if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') ++ { ++ if (strcmp (&result->gr_name[1], name) == 0) ++ return NSS_STATUS_NOTFOUND; ++ else ++ continue; ++ } ++ ++ /* +group */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') ++ { ++ if (strcmp (name, &result->gr_name[1]) == 0) ++ { ++ enum nss_status status; ++ ++ status = getgrnam_plusgroup (name, result, ent, ++ buffer, buflen, errnop); ++ if (status == NSS_STATUS_RETURN) ++ /* We couldn't parse the entry */ ++ continue; ++ else ++ return status; ++ } ++ } ++ /* +:... */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') ++ { ++ enum nss_status status; ++ ++ status = getgrnam_plusgroup (name, result, ent, ++ buffer, buflen, errnop); ++ if (status == NSS_STATUS_RETURN) ++ /* We couldn't parse the entry */ ++ continue; ++ else ++ return status; ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_getgrnam_r (const char *name, struct group *grp, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ ent_t ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; ++ enum nss_status result; ++ ++ if (name[0] == '-' || name[0] == '+') ++ return NSS_STATUS_NOTFOUND; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ __libc_lock_unlock (lock); ++ ++ result = internal_setgrent (&ent, 0, 0); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); ++ ++ internal_endgrent (&ent); ++ ++ return result; ++} ++ ++/* Searches in /etc/group and the NIS/NIS+ map for a special group id */ ++static enum nss_status ++internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ while (1) ++ { ++ fpos_t pos; ++ int parse_res = 0; ++ char *p; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_grent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ /* This is a real entry. */ ++ if (result->gr_name[0] != '+' && result->gr_name[0] != '-') ++ { ++ if (result->gr_gid == gid) ++ return NSS_STATUS_SUCCESS; ++ else ++ continue; ++ } ++ ++ /* -group */ ++ if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') ++ { ++ blacklist_store_name (&result->gr_name[1], ent); ++ continue; ++ } ++ ++ /* +group */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') ++ { ++ /* Yes, no +1, see the memcpy call below. */ ++ size_t len = strlen (result->gr_name); ++ char buf[len]; ++ enum nss_status status; ++ ++ /* Store the group in the blacklist for the "+" at the end of ++ /etc/group */ ++ memcpy (buf, &result->gr_name[1], len); ++ status = getgrnam_plusgroup (&result->gr_name[1], result, ent, ++ buffer, buflen, errnop); ++ blacklist_store_name (buf, ent); ++ if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) ++ break; ++ else ++ continue; ++ } ++ /* +:... */ ++ if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') ++ { ++ if (!nss_getgrgid_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen, ++ errnop); ++ if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_getgrgid_r (gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ ent_t ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ __libc_lock_unlock (lock); ++ ++ result = internal_setgrent (&ent, 0, 0); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); ++ ++ internal_endgrent (&ent); ++ ++ return result; ++} ++ ++ ++/* Support routines for remembering -@netgroup and -user entries. ++ The names are stored in a single string with `|' as separator. */ ++static void ++blacklist_store_name (const char *name, ent_t *ent) ++{ ++ int namelen = strlen (name); ++ char *tmp; ++ ++ /* first call, setup cache */ ++ if (ent->blacklist.size == 0) ++ { ++ ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); ++ ent->blacklist.data = malloc (ent->blacklist.size); ++ if (ent->blacklist.data == NULL) ++ return; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ ent->blacklist.current = 1; ++ } ++ else ++ { ++ if (in_blacklist (name, namelen, ent)) ++ return; /* no duplicates */ ++ ++ if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) ++ { ++ ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); ++ tmp = realloc (ent->blacklist.data, ent->blacklist.size); ++ if (tmp == NULL) ++ { ++ free (ent->blacklist.data); ++ ent->blacklist.size = 0; ++ return; ++ } ++ ent->blacklist.data = tmp; ++ } ++ } ++ ++ tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); ++ *tmp++ = '|'; ++ *tmp = '\0'; ++ ent->blacklist.current += namelen + 1; ++ ++ return; ++} ++ ++/* Return whether ent->blacklist contains name. */ ++static bool ++in_blacklist (const char *name, int namelen, ent_t *ent) ++{ ++ char buf[namelen + 3]; ++ char *cp; ++ ++ if (ent->blacklist.data == NULL) ++ return false; ++ ++ buf[0] = '|'; ++ cp = stpcpy (&buf[1], name); ++ *cp++ = '|'; ++ *cp = '\0'; ++ return strstr (ent->blacklist.data, buf) != NULL; ++} +Index: glibc-2.26/nss/nss_compat/compat-initgroups.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/compat-initgroups.c +@@ -0,0 +1,575 @@ ++/* Copyright (C) 1998-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Thorsten Kukuk , 1998. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static service_user *ni; ++/* Type of the lookup function. */ ++static enum nss_status (*nss_initgroups_dyn) (const char *, gid_t, ++ long int *, long int *, ++ gid_t **, long int, int *); ++static enum nss_status (*nss_getgrnam_r) (const char *name, ++ struct group * grp, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, ++ char *buffer, size_t buflen, ++ int *errnop); ++static enum nss_status (*nss_setgrent) (int stayopen); ++static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_endgrent) (void); ++ ++/* Protect global state against multiple changers. */ ++__libc_lock_define_initialized (static, lock) ++ ++ ++/* Get the declaration of the parser function. */ ++#define ENTNAME grent ++#define STRUCTURE group ++#define EXTERN_PARSER ++#include ++ ++/* Structure for remembering -group members ... */ ++#define BLACKLIST_INITIAL_SIZE 512 ++#define BLACKLIST_INCREMENT 256 ++struct blacklist_t ++{ ++ char *data; ++ int current; ++ int size; ++}; ++ ++struct ent_t ++{ ++ bool files; ++ bool need_endgrent; ++ bool skip_initgroups_dyn; ++ FILE *stream; ++ struct blacklist_t blacklist; ++}; ++typedef struct ent_t ent_t; ++ ++/* Prototypes for local functions. */ ++static void blacklist_store_name (const char *, ent_t *); ++static bool in_blacklist (const char *, int, ent_t *); ++ ++/* Initialize the NSS interface/functions. The calling function must ++ hold the lock. */ ++static void ++init_nss_interface (void) ++{ ++ __libc_lock_lock (lock); ++ ++ /* Retest. */ ++ if (ni == NULL ++ && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) ++ { ++ nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn"); ++ nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); ++ nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); ++ nss_setgrent = __nss_lookup_function (ni, "setgrent"); ++ nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); ++ nss_endgrent = __nss_lookup_function (ni, "endgrent"); ++ } ++ ++ __libc_lock_unlock (lock); ++} ++ ++static enum nss_status ++internal_setgrent (ent_t *ent) ++{ ++ enum nss_status status = NSS_STATUS_SUCCESS; ++ ++ ent->files = true; ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ ent->stream = fopen ("/etc/group", "rme"); ++ ++ if (ent->stream == NULL) ++ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; ++ else ++ /* We take care of locking ourself. */ ++ __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); ++ ++ return status; ++} ++ ++ ++static enum nss_status ++internal_endgrent (ent_t *ent) ++{ ++ if (ent->stream != NULL) ++ { ++ fclose (ent->stream); ++ ent->stream = NULL; ++ } ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ if (ent->need_endgrent && nss_endgrent != NULL) ++ nss_endgrent (); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++/* Add new group record. */ ++static void ++add_group (long int *start, long int *size, gid_t **groupsp, long int limit, ++ gid_t gid) ++{ ++ gid_t *groups = *groupsp; ++ ++ /* Matches user. Insert this group. */ ++ if (__glibc_unlikely (*start == *size)) ++ { ++ /* Need a bigger buffer. */ ++ gid_t *newgroups; ++ long int newsize; ++ ++ if (limit > 0 && *size == limit) ++ /* We reached the maximum. */ ++ return; ++ ++ if (limit <= 0) ++ newsize = 2 * *size; ++ else ++ newsize = MIN (limit, 2 * *size); ++ ++ newgroups = realloc (groups, newsize * sizeof (*groups)); ++ if (newgroups == NULL) ++ return; ++ *groupsp = groups = newgroups; ++ *size = newsize; ++ } ++ ++ groups[*start] = gid; ++ *start += 1; ++} ++ ++/* This function checks, if the user is a member of this group and if ++ yes, add the group id to the list. Return nonzero is we couldn't ++ handle the group because the user is not in the member list. */ ++static int ++check_and_add_group (const char *user, gid_t group, long int *start, ++ long int *size, gid_t **groupsp, long int limit, ++ struct group *grp) ++{ ++ char **member; ++ ++ /* Don't add main group to list of groups. */ ++ if (grp->gr_gid == group) ++ return 0; ++ ++ for (member = grp->gr_mem; *member != NULL; ++member) ++ if (strcmp (*member, user) == 0) ++ { ++ add_group (start, size, groupsp, limit, grp->gr_gid); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* Get the next group from NSS (+ entry). If the NSS module supports ++ initgroups_dyn, get all entries at once. */ ++static enum nss_status ++getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user, ++ gid_t group, long int *start, long int *size, ++ gid_t **groupsp, long int limit, int *errnop) ++{ ++ enum nss_status status; ++ struct group grpbuf; ++ ++ /* Try nss_initgroups_dyn if supported. We also need getgrgid_r. ++ If this function is not supported, step through the whole group ++ database with getgrent_r. */ ++ if (! ent->skip_initgroups_dyn) ++ { ++ long int mystart = 0; ++ long int mysize = limit <= 0 ? *size : limit; ++ gid_t *mygroups = malloc (mysize * sizeof (gid_t)); ++ ++ if (mygroups == NULL) ++ return NSS_STATUS_TRYAGAIN; ++ ++ /* For every gid in the list we get from the NSS module, ++ get the whole group entry. We need to do this, since we ++ need the group name to check if it is in the blacklist. ++ In worst case, this is as twice as slow as stepping with ++ getgrent_r through the whole group database. But for large ++ group databases this is faster, since the user can only be ++ in a limited number of groups. */ ++ if (nss_initgroups_dyn (user, group, &mystart, &mysize, &mygroups, ++ limit, errnop) == NSS_STATUS_SUCCESS) ++ { ++ status = NSS_STATUS_NOTFOUND; ++ ++ /* If there is no blacklist we can trust the underlying ++ initgroups implementation. */ ++ if (ent->blacklist.current <= 1) ++ for (int i = 0; i < mystart; i++) ++ add_group (start, size, groupsp, limit, mygroups[i]); ++ else ++ { ++ /* A temporary buffer. We use the normal buffer, until we find ++ an entry, for which this buffer is to small. In this case, we ++ overwrite the pointer with one to a bigger buffer. */ ++ char *tmpbuf = buffer; ++ size_t tmplen = buflen; ++ bool use_malloc = false; ++ ++ for (int i = 0; i < mystart; i++) ++ { ++ while ((status = nss_getgrgid_r (mygroups[i], &grpbuf, ++ tmpbuf, tmplen, errnop)) ++ == NSS_STATUS_TRYAGAIN ++ && *errnop == ERANGE) ++ { ++ if (__libc_use_alloca (tmplen * 2)) ++ { ++ if (tmpbuf == buffer) ++ { ++ tmplen *= 2; ++ tmpbuf = __alloca (tmplen); ++ } ++ else ++ tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2); ++ } ++ else ++ { ++ tmplen *= 2; ++ char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen); ++ ++ if (newbuf == NULL) ++ { ++ status = NSS_STATUS_TRYAGAIN; ++ goto done; ++ } ++ use_malloc = true; ++ tmpbuf = newbuf; ++ } ++ } ++ ++ if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1)) ++ { ++ if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) ++ goto done; ++ ++ if (!in_blacklist (grpbuf.gr_name, ++ strlen (grpbuf.gr_name), ent) ++ && check_and_add_group (user, group, start, size, ++ groupsp, limit, &grpbuf)) ++ { ++ if (nss_setgrent != NULL) ++ { ++ nss_setgrent (1); ++ ent->need_endgrent = true; ++ } ++ ent->skip_initgroups_dyn = true; ++ ++ goto iter; ++ } ++ } ++ } ++ ++ status = NSS_STATUS_NOTFOUND; ++ ++ done: ++ if (use_malloc) ++ free (tmpbuf); ++ } ++ ++ free (mygroups); ++ ++ return status; ++ } ++ ++ free (mygroups); ++ } ++ ++ /* If we come here, the NSS module does not support initgroups_dyn ++ or we were confronted with a split group. In these cases we have ++ to step through the whole list ourself. */ ++ iter: ++ do ++ { ++ if ((status = nss_getgrent_r (&grpbuf, buffer, buflen, errnop)) != ++ NSS_STATUS_SUCCESS) ++ break; ++ } ++ while (in_blacklist (grpbuf.gr_name, strlen (grpbuf.gr_name), ent)); ++ ++ if (status == NSS_STATUS_SUCCESS) ++ check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); ++ ++ return status; ++} ++ ++static enum nss_status ++internal_getgrent_r (ent_t *ent, char *buffer, size_t buflen, const char *user, ++ gid_t group, long int *start, long int *size, ++ gid_t **groupsp, long int limit, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ struct group grpbuf; ++ ++ if (!ent->files) ++ return getgrent_next_nss (ent, buffer, buflen, user, group, ++ start, size, groupsp, limit, errnop); ++ ++ while (1) ++ { ++ fpos_t pos; ++ int parse_res = 0; ++ char *p; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_grent (p, &grpbuf, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ if (grpbuf.gr_name[0] != '+' && grpbuf.gr_name[0] != '-') ++ /* This is a real entry. */ ++ break; ++ ++ /* -group */ ++ if (grpbuf.gr_name[0] == '-' && grpbuf.gr_name[1] != '\0' ++ && grpbuf.gr_name[1] != '@') ++ { ++ blacklist_store_name (&grpbuf.gr_name[1], ent); ++ continue; ++ } ++ ++ /* +group */ ++ if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] != '\0' ++ && grpbuf.gr_name[1] != '@') ++ { ++ if (in_blacklist (&grpbuf.gr_name[1], ++ strlen (&grpbuf.gr_name[1]), ent)) ++ continue; ++ /* Store the group in the blacklist for the "+" at the end of ++ /etc/group */ ++ blacklist_store_name (&grpbuf.gr_name[1], ent); ++ if (nss_getgrnam_r == NULL) ++ return NSS_STATUS_UNAVAIL; ++ else if (nss_getgrnam_r (&grpbuf.gr_name[1], &grpbuf, buffer, ++ buflen, errnop) != NSS_STATUS_SUCCESS) ++ continue; ++ ++ check_and_add_group (user, group, start, size, groupsp, ++ limit, &grpbuf); ++ ++ return NSS_STATUS_SUCCESS; ++ } ++ ++ /* +:... */ ++ if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] == '\0') ++ { ++ /* If the selected module does not support getgrent_r or ++ initgroups_dyn, abort. We cannot find the needed group ++ entries. */ ++ if (nss_initgroups_dyn == NULL || nss_getgrgid_r == NULL) ++ { ++ if (nss_setgrent != NULL) ++ { ++ nss_setgrent (1); ++ ent->need_endgrent = true; ++ } ++ ent->skip_initgroups_dyn = true; ++ ++ if (nss_getgrent_r == NULL) ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ent->files = false; ++ ++ return getgrent_next_nss (ent, buffer, buflen, user, group, ++ start, size, groupsp, limit, errnop); ++ } ++ } ++ ++ check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++enum nss_status ++_nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, ++ long int *size, gid_t **groupsp, long int limit, ++ int *errnop) ++{ ++ enum nss_status status; ++ ent_t intern = { true, false, false, NULL, {NULL, 0, 0} }; ++ ++ status = internal_setgrent (&intern); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; ++ ++ struct scratch_buffer tmpbuf; ++ scratch_buffer_init (&tmpbuf); ++ ++ do ++ { ++ while ((status = internal_getgrent_r (&intern, tmpbuf.data, tmpbuf.length, ++ user, group, start, size, ++ groupsp, limit, errnop)) ++ == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) ++ if (!scratch_buffer_grow (&tmpbuf)) ++ goto done; ++ } ++ while (status == NSS_STATUS_SUCCESS); ++ ++ status = NSS_STATUS_SUCCESS; ++ ++ done: ++ scratch_buffer_free (&tmpbuf); ++ ++ internal_endgrent (&intern); ++ ++ return status; ++} ++ ++ ++/* Support routines for remembering -@netgroup and -user entries. ++ The names are stored in a single string with `|' as separator. */ ++static void ++blacklist_store_name (const char *name, ent_t *ent) ++{ ++ int namelen = strlen (name); ++ char *tmp; ++ ++ /* First call, setup cache. */ ++ if (ent->blacklist.size == 0) ++ { ++ ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); ++ ent->blacklist.data = malloc (ent->blacklist.size); ++ if (ent->blacklist.data == NULL) ++ return; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ ent->blacklist.current = 1; ++ } ++ else ++ { ++ if (in_blacklist (name, namelen, ent)) ++ return; /* no duplicates */ ++ ++ if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) ++ { ++ ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); ++ tmp = realloc (ent->blacklist.data, ent->blacklist.size); ++ if (tmp == NULL) ++ { ++ free (ent->blacklist.data); ++ ent->blacklist.size = 0; ++ return; ++ } ++ ent->blacklist.data = tmp; ++ } ++ } ++ ++ tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); ++ *tmp++ = '|'; ++ *tmp = '\0'; ++ ent->blacklist.current += namelen + 1; ++ ++ return; ++} ++ ++/* Return whether ent->blacklist contains name. */ ++static bool ++in_blacklist (const char *name, int namelen, ent_t *ent) ++{ ++ char buf[namelen + 3]; ++ char *cp; ++ ++ if (ent->blacklist.data == NULL) ++ return false; ++ ++ buf[0] = '|'; ++ cp = stpcpy (&buf[1], name); ++ *cp++ = '|'; ++ *cp = '\0'; ++ return strstr (ent->blacklist.data, buf) != NULL; ++} +Index: glibc-2.26/nss/nss_compat/compat-pwd.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/compat-pwd.c +@@ -0,0 +1,1131 @@ ++/* Copyright (C) 1996-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Thorsten Kukuk , 1996. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "netgroup.h" ++#include "nisdomain.h" ++ ++static service_user *ni; ++static enum nss_status (*nss_setpwent) (int stayopen); ++static enum nss_status (*nss_getpwnam_r) (const char *name, ++ struct passwd * pwd, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_getpwuid_r) (uid_t uid, struct passwd * pwd, ++ char *buffer, size_t buflen, ++ int *errnop); ++static enum nss_status (*nss_getpwent_r) (struct passwd * pwd, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_endpwent) (void); ++ ++/* Get the declaration of the parser function. */ ++#define ENTNAME pwent ++#define STRUCTURE passwd ++#define EXTERN_PARSER ++#include ++ ++/* Structure for remembering -@netgroup and -user members ... */ ++#define BLACKLIST_INITIAL_SIZE 512 ++#define BLACKLIST_INCREMENT 256 ++struct blacklist_t ++{ ++ char *data; ++ int current; ++ int size; ++}; ++ ++struct ent_t ++{ ++ bool netgroup; ++ bool first; ++ bool files; ++ enum nss_status setent_status; ++ FILE *stream; ++ struct blacklist_t blacklist; ++ struct passwd pwd; ++ struct __netgrent netgrdata; ++}; ++typedef struct ent_t ent_t; ++ ++static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, ++ { NULL, 0, 0 }, ++ { NULL, NULL, 0, 0, NULL, NULL, NULL }}; ++ ++/* Protect global state against multiple changers. */ ++__libc_lock_define_initialized (static, lock) ++ ++/* Prototypes for local functions. */ ++static void blacklist_store_name (const char *, ent_t *); ++static bool in_blacklist (const char *, int, ent_t *); ++ ++/* Initialize the NSS interface/functions. The calling function must ++ hold the lock. */ ++static void ++init_nss_interface (void) ++{ ++ if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0) ++ { ++ nss_setpwent = __nss_lookup_function (ni, "setpwent"); ++ nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r"); ++ nss_getpwuid_r = __nss_lookup_function (ni, "getpwuid_r"); ++ nss_getpwent_r = __nss_lookup_function (ni, "getpwent_r"); ++ nss_endpwent = __nss_lookup_function (ni, "endpwent"); ++ } ++} ++ ++static void ++give_pwd_free (struct passwd *pwd) ++{ ++ free (pwd->pw_name); ++ free (pwd->pw_passwd); ++ free (pwd->pw_gecos); ++ free (pwd->pw_dir); ++ free (pwd->pw_shell); ++ ++ memset (pwd, '\0', sizeof (struct passwd)); ++} ++ ++static size_t ++pwd_need_buflen (struct passwd *pwd) ++{ ++ size_t len = 0; ++ ++ if (pwd->pw_passwd != NULL) ++ len += strlen (pwd->pw_passwd) + 1; ++ ++ if (pwd->pw_gecos != NULL) ++ len += strlen (pwd->pw_gecos) + 1; ++ ++ if (pwd->pw_dir != NULL) ++ len += strlen (pwd->pw_dir) + 1; ++ ++ if (pwd->pw_shell != NULL) ++ len += strlen (pwd->pw_shell) + 1; ++ ++ return len; ++} ++ ++static void ++copy_pwd_changes (struct passwd *dest, struct passwd *src, ++ char *buffer, size_t buflen) ++{ ++ if (src->pw_passwd != NULL && strlen (src->pw_passwd)) ++ { ++ if (buffer == NULL) ++ dest->pw_passwd = strdup (src->pw_passwd); ++ else if (dest->pw_passwd && ++ strlen (dest->pw_passwd) >= strlen (src->pw_passwd)) ++ strcpy (dest->pw_passwd, src->pw_passwd); ++ else ++ { ++ dest->pw_passwd = buffer; ++ strcpy (dest->pw_passwd, src->pw_passwd); ++ buffer += strlen (dest->pw_passwd) + 1; ++ buflen = buflen - (strlen (dest->pw_passwd) + 1); ++ } ++ } ++ ++ if (src->pw_gecos != NULL && strlen (src->pw_gecos)) ++ { ++ if (buffer == NULL) ++ dest->pw_gecos = strdup (src->pw_gecos); ++ else if (dest->pw_gecos && ++ strlen (dest->pw_gecos) >= strlen (src->pw_gecos)) ++ strcpy (dest->pw_gecos, src->pw_gecos); ++ else ++ { ++ dest->pw_gecos = buffer; ++ strcpy (dest->pw_gecos, src->pw_gecos); ++ buffer += strlen (dest->pw_gecos) + 1; ++ buflen = buflen - (strlen (dest->pw_gecos) + 1); ++ } ++ } ++ if (src->pw_dir != NULL && strlen (src->pw_dir)) ++ { ++ if (buffer == NULL) ++ dest->pw_dir = strdup (src->pw_dir); ++ else if (dest->pw_dir && strlen (dest->pw_dir) >= strlen (src->pw_dir)) ++ strcpy (dest->pw_dir, src->pw_dir); ++ else ++ { ++ dest->pw_dir = buffer; ++ strcpy (dest->pw_dir, src->pw_dir); ++ buffer += strlen (dest->pw_dir) + 1; ++ buflen = buflen - (strlen (dest->pw_dir) + 1); ++ } ++ } ++ ++ if (src->pw_shell != NULL && strlen (src->pw_shell)) ++ { ++ if (buffer == NULL) ++ dest->pw_shell = strdup (src->pw_shell); ++ else if (dest->pw_shell && ++ strlen (dest->pw_shell) >= strlen (src->pw_shell)) ++ strcpy (dest->pw_shell, src->pw_shell); ++ else ++ { ++ dest->pw_shell = buffer; ++ strcpy (dest->pw_shell, src->pw_shell); ++ buffer += strlen (dest->pw_shell) + 1; ++ buflen = buflen - (strlen (dest->pw_shell) + 1); ++ } ++ } ++} ++ ++static enum nss_status ++internal_setpwent (ent_t *ent, int stayopen, int needent) ++{ ++ enum nss_status status = NSS_STATUS_SUCCESS; ++ ++ ent->first = ent->netgroup = false; ++ ent->files = true; ++ ent->setent_status = NSS_STATUS_SUCCESS; ++ ++ /* If something was left over free it. */ ++ if (ent->netgroup) ++ __internal_endnetgrent (&ent->netgrdata); ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ if (ent->stream == NULL) ++ { ++ ent->stream = fopen ("/etc/passwd", "rme"); ++ ++ if (ent->stream == NULL) ++ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; ++ else ++ /* We take care of locking ourself. */ ++ __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); ++ } ++ else ++ rewind (ent->stream); ++ ++ give_pwd_free (&ent->pwd); ++ ++ if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent) ++ ent->setent_status = nss_setpwent (stayopen); ++ ++ return status; ++} ++ ++ ++enum nss_status ++_nss_compat_setpwent (int stayopen) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ result = internal_setpwent (&ext_ent, stayopen, 1); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++static enum nss_status ++internal_endpwent (ent_t *ent) ++{ ++ if (ent->stream != NULL) ++ { ++ fclose (ent->stream); ++ ent->stream = NULL; ++ } ++ ++ if (ent->netgroup) ++ __internal_endnetgrent (&ent->netgrdata); ++ ++ ent->first = ent->netgroup = false; ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ give_pwd_free (&ent->pwd); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_endpwent (void) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (nss_endpwent) ++ nss_endpwent (); ++ ++ result = internal_endpwent (&ext_ent); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++static enum nss_status ++getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent, ++ char *group, char *buffer, size_t buflen, ++ int *errnop) ++{ ++ char *curdomain = NULL, *host, *user, *domain, *p2; ++ int status; ++ size_t p2len; ++ ++ /* Leave function if NSS module does not support getpwnam_r, ++ we need this function here. */ ++ if (!nss_getpwnam_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (ent->first) ++ { ++ memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); ++ __internal_setnetgrent (group, &ent->netgrdata); ++ ent->first = false; ++ } ++ ++ while (1) ++ { ++ status = __internal_getnetgrent_r (&host, &user, &domain, ++ &ent->netgrdata, buffer, buflen, ++ errnop); ++ if (status != 1) ++ { ++ __internal_endnetgrent (&ent->netgrdata); ++ ent->netgroup = 0; ++ give_pwd_free (&ent->pwd); ++ return NSS_STATUS_RETURN; ++ } ++ ++ if (user == NULL || user[0] == '-') ++ continue; ++ ++ if (domain != NULL) ++ { ++ if (curdomain == NULL ++ && __nss_get_default_domain (&curdomain) != 0) ++ { ++ __internal_endnetgrent (&ent->netgrdata); ++ ent->netgroup = false; ++ give_pwd_free (&ent->pwd); ++ return NSS_STATUS_UNAVAIL; ++ } ++ if (strcmp (curdomain, domain) != 0) ++ continue; ++ } ++ ++ /* If name != NULL, we are called from getpwnam. */ ++ if (name != NULL) ++ if (strcmp (user, name) != 0) ++ continue; ++ ++ p2len = pwd_need_buflen (&ent->pwd); ++ if (p2len > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ p2 = buffer + (buflen - p2len); ++ buflen -= p2len; ++ ++ if (nss_getpwnam_r (user, result, buffer, buflen, errnop) != ++ NSS_STATUS_SUCCESS) ++ continue; ++ ++ if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent)) ++ { ++ /* Store the User in the blacklist for possible the "+" at the ++ end of /etc/passwd */ ++ blacklist_store_name (result->pw_name, ent); ++ copy_pwd_changes (result, &ent->pwd, p2, p2len); ++ break; ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++/* get the next user from NSS (+ entry) */ ++static enum nss_status ++getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, ++ size_t buflen, int *errnop) ++{ ++ enum nss_status status; ++ char *p2; ++ size_t p2len; ++ ++ /* Return if NSS module does not support getpwent_r. */ ++ if (!nss_getpwent_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ /* If the setpwent call failed, say so. */ ++ if (ent->setent_status != NSS_STATUS_SUCCESS) ++ return ent->setent_status; ++ ++ p2len = pwd_need_buflen (&ent->pwd); ++ if (p2len > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ p2 = buffer + (buflen - p2len); ++ buflen -= p2len; ++ ++ if (ent->first) ++ ent->first = false; ++ ++ do ++ { ++ if ((status = nss_getpwent_r (result, buffer, buflen, errnop)) != ++ NSS_STATUS_SUCCESS) ++ return status; ++ } ++ while (in_blacklist (result->pw_name, strlen (result->pw_name), ent)); ++ ++ copy_pwd_changes (result, &ent->pwd, p2, p2len); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++/* This function handle the +user entrys in /etc/passwd */ ++static enum nss_status ++getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ if (!nss_getpwnam_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ struct passwd pwd; ++ memset (&pwd, '\0', sizeof (struct passwd)); ++ ++ copy_pwd_changes (&pwd, result, NULL, 0); ++ ++ size_t plen = pwd_need_buflen (&pwd); ++ if (plen > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ char *p = buffer + (buflen - plen); ++ buflen -= plen; ++ ++ enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen, ++ errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; ++ ++ if (in_blacklist (result->pw_name, strlen (result->pw_name), ent)) ++ return NSS_STATUS_NOTFOUND; ++ ++ copy_pwd_changes (result, &pwd, p, plen); ++ give_pwd_free (&pwd); ++ /* We found the entry. */ ++ return NSS_STATUS_SUCCESS; ++} ++ ++static enum nss_status ++getpwent_next_file (struct passwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ while (1) ++ { ++ fpos_t pos; ++ char *p; ++ int parse_res; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ if (result->pw_name[0] != '+' && result->pw_name[0] != '-') ++ /* This is a real entry. */ ++ break; ++ ++ /* -@netgroup */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ /* XXX Do not use fixed length buffer. */ ++ char buf2[1024]; ++ char *user, *host, *domain; ++ struct __netgrent netgrdata; ++ ++ memset (&netgrdata, 0, sizeof (struct __netgrent)); ++ __internal_setnetgrent (&result->pw_name[2], &netgrdata); ++ while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata, ++ buf2, sizeof (buf2), errnop)) ++ { ++ if (user != NULL && user[0] != '-') ++ blacklist_store_name (user, ent); ++ } ++ __internal_endnetgrent (&netgrdata); ++ continue; ++ } ++ ++ /* +@netgroup */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ enum nss_status status; ++ ++ ent->netgroup = true; ++ ent->first = true; ++ copy_pwd_changes (&ent->pwd, result, NULL, 0); ++ ++ status = getpwent_next_nss_netgr (NULL, result, ent, ++ &result->pw_name[2], ++ buffer, buflen, errnop); ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ else ++ return status; ++ } ++ ++ /* -user */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ blacklist_store_name (&result->pw_name[1], ent); ++ continue; ++ } ++ ++ /* +user */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ size_t len = strlen (result->pw_name); ++ char buf[len]; ++ enum nss_status status; ++ ++ /* Store the User in the blacklist for the "+" at the end of ++ /etc/passwd */ ++ memcpy (buf, &result->pw_name[1], len); ++ status = getpwnam_plususer (&result->pw_name[1], result, ent, ++ buffer, buflen, errnop); ++ blacklist_store_name (buf, ent); ++ ++ if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ ++ break; ++ else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ ++ || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */ ++ continue; ++ else ++ { ++ if (status == NSS_STATUS_TRYAGAIN) ++ { ++ /* The parser ran out of space */ ++ fsetpos (ent->stream, &pos); ++ *errnop = ERANGE; ++ } ++ return status; ++ } ++ } ++ ++ /* +:... */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') ++ { ++ ent->files = false; ++ ent->first = true; ++ copy_pwd_changes (&ent->pwd, result, NULL, 0); ++ ++ return getpwent_next_nss (result, ent, buffer, buflen, errnop); ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++static enum nss_status ++internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, ++ size_t buflen, int *errnop) ++{ ++ if (ent->netgroup) ++ { ++ enum nss_status status; ++ ++ /* We are searching members in a netgroup */ ++ /* Since this is not the first call, we don't need the group name */ ++ status = getpwent_next_nss_netgr (NULL, pw, ent, NULL, buffer, buflen, ++ errnop); ++ if (status == NSS_STATUS_RETURN) ++ return getpwent_next_file (pw, ent, buffer, buflen, errnop); ++ else ++ return status; ++ } ++ else if (ent->files) ++ return getpwent_next_file (pw, ent, buffer, buflen, errnop); ++ else ++ return getpwent_next_nss (pw, ent, buffer, buflen, errnop); ++ ++} ++ ++enum nss_status ++_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, ++ int *errnop) ++{ ++ enum nss_status result = NSS_STATUS_SUCCESS; ++ ++ __libc_lock_lock (lock); ++ ++ /* Be prepared that the setpwent function was not called before. */ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ if (ext_ent.stream == NULL) ++ result = internal_setpwent (&ext_ent, 1, 1); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ ++static enum nss_status ++internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ ++ while (1) ++ { ++ fpos_t pos; ++ char *p; ++ int parse_res; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ { ++ return NSS_STATUS_NOTFOUND; ++ } ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ /* This is a real entry. */ ++ if (result->pw_name[0] != '+' && result->pw_name[0] != '-') ++ { ++ if (strcmp (result->pw_name, name) == 0) ++ return NSS_STATUS_SUCCESS; ++ else ++ continue; ++ } ++ ++ /* -@netgroup */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ if (innetgr (&result->pw_name[2], NULL, name, NULL)) ++ return NSS_STATUS_NOTFOUND; ++ continue; ++ } ++ ++ /* +@netgroup */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ enum nss_status status; ++ ++ if (innetgr (&result->pw_name[2], NULL, name, NULL)) ++ { ++ status = getpwnam_plususer (name, result, ent, buffer, ++ buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ ++ return status; ++ } ++ continue; ++ } ++ ++ /* -user */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ if (strcmp (&result->pw_name[1], name) == 0) ++ return NSS_STATUS_NOTFOUND; ++ else ++ continue; ++ } ++ ++ /* +user */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ if (strcmp (name, &result->pw_name[1]) == 0) ++ { ++ enum nss_status status; ++ ++ status = getpwnam_plususer (name, result, ent, buffer, buflen, ++ errnop); ++ if (status == NSS_STATUS_RETURN) ++ /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ ++ /* +:... */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') ++ { ++ enum nss_status status; ++ ++ status = getpwnam_plususer (name, result, ent, ++ buffer, buflen, errnop); ++ if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ ++ break; ++ else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_getpwnam_r (const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ enum nss_status result; ++ ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, ++ { NULL, NULL, 0, 0, NULL, NULL, NULL }}; ++ ++ if (name[0] == '-' || name[0] == '+') ++ return NSS_STATUS_NOTFOUND; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ __libc_lock_unlock (lock); ++ ++ result = internal_setpwent (&ent, 0, 0); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); ++ ++ internal_endpwent (&ent); ++ ++ return result; ++} ++ ++/* This function handle the + entry in /etc/passwd for getpwuid */ ++static enum nss_status ++getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer, ++ size_t buflen, int *errnop) ++{ ++ struct passwd pwd; ++ char *p; ++ size_t plen; ++ ++ if (!nss_getpwuid_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ memset (&pwd, '\0', sizeof (struct passwd)); ++ ++ copy_pwd_changes (&pwd, result, NULL, 0); ++ ++ plen = pwd_need_buflen (&pwd); ++ if (plen > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ p = buffer + (buflen - plen); ++ buflen -= plen; ++ ++ if (nss_getpwuid_r (uid, result, buffer, buflen, errnop) == ++ NSS_STATUS_SUCCESS) ++ { ++ copy_pwd_changes (result, &pwd, p, plen); ++ give_pwd_free (&pwd); ++ /* We found the entry. */ ++ return NSS_STATUS_SUCCESS; ++ } ++ else ++ { ++ /* Give buffer the old len back */ ++ buflen += plen; ++ give_pwd_free (&pwd); ++ } ++ return NSS_STATUS_RETURN; ++} ++ ++/* Searches in /etc/passwd and the NSS subsystem for a special user id */ ++static enum nss_status ++internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ ++ while (1) ++ { ++ fpos_t pos; ++ char *p; ++ int parse_res; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ /* This is a real entry. */ ++ if (result->pw_name[0] != '+' && result->pw_name[0] != '-') ++ { ++ if (result->pw_uid == uid) ++ return NSS_STATUS_SUCCESS; ++ else ++ continue; ++ } ++ ++ /* -@netgroup */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ /* -1, because we remove first two character of pw_name. */ ++ size_t len = strlen (result->pw_name) - 1; ++ char buf[len]; ++ enum nss_status status; ++ ++ memcpy (buf, &result->pw_name[2], len); ++ ++ status = getpwuid_plususer (uid, result, buffer, buflen, errnop); ++ if (status == NSS_STATUS_SUCCESS && ++ innetgr (buf, NULL, result->pw_name, NULL)) ++ return NSS_STATUS_NOTFOUND; ++ ++ continue; ++ } ++ ++ /* +@netgroup */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '@' ++ && result->pw_name[2] != '\0') ++ { ++ /* -1, because we remove first two characters of pw_name. */ ++ size_t len = strlen (result->pw_name) - 1; ++ char buf[len]; ++ enum nss_status status; ++ ++ memcpy (buf, &result->pw_name[2], len); ++ ++ status = getpwuid_plususer (uid, result, buffer, buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ if (innetgr (buf, NULL, result->pw_name, NULL)) ++ return NSS_STATUS_SUCCESS; ++ } ++ else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ ++ continue; ++ } ++ ++ /* -user */ ++ if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ size_t len = strlen (result->pw_name); ++ char buf[len]; ++ enum nss_status status; ++ ++ memcpy (buf, &result->pw_name[1], len); ++ ++ status = getpwuid_plususer (uid, result, buffer, buflen, errnop); ++ if (status == NSS_STATUS_SUCCESS && ++ innetgr (buf, NULL, result->pw_name, NULL)) ++ return NSS_STATUS_NOTFOUND; ++ continue; ++ } ++ ++ /* +user */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' ++ && result->pw_name[1] != '@') ++ { ++ size_t len = strlen (result->pw_name); ++ char buf[len]; ++ enum nss_status status; ++ ++ memcpy (buf, &result->pw_name[1], len); ++ ++ status = getpwuid_plususer (uid, result, buffer, buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ if (strcmp (buf, result->pw_name) == 0) ++ return NSS_STATUS_SUCCESS; ++ } ++ else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ ++ continue; ++ } ++ ++ /* +:... */ ++ if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') ++ { ++ enum nss_status status; ++ ++ status = getpwuid_plususer (uid, result, buffer, buflen, errnop); ++ if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ ++ break; ++ else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ enum nss_status result; ++ ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, ++ { NULL, NULL, 0, 0, NULL, NULL, NULL }}; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ __libc_lock_unlock (lock); ++ ++ result = internal_setpwent (&ent, 0, 0); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); ++ ++ internal_endpwent (&ent); ++ ++ return result; ++} ++ ++ ++/* Support routines for remembering -@netgroup and -user entries. ++ The names are stored in a single string with `|' as separator. */ ++static void ++blacklist_store_name (const char *name, ent_t *ent) ++{ ++ int namelen = strlen (name); ++ char *tmp; ++ ++ /* first call, setup cache */ ++ if (ent->blacklist.size == 0) ++ { ++ ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); ++ ent->blacklist.data = malloc (ent->blacklist.size); ++ if (ent->blacklist.data == NULL) ++ return; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ ent->blacklist.current = 1; ++ } ++ else ++ { ++ if (in_blacklist (name, namelen, ent)) ++ return; /* no duplicates */ ++ ++ if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) ++ { ++ ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); ++ tmp = realloc (ent->blacklist.data, ent->blacklist.size); ++ if (tmp == NULL) ++ { ++ free (ent->blacklist.data); ++ ent->blacklist.size = 0; ++ return; ++ } ++ ent->blacklist.data = tmp; ++ } ++ } ++ ++ tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); ++ *tmp++ = '|'; ++ *tmp = '\0'; ++ ent->blacklist.current += namelen + 1; ++ ++ return; ++} ++ ++/* Returns whether ent->blacklist contains name. */ ++static bool ++in_blacklist (const char *name, int namelen, ent_t *ent) ++{ ++ char buf[namelen + 3]; ++ char *cp; ++ ++ if (ent->blacklist.data == NULL) ++ return false; ++ ++ buf[0] = '|'; ++ cp = stpcpy (&buf[1], name); ++ *cp++ = '|'; ++ *cp = '\0'; ++ return strstr (ent->blacklist.data, buf) != NULL; ++} +Index: glibc-2.26/nss/nss_compat/compat-spwd.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/compat-spwd.c +@@ -0,0 +1,857 @@ ++/* Copyright (C) 1996-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Thorsten Kukuk , 1996. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "netgroup.h" ++#include "nisdomain.h" ++ ++static service_user *ni; ++static enum nss_status (*nss_setspent) (int stayopen); ++static enum nss_status (*nss_getspnam_r) (const char *name, struct spwd * sp, ++ char *buffer, size_t buflen, ++ int *errnop); ++static enum nss_status (*nss_getspent_r) (struct spwd * sp, char *buffer, ++ size_t buflen, int *errnop); ++static enum nss_status (*nss_endspent) (void); ++ ++/* Get the declaration of the parser function. */ ++#define ENTNAME spent ++#define STRUCTURE spwd ++#define EXTERN_PARSER ++#include ++ ++/* Structure for remembering -@netgroup and -user members ... */ ++#define BLACKLIST_INITIAL_SIZE 512 ++#define BLACKLIST_INCREMENT 256 ++struct blacklist_t ++{ ++ char *data; ++ int current; ++ int size; ++}; ++ ++struct ent_t ++{ ++ bool netgroup; ++ bool files; ++ bool first; ++ enum nss_status setent_status; ++ FILE *stream; ++ struct blacklist_t blacklist; ++ struct spwd pwd; ++ struct __netgrent netgrdata; ++}; ++typedef struct ent_t ent_t; ++ ++static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, ++ { NULL, 0, 0}, ++ { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; ++ ++/* Protect global state against multiple changers. */ ++__libc_lock_define_initialized (static, lock) ++ ++/* Prototypes for local functions. */ ++static void blacklist_store_name (const char *, ent_t *); ++static bool in_blacklist (const char *, int, ent_t *); ++ ++/* Initialize the NSS interface/functions. The calling function must ++ hold the lock. */ ++static void ++init_nss_interface (void) ++{ ++ if (__nss_database_lookup ("shadow_compat", "passwd_compat", ++ "nis", &ni) >= 0) ++ { ++ nss_setspent = __nss_lookup_function (ni, "setspent"); ++ nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r"); ++ nss_getspent_r = __nss_lookup_function (ni, "getspent_r"); ++ nss_endspent = __nss_lookup_function (ni, "endspent"); ++ } ++} ++ ++static void ++give_spwd_free (struct spwd *pwd) ++{ ++ free (pwd->sp_namp); ++ free (pwd->sp_pwdp); ++ ++ memset (pwd, '\0', sizeof (struct spwd)); ++ pwd->sp_warn = -1; ++ pwd->sp_inact = -1; ++ pwd->sp_expire = -1; ++ pwd->sp_flag = ~0ul; ++} ++ ++static int ++spwd_need_buflen (struct spwd *pwd) ++{ ++ int len = 0; ++ ++ if (pwd->sp_pwdp != NULL) ++ len += strlen (pwd->sp_pwdp) + 1; ++ ++ return len; ++} ++ ++static void ++copy_spwd_changes (struct spwd *dest, struct spwd *src, ++ char *buffer, size_t buflen) ++{ ++ if (src->sp_pwdp != NULL && strlen (src->sp_pwdp)) ++ { ++ if (buffer == NULL) ++ dest->sp_pwdp = strdup (src->sp_pwdp); ++ else if (dest->sp_pwdp && ++ strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp)) ++ strcpy (dest->sp_pwdp, src->sp_pwdp); ++ else ++ { ++ dest->sp_pwdp = buffer; ++ strcpy (dest->sp_pwdp, src->sp_pwdp); ++ buffer += strlen (dest->sp_pwdp) + 1; ++ buflen = buflen - (strlen (dest->sp_pwdp) + 1); ++ } ++ } ++ if (src->sp_lstchg != 0) ++ dest->sp_lstchg = src->sp_lstchg; ++ if (src->sp_min != 0) ++ dest->sp_min = src->sp_min; ++ if (src->sp_max != 0) ++ dest->sp_max = src->sp_max; ++ if (src->sp_warn != -1) ++ dest->sp_warn = src->sp_warn; ++ if (src->sp_inact != -1) ++ dest->sp_inact = src->sp_inact; ++ if (src->sp_expire != -1) ++ dest->sp_expire = src->sp_expire; ++ if (src->sp_flag != ~0ul) ++ dest->sp_flag = src->sp_flag; ++} ++ ++static enum nss_status ++internal_setspent (ent_t *ent, int stayopen, int needent) ++{ ++ enum nss_status status = NSS_STATUS_SUCCESS; ++ ++ ent->first = ent->netgroup = 0; ++ ent->files = true; ++ ++ /* If something was left over free it. */ ++ if (ent->netgroup) ++ __internal_endnetgrent (&ent->netgrdata); ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ if (ent->stream == NULL) ++ { ++ ent->stream = fopen ("/etc/shadow", "rme"); ++ ++ if (ent->stream == NULL) ++ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; ++ else ++ /* We take care of locking ourself. */ ++ __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); ++ } ++ else ++ rewind (ent->stream); ++ ++ give_spwd_free (&ent->pwd); ++ ++ if (needent && status == NSS_STATUS_SUCCESS && nss_setspent) ++ ent->setent_status = nss_setspent (stayopen); ++ ++ return status; ++} ++ ++ ++enum nss_status ++_nss_compat_setspent (int stayopen) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ result = internal_setspent (&ext_ent, stayopen, 1); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++static enum nss_status ++internal_endspent (ent_t *ent) ++{ ++ if (ent->stream != NULL) ++ { ++ fclose (ent->stream); ++ ent->stream = NULL; ++ } ++ ++ if (ent->netgroup) ++ __internal_endnetgrent (&ent->netgrdata); ++ ++ ent->first = ent->netgroup = false; ++ ent->files = true; ++ ++ if (ent->blacklist.data != NULL) ++ { ++ ent->blacklist.current = 1; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ } ++ else ++ ent->blacklist.current = 0; ++ ++ give_spwd_free (&ent->pwd); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_compat_endspent (void) ++{ ++ enum nss_status result; ++ ++ __libc_lock_lock (lock); ++ ++ if (nss_endspent) ++ nss_endspent (); ++ ++ result = internal_endspent (&ext_ent); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++static enum nss_status ++getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, ++ char *group, char *buffer, size_t buflen, ++ int *errnop) ++{ ++ char *curdomain = NULL, *host, *user, *domain, *p2; ++ size_t p2len; ++ ++ if (!nss_getspnam_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ /* If the setpwent call failed, say so. */ ++ if (ent->setent_status != NSS_STATUS_SUCCESS) ++ return ent->setent_status; ++ ++ if (ent->first) ++ { ++ memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); ++ __internal_setnetgrent (group, &ent->netgrdata); ++ ent->first = false; ++ } ++ ++ while (1) ++ { ++ enum nss_status status; ++ ++ status = __internal_getnetgrent_r (&host, &user, &domain, ++ &ent->netgrdata, buffer, buflen, ++ errnop); ++ if (status != 1) ++ { ++ __internal_endnetgrent (&ent->netgrdata); ++ ent->netgroup = false; ++ give_spwd_free (&ent->pwd); ++ return NSS_STATUS_RETURN; ++ } ++ ++ if (user == NULL || user[0] == '-') ++ continue; ++ ++ if (domain != NULL) ++ { ++ if (curdomain == NULL ++ && __nss_get_default_domain (&curdomain) != 0) ++ { ++ __internal_endnetgrent (&ent->netgrdata); ++ ent->netgroup = false; ++ give_spwd_free (&ent->pwd); ++ return NSS_STATUS_UNAVAIL; ++ } ++ if (strcmp (curdomain, domain) != 0) ++ continue; ++ } ++ ++ /* If name != NULL, we are called from getpwnam */ ++ if (name != NULL) ++ if (strcmp (user, name) != 0) ++ continue; ++ ++ p2len = spwd_need_buflen (&ent->pwd); ++ if (p2len > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ p2 = buffer + (buflen - p2len); ++ buflen -= p2len; ++ ++ if (nss_getspnam_r (user, result, buffer, buflen, errnop) != ++ NSS_STATUS_SUCCESS) ++ continue; ++ ++ if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) ++ { ++ /* Store the User in the blacklist for possible the "+" at the ++ end of /etc/passwd */ ++ blacklist_store_name (result->sp_namp, ent); ++ copy_spwd_changes (result, &ent->pwd, p2, p2len); ++ break; ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++static enum nss_status ++getspent_next_nss (struct spwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ enum nss_status status; ++ char *p2; ++ size_t p2len; ++ ++ if (!nss_getspent_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ p2len = spwd_need_buflen (&ent->pwd); ++ if (p2len > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ p2 = buffer + (buflen - p2len); ++ buflen -= p2len; ++ do ++ { ++ if ((status = nss_getspent_r (result, buffer, buflen, errnop)) != ++ NSS_STATUS_SUCCESS) ++ return status; ++ } ++ while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)); ++ ++ copy_spwd_changes (result, &ent->pwd, p2, p2len); ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++/* This function handle the +user entrys in /etc/shadow */ ++static enum nss_status ++getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ if (!nss_getspnam_r) ++ return NSS_STATUS_UNAVAIL; ++ ++ struct spwd pwd; ++ memset (&pwd, '\0', sizeof (struct spwd)); ++ pwd.sp_warn = -1; ++ pwd.sp_inact = -1; ++ pwd.sp_expire = -1; ++ pwd.sp_flag = ~0ul; ++ ++ copy_spwd_changes (&pwd, result, NULL, 0); ++ ++ size_t plen = spwd_need_buflen (&pwd); ++ if (plen > buflen) ++ { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ char *p = buffer + (buflen - plen); ++ buflen -= plen; ++ ++ enum nss_status status = nss_getspnam_r (name, result, buffer, buflen, ++ errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; ++ ++ if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) ++ return NSS_STATUS_NOTFOUND; ++ ++ copy_spwd_changes (result, &pwd, p, plen); ++ give_spwd_free (&pwd); ++ /* We found the entry. */ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++static enum nss_status ++getspent_next_file (struct spwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ while (1) ++ { ++ fpos_t pos; ++ int parse_res = 0; ++ char *p; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ || !(parse_res = _nss_files_parse_spent (p, result, data, ++ buflen, errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') ++ /* This is a real entry. */ ++ break; ++ ++ /* -@netgroup */ ++ if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' ++ && result->sp_namp[2] != '\0') ++ { ++ /* XXX Do not use fixed length buffers. */ ++ char buf2[1024]; ++ char *user, *host, *domain; ++ struct __netgrent netgrdata; ++ ++ memset (&netgrdata, 0, sizeof (struct __netgrent)); ++ __internal_setnetgrent (&result->sp_namp[2], &netgrdata); ++ while (__internal_getnetgrent_r (&host, &user, &domain, ++ &netgrdata, buf2, sizeof (buf2), ++ errnop)) ++ { ++ if (user != NULL && user[0] != '-') ++ blacklist_store_name (user, ent); ++ } ++ __internal_endnetgrent (&netgrdata); ++ continue; ++ } ++ ++ /* +@netgroup */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' ++ && result->sp_namp[2] != '\0') ++ { ++ int status; ++ ++ ent->netgroup = true; ++ ent->first = true; ++ copy_spwd_changes (&ent->pwd, result, NULL, 0); ++ ++ status = getspent_next_nss_netgr (NULL, result, ent, ++ &result->sp_namp[2], ++ buffer, buflen, errnop); ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ else ++ return status; ++ } ++ ++ /* -user */ ++ if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' ++ && result->sp_namp[1] != '@') ++ { ++ blacklist_store_name (&result->sp_namp[1], ent); ++ continue; ++ } ++ ++ /* +user */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' ++ && result->sp_namp[1] != '@') ++ { ++ size_t len = strlen (result->sp_namp); ++ char buf[len]; ++ enum nss_status status; ++ ++ /* Store the User in the blacklist for the "+" at the end of ++ /etc/passwd */ ++ memcpy (buf, &result->sp_namp[1], len); ++ status = getspnam_plususer (&result->sp_namp[1], result, ent, ++ buffer, buflen, errnop); ++ blacklist_store_name (buf, ent); ++ ++ if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ ++ break; ++ /* We couldn't parse the entry */ ++ else if (status == NSS_STATUS_RETURN ++ /* entry doesn't exist */ ++ || status == NSS_STATUS_NOTFOUND) ++ continue; ++ else ++ { ++ if (status == NSS_STATUS_TRYAGAIN) ++ { ++ fsetpos (ent->stream, &pos); ++ *errnop = ERANGE; ++ } ++ return status; ++ } ++ } ++ ++ /* +:... */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') ++ { ++ ent->files = false; ++ ent->first = true; ++ copy_spwd_changes (&ent->pwd, result, NULL, 0); ++ ++ return getspent_next_nss (result, ent, buffer, buflen, errnop); ++ } ++ } ++ ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++static enum nss_status ++internal_getspent_r (struct spwd *pw, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ if (ent->netgroup) ++ { ++ enum nss_status status; ++ ++ /* We are searching members in a netgroup */ ++ /* Since this is not the first call, we don't need the group name */ ++ status = getspent_next_nss_netgr (NULL, pw, ent, NULL, buffer, ++ buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ return getspent_next_file (pw, ent, buffer, buflen, errnop); ++ else ++ return status; ++ } ++ else if (ent->files) ++ return getspent_next_file (pw, ent, buffer, buflen, errnop); ++ else ++ return getspent_next_nss (pw, ent, buffer, buflen, errnop); ++} ++ ++ ++enum nss_status ++_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, ++ int *errnop) ++{ ++ enum nss_status result = NSS_STATUS_SUCCESS; ++ ++ __libc_lock_lock (lock); ++ ++ /* Be prepared that the setpwent function was not called before. */ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ if (ext_ent.stream == NULL) ++ result = internal_setspent (&ext_ent, 1, 1); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop); ++ ++ __libc_lock_unlock (lock); ++ ++ return result; ++} ++ ++ ++/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ ++static enum nss_status ++internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct parser_data *data = (void *) buffer; ++ ++ while (1) ++ { ++ fpos_t pos; ++ char *p; ++ int parse_res; ++ ++ do ++ { ++ /* We need at least 3 characters for one line. */ ++ if (__glibc_unlikely (buflen < 3)) ++ { ++ erange: ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ fgetpos (ent->stream, &pos); ++ buffer[buflen - 1] = '\xff'; ++ p = fgets_unlocked (buffer, buflen, ent->stream); ++ if (p == NULL && feof_unlocked (ent->stream)) ++ return NSS_STATUS_NOTFOUND; ++ ++ if (p == NULL || buffer[buflen - 1] != '\xff') ++ { ++ erange_reset: ++ fsetpos (ent->stream, &pos); ++ goto erange; ++ } ++ ++ /* Terminate the line for any case. */ ++ buffer[buflen - 1] = '\0'; ++ ++ /* Skip leading blanks. */ ++ while (isspace (*p)) ++ ++p; ++ } ++ while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ /* Parse the line. If it is invalid, loop to ++ get the next line of the file to parse. */ ++ !(parse_res = _nss_files_parse_spent (p, result, data, buflen, ++ errnop))); ++ ++ if (__glibc_unlikely (parse_res == -1)) ++ /* The parser ran out of space. */ ++ goto erange_reset; ++ ++ /* This is a real entry. */ ++ if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') ++ { ++ if (strcmp (result->sp_namp, name) == 0) ++ return NSS_STATUS_SUCCESS; ++ else ++ continue; ++ } ++ ++ /* -@netgroup */ ++ /* If the loaded NSS module does not support this service, add ++ all users from a +@netgroup entry to the blacklist, too. */ ++ if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' ++ && result->sp_namp[2] != '\0') ++ { ++ if (innetgr (&result->sp_namp[2], NULL, name, NULL)) ++ return NSS_STATUS_NOTFOUND; ++ continue; ++ } ++ ++ /* +@netgroup */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' ++ && result->sp_namp[2] != '\0') ++ { ++ enum nss_status status; ++ ++ if (innetgr (&result->sp_namp[2], NULL, name, NULL)) ++ { ++ status = getspnam_plususer (name, result, ent, buffer, ++ buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ continue; ++ ++ return status; ++ } ++ continue; ++ } ++ ++ /* -user */ ++ if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' ++ && result->sp_namp[1] != '@') ++ { ++ if (strcmp (&result->sp_namp[1], name) == 0) ++ return NSS_STATUS_NOTFOUND; ++ else ++ continue; ++ } ++ ++ /* +user */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' ++ && result->sp_namp[1] != '@') ++ { ++ if (strcmp (name, &result->sp_namp[1]) == 0) ++ { ++ enum nss_status status; ++ ++ status = getspnam_plususer (name, result, ent, ++ buffer, buflen, errnop); ++ ++ if (status == NSS_STATUS_RETURN) ++ /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ ++ /* +:... */ ++ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') ++ { ++ enum nss_status status; ++ ++ status = getspnam_plususer (name, result, ent, ++ buffer, buflen, errnop); ++ ++ if (status == NSS_STATUS_SUCCESS) ++ /* We found the entry. */ ++ break; ++ else if (status == NSS_STATUS_RETURN) ++ /* We couldn't parse the entry */ ++ return NSS_STATUS_NOTFOUND; ++ else ++ return status; ++ } ++ } ++ return NSS_STATUS_SUCCESS; ++} ++ ++ ++enum nss_status ++_nss_compat_getspnam_r (const char *name, struct spwd *pwd, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ enum nss_status result; ++ ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0}, ++ { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; ++ ++ if (name[0] == '-' || name[0] == '+') ++ return NSS_STATUS_NOTFOUND; ++ ++ __libc_lock_lock (lock); ++ ++ if (ni == NULL) ++ init_nss_interface (); ++ ++ __libc_lock_unlock (lock); ++ ++ result = internal_setspent (&ent, 0, 0); ++ ++ if (result == NSS_STATUS_SUCCESS) ++ result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop); ++ ++ internal_endspent (&ent); ++ ++ return result; ++} ++ ++ ++/* Support routines for remembering -@netgroup and -user entries. ++ The names are stored in a single string with `|' as separator. */ ++static void ++blacklist_store_name (const char *name, ent_t *ent) ++{ ++ int namelen = strlen (name); ++ char *tmp; ++ ++ /* first call, setup cache */ ++ if (ent->blacklist.size == 0) ++ { ++ ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); ++ ent->blacklist.data = malloc (ent->blacklist.size); ++ if (ent->blacklist.data == NULL) ++ return; ++ ent->blacklist.data[0] = '|'; ++ ent->blacklist.data[1] = '\0'; ++ ent->blacklist.current = 1; ++ } ++ else ++ { ++ if (in_blacklist (name, namelen, ent)) ++ return; /* no duplicates */ ++ ++ if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) ++ { ++ ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); ++ tmp = realloc (ent->blacklist.data, ent->blacklist.size); ++ if (tmp == NULL) ++ { ++ free (ent->blacklist.data); ++ ent->blacklist.size = 0; ++ return; ++ } ++ ent->blacklist.data = tmp; ++ } ++ } ++ ++ tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); ++ *tmp++ = '|'; ++ *tmp = '\0'; ++ ent->blacklist.current += namelen + 1; ++ ++ return; ++} ++ ++ ++/* Returns whether ent->blacklist contains name. */ ++static bool ++in_blacklist (const char *name, int namelen, ent_t *ent) ++{ ++ char buf[namelen + 3]; ++ char *cp; ++ ++ if (ent->blacklist.data == NULL) ++ return false; ++ ++ buf[0] = '|'; ++ cp = stpcpy (&buf[1], name); ++ *cp++ = '|'; ++ *cp = '\0'; ++ return strstr (ent->blacklist.data, buf) != NULL; ++} +Index: glibc-2.26/nss/nss_compat/nisdomain.c +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/nisdomain.c +@@ -0,0 +1,58 @@ ++/* Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "nisdomain.h" ++ ++#define MAXDOMAINNAMELEN 1024 ++ ++static char domainname[MAXDOMAINNAMELEN]; ++ ++__libc_lock_define_initialized (static, domainname_lock) ++ ++int ++__nss_get_default_domain (char **outdomain) ++{ ++ int result = 0; ++ *outdomain = NULL; ++ ++ __libc_lock_lock (domainname_lock); ++ ++ if (domainname[0] != '\0') ++ { ++ if (getdomainname (domainname, MAXDOMAINNAMELEN) < 0) ++ result = errno; ++ else if (strcmp (domainname, "(none)") == 0) ++ { ++ /* If domainname is not set, some systems will return "(none)" */ ++ domainname[0] = '\0'; ++ result = ENOENT; ++ } ++ else ++ *outdomain = domainname; ++ } ++ else ++ *outdomain = domainname; ++ ++ __libc_lock_unlock (domainname_lock); ++ ++ return result; ++} +Index: glibc-2.26/nss/nss_compat/nisdomain.h +=================================================================== +--- /dev/null ++++ glibc-2.26/nss/nss_compat/nisdomain.h +@@ -0,0 +1,20 @@ ++/* Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Set OUTDOMAIN to a pointer to the current NIS domain name, or NULL if ++ not set. Return zero on success, an error number on failure. */ ++extern int __nss_get_default_domain (char **outdomain); diff --git a/nsswitch.conf b/nsswitch.conf index fbd63fd..e0c7d96 100644 --- a/nsswitch.conf +++ b/nsswitch.conf @@ -22,12 +22,9 @@ # For more information, please read the nsswitch.conf.5 manual page. # -# passwd: files nis -# shadow: files nis -# group: files nis - -passwd: compat [NOTFOUND=return] files -group: compat [NOTFOUND=return] files +passwd: compat +group: compat +shadow: compat hosts: files dns networks: files dns @@ -37,11 +34,9 @@ protocols: files rpc: files ethers: files netmasks: files -netgroup: files nis +netgroup: files publickey: files bootparams: files -automount: files nis +automount: files aliases: files - - diff --git a/remove-nss-nis-compat.patch b/remove-nss-nis-compat.patch new file mode 100644 index 0000000..4a78c5c --- /dev/null +++ b/remove-nss-nis-compat.patch @@ -0,0 +1,207 @@ +2017-08-29 Steve Ellcey + + * grp/initgroups.c: Include config.h. + (DEFAULT_CONFIG): New macro. + (internal_getgrouplist): Use DEFAULT_CONFIG. + * nscd/initgrcache.c (addinitgroupsX): Likewise. + * nss/nsswitch.c (__nss_disable_nscd): Likewise. + (DEFAULT_DEFCONFIG): New macro. + (__nss_database_lookup): Use DEFAULT_DEFCONFIG. + * nss/grp-lookup.c: Include config.h + (DEFAULT_CONFIG): Set definition based on LINK_OBSOLETE_NSL. + * nss/pwd-lookup.c (DEFAULT_CONFIG): Likewise. + * nss/spwd-lookup.c (DEFAULT_CONFIG): Likewise. + * manual/nss.texi: Update default values section. + + +Index: glibc-2.26/grp/initgroups.c +=================================================================== +--- glibc-2.26.orig/grp/initgroups.c ++++ glibc-2.26/grp/initgroups.c +@@ -26,10 +26,16 @@ + #include + #include + #include ++#include + + #include "../nscd/nscd-client.h" + #include "../nscd/nscd_proto.h" + ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++#endif + + /* Type of the lookup function. */ + typedef enum nss_status (*initgroups_dyn_function) (const char *, gid_t, +@@ -84,7 +90,7 @@ internal_getgrouplist (const char *user, + &__nss_initgroups_database) < 0) + { + if (__nss_group_database == NULL) +- no_more = __nss_database_lookup ("group", NULL, "compat files", ++ no_more = __nss_database_lookup ("group", NULL, DEFAULT_CONFIG, + &__nss_group_database); + + __nss_initgroups_database = __nss_group_database; +Index: glibc-2.26/manual/nss.texi +=================================================================== +--- glibc-2.26.orig/manual/nss.texi ++++ glibc-2.26/manual/nss.texi +@@ -318,13 +318,17 @@ The @code{passwd}, @code{group}, and @co + traditionally handled in a special way. The appropriate files in the + @file{/etc} directory are read but if an entry with a name starting + with a @code{+} character is found NIS is used. This kind of lookup +-remains possible by using the special lookup service @code{compat} +-and the default value for the three databases above is +-@code{compat [NOTFOUND=return] files}. ++remains possible if @theglibc{} was configured with the ++@code{--enable-obsolete-nsl} option and the special lookup service ++@code{compat} is used. If @theglibc{} was configured with the ++@code{--enable-obsolete-nsl} option the default value for the three ++databases above is @code{compat [NOTFOUND=return] files}. If the ++@code{--enable-obsolete-nsl} option was not used the default value ++for the services is @code{files}. + +-For all other databases the default value is +-@code{nis [NOTFOUND=return] files}. This solution gives the best +-chance to be correct since NIS and file based lookups are used. ++For all other databases the default value is @code{files} unless ++@theglibc{} was configured with @code{--enable-obsolete-rpc} option, in ++which case it the default value is @code{nis [NOTFOUND=return] files}. + + @cindex optimizing NSS + A second point is that the user should try to optimize the lookup +Index: glibc-2.26/nscd/initgrcache.c +=================================================================== +--- glibc-2.26.orig/nscd/initgrcache.c ++++ glibc-2.26/nscd/initgrcache.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "dbg_log.h" + #include "nscd.h" +@@ -34,6 +35,11 @@ + + #include "../nss/nsswitch.h" + ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++#endif + + /* Type of the lookup function. */ + typedef enum nss_status (*initgroups_dyn_function) (const char *, gid_t, +@@ -85,8 +91,7 @@ addinitgroupsX (struct database_dyn *db, + int no_more; + + if (group_database == NULL) +- no_more = __nss_database_lookup ("group", NULL, +- "compat [NOTFOUND=return] files", ++ no_more = __nss_database_lookup ("group", NULL, DEFAULT_CONFIG, + &group_database); + else + no_more = 0; +Index: glibc-2.26/nss/grp-lookup.c +=================================================================== +--- glibc-2.26.orig/nss/grp-lookup.c ++++ glibc-2.26/nss/grp-lookup.c +@@ -16,7 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + #define DATABASE_NAME group +-#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++#endif + + #include "XXX-lookup.c" +Index: glibc-2.26/nss/nsswitch.c +=================================================================== +--- glibc-2.26.orig/nss/nsswitch.c ++++ glibc-2.26/nss/nsswitch.c +@@ -40,6 +40,15 @@ + #include "nsswitch.h" + #include "../nscd/nscd_proto.h" + #include ++#include ++ ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++# define DEFAULT_DEFCONFIG "nis [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++# define DEFAULT_DEFCONFIG "files" ++#endif + + /* Prototypes for the local functions. */ + static name_database *nss_parse_file (const char *fname) internal_function; +@@ -151,8 +160,7 @@ __nss_database_lookup (const char *datab + or null to use the most common default. */ + if (*ni == NULL) + { +- *ni = nss_parse_service_list (defconfig +- ?: "nis [NOTFOUND=return] files"); ++ *ni = nss_parse_service_list (defconfig ?: DEFAULT_DEFCONFIG); + if (*ni != NULL) + { + /* Record the memory we've just allocated in defconfig_entries list, +@@ -848,8 +856,8 @@ __nss_disable_nscd (void (*cb) (size_t, + is_nscd = true; + + /* Find all the relevant modules so that the init functions are called. */ +- nss_load_all_libraries ("passwd", "compat [NOTFOUND=return] files"); +- nss_load_all_libraries ("group", "compat [NOTFOUND=return] files"); ++ nss_load_all_libraries ("passwd", DEFAULT_CONFIG); ++ nss_load_all_libraries ("group", DEFAULT_CONFIG); + nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files"); + nss_load_all_libraries ("services", NULL); + +Index: glibc-2.26/nss/pwd-lookup.c +=================================================================== +--- glibc-2.26.orig/nss/pwd-lookup.c ++++ glibc-2.26/nss/pwd-lookup.c +@@ -16,7 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + #define DATABASE_NAME passwd +-#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++#endif + + #include "XXX-lookup.c" +Index: glibc-2.26/nss/spwd-lookup.c +=================================================================== +--- glibc-2.26.orig/nss/spwd-lookup.c ++++ glibc-2.26/nss/spwd-lookup.c +@@ -16,8 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + #define DATABASE_NAME shadow + #define ALTERNATE_NAME passwd +-#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#ifdef LINK_OBSOLETE_NSL ++# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" ++#else ++# define DEFAULT_CONFIG "files" ++#endif + + #include "XXX-lookup.c" diff --git a/resolv-conf-oom.patch b/resolv-conf-oom.patch new file mode 100644 index 0000000..129aa7a --- /dev/null +++ b/resolv-conf-oom.patch @@ -0,0 +1,44 @@ +2017-09-06 Florian Weimer + + [BZ #22096] + * resolv/resolv_conf.c (__resolv_conf_attach): Do not free conf in + case of failure to obtain the global conf object. + +2017-09-06 Florian Weimer + + [BZ #22095] + * resolv/res_init.c (res_vinit_1): Avoid memory leak in case of + dynarray allocation failure. + +Index: glibc-2.26/resolv/res_init.c +=================================================================== +--- glibc-2.26.orig/resolv/res_init.c ++++ glibc-2.26/resolv/res_init.c +@@ -446,6 +446,11 @@ res_vinit_1 (FILE *fp, struct resolv_con + (&parser->nameserver_list); + if (p != NULL) + *p = sa; ++ else ++ { ++ free (sa); ++ return false; ++ } + } + continue; + } +Index: glibc-2.26/resolv/resolv_conf.c +=================================================================== +--- glibc-2.26.orig/resolv/resolv_conf.c ++++ glibc-2.26/resolv/resolv_conf.c +@@ -600,10 +600,7 @@ __resolv_conf_attach (struct __res_state + + struct resolv_conf_global *global_copy = get_locked_global (); + if (global_copy == NULL) +- { +- free (conf); +- return false; +- } ++ return false; + + /* Try to find an unused index in the array. */ + size_t index;