diff options
Diffstat (limited to 'REORG.TODO/nss')
69 files changed, 10323 insertions, 0 deletions
diff --git a/REORG.TODO/nss/Depend b/REORG.TODO/nss/Depend new file mode 100644 index 0000000000..d755539902 --- /dev/null +++ b/REORG.TODO/nss/Depend @@ -0,0 +1,2 @@ +dlfcn +resolv diff --git a/REORG.TODO/nss/Makefile b/REORG.TODO/nss/Makefile new file mode 100644 index 0000000000..430be8726f --- /dev/null +++ b/REORG.TODO/nss/Makefile @@ -0,0 +1,137 @@ +# Copyright (C) 1996-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 +# <http://www.gnu.org/licenses/>. + +# +# Makefile for name service switch. +# +subdir := nss + +include ../Makeconfig + +headers := nss.h + +# This is the trivial part which goes into libc itself. +routines = nsswitch getnssent getnssent_r digits_dots \ + valid_field valid_list_field rewrite_field \ + $(addsuffix -lookup,$(databases)) + +# These are the databases that go through nss dispatch. +# Caution: if you add a database here, you must add its real name +# in databases.def, too. +databases = proto service hosts network grp pwd ethers \ + spwd netgrp alias sgrp + +ifneq (,$(filter sunrpc,$(subdirs))) +databases += key rpc +have-sunrpc := 1 +else +have-sunrpc := 0 +endif +CPPFLAGS-getent.c = -DHAVE_SUNRPC=$(have-sunrpc) + +others := getent makedb +install-bin := getent makedb +makedb-modules = xmalloc hash-string +extra-objs += $(makedb-modules:=.o) + +tests-static = tst-field +tests-internal = tst-field +tests = test-netdb tst-nss-test1 test-digits-dots \ + tst-nss-getpwent bug17079 +xtests = bug-erange + +# If we have a thread library then we can test cancellation against +# some routines like getpwuid_r. +ifeq (yes,$(have-thread-library)) +tests += tst-cancel-getpwuid_r +endif + +# Specify rules for the nss_* modules. We have some services. +services := files db + +extra-libs = $(services:%=libnss_%) +# These libraries will be built in the `others' pass rather than +# the `lib' pass, because they depend on libc.so being built already. +extra-libs-others = $(extra-libs) + +# The sources are found in the appropriate subdir. +subdir-dirs = $(services:%=nss_%) +vpath %.c $(subdir-dirs) ../locale/programs ../intl + + +libnss_files-routines := $(addprefix files-,$(databases)) \ + files-initgroups files-init + +libnss_db-dbs := $(addprefix db-,\ + $(filter-out hosts network key alias,\ + $(databases))) \ + db-initgroups +libnss_db-routines := $(libnss_db-dbs) db-open db-init hash-string +generated += $(filter-out db-alias.c db-netgrp.c, \ + $(addsuffix .c,$(libnss_db-dbs))) + +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)) +ifeq ($(build-static-nss),yes) +routines += $(libnss_files-routines) +static-only-routines += $(libnss_files-routines) +tests-static += tst-nss-static +endif +extra-test-objs += nss_test1.os + +include ../Rules + +ifeq (yes,$(have-selinux)) +LDLIBS-makedb := -lselinux +endif + +libnss-libc = $(common-objpfx)linkobj/libc.so +# Target-specific variable setting to link objects using deprecated +# RPC interfaces with the version of libc.so that makes them available +# for new links: +$(services:%=$(objpfx)libnss_%.so): libc-for-link = $(libnss-libc) + +$(objpfx)libnss_db.so: $(objpfx)libnss_files.so + +$(libnss_db-dbs:%=$(objpfx)%.c): $(objpfx)db-%.c: nss_files/files-%.c + @rm -f $@.new + (echo '#define EXTERN_PARSER';\ + echo '#define GENERIC "../nss_db/db-XXX.c"';\ + echo '#include "$<"') > $@.new + mv -f $@.new $@ + + +$(objpfx)makedb: $(makedb-modules:%=$(objpfx)%.o) + +$(inst_vardbdir)/Makefile: db-Makefile $(+force) + $(do-install) + +libof-nss_test1 = extramodules +$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) +ifdef libnss_test1.so-version +$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so + $(make-link) +endif +$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version) + +ifeq (yes,$(have-thread-library)) +$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +endif diff --git a/REORG.TODO/nss/Versions b/REORG.TODO/nss/Versions new file mode 100644 index 0000000000..f8ababccc7 --- /dev/null +++ b/REORG.TODO/nss/Versions @@ -0,0 +1,162 @@ +libc { + GLIBC_2.0 { + # functions used in other libraries + __nss_passwd_lookup; __nss_group_lookup; __nss_hosts_lookup; __nss_next; + __nss_database_lookup; __nss_configure_lookup; + } + GLIBC_2.2.2 { + __nss_hostname_digits_dots; + } + GLIBC_PRIVATE { + _nss_files_parse_grent; _nss_files_parse_pwent; _nss_files_parse_spent; + __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent; + + __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; + __nss_services_lookup2; __nss_next2; __nss_lookup; + } +} + +libnss_files { + GLIBC_PRIVATE { + _nss_files_setaliasent; + _nss_files_endaliasent; + _nss_files_getaliasbyname_r; + _nss_files_getaliasent_r; + + _nss_files_setetherent; + _nss_files_endetherent; + _nss_files_getetherent_r; + _nss_files_parse_etherent; + _nss_files_gethostton_r; + _nss_files_getntohost_r; + + _nss_files_setgrent; + _nss_files_endgrent; + _nss_files_getgrent_r; + _nss_files_getgrgid_r; + _nss_files_getgrnam_r; + + _nss_files_sethostent; + _nss_files_endhostent; + _nss_files_gethostbyaddr_r; + _nss_files_gethostbyname2_r; + _nss_files_gethostbyname3_r; + _nss_files_gethostbyname4_r; + _nss_files_gethostbyname_r; + _nss_files_gethostent_r; + + _nss_files_setnetent; + _nss_files_endnetent; + _nss_files_getnetbyaddr_r; + _nss_files_getnetbyname_r; + _nss_files_getnetent_r; + _nss_files_parse_netent; + + _nss_files_setnetgrent; + _nss_files_endnetgrent; + _nss_files_getnetgrent_r; + + _nss_files_setprotoent; + _nss_files_endprotoent; + _nss_files_getprotobyname_r; + _nss_files_getprotobynumber_r; + _nss_files_getprotoent_r; + _nss_files_parse_protoent; + + _nss_files_setpwent; + _nss_files_endpwent; + _nss_files_getpwent_r; + _nss_files_getpwnam_r; + _nss_files_getpwuid_r; + + _nss_files_setrpcent; + _nss_files_endrpcent; + _nss_files_getrpcbyname_r; + _nss_files_getrpcbynumber_r; + _nss_files_getrpcent_r; + _nss_files_parse_rpcent; + + _nss_files_setservent; + _nss_files_endservent; + _nss_files_getservbyname_r; + _nss_files_getservbyport_r; + _nss_files_getservent_r; + _nss_files_parse_servent; + + _nss_files_setspent; + _nss_files_endspent; + _nss_files_getspent_r; + _nss_files_getspnam_r; + + _nss_files_setsgent; + _nss_files_endsgent; + _nss_files_getsgent_r; + _nss_files_getsgnam_r; + + _nss_netgroup_parseline; + _nss_files_getpublickey; + _nss_files_getsecretkey; + + _nss_files_initgroups_dyn; + + _nss_files_init; + } +} + +libnss_db { + GLIBC_PRIVATE { + _nss_db_setetherent; + _nss_db_endetherent; + _nss_db_getetherent_r; + _nss_db_gethostton_r; + _nss_db_getntohost_r; + + _nss_db_setgrent; + _nss_db_endgrent; + _nss_db_getgrent_r; + _nss_db_getgrgid_r; + _nss_db_getgrnam_r; + + _nss_db_setnetgrent; + _nss_db_endnetgrent; + _nss_db_getnetgrent_r; + + _nss_db_setprotoent; + _nss_db_endprotoent; + _nss_db_getprotoent_r; + _nss_db_getprotobyname_r; + _nss_db_getprotobynumber_r; + + _nss_db_setpwent; + _nss_db_endpwent; + _nss_db_getpwent_r; + _nss_db_getpwnam_r; + _nss_db_getpwuid_r; + + _nss_db_setrpcent; + _nss_db_endrpcent; + _nss_db_getrpcent_r; + _nss_db_getrpcbyname_r; + _nss_db_getrpcbynumber_r; + + _nss_db_setservent; + _nss_db_endservent; + _nss_db_getservent_r; + _nss_db_getservbyname_r; + _nss_db_getservbyport_r; + + _nss_db_setsgent; + _nss_db_endsgent; + _nss_db_getsgent_r; + _nss_db_getsgnam_r; + + _nss_db_setspent; + _nss_db_endspent; + _nss_db_getspent_r; + _nss_db_getspnam_r; + + _nss_db_initgroups_dyn; + + _nss_db_init; + } +} diff --git a/REORG.TODO/nss/XXX-lookup.c b/REORG.TODO/nss/XXX-lookup.c new file mode 100644 index 0000000000..5a37fdae08 --- /dev/null +++ b/REORG.TODO/nss/XXX-lookup.c @@ -0,0 +1,87 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include "nsswitch.h" + +/*******************************************************************\ +|* Here we assume one symbol to be defined: *| +|* *| +|* DATABASE_NAME - name of the database the function accesses *| +|* (e.g., hosts, services, ...) *| +|* *| +|* One additional symbol may optionally be defined: *| +|* *| +|* ALTERNATE_NAME - name of another service which is examined in *| +|* case DATABASE_NAME is not found *| +|* *| +|* DEFAULT_CONFIG - string for default conf (e.g. "dns files") *| +|* *| +\*******************************************************************/ + +#define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2) +#define DB_COMPAT_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup) +#define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post) +#define CONCAT3_2(Pre, Name, Post) Pre##Name##Post + +#define DATABASE_NAME_SYMBOL CONCAT3_1 (__nss_, DATABASE_NAME, _database) +#define DATABASE_NAME_STRING STRINGIFY1 (DATABASE_NAME) +#define STRINGIFY1(Name) STRINGIFY2 (Name) +#define STRINGIFY2(Name) #Name + +#ifdef ALTERNATE_NAME +#define ALTERNATE_NAME_STRING STRINGIFY1 (ALTERNATE_NAME) +#else +#define ALTERNATE_NAME_STRING NULL +#endif + +#ifndef DEFAULT_CONFIG +#define DEFAULT_CONFIG NULL +#endif + +service_user *DATABASE_NAME_SYMBOL attribute_hidden; + +extern int DB_LOOKUP_FCT (service_user **ni, const char *fct_name, + const char *fct2_name, void **fctp) + internal_function; +libc_hidden_proto (DB_LOOKUP_FCT) + +int +internal_function +DB_LOOKUP_FCT (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp) +{ + if (DATABASE_NAME_SYMBOL == NULL + && __nss_database_lookup (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, + DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) + return -1; + + *ni = DATABASE_NAME_SYMBOL; + + return __nss_lookup (ni, fct_name, fct2_name, fctp); +} +libc_hidden_def (DB_LOOKUP_FCT) + + +#ifndef NO_COMPAT +int +internal_function attribute_compat_text_section +DB_COMPAT_FCT (service_user **ni, const char *fct_name, void **fctp) +{ + return DB_LOOKUP_FCT (ni, fct_name, NULL, fctp); +} +#endif diff --git a/REORG.TODO/nss/alias-lookup.c b/REORG.TODO/nss/alias-lookup.c new file mode 100644 index 0000000000..4e7e5d5921 --- /dev/null +++ b/REORG.TODO/nss/alias-lookup.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME aliases + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/bug-erange.c b/REORG.TODO/nss/bug-erange.c new file mode 100644 index 0000000000..b709418b5c --- /dev/null +++ b/REORG.TODO/nss/bug-erange.c @@ -0,0 +1,52 @@ +/* Test case for gethostbyname_r bug when buffer expansion required. */ + +#include <netdb.h> +#include <arpa/inet.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +main (void) +{ + const char *host = "www.gnu.org"; + + /* This code approximates the example code in the library manual. */ + + struct hostent hostbuf, *hp; + size_t hstbuflen; + char *tmphstbuf; + int res; + int herr; + + hstbuflen = 16; /* Make it way small to ensure ERANGE. */ + /* Allocate buffer, remember to free it to avoid memory leakage. */ + tmphstbuf = malloc (hstbuflen); + + while ((res = gethostbyname_r (host, &hostbuf, tmphstbuf, hstbuflen, + &hp, &herr)) == ERANGE) + { + /* Enlarge the buffer. */ + hstbuflen *= 2; + tmphstbuf = realloc (tmphstbuf, hstbuflen); + } + + if (res != 0 || hp == NULL) + { + printf ("gethostbyname_r failed: %s (errno: %m)\n", strerror (res)); + + if (access ("/etc/resolv.conf", R_OK)) + { + puts ("DNS probably not set up"); + return 0; + } + + return 1; + } + + printf ("Got: %s %s\n", hp->h_name, + inet_ntoa (*(struct in_addr *) hp->h_addr)); + return 0; +} diff --git a/REORG.TODO/nss/bug17079.c b/REORG.TODO/nss/bug17079.c new file mode 100644 index 0000000000..4171c7db55 --- /dev/null +++ b/REORG.TODO/nss/bug17079.c @@ -0,0 +1,244 @@ +/* Test for bug 17079: heap overflow in NSS with small buffers. + Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* Check if two passwd structs contain the same data. */ +static bool +equal (const struct passwd *a, const struct passwd *b) +{ + return strcmp (a->pw_name, b->pw_name) == 0 + && strcmp (a->pw_passwd, b->pw_passwd) == 0 + && a->pw_uid == b->pw_uid + && a->pw_gid == b->pw_gid + && strcmp (a->pw_gecos, b->pw_gecos) == 0 + && strcmp (a->pw_dir, b->pw_dir) == 0 + && strcmp (a->pw_shell, b->pw_shell) == 0; +} + +enum { MAX_TEST_ITEMS = 10 }; +static struct passwd test_items[MAX_TEST_ITEMS]; +static int test_count; + +/* Initialize test_items and test_count above, with data from the + passwd database. */ +static bool +init_test_items (void) +{ + setpwent (); + do + { + struct passwd *pwd = getpwent (); + if (pwd == NULL) + break; + struct passwd *target = test_items + test_count; + target->pw_name = strdup (pwd->pw_name); + target->pw_passwd = strdup (pwd->pw_passwd); + target->pw_uid = pwd->pw_uid; + target->pw_gid = pwd->pw_gid; + target->pw_gecos = strdup (pwd->pw_gecos); + target->pw_dir = strdup (pwd->pw_dir); + target->pw_shell = strdup (pwd->pw_shell); + } + while (++test_count < MAX_TEST_ITEMS); + endpwent (); + + /* Filter out those test items which cannot be looked up by name or + UID. */ + bool found = false; + for (int i = 0; i < test_count; ++i) + { + struct passwd *pwd1 = getpwnam (test_items[i].pw_name); + struct passwd *pwd2 = getpwuid (test_items[i].pw_uid); + if (pwd1 == NULL || !equal (pwd1, test_items + i) + || pwd2 == NULL || !equal (pwd2, test_items + i)) + { + printf ("info: skipping user \"%s\", UID %ld due to inconsistency\n", + test_items[i].pw_name, (long) test_items[i].pw_uid); + test_items[i].pw_name = NULL; + } + else + found = true; + } + + if (!found) + puts ("error: no accounts found which can be looked up by name and UID."); + return found; +} + +/* Set to true if an error is encountered. */ +static bool errors; + +/* Return true if the padding has not been tampered with. */ +static bool +check_padding (char *buffer, size_t size, char pad) +{ + char *end = buffer + size; + while (buffer < end) + { + if (*buffer != pad) + return false; + ++buffer; + } + return true; +} + +/* Test one buffer size and padding combination. */ +static void +test_one (const struct passwd *item, size_t buffer_size, + char pad, size_t padding_size) +{ + char *buffer = malloc (buffer_size + padding_size); + if (buffer == NULL) + { + puts ("error: malloc failure"); + errors = true; + return; + } + + struct passwd pwd; + struct passwd *result; + int ret; + + /* Test getpwname_r. */ + memset (buffer, pad, buffer_size + padding_size); + pwd = (struct passwd) {}; + ret = getpwnam_r (item->pw_name, &pwd, buffer, buffer_size, &result); + if (!check_padding (buffer + buffer_size, padding_size, pad)) + { + printf ("error: padding change: " + "name \"%s\", buffer size %zu, padding size %zu, pad 0x%02x\n", + item->pw_name, buffer_size, padding_size, (unsigned char) pad); + errors = true; + } + if (ret == 0) + { + if (result == NULL) + { + printf ("error: no data: name \"%s\", buffer size %zu\n", + item->pw_name, buffer_size); + errors = true; + } + else if (!equal (item, result)) + { + printf ("error: lookup mismatch: name \"%s\", buffer size %zu\n", + item->pw_name, buffer_size); + errors = true; + } + } + else if (ret != ERANGE) + { + errno = ret; + printf ("error: lookup failure for name \"%s\": %m (%d)\n", + item->pw_name, ret); + errors = true; + } + + /* Test getpwuid_r. */ + memset (buffer, pad, buffer_size + padding_size); + pwd = (struct passwd) {}; + ret = getpwuid_r (item->pw_uid, &pwd, buffer, buffer_size, &result); + if (!check_padding (buffer + buffer_size, padding_size, pad)) + { + printf ("error: padding change: " + "UID %ld, buffer size %zu, padding size %zu, pad 0x%02x\n", + (long) item->pw_uid, buffer_size, padding_size, + (unsigned char) pad); + errors = true; + } + if (ret == 0) + { + if (result == NULL) + { + printf ("error: no data: UID %ld, buffer size %zu\n", + (long) item->pw_uid, buffer_size); + errors = true; + } + else if (!equal (item, result)) + { + printf ("error: lookup mismatch: UID %ld, buffer size %zu\n", + (long) item->pw_uid, buffer_size); + errors = true; + } + } + else if (ret != ERANGE) + { + errno = ret; + printf ("error: lookup failure for UID \"%ld\": %m (%d)\n", + (long) item->pw_uid, ret); + errors = true; + } + + free (buffer); +} + +/* Test one buffer size with different paddings. */ +static void +test_buffer_size (size_t buffer_size) +{ + for (int i = 0; i < test_count; ++i) + for (size_t padding_size = 0; padding_size < 3; ++padding_size) + { + /* Skip entries with inconsistent name/UID lookups. */ + if (test_items[i].pw_name == NULL) + continue; + + test_one (test_items + i, buffer_size, '\0', padding_size); + if (padding_size > 0) + { + test_one (test_items + i, buffer_size, ':', padding_size); + test_one (test_items + i, buffer_size, '\n', padding_size); + test_one (test_items + i, buffer_size, '\xff', padding_size); + test_one (test_items + i, buffer_size, '@', padding_size); + } + } +} + +int +do_test (void) +{ + if (!init_test_items ()) + return 1; + printf ("info: %d test items\n", test_count); + + for (size_t buffer_size = 0; buffer_size <= 65; ++buffer_size) + test_buffer_size (buffer_size); + for (size_t buffer_size = 64 + 4; buffer_size < 256; buffer_size += 4) + test_buffer_size (buffer_size); + test_buffer_size (255); + test_buffer_size (257); + for (size_t buffer_size = 256; buffer_size < 512; buffer_size += 8) + test_buffer_size (buffer_size); + test_buffer_size (511); + test_buffer_size (513); + test_buffer_size (1024); + test_buffer_size (2048); + + if (errors) + return 1; + else + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/databases.def b/REORG.TODO/nss/databases.def new file mode 100644 index 0000000000..8a46839618 --- /dev/null +++ b/REORG.TODO/nss/databases.def @@ -0,0 +1,42 @@ +/* List of all databases defined for the NSS in GNU C Library. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +/* This list must be kept sorted!!! If any long name is added the + field size for it must be increases. */ + +DEFINE_DATABASE (aliases) +DEFINE_DATABASE (ethers) +DEFINE_DATABASE (group) +DEFINE_DATABASE (gshadow) +DEFINE_DATABASE (hosts) +DEFINE_DATABASE (initgroups) +DEFINE_DATABASE (netgroup) +DEFINE_DATABASE (networks) +DEFINE_DATABASE (passwd) +DEFINE_DATABASE (protocols) +DEFINE_DATABASE (publickey) +DEFINE_DATABASE (rpc) +DEFINE_DATABASE (services) +DEFINE_DATABASE (shadow) + +/* + Local Variables: + mode:C + End: + */ diff --git a/REORG.TODO/nss/db-Makefile b/REORG.TODO/nss/db-Makefile new file mode 100644 index 0000000000..aa22ed0d5b --- /dev/null +++ b/REORG.TODO/nss/db-Makefile @@ -0,0 +1,166 @@ +# Makefile to (re-)generate db versions of system database files. +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 +# <http://www.gnu.org/licenses/>. + +DATABASES = $(wildcard /etc/passwd /etc/group /etc/ethers /etc/protocols \ + /etc/rpc /etc/services /etc/shadow /etc/gshadow \ + /etc/netgroup) + +VAR_DB = /var/db + +AWK = awk +MAKEDB = makedb --quiet + +all: $(patsubst %,$(VAR_DB)/%.db,$(notdir $(DATABASES))) + + +$(VAR_DB)/passwd.db: /etc/passwd + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { FS=":"; OFS=":" } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print; \ + printf "=%s ", $$3; print }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/group.db: /etc/group + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { FS=":"; OFS=":" } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print; \ + printf "=%s ", $$3; print; \ + if ($$4 != "") { \ + split($$4, grmems, ","); \ + for (memidx in grmems) { \ + mem=grmems[memidx]; \ + if (members[mem] == "") \ + members[mem]=$$3; \ + else \ + members[mem]=members[mem] "," $$3; \ + } \ + delete grmems; } } \ + END { for (mem in members) \ + printf ":%s %s %s\n", mem, mem, members[mem]; }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/ethers.db: /etc/ethers + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) '/^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print; \ + printf "=%s ", $$2; print }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/protocols.db: /etc/protocols + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) '/^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print; \ + printf "=%s ", $$2; print; \ + for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \ + { printf ".%s ", $$i; print } }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/rpc.db: /etc/rpc + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) '/^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print; \ + printf "=%s ", $$2; print; \ + for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \ + { printf ".%s ", $$i; print } }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/services.db: /etc/services + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { FS="[ \t/]+" } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { sub(/[ \t]*#.*$$/, "");\ + printf ":%s/%s ", $$1, $$3; print; \ + printf ":%s/ ", $$1; print; \ + printf "=%s/%s ", $$2, $$3; print; \ + printf "=%s/ ", $$2; print; \ + for (i = 4; i <= NF && !($$i ~ /^#/); ++i) \ + { printf ":%s/%s ", $$i, $$3; print; \ + printf ":%s/ ", $$i; print } }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." + +$(VAR_DB)/shadow.db: /etc/shadow + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { FS=":"; OFS=":" } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print }' $^ | \ + (umask 077 && $(MAKEDB) -o $@ -) + @echo "done." + @if chgrp shadow $@ 2>/dev/null; then \ + chmod g+r $@; \ + else \ + chown 0 $@; chgrp 0 $@; chmod 600 $@; \ + echo; \ + echo "Warning: The shadow password database $@"; \ + echo "has been set to be readable only by root. You may want"; \ + echo "to make it readable by the \`shadow' group depending"; \ + echo "on your configuration."; \ + echo; \ + fi + +$(VAR_DB)/gshadow.db: /etc/gshadow + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { FS=":"; OFS=":" } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { printf ".%s ", $$1; print }' $^ | \ + (umask 077 && $(MAKEDB) -o $@ -) + @echo "done." + @if chgrp shadow $@ 2>/dev/null; then \ + chmod g+r $@; \ + else \ + chown 0 $@; chgrp 0 $@; chmod 600 $@; \ + echo; \ + echo "Warning: The shadow group database $@"; \ + echo "has been set to be readable only by root. You may want"; \ + echo "to make it readable by the \`shadow' group depending"; \ + echo "on your configuration."; \ + echo; \ + fi + +$(VAR_DB)/netgroup.db: /etc/netgroup + @printf %s "$(patsubst %.db,%,$(@F))... " + @$(AWK) 'BEGIN { ini=1 } \ + /^[ \t]*$$/ { next } \ + /^[ \t]*#/ { next } \ + /^[^#]/ { if (sub(/[ \t]*\\$$/, " ") == 0) end="\n"; \ + else end=""; \ + gsub(/[ \t]+/, " "); \ + sub(/^[ \t]*/, ""); \ + if (ini == 0) printf "%s%s", $$0, end; \ + else printf ".%s %s%s", $$1, $$0, end; \ + ini=end == "" ? 0 : 1; } \ + END { if (ini==0) printf "\n" }' $^ | \ + $(MAKEDB) -o $@ - + @echo "done." diff --git a/REORG.TODO/nss/digits_dots.c b/REORG.TODO/nss/digits_dots.c new file mode 100644 index 0000000000..8dcbf9eb0a --- /dev/null +++ b/REORG.TODO/nss/digits_dots.c @@ -0,0 +1,283 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by H.J. Lu <hjl@gnu.ai.mit.edu>, 1997. + + 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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <wctype.h> +#include <resolv/resolv-internal.h> +#include <netdb.h> +#include <arpa/inet.h> +#include "nsswitch.h" + +#ifdef USE_NSCD +# define inet_aton __inet_aton +# include <nscd/nscd_proto.h> +#endif + +int +__nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + char **buffer, size_t *buffer_size, + size_t buflen, struct hostent **result, + enum nss_status *status, int af, int *h_errnop) +{ + int save; + + /* We have to test for the use of IPv6 which can only be done by + examining `_res'. */ + if (__res_maybe_init (&_res, 0) == -1) + { + if (h_errnop) + *h_errnop = NETDB_INTERNAL; + if (buffer_size == NULL) + *status = NSS_STATUS_TRYAGAIN; + else + *result = NULL; + return -1; + } + + /* + * disallow names consisting only of digits/dots, unless + * they end in a dot. + */ + if (isdigit (name[0]) || isxdigit (name[0]) || name[0] == ':') + { + const char *cp; + char *hostname; + typedef unsigned char host_addr_t[16]; + host_addr_t *host_addr; + typedef char *host_addr_list_t[2]; + host_addr_list_t *h_addr_ptrs; + char **h_alias_ptr; + size_t size_needed; + int addr_size; + + switch (af) + { + case AF_INET: + addr_size = INADDRSZ; + break; + + case AF_INET6: + addr_size = IN6ADDRSZ; + break; + + default: + af = res_use_inet6 () ? AF_INET6 : AF_INET; + addr_size = af == AF_INET6 ? IN6ADDRSZ : INADDRSZ; + break; + } + + size_needed = (sizeof (*host_addr) + + sizeof (*h_addr_ptrs) + + sizeof (*h_alias_ptr) + strlen (name) + 1); + + if (buffer_size == NULL) + { + if (buflen < size_needed) + { + *status = NSS_STATUS_TRYAGAIN; + if (h_errnop != NULL) + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + goto done; + } + } + else if (buffer_size != NULL && *buffer_size < size_needed) + { + char *new_buf; + *buffer_size = size_needed; + new_buf = (char *) realloc (*buffer, *buffer_size); + + if (new_buf == NULL) + { + save = errno; + free (*buffer); + *buffer = NULL; + *buffer_size = 0; + __set_errno (save); + if (h_errnop != NULL) + *h_errnop = NETDB_INTERNAL; + *result = NULL; + goto done; + } + *buffer = new_buf; + } + + memset (*buffer, '\0', size_needed); + + host_addr = (host_addr_t *) *buffer; + h_addr_ptrs = (host_addr_list_t *) + ((char *) host_addr + sizeof (*host_addr)); + h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs)); + hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr); + + if (isdigit (name[0])) + { + for (cp = name;; ++cp) + { + if (*cp == '\0') + { + int ok; + + if (*--cp == '.') + break; + + /* All-numeric, no dot at the end. Fake up a hostent as if + we'd actually done a lookup. What if someone types + 255.255.255.255? The test below will succeed + spuriously... ??? */ + if (af == AF_INET) + ok = __inet_aton (name, (struct in_addr *) host_addr); + else + { + assert (af == AF_INET6); + ok = inet_pton (af, name, host_addr) > 0; + } + if (! ok) + { + *h_errnop = HOST_NOT_FOUND; + if (buffer_size == NULL) + *status = NSS_STATUS_NOTFOUND; + else + *result = NULL; + goto done; + } + + resbuf->h_name = strcpy (hostname, name); + h_alias_ptr[0] = NULL; + resbuf->h_aliases = h_alias_ptr; + (*h_addr_ptrs)[0] = (char *) host_addr; + (*h_addr_ptrs)[1] = NULL; + resbuf->h_addr_list = *h_addr_ptrs; + if (af == AF_INET && res_use_inet6 ()) + { + /* We need to change the IP v4 address into the + IP v6 address. */ + char tmp[INADDRSZ]; + char *p = (char *) host_addr; + int i; + + /* Save a copy of the IP v4 address. */ + memcpy (tmp, host_addr, INADDRSZ); + /* Mark this ipv6 addr as a mapped ipv4. */ + for (i = 0; i < 10; i++) + *p++ = 0x00; + *p++ = 0xff; + *p++ = 0xff; + /* Copy the IP v4 address. */ + memcpy (p, tmp, INADDRSZ); + resbuf->h_addrtype = AF_INET6; + resbuf->h_length = IN6ADDRSZ; + } + else + { + resbuf->h_addrtype = af; + resbuf->h_length = addr_size; + } + if (h_errnop != NULL) + *h_errnop = NETDB_SUCCESS; + if (buffer_size == NULL) + *status = NSS_STATUS_SUCCESS; + else + *result = resbuf; + goto done; + } + + if (!isdigit (*cp) && *cp != '.') + break; + } + } + + if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':') + { + switch (af) + { + default: + af = res_use_inet6 () ? AF_INET6 : AF_INET; + if (af == AF_INET6) + { + addr_size = IN6ADDRSZ; + break; + } + /* FALLTHROUGH */ + + case AF_INET: + /* This is not possible. We cannot represent an IPv6 address + in an `struct in_addr' variable. */ + *h_errnop = HOST_NOT_FOUND; + if (buffer_size == NULL) + *status = NSS_STATUS_NOTFOUND; + else + *result = NULL; + goto done; + + case AF_INET6: + addr_size = IN6ADDRSZ; + break; + } + + for (cp = name;; ++cp) + { + if (!*cp) + { + if (*--cp == '.') + break; + + /* All-IPv6-legal, no dot at the end. Fake up a + hostent as if we'd actually done a lookup. */ + if (inet_pton (AF_INET6, name, host_addr) <= 0) + { + *h_errnop = HOST_NOT_FOUND; + if (buffer_size == NULL) + *status = NSS_STATUS_NOTFOUND; + else + *result = NULL; + goto done; + } + + resbuf->h_name = strcpy (hostname, name); + h_alias_ptr[0] = NULL; + resbuf->h_aliases = h_alias_ptr; + (*h_addr_ptrs)[0] = (char *) host_addr; + (*h_addr_ptrs)[1] = (char *) 0; + resbuf->h_addr_list = *h_addr_ptrs; + resbuf->h_addrtype = AF_INET6; + resbuf->h_length = addr_size; + *h_errnop = NETDB_SUCCESS; + if (buffer_size == NULL) + *status = NSS_STATUS_SUCCESS; + else + *result = resbuf; + goto done; + } + + if (!isxdigit (*cp) && *cp != ':' && *cp != '.') + break; + } + } + } + + return 0; + +done: + return 1; +} +libc_hidden_def (__nss_hostname_digits_dots) diff --git a/REORG.TODO/nss/ethers-lookup.c b/REORG.TODO/nss/ethers-lookup.c new file mode 100644 index 0000000000..ae073dd7a7 --- /dev/null +++ b/REORG.TODO/nss/ethers-lookup.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME ethers + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/function.def b/REORG.TODO/nss/function.def new file mode 100644 index 0000000000..638fcc8126 --- /dev/null +++ b/REORG.TODO/nss/function.def @@ -0,0 +1,78 @@ +/* List of functions defined for static NSS in GNU C Library. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +/* + This is a minimal config. Only services `files' and `dns' are supported. +*/ + +/* aliases */ +DEFINE_ENT (files, alias) +DEFINE_GETBY (files, alias, name) + +/* ethers */ +DEFINE_ENT (files, ether) + +/* group */ +DEFINE_ENT (files, gr) +DEFINE_GET (files, grgid) +DEFINE_GET (files, grnam) + +/* hosts */ +DEFINE_ENT (files, host) +DEFINE_GETBY (files, host, addr) +DEFINE_GETBY (files, host, name) +DEFINE_GETBY (files, host, name2) +DEFINE_GET (files, hostton) +DEFINE_GET (files, ntohost) +DEFINE_GETBY (dns, host, addr) +DEFINE_GETBY (dns, host, name) +DEFINE_GETBY (dns, host, name2) + +/* netgroup */ +DEFINE_ENT (files, netgr) + +/* networks */ +DEFINE_ENT (files, net) +DEFINE_GETBY (files, net, name) +DEFINE_GETBY (files, net, addr) +DEFINE_GETBY (dns, net, name) +DEFINE_GETBY (dns, net, addr) + +/* protocols */ +DEFINE_ENT (files, proto) +DEFINE_GETBY (files, proto, name) +DEFINE_GETBY (files, proto, number) + +/* passwd */ +DEFINE_ENT (files, pw) +DEFINE_GET (files, pwnam) +DEFINE_GET (files, pwuid) + +/* rpc */ +DEFINE_ENT (files, rpc) +DEFINE_GETBY (files, rpc, name) +DEFINE_GETBY (files, rpc, number) + +/* services */ +DEFINE_ENT (files, serv) +DEFINE_GETBY (files, serv, name) +DEFINE_GETBY (files, serv, port) + +/* shadow */ +DEFINE_ENT (files, sp) +DEFINE_GET (files, spnam) diff --git a/REORG.TODO/nss/getXXbyYY.c b/REORG.TODO/nss/getXXbyYY.c new file mode 100644 index 0000000000..d027b14250 --- /dev/null +++ b/REORG.TODO/nss/getXXbyYY.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <libc-lock.h> +#include <stdlib.h> +#include <resolv.h> + +#include "nsswitch.h" + +/*******************************************************************\ +|* Here we assume several symbols to be defined: *| +|* *| +|* LOOKUP_TYPE - the return type of the function *| +|* *| +|* FUNCTION_NAME - name of the non-reentrant function *| +|* *| +|* DATABASE_NAME - name of the database the function accesses *| +|* (e.g., host, services, ...) *| +|* *| +|* ADD_PARAMS - additional parameter, can vary in number *| +|* *| +|* ADD_VARIABLES - names of additional parameter *| +|* *| +|* BUFLEN - length of buffer allocated for the non *| +|* reentrant version *| +|* *| +|* Optionally the following vars can be defined: *| +|* *| +|* NEED_H_ERRNO - an extra parameter will be passed to point to *| +|* the global `h_errno' variable. *| +|* *| +\*******************************************************************/ + +/* To make the real sources a bit prettier. */ +#define REENTRANT_NAME APPEND_R (FUNCTION_NAME) +#define APPEND_R(name) APPEND_R1 (name) +#define APPEND_R1(name) name##_r +#define INTERNAL(name) INTERNAL1 (name) +#define INTERNAL1(name) __##name + +/* Sometimes we need to store error codes in the `h_errno' variable. */ +#ifdef NEED_H_ERRNO +# define H_ERRNO_PARM , int *h_errnop +# define H_ERRNO_VAR , &h_errno_tmp +# define H_ERRNO_VAR_P &h_errno_tmp +#else +# define H_ERRNO_PARM +# define H_ERRNO_VAR +# define H_ERRNO_VAR_P NULL +#endif + +#ifdef HAVE_AF +# define AF_VAL af +#else +# define AF_VAL AF_INET +#endif + +/* Prototype for reentrant version we use here. */ +extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, + char *buffer, size_t buflen, + LOOKUP_TYPE **result H_ERRNO_PARM); + +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + +/* This points to the static buffer used. */ +libc_freeres_ptr (static char *buffer); + + +LOOKUP_TYPE * +FUNCTION_NAME (ADD_PARAMS) +{ + static size_t buffer_size; + static LOOKUP_TYPE resbuf; + LOOKUP_TYPE *result; +#ifdef NEED_H_ERRNO + int h_errno_tmp = 0; +#endif + + /* Get lock. */ + __libc_lock_lock (lock); + + if (buffer == NULL) + { + buffer_size = BUFLEN; + buffer = (char *) malloc (buffer_size); + } + +#ifdef HANDLE_DIGITS_DOTS + if (buffer != NULL) + { + if (__nss_hostname_digits_dots (name, &resbuf, &buffer, + &buffer_size, 0, &result, NULL, AF_VAL, + H_ERRNO_VAR_P)) + goto done; + } +#endif + + while (buffer != NULL + && (INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer, + buffer_size, &result H_ERRNO_VAR) + == ERANGE) +#ifdef NEED_H_ERRNO + && h_errno_tmp == NETDB_INTERNAL +#endif + ) + { + char *new_buf; + buffer_size *= 2; + new_buf = (char *) realloc (buffer, buffer_size); + if (new_buf == NULL) + { + /* We are out of memory. Free the current buffer so that the + process gets a chance for a normal termination. */ + free (buffer); + __set_errno (ENOMEM); + } + buffer = new_buf; + } + + if (buffer == NULL) + result = NULL; + +#ifdef HANDLE_DIGITS_DOTS +done: +#endif + /* Release lock. */ + __libc_lock_unlock (lock); + +#ifdef NEED_H_ERRNO + if (h_errno_tmp != 0) + __set_h_errno (h_errno_tmp); +#endif + + return result; +} + +nss_interface_function (FUNCTION_NAME) diff --git a/REORG.TODO/nss/getXXbyYY_r.c b/REORG.TODO/nss/getXXbyYY_r.c new file mode 100644 index 0000000000..5962475737 --- /dev/null +++ b/REORG.TODO/nss/getXXbyYY_r.c @@ -0,0 +1,465 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <atomic.h> +#include <errno.h> +#include <stdbool.h> +#include "nsswitch.h" +#include "sysdep.h" +#ifdef USE_NSCD +# include <nscd/nscd_proto.h> +#endif +#ifdef NEED__RES_HCONF +# include <resolv/res_hconf.h> +#endif +#ifdef NEED__RES +# include <resolv.h> +#endif +/*******************************************************************\ +|* Here we assume several symbols to be defined: *| +|* *| +|* LOOKUP_TYPE - the return type of the function *| +|* *| +|* FUNCTION_NAME - name of the non-reentrant function *| +|* *| +|* DATABASE_NAME - name of the database the function accesses *| +|* (e.g., host, services, ...) *| +|* *| +|* ADD_PARAMS - additional parameters, can vary in number *| +|* *| +|* ADD_VARIABLES - names of additional parameters *| +|* *| +|* Optionally the following vars can be defined: *| +|* *| +|* EXTRA_PARAMS - optional parameters, can vary in number *| +|* *| +|* EXTRA_VARIABLES - names of optional parameter *| +|* *| +|* FUNCTION2_NAME - alternative name of the non-reentrant function *| +|* *| +|* NEED_H_ERRNO - an extra parameter will be passed to point to *| +|* the global `h_errno' variable. *| +|* *| +|* NEED__RES - the global _res variable might be used so we *| +|* will have to initialize it if necessary *| +|* *| +|* PREPROCESS - code run before anything else *| +|* *| +|* POSTPROCESS - code run after the lookup *| +|* *| +\*******************************************************************/ + +/* To make the real sources a bit prettier. */ +#define REENTRANT_NAME APPEND_R (FUNCTION_NAME) +#ifdef FUNCTION2_NAME +# define REENTRANT2_NAME APPEND_R (FUNCTION2_NAME) +#else +# define REENTRANT2_NAME NULL +#endif +#define APPEND_R(name) APPEND_R1 (name) +#define APPEND_R1(name) name##_r +#define INTERNAL(name) INTERNAL1 (name) +#define INTERNAL1(name) __##name +#define NEW(name) NEW1 (name) +#define NEW1(name) __new_##name + +#ifdef USE_NSCD +# define NSCD_NAME ADD_NSCD (REENTRANT_NAME) +# define ADD_NSCD(name) ADD_NSCD1 (name) +# define ADD_NSCD1(name) __nscd_##name +# define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME) +# define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name) +# define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name +# define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2) +# define CONCAT2_2(arg1, arg2) arg1##arg2 +#endif + +#define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME) +#define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME) +#ifdef FUNCTION2_NAME +# define REENTRANT2_NAME_STRING STRINGIZE (REENTRANT2_NAME) +#else +# define REENTRANT2_NAME_STRING NULL +#endif +#define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME) +#define STRINGIZE(name) STRINGIZE1 (name) +#define STRINGIZE1(name) #name + +#ifndef DB_LOOKUP_FCT +# define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2) +# define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post) +# define CONCAT3_2(Pre, Name, Post) Pre##Name##Post +#endif + +/* Sometimes we need to store error codes in the `h_errno' variable. */ +#ifdef NEED_H_ERRNO +# define H_ERRNO_PARM , int *h_errnop +# define H_ERRNO_VAR , h_errnop +# define H_ERRNO_VAR_P h_errnop +#else +# define H_ERRNO_PARM +# define H_ERRNO_VAR +# define H_ERRNO_VAR_P NULL +#endif + +#ifndef EXTRA_PARAMS +# define EXTRA_PARAMS +#endif +#ifndef EXTRA_VARIABLES +# define EXTRA_VARIABLES +#endif + +#ifdef HAVE_AF +# define AF_VAL af +#else +# define AF_VAL AF_INET +#endif + + +/* Set defaults for merge functions that haven't been defined. */ +#ifndef DEEPCOPY_FN +static inline int +__copy_einval (LOOKUP_TYPE a, + const size_t b, + LOOKUP_TYPE *c, + char *d, + char **e) +{ + return EINVAL; +} +# define DEEPCOPY_FN __copy_einval +#endif + +#ifndef MERGE_FN +static inline int +__merge_einval (LOOKUP_TYPE *a, + char *b, + char *c, + size_t d, + LOOKUP_TYPE *e, + char *f) +{ + return EINVAL; +} +# define MERGE_FN __merge_einval +#endif + +#define CHECK_MERGE(err, status) \ + ({ \ + do \ + { \ + if (err) \ + { \ + __set_errno (err); \ + if (err == ERANGE) \ + status = NSS_STATUS_TRYAGAIN; \ + else \ + status = NSS_STATUS_UNAVAIL; \ + break; \ + } \ + } \ + while (0); \ + }) + +/* Type of the lookup function we need here. */ +typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, + size_t, int * H_ERRNO_PARM + EXTRA_PARAMS); + +/* The lookup function for the first entry of this service. */ +extern int DB_LOOKUP_FCT (service_user **nip, const char *name, + const char *name2, void **fctp) + internal_function; +libc_hidden_proto (DB_LOOKUP_FCT) + + +int +INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, + size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM + EXTRA_PARAMS) +{ + static bool startp_initialized; + static service_user *startp; + static lookup_function start_fct; + service_user *nip; + int do_merge = 0; + LOOKUP_TYPE mergegrp; + char *mergebuf = NULL; + char *endptr = NULL; + union + { + lookup_function l; + void *ptr; + } fct; + int no_more, err; + enum nss_status status = NSS_STATUS_UNAVAIL; +#ifdef USE_NSCD + int nscd_status; +#endif +#ifdef NEED_H_ERRNO + bool any_service = false; +#endif + +#ifdef PREPROCESS + PREPROCESS; +#endif + +#ifdef HANDLE_DIGITS_DOTS + switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL, + buflen, result, &status, AF_VAL, + H_ERRNO_VAR_P)) + { + case -1: + return errno; + case 1: +#ifdef NEED_H_ERRNO + any_service = true; +#endif + goto done; + } +#endif + +#ifdef USE_NSCD + if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY) + NOT_USENSCD_NAME = 0; + + if (!NOT_USENSCD_NAME + && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)]) + { + nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result + H_ERRNO_VAR); + if (nscd_status >= 0) + return nscd_status; + } +#endif + + if (! startp_initialized) + { + no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, + REENTRANT2_NAME_STRING, &fct.ptr); + if (no_more) + { + void *tmp_ptr = (service_user *) -1l; +#ifdef PTR_MANGLE + PTR_MANGLE (tmp_ptr); +#endif + startp = tmp_ptr; + } + else + { +#ifdef NEED__RES + /* The resolver code will really be used so we have to + initialize it. */ + if (__res_maybe_init (&_res, 0) == -1) + { + *h_errnop = NETDB_INTERNAL; + *result = NULL; + return errno; + } +#endif /* need _res */ +#ifdef NEED__RES_HCONF + _res_hconf_init (); +#endif /* need _res_hconf */ + + void *tmp_ptr = fct.l; +#ifdef PTR_MANGLE + PTR_MANGLE (tmp_ptr); +#endif + start_fct = tmp_ptr; + tmp_ptr = nip; +#ifdef PTR_MANGLE + PTR_MANGLE (tmp_ptr); +#endif + startp = tmp_ptr; + } + + /* Make sure start_fct and startp are written before + startp_initialized. */ + atomic_write_barrier (); + startp_initialized = true; + } + else + { + fct.l = start_fct; + nip = startp; +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (fct.l); + PTR_DEMANGLE (nip); +#endif + no_more = nip == (service_user *) -1l; + } + + while (no_more == 0) + { +#ifdef NEED_H_ERRNO + any_service = true; +#endif + + status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen, + &errno H_ERRNO_VAR EXTRA_VARIABLES)); + + /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the + provided buffer is too small. In this case we should give + the user the possibility to enlarge the buffer and we should + not simply go on with the next service (even if the TRYAGAIN + action tells us so). */ + if (status == NSS_STATUS_TRYAGAIN +#ifdef NEED_H_ERRNO + && *h_errnop == NETDB_INTERNAL +#endif + && errno == ERANGE) + break; + + if (do_merge) + { + + if (status == NSS_STATUS_SUCCESS) + { + /* The previous loop saved a buffer for merging. + Perform the merge now. */ + err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf, + buffer); + CHECK_MERGE (err,status); + do_merge = 0; + } + else + { + /* If the result wasn't SUCCESS, copy the saved buffer back + into the result buffer and set the status back to + NSS_STATUS_SUCCESS to match the previous pass through the + loop. + * If the next action is CONTINUE, it will overwrite the value + currently in the buffer and return the new value. + * If the next action is RETURN, we'll return the previously- + acquired values. + * If the next action is MERGE, then it will be added to the + buffer saved from the previous source. */ + err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL); + CHECK_MERGE (err, status); + status = NSS_STATUS_SUCCESS; + } + } + + /* If we were are configured to merge this value with the next one, + save the current value of the group struct. */ + if (nss_next_action (nip, status) == NSS_ACTION_MERGE + && status == NSS_STATUS_SUCCESS) + { + /* Copy the current values into a buffer to be merged with the next + set of retrieved values. */ + if (mergebuf == NULL) + { + /* Only allocate once and reuse it for as many merges as we need + to perform. */ + mergebuf = malloc (buflen); + if (mergebuf == NULL) + { + __set_errno (ENOMEM); + status = NSS_STATUS_UNAVAIL; + break; + } + } + + err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr); + CHECK_MERGE (err, status); + do_merge = 1; + } + + no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING, + REENTRANT2_NAME_STRING, &fct.ptr, status, 0); + } + free (mergebuf); + mergebuf = NULL; + +#ifdef HANDLE_DIGITS_DOTS +done: +#endif + *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL; +#ifdef NEED_H_ERRNO + if (status == NSS_STATUS_UNAVAIL && !any_service && errno != ENOENT) + /* This happens when we weren't able to use a service for reasons other + than the module not being found. In such a case, we'd want to tell the + caller that errno has the real reason for failure. */ + *h_errnop = NETDB_INTERNAL; + else if (status != NSS_STATUS_SUCCESS && !any_service) + /* We were not able to use any service. */ + *h_errnop = NO_RECOVERY; +#endif +#ifdef POSTPROCESS + POSTPROCESS; +#endif + + int res; + if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) + res = 0; + /* Don't pass back ERANGE if this is not for a too-small buffer. */ + else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN) + res = EINVAL; +#ifdef NEED_H_ERRNO + /* These functions only set errno if h_errno is NETDB_INTERNAL. */ + else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL) + res = EAGAIN; +#endif + else + return errno; + + __set_errno (res); + return res; +} + + +#ifdef NO_COMPAT_NEEDED +strong_alias (INTERNAL (REENTRANT_NAME), REENTRANT_NAME); +#elif !defined FUNCTION2_NAME +# include <shlib-compat.h> +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +# define OLD(name) OLD1 (name) +# define OLD1(name) __old_##name + +int +attribute_compat_text_section +OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, + size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM) +{ + int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer, + buflen, result H_ERRNO_VAR); + + if (ret != 0 || result == NULL) + ret = -1; + + return ret; +} + +# define do_symbol_version(real, name, version) \ + compat_symbol (libc, real, name, version) +do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0); +# endif + +/* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias + in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not + hidden too. */ +strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME)); + +# define do_default_symbol_version(real, name, version) \ + versioned_symbol (libc, real, name, version) +do_default_symbol_version (NEW (REENTRANT_NAME), + REENTRANT_NAME, GLIBC_2_1_2); +#endif + +nss_interface_function (REENTRANT_NAME) diff --git a/REORG.TODO/nss/getXXent.c b/REORG.TODO/nss/getXXent.c new file mode 100644 index 0000000000..aad374197f --- /dev/null +++ b/REORG.TODO/nss/getXXent.c @@ -0,0 +1,94 @@ +/* Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <libc-lock.h> +#include <stdlib.h> + +#include "nsswitch.h" + +/*******************************************************************\ +|* Here we assume several symbols to be defined: *| +|* *| +|* LOOKUP_TYPE - the return type of the function *| +|* *| +|* GETFUNC_NAME - name of the non-reentrant getXXXent function *| +|* *| +|* BUFLEN - size of static buffer *| +|* *| +|* Optionally the following vars can be defined: *| +|* *| +|* NEED_H_ERRNO - an extra parameter will be passed to point to *| +|* the global `h_errno' variable. *| +|* *| +\*******************************************************************/ + +/* To make the real sources a bit prettier. */ +#define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME) +#define APPEND_R(name) APPEND_R1 (name) +#define APPEND_R1(name) name##_r +#define INTERNAL(name) INTERNAL1 (name) +#define INTERNAL1(name) __##name + +/* Sometimes we need to store error codes in the `h_errno' variable. */ +#ifdef NEED_H_ERRNO +# define H_ERRNO_PARM , int *h_errnop +# define H_ERRNO_VAR &h_errno +#else +# define H_ERRNO_PARM +# define H_ERRNO_VAR NULL +#endif + +/* Prototype of the reentrant version. */ +extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, + size_t buflen, LOOKUP_TYPE **result + H_ERRNO_PARM); + +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + +/* This points to the static buffer used. */ +libc_freeres_ptr (static char *buffer); + + +LOOKUP_TYPE * +GETFUNC_NAME (void) +{ + static size_t buffer_size; + static union + { + LOOKUP_TYPE l; + void *ptr; + } resbuf; + LOOKUP_TYPE *result; + int save; + + /* Get lock. */ + __libc_lock_lock (lock); + + result = (LOOKUP_TYPE *) + __nss_getent ((getent_r_function) INTERNAL (REENTRANT_GETNAME), + &resbuf.ptr, &buffer, BUFLEN, &buffer_size, + H_ERRNO_VAR); + + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); + return result; +} + +nss_interface_function (GETFUNC_NAME) diff --git a/REORG.TODO/nss/getXXent_r.c b/REORG.TODO/nss/getXXent_r.c new file mode 100644 index 0000000000..2710c1cd51 --- /dev/null +++ b/REORG.TODO/nss/getXXent_r.c @@ -0,0 +1,212 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <libc-lock.h> + +#include "nsswitch.h" + +/*******************************************************************\ +|* Here we assume several symbols to be defined: *| +|* *| +|* LOOKUP_TYPE - the return type of the function *| +|* *| +|* SETFUNC_NAME - name of the non-reentrant setXXXent function *| +|* *| +|* GETFUNC_NAME - name of the non-reentrant getXXXent function *| +|* *| +|* ENDFUNC_NAME - name of the non-reentrant endXXXent function *| +|* *| +|* DATABASE_NAME - name of the database the function accesses *| +|* (e.g., host, services, ...) *| +|* *| +|* Optionally the following vars can be defined: *| +|* *| +|* STAYOPEN - variable declaration for setXXXent function *| +|* *| +|* STAYOPEN_VAR - variable name for setXXXent function *| +|* *| +|* NEED_H_ERRNO - an extra parameter will be passed to point to *| +|* the global `h_errno' variable. *| +|* *| +\*******************************************************************/ + +/* To make the real sources a bit prettier. */ +#define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME) +#define APPEND_R(Name) CONCAT2_2 (Name, _r) +#define INTERNAL(Name) CONCAT2_2 (__, Name) +#define CONCAT2_1(Pre, Post) CONCAT2_2 (Pre, Post) +#define CONCAT2_2(Pre, Post) Pre##Post +#define NEW(name) NEW1 (name) +#define NEW1(name) __new_##name + +#define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME) +#define GETFUNC_NAME_STRING STRINGIZE (REENTRANT_GETNAME) +#define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME) +#define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME) +#define STRINGIZE(Name) STRINGIZE1 (Name) +#define STRINGIZE1(Name) #Name + +#ifndef DB_LOOKUP_FCT +# define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2) +# define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post) +# define CONCAT3_2(Pre, Name, Post) Pre##Name##Post +#endif + +/* Sometimes we need to store error codes in the `h_errno' variable. */ +#ifdef NEED_H_ERRNO +# define H_ERRNO_PARM , int *h_errnop +# define H_ERRNO_VAR , &h_errno +# define H_ERRNO_VAR_P &h_errno +#else +# define H_ERRNO_PARM +# define H_ERRNO_VAR +# define H_ERRNO_VAR_P NULL +#endif + +/* Some databases take the `stayopen' flag. */ +#ifdef STAYOPEN +# define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp) +# define STAYOPEN_TMPVAR &CONCAT2_1 (STAYOPEN_VAR, _tmp) +#else +# define STAYOPEN void +# define STAYOPEN_VAR 0 +# define STAYOPEN_TMPVAR NULL +#endif + +#ifndef NEED__RES +# define NEED__RES 0 +#endif + +/* This handle for the NSS data base is shared between all + set/get/endXXXent functions. */ +static service_user *nip; +/* Remember the last service used since the last call to `endXXent'. */ +static service_user *last_nip; +/* Remember the first service_entry, it's always the same. */ +static service_user *startp; + +#ifdef STAYOPEN_TMP +/* We need to remember the last `stayopen' flag given by the user + since the `setent' function is only called for the first available + service. */ +static STAYOPEN_TMP; +#endif + +/* Protect above variable against multiple uses at the same time. */ +__libc_lock_define_initialized (static, lock) + +/* The lookup function for the first entry of this service. */ +extern int DB_LOOKUP_FCT (service_user **nip, const char *name, + const char *name2, void **fctp) + internal_function; +libc_hidden_proto (DB_LOOKUP_FCT) + +void +SETFUNC_NAME (STAYOPEN) +{ + int save; + + __libc_lock_lock (lock); + __nss_setent (SETFUNC_NAME_STRING, DB_LOOKUP_FCT, &nip, &startp, + &last_nip, STAYOPEN_VAR, STAYOPEN_TMPVAR, NEED__RES); + + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); +} + + +void +ENDFUNC_NAME (void) +{ + int save; + + /* If the service has not been used before do not do anything. */ + if (startp != NULL) + { + __libc_lock_lock (lock); + __nss_endent (ENDFUNC_NAME_STRING, DB_LOOKUP_FCT, &nip, &startp, + &last_nip, NEED__RES); + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); + } +} + + +int +INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen, + LOOKUP_TYPE **result H_ERRNO_PARM) +{ + int status; + int save; + + __libc_lock_lock (lock); + status = __nss_getent_r (GETFUNC_NAME_STRING, SETFUNC_NAME_STRING, + DB_LOOKUP_FCT, &nip, &startp, &last_nip, + STAYOPEN_TMPVAR, NEED__RES, resbuf, buffer, + buflen, (void **) result, H_ERRNO_VAR_P); + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); + return status; +} + + +#ifdef NO_COMPAT_NEEDED +strong_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME); +#else +# include <shlib-compat.h> +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +# define OLD(name) OLD1 (name) +# define OLD1(name) __old_##name + +int +attribute_compat_text_section +OLD (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen, + LOOKUP_TYPE **result H_ERRNO_PARM) +{ + int ret = INTERNAL (REENTRANT_GETNAME) (resbuf, buffer, buflen, + result H_ERRNO_VAR); + + if (ret != 0) + ret = -1; + + return ret; +} + +# define do_symbol_version(real, name, version) \ + compat_symbol (libc, real, name, version) +do_symbol_version (OLD (REENTRANT_GETNAME), REENTRANT_GETNAME, GLIBC_2_0); +# endif + +/* As INTERNAL (REENTRANT_GETNAME) may be hidden, we need an alias + in between so that the REENTRANT_GETNAME@@GLIBC_2.1.2 is not + hidden too. */ +strong_alias (INTERNAL (REENTRANT_GETNAME), NEW (REENTRANT_GETNAME)); + +# define do_default_symbol_version(real, name, version) \ + versioned_symbol (libc, real, name, version) +do_default_symbol_version (NEW (REENTRANT_GETNAME), + REENTRANT_GETNAME, GLIBC_2_1_2); +#endif + +nss_interface_function (SETFUNC_NAME) +nss_interface_function (ENDFUNC_NAME) +nss_interface_function (REENTRANT_GETNAME) diff --git a/REORG.TODO/nss/getent.c b/REORG.TODO/nss/getent.c new file mode 100644 index 0000000000..8f8c3fe80a --- /dev/null +++ b/REORG.TODO/nss/getent.c @@ -0,0 +1,960 @@ +/* Copyright (c) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 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 + <http://www.gnu.org/licenses/>. */ + +/* getent: get entries from administrative database. */ + +#include <aliases.h> +#include <argp.h> +#include <ctype.h> +#include <error.h> +#include <grp.h> +#include <gshadow.h> +#include <libintl.h> +#include <locale.h> +#include <mcheck.h> +#include <netdb.h> +#include <pwd.h> +#include <shadow.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <sys/socket.h> + +/* Get libc version number. */ +#include <version.h> + +#define PACKAGE _libc_intl_domainname + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Short description of parameters. */ +static const char args_doc[] = N_("database [key ...]"); + +/* Supported options. */ +static const struct argp_option args_options[] = + { + { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") }, + { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") }, + { NULL, 0, NULL, 0, NULL }, + }; + +/* Short description of program. */ +static const char doc[] = N_("Get entries from administrative database."); + +/* Prototype for option handler. */ +static error_t parse_option (int key, char *arg, struct argp_state *state); + +/* Function to print some extra text in the help message. */ +static char *more_help (int key, const char *text, void *input); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = + { + args_options, parse_option, args_doc, doc, NULL, more_help + }; + +/* Additional getaddrinfo flags for IDN encoding. */ +static int idn_flags = AI_IDN | AI_CANONIDN; + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "getent %s%s\n", PKGVERSION, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2017"); + fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk"); +} + +/* This is for aliases */ +static void +print_aliases (struct aliasent *alias) +{ + unsigned int i = 0; + + printf ("%s: ", alias->alias_name); + for (i = strlen (alias->alias_name); i < 14; ++i) + fputs_unlocked (" ", stdout); + + for (i = 0; i < alias->alias_members_len; ++i) + printf ("%s%s", + alias->alias_members [i], + i + 1 == alias->alias_members_len ? "\n" : ", "); +} + +static int +aliases_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct aliasent *alias; + + if (number == 0) + { + setaliasent (); + while ((alias = getaliasent ()) != NULL) + print_aliases (alias); + endaliasent (); + return result; + } + + for (i = 0; i < number; ++i) + { + alias = getaliasbyname (key[i]); + + if (alias == NULL) + result = 2; + else + print_aliases (alias); + } + + return result; +} + +/* This is for ethers */ +static int +ethers_keys (int number, char *key[]) +{ + int result = 0; + int i; + + if (number == 0) + { + fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers"); + return 3; + } + + for (i = 0; i < number; ++i) + { + struct ether_addr *ethp, eth; + char buffer [1024], *p; + + ethp = ether_aton (key[i]); + if (ethp != NULL) + { + if (ether_ntohost (buffer, ethp)) + { + result = 2; + continue; + } + p = buffer; + } + else + { + if (ether_hostton (key[i], ð)) + { + result = 2; + continue; + } + p = key[i]; + ethp = ð + } + printf ("%s %s\n", ether_ntoa (ethp), p); + } + + return result; +} + +/* This is for group */ +static void +print_group (struct group *grp) +{ + if (putgrent (grp, stdout) != 0) + fprintf (stderr, "error writing group entry: %m\n"); +} + +static int +group_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct group *grp; + + if (number == 0) + { + setgrent (); + while ((grp = getgrent ()) != NULL) + print_group (grp); + endgrent (); + return result; + } + + for (i = 0; i < number; ++i) + { + errno = 0; + char *ep; + gid_t arg_gid = strtoul(key[i], &ep, 10); + + if (errno != EINVAL && *key[i] != '\0' && *ep == '\0') + /* Valid numeric gid. */ + grp = getgrgid (arg_gid); + else + grp = getgrnam (key[i]); + + if (grp == NULL) + result = 2; + else + print_group (grp); + } + + return result; +} + +/* This is for gshadow */ +static void +print_gshadow (struct sgrp *sg) +{ + if (putsgent (sg, stdout) != 0) + fprintf (stderr, "error writing gshadow entry: %m\n"); +} + +static int +gshadow_keys (int number, char *key[]) +{ + int result = 0; + int i; + + if (number == 0) + { + struct sgrp *sg; + + setsgent (); + while ((sg = getsgent ()) != NULL) + print_gshadow (sg); + endsgent (); + return result; + } + + for (i = 0; i < number; ++i) + { + struct sgrp *sg; + + sg = getsgnam (key[i]); + + if (sg == NULL) + result = 2; + else + print_gshadow (sg); + } + + return result; +} + +/* This is for hosts */ +static void +print_hosts (struct hostent *host) +{ + unsigned int cnt; + + for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt) + { + char buf[INET6_ADDRSTRLEN]; + const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt], + buf, sizeof (buf)); + + printf ("%-15s %s", ip, host->h_name); + + unsigned int i; + for (i = 0; host->h_aliases[i] != NULL; ++i) + { + putchar_unlocked (' '); + fputs_unlocked (host->h_aliases[i], stdout); + } + putchar_unlocked ('\n'); + } +} + +static int +hosts_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct hostent *host; + + if (number == 0) + { + sethostent (0); + while ((host = gethostent ()) != NULL) + print_hosts (host); + endhostent (); + return result; + } + + for (i = 0; i < number; ++i) + { + struct hostent *host = NULL; + char addr[IN6ADDRSZ]; + + if (inet_pton (AF_INET6, key[i], &addr) > 0) + host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6); + else if (inet_pton (AF_INET, key[i], &addr) > 0) + host = gethostbyaddr (addr, INADDRSZ, AF_INET); + else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL) + host = gethostbyname2 (key[i], AF_INET); + + if (host == NULL) + result = 2; + else + print_hosts (host); + } + + return result; +} + +/* This is for hosts, but using getaddrinfo */ +static int +ahosts_keys_int (int af, int xflags, int number, char *key[]) +{ + int result = 0; + int i; + struct hostent *host; + + if (number == 0) + { + sethostent (0); + while ((host = gethostent ()) != NULL) + print_hosts (host); + endhostent (); + return result; + } + + struct addrinfo hint; + memset (&hint, '\0', sizeof (hint)); + hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME + | idn_flags | xflags); + hint.ai_family = af; + + for (i = 0; i < number; ++i) + { + struct addrinfo *res; + + if (getaddrinfo (key[i], NULL, &hint, &res) != 0) + result = 2; + else + { + struct addrinfo *runp = res; + + while (runp != NULL) + { + char sockbuf[20]; + const char *sockstr; + if (runp->ai_socktype == SOCK_STREAM) + sockstr = "STREAM"; + else if (runp->ai_socktype == SOCK_DGRAM) + sockstr = "DGRAM"; + else if (runp->ai_socktype == SOCK_RAW) + sockstr = "RAW"; +#ifdef SOCK_SEQPACKET + else if (runp->ai_socktype == SOCK_SEQPACKET) + sockstr = "SEQPACKET"; +#endif +#ifdef SOCK_RDM + else if (runp->ai_socktype == SOCK_RDM) + sockstr = "RDM"; +#endif +#ifdef SOCK_DCCP + else if (runp->ai_socktype == SOCK_DCCP) + sockstr = "DCCP"; +#endif +#ifdef SOCK_PACKET + else if (runp->ai_socktype == SOCK_PACKET) + sockstr = "PACKET"; +#endif + else + { + snprintf (sockbuf, sizeof (sockbuf), "%d", + runp->ai_socktype); + sockstr = sockbuf; + } + + char buf[INET6_ADDRSTRLEN]; + printf ("%-15s %-6s %s\n", + inet_ntop (runp->ai_family, + runp->ai_family == AF_INET + ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr + : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr, + buf, sizeof (buf)), + sockstr, + runp->ai_canonname ?: ""); + + runp = runp->ai_next; + } + + freeaddrinfo (res); + } + } + + return result; +} + +static int +ahosts_keys (int number, char *key[]) +{ + return ahosts_keys_int (AF_UNSPEC, 0, number, key); +} + +static int +ahostsv4_keys (int number, char *key[]) +{ + return ahosts_keys_int (AF_INET, 0, number, key); +} + +static int +ahostsv6_keys (int number, char *key[]) +{ + return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key); +} + +/* This is for netgroup */ +static int +netgroup_keys (int number, char *key[]) +{ + int result = 0; + + if (number == 0) + { + fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup"); + return 3; + } + + if (number == 4) + { + char *host = strcmp (key[1], "*") == 0 ? NULL : key[1]; + char *user = strcmp (key[2], "*") == 0 ? NULL : key[2]; + char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3]; + + printf ("%-21s (%s,%s,%s) = %d\n", + key[0], host ?: "", user ?: "", domain ?: "", + innetgr (key[0], host, user, domain)); + } + else if (number == 1) + { + if (!setnetgrent (key[0])) + result = 2; + else + { + char *p[3]; + + printf ("%-21s", key[0]); + + while (getnetgrent (p, p + 1, p + 2)) + printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: ""); + putchar_unlocked ('\n'); + } + } + + endnetgrent (); + + return result; +} + +/* This is for initgroups */ +static int +initgroups_keys (int number, char *key[]) +{ + int ngrps = 100; + size_t grpslen = ngrps * sizeof (gid_t); + gid_t *grps = alloca (grpslen); + + if (number == 0) + { + fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups"); + return 3; + } + + for (int i = 0; i < number; ++i) + { + int no = ngrps; + int n; + while ((n = getgrouplist (key[i], -1, grps, &no)) == -1 + && no > ngrps) + { + grps = extend_alloca (grps, grpslen, no * sizeof (gid_t)); + ngrps = no; + } + + if (n == -1) + return 1; + + printf ("%-21s", key[i]); + for (int j = 0; j < n; ++j) + if (grps[j] != -1) + printf (" %ld", (long int) grps[j]); + putchar_unlocked ('\n'); + } + + return 0; +} + +/* This is for networks */ +static void +print_networks (struct netent *net) +{ + unsigned int i; + struct in_addr ip; + ip.s_addr = htonl (net->n_net); + + printf ("%-21s %s", net->n_name, inet_ntoa (ip)); + + i = 0; + while (net->n_aliases[i] != NULL) + { + putchar_unlocked (' '); + fputs_unlocked (net->n_aliases[i], stdout); + ++i; + } + putchar_unlocked ('\n'); +} + +static int +networks_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct netent *net; + + if (number == 0) + { + setnetent (0); + while ((net = getnetent ()) != NULL) + print_networks (net); + endnetent (); + return result; + } + + for (i = 0; i < number; ++i) + { + if (isdigit (key[i][0])) + net = getnetbyaddr (ntohl (inet_addr (key[i])), AF_UNSPEC); + else + net = getnetbyname (key[i]); + + if (net == NULL) + result = 2; + else + print_networks (net); + } + + return result; +} + +/* Now is all for passwd */ +static void +print_passwd (struct passwd *pwd) +{ + if (putpwent (pwd, stdout) != 0) + fprintf (stderr, "error writing passwd entry: %m\n"); +} + +static int +passwd_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct passwd *pwd; + + if (number == 0) + { + setpwent (); + while ((pwd = getpwent ()) != NULL) + print_passwd (pwd); + endpwent (); + return result; + } + + for (i = 0; i < number; ++i) + { + errno = 0; + char *ep; + uid_t arg_uid = strtoul(key[i], &ep, 10); + + if (errno != EINVAL && *key[i] != '\0' && *ep == '\0') + /* Valid numeric uid. */ + pwd = getpwuid (arg_uid); + else + pwd = getpwnam (key[i]); + + if (pwd == NULL) + result = 2; + else + print_passwd (pwd); + } + + return result; +} + +/* This is for protocols */ +static void +print_protocols (struct protoent *proto) +{ + unsigned int i; + + printf ("%-21s %d", proto->p_name, proto->p_proto); + + i = 0; + while (proto->p_aliases[i] != NULL) + { + putchar_unlocked (' '); + fputs_unlocked (proto->p_aliases[i], stdout); + ++i; + } + putchar_unlocked ('\n'); +} + +static int +protocols_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct protoent *proto; + + if (number == 0) + { + setprotoent (0); + while ((proto = getprotoent ()) != NULL) + print_protocols (proto); + endprotoent (); + return result; + } + + for (i = 0; i < number; ++i) + { + if (isdigit (key[i][0])) + proto = getprotobynumber (atol (key[i])); + else + proto = getprotobyname (key[i]); + + if (proto == NULL) + result = 2; + else + print_protocols (proto); + } + + return result; +} + +#if HAVE_SUNRPC +/* Now is all for rpc */ +static void +print_rpc (struct rpcent *rpc) +{ + int i; + + printf ("%-15s %d%s", + rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : ""); + + for (i = 0; rpc->r_aliases[i]; ++i) + printf (" %s", rpc->r_aliases[i]); + putchar_unlocked ('\n'); +} + +static int +rpc_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct rpcent *rpc; + + if (number == 0) + { + setrpcent (0); + while ((rpc = getrpcent ()) != NULL) + print_rpc (rpc); + endrpcent (); + return result; + } + + for (i = 0; i < number; ++i) + { + if (isdigit (key[i][0])) + rpc = getrpcbynumber (atol (key[i])); + else + rpc = getrpcbyname (key[i]); + + if (rpc == NULL) + result = 2; + else + print_rpc (rpc); + } + + return result; +} +#endif + +/* for services */ +static void +print_services (struct servent *serv) +{ + unsigned int i; + + printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto); + + i = 0; + while (serv->s_aliases[i] != NULL) + { + putchar_unlocked (' '); + fputs_unlocked (serv->s_aliases[i], stdout); + ++i; + } + putchar_unlocked ('\n'); +} + +static int +services_keys (int number, char *key[]) +{ + int result = 0; + int i; + struct servent *serv; + + if (!number) + { + setservent (0); + while ((serv = getservent ()) != NULL) + print_services (serv); + endservent (); + return result; + } + + for (i = 0; i < number; ++i) + { + struct servent *serv; + char *proto = strchr (key[i], '/'); + + if (proto != NULL) + *proto++ = '\0'; + + char *endptr; + long port = strtol (key[i], &endptr, 10); + + if (isdigit (key[i][0]) && *endptr == '\0' + && 0 <= port && port <= 65535) + serv = getservbyport (htons (port), proto); + else + serv = getservbyname (key[i], proto); + + if (serv == NULL) + result = 2; + else + print_services (serv); + } + + return result; +} + +/* This is for shadow */ +static void +print_shadow (struct spwd *sp) +{ + if (putspent (sp, stdout) != 0) + fprintf (stderr, "error writing shadow entry: %m\n"); +} + +static int +shadow_keys (int number, char *key[]) +{ + int result = 0; + int i; + + if (number == 0) + { + struct spwd *sp; + + setspent (); + while ((sp = getspent ()) != NULL) + print_shadow (sp); + endspent (); + return result; + } + + for (i = 0; i < number; ++i) + { + struct spwd *sp; + + sp = getspnam (key[i]); + + if (sp == NULL) + result = 2; + else + print_shadow (sp); + } + + return result; +} + +struct + { + const char *name; + int (*func) (int number, char *key[]); + } databases[] = + { +#define D(name) { #name, name ## _keys }, +D(ahosts) +D(ahostsv4) +D(ahostsv6) +D(aliases) +D(ethers) +D(group) +D(gshadow) +D(hosts) +D(initgroups) +D(netgroup) +D(networks) +D(passwd) +D(protocols) +#if HAVE_SUNRPC +D(rpc) +#endif +D(services) +D(shadow) +#undef D + { NULL, NULL } + }; + +/* Handle arguments found by argp. */ +static error_t +parse_option (int key, char *arg, struct argp_state *state) +{ + char *endp; + switch (key) + { + case 's': + endp = strchr (arg, ':'); + if (endp == NULL) + /* No specific database, change them all. */ + for (int i = 0; databases[i].name != NULL; ++i) + __nss_configure_lookup (databases[i].name, arg); + else + { + int i; + for (i = 0; databases[i].name != NULL; ++i) + if (strncmp (databases[i].name, arg, endp - arg) == 0) + { + __nss_configure_lookup (databases[i].name, endp + 1); + break; + } + if (databases[i].name == NULL) + error (EXIT_FAILURE, 0, gettext ("Unknown database name")); + } + break; + + case 'i': + idn_flags = 0; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + + +static char * +more_help (int key, const char *text, void *input) +{ + switch (key) + { + size_t len; + char *doc; + FILE *fp; + + case ARGP_KEY_HELP_EXTRA: + /* We print some extra information. */ + fp = open_memstream (&doc, &len); + if (fp != NULL) + { + fputs_unlocked (_("Supported databases:\n"), fp); + + for (int i = 0, col = 0; databases[i].name != NULL; ++i) + { + len = strlen (databases[i].name); + if (i != 0) + { + if (col + len > 72) + { + col = 0; + fputc_unlocked ('\n', fp); + } + else + fputc_unlocked (' ', fp); + } + + fputs_unlocked (databases[i].name, fp); + col += len + 1; + } + + fputs ("\n\n", fp); + + fprintf (fp, gettext ("\ +For bug reporting instructions, please see:\n\ +%s.\n"), REPORT_BUGS_TO); + + if (fclose (fp) == 0) + return doc; + } + break; + + default: + break; + } + return (char *) text; +} + + +/* the main function */ +int +main (int argc, char *argv[]) +{ + /* Debugging support. */ + mtrace (); + + /* Set locale via LC_ALL. */ + setlocale (LC_ALL, ""); + /* Set the text message domain. */ + textdomain (PACKAGE); + + /* Parse and process arguments. */ + int remaining; + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + if ((argc - remaining) < 1) + { + error (0, 0, gettext ("wrong number of arguments")); + argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name); + return 1; + } + + for (int i = 0; databases[i].name; ++i) + if (argv[remaining][0] == databases[i].name[0] + && !strcmp (argv[remaining], databases[i].name)) + return databases[i].func (argc - remaining - 1, &argv[remaining + 1]); + + fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]); + argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name); + return 1; +} diff --git a/REORG.TODO/nss/getnssent.c b/REORG.TODO/nss/getnssent.c new file mode 100644 index 0000000000..fdaeed1e7b --- /dev/null +++ b/REORG.TODO/nss/getnssent.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2000-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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <netdb.h> +#include "nsswitch.h" + +void * +__nss_getent (getent_r_function func, void **resbuf, char **buffer, + size_t buflen, size_t *buffer_size, int *h_errnop) +{ + void *result; + + if (*buffer == NULL) + { + *buffer_size = buflen; + *buffer = malloc (*buffer_size); + } + + while (*buffer != NULL + && func (resbuf, *buffer, *buffer_size, &result, h_errnop) == ERANGE + && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)) + { + char *new_buf; + *buffer_size *= 2; + new_buf = realloc (*buffer, *buffer_size); + if (new_buf == NULL) + { + /* We are out of memory. Free the current buffer so that the + process gets a chance for a normal termination. */ + int save = errno; + free (*buffer); + __set_errno (save); + } + *buffer = new_buf; + } + + if (*buffer == NULL) + result = NULL; + + return result; +} diff --git a/REORG.TODO/nss/getnssent_r.c b/REORG.TODO/nss/getnssent_r.c new file mode 100644 index 0000000000..5fdbf3be00 --- /dev/null +++ b/REORG.TODO/nss/getnssent_r.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2000-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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <netdb.h> +#include "nsswitch.h" + +/* Set up NIP to run through the services. If ALL is zero, use NIP's + current location if it's not nil. Return nonzero if there are no + services (left). */ +static int +setup (const char *func_name, db_lookup_function lookup_fct, + void **fctp, service_user **nip, service_user **startp, int all) +{ + int no_more; + if (*startp == NULL) + { + no_more = lookup_fct (nip, func_name, NULL, fctp); + *startp = no_more ? (service_user *) -1l : *nip; + } + else if (*startp == (service_user *) -1l) + /* No services at all. */ + return 1; + else + { + if (all || !*nip) + /* Reset to the beginning of the service list. */ + *nip = *startp; + /* Look up the first function. */ + no_more = __nss_lookup (nip, func_name, NULL, fctp); + } + return no_more; +} + +void +__nss_setent (const char *func_name, db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int stayopen, int *stayopen_tmp, + int res) +{ + union + { + setent_function f; + void *ptr; + } fct; + int no_more; + + if (res && __res_maybe_init (&_res, 0) == -1) + { + __set_h_errno (NETDB_INTERNAL); + return; + } + + /* Cycle through the services and run their `setXXent' functions until + we find an available service. */ + no_more = setup (func_name, lookup_fct, &fct.ptr, nip, + startp, 1); + while (! no_more) + { + int is_last_nip = *nip == *last_nip; + enum nss_status status; + + if (stayopen_tmp) + status = DL_CALL_FCT (fct.f, (*stayopen_tmp)); + else + status = DL_CALL_FCT (fct.f, (0)); + + + /* This is a special-case. When [SUCCESS=merge] is in play, + _nss_next2() will skip to the next database. Due to the + implementation of that function, we can't know whether we're + in an enumeration or an individual lookup, which behaves + differently with regards to merging. We'll treat SUCCESS as + an indication to start the enumeration at this database. */ + if (nss_next_action (*nip, status) == NSS_ACTION_MERGE) + no_more = 1; + else + no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0); + + if (is_last_nip) + *last_nip = *nip; + } + + if (stayopen_tmp) + *stayopen_tmp = stayopen; +} + + +void +__nss_endent (const char *func_name, db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int res) +{ + union + { + endent_function f; + void *ptr; + } fct; + int no_more; + + if (res && __res_maybe_init (&_res, 0) == -1) + { + __set_h_errno (NETDB_INTERNAL); + return; + } + + /* Cycle through all the services and run their endXXent functions. */ + no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1); + while (! no_more) + { + /* Ignore status, we force check in __NSS_NEXT. */ + DL_CALL_FCT (fct.f, ()); + + if (*nip == *last_nip) + /* We have processed all services which were used. */ + break; + + no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1); + } + *last_nip = *nip = NULL; +} + + +int +__nss_getent_r (const char *getent_func_name, + const char *setent_func_name, + db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int *stayopen_tmp, int res, + void *resbuf, char *buffer, size_t buflen, + void **result, int *h_errnop) +{ + union + { + getent_function f; + void *ptr; + } fct; + int no_more; + enum nss_status status; + + if (res && __res_maybe_init (&_res, 0) == -1) + { + *h_errnop = NETDB_INTERNAL; + *result = NULL; + return errno; + } + + /* Initialize status to return if no more functions are found. */ + status = NSS_STATUS_NOTFOUND; + + /* Run through available functions, starting with the same function last + run. We will repeat each function as long as it succeeds, and then go + on to the next service action. */ + no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip, + startp, 0); + while (! no_more) + { + int is_last_nip = *nip == *last_nip; + + status = DL_CALL_FCT (fct.f, + (resbuf, buffer, buflen, &errno, &h_errno)); + + /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the + provided buffer is too small. In this case we should give + the user the possibility to enlarge the buffer and we should + not simply go on with the next service (even if the TRYAGAIN + action tells us so). */ + if (status == NSS_STATUS_TRYAGAIN + && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) + && errno == ERANGE) + break; + + do + { + /* This is a special-case. When [SUCCESS=merge] is in play, + _nss_next2() will skip to the next database. Due to the + implementation of that function, we can't know whether we're + in an enumeration or an individual lookup, which behaves + differently with regards to merging. We'll treat SUCCESS as + an indication to return the results here. */ + if (status == NSS_STATUS_SUCCESS + && nss_next_action (*nip, status) == NSS_ACTION_MERGE) + no_more = 1; + else + no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr, + status, 0); + + if (is_last_nip) + *last_nip = *nip; + + if (! no_more) + { + /* Call the `setXXent' function. This wasn't done before. */ + union + { + setent_function f; + void *ptr; + } sfct; + + no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr); + + if (! no_more) + { + if (stayopen_tmp) + status = DL_CALL_FCT (sfct.f, (*stayopen_tmp)); + else + status = DL_CALL_FCT (sfct.f, (0)); + } + else + status = NSS_STATUS_NOTFOUND; + } + } + while (! no_more && status != NSS_STATUS_SUCCESS); + } + + *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL; + return (status == NSS_STATUS_SUCCESS ? 0 + : status != NSS_STATUS_TRYAGAIN ? ENOENT + /* h_errno functions only set errno if h_errno is NETDB_INTERNAL. */ + : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno + : EAGAIN); +} diff --git a/REORG.TODO/nss/grp-lookup.c b/REORG.TODO/nss/grp-lookup.c new file mode 100644 index 0000000000..8cb00aa22f --- /dev/null +++ b/REORG.TODO/nss/grp-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME group +#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/hosts-lookup.c b/REORG.TODO/nss/hosts-lookup.c new file mode 100644 index 0000000000..9fdf958a97 --- /dev/null +++ b/REORG.TODO/nss/hosts-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME hosts +#define DEFAULT_CONFIG "dns [!UNAVAIL=return] files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/key-lookup.c b/REORG.TODO/nss/key-lookup.c new file mode 100644 index 0000000000..cce0ddf1e7 --- /dev/null +++ b/REORG.TODO/nss/key-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME publickey +#define DEFAULT_CONFIG "nis nisplus" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/makedb.c b/REORG.TODO/nss/makedb.c new file mode 100644 index 0000000000..542244dd35 --- /dev/null +++ b/REORG.TODO/nss/makedb.c @@ -0,0 +1,879 @@ +/* Create simple DB database from textual input. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <argp.h> +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <inttypes.h> +#include <libintl.h> +#include <locale.h> +#include <search.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include "nss_db/nss_db.h" + +/* Get libc version number. */ +#include "../version.h" + +/* The hashing function we use. */ +#include "../intl/hash-string.h" + +/* SELinux support. */ +#ifdef HAVE_SELINUX +# include <selinux/selinux.h> +#endif + +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +#define PACKAGE _libc_intl_domainname + +/* List of data bases. */ +struct database +{ + char dbid; + bool extra_string; + struct database *next; + void *entries; + size_t nentries; + size_t nhashentries; + stridx_t *hashtable; + size_t keystrlen; + stridx_t *keyidxtab; + char *keystrtab; +} *databases; +static size_t ndatabases; +static size_t nhashentries_total; +static size_t valstrlen; +static void *valstrtree; +static char *valstrtab; +static size_t extrastrlen; + +/* Database entry. */ +struct dbentry +{ + stridx_t validx; + uint32_t hashval; + char str[0]; +}; + +/* Stored string entry. */ +struct valstrentry +{ + stridx_t idx; + bool extra_string; + char str[0]; +}; + + +/* True if any entry has been added. */ +static bool any_dbentry; + +/* If non-zero convert key to lower case. */ +static int to_lowercase; + +/* If non-zero print content of input file, one entry per line. */ +static int do_undo; + +/* If non-zero do not print informational messages. */ +static int be_quiet; + +/* Name of output file. */ +static const char *output_name; + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") }, + { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") }, + { "quiet", 'q', NULL, 0, + N_("Do not print messages while building database") }, + { "undo", 'u', NULL, 0, + N_("Print content of database file, one entry a line") }, + { "generated", 'g', N_("CHAR"), 0, + N_("Generated line not part of iteration") }, + { NULL, 0, NULL, 0, NULL } +}; + +/* Short description of program. */ +static const char doc[] = N_("Create simple database from textual input."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("\ +INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Function to print some extra text in the help message. */ +static char *more_help (int key, const char *text, void *input); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, more_help +}; + + +/* List of databases which are not part of the iteration table. */ +static struct db_option +{ + char dbid; + struct db_option *next; +} *db_options; + + +/* Prototypes for local functions. */ +static int process_input (FILE *input, const char *inname, + int to_lowercase, int be_quiet); +static int print_database (int fd); +static void compute_tables (void); +static int write_output (int fd); + +/* SELinux support. */ +#ifdef HAVE_SELINUX +/* Set the SELinux file creation context for the given file. */ +static void set_file_creation_context (const char *outname, mode_t mode); +static void reset_file_creation_context (void); +#else +# define set_file_creation_context(_outname,_mode) +# define reset_file_creation_context() +#endif + + +/* External functions. */ +#include <programs/xmalloc.h> + + +int +main (int argc, char *argv[]) +{ + const char *input_name; + FILE *input_file; + int remaining; + int mode = 0644; + + /* Set locale via LC_ALL. */ + setlocale (LC_ALL, ""); + + /* Set the text message domain. */ + textdomain (_libc_intl_domainname); + + /* Initialize local variables. */ + input_name = NULL; + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Determine file names. */ + if (do_undo || output_name != NULL) + { + if (remaining + 1 != argc) + { + wrong_arguments: + error (0, 0, gettext ("wrong number of arguments")); + argp_help (&argp, stdout, ARGP_HELP_SEE, + program_invocation_short_name); + exit (1); + } + input_name = argv[remaining]; + } + else + { + if (remaining + 2 != argc) + goto wrong_arguments; + + input_name = argv[remaining++]; + output_name = argv[remaining]; + } + + /* Special handling if we are asked to print the database. */ + if (do_undo) + { + int fd = open (input_name, O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"), + input_name); + + int status = print_database (fd); + + close (fd); + + return status; + } + + /* Open input file. */ + if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0) + input_file = stdin; + else + { + struct stat64 st; + + input_file = fopen64 (input_name, "r"); + if (input_file == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"), + input_name); + + /* Get the access rights from the source file. The output file should + have the same. */ + if (fstat64 (fileno (input_file), &st) >= 0) + mode = st.st_mode & ACCESSPERMS; + } + + /* Start the real work. */ + int status = process_input (input_file, input_name, to_lowercase, be_quiet); + + /* Close files. */ + if (input_file != stdin) + fclose (input_file); + + /* No need to continue when we did not read the file successfully. */ + if (status != EXIT_SUCCESS) + return status; + + /* Bail out if nothing is to be done. */ + if (!any_dbentry) + { + if (be_quiet) + return EXIT_SUCCESS; + else + error (EXIT_SUCCESS, 0, gettext ("no entries to be processed")); + } + + /* Compute hash and string tables. */ + compute_tables (); + + /* Open output file. This must not be standard output so we don't + handle "-" and "/dev/stdout" special. */ + char *tmp_output_name; + if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1) + error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name")); + + set_file_creation_context (output_name, mode); + int fd = mkstemp (tmp_output_name); + reset_file_creation_context (); + if (fd == -1) + error (EXIT_FAILURE, errno, gettext ("cannot create temporary file")); + + status = write_output (fd); + + if (status == EXIT_SUCCESS) + { + struct stat64 st; + + if (fstat64 (fd, &st) == 0) + { + if ((st.st_mode & ACCESSPERMS) != mode) + /* We ignore problems with changing the mode. */ + fchmod (fd, mode); + } + else + { + error (0, errno, gettext ("cannot stat newly created file")); + status = EXIT_FAILURE; + } + } + + close (fd); + + if (status == EXIT_SUCCESS) + { + if (rename (tmp_output_name, output_name) != 0) + { + error (0, errno, gettext ("cannot rename temporary file")); + status = EXIT_FAILURE; + goto do_unlink; + } + } + else + do_unlink: + unlink (tmp_output_name); + + return status; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + struct db_option *newp; + + switch (key) + { + case 'f': + to_lowercase = 1; + break; + case 'o': + output_name = arg; + break; + case 'q': + be_quiet = 1; + break; + case 'u': + do_undo = 1; + break; + case 'g': + newp = xmalloc (sizeof (*newp)); + newp->dbid = arg[0]; + newp->next = db_options; + db_options = newp; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static char * +more_help (int key, const char *text, void *input) +{ + char *tp = NULL; + switch (key) + { + case ARGP_KEY_HELP_EXTRA: + /* We print some extra information. */ + if (asprintf (&tp, gettext ("\ +For bug reporting instructions, please see:\n\ +%s.\n"), REPORT_BUGS_TO) < 0) + return NULL; + return tp; + default: + break; + } + return (char *) text; +} + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "makedb %s%s\n", PKGVERSION, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2017"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +static int +dbentry_compare (const void *p1, const void *p2) +{ + const struct dbentry *d1 = (const struct dbentry *) p1; + const struct dbentry *d2 = (const struct dbentry *) p2; + + if (d1->hashval != d2->hashval) + return d1->hashval < d2->hashval ? -1 : 1; + + return strcmp (d1->str, d2->str); +} + + +static int +valstr_compare (const void *p1, const void *p2) +{ + const struct valstrentry *d1 = (const struct valstrentry *) p1; + const struct valstrentry *d2 = (const struct valstrentry *) p2; + + return strcmp (d1->str, d2->str); +} + + +static int +process_input (FILE *input, const char *inname, int to_lowercase, int be_quiet) +{ + char *line; + size_t linelen; + int status; + size_t linenr; + + line = NULL; + linelen = 0; + status = EXIT_SUCCESS; + linenr = 0; + + struct database *last_database = NULL; + + while (!feof_unlocked (input)) + { + ssize_t n = getline (&line, &linelen, input); + if (n < 0) + /* This means end of file or some bug. */ + break; + if (n == 0) + /* Short read. Probably interrupted system call. */ + continue; + + ++linenr; + + if (line[n - 1] == '\n') + /* Remove trailing newline. */ + line[--n] = '\0'; + + char *cp = line; + while (isspace (*cp)) + ++cp; + + if (*cp == '#' || *cp == '\0') + /* First non-space character in line '#': it's a comment. + Also go to the next line if it is empty except for whitespaces. */ + continue; + + /* Skip over the character indicating the database so that it is not + affected by TO_LOWERCASE. */ + char *key = cp++; + while (*cp != '\0' && !isspace (*cp)) + { + if (to_lowercase) + *cp = tolower (*cp); + ++cp; + } + + if (*cp == '\0') + /* It's a line without a value field. */ + continue; + + *cp++ = '\0'; + size_t keylen = cp - key; + + while (isspace (*cp)) + ++cp; + + char *data = cp; + size_t datalen = (&line[n] - cp) + 1; + + /* Find the database. */ + if (last_database == NULL || last_database->dbid != key[0]) + { + last_database = databases; + while (last_database != NULL && last_database->dbid != key[0]) + last_database = last_database->next; + + if (last_database == NULL) + { + last_database = xmalloc (sizeof (*last_database)); + last_database->dbid = key[0]; + last_database->extra_string = false; + last_database->next = databases; + last_database->entries = NULL; + last_database->nentries = 0; + last_database->keystrlen = 0; + databases = last_database; + + struct db_option *runp = db_options; + while (runp != NULL) + if (runp->dbid == key[0]) + { + last_database->extra_string = true; + break; + } + else + runp = runp->next; + } + } + + /* Skip the database selector. */ + ++key; + --keylen; + + /* Store the data. */ + struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry) + + datalen); + if (last_database->extra_string) + nentry->idx = extrastrlen; + else + nentry->idx = valstrlen; + nentry->extra_string = last_database->extra_string; + memcpy (nentry->str, data, datalen); + + struct valstrentry **fdata = tsearch (nentry, &valstrtree, + valstr_compare); + if (fdata == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot create search tree")); + + if (*fdata != nentry) + { + /* We can reuse a string. */ + free (nentry); + nentry = *fdata; + } + else + if (last_database->extra_string) + extrastrlen += datalen; + else + valstrlen += datalen; + + /* Store the key. */ + struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen); + newp->validx = nentry->idx; + newp->hashval = __hash_string (key); + memcpy (newp->str, key, keylen); + + struct dbentry **found = tsearch (newp, &last_database->entries, + dbentry_compare); + if (found == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot create search tree")); + + if (*found != newp) + { + free (newp); + if (!be_quiet) + error_at_line (0, 0, inname, linenr, gettext ("duplicate key")); + continue; + } + + ++last_database->nentries; + last_database->keystrlen += keylen; + + any_dbentry = true; + } + + if (ferror_unlocked (input)) + { + error (0, 0, gettext ("problems while reading `%s'"), inname); + status = EXIT_FAILURE; + } + + return status; +} + + +static void +copy_valstr (const void *nodep, const VISIT which, const int depth) +{ + if (which != leaf && which != postorder) + return; + + const struct valstrentry *p = *(const struct valstrentry **) nodep; + + strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str); +} + + +/* Determine if the candidate is prime by using a modified trial division + algorithm. The candidate must be both odd and greater than 4. */ +static int +is_prime (size_t candidate) +{ + size_t divn = 3; + size_t sq = divn * divn; + + assert (candidate > 4 && candidate % 2 != 0); + + while (sq < candidate && candidate % divn != 0) + { + ++divn; + sq += 4 * divn; + ++divn; + } + + return candidate % divn != 0; +} + + +static size_t +next_prime (size_t seed) +{ + /* Make sure that we're always greater than 4. */ + seed = (seed + 4) | 1; + + while (!is_prime (seed)) + seed += 2; + + return seed; +} + + +static void +compute_tables (void) +{ + valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t))); + while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0) + valstrtab[valstrlen++] = '\0'; + twalk (valstrtree, copy_valstr); + + static struct database *db; + for (db = databases; db != NULL; db = db->next) + if (db->nentries != 0) + { + ++ndatabases; + + /* We simply use an odd number large than twice the number of + elements to store in the hash table for the size. This gives + enough efficiency. */ +#define TEST_RANGE 30 + size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE + ? db->nentries + : db->nentries * 2 - TEST_RANGE); + size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4); + size_t nhashentries_best = nhashentries_min; + size_t chainlength_best = db->nentries; + + db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t) + + db->keystrlen); + db->keyidxtab = db->hashtable + nhashentries_max; + db->keystrtab = (char *) (db->keyidxtab + nhashentries_max); + + static size_t max_chainlength; + static char *wp; + static size_t nhashentries; + static bool copy_string; + + void add_key(const void *nodep, const VISIT which, const int depth) + { + if (which != leaf && which != postorder) + return; + + const struct dbentry *dbe = *(const struct dbentry **) nodep; + + ptrdiff_t stridx; + if (copy_string) + { + stridx = wp - db->keystrtab; + wp = stpcpy (wp, dbe->str) + 1; + } + else + stridx = 0; + + size_t hidx = dbe->hashval % nhashentries; + size_t hval2 = 1 + dbe->hashval % (nhashentries - 2); + size_t chainlength = 0; + + while (db->hashtable[hidx] != ~((stridx_t) 0)) + { + ++chainlength; + if ((hidx += hval2) >= nhashentries) + hidx -= nhashentries; + } + + db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0) + + dbe->validx); + db->keyidxtab[hidx] = stridx; + + max_chainlength = MAX (max_chainlength, chainlength); + } + + copy_string = false; + nhashentries = nhashentries_min; + for (size_t cnt = 0; cnt < TEST_RANGE; ++cnt) + { + memset (db->hashtable, '\xff', nhashentries * sizeof (stridx_t)); + + max_chainlength = 0; + wp = db->keystrtab; + + twalk (db->entries, add_key); + + if (max_chainlength == 0) + { + /* No need to look further, this is as good as it gets. */ + nhashentries_best = nhashentries; + break; + } + + if (max_chainlength < chainlength_best) + { + chainlength_best = max_chainlength; + nhashentries_best = nhashentries; + } + + nhashentries = next_prime (nhashentries + 1); + if (nhashentries > nhashentries_max) + break; + } + + /* Recompute the best table again, this time fill in the strings. */ + nhashentries = nhashentries_best; + memset (db->hashtable, '\xff', + 2 * nhashentries_max * sizeof (stridx_t)); + copy_string = true; + wp = db->keystrtab; + + twalk (db->entries, add_key); + + db->nhashentries = nhashentries_best; + nhashentries_total += nhashentries_best; + } +} + + +static int +write_output (int fd) +{ + struct nss_db_header *header; + uint64_t file_offset = (sizeof (struct nss_db_header) + + (ndatabases * sizeof (header->dbs[0]))); + header = alloca (file_offset); + + header->magic = NSS_DB_MAGIC; + header->ndbs = ndatabases; + header->valstroffset = file_offset; + header->valstrlen = valstrlen; + + size_t filled_dbs = 0; + struct iovec iov[2 + ndatabases * 3]; + iov[0].iov_base = header; + iov[0].iov_len = file_offset; + + iov[1].iov_base = valstrtab; + iov[1].iov_len = valstrlen + extrastrlen; + file_offset += iov[1].iov_len; + + size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t); + for (struct database *db = databases; db != NULL; db = db->next) + if (db->entries != NULL) + { + assert (file_offset % sizeof (stridx_t) == 0); + assert (filled_dbs < ndatabases); + + header->dbs[filled_dbs].id = db->dbid; + memset (header->dbs[filled_dbs].pad, '\0', + sizeof (header->dbs[0].pad)); + header->dbs[filled_dbs].hashsize = db->nhashentries; + + iov[2 + filled_dbs].iov_base = db->hashtable; + iov[2 + filled_dbs].iov_len = db->nhashentries * sizeof (stridx_t); + header->dbs[filled_dbs].hashoffset = file_offset; + file_offset += iov[2 + filled_dbs].iov_len; + + iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab; + iov[2 + ndatabases + filled_dbs * 2].iov_len + = db->nhashentries * sizeof (stridx_t); + header->dbs[filled_dbs].keyidxoffset = keydataoffset; + keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len; + + iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab; + iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen; + header->dbs[filled_dbs].keystroffset = keydataoffset; + keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len; + + ++filled_dbs; + } + + assert (filled_dbs == ndatabases); + assert (file_offset == (iov[0].iov_len + iov[1].iov_len + + nhashentries_total * sizeof (stridx_t))); + header->allocate = file_offset; + + if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset) + { + error (0, errno, gettext ("failed to write new database file")); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + + +static int +print_database (int fd) +{ + struct stat64 st; + if (fstat64 (fd, &st) != 0) + error (EXIT_FAILURE, errno, gettext ("cannot stat database file")); + + const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ, + MAP_PRIVATE|MAP_POPULATE, fd, 0); + if (header == MAP_FAILED) + error (EXIT_FAILURE, errno, gettext ("cannot map database file")); + + if (header->magic != NSS_DB_MAGIC) + error (EXIT_FAILURE, 0, gettext ("file not a database file")); + + const char *valstrtab = (const char *) header + header->valstroffset; + + for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx) + { + const stridx_t *stridxtab + = ((const stridx_t *) ((const char *) header + + header->dbs[dbidx].keyidxoffset)); + const char *keystrtab + = (const char *) header + header->dbs[dbidx].keystroffset; + const stridx_t *hashtab + = (const stridx_t *) ((const char *) header + + header->dbs[dbidx].hashoffset); + + for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx) + if (hashtab[hidx] != ~((stridx_t) 0)) + printf ("%c%s %s\n", + header->dbs[dbidx].id, + keystrtab + stridxtab[hidx], + valstrtab + hashtab[hidx]); + } + + return EXIT_SUCCESS; +} + + +#ifdef HAVE_SELINUX +static void +set_file_creation_context (const char *outname, mode_t mode) +{ + static int enabled; + static int enforcing; + security_context_t ctx; + + /* Check if SELinux is enabled, and remember. */ + if (enabled == 0) + enabled = is_selinux_enabled () ? 1 : -1; + if (enabled < 0) + return; + + /* Check if SELinux is enforcing, and remember. */ + if (enforcing == 0) + enforcing = security_getenforce () ? 1 : -1; + + /* Determine the context which the file should have. */ + ctx = NULL; + if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL) + { + if (setfscreatecon (ctx) != 0) + error (enforcing > 0 ? EXIT_FAILURE : 0, 0, + gettext ("cannot set file creation context for `%s'"), + outname); + + freecon (ctx); + } +} + +static void +reset_file_creation_context (void) +{ + setfscreatecon (NULL); +} +#endif diff --git a/REORG.TODO/nss/netgrp-lookup.c b/REORG.TODO/nss/netgrp-lookup.c new file mode 100644 index 0000000000..d32e8b8e30 --- /dev/null +++ b/REORG.TODO/nss/netgrp-lookup.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME netgroup + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/network-lookup.c b/REORG.TODO/nss/network-lookup.c new file mode 100644 index 0000000000..a5f5e38d61 --- /dev/null +++ b/REORG.TODO/nss/network-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME networks +#define DEFAULT_CONFIG "dns [!UNAVAIL=return] files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/nss.h b/REORG.TODO/nss/nss.h new file mode 100644 index 0000000000..fefdc4e44b --- /dev/null +++ b/REORG.TODO/nss/nss.h @@ -0,0 +1,63 @@ +/* Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +/* Define interface to NSS. This is meant for the interface functions + and for implementors of new services. */ + +#ifndef _NSS_H +#define _NSS_H 1 + +#include <features.h> +#include <stdint.h> + + +__BEGIN_DECLS + +/* Possible results of lookup using a nss_* function. */ +enum nss_status +{ + NSS_STATUS_TRYAGAIN = -2, + NSS_STATUS_UNAVAIL, + NSS_STATUS_NOTFOUND, + NSS_STATUS_SUCCESS, + NSS_STATUS_RETURN +}; + + +/* Data structure used for the 'gethostbyname4_r' function. */ +struct gaih_addrtuple + { + struct gaih_addrtuple *next; + char *name; + int family; + uint32_t addr[4]; + uint32_t scopeid; + }; + + +/* Overwrite service selection for database DBNAME using specification + in STRING. + This function should only be used by system programs which have to + work around non-existing services (e.e., while booting). + Attention: Using this function repeatedly will slowly eat up the + whole memory since previous selection data cannot be freed. */ +extern int __nss_configure_lookup (const char *__dbname, + const char *__string) __THROW; + +__END_DECLS + +#endif /* nss.h */ diff --git a/REORG.TODO/nss/nss_db/db-XXX.c b/REORG.TODO/nss/nss_db/db-XXX.c new file mode 100644 index 0000000000..9849c36223 --- /dev/null +++ b/REORG.TODO/nss/nss_db/db-XXX.c @@ -0,0 +1,311 @@ +/* Common code for DB-based databases in nss_db module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <fcntl.h> +#include <stdint.h> +#include <sys/mman.h> +#include <libc-lock.h> +#include "nsswitch.h" +#include "nss_db.h" + +/* The hashing function we use. */ +#include "../intl/hash-string.h" + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- database file name, ("hosts", "passwd") + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#include <paths.h> +#define DBFILE _PATH_VARDB DATABASE ".db" + +#ifdef NEED_H_ERRNO +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) +#else +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) +#endif + +/* State for this database. */ +static struct nss_db_map state; +/* Lock to protect the state and global variables. */ +__libc_lock_define (static , lock); + +/* Maintenance of the shared handle open on the database. */ +static int keep_db; +static const char *entidx; + + +/* Open the database. */ +enum nss_status +CONCAT(_nss_db_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (DBFILE, &state); + + if (status == NSS_STATUS_SUCCESS) + { + /* Remember STAYOPEN flag. */ + keep_db |= stayopen; + + /* Reset the sequential index. */ + entidx = NULL; + } + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close it again. */ +enum nss_status +CONCAT(_nss_db_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (&state); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +/* Macro for defining lookup functions for this DB-based database. + + NAME is the name of the lookup; e.g. `pwnam'. + + DB_CHAR is index indicator for the database. + + KEYPATTERN gives `printf' args to construct a key string; + e.g. `("%d", id)'. + + KEYSIZE gives the allocation size of a buffer to construct it in; + e.g. `1 + sizeof (id) * 4'. + + PROTO is the potentially empty list of other parameters. + + BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result' + to the lookup key arguments and does `break;' if they match. */ + +#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\ +enum nss_status \ + _nss_db_get##name##_r (proto, struct STRUCTURE *result, \ + char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\ +{ \ + struct parser_data *data = (void *) buffer; \ + \ + if (buflen < sizeof *data) \ + { \ + *errnop = ERANGE; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + return NSS_STATUS_TRYAGAIN; \ + } \ + \ + struct nss_db_map state = { NULL, 0 }; \ + enum nss_status status = internal_setent (DBFILE, &state); \ + if (status != NSS_STATUS_SUCCESS) \ + { \ + *errnop = errno; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + return status; \ + } \ + \ + const struct nss_db_header *header = state.header; \ + int i; \ + for (i = 0; i < header->ndbs; ++i) \ + if (header->dbs[i].id == db_char) \ + break; \ + if (i == header->ndbs) \ + { \ + status = NSS_STATUS_UNAVAIL; \ + goto out; \ + } \ + \ + char *key; \ + if (db_char == '.') \ + key = (char *) IGNOREPATTERN keypattern; \ + else \ + { \ + const size_t size = (keysize) + 1; \ + key = alloca (size); \ + \ + KEYPRINTF keypattern; \ + } \ + \ + const stridx_t *hashtable \ + = (const stridx_t *) ((const char *) header \ + + header->dbs[i].hashoffset); \ + const char *valstrtab = (const char *) header + header->valstroffset; \ + uint32_t hashval = __hash_string (key); \ + size_t hidx = hashval % header->dbs[i].hashsize; \ + size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); \ + \ + status = NSS_STATUS_NOTFOUND; \ + while (hashtable[hidx] != ~((stridx_t) 0)) \ + { \ + const char *valstr = valstrtab + hashtable[hidx]; \ + size_t len = strlen (valstr) + 1; \ + if (len > buflen) \ + { \ + /* No room to copy the data to. */ \ + *errnop = ERANGE; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + status = NSS_STATUS_TRYAGAIN; \ + break; \ + } \ + \ + /* Copy the string to a place where it can be modified. */ \ + char *p = memcpy (buffer, valstr, len); \ + \ + int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); \ + \ + /* Advance before break_if_match, lest it uses continue to skip + to the next entry. */ \ + if ((hidx += hval2) >= header->dbs[i].hashsize) \ + hidx -= header->dbs[i].hashsize; \ + \ + if (err > 0) \ + { \ + status = NSS_STATUS_SUCCESS; \ + break_if_match; \ + status = NSS_STATUS_NOTFOUND; \ + } \ + else if (err == -1) \ + { \ + H_ERRNO_SET (NETDB_INTERNAL); \ + status = NSS_STATUS_TRYAGAIN; \ + break; \ + } \ + } \ + \ + if (status == NSS_STATUS_NOTFOUND) \ + H_ERRNO_SET (HOST_NOT_FOUND); \ + \ + out: \ + internal_endent (&state); \ + \ + return status; \ +} + +#define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args) +#define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1 + + + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, + size_t buflen, int *errnop H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status; + struct parser_data *data = (void *) buffer; + + if (buflen < sizeof *data) + { + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + __libc_lock_lock (lock); + + if (state.header == NULL) + { + status = internal_setent (DBFILE, &state); + if (status != NSS_STATUS_SUCCESS) + { + *errnop = errno; + H_ERRNO_SET (NETDB_INTERNAL); + goto out; + } + entidx = NULL; + } + + /* Start from the beginning if freshly initialized or reset + requested by set*ent. */ + if (entidx == NULL) + entidx = (const char *) state.header + state.header->valstroffset; + + status = NSS_STATUS_UNAVAIL; + if (state.header != MAP_FAILED) + { + const char *const end = ((const char *) state.header + + state.header->valstroffset + + state.header->valstrlen); + while (entidx < end) + { + const char *next = rawmemchr (entidx, '\0') + 1; + size_t len = next - entidx; + + if (len > buflen) + { + /* No room to copy the data to. */ + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + break; + } + + /* Copy the string to a place where it can be modified. */ + char *p = memcpy (buffer, entidx, len); + + int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); + + if (err > 0) + { + status = NSS_STATUS_SUCCESS; + entidx = next; + break; + } + if (err < 0) + { + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + break; + } + + /* Continue with the next record, this one is ill-formed. */ + entidx = next; + } + } + + out: + __libc_lock_unlock (lock); + + return status; +} diff --git a/REORG.TODO/nss/nss_db/db-init.c b/REORG.TODO/nss/nss_db/db-init.c new file mode 100644 index 0000000000..1a65c59119 --- /dev/null +++ b/REORG.TODO/nss/nss_db/db-init.c @@ -0,0 +1,47 @@ +/* Initialization in nss_db module. + Copyright (C) 2011-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 + <http://www.gnu.org/licenses/>. */ + +#ifdef USE_NSCD + +#include <paths.h> +#include <nscd/nscd.h> +#include <string.h> + +#define PWD_FILENAME (_PATH_VARDB "passwd.db") +define_traced_file (pwd, PWD_FILENAME); + +#define GRP_FILENAME (_PATH_VARDB "group.db") +define_traced_file (grp, GRP_FILENAME); + +#define SERV_FILENAME (_PATH_VARDB "services.db") +define_traced_file (serv, SERV_FILENAME); + +void +_nss_db_init (void (*cb) (size_t, struct traced_file *)) +{ + init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0); + cb (pwddb, &pwd_traced_file.file); + + init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0); + cb (grpdb, &grp_traced_file.file); + + init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0); + cb (servdb, &serv_traced_file.file); +} + +#endif diff --git a/REORG.TODO/nss/nss_db/db-initgroups.c b/REORG.TODO/nss/nss_db/db-initgroups.c new file mode 100644 index 0000000000..11e6052453 --- /dev/null +++ b/REORG.TODO/nss/nss_db/db-initgroups.c @@ -0,0 +1,142 @@ +/* Initgroups handling in nss_db module. + Copyright (C) 2011-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@gmail.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <paths.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/param.h> + +#include "nss_db.h" + +/* The hashing function we use. */ +#include "../intl/hash-string.h" + + +enum nss_status +_nss_db_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + struct nss_db_map state = { NULL, 0 }; + enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state); + if (status != NSS_STATUS_SUCCESS) + { + *errnop = errno; + return status; + } + + const struct nss_db_header *header = state.header; + int i; + for (i = 0; i < header->ndbs; ++i) + if (header->dbs[i].id == ':') + break; + if (i == header->ndbs) + { + status = NSS_STATUS_UNAVAIL; + goto out; + } + + const stridx_t *hashtable + = (const stridx_t *) ((const char *) header + + header->dbs[i].hashoffset); + const char *valstrtab = (const char *) header + header->valstroffset; + size_t userlen = strlen (user); + uint32_t hashval = __hash_string (user); + size_t hidx = hashval % header->dbs[i].hashsize; + size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); + + gid_t *groups = *groupsp; + + status = NSS_STATUS_NOTFOUND; + while (hashtable[hidx] != ~((stridx_t) 0)) + { + const char *valstr = valstrtab + hashtable[hidx]; + while (isblank (*valstr)) + ++valstr; + + if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen])) + { + valstr += userlen + 1; + while (isblank (*valstr)) + ++valstr; + + while (*valstr != '\0') + { + errno = 0; + char *endp; + unsigned long int n = strtoul (valstr, &endp, 10); + if (*endp != ',' && *endp != '\0') + break; + valstr = *endp == '\0' ? endp : endp + 1; + + if (n != ULONG_MAX || errno != ERANGE) + { + /* Insert the group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + if (limit > 0 && *size == limit) + { + /* We reached the maximum. */ + status = NSS_STATUS_SUCCESS; + goto out; + } + + long int newsize; + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, + newsize * sizeof (*groups)); + if (newgroups == NULL) + { + *errnop = ENOMEM; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = n; + *start += 1; + } + } + + status = NSS_STATUS_SUCCESS; + break; + } + + if ((hidx += hval2) >= header->dbs[i].hashsize) + hidx -= header->dbs[i].hashsize; + } + + out: + internal_endent (&state); + + return status; +} diff --git a/REORG.TODO/nss/nss_db/db-netgrp.c b/REORG.TODO/nss/nss_db/db-netgrp.c new file mode 100644 index 0000000000..25530cc206 --- /dev/null +++ b/REORG.TODO/nss/nss_db/db-netgrp.c @@ -0,0 +1,122 @@ +/* Netgroup file parser in nss_db modules. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <netgroup.h> +#include <string.h> +#include <stdint.h> +#include <libc-lock.h> +#include <paths.h> +#include <stdlib.h> + +#include "nsswitch.h" +#include "nss_db.h" + +/* The hashing function we use. */ +#include "../intl/hash-string.h" + + +#define DBFILE _PATH_VARDB "netgroup.db" + +/* Maintenance of the shared handle open on the database. */ +enum nss_status +_nss_db_setnetgrent (const char *group, struct __netgrent *result) +{ + struct nss_db_map state; + enum nss_status status = internal_setent (DBFILE, &state); + + if (status == NSS_STATUS_SUCCESS) + { + const struct nss_db_header *header = state.header; + const stridx_t *hashtable + = (const stridx_t *) ((const char *) header + + header->dbs[0].hashoffset); + const char *valstrtab = (const char *) header + header->valstroffset; + uint32_t hashval = __hash_string (group); + size_t grouplen = strlen (group); + size_t hidx = hashval % header->dbs[0].hashsize; + size_t hval2 = 1 + hashval % (header->dbs[0].hashsize - 2); + + status = NSS_STATUS_NOTFOUND; + while (hashtable[hidx] != ~((stridx_t) 0)) + { + const char *valstr = valstrtab + hashtable[hidx]; + + if (strncmp (valstr, group, grouplen) == 0 + && isblank (valstr[grouplen])) + { + const char *cp = &valstr[grouplen + 1]; + while (isblank (*cp)) + ++cp; + if (*cp != '\0') + { + result->data = strdup (cp); + if (result->data == NULL) + status = NSS_STATUS_TRYAGAIN; + else + { + status = NSS_STATUS_SUCCESS; + result->cursor = result->data; + } + break; + } + } + + if ((hidx += hval2) >= header->dbs[0].hashsize) + hidx -= header->dbs[0].hashsize; + } + + internal_endent (&state); + } + + return status; + +} + + +enum nss_status +_nss_db_endnetgrent (struct __netgrent *result) +{ + free (result->data); + result->data = NULL; + result->data_size = 0; + result->cursor = NULL; + return NSS_STATUS_SUCCESS; +} + + +extern enum nss_status _nss_netgroup_parseline (char **cursor, + struct __netgrent *result, + char *buffer, size_t buflen, + int *errnop); + +enum nss_status +_nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, + errnop); + + return status; +} diff --git a/REORG.TODO/nss/nss_db/db-open.c b/REORG.TODO/nss/nss_db/db-open.c new file mode 100644 index 0000000000..1c58bd1c54 --- /dev/null +++ b/REORG.TODO/nss/nss_db/db-open.c @@ -0,0 +1,67 @@ +/* Common database routines for nss_db. + Copyright (C) 2000-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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <not-cancel.h> + +#include "nss_db.h" + +/* Open the database stored in FILE. If succesful, store either a + pointer to the mapped file or a file handle for the file in H and + return NSS_STATUS_SUCCESS. On failure, return the appropriate + lookup status. */ +enum nss_status +internal_setent (const char *file, struct nss_db_map *mapping) +{ + enum nss_status status = NSS_STATUS_UNAVAIL; + + int fd = open_not_cancel_2 (file, O_RDONLY | O_LARGEFILE | O_CLOEXEC); + if (fd != -1) + { + struct nss_db_header header; + + if (read (fd, &header, sizeof (header)) == sizeof (header)) + { + mapping->header = mmap (NULL, header.allocate, PROT_READ, + MAP_PRIVATE, fd, 0); + mapping->len = header.allocate; + if (mapping->header != MAP_FAILED) + status = NSS_STATUS_SUCCESS; + else if (errno == ENOMEM) + status = NSS_STATUS_TRYAGAIN; + } + + close_not_cancel_no_status (fd); + } + + return status; +} + + +/* Close the database. */ +void +internal_endent (struct nss_db_map *mapping) +{ + munmap (mapping->header, mapping->len); +} diff --git a/REORG.TODO/nss/nss_db/nss_db.h b/REORG.TODO/nss/nss_db/nss_db.h new file mode 100644 index 0000000000..6978cead07 --- /dev/null +++ b/REORG.TODO/nss/nss_db/nss_db.h @@ -0,0 +1,69 @@ +/* Common database open/close routines for nss_db. + Copyright (C) 1999-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 + <http://www.gnu.org/licenses/>. */ + +#ifndef _NSS_DB_H +#define _NSS_DB_H 1 + +#include <nss.h> +#include <stdint.h> +#include <libc-lock.h> + + +/* String table index type. */ +typedef uint32_t stridx_t; + +/* Database file header. */ +struct nss_db_header +{ + uint32_t magic; +#define NSS_DB_MAGIC 0xdd110601 + uint32_t ndbs; + uint64_t valstroffset; + uint64_t valstrlen; + uint64_t allocate; + struct + { + char id; + char pad[sizeof (uint32_t) - 1]; + uint32_t hashsize; + uint64_t hashoffset; + uint64_t keyidxoffset; + uint64_t keystroffset; + } dbs[0]; +}; + + +/* Information about mapped database. */ +struct nss_db_map +{ + struct nss_db_header *header; + size_t len; +}; + + +/* Open the database stored in FILE. If succesful, store the database + handle in *MAPPINGP or a file descriptor for the file in *FDP and + return NSS_STATUS_SUCCESS. On failure, return the appropriate + lookup status. */ +enum nss_status internal_setent (const char *file, + struct nss_db_map *mappingp); + +/* Close the database FD. */ +extern void internal_endent (struct nss_db_map *mapping); + +#endif /* nss_db.h */ diff --git a/REORG.TODO/nss/nss_files/files-XXX.c b/REORG.TODO/nss/nss_files/files-XXX.c new file mode 100644 index 0000000000..265331ef21 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-XXX.c @@ -0,0 +1,300 @@ +/* Common code for file-based databases in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <libc-lock.h> +#include "nsswitch.h" + +#include <kernel-features.h> + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + Also see files-parse.c. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#define DATAFILE "/etc/" DATABASE + +#ifdef NEED_H_ERRNO +# include <netdb.h> +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) +#else +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) +#endif + +#ifndef EXTRA_ARGS +# define EXTRA_ARGS +# define EXTRA_ARGS_DECL +# define EXTRA_ARGS_VALUE +#endif + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the stream open on the database file. For getXXent + operations the stream needs to be held open across calls, the other + getXXbyYY operations all use their own stream. */ + +static FILE *stream; + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (FILE **stream) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (*stream == NULL) + { + *stream = fopen (DATAFILE, "rce"); + + if (*stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + else + rewind (*stream); + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (&stream); + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (FILE **stream) +{ + if (*stream != NULL) + { + fclose (*stream); + *stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (&stream); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +typedef enum +{ + gcr_ok = 0, + gcr_error = -1, + gcr_overflow = -2 +} get_contents_ret; + +/* Hack around the fact that fgets only accepts int sizes. */ +static get_contents_ret +get_contents (char *linebuf, size_t len, FILE *stream) +{ + size_t remaining_len = len; + char *curbuf = linebuf; + + do + { + int curlen = ((remaining_len > (size_t) INT_MAX) ? INT_MAX + : remaining_len); + + /* Terminate the line so that we can test for overflow. */ + ((unsigned char *) curbuf)[curlen - 1] = 0xff; + + char *p = fgets_unlocked (curbuf, curlen, stream); + + /* EOF or read error. */ + if (p == NULL) + return gcr_error; + + /* Done reading in the line. */ + if (((unsigned char *) curbuf)[curlen - 1] == 0xff) + return gcr_ok; + + /* Drop the terminating '\0'. */ + remaining_len -= curlen - 1; + curbuf += curlen - 1; + } + /* fgets copies one less than the input length. Our last iteration is of + REMAINING_LEN and once that is done, REMAINING_LEN is decremented by + REMAINING_LEN - 1, leaving the result as 1. */ + while (remaining_len > 1); + + /* This means that the current buffer was not large enough. */ + return gcr_overflow; +} + +/* Parsing the database file into `struct STRUCTURE' data structures. */ +static enum nss_status +internal_getent (FILE *stream, struct STRUCTURE *result, + char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO + EXTRA_ARGS_DECL) +{ + char *p; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + int parse_result; + + if (buflen < sizeof *data + 2) + { + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + do + { + get_contents_ret r = get_contents (data->linebuffer, linebuflen, stream); + + if (r == gcr_error) + { + /* End of file or read error. */ + H_ERRNO_SET (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } + + if (r == gcr_overflow) + { + /* The line is too long. Give the user the opportunity to + enlarge the buffer. */ + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + /* Everything OK. Now skip leading blanks. */ + p = data->linebuffer; + 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_result = parse_line (p, result, data, buflen, errnop + EXTRA_ARGS))); + + if (__glibc_unlikely (parse_result == -1)) + { + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + /* Filled in RESULT with the next entry from the database file. */ + return NSS_STATUS_SUCCESS; +} + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, + size_t buflen, int *errnop H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + { + int save_errno = errno; + + status = internal_setent (&stream); + + __set_errno (save_errno); + } + + if (status == NSS_STATUS_SUCCESS) + status = internal_getent (stream, result, buffer, buflen, errnop + H_ERRNO_ARG EXTRA_ARGS_VALUE); + + __libc_lock_unlock (lock); + + return status; +} + +/* Macro for defining lookup functions for this file-based database. + + NAME is the name of the lookup; e.g. `hostbyname'. + + DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c + e.g. `1 + sizeof (id) * 4'. + + PROTO is the potentially empty list of other parameters. + + BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result' + to the lookup key arguments and does `break;' if they match. */ + +#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\ +enum nss_status \ +_nss_files_get##name##_r (proto, \ + struct STRUCTURE *result, char *buffer, \ + size_t buflen, int *errnop H_ERRNO_PROTO) \ +{ \ + enum nss_status status; \ + FILE *stream = NULL; \ + \ + /* Open file. */ \ + status = internal_setent (&stream); \ + \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + while ((status = internal_getent (stream, result, buffer, buflen, errnop \ + H_ERRNO_ARG EXTRA_ARGS_VALUE)) \ + == NSS_STATUS_SUCCESS) \ + { break_if_match } \ + \ + internal_endent (&stream); \ + } \ + \ + return status; \ +} diff --git a/REORG.TODO/nss/nss_files/files-alias.c b/REORG.TODO/nss/nss_files/files-alias.c new file mode 100644 index 0000000000..cf872bb603 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-alias.c @@ -0,0 +1,404 @@ +/* Mail alias file parser in nss_files module. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <aliases.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <libc-lock.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <kernel-features.h> + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the stream open on the database file. For getXXent + operations the stream needs to be held open across calls, the other + getXXbyYY operations all use their own stream. */ + +static FILE *stream; + + +static enum nss_status +internal_setent (FILE **stream) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (*stream == NULL) + { + *stream = fopen ("/etc/aliases", "rce"); + + if (*stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + else + rewind (*stream); + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_setaliasent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (&stream); + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (FILE **stream) +{ + if (*stream != NULL) + { + fclose (*stream); + *stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (&stream); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct aliasent' data structures. */ +static enum nss_status +get_next_alias (FILE *stream, const char *match, struct aliasent *result, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + int ignore = 0; + + result->alias_members_len = 0; + + while (1) + { + /* Now we are ready to process the input. We have to read a + line and all its continuations and construct the array of + string pointers. This pointers and the names itself have to + be placed in BUFFER. */ + char *first_unused = buffer; + size_t room_left = buflen - (buflen % __alignof__ (char *)); + char *line; + + /* Check whether the buffer is large enough for even trying to + read something. */ + if (room_left < 2) + goto no_more_room; + + /* Read the first line. It must contain the alias name and + possibly some alias names. */ + first_unused[room_left - 1] = '\xff'; + line = fgets_unlocked (first_unused, room_left, stream); + if (line == NULL) + /* Nothing to read. */ + break; + else if (first_unused[room_left - 1] != '\xff') + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + status = NSS_STATUS_TRYAGAIN; + break; + } + else + { + char *cp; + + /* If we are in IGNORE mode and the first character in the + line is a white space we ignore the line and start + reading the next. */ + if (ignore && isspace (*first_unused)) + continue; + + /* Terminate the line for any case. */ + cp = strpbrk (first_unused, "#\n"); + if (cp != NULL) + *cp = '\0'; + + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; + + result->alias_name = first_unused; + while (*line != '\0' && *line != ':') + *first_unused++ = *line++; + if (*line == '\0' || result->alias_name == first_unused) + /* No valid name. Ignore the line. */ + continue; + + *first_unused++ = '\0'; + if (room_left < (size_t) (first_unused - result->alias_name)) + goto no_more_room; + room_left -= first_unused - result->alias_name; + ++line; + + /* When we search for a specific alias we can avoid all the + difficult parts and compare now with the name we are + looking for. If it does not match we simply ignore all + lines until the next line containing the start of a new + alias is found. */ + ignore = (match != NULL + && __strcasecmp (result->alias_name, match) != 0); + + while (! ignore) + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (first_unused != cp) + { + /* OK, we can have a regular entry or an include + request. */ + if (*line != '\0') + ++line; + *first_unused++ = '\0'; + + if (strncmp (cp, ":include:", 9) != 0) + { + if (room_left < (first_unused - cp) + sizeof (char *)) + goto no_more_room; + room_left -= (first_unused - cp) + sizeof (char *); + + ++result->alias_members_len; + } + else + { + /* Oh well, we have to read the addressed file. */ + FILE *listfile; + char *old_line = NULL; + + first_unused = cp; + + listfile = fopen (&cp[9], "rce"); + /* If the file does not exist we simply ignore + the statement. */ + if (listfile != NULL + && (old_line = strdup (line)) != NULL) + { + while (! feof_unlocked (listfile)) + { + first_unused[room_left - 1] = '\xff'; + line = fgets_unlocked (first_unused, room_left, + listfile); + if (line == NULL) + break; + if (first_unused[room_left - 1] != '\xff') + { + free (old_line); + goto no_more_room; + } + + /* Parse the line. */ + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + + do + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (*line != '\0') + ++line; + + if (first_unused != cp) + { + *first_unused++ = '\0'; + if (room_left < ((first_unused - cp) + + __alignof__ (char *))) + { + free (old_line); + goto no_more_room; + } + room_left -= ((first_unused - cp) + + __alignof__ (char *)); + ++result->alias_members_len; + } + } + while (*line != '\0'); + } + fclose (listfile); + + first_unused[room_left - 1] = '\0'; + strncpy (first_unused, old_line, room_left); + + free (old_line); + line = first_unused; + + if (first_unused[room_left - 1] != '\0') + goto no_more_room; + } + } + } + + if (*line == '\0') + { + /* Get the next line. But we must be careful. We + must not read the whole line at once since it + might belong to the current alias. Simply read + the first character. If it is a white space we + have a continuation line. Otherwise it is the + beginning of a new alias and we can push back the + just read character. */ + int ch; + + ch = fgetc_unlocked (stream); + if (ch == EOF || ch == '\n' || !isspace (ch)) + { + size_t cnt; + + /* Now prepare the return. Provide string + pointers for the currently selected aliases. */ + if (ch != EOF) + ungetc (ch, stream); + + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) + % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + break; + } + + /* The just read character is a white space and so + can be ignored. */ + first_unused[room_left - 1] = '\xff'; + line = fgets_unlocked (first_unused, room_left, stream); + if (first_unused[room_left - 1] != '\xff') + goto no_more_room; + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + } + } + } + + if (status != NSS_STATUS_NOTFOUND) + /* We read something. In any case break here. */ + break; + } + + return status; +} + + +enum nss_status +_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen, + int *errnop) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + status = internal_setent (&stream); + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (stream, NULL, result, buffer, buflen, errnop); + while (status == NSS_STATUS_RETURN); + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_files_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen, int *errnop) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + FILE *stream = NULL; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + /* Open the stream. */ + status = internal_setent (&stream); + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (stream, name, result, buffer, buflen, errnop); + while (status == NSS_STATUS_RETURN); + } + + internal_endent (&stream); + + return status; +} diff --git a/REORG.TODO/nss/nss_files/files-ethers.c b/REORG.TODO/nss/nss_files/files-ethers.c new file mode 100644 index 0000000000..6f5c02636f --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-ethers.c @@ -0,0 +1,67 @@ +/* Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <netinet/ether.h> +#include <netinet/if_ether.h> + +struct etherent_data {}; + +#define ENTNAME etherent +#define DATABASE "ethers" +#include "files-parse.c" +LINE_PARSER +("#", + /* Read the ethernet address: 6 x 8bit hexadecimal number. */ + { + size_t cnt; + + for (cnt = 0; cnt < 6; ++cnt) + { + unsigned int number; + + if (cnt < 5) + INT_FIELD (number, ISCOLON , 0, 16, (unsigned int)) + else + INT_FIELD (number, isspace, 1, 16, (unsigned int)) + + if (number > 0xff) + return 0; + result->e_addr.ether_addr_octet[cnt] = number; + } + }; + STRING_FIELD (result->e_name, isspace, 1); + ) + + +#include GENERIC + +DB_LOOKUP (hostton, '.', 0, ("%s", name), + { + if (__strcasecmp (result->e_name, name) == 0) + break; + }, const char *name) + +DB_LOOKUP (ntohost, '=', 18, ("%x:%x:%x:%x:%x:%x", + addr->ether_addr_octet[0], addr->ether_addr_octet[1], + addr->ether_addr_octet[2], addr->ether_addr_octet[3], + addr->ether_addr_octet[4], addr->ether_addr_octet[5]), + { + if (memcmp (&result->e_addr, addr, + sizeof (struct ether_addr)) == 0) + break; + }, const struct ether_addr *addr) diff --git a/REORG.TODO/nss/nss_files/files-grp.c b/REORG.TODO/nss/nss_files/files-grp.c new file mode 100644 index 0000000000..ff8b27f2b3 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-grp.c @@ -0,0 +1,44 @@ +/* Group file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <grp.h> + +#define STRUCTURE group +#define ENTNAME grent +#define DATABASE "group" +struct grent_data {}; + +/* Our parser function is already defined in fgetgrent.c, so use that. + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (grnam, '.', 0, ("%s", name), + { + if (name[0] != '-' && name[0] != '+' + && ! strcmp (name, result->gr_name)) + break; + }, const char *name) + +DB_LOOKUP (grgid, '=', 20, ("%lu", (unsigned long int) gid), + { + if (result->gr_gid == gid && result->gr_name[0] != '+' + && result->gr_name[0] != '-') + break; + }, gid_t gid) diff --git a/REORG.TODO/nss/nss_files/files-hosts.c b/REORG.TODO/nss/nss_files/files-hosts.c new file mode 100644 index 0000000000..bccb6a5780 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-hosts.c @@ -0,0 +1,482 @@ +/* Hosts file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv/resolv-internal.h> + + +/* Get implementation for some internal functions. */ +#include "../resolv/mapv4v6addr.h" +#include "../resolv/res_hconf.h" + + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define EXTRA_ARGS , af, flags +#define EXTRA_ARGS_DECL , int af, int flags + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + /* Parse address. */ + if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr) + > 0) + af = af == AF_UNSPEC ? AF_INET : af; + else + { + if (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 + && inet_pton (AF_INET, addr, entdata->host_addr) > 0) + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + else if (af == AF_INET + && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + if (IN6_IS_ADDR_V4MAPPED (entdata->host_addr)) + memcpy (entdata->host_addr, entdata->host_addr + 12, INADDRSZ); + else if (IN6_IS_ADDR_LOOPBACK (entdata->host_addr)) + { + in_addr_t localhost = htonl (INADDR_LOOPBACK); + memcpy (entdata->host_addr, &localhost, sizeof (localhost)); + } + else + /* Illegal address: ignore line. */ + return 0; + } + else if (af == AF_UNSPEC + && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + af = AF_INET6; + else + /* Illegal address: ignore line. */ + return 0; + } + + /* We always return entries of the requested form. */ + result->h_addrtype = af; + result->h_length = af == AF_INET ? INADDRSZ : IN6ADDRSZ; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = (char *) entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + STRING_FIELD (result->h_name, isspace, 1); + }) + +#define EXTRA_ARGS_VALUE \ + , (res_use_inet6 () ? AF_INET6 : AF_INET), \ + (res_use_inet6 () ? AI_V4MAPPED : 0) +#include "files-XXX.c" +#undef EXTRA_ARGS_VALUE + +/* We only need to consider IPv4 mapped addresses if the input to the + gethostbyaddr() function is an IPv6 address. */ +#define EXTRA_ARGS_VALUE \ + , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0) +DB_LOOKUP (hostbyaddr, ,,, + { + if (result->h_length == (int) len + && ! memcmp (addr, result->h_addr_list[0], len)) + break; + }, const void *addr, socklen_t len, int af) +#undef EXTRA_ARGS_VALUE + +enum nss_status +_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp, char **canonp) +{ + FILE *stream = NULL; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + /* Open file. */ + enum nss_status status = internal_setent (&stream); + + if (status == NSS_STATUS_SUCCESS) + { + /* XXX Is using _res to determine whether we want to convert IPv4 + addresses to IPv6 addresses really the right thing to do? */ + int flags = (res_use_inet6 () ? AI_V4MAPPED : 0); + + while ((status = internal_getent (stream, result, buffer, buflen, errnop, + herrnop, af, flags)) + == NSS_STATUS_SUCCESS) + { + LOOKUP_NAME_CASE (h_name, h_aliases) + } + + if (status == NSS_STATUS_SUCCESS + && _res_hconf.flags & HCONF_FLAG_MULTI) + { + /* We have to get all host entries from the file. */ + size_t tmp_buflen = MIN (buflen, 4096); + char tmp_buffer_stack[tmp_buflen] + __attribute__ ((__aligned__ (__alignof__ (struct hostent_data)))); + char *tmp_buffer = tmp_buffer_stack; + struct hostent tmp_result_buf; + int naddrs = 1; + int naliases = 0; + char *bufferend; + bool tmp_buffer_malloced = false; + + while (result->h_aliases[naliases] != NULL) + ++naliases; + + bufferend = (char *) &result->h_aliases[naliases + 1]; + + again: + while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer, + tmp_buflen, errnop, herrnop, af, + flags)) + == NSS_STATUS_SUCCESS) + { + int matches = 1; + struct hostent *old_result = result; + result = &tmp_result_buf; + /* The following piece is a bit clumsy but we want to use the + `LOOKUP_NAME_CASE' value. The optimizer should do its + job. */ + do + { + LOOKUP_NAME_CASE (h_name, h_aliases) + result = old_result; + } + while ((matches = 0)); + + if (matches) + { + /* We could be very clever and try to recycle a few bytes + in the buffer instead of generating new arrays. But + we are not doing this here since it's more work than + it's worth. Simply let the user provide a bit bigger + buffer. */ + char **new_h_addr_list; + char **new_h_aliases; + int newaliases = 0; + size_t newstrlen = 0; + int cnt; + + /* Count the new aliases and the length of the strings. */ + while (tmp_result_buf.h_aliases[newaliases] != NULL) + { + char *cp = tmp_result_buf.h_aliases[newaliases]; + ++newaliases; + newstrlen += strlen (cp) + 1; + } + /* If the real name is different add it also to the + aliases. This means that there is a duplication + in the alias list but this is really the user's + problem. */ + if (strcmp (old_result->h_name, + tmp_result_buf.h_name) != 0) + { + ++newaliases; + newstrlen += strlen (tmp_result_buf.h_name) + 1; + } + + /* Make sure bufferend is aligned. */ + assert ((bufferend - (char *) 0) % sizeof (char *) == 0); + + /* Now we can check whether the buffer is large enough. + 16 is the maximal size of the IP address. */ + if (bufferend + 16 + (naddrs + 2) * sizeof (char *) + + roundup (newstrlen, sizeof (char *)) + + (naliases + newaliases + 1) * sizeof (char *) + >= buffer + buflen) + { + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + + new_h_addr_list = + (char **) (bufferend + + roundup (newstrlen, sizeof (char *)) + + 16); + new_h_aliases = + (char **) ((char *) new_h_addr_list + + (naddrs + 2) * sizeof (char *)); + + /* Copy the old data in the new arrays. */ + for (cnt = 0; cnt < naddrs; ++cnt) + new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; + + for (cnt = 0; cnt < naliases; ++cnt) + new_h_aliases[cnt] = old_result->h_aliases[cnt]; + + /* Store the new strings. */ + cnt = 0; + while (tmp_result_buf.h_aliases[cnt] != NULL) + { + new_h_aliases[naliases++] = bufferend; + bufferend = (__stpcpy (bufferend, + tmp_result_buf.h_aliases[cnt]) + + 1); + ++cnt; + } + + if (cnt < newaliases) + { + new_h_aliases[naliases++] = bufferend; + bufferend = __stpcpy (bufferend, + tmp_result_buf.h_name) + 1; + } + + /* Final NULL pointer. */ + new_h_aliases[naliases] = NULL; + + /* Round up the buffer end address. */ + bufferend += (sizeof (char *) + - ((bufferend - (char *) 0) + % sizeof (char *))) % sizeof (char *); + + /* Now the new address. */ + new_h_addr_list[naddrs++] = + memcpy (bufferend, tmp_result_buf.h_addr, + tmp_result_buf.h_length); + + /* Also here a final NULL pointer. */ + new_h_addr_list[naddrs] = NULL; + + /* Store the new array pointers. */ + old_result->h_aliases = new_h_aliases; + old_result->h_addr_list = new_h_addr_list; + + /* Compute the new buffer end. */ + bufferend = (char *) &new_h_aliases[naliases + 1]; + assert (bufferend <= buffer + buflen); + + result = old_result; + } + } + + if (status == NSS_STATUS_TRYAGAIN) + { + size_t newsize = 2 * tmp_buflen; + if (tmp_buffer_malloced) + { + char *newp = realloc (tmp_buffer, newsize); + if (newp != NULL) + { + assert ((((uintptr_t) newp) + & (__alignof__ (struct hostent_data) - 1)) + == 0); + tmp_buffer = newp; + tmp_buflen = newsize; + goto again; + } + } + else if (!__libc_use_alloca (buflen + newsize)) + { + tmp_buffer = malloc (newsize); + if (tmp_buffer != NULL) + { + assert ((((uintptr_t) tmp_buffer) + & (__alignof__ (struct hostent_data) - 1)) + == 0); + tmp_buffer_malloced = true; + tmp_buflen = newsize; + goto again; + } + } + else + { + tmp_buffer + = extend_alloca (tmp_buffer, tmp_buflen, + newsize + + __alignof__ (struct hostent_data)); + tmp_buffer = (char *) (((uintptr_t) tmp_buffer + + __alignof__ (struct hostent_data) + - 1) + & ~(__alignof__ (struct hostent_data) + - 1)); + goto again; + } + } + else + status = NSS_STATUS_SUCCESS; + out: + if (tmp_buffer_malloced) + free (tmp_buffer); + } + + internal_endent (&stream); + } + + if (canonp && status == NSS_STATUS_SUCCESS) + *canonp = result->h_name; + + return status; +} + +enum nss_status +_nss_files_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + int af = (res_use_inet6 () ? AF_INET6 : AF_INET); + + return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} + +enum nss_status +_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} + +enum nss_status +_nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + FILE *stream = NULL; + + /* Open file. */ + enum nss_status status = internal_setent (&stream); + + if (status == NSS_STATUS_SUCCESS) + { + bool any = false; + bool got_canon = false; + while (1) + { + /* Align the buffer for the next record. */ + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct hostent_data)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + struct hostent result; + status = internal_getent (stream, &result, buffer, buflen, errnop, + herrnop, AF_UNSPEC, 0); + if (status != NSS_STATUS_SUCCESS) + break; + + int naliases = 0; + if (__strcasecmp (name, result.h_name) != 0) + { + for (; result.h_aliases[naliases] != NULL; ++naliases) + if (! __strcasecmp (name, result.h_aliases[naliases])) + break; + if (result.h_aliases[naliases] == NULL) + continue; + + /* We know this alias exist. Count it. */ + ++naliases; + } + + /* Determine how much memory has been used so far. */ + // XXX It is not necessary to preserve the aliases array + while (result.h_aliases[naliases] != NULL) + ++naliases; + char *bufferend = (char *) &result.h_aliases[naliases + 1]; + assert (buflen >= bufferend - buffer); + buflen -= bufferend - buffer; + buffer = bufferend; + + /* We found something. */ + any = true; + + /* Create the record the caller expects. There is only one + address. */ + assert (result.h_addr_list[1] == NULL); + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), + 0)) + { + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + status = NSS_STATUS_TRYAGAIN; + break; + } + + *pat = (struct gaih_addrtuple *) buffer; + buffer += sizeof (struct gaih_addrtuple); + buflen -= sizeof (struct gaih_addrtuple); + } + + (*pat)->next = NULL; + (*pat)->name = got_canon ? NULL : result.h_name; + got_canon = true; + (*pat)->family = result.h_addrtype; + memcpy ((*pat)->addr, result.h_addr_list[0], result.h_length); + (*pat)->scopeid = 0; + + pat = &((*pat)->next); + + /* If we only look for the first matching entry we are done. */ + if ((_res_hconf.flags & HCONF_FLAG_MULTI) == 0) + break; + } + + /* If we have to look for multiple records and found one, this + is a success. */ + if (status == NSS_STATUS_NOTFOUND && any) + { + assert ((_res_hconf.flags & HCONF_FLAG_MULTI) != 0); + status = NSS_STATUS_SUCCESS; + } + + internal_endent (&stream); + } + else if (status == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = TRY_AGAIN; + } + else + { + *errnop = errno; + *herrnop = NO_DATA; + } + + return status; +} diff --git a/REORG.TODO/nss/nss_files/files-init.c b/REORG.TODO/nss/nss_files/files-init.c new file mode 100644 index 0000000000..9243d86cc9 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-init.c @@ -0,0 +1,64 @@ +/* Initialization in nss_files module. + Copyright (C) 2011-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 + <http://www.gnu.org/licenses/>. */ + +#ifdef USE_NSCD + +#include <string.h> +#include <nscd/nscd.h> + +#define PWD_FILENAME "/etc/passwd" +define_traced_file (pwd, PWD_FILENAME); + +#define GRP_FILENAME "/etc/group" +define_traced_file (grp, GRP_FILENAME); + +#define HST_FILENAME "/etc/hosts" +define_traced_file (hst, HST_FILENAME); + +#define RESOLV_FILENAME "/etc/resolv.conf" +define_traced_file (resolv, RESOLV_FILENAME); + +#define SERV_FILENAME "/etc/services" +define_traced_file (serv, SERV_FILENAME); + +#define NETGR_FILENAME "/etc/netgroup" +define_traced_file (netgr, NETGR_FILENAME); + +void +_nss_files_init (void (*cb) (size_t, struct traced_file *)) +{ + init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0); + cb (pwddb, &pwd_traced_file.file); + + init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0); + cb (grpdb, &grp_traced_file.file); + + init_traced_file (&hst_traced_file.file, HST_FILENAME, 0); + cb (hstdb, &hst_traced_file.file); + + init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1); + cb (hstdb, &resolv_traced_file.file); + + init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0); + cb (servdb, &serv_traced_file.file); + + init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0); + cb (netgrdb, &netgr_traced_file.file); +} + +#endif diff --git a/REORG.TODO/nss/nss_files/files-initgroups.c b/REORG.TODO/nss/nss_files/files-initgroups.c new file mode 100644 index 0000000000..27cd8ece40 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-initgroups.c @@ -0,0 +1,142 @@ +/* Initgroups handling in nss_files module. + Copyright (C) 2011-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 + <http://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <errno.h> +#include <grp.h> +#include <nss.h> +#include <stdio_ext.h> +#include <string.h> +#include <sys/param.h> +#include <stdbool.h> +#include <stdlib.h> + +enum nss_status +_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + FILE *stream = fopen ("/etc/group", "rce"); + if (stream == NULL) + { + *errnop = errno; + return *errnop == ENOMEM ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + + /* No other thread using this stream. */ + __fsetlocking (stream, FSETLOCKING_BYCALLER); + + char *line = NULL; + size_t linelen = 0; + enum nss_status status = NSS_STATUS_SUCCESS; + bool any = false; + + size_t buflen = 1024; + void *buffer = alloca (buflen); + bool buffer_use_malloc = false; + + gid_t *groups = *groupsp; + + /* We have to iterate over the entire file. */ + while (1) + { + fpos_t pos; + fgetpos (stream, &pos); + ssize_t n = getline (&line, &linelen, stream); + if (n < 0) + { + if (! feof_unlocked (stream)) + status = ((*errnop = errno) == ENOMEM + ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL); + break; + } + + struct group grp; + int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop); + if (res == -1) + { + size_t newbuflen = 2 * buflen; + if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen)) + { + void *newbuf = realloc (buffer_use_malloc ? buffer : NULL, + newbuflen); + if (newbuf == NULL) + { + *errnop = ENOMEM; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + buffer = newbuf; + buflen = newbuflen; + buffer_use_malloc = true; + } + else + buffer = extend_alloca (buffer, buflen, newbuflen); + /* Reread current line, the parser has clobbered it. */ + fsetpos (stream, &pos); + continue; + } + + if (res > 0 && grp.gr_gid != group) + for (char **m = grp.gr_mem; *m != NULL; ++m) + if (strcmp (*m, user) == 0) + { + /* Matches user. Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + goto out; + + long int newsize; + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, + newsize * sizeof (*groups)); + if (newgroups == NULL) + { + *errnop = ENOMEM; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = grp.gr_gid; + *start += 1; + any = true; + + break; + } + } + + out: + /* Free memory. */ + if (buffer_use_malloc) + free (buffer); + free (line); + + fclose (stream); + + return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status; +} diff --git a/REORG.TODO/nss/nss_files/files-key.c b/REORG.TODO/nss/nss_files/files-key.c new file mode 100644 index 0000000000..11a574a0b1 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-key.c @@ -0,0 +1,111 @@ +/* Public key file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <rpc/key_prot.h> +#include <rpc/des_crypt.h> +#include "nsswitch.h" + +#define DATAFILE "/etc/publickey" + + +static enum nss_status +search (const char *netname, char *result, int *errnop, int secret) +{ + FILE *stream = fopen (DATAFILE, "rce"); + if (stream == NULL) + return errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + + for (;;) + { + char buffer[HEXKEYBYTES * 2 + KEYCHECKSUMSIZE + MAXNETNAMELEN + 17]; + char *p; + char *save_ptr; + + buffer[sizeof (buffer) - 1] = '\xff'; + p = fgets_unlocked (buffer, sizeof (buffer), stream); + if (p == NULL) + { + /* End of file or read error. */ + *errnop = errno; + fclose (stream); + return NSS_STATUS_NOTFOUND; + } + else if (buffer[sizeof (buffer) - 1] != '\xff') + { + /* Invalid line in file? Skip remainder of line. */ + if (buffer[sizeof (buffer) - 2] != '\0') + while (getc_unlocked (stream) != '\n') + continue; + continue; + } + + /* Parse line. */ + p = __strtok_r (buffer, "# \t:\n", &save_ptr); + if (p == NULL) /* Skip empty and comment lines. */ + continue; + if (strcmp (p, netname) != 0) + continue; + + /* A hit! Find the field we want and return. */ + p = __strtok_r (NULL, ":\n", &save_ptr); + if (p == NULL) /* malformed line? */ + continue; + if (secret) + p = __strtok_r (NULL, ":\n", &save_ptr); + if (p == NULL) /* malformed line? */ + continue; + fclose (stream); + strcpy (result, p); + return NSS_STATUS_SUCCESS; + } +} + +enum nss_status +_nss_files_getpublickey (const char *netname, char *pkey, int *errnop) +{ + return search (netname, pkey, errnop, 0); +} + +enum nss_status +_nss_files_getsecretkey (const char *netname, char *skey, char *passwd, + int *errnop) +{ + enum nss_status status; + char buf[HEXKEYBYTES + KEYCHECKSUMSIZE + 16]; + + skey[0] = 0; + + status = search (netname, buf, errnop, 1); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (!xdecrypt (buf, passwd)) + return NSS_STATUS_SUCCESS; + + if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) + return NSS_STATUS_SUCCESS; + + buf[HEXKEYBYTES] = 0; + strcpy (skey, buf); + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nss/nss_files/files-netgrp.c b/REORG.TODO/nss/nss_files/files-netgrp.c new file mode 100644 index 0000000000..009ce02432 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-netgrp.c @@ -0,0 +1,294 @@ +/* Netgroup file parser in nss_files modules. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include "nsswitch.h" +#include "netgroup.h" + +#define DATAFILE "/etc/netgroup" + +libnss_files_hidden_proto (_nss_files_endnetgrent) + +#define EXPAND(needed) \ + do \ + { \ + size_t old_cursor = result->cursor - result->data; \ + void *old_data = result->data; \ + \ + result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \ + result->data = realloc (result->data, result->data_size); \ + \ + if (result->data == NULL) \ + { \ + free (old_data); \ + status = NSS_STATUS_UNAVAIL; \ + goto the_end; \ + } \ + \ + result->cursor = result->data + old_cursor; \ + } \ + while (0) + + +enum nss_status +_nss_files_setnetgrent (const char *group, struct __netgrent *result) +{ + FILE *fp; + enum nss_status status; + + if (group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + /* Find the netgroups file and open it. */ + fp = fopen (DATAFILE, "rce"); + if (fp == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* Read the file line by line and try to find the description + GROUP. We must take care for long lines. */ + char *line = NULL; + size_t line_len = 0; + const ssize_t group_len = strlen (group); + + status = NSS_STATUS_NOTFOUND; + result->cursor = result->data; + + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + while (!feof_unlocked (fp)) + { + ssize_t curlen = getline (&line, &line_len, fp); + int found; + + if (curlen < 0) + { + status = NSS_STATUS_NOTFOUND; + break; + } + + found = (curlen > group_len && strncmp (line, group, group_len) == 0 + && isspace (line[group_len])); + + /* Read the whole line (including continuation) and store it + if FOUND in nonzero. Otherwise we don't need it. */ + if (found) + { + /* Store the data from the first line. */ + EXPAND (curlen - group_len); + memcpy (result->cursor, &line[group_len + 1], + curlen - group_len); + result->cursor += (curlen - group_len) - 1; + } + + while (curlen > 1 && line[curlen - 1] == '\n' + && line[curlen - 2] == '\\') + { + /* Yes, we have a continuation line. */ + if (found) + /* Remove these characters from the stored line. */ + result->cursor -= 2; + + /* Get next line. */ + curlen = getline (&line, &line_len, fp); + if (curlen <= 0) + break; + + if (found) + { + /* Make sure we have enough room. */ + EXPAND (1 + curlen + 1); + + /* Add separator in case next line starts immediately. */ + *result->cursor++ = ' '; + + /* Copy new line. */ + memcpy (result->cursor, line, curlen + 1); + result->cursor += curlen; + } + } + + if (found) + { + /* Now we have read the line. */ + status = NSS_STATUS_SUCCESS; + result->cursor = result->data; + result->first = 1; + break; + } + } + + the_end: + /* We don't need the file and the line buffer anymore. */ + free (line); + fclose (fp); + + if (status != NSS_STATUS_SUCCESS) + _nss_files_endnetgrent (result); + } + + return status; +} + + +enum nss_status +_nss_files_endnetgrent (struct __netgrent *result) +{ + /* Free allocated memory for data if some is present. */ + free (result->data); + result->data = NULL; + result->data_size = 0; + result->cursor = NULL; + return NSS_STATUS_SUCCESS; +} +libnss_files_hidden_def (_nss_files_endnetgrent) + +static char * +strip_whitespace (char *str) +{ + char *cp = str; + + /* Skip leading spaces. */ + while (isspace (*cp)) + cp++; + + str = cp; + while (*cp != '\0' && ! isspace(*cp)) + cp++; + + /* Null-terminate, stripping off any trailing spaces. */ + *cp = '\0'; + + return *str == '\0' ? NULL : str; +} + +enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *result, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status status; + const char *host, *user, *domain; + char *cp = *cursor; + + /* Some sanity checks. */ + if (cp == NULL) + return NSS_STATUS_NOTFOUND; + + /* First skip leading spaces. */ + while (isspace (*cp)) + ++cp; + + if (*cp != '(') + { + /* We have a list of other netgroups. */ + char *name = cp; + + while (*cp != '\0' && ! isspace (*cp)) + ++cp; + + if (name != cp) + { + /* It is another netgroup name. */ + int last = *cp == '\0'; + + result->type = group_val; + result->val.group = name; + *cp = '\0'; + if (! last) + ++cp; + *cursor = cp; + result->first = 0; + + return NSS_STATUS_SUCCESS; + } + + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + } + + /* Match host name. */ + host = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match user name. */ + user = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match domain name. */ + domain = ++cp; + while (*cp != ')') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + ++cp; + + + /* When we got here we have found an entry. Before we can copy it + to the private buffer we have to make sure it is big enough. */ + if (cp - host > buflen) + { + *errnop = ERANGE; + status = NSS_STATUS_TRYAGAIN; + } + else + { + memcpy (buffer, host, cp - host); + result->type = triple_val; + + buffer[(user - host) - 1] = '\0'; /* Replace ',' with '\0'. */ + result->val.triple.host = strip_whitespace (buffer); + + buffer[(domain - host) - 1] = '\0'; /* Replace ',' with '\0'. */ + result->val.triple.user = strip_whitespace (buffer + (user - host)); + + buffer[(cp - host) - 1] = '\0'; /* Replace ')' with '\0'. */ + result->val.triple.domain = strip_whitespace (buffer + (domain - host)); + + status = NSS_STATUS_SUCCESS; + + /* Remember where we stopped reading. */ + *cursor = cp; + + result->first = 0; + } + + return status; +} +libnss_files_hidden_def (_nss_netgroup_parseline) + + +enum nss_status +_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status status; + + status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, + errnop); + + return status; +} diff --git a/REORG.TODO/nss/nss_files/files-network.c b/REORG.TODO/nss/nss_files/files-network.c new file mode 100644 index 0000000000..1fbd60fcf2 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-network.c @@ -0,0 +1,88 @@ +/* Networks file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdint.h> + +#define ENTNAME netent +#define DATABASE "networks" +#define NEED_H_ERRNO + +struct netent_data {}; + +#define TRAILING_LIST_MEMBER n_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + char *cp; + int n = 1; + + STRING_FIELD (result->n_name, isspace, 1); + + STRING_FIELD (addr, isspace, 1); + /* 'inet_network' does not add zeroes at the end if the network number + does not four byte values. We add them outselves if necessary. */ + cp = strchr (addr, '.'); + if (cp != NULL) + { + ++n; + cp = strchr (cp + 1, '.'); + if (cp != NULL) + { + ++n; + cp = strchr (cp + 1, '.'); + if (cp != NULL) + ++n; + } + } + if (n < 4) + { + char *newp = (char *) alloca (strlen (addr) + (4 - n) * 2 + 1); + cp = stpcpy (newp, addr); + do + { + *cp++ = '.'; + *cp++ = '0'; + } + while (++n < 4); + *cp = '\0'; + addr = newp; + } + result->n_net = inet_network (addr); + result->n_addrtype = AF_INET; + + }) + +#include "files-XXX.c" + +DB_LOOKUP (netbyname, ,,, + LOOKUP_NAME_CASE (n_name, n_aliases), + const char *name) + +DB_LOOKUP (netbyaddr, ,,, + { + if ((type == AF_UNSPEC || result->n_addrtype == type) + && result->n_net == net) + /* Bingo! */ + break; + }, uint32_t net, int type) diff --git a/REORG.TODO/nss/nss_files/files-parse.c b/REORG.TODO/nss/nss_files/files-parse.c new file mode 100644 index 0000000000..b31ff9e17b --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-parse.c @@ -0,0 +1,335 @@ +/* Common code for file-based database parsers in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store + things pointed to by the resultant `struct STRUCTURE'. + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + EXTRA_ARGS -- defined iff extra parameters must be passed to the parser + EXTRA_ARGS_DECL -- declaration for these extra parameters + EXTRA_ARGS_VALUE -- values to be passed for these parameters + + Also see files-XXX.c. */ + +#ifndef EXTRA_ARGS +# define EXTRA_ARGS +# define EXTRA_ARGS_DECL +# define EXTRA_ARGS_VALUE +#endif + +#define CONCAT(a,b) CONCAT1(a,b) +#define CONCAT1(a,b) a##b + +#ifndef STRUCTURE +# define STRUCTURE ENTNAME +#endif + + +struct parser_data + { +#ifdef ENTDATA + struct ENTDATA entdata; +# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; +#else +# define ENTDATA_DECL(data) +#endif + char linebuffer[0]; + }; + +#ifdef ENTDATA +/* The function can't be exported, because the entdata structure + is defined only in files-foo.c. */ +# define parser_stclass static +# define nss_files_parse_hidden_def(name) +#else +/* Export the line parser function so it can be used in nss_db. */ +# define parser_stclass /* Global */ +# define parse_line CONCAT(_nss_files_parse_,ENTNAME) +# if IS_IN (libc) +/* We are defining one of the functions that actually lives in libc + because it is used to implement fget*ent and suchlike. */ +# define nss_files_parse_hidden_def(name) libc_hidden_def (name) +# else +# define nss_files_parse_hidden_def(name) libnss_files_hidden_def (name) +# endif +#endif + + +#ifdef EXTERN_PARSER + +/* The parser is defined in a different module. */ +extern int parse_line (char *line, struct STRUCTURE *result, + struct parser_data *data, size_t datalen, int *errnop + EXTRA_ARGS_DECL); + +# define LINE_PARSER(EOLSET, BODY) /* Do nothing */ + +#else + +/* Define a line parsing function. */ + +# define LINE_PARSER(EOLSET, BODY) \ +parser_stclass int \ +parse_line (char *line, struct STRUCTURE *result, \ + struct parser_data *data, size_t datalen, int *errnop \ + EXTRA_ARGS_DECL) \ +{ \ + ENTDATA_DECL (data) \ + BUFFER_PREPARE \ + char *p = strpbrk (line, EOLSET "\n"); \ + if (p != NULL) \ + *p = '\0'; \ + BODY; \ + TRAILING_LIST_PARSER; \ + return 1; \ +} \ +nss_files_parse_hidden_def (parse_line) + + +# define STRING_FIELD(variable, terminator_p, swallow) \ + { \ + variable = line; \ + while (*line != '\0' && !terminator_p (*line)) \ + ++line; \ + if (*line != '\0') \ + { \ + *line = '\0'; \ + do \ + ++line; \ + while (swallow && terminator_p (*line)); \ + } \ + } + +# define STRING_LIST(variable, terminator_c) \ + { \ + char **list = parse_list (&line, buf_start, buf_end, terminator_c, \ + errnop); \ + if (list) \ + variable = list; \ + else \ + return -1; /* -1 indicates we ran out of space. */ \ + \ + /* Determine the new end of the buffer. */ \ + while (*list != NULL) \ + ++list; \ + buf_start = (char *) (list + 1); \ + } + +/* Helper function. */ +static inline uint32_t +__attribute__ ((always_inline)) +strtou32 (const char *nptr, char **endptr, int base) +{ + unsigned long int val = strtoul (nptr, endptr, base); + + /* Match the 32-bit behavior on 64-bit platforms. */ + if (sizeof (long int) > 4 && val > 0xffffffff) + val = 0xffffffff; + + return val; +} + +# define INT_FIELD(variable, terminator_p, swallow, base, convert) \ + { \ + char *endp; \ + variable = convert (strtou32 (line, &endp, base)); \ + if (endp == line) \ + return 0; \ + else if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ + { \ + char *endp; \ + if (*line == '\0') \ + /* We expect some more input, so don't allow the string to end here. */ \ + return 0; \ + variable = convert (strtou32 (line, &endp, base)); \ + if (endp == line) \ + variable = default; \ + if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define ISCOLON(c) ((c) == ':') + + +# ifndef TRAILING_LIST_MEMBER +# define BUFFER_PREPARE /* Nothing to do. */ +# define TRAILING_LIST_PARSER /* Nothing to do. */ +# else + +# define BUFFER_PREPARE \ + char *buf_start = NULL; \ + char *buf_end = (char *) data + datalen; \ + if (line >= data->linebuffer && line < buf_end) \ + /* Find the end of the line buffer, we will use the space in \ + DATA after it for storing the vector of pointers. */ \ + buf_start = strchr (line, '\0') + 1; \ + else \ + /* LINE does not point within DATA->linebuffer, so that space is \ + not being used for scratch space right now. We can use all of \ + it for the pointer vector storage. */ \ + buf_start = data->linebuffer; \ + +# define TRAILING_LIST_PARSER \ +{ \ + if (buf_start == NULL) \ + { \ + if (line >= data->linebuffer && line < buf_end) \ + /* Find the end of the line buffer, we will use the space in \ + DATA after it for storing the vector of pointers. */ \ + buf_start = strchr (line, '\0') + 1; \ + else \ + /* LINE does not point within DATA->linebuffer, so that space is \ + not being used for scratch space right now. We can use all of \ + it for the pointer vector storage. */ \ + buf_start = data->linebuffer; \ + } \ + \ + char **list = parse_list (&line, buf_start, buf_end, '\0', errnop); \ + if (list) \ + result->TRAILING_LIST_MEMBER = list; \ + else \ + return -1; /* -1 indicates we ran out of space. */ \ +} + +static inline char ** +__attribute ((always_inline)) +parse_list (char **linep, char *eol, char *buf_end, int terminator_c, + int *errnop) +{ + char *line = *linep; + char **list, **p; + + /* Adjust the pointer so it is aligned for storing pointers. */ + eol += __alignof__ (char *) - 1; + eol -= (eol - (char *) 0) % __alignof__ (char *); + /* We will start the storage here for the vector of pointers. */ + list = (char **) eol; + + p = list; + while (1) + { + if ((char *) (p + 2) > buf_end) + { + /* We cannot fit another pointer in the buffer. */ + *errnop = ERANGE; + return NULL; + } + + if (*line == '\0') + break; + if (*line == terminator_c) + { + ++line; + break; + } + + /* Skip leading white space. This might not be portable but useful. */ + while (isspace (*line)) + ++line; + + char *elt = line; + while (1) + { + if (*line == '\0' || *line == terminator_c + || TRAILING_LIST_SEPARATOR_P (*line)) + { + /* End of the next entry. */ + if (line > elt) + /* We really found some data. */ + *p++ = elt; + + /* Terminate string if necessary. */ + if (*line != '\0') + { + char endc = *line; + *line++ = '\0'; + if (endc == terminator_c) + goto out; + } + break; + } + ++line; + } + } + out: + *p = NULL; + *linep = line; + + return list; +} + +# endif /* TRAILING_LIST_MEMBER */ +#endif /* EXTERN_PARSER */ + + +#define LOOKUP_NAME(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! strcmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! strcmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + +#define LOOKUP_NAME_CASE(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! __strcasecmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! __strcasecmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + + +/* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead. */ +#ifndef GENERIC +# define GENERIC "files-XXX.c" +#endif diff --git a/REORG.TODO/nss/nss_files/files-proto.c b/REORG.TODO/nss/nss_files/files-proto.c new file mode 100644 index 0000000000..5402a7a300 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-proto.c @@ -0,0 +1,46 @@ +/* Protocols file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <netdb.h> + + +#define ENTNAME protoent +#define DATABASE "protocols" + +struct protoent_data {}; + +#define TRAILING_LIST_MEMBER p_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->p_name, isspace, 1); + INT_FIELD (result->p_proto, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (protobyname, '.', 0, ("%s", name), + LOOKUP_NAME (p_name, p_aliases), + const char *name) + +DB_LOOKUP (protobynumber, '=', 20, ("%zd", (ssize_t) proto), + { + if (result->p_proto == proto) + break; + }, int proto) diff --git a/REORG.TODO/nss/nss_files/files-pwd.c b/REORG.TODO/nss/nss_files/files-pwd.c new file mode 100644 index 0000000000..62c597703a --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-pwd.c @@ -0,0 +1,44 @@ +/* User file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <pwd.h> + +#define STRUCTURE passwd +#define ENTNAME pwent +#define DATABASE "passwd" +struct pwent_data {}; + +/* Our parser function is already defined in fgetpwent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (pwnam, '.', 0, ("%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->pw_name)) + break; + }, const char *name) + +DB_LOOKUP (pwuid, '=', 20, ("%lu", (unsigned long int) uid), + { + if (result->pw_uid == uid && result->pw_name[0] != '+' + && result->pw_name[0] != '-') + break; + }, uid_t uid) diff --git a/REORG.TODO/nss/nss_files/files-rpc.c b/REORG.TODO/nss/nss_files/files-rpc.c new file mode 100644 index 0000000000..8ee0d19f32 --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-rpc.c @@ -0,0 +1,46 @@ +/* SunRPC program number file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <rpc/netdb.h> + + +#define ENTNAME rpcent +#define DATABASE "rpc" + +struct rpcent_data {}; + +#define TRAILING_LIST_MEMBER r_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->r_name, isspace, 1); + INT_FIELD (result->r_number, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (rpcbyname, '.', 0, ("%s", name), + LOOKUP_NAME (r_name, r_aliases), + const char *name) + +DB_LOOKUP (rpcbynumber, '=', 20, ("%zd", (ssize_t) number), + { + if (result->r_number == number) + break; + }, int number) diff --git a/REORG.TODO/nss/nss_files/files-service.c b/REORG.TODO/nss/nss_files/files-service.c new file mode 100644 index 0000000000..b6ae51082f --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-service.c @@ -0,0 +1,63 @@ +/* Services file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <netinet/in.h> +#include <netdb.h> + + +#define ENTNAME servent +#define DATABASE "services" + +struct servent_data {}; + +#define TRAILING_LIST_MEMBER s_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +#define ISSLASH(c) ((c) == '/') +LINE_PARSER +("#", + STRING_FIELD (result->s_name, isspace, 1); + INT_FIELD (result->s_port, ISSLASH, 10, 0, htons); + STRING_FIELD (result->s_proto, isspace, 1); + ) + +#include GENERIC + +DB_LOOKUP (servbyname, ':', + strlen (name) + 2 + (proto == NULL ? 0 : strlen (proto)), + ("%s/%s", name, proto ?: ""), + { + /* Must match both protocol (if specified) and name. */ + if (proto != NULL && strcmp (result->s_proto, proto)) + /* A continue statement here breaks nss_db, because it + bypasses advancing to the next db entry, and it + doesn't make nss_files any more efficient. */; + else + LOOKUP_NAME (s_name, s_aliases) + }, + const char *name, const char *proto) + +DB_LOOKUP (servbyport, '=', 21 + (proto ? strlen (proto) : 0), + ("%zd/%s", (ssize_t) ntohs (port), proto ?: ""), + { + /* Must match both port and protocol. */ + if (result->s_port == port + && (proto == NULL + || strcmp (result->s_proto, proto) == 0)) + break; + }, int port, const char *proto) diff --git a/REORG.TODO/nss/nss_files/files-sgrp.c b/REORG.TODO/nss/nss_files/files-sgrp.c new file mode 100644 index 0000000000..03b7da5e2f --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-sgrp.c @@ -0,0 +1,37 @@ +/* User file parser in nss_files module. + Copyright (C) 2009-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 + <http://www.gnu.org/licenses/>. */ + +#include <gshadow.h> + +#define STRUCTURE sgrp +#define ENTNAME sgent +#define DATABASE "gshadow" +struct sgent_data {}; + +/* Our parser function is already defined in sgetspent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (sgnam, '.', 0, ("%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->sg_namp)) + break; + }, const char *name) diff --git a/REORG.TODO/nss/nss_files/files-spwd.c b/REORG.TODO/nss/nss_files/files-spwd.c new file mode 100644 index 0000000000..7f13562acb --- /dev/null +++ b/REORG.TODO/nss/nss_files/files-spwd.c @@ -0,0 +1,37 @@ +/* User file parser in nss_files module. + Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#include <shadow.h> + +#define STRUCTURE spwd +#define ENTNAME spent +#define DATABASE "shadow" +struct spent_data {}; + +/* Our parser function is already defined in sgetspent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (spnam, '.', 0, ("%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->sp_namp)) + break; + }, const char *name) diff --git a/REORG.TODO/nss/nss_test1.c b/REORG.TODO/nss/nss_test1.c new file mode 100644 index 0000000000..3beb488fcf --- /dev/null +++ b/REORG.TODO/nss/nss_test1.c @@ -0,0 +1,154 @@ +#include <errno.h> +#include <nss.h> +#include <pthread.h> +#include <string.h> + + +#define COPY_IF_ROOM(s) \ + ({ size_t len_ = strlen (s) + 1; \ + char *start_ = cp; \ + buflen - (cp - buffer) < len_ \ + ? NULL \ + : (cp = mempcpy (cp, s, len_), start_); }) + + +/* Password handling. */ +#include <pwd.h> + +static struct passwd pwd_data[] = + { +#define PWD(u) \ + { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u, \ + .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*", \ + .pw_shell = (char *) "*" } + PWD (100), + PWD (30), + PWD (200), + PWD (60), + PWD (20000) + }; +#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0])) + +static size_t pwd_iter; +#define CURPWD pwd_data[pwd_iter] + +static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER; + + +enum nss_status +_nss_test1_setpwent (int stayopen) +{ + pwd_iter = 0; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_test1_endpwent (void) +{ + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen, + int *errnop) +{ + char *cp = buffer; + int res = NSS_STATUS_SUCCESS; + + pthread_mutex_lock (&pwd_lock); + + if (pwd_iter >= npwd_data) + res = NSS_STATUS_NOTFOUND; + else + { + result->pw_name = COPY_IF_ROOM (CURPWD.pw_name); + result->pw_passwd = COPY_IF_ROOM (CURPWD.pw_passwd); + result->pw_uid = CURPWD.pw_uid; + result->pw_gid = CURPWD.pw_gid; + result->pw_gecos = COPY_IF_ROOM (CURPWD.pw_gecos); + result->pw_dir = COPY_IF_ROOM (CURPWD.pw_dir); + result->pw_shell = COPY_IF_ROOM (CURPWD.pw_shell); + + if (result->pw_name == NULL || result->pw_passwd == NULL + || result->pw_gecos == NULL || result->pw_dir == NULL + || result->pw_shell == NULL) + { + *errnop = ERANGE; + res = NSS_STATUS_TRYAGAIN; + } + + ++pwd_iter; + } + + pthread_mutex_unlock (&pwd_lock); + + return res; +} + + +enum nss_status +_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer, + size_t buflen, int *errnop) +{ + for (size_t idx = 0; idx < npwd_data; ++idx) + if (pwd_data[idx].pw_uid == uid) + { + char *cp = buffer; + int res = NSS_STATUS_SUCCESS; + + result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name); + result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd); + result->pw_uid = pwd_data[idx].pw_uid; + result->pw_gid = pwd_data[idx].pw_gid; + result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos); + result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir); + result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell); + + if (result->pw_name == NULL || result->pw_passwd == NULL + || result->pw_gecos == NULL || result->pw_dir == NULL + || result->pw_shell == NULL) + { + *errnop = ERANGE; + res = NSS_STATUS_TRYAGAIN; + } + + return res; + } + + return NSS_STATUS_NOTFOUND; +} + + +enum nss_status +_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer, + size_t buflen, int *errnop) +{ + for (size_t idx = 0; idx < npwd_data; ++idx) + if (strcmp (pwd_data[idx].pw_name, name) == 0) + { + char *cp = buffer; + int res = NSS_STATUS_SUCCESS; + + result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name); + result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd); + result->pw_uid = pwd_data[idx].pw_uid; + result->pw_gid = pwd_data[idx].pw_gid; + result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos); + result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir); + result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell); + + if (result->pw_name == NULL || result->pw_passwd == NULL + || result->pw_gecos == NULL || result->pw_dir == NULL + || result->pw_shell == NULL) + { + *errnop = ERANGE; + res = NSS_STATUS_TRYAGAIN; + } + + return res; + } + + return NSS_STATUS_NOTFOUND; +} diff --git a/REORG.TODO/nss/nsswitch.c b/REORG.TODO/nss/nsswitch.c new file mode 100644 index 0000000000..8f31658523 --- /dev/null +++ b/REORG.TODO/nss/nsswitch.c @@ -0,0 +1,931 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <dlfcn.h> +#include <errno.h> +#include <netdb.h> +#include <libc-lock.h> +#include <search.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> + +#include <aliases.h> +#include <grp.h> +#include <netinet/ether.h> +#include <pwd.h> +#include <shadow.h> + +#if !defined DO_STATIC_NSS || defined SHARED +# include <gnu/lib-names.h> +#endif + +#include "nsswitch.h" +#include "../nscd/nscd_proto.h" +#include <sysdep.h> + +/* Prototypes for the local functions. */ +static name_database *nss_parse_file (const char *fname) internal_function; +static name_database_entry *nss_getline (char *line) internal_function; +static service_user *nss_parse_service_list (const char *line) + internal_function; +#if !defined DO_STATIC_NSS || defined SHARED +static service_library *nss_new_service (name_database *database, + const char *name) internal_function; +#endif + + +/* Declare external database variables. */ +#define DEFINE_DATABASE(name) \ + extern service_user *__nss_##name##_database attribute_hidden; \ + weak_extern (__nss_##name##_database) +#include "databases.def" +#undef DEFINE_DATABASE + +/* Structure to map database name to variable. */ +static const struct +{ + const char name[10]; + service_user **dbp; +} databases[] = +{ +#define DEFINE_DATABASE(name) \ + { #name, &__nss_##name##_database }, +#include "databases.def" +#undef DEFINE_DATABASE +}; +#define ndatabases (sizeof (databases) / sizeof (databases[0])) + +/* Flags whether custom rules for database is set. */ +bool __nss_database_custom[NSS_DBSIDX_max]; + + +__libc_lock_define_initialized (static, lock) + +#if !defined DO_STATIC_NSS || defined SHARED +/* String with revision number of the shared object files. */ +static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; +#endif + +/* The root of the whole data base. */ +static name_database *service_table; + +/* List of default service lists that were generated by glibc because + /etc/nsswitch.conf did not provide a value. + The list is only maintained so we can free such service lists in + __libc_freeres. */ +static name_database_entry *defconfig_entries; + + +#if defined USE_NSCD && (!defined DO_STATIC_NSS || defined SHARED) +/* Nonzero if this is the nscd process. */ +static bool is_nscd; +/* The callback passed to the init functions when nscd is used. */ +static void (*nscd_init_cb) (size_t, struct traced_file *); +#endif + + +/* -1 == database not found + 0 == database entry pointer stored */ +int +__nss_database_lookup (const char *database, const char *alternate_name, + const char *defconfig, service_user **ni) +{ + /* Prevent multiple threads to change the service table. */ + __libc_lock_lock (lock); + + /* Reconsider database variable in case some other thread called + `__nss_configure_lookup' while we waited for the lock. */ + if (*ni != NULL) + { + __libc_lock_unlock (lock); + return 0; + } + + /* Are we initialized yet? */ + if (service_table == NULL) + /* Read config file. */ + service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + + /* Test whether configuration data is available. */ + if (service_table != NULL) + { + /* Return first `service_user' entry for DATABASE. */ + name_database_entry *entry; + + /* XXX Could use some faster mechanism here. But each database is + only requested once and so this might not be critical. */ + for (entry = service_table->entry; entry != NULL; entry = entry->next) + if (strcmp (database, entry->name) == 0) + *ni = entry->service; + + if (*ni == NULL && alternate_name != NULL) + /* We haven't found an entry so far. Try to find it with the + alternative name. */ + for (entry = service_table->entry; entry != NULL; entry = entry->next) + if (strcmp (alternate_name, entry->name) == 0) + *ni = entry->service; + } + + /* No configuration data is available, either because nsswitch.conf + doesn't exist or because it doesn't have a line for this database. + + DEFCONFIG specifies the default service list for this database, + or null to use the most common default. */ + if (*ni == NULL) + { + *ni = nss_parse_service_list (defconfig + ?: "nis [NOTFOUND=return] files"); + if (*ni != NULL) + { + /* Record the memory we've just allocated in defconfig_entries list, + so we can free it later. */ + name_database_entry *entry; + + /* Allocate ENTRY plus size of name (1 here). */ + entry = (name_database_entry *) malloc (sizeof (*entry) + 1); + + if (entry != NULL) + { + entry->next = defconfig_entries; + entry->service = *ni; + entry->name[0] = '\0'; + defconfig_entries = entry; + } + } + } + + __libc_lock_unlock (lock); + + return *ni != NULL ? 0 : -1; +} +libc_hidden_def (__nss_database_lookup) + + +/* -1 == not found + 0 == function found + 1 == finished */ +int +__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp) +{ + *fctp = __nss_lookup_function (*ni, fct_name); + if (*fctp == NULL && fct2_name != NULL) + *fctp = __nss_lookup_function (*ni, fct2_name); + + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE + && (*ni)->next != NULL) + { + *ni = (*ni)->next; + + *fctp = __nss_lookup_function (*ni, fct_name); + if (*fctp == NULL && fct2_name != NULL) + *fctp = __nss_lookup_function (*ni, fct2_name); + } + + return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1; +} +libc_hidden_def (__nss_lookup) + + +/* -1 == not found + 0 == adjusted for next function + 1 == finished */ +int +__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp, int status, int all_values) +{ + if (all_values) + { + if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN) + return 1; + } + else + { + /* This is really only for debugging. */ + if (__builtin_expect (NSS_STATUS_TRYAGAIN > status + || status > NSS_STATUS_RETURN, 0)) + __libc_fatal ("illegal status in __nss_next"); + + if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) + return 1; + } + + if ((*ni)->next == NULL) + return -1; + + do + { + *ni = (*ni)->next; + + *fctp = __nss_lookup_function (*ni, fct_name); + if (*fctp == NULL && fct2_name != NULL) + *fctp = __nss_lookup_function (*ni, fct2_name); + } + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE + && (*ni)->next != NULL); + + return *fctp != NULL ? 0 : -1; +} +libc_hidden_def (__nss_next2) + + +int +attribute_compat_text_section +__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, + int all_values) +{ + return __nss_next2 (ni, fct_name, NULL, fctp, status, all_values); +} + + +int +__nss_configure_lookup (const char *dbname, const char *service_line) +{ + service_user *new_db; + size_t cnt; + + for (cnt = 0; cnt < ndatabases; ++cnt) + { + int cmp = strcmp (dbname, databases[cnt].name); + if (cmp == 0) + break; + if (cmp < 0) + { + __set_errno (EINVAL); + return -1; + } + } + + if (cnt == ndatabases) + { + __set_errno (EINVAL); + return -1; + } + + /* Test whether it is really used. */ + if (databases[cnt].dbp == NULL) + /* Nothing to do, but we could do. */ + return 0; + + /* Try to generate new data. */ + new_db = nss_parse_service_list (service_line); + if (new_db == NULL) + { + /* Illegal service specification. */ + __set_errno (EINVAL); + return -1; + } + + /* Prevent multiple threads to change the service table. */ + __libc_lock_lock (lock); + + /* Install new rules. */ + *databases[cnt].dbp = new_db; + __nss_database_custom[cnt] = true; + + __libc_lock_unlock (lock); + + return 0; +} + + +/* Comparison function for searching NI->known tree. */ +static int +known_compare (const void *p1, const void *p2) +{ + return p1 == p2 ? 0 : strcmp (*(const char *const *) p1, + *(const char *const *) p2); +} + + +#if !defined DO_STATIC_NSS || defined SHARED +/* Load library. */ +static int +nss_load_library (service_user *ni) +{ + if (ni->library == NULL) + { + /* This service has not yet been used. Fetch the service + library for it, creating a new one if need be. If there + is no service table from the file, this static variable + holds the head of the service_library list made from the + default configuration. */ + static name_database default_table; + ni->library = nss_new_service (service_table ?: &default_table, + ni->name); + if (ni->library == NULL) + return -1; + } + + if (ni->library->lib_handle == NULL) + { + /* Load the shared library. */ + size_t shlen = (7 + strlen (ni->name) + 3 + + strlen (__nss_shlib_revision) + 1); + int saved_errno = errno; + char shlib_name[shlen]; + + /* Construct shared object name. */ + __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, + "libnss_"), + ni->name), + ".so"), + __nss_shlib_revision); + + ni->library->lib_handle = __libc_dlopen (shlib_name); + if (ni->library->lib_handle == NULL) + { + /* Failed to load the library. */ + ni->library->lib_handle = (void *) -1l; + __set_errno (saved_errno); + } +# ifdef USE_NSCD + else if (is_nscd) + { + /* Call the init function when nscd is used. */ + size_t initlen = (5 + strlen (ni->name) + + strlen ("_init") + 1); + char init_name[initlen]; + + /* Construct the init function name. */ + __stpcpy (__stpcpy (__stpcpy (init_name, + "_nss_"), + ni->name), + "_init"); + + /* Find the optional init function. */ + void (*ifct) (void (*) (size_t, struct traced_file *)) + = __libc_dlsym (ni->library->lib_handle, init_name); + if (ifct != NULL) + { + void (*cb) (size_t, struct traced_file *) = nscd_init_cb; +# ifdef PTR_DEMANGLE + PTR_DEMANGLE (cb); +# endif + ifct (cb); + } + } +# endif + } + + return 0; +} +#endif + + +void * +__nss_lookup_function (service_user *ni, const char *fct_name) +{ + void **found, *result; + + /* We now modify global data. Protect it. */ + __libc_lock_lock (lock); + + /* Search the tree of functions previously requested. Data in the + tree are `known_function' structures, whose first member is a + `const char *', the lookup key. The search returns a pointer to + the tree node structure; the first member of the is a pointer to + our structure (i.e. what will be a `known_function'); since the + first member of that is the lookup key string, &FCT_NAME is close + enough to a pointer to our structure to use as a lookup key that + will be passed to `known_compare' (above). */ + + found = __tsearch (&fct_name, &ni->known, &known_compare); + if (found == NULL) + /* This means out-of-memory. */ + result = NULL; + else if (*found != &fct_name) + { + /* The search found an existing structure in the tree. */ + result = ((known_function *) *found)->fct_ptr; +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (result); +#endif + } + else + { + /* This name was not known before. Now we have a node in the tree + (in the proper sorted position for FCT_NAME) that points to + &FCT_NAME instead of any real `known_function' structure. + Allocate a new structure and fill it in. */ + + known_function *known = malloc (sizeof *known); + if (! known) + { +#if !defined DO_STATIC_NSS || defined SHARED + remove_from_tree: +#endif + /* Oops. We can't instantiate this node properly. + Remove it from the tree. */ + __tdelete (&fct_name, &ni->known, &known_compare); + free (known); + result = NULL; + } + else + { + /* Point the tree node at this new structure. */ + *found = known; + known->fct_name = fct_name; + +#if !defined DO_STATIC_NSS || defined SHARED + /* Load the appropriate library. */ + if (nss_load_library (ni) != 0) + /* This only happens when out of memory. */ + goto remove_from_tree; + + if (ni->library->lib_handle == (void *) -1l) + /* Library not found => function not found. */ + result = NULL; + else + { + /* Get the desired function. */ + size_t namlen = (5 + strlen (ni->name) + 1 + + strlen (fct_name) + 1); + char name[namlen]; + + /* Construct the function name. */ + __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), + ni->name), + "_"), + fct_name); + + /* Look up the symbol. */ + result = __libc_dlsym (ni->library->lib_handle, name); + } +#else + /* We can't get function address dynamically in static linking. */ + { +# define DEFINE_ENT(h,nm) \ + { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ + { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ + { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, +# define DEFINE_GET(h,nm) \ + { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, +# define DEFINE_GETBY(h,nm,ky) \ + { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, + static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = + { +# include "function.def" + { NULL, NULL } + }; + size_t namlen = (5 + strlen (ni->name) + 1 + + strlen (fct_name) + 1); + char name[namlen]; + + /* Construct the function name. */ + __stpcpy (__stpcpy (__stpcpy (name, ni->name), + "_"), + fct_name); + + result = NULL; + for (tp = &tbl[0]; tp->fname; tp++) + if (strcmp (tp->fname, name) == 0) + { + result = tp->fp; + break; + } + } +#endif + + /* Remember function pointer for later calls. Even if null, we + record it so a second try needn't search the library again. */ + known->fct_ptr = result; +#ifdef PTR_MANGLE + PTR_MANGLE (known->fct_ptr); +#endif + } + } + + /* Remove the lock. */ + __libc_lock_unlock (lock); + + return result; +} +libc_hidden_def (__nss_lookup_function) + + +static name_database * +internal_function +nss_parse_file (const char *fname) +{ + FILE *fp; + name_database *result; + name_database_entry *last; + char *line; + size_t len; + + /* Open the configuration file. */ + fp = fopen (fname, "rce"); + if (fp == NULL) + return NULL; + + /* No threads use this stream. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + result = (name_database *) malloc (sizeof (name_database)); + if (result == NULL) + { + fclose (fp); + return NULL; + } + + result->entry = NULL; + result->library = NULL; + last = NULL; + line = NULL; + len = 0; + do + { + name_database_entry *this; + ssize_t n; + + n = __getline (&line, &len, fp); + if (n < 0) + break; + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + *__strchrnul (line, '#') = '\0'; + + /* If the line is blank it is ignored. */ + if (line[0] == '\0') + continue; + + /* Each line completely specifies the actions for a database. */ + this = nss_getline (line); + if (this != NULL) + { + if (last != NULL) + last->next = this; + else + result->entry = this; + + last = this; + } + } + while (!feof_unlocked (fp)); + + /* Free the buffer. */ + free (line); + /* Close configuration file. */ + fclose (fp); + + return result; +} + + +/* Read the source names: + `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*' + */ +static service_user * +internal_function +nss_parse_service_list (const char *line) +{ + service_user *result = NULL, **nextp = &result; + + while (1) + { + service_user *new_service; + const char *name; + + while (isspace (line[0])) + ++line; + if (line[0] == '\0') + /* No source specified. */ + return result; + + /* Read <source> identifier. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') + ++line; + if (name == line) + return result; + + + new_service = (service_user *) malloc (sizeof (service_user) + + (line - name + 1)); + if (new_service == NULL) + return result; + + *((char *) __mempcpy (new_service->name, name, line - name)) = '\0'; + + /* Set default actions. */ + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; + new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN; + new_service->library = NULL; + new_service->known = NULL; + new_service->next = NULL; + + while (isspace (line[0])) + ++line; + + if (line[0] == '[') + { + /* Read criterions. */ + do + ++line; + while (line[0] != '\0' && isspace (line[0])); + + do + { + int not; + enum nss_status status; + lookup_actions action; + + /* Grok ! before name to mean all statii but that one. */ + not = line[0] == '!'; + if (not) + ++line; + + /* Read status name. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + /* Compare with known statii. */ + if (line - name == 7) + { + if (__strncasecmp (name, "SUCCESS", 7) == 0) + status = NSS_STATUS_SUCCESS; + else if (__strncasecmp (name, "UNAVAIL", 7) == 0) + status = NSS_STATUS_UNAVAIL; + else + goto finish; + } + else if (line - name == 8) + { + if (__strncasecmp (name, "NOTFOUND", 8) == 0) + status = NSS_STATUS_NOTFOUND; + else if (__strncasecmp (name, "TRYAGAIN", 8) == 0) + status = NSS_STATUS_TRYAGAIN; + else + goto finish; + } + else + goto finish; + + while (isspace (line[0])) + ++line; + if (line[0] != '=') + goto finish; + do + ++line; + while (isspace (line[0])); + + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0) + action = NSS_ACTION_RETURN; + else if (line - name == 8 + && __strncasecmp (name, "CONTINUE", 8) == 0) + action = NSS_ACTION_CONTINUE; + else if (line - name == 5 + && __strncasecmp (name, "MERGE", 5) == 0) + action = NSS_ACTION_MERGE; + else + goto finish; + + if (not) + { + /* Save the current action setting for this status, + set them all to the given action, and reset this one. */ + const lookup_actions save = new_service->actions[2 + status]; + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action; + new_service->actions[2 + NSS_STATUS_UNAVAIL] = action; + new_service->actions[2 + NSS_STATUS_NOTFOUND] = action; + new_service->actions[2 + NSS_STATUS_SUCCESS] = action; + new_service->actions[2 + status] = save; + } + else + new_service->actions[2 + status] = action; + + /* Skip white spaces. */ + while (isspace (line[0])) + ++line; + } + while (line[0] != ']'); + + /* Skip the ']'. */ + ++line; + } + + *nextp = new_service; + nextp = &new_service->next; + continue; + + finish: + free (new_service); + return result; + } +} + +static name_database_entry * +internal_function +nss_getline (char *line) +{ + const char *name; + name_database_entry *result; + size_t len; + + /* Ignore leading white spaces. ATTENTION: this is different from + what is implemented in Solaris. The Solaris man page says a line + beginning with a white space character is ignored. We regard + this as just another misfeature in Solaris. */ + while (isspace (line[0])) + ++line; + + /* Recognize `<database> ":"'. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') + ++line; + if (line[0] == '\0' || name == line) + /* Syntax error. */ + return NULL; + *line++ = '\0'; + + len = strlen (name) + 1; + + result = (name_database_entry *) malloc (sizeof (name_database_entry) + len); + if (result == NULL) + return NULL; + + /* Save the database name. */ + memcpy (result->name, name, len); + + /* Parse the list of services. */ + result->service = nss_parse_service_list (line); + + result->next = NULL; + return result; +} + + +#if !defined DO_STATIC_NSS || defined SHARED +static service_library * +internal_function +nss_new_service (name_database *database, const char *name) +{ + service_library **currentp = &database->library; + + while (*currentp != NULL) + { + if (strcmp ((*currentp)->name, name) == 0) + return *currentp; + currentp = &(*currentp)->next; + } + + /* We have to add the new service. */ + *currentp = (service_library *) malloc (sizeof (service_library)); + if (*currentp == NULL) + return NULL; + + (*currentp)->name = name; + (*currentp)->lib_handle = NULL; + (*currentp)->next = NULL; + + return *currentp; +} +#endif + + +#if defined SHARED && defined USE_NSCD +/* Load all libraries for the service. */ +static void +nss_load_all_libraries (const char *service, const char *def) +{ + service_user *ni = NULL; + + if (__nss_database_lookup (service, NULL, def, &ni) == 0) + while (ni != NULL) + { + nss_load_library (ni); + ni = ni->next; + } +} + + +/* Called by nscd and nscd alone. */ +void +__nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) +{ +# ifdef PTR_MANGLE + PTR_MANGLE (cb); +# endif + nscd_init_cb = cb; + 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 ("hosts", "dns [!UNAVAIL=return] files"); + nss_load_all_libraries ("services", NULL); + + /* Disable all uses of NSCD. */ + __nss_not_use_nscd_passwd = -1; + __nss_not_use_nscd_group = -1; + __nss_not_use_nscd_hosts = -1; + __nss_not_use_nscd_services = -1; + __nss_not_use_nscd_netgroup = -1; +} +#endif + +static void +free_database_entries (name_database_entry *entry) +{ + while (entry != NULL) + { + name_database_entry *olde = entry; + service_user *service = entry->service; + + while (service != NULL) + { + service_user *olds = service; + + if (service->known != NULL) + __tdestroy (service->known, free); + + service = service->next; + free (olds); + } + + entry = entry->next; + free (olde); + } +} + +/* Free all resources if necessary. */ +libc_freeres_fn (free_defconfig) +{ + name_database_entry *entry = defconfig_entries; + + if (entry == NULL) + /* defconfig was not used. */ + return; + + /* Don't disturb ongoing other threads (if there are any). */ + defconfig_entries = NULL; + + free_database_entries (entry); +} + +libc_freeres_fn (free_mem) +{ + name_database *top = service_table; + service_library *library; + + if (top == NULL) + /* Maybe we have not read the nsswitch.conf file. */ + return; + + /* Don't disturb ongoing other threads (if there are any). */ + service_table = NULL; + + free_database_entries (top->entry); + + library = top->library; + while (library != NULL) + { + service_library *oldl = library; + + if (library->lib_handle && library->lib_handle != (void *) -1l) + __libc_dlclose (library->lib_handle); + + library = library->next; + free (oldl); + } + + free (top); +} diff --git a/REORG.TODO/nss/nsswitch.conf b/REORG.TODO/nss/nsswitch.conf new file mode 100644 index 0000000000..39ca88bf51 --- /dev/null +++ b/REORG.TODO/nss/nsswitch.conf @@ -0,0 +1,20 @@ +# /etc/nsswitch.conf +# +# Example configuration of GNU Name Service Switch functionality. +# + +passwd: db files +group: db files +initgroups: db [SUCCESS=continue] files +shadow: db files +gshadow: files + +hosts: files dns +networks: files dns + +protocols: db files +services: db files +ethers: db files +rpc: db files + +netgroup: db files diff --git a/REORG.TODO/nss/nsswitch.h b/REORG.TODO/nss/nsswitch.h new file mode 100644 index 0000000000..f3e756b684 --- /dev/null +++ b/REORG.TODO/nss/nsswitch.h @@ -0,0 +1,213 @@ +/* Copyright (C) 1996-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 + <http://www.gnu.org/licenses/>. */ + +#ifndef _NSSWITCH_H +#define _NSSWITCH_H 1 + +/* This is an *internal* header. */ + +#include <arpa/nameser.h> +#include <netinet/in.h> +#include <nss.h> +#include <resolv.h> +#include <search.h> +#include <dlfcn.h> +#include <stdbool.h> + +/* Actions performed after lookup finished. */ +typedef enum +{ + NSS_ACTION_CONTINUE, + NSS_ACTION_RETURN, + NSS_ACTION_MERGE +} lookup_actions; + + +typedef struct service_library +{ + /* Name of service (`files', `dns', `nis', ...). */ + const char *name; + /* Pointer to the loaded shared library. */ + void *lib_handle; + /* And the link to the next entry. */ + struct service_library *next; +} service_library; + + +/* For mapping a function name to a function pointer. It is known in + nsswitch.c:nss_lookup_function that a string pointer for the lookup key + is the first member. */ +typedef struct +{ + const char *fct_name; + void *fct_ptr; +} known_function; + + +typedef struct service_user +{ + /* And the link to the next entry. */ + struct service_user *next; + /* Action according to result. */ + lookup_actions actions[5]; + /* Link to the underlying library object. */ + service_library *library; + /* Collection of known functions. */ + void *known; + /* Name of the service (`files', `dns', `nis', ...). */ + char name[0]; +} service_user; + +/* To access the action based on the status value use this macro. */ +#define nss_next_action(ni, status) ((ni)->actions[2 + status]) + + +typedef struct name_database_entry +{ + /* And the link to the next entry. */ + struct name_database_entry *next; + /* List of service to be used. */ + service_user *service; + /* Name of the database. */ + char name[0]; +} name_database_entry; + + +typedef struct name_database +{ + /* List of all known databases. */ + name_database_entry *entry; + /* List of libraries with service implementation. */ + service_library *library; +} name_database; + + +/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM. */ +enum + { +#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg, +#include "databases.def" +#undef DEFINE_DATABASE + NSS_DBSIDX_max + }; + +/* Flags whether custom rules for database is set. */ +extern bool __nss_database_custom[NSS_DBSIDX_max]; + +/* Warning for NSS functions, which don't require dlopen if glibc + was built with --enable-static-nss. */ +#ifdef DO_STATIC_NSS +# define nss_interface_function(name) +#else +# define nss_interface_function(name) static_link_warning (name) +#endif + + +/* Interface functions for NSS. */ + +/* Get the data structure representing the specified database. + If there is no configuration for this database in the file, + parse a service list from DEFCONFIG and use that. More + than one function can use the database. */ +extern int __nss_database_lookup (const char *database, + const char *alternative_name, + const char *defconfig, service_user **ni); +libc_hidden_proto (__nss_database_lookup) + +/* Put first function with name FCT_NAME for SERVICE in FCTP. The + position is remembered in NI. The function returns a value < 0 if + an error occurred or no such function exists. */ +extern int __nss_lookup (service_user **ni, const char *fct_name, + const char *fct2_name, void **fctp); +libc_hidden_proto (__nss_lookup) + +/* Determine the next step in the lookup process according to the + result STATUS of the call to the last function returned by + `__nss_lookup' or `__nss_next'. NI specifies the last function + examined. The function return a value > 0 if the process should + stop with the last result of the last function call to be the + result of the entire lookup. The returned value is 0 if there is + another function to use and < 0 if an error occurred. + + If ALL_VALUES is nonzero, the return value will not be > 0 as long as + there is a possibility the lookup process can ever use following + services. In other words, only if all four lookup results have + the action RETURN associated the lookup process stops before the + natural end. */ +extern int __nss_next2 (service_user **ni, const char *fct_name, + const char *fct2_name, void **fctp, int status, + int all_values) attribute_hidden; +libc_hidden_proto (__nss_next2) +extern int __nss_next (service_user **ni, const char *fct_name, void **fctp, + int status, int all_values); + +/* Search for the service described in NI for a function named FCT_NAME + and return a pointer to this function if successful. */ +extern void *__nss_lookup_function (service_user *ni, const char *fct_name); +libc_hidden_proto (__nss_lookup_function) + + +/* Called by NSCD to disable recursive calls and enable special handling + when used in nscd. */ +struct traced_file; +extern void __nss_disable_nscd (void (*) (size_t, struct traced_file *)); + + +typedef int (*db_lookup_function) (service_user **, const char *, const char *, + void **) + internal_function; +typedef enum nss_status (*setent_function) (int); +typedef enum nss_status (*endent_function) (void); +typedef enum nss_status (*getent_function) (void *, char *, size_t, + int *, int *); +typedef int (*getent_r_function) (void *, char *, size_t, + void **result, int *); + +extern void __nss_setent (const char *func_name, + db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int stayon, + int *stayon_tmp, int res); +extern void __nss_endent (const char *func_name, + db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int res); +extern int __nss_getent_r (const char *getent_func_name, + const char *setent_func_name, + db_lookup_function lookup_fct, + service_user **nip, service_user **startp, + service_user **last_nip, int *stayon_tmp, + int res, + void *resbuf, char *buffer, size_t buflen, + void **result, int *h_errnop); +extern void *__nss_getent (getent_r_function func, + void **resbuf, char **buffer, size_t buflen, + size_t *buffer_size, int *h_errnop); +struct hostent; +extern int __nss_hostname_digits_dots (const char *name, + struct hostent *resbuf, char **buffer, + size_t *buffer_size, size_t buflen, + struct hostent **result, + enum nss_status *status, int af, + int *h_errnop); +libc_hidden_proto (__nss_hostname_digits_dots) + +/* Maximum number of aliases we allow. */ +#define MAX_NR_ALIASES 48 +#define MAX_NR_ADDRS 48 + +#endif /* nsswitch.h */ diff --git a/REORG.TODO/nss/proto-lookup.c b/REORG.TODO/nss/proto-lookup.c new file mode 100644 index 0000000000..bfad4202aa --- /dev/null +++ b/REORG.TODO/nss/proto-lookup.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME protocols + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/pwd-lookup.c b/REORG.TODO/nss/pwd-lookup.c new file mode 100644 index 0000000000..00040d4e30 --- /dev/null +++ b/REORG.TODO/nss/pwd-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME passwd +#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/rewrite_field.c b/REORG.TODO/nss/rewrite_field.c new file mode 100644 index 0000000000..c0ae3d23f2 --- /dev/null +++ b/REORG.TODO/nss/rewrite_field.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <string.h> + +/* Rewrite VALUE to a valid field value in the NSS database. Invalid + characters are replaced with a single space character ' '. If + VALUE is NULL, the empty string is returned. *TO_BE_FREED is + overwritten with a pointer the caller has to free if the function + returns successfully. On failure, return NULL. */ +const char * +internal_function +__nss_rewrite_field (const char *value, char **to_be_freed) +{ + *to_be_freed = NULL; + if (value == NULL) + return ""; + + /* Search for non-allowed characters. */ + const char *p = strpbrk (value, __nss_invalid_field_characters); + if (p == NULL) + return value; + *to_be_freed = __strdup (value); + if (*to_be_freed == NULL) + return NULL; + + /* Switch pointer to freshly-allocated buffer. */ + char *bad = *to_be_freed + (p - value); + do + { + *bad = ' '; + bad = strpbrk (bad + 1, __nss_invalid_field_characters); + } + while (bad != NULL); + + return *to_be_freed; +} diff --git a/REORG.TODO/nss/rpc-lookup.c b/REORG.TODO/nss/rpc-lookup.c new file mode 100644 index 0000000000..ea34c24927 --- /dev/null +++ b/REORG.TODO/nss/rpc-lookup.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME rpc + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/service-lookup.c b/REORG.TODO/nss/service-lookup.c new file mode 100644 index 0000000000..3f230d606a --- /dev/null +++ b/REORG.TODO/nss/service-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME services +#define NO_COMPAT + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/sgrp-lookup.c b/REORG.TODO/nss/sgrp-lookup.c new file mode 100644 index 0000000000..87c1480690 --- /dev/null +++ b/REORG.TODO/nss/sgrp-lookup.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + + 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME gshadow +#define ALTERNATE_NAME group +#define DEFAULT_CONFIG "files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/spwd-lookup.c b/REORG.TODO/nss/spwd-lookup.c new file mode 100644 index 0000000000..319a7bb062 --- /dev/null +++ b/REORG.TODO/nss/spwd-lookup.c @@ -0,0 +1,23 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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 + <http://www.gnu.org/licenses/>. */ + +#define DATABASE_NAME shadow +#define ALTERNATE_NAME passwd +#define DEFAULT_CONFIG "compat [NOTFOUND=return] files" + +#include "XXX-lookup.c" diff --git a/REORG.TODO/nss/test-digits-dots.c b/REORG.TODO/nss/test-digits-dots.c new file mode 100644 index 0000000000..2685161e65 --- /dev/null +++ b/REORG.TODO/nss/test-digits-dots.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2013-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 + <http://www.gnu.org/licenses/>. */ + +/* Testcase for BZ #15014 */ + +#include <stdlib.h> +#include <netdb.h> +#include <errno.h> + +static int +do_test (void) +{ + char buf[32]; + struct hostent *result = NULL; + struct hostent ret; + int h_err = 0; + int err; + + err = gethostbyname_r ("1.2.3.4", &ret, buf, sizeof (buf), &result, &h_err); + return err == ERANGE && h_err == NETDB_INTERNAL ? EXIT_SUCCESS : EXIT_FAILURE; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/test-netdb.c b/REORG.TODO/nss/test-netdb.c new file mode 100644 index 0000000000..319541bc03 --- /dev/null +++ b/REORG.TODO/nss/test-netdb.c @@ -0,0 +1,340 @@ +/* Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger <aj@suse.de>, 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 + <http://www.gnu.org/licenses/>. */ + +/* + Testing of some network related lookup functions. + The system databases looked up are: + - /etc/services + - /etc/hosts + - /etc/networks + - /etc/protocols + The tests try to be fairly generic and simple so that they work on + every possible setup (and might therefore not detect some possible + errors). +*/ + +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> +#include "nss.h" + +/* + The following define is necessary for glibc 2.0.6 +*/ +#ifndef INET6_ADDRSTRLEN +# define INET6_ADDRSTRLEN 46 +#endif + +int error_count; + +static void +output_servent (const char *call, struct servent *sptr) +{ + char **pptr; + + if (sptr == NULL) + printf ("Call: %s returned NULL\n", call); + else + { + printf ("Call: %s, returned: s_name: %s, s_port: %d, s_proto: %s\n", + call, sptr->s_name, ntohs(sptr->s_port), sptr->s_proto); + for (pptr = sptr->s_aliases; *pptr != NULL; pptr++) + printf (" alias: %s\n", *pptr); + } +} + + +static void +test_services (void) +{ + struct servent *sptr; + + sptr = getservbyname ("domain", "tcp"); + output_servent ("getservbyname (\"domain\", \"tcp\")", sptr); + + sptr = getservbyname ("domain", "udp"); + output_servent ("getservbyname (\"domain\", \"udp\")", sptr); + + sptr = getservbyname ("domain", NULL); + output_servent ("getservbyname (\"domain\", NULL)", sptr); + + sptr = getservbyname ("not-existant", NULL); + output_servent ("getservbyname (\"not-existant\", NULL)", sptr); + + /* This shouldn't return anything. */ + sptr = getservbyname ("", ""); + output_servent ("getservbyname (\"\", \"\")", sptr); + + sptr = getservbyname ("", "tcp"); + output_servent ("getservbyname (\"\", \"tcp\")", sptr); + + sptr = getservbyport (htons(53), "tcp"); + output_servent ("getservbyport (htons(53), \"tcp\")", sptr); + + sptr = getservbyport (htons(53), NULL); + output_servent ("getservbyport (htons(53), NULL)", sptr); + + sptr = getservbyport (htons(1), "udp"); /* shouldn't exist */ + output_servent ("getservbyport (htons(1), \"udp\")", sptr); + + setservent (0); + do + { + sptr = getservent (); + output_servent ("getservent ()", sptr); + } + while (sptr != NULL); + endservent (); +} + + +static void +output_hostent (const char *call, struct hostent *hptr) +{ + char **pptr; + char buf[INET6_ADDRSTRLEN]; + + if (hptr == NULL) + printf ("Call: %s returned NULL\n", call); + else + { + printf ("Call: %s returned: name: %s, addr_type: %d\n", + call, hptr->h_name, hptr->h_addrtype); + if (hptr->h_aliases) + for (pptr = hptr->h_aliases; *pptr != NULL; pptr++) + printf (" alias: %s\n", *pptr); + + for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++) + printf (" ip: %s\n", + inet_ntop (hptr->h_addrtype, *pptr, buf, sizeof (buf))); + } +} + +static void +test_hosts (void) +{ + struct hostent *hptr1, *hptr2; + char *name = NULL; + size_t namelen = 0; + struct in_addr ip; + + hptr1 = gethostbyname ("localhost"); + hptr2 = gethostbyname ("LocalHost"); + if (hptr1 != NULL || hptr2 != NULL) + { + if (hptr1 == NULL) + { + printf ("localhost not found - but LocalHost found:-(\n"); + ++error_count; + } + else if (hptr2 == NULL) + { + printf ("LocalHost not found - but localhost found:-(\n"); + ++error_count; + } + else if (strcmp (hptr1->h_name, hptr2->h_name) != 0) + { + printf ("localhost and LocalHost have different canoncial name\n"); + printf ("gethostbyname (\"localhost\")->%s\n", hptr1->h_name); + printf ("gethostbyname (\"LocalHost\")->%s\n", hptr2->h_name); + ++error_count; + } + else + output_hostent ("gethostbyname(\"localhost\")", hptr1); + } + + hptr1 = gethostbyname ("127.0.0.1"); + output_hostent ("gethostbyname (\"127.0.0.1\")", hptr1); + + hptr1 = gethostbyname ("10.1234"); + output_hostent ("gethostbyname (\"10.1234\")", hptr1); + + hptr1 = gethostbyname2 ("localhost", AF_INET); + output_hostent ("gethostbyname2 (\"localhost\", AF_INET)", hptr1); + + while (gethostname (name, namelen) < 0 && errno == ENAMETOOLONG) + { + namelen += 2; /* tiny increments to test a lot */ + name = realloc (name, namelen); + } + if (gethostname (name, namelen) == 0) + { + printf ("Hostname: %s\n", name); + if (name != NULL) + { + hptr1 = gethostbyname (name); + output_hostent ("gethostbyname (gethostname(...))", hptr1); + } + } + + ip.s_addr = htonl (INADDR_LOOPBACK); + hptr1 = gethostbyaddr ((char *) &ip, sizeof(ip), AF_INET); + if (hptr1 != NULL) + { + printf ("official name of 127.0.0.1: %s\n", hptr1->h_name); + } + + sethostent (0); + do + { + hptr1 = gethostent (); + output_hostent ("gethostent ()", hptr1); + } + while (hptr1 != NULL); + endhostent (); + +} + + +static void +output_netent (const char *call, struct netent *nptr) +{ + char **pptr; + + if (nptr == NULL) + printf ("Call: %s returned NULL\n", call); + else + { + struct in_addr ip; + + ip.s_addr = htonl(nptr->n_net); + printf ("Call: %s, returned: n_name: %s, network_number: %s\n", + call, nptr->n_name, inet_ntoa (ip)); + + for (pptr = nptr->n_aliases; *pptr != NULL; pptr++) + printf (" alias: %s\n", *pptr); + } +} + +static void +test_network (void) +{ + struct netent *nptr; + u_int32_t ip; + + /* + This test needs the following line in /etc/networks: + loopback 127.0.0.0 + */ + nptr = getnetbyname ("loopback"); + output_netent ("getnetbyname (\"loopback\")",nptr); + + nptr = getnetbyname ("LoopBACK"); + output_netent ("getnetbyname (\"LoopBACK\")",nptr); + + ip = inet_network ("127.0.0.0"); + nptr = getnetbyaddr (ip, AF_INET); + output_netent ("getnetbyaddr (inet_network (\"127.0.0.0\"), AF_INET)",nptr); + + setnetent (0); + do + { + nptr = getnetent (); + output_netent ("getnetent ()", nptr); + } + while (nptr != NULL); + endnetent (); +} + + +static void +output_protoent (const char *call, struct protoent *prptr) +{ + char **pptr; + + if (prptr == NULL) + printf ("Call: %s returned NULL\n", call); + else + { + printf ("Call: %s, returned: p_name: %s, p_proto: %d\n", + call, prptr->p_name, prptr->p_proto); + for (pptr = prptr->p_aliases; *pptr != NULL; pptr++) + printf (" alias: %s\n", *pptr); + } +} + + +static void +test_protocols (void) +{ + struct protoent *prptr; + + prptr = getprotobyname ("IP"); + output_protoent ("getprotobyname (\"IP\")", prptr); + + prptr = getprotobynumber (1); + output_protoent ("getprotobynumber (1)", prptr); + + setprotoent (0); + do + { + prptr = getprotoent (); + output_protoent ("getprotoent ()", prptr); + } + while (prptr != NULL); + endprotoent (); +} + + +/* Override /etc/nsswitch.conf for this program. This is mainly + useful for developers. */ +static void __attribute__ ((unused)) +setdb (const char *dbname) +{ + if (strcmp ("db", dbname)) + { + /* + db is not implemented for hosts, networks + */ + __nss_configure_lookup ("hosts", dbname); + __nss_configure_lookup ("networks", dbname); + } + __nss_configure_lookup ("protocols", dbname); + __nss_configure_lookup ("services", dbname); +} + + +static int +do_test (void) +{ + /* + setdb ("db"); + */ + + test_hosts (); + test_network (); + test_protocols (); + test_services (); + + if (error_count) + printf ("\n %d errors occurred!\n", error_count); + else + printf ("No visible errors occurred!\n"); + + return (error_count != 0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/tst-cancel-getpwuid_r.c b/REORG.TODO/nss/tst-cancel-getpwuid_r.c new file mode 100644 index 0000000000..53de82985c --- /dev/null +++ b/REORG.TODO/nss/tst-cancel-getpwuid_r.c @@ -0,0 +1,182 @@ +/* Test cancellation of getpwuid_r. + Copyright (C) 2016-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 + <http://www.gnu.org/licenses/>. */ + +/* Test if cancellation of getpwuid_r incorrectly leaves internal + function state locked resulting in hang of subsequent calls to + getpwuid_r. The main thread creates a second thread which will do + the calls to getpwuid_r. A semaphore is used by the second thread to + signal to the main thread that it is as close as it can be to the + call site of getpwuid_r. The goal of the semaphore is to avoid any + cancellable function calls between the sem_post and the call to + getpwuid_r. The main thread then attempts to cancel the second + thread. Without the fixes the cancellation happens at any number of + calls to cancellable functions in getpuid_r, but with the fix the + cancellation either does not happen or happens only at expected + points where the internal state is consistent. We use an explicit + pthread_testcancel call to terminate the loop in a timely fashion + if the implementation does not have a cancellation point. */ + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <pwd.h> +#include <nss.h> +#include <sys/types.h> +#include <unistd.h> +#include <semaphore.h> +#include <errno.h> +#include <support/support.h> + +sem_t started; +char *wbuf; +long wbufsz; + +void +worker_free (void *arg) +{ + free (arg); +} + +static void * +worker (void *arg) +{ + int ret; + unsigned int iter = 0; + struct passwd pwbuf, *pw; + uid_t uid; + + uid = geteuid (); + + /* Use a reasonable sized buffer. Note that _SC_GETPW_R_SIZE_MAX is + just a hint and not any kind of maximum value. */ + wbufsz = sysconf (_SC_GETPW_R_SIZE_MAX); + if (wbufsz == -1) + wbufsz = 1024; + wbuf = xmalloc (wbufsz); + + pthread_cleanup_push (worker_free, wbuf); + sem_post (&started); + while (1) + { + iter++; + + ret = getpwuid_r (uid, &pwbuf, wbuf, wbufsz, &pw); + + /* The call to getpwuid_r may not cancel so we need to test + for cancellation after some number of iterations of the + function. Choose an arbitrary 100,000 iterations of running + getpwuid_r in a tight cancellation loop before testing for + cancellation. */ + if (iter > 100000) + pthread_testcancel (); + + if (ret == ERANGE) + { + /* Increase the buffer size. */ + free (wbuf); + wbufsz = wbufsz * 2; + wbuf = xmalloc (wbufsz); + } + + } + pthread_cleanup_pop (1); + + return NULL; +} + +static int +do_test (void) +{ + int ret; + char *buf; + long bufsz; + void *retval; + struct passwd pwbuf, *pw; + pthread_t thread; + + /* Configure the test to only use files. We control the files plugin + as part of glibc so we assert that it should be deferred + cancellation safe. */ + __nss_configure_lookup ("passwd", "files"); + + /* Use a reasonable sized buffer. Note that _SC_GETPW_R_SIZE_MAX is + just a hint and not any kind of maximum value. */ + bufsz = sysconf (_SC_GETPW_R_SIZE_MAX); + if (bufsz == -1) + bufsz = 1024; + buf = xmalloc (bufsz); + + sem_init (&started, 0, 0); + + pthread_create (&thread, NULL, worker, NULL); + + do + { + ret = sem_wait (&started); + if (ret == -1 && errno != EINTR) + { + printf ("FAIL: Failed to wait for second thread to start.\n"); + exit (EXIT_FAILURE); + } + } + while (ret != 0); + + printf ("INFO: Cancelling thread\n"); + if ((ret = pthread_cancel (thread)) != 0) + { + printf ("FAIL: Failed to cancel thread. Returned %d\n", ret); + exit (EXIT_FAILURE); + } + + printf ("INFO: Joining...\n"); + pthread_join (thread, &retval); + if (retval != PTHREAD_CANCELED) + { + printf ("FAIL: Thread was not cancelled.\n"); + exit (EXIT_FAILURE); + } + printf ("INFO: Joined, trying getpwuid_r call\n"); + + /* Before the fix in 312be3f9f5eab1643d7dcc7728c76d413d4f2640 for this + issue the cancellation point could happen in any number of internal + calls, and therefore locks would be left held and the following + call to getpwuid_r would block and the test would time out. */ + do + { + ret = getpwuid_r (geteuid (), &pwbuf, buf, bufsz, &pw); + if (ret == ERANGE) + { + /* Increase the buffer size. */ + free (buf); + bufsz = bufsz * 2; + buf = xmalloc (bufsz); + } + } + while (ret == ERANGE); + + free (buf); + + /* Before the fix we would never get here. */ + printf ("PASS: Canceled getpwuid_r successfully" + " and called it again without blocking.\n"); + + return 0; +} + +#define TIMEOUT 900 +#include <support/test-driver.c> diff --git a/REORG.TODO/nss/tst-field.c b/REORG.TODO/nss/tst-field.c new file mode 100644 index 0000000000..d80be681c2 --- /dev/null +++ b/REORG.TODO/nss/tst-field.c @@ -0,0 +1,101 @@ +/* Test for invalid field handling in file-style NSS databases. [BZ #18724] + Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +/* This test needs to be statically linked because it access hidden + functions. */ + +#include <nss.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static bool errors; + +static void +check (const char *what, bool expr) +{ + if (!expr) + { + printf ("FAIL: %s\n", what); + errors = true; + } +} + +#define CHECK(expr) check (#expr, (expr)) + +static void +check_rewrite (const char *input, const char *expected) +{ + char *to_free; + const char *result = __nss_rewrite_field (input, &to_free); + CHECK (result != NULL); + if (result != NULL && strcmp (result, expected) != 0) + { + printf ("FAIL: rewrite \"%s\" -> \"%s\", expected \"%s\"\n", + input, result, expected); + errors = true; + } + free (to_free); +} + +static int +do_test (void) +{ + CHECK (__nss_valid_field (NULL)); + CHECK (__nss_valid_field ("")); + CHECK (__nss_valid_field ("+")); + CHECK (__nss_valid_field ("-")); + CHECK (__nss_valid_field (" ")); + CHECK (__nss_valid_field ("abcdef")); + CHECK (__nss_valid_field ("abc def")); + CHECK (__nss_valid_field ("abc\tdef")); + CHECK (!__nss_valid_field ("abcdef:")); + CHECK (!__nss_valid_field ("abcde:f")); + CHECK (!__nss_valid_field (":abcdef")); + CHECK (!__nss_valid_field ("abcdef\n")); + CHECK (!__nss_valid_field ("\nabcdef")); + CHECK (!__nss_valid_field (":")); + CHECK (!__nss_valid_field ("\n")); + + CHECK (__nss_valid_list_field (NULL)); + CHECK (__nss_valid_list_field ((char *[]) {(char *) "good", NULL})); + CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g,ood", NULL})); + CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g\nood", NULL})); + CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g:ood", NULL})); + + check_rewrite (NULL, ""); + check_rewrite ("", ""); + check_rewrite ("abc", "abc"); + check_rewrite ("abc\n", "abc "); + check_rewrite ("abc:", "abc "); + check_rewrite ("\nabc", " abc"); + check_rewrite (":abc", " abc"); + check_rewrite (":", " "); + check_rewrite ("\n", " "); + check_rewrite ("a:b:c", "a b c"); + check_rewrite ("a\nb\nc", "a b c"); + check_rewrite ("a\nb:c", "a b c"); + check_rewrite ("aa\nbb\ncc", "aa bb cc"); + check_rewrite ("aa\nbb:cc", "aa bb cc"); + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/tst-nss-getpwent.c b/REORG.TODO/nss/tst-nss-getpwent.c new file mode 100644 index 0000000000..7bd69fc378 --- /dev/null +++ b/REORG.TODO/nss/tst-nss-getpwent.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +#include <pwd.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +do_test (void) +{ + /* Count the number of entries in the password database, and fetch + data from the first and last entries. */ + size_t count = 0; + struct passwd * pw; + char *first_name = NULL; + uid_t first_uid = 0; + char *last_name = NULL; + uid_t last_uid = 0; + setpwent (); + while ((pw = getpwent ()) != NULL) + { + if (first_name == NULL) + { + first_name = strdup (pw->pw_name); + if (first_name == NULL) + { + printf ("strdup: %m\n"); + return 1; + } + first_uid = pw->pw_uid; + } + + free (last_name); + last_name = strdup (pw->pw_name); + if (last_name == NULL) + { + printf ("strdup: %m\n"); + return 1; + } + last_uid = pw->pw_uid; + ++count; + } + endpwent (); + + if (count == 0) + { + printf ("No entries in the password database.\n"); + return 0; + } + + /* Try again, this time interleaving with name-based and UID-based + lookup operations. The counts do not match if the interleaved + lookups affected the enumeration. */ + size_t new_count = 0; + setpwent (); + while ((pw = getpwent ()) != NULL) + { + if (new_count == count) + { + printf ("Additional entry in the password database.\n"); + return 1; + } + ++new_count; + struct passwd *pw2 = getpwnam (first_name); + if (pw2 == NULL) + { + printf ("getpwnam (%s) failed: %m\n", first_name); + return 1; + } + pw2 = getpwnam (last_name); + if (pw2 == NULL) + { + printf ("getpwnam (%s) failed: %m\n", last_name); + return 1; + } + pw2 = getpwuid (first_uid); + if (pw2 == NULL) + { + printf ("getpwuid (%llu) failed: %m\n", + (unsigned long long) first_uid); + return 1; + } + pw2 = getpwuid (last_uid); + if (pw2 == NULL) + { + printf ("getpwuid (%llu) failed: %m\n", + (unsigned long long) last_uid); + return 1; + } + } + endpwent (); + if (new_count < count) + { + printf ("Missing entry in the password database.\n"); + return 1; + } + + return 0; +} + +#define TIMEOUT 300 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/tst-nss-static.c b/REORG.TODO/nss/tst-nss-static.c new file mode 100644 index 0000000000..98cf073deb --- /dev/null +++ b/REORG.TODO/nss/tst-nss-static.c @@ -0,0 +1,15 @@ +/* glibc test for static NSS. */ +#include <stdio.h> + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + struct passwd *pw; + + pw = getpwuid(0); + return pw == NULL; +} + + +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/tst-nss-test1.c b/REORG.TODO/nss/tst-nss-test1.c new file mode 100644 index 0000000000..c5750e0956 --- /dev/null +++ b/REORG.TODO/nss/tst-nss-test1.c @@ -0,0 +1,72 @@ +#include <nss.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static int +do_test (void) +{ + int retval = 0; + + __nss_configure_lookup ("passwd", "test1"); + + static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 }; +#define npwdids (sizeof (pwdids) / sizeof (pwdids[0])) + setpwent (); + + const unsigned int *np = pwdids; + for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ()) + if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0 + || atol (p->pw_name + 4) != *np) + { + printf ("passwd entry %td wrong (%s, %u)\n", + np - pwdids, p->pw_name, p->pw_uid); + retval = 1; + break; + } + + endpwent (); + + for (int i = npwdids - 1; i >= 0; --i) + { + char buf[30]; + snprintf (buf, sizeof (buf), "name%u", pwdids[i]); + + struct passwd *p = getpwnam (buf); + if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0) + { + printf ("passwd entry \"%s\" wrong\n", buf); + retval = 1; + } + + p = getpwuid (pwdids[i]); + if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0) + { + printf ("passwd entry %u wrong\n", pwdids[i]); + retval = 1; + } + + snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1); + + p = getpwnam (buf); + if (p != NULL) + { + printf ("passwd entry \"%s\" wrong\n", buf); + retval = 1; + } + + p = getpwuid (pwdids[i] + 1); + if (p != NULL) + { + printf ("passwd entry %u wrong\n", pwdids[i] + 1); + retval = 1; + } + } + + return retval; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/nss/valid_field.c b/REORG.TODO/nss/valid_field.c new file mode 100644 index 0000000000..88c41a81a0 --- /dev/null +++ b/REORG.TODO/nss/valid_field.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <string.h> + +const char __nss_invalid_field_characters[] = NSS_INVALID_FIELD_CHARACTERS; + +/* Check that VALUE is either NULL or a NUL-terminated string which + does not contain characters not permitted in NSS database + fields. */ +_Bool +internal_function +__nss_valid_field (const char *value) +{ + return value == NULL + || strpbrk (value, __nss_invalid_field_characters) == NULL; +} diff --git a/REORG.TODO/nss/valid_list_field.c b/REORG.TODO/nss/valid_list_field.c new file mode 100644 index 0000000000..9763c89bcd --- /dev/null +++ b/REORG.TODO/nss/valid_list_field.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2015-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 + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <stdbool.h> +#include <string.h> + +static const char invalid_characters[] = NSS_INVALID_FIELD_CHARACTERS ","; + +/* Check that all list members match the field syntax requirements and + do not contain the character ','. */ +_Bool +internal_function +__nss_valid_list_field (char **list) +{ + if (list == NULL) + return true; + for (; *list != NULL; ++list) + if (strpbrk (*list, invalid_characters) != NULL) + return false; + return true; +} |