This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
RFC: Test hook for nss_files testing
- From: Florian Weimer <fweimer at redhat dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Sun, 6 Dec 2015 21:22:54 +0100
- Subject: RFC: Test hook for nss_files testing
- Authentication-results: sourceware.org; auth=none
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 <fweimer@redhat.com>
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 <paths.h>
-#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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <fcntl.h>
#include <libc-lock.h>
#include "nsswitch.h"
+#include <nss_files.h>
#include <kernel-features.h>
@@ -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 <netdb.h>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <nss_files.h>
+
+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 <rpc/key_prot.h>
#include <rpc/des_crypt.h>
#include "nsswitch.h"
+#include <nss_files.h>
-#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 <string.h>
#include "nsswitch.h"
#include "netgroup.h"
+#include <nss_files.h>
-#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 <stdint.h>
#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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <gnu/lib-names.h>
+#include <netdb.h>
+#include <nss_files.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+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"