From patchwork Thu Aug 27 18:42:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 40335 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BD317393FC34; Thu, 27 Aug 2020 18:42:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BD317393FC34 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1598553766; bh=AU+0m1zqUpw6fX00FSxQL5gsTZdnCVWcvm/34lswSZA=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=JlLANXeZqeFbSbuqiP+XhZ6Qfj2hxKHWX+GDpS3Jhrjoo0G+xMcbJBJZlaMXuvB+p R41I9LaIBUa5cH7iAuxfAxzCc0W9MxFhSwMxnXTKwR2TItUjtE5C/ZrouQqcT3GyHv vCCOR/nx1oQjSOaAWuCeNjclAiQPZ2F1jjR5+PVw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [205.139.110.61]) by sourceware.org (Postfix) with ESMTP id 3F49E3870879 for ; Thu, 27 Aug 2020 18:42:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 3F49E3870879 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-462-Ev4rYw7lNZCDq8-fZpZZiw-1; Thu, 27 Aug 2020 14:42:35 -0400 X-MC-Unique: Ev4rYw7lNZCDq8-fZpZZiw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 009AA1084C91 for ; Thu, 27 Aug 2020 18:42:35 +0000 (UTC) Received: from greed.delorie.com (ovpn-112-147.phx2.redhat.com [10.3.112.147]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9282D7C3F8 for ; Thu, 27 Aug 2020 18:42:34 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.14.7/8.14.7) with ESMTP id 07RIgXou020010 for ; Thu, 27 Aug 2020 14:42:33 -0400 Date: Thu, 27 Aug 2020 14:42:33 -0400 Message-Id: To: libc-alpha@sourceware.org Subject: v3 [PATCH 4/4] nsswitch: use new internal API X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Mimecast-Spam-Score: 0.001 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: DJ Delorie via Libc-alpha From: DJ Delorie Reply-To: DJ Delorie Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" From 4b6ef844fe1ed39e8f9b8ffeb1dae51bdcbff32e Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Tue, 23 Jun 2020 16:49:16 -0400 Subject: [PATCH 4/4] nsswitch: use new internal API Stitch new ABI and types throughout all NSS callers and providers. --- grp/compat-initgroups.c | 2 +- grp/initgroups.c | 41 +- inet/ether_hton.c | 21 +- inet/ether_ntoh.c | 21 +- inet/getnetgrent_r.c | 40 +- inet/netgroup.h | 2 +- malloc/set-freeres.c | 4 +- nscd/aicache.c | 17 +- nscd/gai.c | 2 +- nscd/initgrcache.c | 8 +- nscd/netgroupcache.c | 4 +- nscd/nscd_netgroup.c | 2 +- nss/Makefile | 3 +- nss/XXX-lookup.c | 7 +- nss/compat-lookup.c | 8 +- nss/getXXbyYY_r.c | 51 +- nss/getXXent_r.c | 10 +- nss/getnssent_r.c | 22 +- nss/nss_action.c | 2 +- nss/nss_action_parse.c | 22 +- nss/nss_compat/compat-grp.c | 2 +- nss/nss_compat/compat-initgroups.c | 2 +- nss/nss_compat/compat-pwd.c | 2 +- nss/nss_compat/compat-spwd.c | 2 +- nss/nss_database.c | 40 +- nss/nss_module.c | 64 +- nss/nss_test.h | 9 + nss/nss_test1.c | 166 ++++- nss/nsswitch.c | 809 +----------------------- nss/nsswitch.h | 69 +- nss/tst-reload1.c | 341 ++++++++++ nss/tst-reload1.root/etc/nsswitch.conf | 3 + nss/tst-reload1.root/etc/nsswitch.conf2 | 3 + nss/tst-reload1.root/etc/services | 1 + nss/tst-reload1.root/tst-reload1.script | 2 + posix/tst-rfc3484-2.c | 2 +- posix/tst-rfc3484-3.c | 2 +- posix/tst-rfc3484.c | 2 +- sunrpc/netname.c | 21 +- sunrpc/publickey.c | 42 +- sysdeps/posix/getaddrinfo.c | 19 +- 41 files changed, 782 insertions(+), 1110 deletions(-) create mode 100644 nss/tst-reload1.c create mode 100644 nss/tst-reload1.root/etc/nsswitch.conf create mode 100644 nss/tst-reload1.root/etc/nsswitch.conf2 create mode 100644 nss/tst-reload1.root/etc/services create mode 100644 nss/tst-reload1.root/tst-reload1.script diff --git a/grp/compat-initgroups.c b/grp/compat-initgroups.c index 3dd50d2306..9df940767b 100644 --- a/grp/compat-initgroups.c +++ b/grp/compat-initgroups.c @@ -10,7 +10,7 @@ typedef enum nss_status (*get_function) (struct group *, char *, static enum nss_status -compat_call (service_user *nip, const char *user, gid_t group, long int *start, +compat_call (nss_action_list nip, const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { struct group grpbuf; diff --git a/grp/initgroups.c b/grp/initgroups.c index 0c17141117..6fd8e85517 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -63,7 +63,6 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, #endif enum nss_status status = NSS_STATUS_UNAVAIL; - int no_more = 0; /* Never store more than the starting *SIZE number of elements. */ assert (*size > 0); @@ -71,33 +70,28 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, /* Start is one, because we have the first group as parameter. */ long int start = 1; - if (__nss_initgroups_database == NULL) - { - if (__nss_database_lookup2 ("initgroups", NULL, "", - &__nss_initgroups_database) < 0) - { - if (__nss_group_database == NULL) - no_more = __nss_database_lookup2 ("group", NULL, "files", - &__nss_group_database); + nss_action_list nip; - __nss_initgroups_database = __nss_group_database; - } - else - use_initgroups_entry = true; + if (__nss_database_get (nss_database_initgroups, &nip)) + { + use_initgroups_entry = true; + } + else if (__nss_database_get (nss_database_group, &nip)) + { + use_initgroups_entry = false; } else - /* __nss_initgroups_database might have been set through - __nss_configure_lookup in which case use_initgroups_entry was - not set here. */ - use_initgroups_entry = __nss_initgroups_database != __nss_group_database; + { + nip = __nss_action_parse ("files"); + use_initgroups_entry = false; + } - service_user *nip = __nss_initgroups_database; - while (! no_more) + while (nip && nip->module) { long int prev_start = start; - initgroups_dyn_function fct = __nss_lookup_function (nip, - "initgroups_dyn"); + initgroups_dyn_function fct = __nss_lookup_function (nip, "initgroups_dyn"); + if (fct == NULL) status = compat_call (nip, user, group, &start, size, groupsp, limit, &errno); @@ -134,10 +128,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, && nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) - no_more = -1; - else - nip = nip->next; + nip ++; } return start; diff --git a/inet/ether_hton.c b/inet/ether_hton.c index ff6943fc35..cccae17f10 100644 --- a/inet/ether_hton.c +++ b/inet/ether_hton.c @@ -30,9 +30,7 @@ typedef int (*lookup_function) (const char *, struct etherent *, char *, int, int ether_hostton (const char *hostname, struct ether_addr *addr) { - static service_user *startp; - static lookup_function start_fct; - service_user *nip; + nss_action_list nip; union { lookup_function f; @@ -42,22 +40,7 @@ ether_hostton (const char *hostname, struct ether_addr *addr) enum nss_status status = NSS_STATUS_UNAVAIL; struct etherent etherent; - if (startp == NULL) - { - no_more = __nss_ethers_lookup2 (&nip, "gethostton_r", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_ethers_lookup2 (&nip, "gethostton_r", NULL, &fct.ptr); while (no_more == 0) { diff --git a/inet/ether_ntoh.c b/inet/ether_ntoh.c index e409773601..5ef654292c 100644 --- a/inet/ether_ntoh.c +++ b/inet/ether_ntoh.c @@ -31,9 +31,7 @@ typedef int (*lookup_function) (const struct ether_addr *, struct etherent *, int ether_ntohost (char *hostname, const struct ether_addr *addr) { - static service_user *startp; - static lookup_function start_fct; - service_user *nip; + nss_action_list nip; union { lookup_function f; @@ -43,22 +41,7 @@ ether_ntohost (char *hostname, const struct ether_addr *addr) enum nss_status status = NSS_STATUS_UNAVAIL; struct etherent etherent; - if (startp == NULL) - { - no_more = __nss_ethers_lookup2 (&nip, "getntohost_r", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_ethers_lookup2 (&nip, "getntohost_r", NULL, &fct.ptr); while (no_more == 0) { diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c index 78a66eee00..9c75af6f77 100644 --- a/inet/getnetgrent_r.c +++ b/inet/getnetgrent_r.c @@ -39,40 +39,12 @@ static struct __netgrent dataset; /* Set up NIP to run through the services. Return nonzero if there are no services (left). */ static int -setup (void **fctp, service_user **nipp) +setup (void **fctp, nss_action_list *nipp) { - /* Remember the first service_entry, it's always the same. */ - static bool startp_initialized; - static service_user *startp; int no_more; - if (!startp_initialized) - { - /* Executing this more than once at the same time must yield the - same result every time. So we need no locking. */ - no_more = __nss_netgroup_lookup2 (nipp, "setnetgrent", NULL, fctp); - startp = no_more ? (service_user *) -1 : *nipp; -#ifdef PTR_MANGLE - PTR_MANGLE (startp); -#endif - atomic_write_barrier (); - startp_initialized = true; - } - else - { - service_user *nip = startp; -#ifdef PTR_DEMANGLE - PTR_DEMANGLE (nip); -#endif - if (nip == (service_user *) -1) - /* No services at all. */ - return 1; - - /* Reset to the beginning of the service list. */ - *nipp = nip; - /* Look up the first function. */ - no_more = __nss_lookup (nipp, "setnetgrent", NULL, fctp); - } + no_more = __nss_netgroup_lookup2 (nipp, "setnetgrent", NULL, fctp); + return no_more; } @@ -100,7 +72,7 @@ endnetgrent_hook (struct __netgrent *datap) { enum nss_status (*endfct) (struct __netgrent *); - if (datap->nip == NULL || datap->nip == (service_user *) -1l) + if (datap->nip == NULL || datap->nip == (nss_action_list) -1l) return; endfct = __nss_lookup_function (datap->nip, "endnetgrent"); @@ -133,7 +105,7 @@ __internal_setnetgrent_reuse (const char *group, struct __netgrent *datap, /* Ignore status, we force check in `__nss_next2'. */ status = DL_CALL_FCT (*fct.f, (group, datap)); - service_user *old_nip = datap->nip; + nss_action_list old_nip = datap->nip; no_more = __nss_next2 (&datap->nip, "setnetgrent", NULL, &fct.ptr, status, 0); @@ -275,7 +247,7 @@ __internal_getnetgrent_r (char **hostp, char **userp, char **domainp, /* This bogus function pointer is a special marker left by __nscd_setnetgrent to tell us to use the data it left before considering any modules. */ - if (datap->nip == (service_user *) -1l) + if (datap->nip == (nss_action_list) -1l) fct = nscd_getnetgrent; else #endif diff --git a/inet/netgroup.h b/inet/netgroup.h index 53081db78f..910094b9ca 100644 --- a/inet/netgroup.h +++ b/inet/netgroup.h @@ -64,7 +64,7 @@ struct __netgrent /* This handle for the NSS data base is shared between all set/get/endXXXent functions. */ - service_user *nip; + struct nss_action *nip; }; diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index b328cca7c6..0769ad7a6f 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -20,7 +20,7 @@ #include #include -#include "../nss/nss_module.h" +#include "../nss/nsswitch.h" #include "../libio/libioP.h" DEFINE_HOOK (__libc_subfreeres, (void)); @@ -43,6 +43,8 @@ __libc_freeres (void) void *const *p; call_function_static_weak (__nss_module_freeres); + call_function_static_weak (__nss_action_freeres); + call_function_static_weak (__nss_database_freeres); _IO_cleanup (); diff --git a/nscd/aicache.c b/nscd/aicache.c index ee9c9b8843..ce3bb382ce 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -71,20 +71,15 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) key); } - static service_user *hosts_database; - service_user *nip; + nss_action_list nip; int no_more; int rc6 = 0; int rc4 = 0; int herrno = 0; - if (hosts_database == NULL) - no_more = __nss_database_lookup2 ("hosts", NULL, - "dns [!UNAVAIL=return] files", - &hosts_database); - else - no_more = 0; - nip = hosts_database; + no_more = __nss_database_lookup2 ("hosts", NULL, + "dns [!UNAVAIL=return] files", + &nip); /* Initialize configurations. */ struct resolv_context *ctx = __resolv_context_get (); @@ -442,10 +437,10 @@ next_nip: if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + if (nip[1].module == NULL) no_more = -1; else - nip = nip->next; + ++ nip; } /* No result found. Create a negative result record. */ diff --git a/nscd/gai.c b/nscd/gai.c index 2e19530102..aaaddd8fe5 100644 --- a/nscd/gai.c +++ b/nscd/gai.c @@ -43,4 +43,4 @@ #include /* Some variables normally defined in libc. */ -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index a1102e4e46..7f110d51b4 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -77,8 +77,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in group cache!"), (char *) key); } - static service_user *group_database; - service_user *nip; + static nss_action_list group_database; + nss_action_list nip; int no_more; if (group_database == NULL) @@ -161,10 +161,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, && nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + if (nip[1].module == NULL) no_more = -1; else - nip = nip->next; + ++ nip; } bool all_written; diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 88c69d1e9c..67be24e837 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -124,7 +124,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in netgroup cache!"), key); } - static service_user *netgroup_database; + static nss_action_list netgroup_database; time_t timeout; struct dataset *dataset; bool cacheable = false; @@ -175,7 +175,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, void *ptr; } setfct; - service_user *nip = netgroup_database; + nss_action_list nip = netgroup_database; int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr); while (!no_more) { diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c index 7b8dc4081a..0ed9c0cda6 100644 --- a/nscd/nscd_netgroup.c +++ b/nscd/nscd_netgroup.c @@ -116,7 +116,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) datap->data_size = datalen; datap->cursor = respdata; datap->first = 1; - datap->nip = (service_user *) -1l; + datap->nip = (nss_action_list) -1l; datap->known_groups = NULL; datap->needed_groups = NULL; diff --git a/nss/Makefile b/nss/Makefile index ccd1a6ae4f..83323cb934 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -66,7 +66,8 @@ tests-container = \ tst-nss-test3 \ tst-nss-files-hosts-long \ tst-nss-db-endpwent \ - tst-nss-db-endgrent + tst-nss-db-endgrent \ + tst-reload1 # Tests which need libdl ifeq (yes,$(build-shared)) diff --git a/nss/XXX-lookup.c b/nss/XXX-lookup.c index e26c6d7f8b..8ebd9a740a 100644 --- a/nss/XXX-lookup.c +++ b/nss/XXX-lookup.c @@ -53,12 +53,11 @@ #endif int -DB_LOOKUP_FCT (service_user **ni, const char *fct_name, const char *fct2_name, +DB_LOOKUP_FCT (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp) { - if (DATABASE_NAME_SYMBOL == NULL - && __nss_database_lookup2 (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, - DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) + if (__nss_database_lookup2 (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, + DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) return -1; *ni = DATABASE_NAME_SYMBOL; diff --git a/nss/compat-lookup.c b/nss/compat-lookup.c index 9af34150bd..07fcc94f58 100644 --- a/nss/compat-lookup.c +++ b/nss/compat-lookup.c @@ -29,7 +29,7 @@ glibc 2.7 and earlier and glibc 2.8 and later, even on i386. */ int attribute_compat_text_section -__nss_passwd_lookup (service_user **ni, const char *fct_name, void **fctp) +__nss_passwd_lookup (nss_action_list *ni, const char *fct_name, void **fctp) { __set_errno (ENOSYS); return -1; @@ -46,11 +46,11 @@ compat_symbol (libc, __nss_hosts_lookup, __nss_hosts_lookup, GLIBC_2_0); /* These functions were exported under a non-GLIBC_PRIVATE version, even though it is not usable externally due to the service_user - type dependency. */ + (now nss_action_list) type dependency. */ int attribute_compat_text_section -__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, +__nss_next (nss_action_list *ni, const char *fct_name, void **fctp, int status, int all_values) { return -1; @@ -60,7 +60,7 @@ compat_symbol (libc, __nss_next, __nss_next, GLIBC_2_0); int attribute_compat_text_section __nss_database_lookup (const char *database, const char *alternate_name, - const char *defconfig, service_user **ni) + const char *defconfig, nss_action_list *ni) { *ni = NULL; return -1; diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index e8c9ab1bb3..6c287a6127 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -179,7 +179,7 @@ typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, EXTRA_PARAMS); /* The lookup function for the first entry of this service. */ -extern int DB_LOOKUP_FCT (service_user **nip, const char *name, +extern int DB_LOOKUP_FCT (nss_action_list *nip, const char *name, const char *name2, void **fctp); libc_hidden_proto (DB_LOOKUP_FCT) @@ -189,10 +189,7 @@ 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; + nss_action_list nip; int do_merge = 0; LOOKUP_TYPE mergegrp; char *mergebuf = NULL; @@ -227,6 +224,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, PREPROCESS; #endif + #ifdef HANDLE_DIGITS_DOTS switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL, buflen, result, &status, AF_VAL, @@ -264,47 +262,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, } #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 - { - 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; - } + no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, + REENTRANT2_NAME_STRING, &fct.ptr); while (no_more == 0) { diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c index 8b64fcd795..dfcbd01f66 100644 --- a/nss/getXXent_r.c +++ b/nss/getXXent_r.c @@ -95,11 +95,11 @@ /* This handle for the NSS data base is shared between all set/get/endXXXent functions. */ -static service_user *nip; +static nss_action_list 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; +static nss_action_list last_nip; +/* Remember the first service_entry across set/get/endent. */ +static nss_action_list startp; #ifdef STAYOPEN_TMP /* We need to remember the last `stayopen' flag given by the user @@ -112,7 +112,7 @@ static STAYOPEN_TMP; __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, +extern int DB_LOOKUP_FCT (nss_action_list *nip, const char *name, const char *name2, void **fctp); libc_hidden_proto (DB_LOOKUP_FCT) diff --git a/nss/getnssent_r.c b/nss/getnssent_r.c index 8a366bc7ea..84e977c33b 100644 --- a/nss/getnssent_r.c +++ b/nss/getnssent_r.c @@ -25,20 +25,20 @@ services (left). */ static int setup (const char *func_name, db_lookup_function lookup_fct, - void **fctp, service_user **nip, service_user **startp, int all) + void **fctp, nss_action_list *nip, nss_action_list *startp, int all) { int no_more; - if (*startp == NULL) + if (*startp == NULL || all) { no_more = lookup_fct (nip, func_name, NULL, fctp); - *startp = no_more ? (service_user *) -1l : *nip; + *startp = no_more ? (nss_action_list) -1l : *nip; } - else if (*startp == (service_user *) -1l) + else if (*startp == (nss_action_list) -1l) /* No services at all. */ return 1; else { - if (all || !*nip) + if (!*nip) /* Reset to the beginning of the service list. */ *nip = *startp; /* Look up the first function. */ @@ -49,8 +49,8 @@ setup (const char *func_name, db_lookup_function lookup_fct, 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, + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int stayopen, int *stayopen_tmp, int res) { union @@ -110,8 +110,8 @@ __nss_setent (const char *func_name, db_lookup_function lookup_fct, void __nss_endent (const char *func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int res) + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int res) { union { @@ -154,8 +154,8 @@ 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, + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int *stayopen_tmp, int res, void *resbuf, char *buffer, size_t buflen, void **result, int *h_errnop) { diff --git a/nss/nss_action.c b/nss/nss_action.c index b9c3b93fea..5008323859 100644 --- a/nss/nss_action.c +++ b/nss/nss_action.c @@ -16,7 +16,7 @@ License along with the GNU C Library; if not, see . */ -#include +#include #include #include diff --git a/nss/nss_action_parse.c b/nss/nss_action_parse.c index ada3acbb08..7a80582842 100644 --- a/nss/nss_action_parse.c +++ b/nss/nss_action_parse.c @@ -16,8 +16,7 @@ License along with the GNU C Library; if not, see . */ -#include "nss_action.h" -#include "nss_module.h" +#include #include #include @@ -169,18 +168,13 @@ nss_action_list action_list_init (&list); if (nss_action_parse (line, &list)) { - size_t size = action_list_size (&list); - nss_action_list result - = malloc (sizeof (*result) * (size + 1)); - if (result == NULL) - { - action_list_free (&list); - return NULL; - } - memcpy (result, action_list_begin (&list), sizeof (*result) * size); - /* Sentinel. */ - result[size].module = NULL; - return result; + size_t size; + struct nss_action null_service + = { .module = NULL, }; + + action_list_add (&list, null_service); + size = action_list_size (&list); + return __nss_action_allocate (action_list_begin (&list), size); } else if (action_list_has_failed (&list)) { diff --git a/nss/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c index 510d49e8c7..6637c96355 100644 --- a/nss/nss_compat/compat-grp.c +++ b/nss/nss_compat/compat-grp.c @@ -30,7 +30,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setgrent_impl) (int stayopen); static enum nss_status (*getgrnam_r_impl) (const char *name, struct group * grp, char *buffer, diff --git a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c index c0dcdf839d..99f7df613a 100644 --- a/nss/nss_compat/compat-initgroups.c +++ b/nss/nss_compat/compat-initgroups.c @@ -33,7 +33,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*initgroups_dyn_impl) (const char *, gid_t, long int *, long int *, gid_t **, long int, int *); diff --git a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c index 3a212a0dab..789878ccbd 100644 --- a/nss/nss_compat/compat-pwd.c +++ b/nss/nss_compat/compat-pwd.c @@ -34,7 +34,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setpwent_impl) (int stayopen); static enum nss_status (*getpwnam_r_impl) (const char *name, struct passwd * pwd, char *buffer, diff --git a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c index d802ee0302..7310da85bd 100644 --- a/nss/nss_compat/compat-spwd.c +++ b/nss/nss_compat/compat-spwd.c @@ -34,7 +34,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setspent_impl) (int stayopen); static enum nss_status (*getspnam_r_impl) (const char *name, struct spwd * sp, char *buffer, size_t buflen, diff --git a/nss/nss_database.c b/nss/nss_database.c index 40162e0bc2..8508af51e3 100644 --- a/nss/nss_database.c +++ b/nss/nss_database.c @@ -226,6 +226,39 @@ process_line (struct nss_database_data *data, char *line) return true; } +int +__nss_configure_lookup (const char *dbname, const char *service_line) +{ + int db; + nss_action_list result; + struct nss_database_state *local; + + /* Convert named database to index. */ + db = name_to_database_index (dbname); + if (db < 0) + /* Not our database (e.g., sudoers). */ + return -1; + + /* Force any load/cache/read whatever to happen, so we can override + it. */ + __nss_database_get (db, &result); + + local = nss_database_state_get (); + + result = __nss_action_parse (service_line); + if (result == NULL) + return -1; + + atomic_store_release (&local->data.reload_disabled, 1); + local->data.services[db] = result; + +#ifdef USE_NSCD + __nss_database_custom[db] = true; +#endif + + return 0; +} + /* Iterate over the lines in FP, parse them, and store them in DATA. Return false on memory allocation failure, true on success. */ static bool @@ -326,8 +359,11 @@ nss_database_check_reload_and_get (struct nss_database_state *local, may have loaded the configuration first, so synchronize with the Release MO store there. */ if (atomic_load_acquire (&local->data.reload_disabled)) - /* No reload, so there is no error. */ - return true; + { + *result = local->data.services[database_index]; + /* No reload, so there is no error. */ + return true; + } struct file_change_detection initial; if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF)) diff --git a/nss/nss_module.c b/nss/nss_module.c index 1c9eec0c01..59e46c5acb 100644 --- a/nss/nss_module.c +++ b/nss/nss_module.c @@ -16,7 +16,9 @@ License along with the GNU C Library; if not, see . */ -#include +#include +#include +#include #include #include @@ -357,6 +359,66 @@ __nss_module_get_function (struct nss_module *module, const char *name) return fptr; } +#if defined SHARED && defined USE_NSCD +/* Load all libraries for the service. */ +static void +nss_load_all_libraries (const char *service, const char *def) +{ + nss_action_list ni = NULL; + + if (__nss_database_lookup2 (service, NULL, def, &ni) == 0) + while (ni->module != NULL) + { + __nss_module_load (ni->module); + ++ ni; + } +} + +define_traced_file (pwd, _PATH_NSSWITCH_CONF); +define_traced_file (grp, _PATH_NSSWITCH_CONF); +define_traced_file (hst, _PATH_NSSWITCH_CONF); +define_traced_file (serv, _PATH_NSSWITCH_CONF); +define_traced_file (netgr, _PATH_NSSWITCH_CONF); + +/* Called by nscd and nscd alone. */ +void +__nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) +{ + void (*cb1) (size_t, struct traced_file *); + cb1 = cb; +# 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", DEFAULT_CONFIG); + nss_load_all_libraries ("group", DEFAULT_CONFIG); + nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files"); + nss_load_all_libraries ("services", NULL); + + /* Make sure NSCD purges its cache if nsswitch.conf changes. */ + init_traced_file (&pwd_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (pwddb, &pwd_traced_file.file); + init_traced_file (&grp_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (grpdb, &grp_traced_file.file); + init_traced_file (&hst_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (hstdb, &hst_traced_file.file); + init_traced_file (&serv_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (servdb, &serv_traced_file.file); + init_traced_file (&netgr_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (netgrdb, &netgr_traced_file.file); + + /* 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 + void __libc_freeres_fn_section __nss_module_freeres (void) { diff --git a/nss/nss_test.h b/nss/nss_test.h index 49a9aff2fd..b6c6ad2333 100644 --- a/nss/nss_test.h +++ b/nss/nss_test.h @@ -33,10 +33,12 @@ #include #include +#include typedef struct test_tables { struct passwd *pwd_table; struct group *grp_table; + struct hostent *host_table; } test_tables; extern void _nss_test1_init_hook (test_tables *) __attribute__((weak)); @@ -44,9 +46,11 @@ extern void _nss_test2_init_hook (test_tables *) __attribute__((weak)); #define PWD_LAST() { .pw_name = NULL, .pw_uid = 0 } #define GRP_LAST() { .gr_name = NULL, .gr_gid = 0 } +#define HOST_LAST() { .h_name = NULL, .h_aliases = NULL, .h_length = 0, .h_addr_list = NULL } #define PWD_ISLAST(p) ((p)->pw_name == NULL && (p)->pw_uid == 0) #define GRP_ISLAST(g) ((g)->gr_name == NULL && (g)->gr_gid == 0) +#define HOST_ISLAST(h) ((h)->h_name == NULL && (h)->h_length == 0) /* Macros to fill in the tables easily. */ @@ -72,6 +76,11 @@ extern void _nss_test2_init_hook (test_tables *) __attribute__((weak)); { .gr_name = (char *) n, .gr_passwd = (char *) "*", .gr_gid = u, \ .gr_mem = (char **) m } +#define HOST(u) \ + { .h_name = (char *) "name" #u, .h_aliases = NULL, .h_addrtype = u, \ + .h_length = 4, \ + .h_addr_list = (char **) hostaddr_##u } + /*------------------------------------------------------------*/ /* Helper functions for testing passwd entries. Call diff --git a/nss/nss_test1.c b/nss/nss_test1.c index 13532cd7ab..212719dc98 100644 --- a/nss/nss_test1.c +++ b/nss/nss_test1.c @@ -66,6 +66,9 @@ static int npwd_data = default_npwd_data; static struct group *grp_data = NULL; static int ngrp_data = 0; +static struct hostent *host_data = NULL; +static int nhost_data = 0; + /* This function will get called, and once per session, look back into the test case's executable for an init hook function, and call it. */ @@ -99,6 +102,13 @@ init(void) ; ngrp_data = i; } + if (t.host_table) + { + host_data = t.host_table; + for (i=0; ! HOST_ISLAST(& host_data[i]); i++) + ; + nhost_data = i; + } } initted = 1; } @@ -280,7 +290,7 @@ NAME(getgrent_r) (struct group *result, char *buffer, size_t buflen, ++grp_iter; } - pthread_mutex_unlock (&pwd_lock); + pthread_mutex_unlock (&grp_lock); return res; } @@ -312,3 +322,157 @@ NAME(getgrnam_r) (const char *name, struct group *result, char *buffer, return NSS_STATUS_NOTFOUND; } + +/* -------------------------------------------------- */ +/* Host handling. */ + +static size_t host_iter; +#define CURHOST host_data[host_iter] + +static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER; + +enum nss_status +NAME(sethostent) (int stayopen) +{ + init(); + host_iter = 0; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +NAME(endhostent) (void) +{ + init(); + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +copy_host (struct hostent *result, struct hostent *local, + char *buffer, size_t buflen, int *errnop) +{ + struct alloc_buffer buf = alloc_buffer_create (buffer, buflen); + char **memlist; + int i, j; + + if (local->h_addr_list) + { + i = 0; + while (local->h_addr_list[i]) + ++i; + + memlist = alloc_buffer_alloc_array (&buf, char *, i + 1); + + if (memlist) { + for (j = 0; j < i; ++j) + memlist[j] = alloc_buffer_maybe_copy_string (&buf, local->h_addr_list[j]); + memlist[j] = NULL; + } + + result->h_addr_list = memlist; + } + else + { + result->h_addr_list = NULL; + } + + result->h_aliases = NULL; + result->h_addrtype = AF_INET; + result->h_length = 4; + result->h_name = alloc_buffer_maybe_copy_string (&buf, local->h_name); + + if (alloc_buffer_has_failed (&buf)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +NAME(gethostent_r) (struct hostent *ret, char *buffer, size_t buflen, + struct hostent **result, int *errnop) +{ + int res = NSS_STATUS_SUCCESS; + + init(); + pthread_mutex_lock (&host_lock); + + if (host_iter >= nhost_data) + { + res = NSS_STATUS_NOTFOUND; + *result = NULL; + } + else + { + res = copy_host (ret, &CURHOST, buffer, buflen, errnop); + *result = ret; + ++host_iter; + } + + pthread_mutex_unlock (&host_lock); + + return res; +} + +enum nss_status +NAME(gethostbyname3_r) (const char *name, int af, struct hostent *ret, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp) +{ + init(); + + for (size_t idx = 0; idx < nhost_data; ++idx) + if (strcmp (host_data[idx].h_name, name) == 0) + return copy_host (ret, & host_data[idx], buffer, buflen, h_errnop); + + return NSS_STATUS_NOTFOUND; +} + +enum nss_status +NAME(gethostbyname_r) (const char *name, struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + return NAME(gethostbyname3_r) (name, AF_INET, result, buffer, buflen, + errnop, h_errnop, NULL, NULL); +} + +enum nss_status +NAME(gethostbyname2_r) (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + return NAME(gethostbyname3_r) (name, af, result, buffer, buflen, + errnop, h_errnop, NULL, NULL); +} + +enum nss_status +NAME(gethostbyaddr2_r) (const void *addr, socklen_t len, int af, + struct hostent *result, char *buffer, size_t buflen, + int *errnop, int *h_errnop, int32_t *ttlp) +{ + init(); + + /* Support this later. */ + if (len != 4) + return NSS_STATUS_NOTFOUND; + + for (size_t idx = 0; idx < nhost_data; ++idx) + if (memcmp (host_data[idx].h_addr, addr, len) == 0) + return copy_host (result, & host_data[idx], buffer, buflen, h_errnop); + + return NSS_STATUS_NOTFOUND; +} + +/* Note: only the first address is supported, intentionally. */ +enum nss_status +NAME(gethostbyaddr_r) (const void *addr, socklen_t len, int af, + struct hostent *result, char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + return NAME(gethostbyaddr2_r) (addr, len, af, result, buffer, buflen, + errnop, h_errnop, NULL); +} diff --git a/nss/nsswitch.c b/nss/nsswitch.c index 8d7b69d4bc..9b73296c5f 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -32,6 +32,7 @@ #include #include #include +#include #if !defined DO_STATIC_NSS || defined SHARED # include @@ -42,36 +43,20 @@ #include #include -/* Prototypes for the local functions. */ -static name_database *nss_parse_file (const char *fname); -static name_database_entry *nss_getline (char *line); -static service_user *nss_parse_service_list (const char *line); -#if !defined DO_STATIC_NSS || defined SHARED -static service_library *nss_new_service (name_database *database, - const char *name); -#endif - - /* Declare external database variables. */ #define DEFINE_DATABASE(name) \ - service_user *__nss_##name##_database attribute_hidden; \ + nss_action_list __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 DEFINE_DATABASE(name) #name, +static const char * database_names[] = { +#include "databases.def" + NULL }; -#define ndatabases (sizeof (databases) / sizeof (databases[0])) #ifdef USE_NSCD /* Flags whether custom rules for database is set. */ @@ -79,103 +64,33 @@ bool __nss_database_custom[NSS_DBSIDX_max]; #endif -__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 - +/*__libc_lock_define_initialized (static, lock)*/ /* -1 == database not found 0 == database entry pointer stored */ int __nss_database_lookup2 (const char *database, const char *alternate_name, - const char *defconfig, service_user **ni) + const char *defconfig, nss_action_list *ni) { - /* Prevent multiple threads to change the service table. */ - __libc_lock_lock (lock); + int database_id; - /* 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; - } + for (database_id = 0; database_names[database_id]; database_id ++) + if (strcmp (database_names[database_id], database) == 0) + break; - /* Are we initialized yet? */ - if (service_table == NULL) - /* Read config file. */ - service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + if (database_names[database_id] == NULL) + return -1; - /* Test whether configuration data is available. */ - if (service_table != NULL) + if (__nss_database_get (database_id, ni)) { - /* 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; + /* Success. */ + return 0; } - - /* 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) + else { - *ni = nss_parse_service_list (defconfig ?: "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; - } - } + /* Failure. */ + return -1; } - - __libc_lock_unlock (lock); - - return *ni != NULL ? 0 : -1; } libc_hidden_def (__nss_database_lookup2) @@ -184,7 +99,7 @@ libc_hidden_def (__nss_database_lookup2) 0 == function found 1 == finished */ int -__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, +__nss_lookup (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp) { *fctp = __nss_lookup_function (*ni, fct_name); @@ -193,16 +108,16 @@ __nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE - && (*ni)->next != NULL) + && (*ni)[1].module != NULL) { - *ni = (*ni)->next; + ++ (*ni); *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; + return *fctp != NULL ? 0 : (*ni)[1].module == NULL ? 1 : -1; } libc_hidden_def (__nss_lookup) @@ -211,7 +126,7 @@ libc_hidden_def (__nss_lookup) 0 == adjusted for next function 1 == finished */ int -__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, +__nss_next2 (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp, int status, int all_values) { if (all_values) @@ -233,12 +148,12 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, return 1; } - if ((*ni)->next == NULL) + if ((*ni)[1].module == NULL) return -1; do { - *ni = (*ni)->next; + ++ (*ni); *fctp = __nss_lookup_function (*ni, fct_name); if (*fctp == NULL && fct2_name != NULL) @@ -246,675 +161,17 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, } while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE - && (*ni)->next != NULL); + && (*ni)[1].module != NULL); return *fctp != NULL ? 0 : -1; } libc_hidden_def (__nss_next2) -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; -#ifdef USE_NSCD - __nss_database_custom[cnt] = true; -#endif - - __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 * -nss_parse_file (const char *fname) +__nss_lookup_function (nss_action_list ni, const char *fct_name) { - 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) + if (ni->module == 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: - `( ( "[" "!"? ( "=" )+ "]" )? )*' - */ -static service_user * -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 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 * -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 ` ":"'. */ - 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 * -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_lookup2 (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", "files"); - nss_load_all_libraries ("group", "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); + return __nss_module_get_function (ni->module, fct_name); } +libc_hidden_def (__nss_lookup_function) diff --git a/nss/nsswitch.h b/nss/nsswitch.h index eaf81587d6..61b92a7115 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -36,6 +36,7 @@ typedef enum NSS_ACTION_MERGE } lookup_actions; +struct nss_action; typedef struct service_library { @@ -58,42 +59,8 @@ typedef struct } 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; +#define nss_next_action(ni, status) nss_action_get (ni, status) #ifdef USE_NSCD @@ -127,13 +94,13 @@ extern bool __nss_database_custom[NSS_DBSIDX_max] attribute_hidden; than one function can use the database. */ extern int __nss_database_lookup2 (const char *database, const char *alternative_name, - const char *defconfig, service_user **ni); + const char *defconfig, struct nss_action **ni); libc_hidden_proto (__nss_database_lookup2) /* 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, +extern int __nss_lookup (struct nss_action **ni, const char *fct_name, const char *fct2_name, void **fctp); libc_hidden_proto (__nss_lookup) @@ -150,16 +117,16 @@ libc_hidden_proto (__nss_lookup) 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, +extern int __nss_next2 (struct nss_action **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, +extern int __nss_next (struct nss_action **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); +extern void *__nss_lookup_function (struct nss_action *ni, const char *fct_name); libc_hidden_proto (__nss_lookup_function) @@ -169,7 +136,7 @@ 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 *, +typedef int (*db_lookup_function) (struct nss_action **, const char *, const char *, void **); typedef enum nss_status (*setent_function) (int); typedef enum nss_status (*endent_function) (void); @@ -180,20 +147,20 @@ typedef int (*getent_r_function) (void *, char *, size_t, 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, + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int stayon, int *stayon_tmp, int res) attribute_hidden; 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) + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int res) attribute_hidden; 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, + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int *stayon_tmp, int res, void *resbuf, char *buffer, size_t buflen, void **result, int *h_errnop) @@ -227,11 +194,15 @@ libc_hidden_proto (__nss_hostname_digits_dots) /* Prototypes for __nss_*_lookup2 functions. */ #define DEFINE_DATABASE(arg) \ - extern service_user *__nss_##arg##_database attribute_hidden; \ - int __nss_##arg##_lookup2 (service_user **, const char *, \ + extern struct nss_action *__nss_##arg##_database attribute_hidden; \ + int __nss_##arg##_lookup2 (struct nss_action **, const char *, \ const char *, void **); \ libc_hidden_proto (__nss_##arg##_lookup2) #include "databases.def" #undef DEFINE_DATABASE +#include +#include +#include + #endif /* nsswitch.h */ diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c new file mode 100644 index 0000000000..8e6241382b --- /dev/null +++ b/nss/tst-reload1.c @@ -0,0 +1,341 @@ +/* Test that nsswitch.conf reloading actually works. + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nss_test.h" + +/* Size of buffers used by *_r functions. */ +#define TESTBUFLEN 4096 + +static struct passwd pwd_table_1[] = { + PWD (100), + PWD (30), + PWD (200), + PWD (60), + PWD (20000), + PWD_LAST () + }; + +static const char *hostaddr_5[] = + { + "ABCD", "abcd", "1234", NULL + }; + +static const char *hostaddr_15[] = + { + "4321", "ghij", NULL + }; + +static const char *hostaddr_25[] = + { + "WXYZ", NULL + }; + + +static struct hostent host_table_1[] = { + HOST (5), + HOST (15), + HOST (25), + HOST_LAST () +}; + +void +_nss_test1_init_hook(test_tables *t) +{ + t->pwd_table = pwd_table_1; + t->host_table = host_table_1; +} + +/* The first of these must not appear in pwd_table_1. */ +static struct passwd pwd_table_2[] = { + PWD (5), + PWD_N(200, "name30"), + PWD (16), + PWD_LAST () + }; + +static const char *hostaddr_6[] = + { + "mnop", NULL + }; + +static const char *hostaddr_16[] = + { + "7890", "a1b2", NULL + }; + +static const char *hostaddr_26[] = + { + "qwer", "tyui", NULL + }; + +static struct hostent host_table_2[] = { + HOST (6), + HOST (16), + HOST (26), + HOST_LAST () +}; + +void +_nss_test2_init_hook(test_tables *t) +{ + t->pwd_table = pwd_table_2; + t->host_table = host_table_2; +} + +static void +must_be_tests (struct passwd *pt, struct hostent *ht) +{ + int i; + struct hostent *h; + + struct passwd *p; + for (i = 0; !PWD_ISLAST (&pt[i]); ++ i) + { + p = getpwuid (pt[i].pw_uid); + TEST_VERIFY (p != NULL); + if (p != NULL) + { + TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0); + } + } + + setpwent (); + for (i = 0; !PWD_ISLAST (&pt[i]); ++ i) + { + p = getpwent (); + TEST_VERIFY (p != NULL); + if (p != NULL) + { + TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0); + TEST_VERIFY (p->pw_uid == pt[i].pw_uid); + } + } + endpwent (); + + for (i = 0; !HOST_ISLAST (&ht[i]); ++ i) + { + h = gethostbyname (ht[i].h_name); + TEST_VERIFY (h != NULL); + if (h != NULL) + { + TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0); + TEST_VERIFY (h->h_addr_list[0] != NULL); + if (h->h_addr_list[0]) + TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0); + } + } + + for (i = 0; !HOST_ISLAST (&ht[i]); ++ i) + { + struct hostent r, *rp; + char buf[TESTBUFLEN]; + int herrno, res; + + res = gethostbyname2_r (ht[i].h_name, AF_INET, + &r, buf, TESTBUFLEN, &rp, &herrno); + TEST_VERIFY (res == 0); + if (res == 0) + { + TEST_VERIFY (strcmp (r.h_name, ht[i].h_name) == 0); + TEST_VERIFY (r.h_addr_list[0] != NULL); + if (r.h_addr_list[0]) + TEST_VERIFY (strcmp (r.h_addr_list[0], ht[i].h_addr_list[0]) == 0); + } + } + + for (i = 0; !HOST_ISLAST (&ht[i]); ++ i) + { + h = gethostbyaddr (ht[i].h_addr, 4, AF_INET); + TEST_VERIFY (h != NULL); + if (h != NULL) + { + TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0); + TEST_VERIFY (h->h_addr_list[0] != NULL); + if (h->h_addr_list[0]) + TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0); + } + } + + /* getaddrinfo */ + + for (i = 0; !HOST_ISLAST (&ht[i]); ++ i) + { + struct addrinfo *ap; + struct addrinfo hint; + int res, j; + + memset (&hint, 0, sizeof (hint)); + hint.ai_family = AF_INET; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = 0; + hint.ai_flags = 0; + + ap = NULL; + res = getaddrinfo (ht[i].h_name, NULL, &hint, &ap); + TEST_VERIFY (res == 0); + TEST_VERIFY (ap != NULL); + if (res == 0 && ap != NULL) + { + j = 0; /* which address in the list */ + while (ap) + { + struct sockaddr_in *in = (struct sockaddr_in *)ap->ai_addr; + unsigned char *up = (unsigned char *)&in->sin_addr; + + TEST_VERIFY (memcmp (up, ht[i].h_addr_list[j], 4) == 0); + + ap = ap->ai_next; + ++ j; + } + } + } + + /* getnameinfo */ + + for (i = 0; !HOST_ISLAST (&ht[i]); ++ i) + { + struct sockaddr_in addr; + int res; + char host_buf[NI_MAXHOST]; + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = 80; + memcpy (& addr.sin_addr, ht[i].h_addr_list[0], 4); + + res = getnameinfo ((struct sockaddr *) &addr, sizeof(addr), + host_buf, sizeof(host_buf), + NULL, 0, NI_NOFQDN); + + TEST_VERIFY (res == 0); + if (res == 0) + TEST_VERIFY (strcmp (ht[i].h_name, host_buf) == 0); + else + printf ("error %s\n", gai_strerror (res)); + } +} + +static void +must_be_1 (void) +{ + struct passwd *p; + + must_be_tests (pwd_table_1, host_table_1); + p = getpwnam("name5"); + TEST_VERIFY (p == NULL); +} + +static void +must_be_2 (void) +{ + struct passwd *p; + + must_be_tests (pwd_table_2, host_table_2); + p = getpwnam("name100"); + TEST_VERIFY (p == NULL); +} + +static void +xrename (const char *a, const char *b) +{ + int i = rename (a, b); + if (i != 0) + FAIL_EXIT1 ("rename(%s,%s) failed: %s\n", a, b, strerror(errno)); +} + +/* If the actions change while in the midst of doing a series of + lookups, make sure they're consistent. */ +static void +test_cross_switch_consistency (void) +{ + int i; + struct passwd *p; + + /* We start by initiating a set/get/end loop on conf1. */ + setpwent (); + for (i = 0; !PWD_ISLAST (&pwd_table_1[i]); ++ i) + { + p = getpwent (); + TEST_VERIFY (p != NULL); + if (p != NULL) + { + TEST_VERIFY (strcmp (p->pw_name, pwd_table_1[i].pw_name) == 0); + TEST_VERIFY (p->pw_uid == pwd_table_1[i].pw_uid); + } + + /* After the first lookup, switch to conf2 and verify */ + if (i == 0) + { + xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1"); + xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf"); + + p = getpwnam (pwd_table_2[0].pw_name); + TEST_VERIFY (p->pw_uid == pwd_table_2[0].pw_uid); + } + + /* But the original loop should still be on conf1. */ + } + endpwent (); + + /* Make sure the set/get/end loop sees conf2 now. */ + setpwent (); + for (i = 0; !PWD_ISLAST (&pwd_table_2[i]); ++ i) + { + p = getpwent (); + TEST_VERIFY (p != NULL); + if (p != NULL) + { + TEST_VERIFY (strcmp (p->pw_name, pwd_table_2[i].pw_name) == 0); + TEST_VERIFY (p->pw_uid == pwd_table_2[i].pw_uid); + } + } + endpwent (); + +} + +static int +do_test (void) +{ + /* The test1 module was configured at program start. */ + must_be_1 (); + + xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1"); + xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf"); + must_be_2 (); + + xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf2"); + xrename ("/etc/nsswitch.conf1", "/etc/nsswitch.conf"); + must_be_1 (); + + test_cross_switch_consistency (); + + return 0; +} + +#include diff --git a/nss/tst-reload1.root/etc/nsswitch.conf b/nss/tst-reload1.root/etc/nsswitch.conf new file mode 100644 index 0000000000..606d8f51d6 --- /dev/null +++ b/nss/tst-reload1.root/etc/nsswitch.conf @@ -0,0 +1,3 @@ +passwd: test1 +group: test1 +hosts: test1 diff --git a/nss/tst-reload1.root/etc/nsswitch.conf2 b/nss/tst-reload1.root/etc/nsswitch.conf2 new file mode 100644 index 0000000000..2e93977efb --- /dev/null +++ b/nss/tst-reload1.root/etc/nsswitch.conf2 @@ -0,0 +1,3 @@ +passwd: test2 +group: test2 +hosts: test2 diff --git a/nss/tst-reload1.root/etc/services b/nss/tst-reload1.root/etc/services new file mode 100644 index 0000000000..94d4f07612 --- /dev/null +++ b/nss/tst-reload1.root/etc/services @@ -0,0 +1 @@ +http 80/tcp diff --git a/nss/tst-reload1.root/tst-reload1.script b/nss/tst-reload1.root/tst-reload1.script new file mode 100644 index 0000000000..a10beb1e6c --- /dev/null +++ b/nss/tst-reload1.root/tst-reload1.script @@ -0,0 +1,2 @@ +cp $B/nss/libnss_test1.so $L/libnss_test1.so.2 +cp $B/nss/libnss_test2.so $L/libnss_test2.so.2 diff --git a/posix/tst-rfc3484-2.c b/posix/tst-rfc3484-2.c index 8c64ac59ff..5f5ada9420 100644 --- a/posix/tst-rfc3484-2.c +++ b/posix/tst-rfc3484-2.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/posix/tst-rfc3484-3.c b/posix/tst-rfc3484-3.c index 1c61aaf844..d9ec5cc851 100644 --- a/posix/tst-rfc3484-3.c +++ b/posix/tst-rfc3484-3.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/posix/tst-rfc3484.c b/posix/tst-rfc3484.c index 8f45848e44..97d065b6bf 100644 --- a/posix/tst-rfc3484.c +++ b/posix/tst-rfc3484.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/sunrpc/netname.c b/sunrpc/netname.c index 61d82ca31a..aa64362b4b 100644 --- a/sunrpc/netname.c +++ b/sunrpc/netname.c @@ -145,9 +145,7 @@ int netname2user (const char netname[MAXNETNAMELEN + 1], uid_t * uidp, gid_t * gidp, int *gidlenp, gid_t * gidlist) { - static service_user *startp; - static netname2user_function start_fct; - service_user *nip; + nss_action_list nip; union { netname2user_function f; @@ -156,22 +154,7 @@ netname2user (const char netname[MAXNETNAMELEN + 1], uid_t * uidp, gid_t * gidp, enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "netname2user", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) - 1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) - 1; - } + no_more = __nss_publickey_lookup2 (&nip, "netname2user", NULL, &fct.ptr); while (!no_more) { diff --git a/sunrpc/publickey.c b/sunrpc/publickey.c index 2fa0252d5b..63866ef900 100644 --- a/sunrpc/publickey.c +++ b/sunrpc/publickey.c @@ -34,9 +34,7 @@ typedef int (*secret_function) (const char *, char *, const char *, int *); int getpublickey (const char *name, char *key) { - static service_user *startp; - static public_function start_fct; - service_user *nip; + nss_action_list nip; union { public_function f; @@ -45,22 +43,7 @@ getpublickey (const char *name, char *key) enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "getpublickey", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_publickey_lookup2 (&nip, "getpublickey", NULL, &fct.ptr); while (! no_more) { @@ -77,9 +60,7 @@ libc_hidden_nolink_sunrpc (getpublickey, GLIBC_2_0) int getsecretkey (const char *name, char *key, const char *passwd) { - static service_user *startp; - static secret_function start_fct; - service_user *nip; + nss_action_list nip; union { secret_function f; @@ -88,22 +69,7 @@ getsecretkey (const char *name, char *key, const char *passwd) enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "getsecretkey", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_publickey_lookup2 (&nip, "getsecretkey", NULL, &fct.ptr); while (! no_more) { diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index ed04e564f9..39e54fc741 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -307,7 +307,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, memory allocation failure. The returned string is allocated on the heap; the caller has to free it. */ static char * -getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name) +getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) { nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); char *s = (char *) name; @@ -538,7 +538,7 @@ gaih_inet (const char *name, const struct gaih_service *service, struct gaih_addrtuple **pat = &at; int no_data = 0; int no_inet6_data = 0; - service_user *nip; + nss_action_list nip; enum nss_status inet6_status = NSS_STATUS_UNAVAIL; enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; @@ -720,13 +720,9 @@ gaih_inet (const char *name, const struct gaih_service *service, } #endif - if (__nss_hosts_database == NULL) - no_more = __nss_database_lookup2 ("hosts", NULL, - "dns [!UNAVAIL=return] files", - &__nss_hosts_database); - else - no_more = 0; - nip = __nss_hosts_database; + no_more = __nss_database_lookup2 ("hosts", NULL, + "dns [!UNAVAIL=return] files", + &nip); /* If we are looking for both IPv4 and IPv6 address we don't want the lookup functions to automatically promote IPv4 @@ -905,10 +901,9 @@ gaih_inet (const char *name, const struct gaih_service *service, if (nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + nip ++; + if (nip->module == NULL) no_more = -1; - else - nip = nip->next; } __resolv_context_put (res_ctx);