From c3e2f19bb995a0281f4cc56ad81bd67a5404dde6 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 11 Aug 2010 07:25:02 -0700 Subject: [PATCH] Add self-contained test for NSS. While at it fix interaction between __nss_configure_lookup and nscd. Otherwise the test fails if nscd is runnung. --- ChangeLog | 20 +++++ grp/initgroups.c | 5 +- nss/Makefile | 16 +++- nss/getXXbyYY_r.c | 7 +- nss/nss_files/files-parse.c | 6 +- nss/nss_test1.c | 154 ++++++++++++++++++++++++++++++++++++ nss/nsswitch.c | 6 +- nss/nsswitch.h | 16 +++- nss/tst-nss-test1.c | 72 +++++++++++++++++ shlib-versions | 4 + sysdeps/posix/getaddrinfo.c | 3 +- 11 files changed, 297 insertions(+), 12 deletions(-) create mode 100644 nss/nss_test1.c create mode 100644 nss/tst-nss-test1.c diff --git a/ChangeLog b/ChangeLog index 281191def5..8d267c9ccb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2010-08-11 Ulrich Drepper + + * nss/Makefile: Add rules to build and run tst-nss-test1. + * shlib-versions: Add entry for libnss_test1. + * nss/nss_test1.c: New file. + * nss/tst-nss-test1.c: New file. + + * nss/nsswitch.c (__nss_database_custom): Define new variable. + (__nss_configure_lookup): Set appropriate entry in + __nss_configure_lookup to true. + * nss/nsswitch.h: Define enum with indeces of databases in + databases and __nss_database_custom arrays. Declare + __nss_database_custom. + * grp/initgroups.c (internal_getgrouplist): Use __nss_database_custom + to avoid using nscd when custom rules are installed. + * nss/getXXbyYY_r.c: Likewise. + * sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise. + + * nss/nss_files/files-parse.c: Whitespace fixes. + 2010-08-09 Ulrich Drepper [BZ #11883] diff --git a/grp/initgroups.c b/grp/initgroups.c index cab63e52bf..180e653c30 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1989,91,93,1996-2005,2006,2008 Free Software Foundation, Inc. +/* Copyright (C) 1989,91,93,1996-2006,2008,2010 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 @@ -56,7 +56,8 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, if (__nss_not_use_nscd_group > 0 && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY) __nss_not_use_nscd_group = 0; - if (!__nss_not_use_nscd_group) + if (!__nss_not_use_nscd_group + && !__nss_database_custom[NSS_DBSIDX_group]) { int n = __nscd_getgrouplist (user, group, size, groupsp, limit); if (n >= 0) diff --git a/nss/Makefile b/nss/Makefile index 670e6b2f16..04165b7604 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -1,4 +1,5 @@ -# Copyright (C) 1996-1998,2000-2002,2007,2009 Free Software Foundation, Inc. +# Copyright (C) 1996-1998,2000-2002,2007,2009,2010 +# 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 @@ -39,7 +40,7 @@ databases = proto service hosts network grp pwd rpc ethers \ others := getent install-bin := getent -tests = test-netdb +tests = test-netdb tst-nss-test1 xtests = bug-erange include ../Makeconfig @@ -84,3 +85,14 @@ endif # a statically-linked program that hasn't already loaded it. $(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so \ $(common-objpfx)libc_nonshared.a + + +distribute += nss_test1.c + +CFLAGS-nss_test1.c = -DNOT_IN_libc=1 +$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(common-objpfx)libc.so \ + $(common-objpfx)libc_nonshared.a + $(build-module) +$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so + $(make-link) +$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version) diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 16dadd70ef..0dbb0030e9 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2004, 2006, 2007, 2009 Free Software Foundation, Inc. +/* Copyright (C) 1996-2004,2006,2007,2009,2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. @@ -87,6 +87,8 @@ # 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) @@ -186,7 +188,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY) NOT_USENSCD_NAME = 0; - if (!NOT_USENSCD_NAME) + 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); diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c index 3603762f8e..66604bf94e 100644 --- a/nss/nss_files/files-parse.c +++ b/nss/nss_files/files-parse.c @@ -1,5 +1,5 @@ /* Common code for file-based database parsers in nss_files module. - Copyright (C) 1996-2000, 2003, 2004, 2009 Free Software Foundation, Inc. + Copyright (C) 1996-2000,2003,2004,2009,2010 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 @@ -29,7 +29,7 @@ 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'. + things pointed to by the resultant `struct STRUCTURE'. NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. @@ -229,7 +229,7 @@ strtou32 (const char *nptr, char **endptr, int base) char **list = parse_list (&line, buf_start, buf_end, '\0', errnop); \ if (list) \ result->TRAILING_LIST_MEMBER = list; \ - else \ + else \ return -1; /* -1 indicates we ran out of space. */ \ } diff --git a/nss/nss_test1.c b/nss/nss_test1.c new file mode 100644 index 0000000000..3beb488fcf --- /dev/null +++ b/nss/nss_test1.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include + + +#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 + +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/nss/nsswitch.c b/nss/nsswitch.c index da94ca9838..92e6f5f91f 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999, 2001-2007, 2009 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. @@ -71,6 +71,9 @@ static const struct }; #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) @@ -265,6 +268,7 @@ __nss_configure_lookup (const char *dbname, const char *service_line) /* Install new rules. */ *databases[cnt].dbp = new_db; + __nss_database_custom[cnt] = true; __libc_lock_unlock (lock); diff --git a/nss/nsswitch.h b/nss/nsswitch.h index b80edef651..ae5657e889 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007 +/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -28,6 +28,7 @@ #include #include #include +#include /* Actions performed after lookup finished. */ typedef enum @@ -96,6 +97,19 @@ typedef struct name_database } 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]; + + /* Interface functions for NSS. */ /* Get the data structure representing the specified database. diff --git a/nss/tst-nss-test1.c b/nss/tst-nss-test1.c new file mode 100644 index 0000000000..4e443d4539 --- /dev/null +++ b/nss/tst-nss-test1.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + + +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 %ju 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/shlib-versions b/shlib-versions index 65e772bbb5..d3e8407522 100644 --- a/shlib-versions +++ b/shlib-versions @@ -114,6 +114,10 @@ alpha.*-.*-linux.* libresolv=2.1 .*-.*-.* libnss_ldap=2 .*-.*-.* libnss_hesiod=2 +# Tests for NSS. They must have the same NSS_SHLIB_REVISION number as +# the rest. +.*-.*-.* libnss_test1=2 + # Version for libnsl with YP and NIS+ functions. alpha.*-.*-linux.* libnsl=1.1 .*-.*-.* libnsl=1 diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 2e0c7248f0..126a09ea33 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -600,7 +600,8 @@ gaih_inet (const char *name, const struct gaih_service *service, && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) __nss_not_use_nscd_hosts = 0; - if (!__nss_not_use_nscd_hosts) + if (!__nss_not_use_nscd_hosts + && !__nss_database_custom[NSS_DBSIDX_hosts]) { /* Try to use nscd. */ struct nscd_ai_result *air = NULL;