From patchwork Sun Dec 6 20:22:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 9910 Received: (qmail 74662 invoked by alias); 6 Dec 2015 20:23:02 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 74652 invoked by uid 89); 6 Dec 2015 20:23:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_50, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com To: GNU C Library From: Florian Weimer Subject: RFC: Test hook for nss_files testing X-Enigmail-Draft-Status: N1110 Message-ID: <5664991E.4090105@redhat.com> Date: Sun, 6 Dec 2015 21:22:54 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 The attached patch adds a test hook which allows us to select different files (not those under /etc) for testing nss_files inside the build tree. It contains a regression test for bug 17363 as an example. If the direction is acceptable, I'll add further tests. This change increases the size of nss_files slightly (on x86_64): Old: text data bss dec hex filename 40895 992 26040 67927 10957 nss/libnss_files.so.2 New: text data bss dec hex filename 41426 1088 26040 68554 10bca nss/libnss_files.so.2 If this is a problem, I can make additional cleanups which reduce the DSO size to the previous level. There are also a few additional relocations (for the string constants), but they should not matter. Florian 2015-12-06 Florian Weimer Implement test hook for nss_files database file selection. * nss/Makefile (tests): Add tst-nss-files. (libnss_files-routines): Add files-config. (LDLIBS-tst-nss-files): New variable. * nss/Versions (libnss_files): Export _nss_files_set_config. * nss/nss_db/db-XXX.c (DBFILE_): New macro. (DBFILE): Use it to stringify DATABASE. * nss/nss_files.h: New file. * nss/nss_files/files-XXX.c: Update comment: DATABASE is now an identifier. (DATAFILE): Adjust. * nss/nss_files/files-config.c: New file. * nss/nss_files/files-ethers.c (DATABASE): Adjust. * nss/nss_files/files-group.c (DATABASE): Likewise. * nss/nss_files/files-hosts.c (DATABASE): Likewise. * nss/nss_files/files-key.c (DATABASE): Likewise. * nss/nss_files/files-netgrp.c (DATABASE): Likewise. * nss/nss_files/files-network.c (DATABASE): Likewise. * nss/nss_files/files-parse.c: Update comment: DATABASE is now an identifier. * nss/nss_files/files-proto.c (DATABASE): Adjust. * nss/nss_files/files-pwd.c (DATABASE): Likewise. * nss/nss_files/files-rpc.c (DATABASE): Likewise. * nss/nss_files/files-services.c (DATABASE): Likewise. * nss/nss_files/files-sgrp.c (DATABASE): Likewise. * nss/nss_files/files-spwd.c (DATABASE): Likewise. * nss/test-data/files/netgroup: New file. * nss/test-data/files/passwd: Likewise. * nss/tst-nss-files.c: Likewise. diff --git a/nss/Makefile b/nss/Makefile index bbbad85..e666ec6 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -50,7 +50,7 @@ extra-objs += $(makedb-modules:=.o) tests-static = tst-field tests = test-netdb tst-nss-test1 test-digits-dots \ - tst-nss-getpwent bug17079 \ + tst-nss-getpwent bug17079 tst-nss-files \ $(tests-static) xtests = bug-erange @@ -68,7 +68,8 @@ vpath %.c $(subdir-dirs) ../locale/programs ../intl libnss_files-routines := $(addprefix files-,$(databases)) \ - files-initgroups files-have_o_cloexec files-init + files-initgroups files-have_o_cloexec files-init \ + files-config libnss_db-dbs := $(addprefix db-,\ $(filter-out hosts network key alias,\ @@ -124,3 +125,5 @@ $(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) + +LDLIBS-tst-nss-files = -ldl diff --git a/nss/Versions b/nss/Versions index f8ababc..ff7dd29 100644 --- a/nss/Versions +++ b/nss/Versions @@ -100,6 +100,7 @@ libnss_files { _nss_files_initgroups_dyn; _nss_files_init; + _nss_files_set_config; } } diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c index 314edc9..5db2711 100644 --- a/nss/nss_db/db-XXX.c +++ b/nss/nss_db/db-XXX.c @@ -39,7 +39,8 @@ #define ENTNAME_r CONCAT(ENTNAME,_r) #include -#define DBFILE _PATH_VARDB DATABASE ".db" +#define DBFILE_(name) _PATH_VARDB #name ".db" +#define DBFILE DBFILE_(name) #ifdef NEED_H_ERRNO # define H_ERRNO_PROTO , int *herrnop diff --git a/nss/nss_files.h b/nss/nss_files.h new file mode 100644 index 0000000..f700c22 --- /dev/null +++ b/nss/nss_files.h @@ -0,0 +1,51 @@ +/* Internal interfaces of the nss_files service module. + Copyright (C) 2015 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 + . */ + +#ifndef NSS_FILES_H +#define NSS_FILES_H + +struct nss_files_config +{ + const char *path_ethers; + const char *path_group; + const char *path_gshadow; + const char *path_hosts; + const char *path_netgroup; + const char *path_networks; + const char *path_passwd; + const char *path_protocols; + const char *path_publickey; + const char *path_rpc; + const char *path_services; + const char *path_shadow; +}; + +/* Internal configuration setting. Only available within the DSO. */ +extern struct nss_files_config _nss_files_config attribute_hidden; + +/* Internal access to the file name based on the database name. */ +#define NSS_FILES_DATABASE_(name) _nss_files_config.path_##name +#define NSS_FILES_DATABASE(name) NSS_FILES_DATABASE_ (name) + +/* Internal function to set _nss_files_config. Only copies the + struct, but not the value of the strings. Outside the DSO, this + function has to be looked up with dlsym. */ +void _nss_files_set_config (const struct nss_files_config *) + internal_function; + +#endif /* NSS_FILES_H */ diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c index cca4322..63b0c02 100644 --- a/nss/nss_files/files-XXX.c +++ b/nss/nss_files/files-XXX.c @@ -22,6 +22,7 @@ #include #include #include "nsswitch.h" +#include #include @@ -29,7 +30,7 @@ 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"). + DATABASE -- name of the database file's name ("hosts", "passwd"). NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. @@ -38,7 +39,7 @@ #define ENTNAME_r CONCAT(ENTNAME,_r) -#define DATAFILE "/etc/" DATABASE +#define DATAFILE NSS_FILES_DATABASE (DATABASE) #ifdef NEED_H_ERRNO # include diff --git a/nss/nss_files/files-config.c b/nss/nss_files/files-config.c new file mode 100644 index 0000000..68f9907 --- /dev/null +++ b/nss/nss_files/files-config.c @@ -0,0 +1,42 @@ +/* Files configuration for nss_files. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +struct nss_files_config _nss_files_config = + { + .path_ethers = "/etc/ethers", + .path_group = "/etc/group", + .path_gshadow = "/etc/gshadow", + .path_hosts = "/etc/hosts", + .path_netgroup = "/etc/netgroup", + .path_networks = "/etc/networks", + .path_passwd = "/etc/passwd", + .path_protocols = "/etc/protocols", + .path_publickey = "/etc/publickey", + .path_rpc = "/etc/rpc", + .path_services = "/etc/services", + .path_shadow = "/etc/shadow", + }; + +void +internal_function +_nss_files_set_config (const struct nss_files_config *config) +{ + _nss_files_config = *config; +} diff --git a/nss/nss_files/files-ethers.c b/nss/nss_files/files-ethers.c index 47fa784..ca96799 100644 --- a/nss/nss_files/files-ethers.c +++ b/nss/nss_files/files-ethers.c @@ -22,7 +22,7 @@ struct etherent_data {}; #define ENTNAME etherent -#define DATABASE "ethers" +#define DATABASE ethers #include "files-parse.c" LINE_PARSER ("#", diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c index 42155bc..6a631ef 100644 --- a/nss/nss_files/files-grp.c +++ b/nss/nss_files/files-grp.c @@ -20,7 +20,7 @@ #define STRUCTURE group #define ENTNAME grent -#define DATABASE "group" +#define DATABASE group struct grent_data {}; /* Our parser function is already defined in fgetgrent.c, so use that. diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c index 4117458..aad8d90 100644 --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -30,7 +30,7 @@ #define ENTNAME hostent -#define DATABASE "hosts" +#define DATABASE hosts #define NEED_H_ERRNO #define EXTRA_ARGS , af, flags diff --git a/nss/nss_files/files-key.c b/nss/nss_files/files-key.c index 2d64744..60fb0f4 100644 --- a/nss/nss_files/files-key.c +++ b/nss/nss_files/files-key.c @@ -23,8 +23,9 @@ #include #include #include "nsswitch.h" +#include -#define DATAFILE "/etc/publickey" +#define DATAFILE _nss_files_config.path_publickey static enum nss_status diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c index 8886c26..c1c3f00 100644 --- a/nss/nss_files/files-netgrp.c +++ b/nss/nss_files/files-netgrp.c @@ -26,8 +26,9 @@ #include #include "nsswitch.h" #include "netgroup.h" +#include -#define DATAFILE "/etc/netgroup" +#define DATAFILE _nss_files_config.path_netgroup libnss_files_hidden_proto (_nss_files_endnetgrent) diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c index 46e9945..d9868c4 100644 --- a/nss/nss_files/files-network.c +++ b/nss/nss_files/files-network.c @@ -22,7 +22,7 @@ #include #define ENTNAME netent -#define DATABASE "networks" +#define DATABASE networks #define NEED_H_ERRNO struct netent_data {}; diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c index 9911633..836a0c9 100644 --- a/nss/nss_files/files-parse.c +++ b/nss/nss_files/files-parse.c @@ -26,7 +26,7 @@ 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"). + DATABASE -- name of the database (hosts, passwd). ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store things pointed to by the resultant `struct STRUCTURE'. diff --git a/nss/nss_files/files-proto.c b/nss/nss_files/files-proto.c index 370266a..e2099ef 100644 --- a/nss/nss_files/files-proto.c +++ b/nss/nss_files/files-proto.c @@ -20,7 +20,7 @@ #define ENTNAME protoent -#define DATABASE "protocols" +#define DATABASE protocols struct protoent_data {}; diff --git a/nss/nss_files/files-pwd.c b/nss/nss_files/files-pwd.c index 84ce5bb..4936624 100644 --- a/nss/nss_files/files-pwd.c +++ b/nss/nss_files/files-pwd.c @@ -20,7 +20,7 @@ #define STRUCTURE passwd #define ENTNAME pwent -#define DATABASE "passwd" +#define DATABASE passwd struct pwent_data {}; /* Our parser function is already defined in fgetpwent_r.c, so use that diff --git a/nss/nss_files/files-rpc.c b/nss/nss_files/files-rpc.c index 34f6aec..3415ca6 100644 --- a/nss/nss_files/files-rpc.c +++ b/nss/nss_files/files-rpc.c @@ -20,7 +20,7 @@ #define ENTNAME rpcent -#define DATABASE "rpc" +#define DATABASE rpc struct rpcent_data {}; diff --git a/nss/nss_files/files-service.c b/nss/nss_files/files-service.c index 7fccbdb..0bbf046 100644 --- a/nss/nss_files/files-service.c +++ b/nss/nss_files/files-service.c @@ -21,7 +21,7 @@ #define ENTNAME servent -#define DATABASE "services" +#define DATABASE services struct servent_data {}; diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c index ac74324..538e417 100644 --- a/nss/nss_files/files-sgrp.c +++ b/nss/nss_files/files-sgrp.c @@ -20,7 +20,7 @@ #define STRUCTURE sgrp #define ENTNAME sgent -#define DATABASE "gshadow" +#define DATABASE gshadow struct sgent_data {}; /* Our parser function is already defined in sgetspent_r.c, so use that diff --git a/nss/nss_files/files-spwd.c b/nss/nss_files/files-spwd.c index a255454..6436ee1 100644 --- a/nss/nss_files/files-spwd.c +++ b/nss/nss_files/files-spwd.c @@ -20,7 +20,7 @@ #define STRUCTURE spwd #define ENTNAME spent -#define DATABASE "shadow" +#define DATABASE shadow struct spent_data {}; /* Our parser function is already defined in sgetspent_r.c, so use that diff --git a/nss/test-data/files/netgroup b/nss/test-data/files/netgroup new file mode 100644 index 0000000..b367576 --- /dev/null +++ b/nss/test-data/files/netgroup @@ -0,0 +1,6 @@ +netgr gr1 gr2 gr3 +gr1 (,u1,) +gr2 (,u2,) +gr3 gr5 gr6 +gr5 +gr6 (,u3,) diff --git a/nss/test-data/files/passwd b/nss/test-data/files/passwd new file mode 100644 index 0000000..873152a --- /dev/null +++ b/nss/test-data/files/passwd @@ -0,0 +1 @@ +root:x:0:0:glibc root test user:/root:/bin/bash diff --git a/nss/tst-nss-files.c b/nss/tst-nss-files.c new file mode 100644 index 0000000..8d3cb75 --- /dev/null +++ b/nss/tst-nss-files.c @@ -0,0 +1,211 @@ +/* Test nss_files parsing. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +configure_nss (void) +{ + __nss_configure_lookup ("passwd", "files"); +} + +static char * +file_name_for_database (const char *name) +{ + char *curdir = realpath (".", NULL); + if (curdir == NULL) + { + printf ("error: realpath (\".\", NULL): %m\n"); + exit (1); + } + + char *result; + int ret = asprintf (&result, "%s/test-data/files/%s", curdir, name); + if (ret < 0) + { + printf ("error: asprintf: %m\n"); + exit (1); + } + return result; +} + +static struct nss_files_config test_config; + +static void +init_test_config (void) +{ + test_config = (struct nss_files_config) + { + .path_ethers = file_name_for_database ("ethers"), + .path_group = file_name_for_database ("group"), + .path_gshadow = file_name_for_database ("gshadow"), + .path_hosts = file_name_for_database ("hosts"), + .path_netgroup = file_name_for_database ("netgroup"), + .path_networks = file_name_for_database ("networks"), + .path_passwd = file_name_for_database ("passwd"), + .path_protocols = file_name_for_database ("protocols"), + .path_publickey = file_name_for_database ("publickey"), + .path_rpc = file_name_for_database ("rpc"), + .path_services = file_name_for_database ("services"), + .path_shadow = file_name_for_database ("shadow"), + }; +} + +static bool errors; + +static int +sort_strings (const void *a, const void *b) +{ + return strcmp (*(const char **) a, *(const char **) b); +} + + +/* Test case from bug 17363: getnetgrent does not return the complete + list of entries if one of the netgroups in its definition tree is + empty. */ +static void +test_bug17363 (void) +{ + int ret = setnetgrent ("netgr"); + if (ret != 1) + { + printf ("error: setnetgrent (\"netgr\"): %m\n"); + errors = true; + } + +#define COUNT 3 + static const char *const expected[COUNT] = + { + ",u1,", + ",u2,", + ",u3,", + }; + + char *actual[COUNT] = {}; + + for (size_t i = 0; ; ++i) + { + char *host; + char *user; + char *domain; + ret = getnetgrent (&host, &user, &domain); + if (ret != 1) + { + if (i == COUNT) + break; + printf ("error: getnetgrent (%zu)\n", i); + errors = true; + break; + } + if (i == COUNT) + { + printf ("error: getnetgrent (%zu): unexpected success\n", i); + errors = true; + break; + } + + if (host == NULL) + host = (char *) ""; + if (user == NULL) + user = (char *) ""; + if (domain == NULL) + domain = (char *) ""; + + ret = asprintf (actual + i, "%s,%s,%s", host, user, domain); + if (ret < 0) + { + printf ("error: asprintf: %m\n"); + exit (1); + } + } + + endnetgrent (); + + if (!errors) + { + qsort (actual, COUNT, sizeof (actual[0]), sort_strings); + for (size_t i = 0; i < COUNT; ++i) + { + if (strcmp (actual[i], expected[i]) != 0) + { + printf ("error: getnetgrent (%zu): \"%s\" instead of \"%s\"\n", + i, actual[i], expected[i]); + errors = true; + } + free (actual[i]); + } + } +#undef COUNT +} + +static int +do_test (void) +{ + configure_nss (); + + void *handle = dlopen (LIBNSS_FILES_SO, RTLD_LAZY); + if (handle == NULL) + { + printf ("error: cannot open " LIBNSS_FILES_SO ": %s\n", + dlerror ()); + return 1; + } + + __typeof__ (&_nss_files_set_config) config_function = + dlsym (handle, "_nss_files_set_config"); + if (config_function == NULL) + { + printf ("error: cannot find configuration function symbol: %s\n", + dlerror ()); + return 1; + } + + init_test_config (); + config_function (&test_config); + + /* Check that the reconfiguration to the test files was + successful. */ + const struct passwd *pw = getpwuid (0); + if (pw == NULL) + { + printf ("error: root user lookup failed: %m\n"); + return 1; + } + if (strcmp (pw->pw_gecos, "glibc root test user") != 0) + { + printf ("error: incorrect GECOS field for root user: \"%s\n\"", + pw->pw_gecos); + return 1; + } + + test_bug17363 (); + dlclose (handle); + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"