LCOV - code coverage report
Current view: top level - third_party/nss_wrapper - nss_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 1556 2626 59.3 %
Date: 2024-02-28 12:06:22 Functions: 116 159 73.0 %

          Line data    Source code
       1             : /*
       2             :  * BSD 3-Clause License
       3             :  *
       4             :  * Copyright (c) 2007,      Stefan Metzmacher <metze@samba.org>
       5             :  * Copyright (c) 2009,      Guenther Deschner <gd@samba.org>
       6             :  * Copyright (c) 2014-2015, Michael Adam <obnox@samba.org>
       7             :  * Copyright (c) 2015,      Robin Hack <hack.robin@gmail.com>
       8             :  * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
       9             :  * All rights reserved.
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  *
      15             :  * 1. Redistributions of source code must retain the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer.
      17             :  *
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  *
      22             :  * 3. Neither the name of the author nor the names of its contributors
      23             :  *    may be used to endorse or promote products derived from this software
      24             :  *    without specific prior written permission.
      25             :  *
      26             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      27             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      28             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      29             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      30             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      31             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      32             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      33             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      34             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      35             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      36             :  * SUCH DAMAGE.
      37             :  */
      38             : 
      39             : #include "config.h"
      40             : 
      41             : #include <pthread.h>
      42             : 
      43             : #include <sys/types.h>
      44             : #include <sys/stat.h>
      45             : #include <sys/socket.h>
      46             : #include <errno.h>
      47             : #include <fcntl.h>
      48             : #include <stdarg.h>
      49             : #include <stdbool.h>
      50             : #include <stddef.h>
      51             : #include <stdio.h>
      52             : #include <stdint.h>
      53             : #include <stdlib.h>
      54             : #include <string.h>
      55             : #include <unistd.h>
      56             : #include <ctype.h>
      57             : #include <limits.h>
      58             : 
      59             : #include <netinet/in.h>
      60             : 
      61             : #include <search.h>
      62             : #include <assert.h>
      63             : 
      64             : #include "nss_utils.h"
      65             : /*
      66             :  * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h  gives us
      67             :  * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
      68             :  * Solaris
      69             :  */
      70             : #ifndef _POSIX_PTHREAD_SEMANTICS
      71             : #define _POSIX_PTHREAD_SEMANTICS
      72             : #endif
      73             : 
      74             : #include <pwd.h>
      75             : #include <grp.h>
      76             : #ifdef HAVE_SHADOW_H
      77             : #include <shadow.h>
      78             : #endif /* HAVE_SHADOW_H */
      79             : 
      80             : #include <netdb.h>
      81             : #include <arpa/inet.h>
      82             : #include <netinet/in.h>
      83             : 
      84             : #include <dlfcn.h>
      85             : 
      86             : #if defined(HAVE_NSS_H)
      87             : /* Linux and BSD */
      88             : #include <nss.h>
      89             : 
      90             : typedef enum nss_status NSS_STATUS;
      91             : #elif defined(HAVE_NSS_COMMON_H)
      92             : /* Solaris */
      93             : #include <nss_common.h>
      94             : #include <nss_dbdefs.h>
      95             : #include <nsswitch.h>
      96             : 
      97             : typedef nss_status_t NSS_STATUS;
      98             : 
      99             : # define NSS_STATUS_SUCCESS     NSS_SUCCESS
     100             : # define NSS_STATUS_NOTFOUND    NSS_NOTFOUND
     101             : # define NSS_STATUS_UNAVAIL     NSS_UNAVAIL
     102             : # define NSS_STATUS_TRYAGAIN    NSS_TRYAGAIN
     103             : #else
     104             : # error "No nsswitch support detected"
     105             : #endif
     106             : 
     107             : #ifndef PTR_DIFF
     108             : #define PTR_DIFF(p1, p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
     109             : #endif
     110             : 
     111             : #ifndef _PUBLIC_
     112             : #define _PUBLIC_
     113             : #endif
     114             : 
     115             : #ifndef EAI_NODATA
     116             : #define EAI_NODATA EAI_NONAME
     117             : #endif
     118             : 
     119             : #ifndef EAI_ADDRFAMILY
     120             : #define EAI_ADDRFAMILY EAI_FAMILY
     121             : #endif
     122             : 
     123             : #ifndef __STRING
     124             : #define __STRING(x)    #x
     125             : #endif
     126             : 
     127             : #ifndef __STRINGSTRING
     128             : #define __STRINGSTRING(x) __STRING(x)
     129             : #endif
     130             : 
     131             : #ifndef __LINESTR__
     132             : #define __LINESTR__ __STRINGSTRING(__LINE__)
     133             : #endif
     134             : 
     135             : #ifndef __location__
     136             : #define __location__ __FILE__ ":" __LINESTR__
     137             : #endif
     138             : 
     139             : #ifndef DNS_NAME_MAX
     140             : #define DNS_NAME_MAX 255
     141             : #endif
     142             : 
     143             : /* GCC have printf type attribute check. */
     144             : #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
     145             : #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
     146             : #else
     147             : #define PRINTF_ATTRIBUTE(a,b)
     148             : #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
     149             : 
     150             : #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
     151             : #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
     152             : #else
     153             : #define CONSTRUCTOR_ATTRIBUTE
     154             : #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
     155             : 
     156             : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
     157             : #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
     158             : #else
     159             : #define DESTRUCTOR_ATTRIBUTE
     160             : #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
     161             : 
     162             : #define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
     163             : 
     164             : #ifndef SAFE_FREE
     165             : #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
     166             : #endif
     167             : 
     168             : #ifndef discard_const
     169             : #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
     170             : #endif
     171             : 
     172             : #ifndef discard_const_p
     173             : #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
     174             : #endif
     175             : 
     176             : #ifdef HAVE_IPV6
     177             : #define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
     178             : #else
     179             : #define NWRAP_INET_ADDRSTRLEN INET_ADDRSTRLEN
     180             : #endif
     181             : 
     182             : #define MAX(a,b) ((a) < (b) ? (b) : (a))
     183             : #define MIN(a,b) ((a) > (b) ? (b) : (a))
     184             : 
     185             : static bool nwrap_initialized = false;
     186             : static pthread_mutex_t nwrap_initialized_mutex = PTHREAD_MUTEX_INITIALIZER;
     187             : 
     188             : /* The mutex or accessing the id */
     189             : static pthread_mutex_t nwrap_global_mutex = PTHREAD_MUTEX_INITIALIZER;
     190             : static pthread_mutex_t nwrap_gr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
     191             : static pthread_mutex_t nwrap_he_global_mutex = PTHREAD_MUTEX_INITIALIZER;
     192             : static pthread_mutex_t nwrap_pw_global_mutex = PTHREAD_MUTEX_INITIALIZER;
     193             : static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
     194             : 
     195             : #define nss_wrapper_init_mutex(m) \
     196             :         _nss_wrapper_init_mutex(m, #m)
     197             : 
     198             : /* Add new global locks here please */
     199             : /* Also don't forget to add locks to
     200             :  * nwrap_init() function.
     201             :  */
     202             : # define NWRAP_REINIT_ALL do { \
     203             :         int ret; \
     204             :         ret = nss_wrapper_init_mutex(&nwrap_initialized_mutex); \
     205             :         if (ret != 0) exit(-1); \
     206             :         ret = nss_wrapper_init_mutex(&nwrap_global_mutex); \
     207             :         if (ret != 0) exit(-1); \
     208             :         ret = nss_wrapper_init_mutex(&nwrap_gr_global_mutex); \
     209             :         if (ret != 0) exit(-1); \
     210             :         ret = nss_wrapper_init_mutex(&nwrap_he_global_mutex); \
     211             :         if (ret != 0) exit(-1); \
     212             :         ret = nss_wrapper_init_mutex(&nwrap_pw_global_mutex); \
     213             :         if (ret != 0) exit(-1); \
     214             :         ret = nss_wrapper_init_mutex(&nwrap_sp_global_mutex); \
     215             :         if (ret != 0) exit(-1); \
     216             : } while(0)
     217             : 
     218             : # define NWRAP_LOCK_ALL do { \
     219             :         nwrap_mutex_lock(&nwrap_initialized_mutex); \
     220             :         nwrap_mutex_lock(&nwrap_global_mutex); \
     221             :         nwrap_mutex_lock(&nwrap_gr_global_mutex); \
     222             :         nwrap_mutex_lock(&nwrap_he_global_mutex); \
     223             :         nwrap_mutex_lock(&nwrap_pw_global_mutex); \
     224             :         nwrap_mutex_lock(&nwrap_sp_global_mutex); \
     225             : } while (0);
     226             : 
     227             : # define NWRAP_UNLOCK_ALL do {\
     228             :         nwrap_mutex_unlock(&nwrap_sp_global_mutex); \
     229             :         nwrap_mutex_unlock(&nwrap_pw_global_mutex); \
     230             :         nwrap_mutex_unlock(&nwrap_he_global_mutex); \
     231             :         nwrap_mutex_unlock(&nwrap_gr_global_mutex); \
     232             :         nwrap_mutex_unlock(&nwrap_global_mutex); \
     233             :         nwrap_mutex_unlock(&nwrap_initialized_mutex); \
     234             : } while (0);
     235             : 
     236             : static void nwrap_init(void);
     237             : 
     238             : enum nwrap_dbglvl_e {
     239             :         NWRAP_LOG_ERROR = 0,
     240             :         NWRAP_LOG_WARN,
     241             :         NWRAP_LOG_DEBUG,
     242             :         NWRAP_LOG_TRACE
     243             : };
     244             : 
     245             : #ifndef HAVE_GETPROGNAME
     246    24941245 : static const char *getprogname(void)
     247             : {
     248             : #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
     249    24941245 :         return program_invocation_short_name;
     250             : #elif defined(HAVE_GETEXECNAME)
     251             :         return getexecname();
     252             : #else
     253             :         return NULL;
     254             : #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
     255             : }
     256             : #endif /* HAVE_GETPROGNAME */
     257             : 
     258             : static void nwrap_log(enum nwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
     259             : # define NWRAP_LOG(dbglvl, ...) nwrap_log((dbglvl), __func__, __VA_ARGS__)
     260             : 
     261    24941245 : static void nwrap_log(enum nwrap_dbglvl_e dbglvl,
     262             :                       const char *func,
     263             :                       const char *format, ...)
     264             : {
     265      124331 :         char buffer[1024];
     266      124331 :         va_list va;
     267      124331 :         const char *d;
     268    24941245 :         unsigned int lvl = 0;
     269    24941245 :         const char *prefix = "NWRAP";
     270    24941245 :         const char *progname = getprogname();
     271             : 
     272    24941245 :         d = getenv("NSS_WRAPPER_DEBUGLEVEL");
     273    24941245 :         if (d != NULL) {
     274           0 :                 lvl = atoi(d);
     275             :         }
     276             : 
     277    24941245 :         if (lvl < dbglvl) {
     278    24941245 :                 return;
     279             :         }
     280             : 
     281           0 :         va_start(va, format);
     282           0 :         vsnprintf(buffer, sizeof(buffer), format, va);
     283           0 :         va_end(va);
     284             : 
     285           0 :         switch (dbglvl) {
     286           0 :                 case NWRAP_LOG_ERROR:
     287           0 :                         prefix = "NWRAP_ERROR";
     288           0 :                         break;
     289           0 :                 case NWRAP_LOG_WARN:
     290           0 :                         prefix = "NWRAP_WARN";
     291           0 :                         break;
     292           0 :                 case NWRAP_LOG_DEBUG:
     293           0 :                         prefix = "NWRAP_DEBUG";
     294           0 :                         break;
     295           0 :                 case NWRAP_LOG_TRACE:
     296           0 :                         prefix = "NWRAP_TRACE";
     297           0 :                         break;
     298             :         }
     299             : 
     300           0 :         if (progname == NULL) {
     301           0 :                 progname = "<unknown>";
     302             :         }
     303             : 
     304           0 :         fprintf(stderr,
     305             :                 "%s[%s (%u)] - %s: %s\n",
     306             :                 prefix,
     307             :                 progname,
     308           0 :                 (unsigned int)getpid(),
     309             :                 func,
     310             :                 buffer);
     311             : }
     312             : 
     313             : /*****************
     314             :  * LIBC
     315             :  *****************/
     316             : 
     317             : #define LIBC_NAME "libc.so"
     318             : 
     319             : typedef struct passwd *(*__libc_getpwnam)(const char *name);
     320             : 
     321             : typedef int (*__libc_getpwnam_r)(const char *name,
     322             :                                  struct passwd *pwd,
     323             :                                  char *buf,
     324             :                                  size_t buflen,
     325             :                                  struct passwd **result);
     326             : 
     327             : typedef struct passwd *(*__libc_getpwuid)(uid_t uid);
     328             : 
     329             : typedef int (*__libc_getpwuid_r)(uid_t uid,
     330             :                                  struct passwd *pwd,
     331             :                                  char *buf,
     332             :                                  size_t buflen,
     333             :                                  struct passwd **result);
     334             : 
     335             : typedef void (*__libc_setpwent)(void);
     336             : 
     337             : typedef struct passwd *(*__libc_getpwent)(void);
     338             : 
     339             : #ifdef HAVE_GETPWENT_R
     340             : # ifdef HAVE_SOLARIS_GETPWENT_R
     341             : typedef struct passwd *(*__libc_getpwent_r)(struct passwd *pwbuf,
     342             :                                             char *buf,
     343             :                                             size_t buflen);
     344             : # else /* HAVE_SOLARIS_GETPWENT_R */
     345             : typedef int (*__libc_getpwent_r)(struct passwd *pwbuf,
     346             :                                  char *buf,
     347             :                                  size_t buflen,
     348             :                                  struct passwd **pwbufp);
     349             : # endif /* HAVE_SOLARIS_GETPWENT_R */
     350             : #endif /* HAVE_GETPWENT_R */
     351             : 
     352             : typedef void (*__libc_endpwent)(void);
     353             : 
     354             : typedef int (*__libc_initgroups)(const char *user, gid_t gid);
     355             : 
     356             : typedef struct group *(*__libc_getgrnam)(const char *name);
     357             : 
     358             : typedef int (*__libc_getgrnam_r)(const char *name,
     359             :                                  struct group *grp,
     360             :                                  char *buf,
     361             :                                  size_t buflen,
     362             :                                  struct group **result);
     363             : 
     364             : typedef struct group *(*__libc_getgrgid)(gid_t gid);
     365             : 
     366             : typedef int (*__libc_getgrgid_r)(gid_t gid,
     367             :                                  struct group *grp,
     368             :                                  char *buf,
     369             :                                  size_t buflen,
     370             :                                  struct group **result);
     371             : 
     372             : typedef void (*__libc_setgrent)(void);
     373             : 
     374             : typedef struct group *(*__libc_getgrent)(void);
     375             : 
     376             : #ifdef HAVE_GETGRENT_R
     377             : # ifdef HAVE_SOLARIS_GETGRENT_R
     378             : typedef struct group *(*__libc_getgrent_r)(struct group *group,
     379             :                                            char *buf,
     380             :                                            size_t buflen);
     381             : # else /* HAVE_SOLARIS_GETGRENT_R */
     382             : typedef int (*__libc_getgrent_r)(struct group *group,
     383             :                                  char *buf,
     384             :                                  size_t buflen,
     385             :                                  struct group **result);
     386             : # endif /* HAVE_SOLARIS_GETGRENT_R */
     387             : #endif /* HAVE_GETGRENT_R */
     388             : 
     389             : typedef void (*__libc_endgrent)(void);
     390             : 
     391             : typedef int (*__libc_getgrouplist)(const char *user,
     392             :                                    gid_t group,
     393             :                                    gid_t *groups,
     394             :                                    int *ngroups);
     395             : 
     396             : typedef void (*__libc_sethostent)(int stayopen);
     397             : 
     398             : typedef struct hostent *(*__libc_gethostent)(void);
     399             : 
     400             : typedef void (*__libc_endhostent)(void);
     401             : 
     402             : typedef struct hostent *(*__libc_gethostbyname)(const char *name);
     403             : 
     404             : #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
     405             : typedef struct hostent *(*__libc_gethostbyname2)(const char *name, int af);
     406             : #endif
     407             : 
     408             : #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
     409             : typedef int (*__libc_gethostbyname2_r)(const char *name,
     410             :                               int af,
     411             :                               struct hostent *ret,
     412             :                               char *buf,
     413             :                               size_t buflen,
     414             :                               struct hostent **result,
     415             :                               int *h_errnop);
     416             : #endif
     417             : 
     418             : typedef struct hostent *(*__libc_gethostbyaddr)(const void *addr,
     419             :                                                 socklen_t len,
     420             :                                                 int type);
     421             : 
     422             : typedef int (*__libc_getaddrinfo)(const char *node,
     423             :                                   const char *service,
     424             :                                   const struct addrinfo *hints,
     425             :                                   struct addrinfo **res);
     426             : typedef int (*__libc_getnameinfo)(const struct sockaddr *sa,
     427             :                                   socklen_t salen,
     428             :                                   char *host,
     429             :                                   size_t hostlen,
     430             :                                   char *serv,
     431             :                                   size_t servlen,
     432             :                                   int flags);
     433             : 
     434             : typedef int (*__libc_gethostname)(char *name, size_t len);
     435             : 
     436             : #ifdef HAVE_GETHOSTBYNAME_R
     437             : typedef int (*__libc_gethostbyname_r)(const char *name,
     438             :                              struct hostent *ret,
     439             :                              char *buf, size_t buflen,
     440             :                              struct hostent **result, int *h_errnop);
     441             : #endif
     442             : 
     443             : #ifdef HAVE_GETHOSTBYADDR_R
     444             : typedef int (*__libc_gethostbyaddr_r)(const void *addr,
     445             :                                       socklen_t len,
     446             :                                       int type,
     447             :                                       struct hostent *ret,
     448             :                                       char *buf,
     449             :                                       size_t buflen,
     450             :                                       struct hostent **result,
     451             :                                       int *h_errnop);
     452             : #endif
     453             : 
     454             : #define NWRAP_SYMBOL_ENTRY(i) \
     455             :         union { \
     456             :                 __libc_##i f; \
     457             :                 void *obj; \
     458             :         } _libc_##i
     459             : 
     460             : struct nwrap_libc_symbols {
     461             :         NWRAP_SYMBOL_ENTRY(getpwnam);
     462             :         NWRAP_SYMBOL_ENTRY(getpwnam_r);
     463             :         NWRAP_SYMBOL_ENTRY(getpwuid);
     464             :         NWRAP_SYMBOL_ENTRY(getpwuid_r);
     465             :         NWRAP_SYMBOL_ENTRY(setpwent);
     466             :         NWRAP_SYMBOL_ENTRY(getpwent);
     467             : #ifdef HAVE_GETPWENT_R
     468             :         NWRAP_SYMBOL_ENTRY(getpwent_r);
     469             : #endif
     470             :         NWRAP_SYMBOL_ENTRY(endpwent);
     471             : 
     472             :         NWRAP_SYMBOL_ENTRY(initgroups);
     473             :         NWRAP_SYMBOL_ENTRY(getgrnam);
     474             :         NWRAP_SYMBOL_ENTRY(getgrnam_r);
     475             :         NWRAP_SYMBOL_ENTRY(getgrgid);
     476             :         NWRAP_SYMBOL_ENTRY(getgrgid_r);
     477             :         NWRAP_SYMBOL_ENTRY(setgrent);
     478             :         NWRAP_SYMBOL_ENTRY(getgrent);
     479             : #ifdef HAVE_GETGRENT_R
     480             :         NWRAP_SYMBOL_ENTRY(getgrent_r);
     481             : #endif
     482             :         NWRAP_SYMBOL_ENTRY(endgrent);
     483             :         NWRAP_SYMBOL_ENTRY(getgrouplist);
     484             : 
     485             :         NWRAP_SYMBOL_ENTRY(sethostent);
     486             :         NWRAP_SYMBOL_ENTRY(gethostent);
     487             :         NWRAP_SYMBOL_ENTRY(endhostent);
     488             :         NWRAP_SYMBOL_ENTRY(gethostbyname);
     489             : #ifdef HAVE_GETHOSTBYNAME_R
     490             :         NWRAP_SYMBOL_ENTRY(gethostbyname_r);
     491             : #endif
     492             : #ifdef HAVE_GETHOSTBYNAME2
     493             :         NWRAP_SYMBOL_ENTRY(gethostbyname2);
     494             : #endif
     495             : #ifdef HAVE_GETHOSTBYNAME2_R
     496             :         NWRAP_SYMBOL_ENTRY(gethostbyname2_r);
     497             : #endif
     498             :         NWRAP_SYMBOL_ENTRY(gethostbyaddr);
     499             : #ifdef HAVE_GETHOSTBYADDR_R
     500             :         NWRAP_SYMBOL_ENTRY(gethostbyaddr_r);
     501             : #endif
     502             :         NWRAP_SYMBOL_ENTRY(getaddrinfo);
     503             :         NWRAP_SYMBOL_ENTRY(getnameinfo);
     504             :         NWRAP_SYMBOL_ENTRY(gethostname);
     505             : };
     506             : #undef NWRAP_SYMBOL_ENTRY
     507             : 
     508             : typedef NSS_STATUS (*__nss_getpwnam_r)(const char *name,
     509             :                                        struct passwd *result,
     510             :                                        char *buffer,
     511             :                                        size_t buflen,
     512             :                                        int *errnop);
     513             : typedef NSS_STATUS (*__nss_getpwuid_r)(uid_t uid,
     514             :                                        struct passwd *result,
     515             :                                        char *buffer,
     516             :                                        size_t buflen,
     517             :                                        int *errnop);
     518             : typedef NSS_STATUS (*__nss_setpwent)(void);
     519             : typedef NSS_STATUS (*__nss_getpwent_r)(struct passwd *result,
     520             :                                        char *buffer,
     521             :                                        size_t buflen,
     522             :                                        int *errnop);
     523             : typedef NSS_STATUS (*__nss_endpwent)(void);
     524             : typedef NSS_STATUS (*__nss_initgroups_dyn)(const char *user,
     525             :                                        gid_t group,
     526             :                                        long int *start,
     527             :                                        long int *size,
     528             :                                        gid_t **groups,
     529             :                                        long int limit,
     530             :                                        int *errnop);
     531             : typedef NSS_STATUS (*__nss_getgrnam_r)(const char *name,
     532             :                                        struct group *result,
     533             :                                        char *buffer,
     534             :                                        size_t buflen,
     535             :                                        int *errnop);
     536             : typedef NSS_STATUS (*__nss_getgrgid_r)(gid_t gid,
     537             :                                        struct group *result,
     538             :                                        char *buffer,
     539             :                                        size_t buflen,
     540             :                                        int *errnop);
     541             : typedef NSS_STATUS (*__nss_setgrent)(void);
     542             : typedef NSS_STATUS (*__nss_getgrent_r)(struct group *result,
     543             :                                        char *buffer,
     544             :                                        size_t buflen,
     545             :                                        int *errnop);
     546             : typedef NSS_STATUS (*__nss_endgrent)(void);
     547             : typedef NSS_STATUS (*__nss_gethostbyaddr_r)(const void *addr,
     548             :                                             socklen_t addrlen,
     549             :                                             int af,
     550             :                                             struct hostent *result,
     551             :                                             char *buffer,
     552             :                                             size_t buflen,
     553             :                                             int *errnop,
     554             :                                             int *h_errnop);
     555             : typedef NSS_STATUS (*__nss_gethostbyname2_r)(const char *name,
     556             :                                              int af,
     557             :                                              struct hostent *result,
     558             :                                              char *buffer,
     559             :                                              size_t buflen,
     560             :                                              int *errnop,
     561             :                                              int *h_errnop);
     562             : 
     563             : #define NWRAP_NSS_MODULE_SYMBOL_ENTRY(i) \
     564             :         union { \
     565             :                 __nss_##i f; \
     566             :                 void *obj; \
     567             :         } _nss_##i
     568             : 
     569             : struct nwrap_nss_module_symbols {
     570             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwnam_r);
     571             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwuid_r);
     572             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(setpwent);
     573             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwent_r);
     574             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(endpwent);
     575             : 
     576             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(initgroups_dyn);
     577             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrnam_r);
     578             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrgid_r);
     579             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(setgrent);
     580             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrent_r);
     581             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(endgrent);
     582             : 
     583             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyaddr_r);
     584             :         NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyname2_r);
     585             : };
     586             : 
     587             : struct nwrap_backend {
     588             :         const char *name;
     589             :         const char *so_path;
     590             :         void *so_handle;
     591             :         struct nwrap_ops *ops;
     592             :         struct nwrap_nss_module_symbols *symbols;
     593             : };
     594             : 
     595             : struct nwrap_vector;
     596             : 
     597             : struct nwrap_ops {
     598             :         struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
     599             :                                        const char *name);
     600             :         int             (*nw_getpwnam_r)(struct nwrap_backend *b,
     601             :                                          const char *name, struct passwd *pwdst,
     602             :                                          char *buf, size_t buflen, struct passwd **pwdstp);
     603             :         struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
     604             :                                        uid_t uid);
     605             :         int             (*nw_getpwuid_r)(struct nwrap_backend *b,
     606             :                                          uid_t uid, struct passwd *pwdst,
     607             :                                          char *buf, size_t buflen, struct passwd **pwdstp);
     608             :         void            (*nw_setpwent)(struct nwrap_backend *b);
     609             :         struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
     610             :         int             (*nw_getpwent_r)(struct nwrap_backend *b,
     611             :                                          struct passwd *pwdst, char *buf,
     612             :                                          size_t buflen, struct passwd **pwdstp);
     613             :         void            (*nw_endpwent)(struct nwrap_backend *b);
     614             :         int             (*nw_initgroups_dyn)(struct nwrap_backend *b,
     615             :                                              const char *user,
     616             :                                              gid_t group,
     617             :                                              long int *start,
     618             :                                              long int *size,
     619             :                                              gid_t **groups,
     620             :                                              long int limit,
     621             :                                              int *errnop);
     622             :         struct group *  (*nw_getgrnam)(struct nwrap_backend *b,
     623             :                                        const char *name);
     624             :         int             (*nw_getgrnam_r)(struct nwrap_backend *b,
     625             :                                          const char *name, struct group *grdst,
     626             :                                          char *buf, size_t buflen, struct group **grdstp);
     627             :         struct group *  (*nw_getgrgid)(struct nwrap_backend *b,
     628             :                                        gid_t gid);
     629             :         int             (*nw_getgrgid_r)(struct nwrap_backend *b,
     630             :                                          gid_t gid, struct group *grdst,
     631             :                                          char *buf, size_t buflen, struct group **grdstp);
     632             :         void            (*nw_setgrent)(struct nwrap_backend *b);
     633             :         struct group *  (*nw_getgrent)(struct nwrap_backend *b);
     634             :         int             (*nw_getgrent_r)(struct nwrap_backend *b,
     635             :                                          struct group *grdst, char *buf,
     636             :                                          size_t buflen, struct group **grdstp);
     637             :         void            (*nw_endgrent)(struct nwrap_backend *b);
     638             :         struct hostent *(*nw_gethostbyaddr)(struct nwrap_backend *b,
     639             :                                             const void *addr,
     640             :                                             socklen_t len, int type);
     641             :         struct hostent *(*nw_gethostbyname)(struct nwrap_backend *b,
     642             :                                             const char *name);
     643             :         struct hostent *(*nw_gethostbyname2)(struct nwrap_backend *b,
     644             :                                              const char *name, int af);
     645             :         int             (*nw_gethostbyname2_r)(struct nwrap_backend *b,
     646             :                                                const char *name, int af,
     647             :                                                struct hostent *hedst,
     648             :                                                char *buf, size_t buflen,
     649             :                                                struct hostent **hedstp);
     650             : };
     651             : 
     652             : /* Public prototypes */
     653             : 
     654             : bool nss_wrapper_enabled(void);
     655             : bool nss_wrapper_shadow_enabled(void);
     656             : bool nss_wrapper_hosts_enabled(void);
     657             : 
     658             : /* prototypes for files backend */
     659             : 
     660             : 
     661             : static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
     662             :                                            const char *name);
     663             : static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
     664             :                                   const char *name, struct passwd *pwdst,
     665             :                                   char *buf, size_t buflen, struct passwd **pwdstp);
     666             : static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
     667             :                                            uid_t uid);
     668             : static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
     669             :                                   uid_t uid, struct passwd *pwdst,
     670             :                                   char *buf, size_t buflen, struct passwd **pwdstp);
     671             : static void nwrap_files_setpwent(struct nwrap_backend *b);
     672             : static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
     673             : static int nwrap_files_getpwent_r(struct nwrap_backend *b,
     674             :                                   struct passwd *pwdst, char *buf,
     675             :                                   size_t buflen, struct passwd **pwdstp);
     676             : static void nwrap_files_endpwent(struct nwrap_backend *b);
     677             : static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
     678             :                                       const char *user,
     679             :                                       gid_t group,
     680             :                                       long int *start,
     681             :                                       long int *size,
     682             :                                       gid_t **groups,
     683             :                                       long int limit,
     684             :                                       int *errnop);
     685             : static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
     686             :                                           const char *name);
     687             : static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
     688             :                                   const char *name, struct group *grdst,
     689             :                                   char *buf, size_t buflen, struct group **grdstp);
     690             : static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
     691             :                                           gid_t gid);
     692             : static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
     693             :                                   gid_t gid, struct group *grdst,
     694             :                                   char *buf, size_t buflen, struct group **grdstp);
     695             : static void nwrap_files_setgrent(struct nwrap_backend *b);
     696             : static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
     697             : static int nwrap_files_getgrent_r(struct nwrap_backend *b,
     698             :                                   struct group *grdst, char *buf,
     699             :                                   size_t buflen, struct group **grdstp);
     700             : static void nwrap_files_endgrent(struct nwrap_backend *b);
     701             : static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
     702             :                                                  const void *addr,
     703             :                                                  socklen_t len, int type);
     704             : static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
     705             :                                                  const char *name);
     706             : #ifdef HAVE_GETHOSTBYNAME2
     707             : static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
     708             :                                                   const char *name, int af);
     709             : #endif /* HAVE_GETHOSTBYNAME2 */
     710             : static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
     711             :                                         const char *name, int af,
     712             :                                         struct hostent *hedst,
     713             :                                         char *buf, size_t buflen,
     714             :                                         struct hostent **hedstp);
     715             : 
     716             : /* prototypes for module backend */
     717             : 
     718             : static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
     719             : static int nwrap_module_getpwent_r(struct nwrap_backend *b,
     720             :                                    struct passwd *pwdst, char *buf,
     721             :                                    size_t buflen, struct passwd **pwdstp);
     722             : static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
     723             :                                             const char *name);
     724             : static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
     725             :                                    const char *name, struct passwd *pwdst,
     726             :                                    char *buf, size_t buflen, struct passwd **pwdstp);
     727             : static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
     728             :                                             uid_t uid);
     729             : static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
     730             :                                    uid_t uid, struct passwd *pwdst,
     731             :                                    char *buf, size_t buflen, struct passwd **pwdstp);
     732             : static void nwrap_module_setpwent(struct nwrap_backend *b);
     733             : static void nwrap_module_endpwent(struct nwrap_backend *b);
     734             : static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
     735             : static int nwrap_module_getgrent_r(struct nwrap_backend *b,
     736             :                                    struct group *grdst, char *buf,
     737             :                                    size_t buflen, struct group **grdstp);
     738             : static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
     739             :                                            const char *name);
     740             : static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
     741             :                                    const char *name, struct group *grdst,
     742             :                                    char *buf, size_t buflen, struct group **grdstp);
     743             : static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
     744             :                                            gid_t gid);
     745             : static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
     746             :                                    gid_t gid, struct group *grdst,
     747             :                                    char *buf, size_t buflen, struct group **grdstp);
     748             : static void nwrap_module_setgrent(struct nwrap_backend *b);
     749             : static void nwrap_module_endgrent(struct nwrap_backend *b);
     750             : static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
     751             :                                        const char *user,
     752             :                                        gid_t group,
     753             :                                        long int *start,
     754             :                                        long int *size,
     755             :                                        gid_t **groups,
     756             :                                        long int limit,
     757             :                                        int *errnop);
     758             : static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
     759             :                                                   const void *addr,
     760             :                                                   socklen_t len, int type);
     761             : static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
     762             :                                                   const char *name);
     763             : static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
     764             :                                                    const char *name, int af);
     765             : static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
     766             :                                          const char *name, int af,
     767             :                                          struct hostent *hedst,
     768             :                                          char *buf, size_t buflen,
     769             :                                          struct hostent **hedstp);
     770             : 
     771             : struct nwrap_ops nwrap_files_ops = {
     772             :         .nw_getpwnam    = nwrap_files_getpwnam,
     773             :         .nw_getpwnam_r  = nwrap_files_getpwnam_r,
     774             :         .nw_getpwuid    = nwrap_files_getpwuid,
     775             :         .nw_getpwuid_r  = nwrap_files_getpwuid_r,
     776             :         .nw_setpwent    = nwrap_files_setpwent,
     777             :         .nw_getpwent    = nwrap_files_getpwent,
     778             :         .nw_getpwent_r  = nwrap_files_getpwent_r,
     779             :         .nw_endpwent    = nwrap_files_endpwent,
     780             :         .nw_initgroups_dyn      = nwrap_files_initgroups_dyn,
     781             :         .nw_getgrnam    = nwrap_files_getgrnam,
     782             :         .nw_getgrnam_r  = nwrap_files_getgrnam_r,
     783             :         .nw_getgrgid    = nwrap_files_getgrgid,
     784             :         .nw_getgrgid_r  = nwrap_files_getgrgid_r,
     785             :         .nw_setgrent    = nwrap_files_setgrent,
     786             :         .nw_getgrent    = nwrap_files_getgrent,
     787             :         .nw_getgrent_r  = nwrap_files_getgrent_r,
     788             :         .nw_endgrent    = nwrap_files_endgrent,
     789             :         .nw_gethostbyaddr       = nwrap_files_gethostbyaddr,
     790             :         .nw_gethostbyname       = nwrap_files_gethostbyname,
     791             : #ifdef HAVE_GETHOSTBYNAME2
     792             :         .nw_gethostbyname2      = nwrap_files_gethostbyname2,
     793             : #endif /* HAVE_GETHOSTBYNAME2 */
     794             :         .nw_gethostbyname2_r    = nwrap_files_gethostbyname2_r,
     795             : };
     796             : 
     797             : struct nwrap_ops nwrap_module_ops = {
     798             :         .nw_getpwnam    = nwrap_module_getpwnam,
     799             :         .nw_getpwnam_r  = nwrap_module_getpwnam_r,
     800             :         .nw_getpwuid    = nwrap_module_getpwuid,
     801             :         .nw_getpwuid_r  = nwrap_module_getpwuid_r,
     802             :         .nw_setpwent    = nwrap_module_setpwent,
     803             :         .nw_getpwent    = nwrap_module_getpwent,
     804             :         .nw_getpwent_r  = nwrap_module_getpwent_r,
     805             :         .nw_endpwent    = nwrap_module_endpwent,
     806             :         .nw_initgroups_dyn      = nwrap_module_initgroups_dyn,
     807             :         .nw_getgrnam    = nwrap_module_getgrnam,
     808             :         .nw_getgrnam_r  = nwrap_module_getgrnam_r,
     809             :         .nw_getgrgid    = nwrap_module_getgrgid,
     810             :         .nw_getgrgid_r  = nwrap_module_getgrgid_r,
     811             :         .nw_setgrent    = nwrap_module_setgrent,
     812             :         .nw_getgrent    = nwrap_module_getgrent,
     813             :         .nw_getgrent_r  = nwrap_module_getgrent_r,
     814             :         .nw_endgrent    = nwrap_module_endgrent,
     815             :         .nw_gethostbyaddr       = nwrap_module_gethostbyaddr,
     816             :         .nw_gethostbyname       = nwrap_module_gethostbyname,
     817             :         .nw_gethostbyname2      = nwrap_module_gethostbyname2,
     818             :         .nw_gethostbyname2_r    = nwrap_module_gethostbyname2_r,
     819             : };
     820             : 
     821             : struct nwrap_libc {
     822             :         void *handle;
     823             :         void *nsl_handle;
     824             :         void *sock_handle;
     825             :         struct nwrap_libc_symbols symbols;
     826             : };
     827             : 
     828             : struct nwrap_main {
     829             :         size_t num_backends;
     830             :         struct nwrap_backend *backends;
     831             :         struct nwrap_libc *libc;
     832             : };
     833             : 
     834             : static struct nwrap_main *nwrap_main_global;
     835             : static struct nwrap_main __nwrap_main_global;
     836             : 
     837             : /*
     838             :  * PROTOTYPES
     839             :  */
     840             : static int nwrap_convert_he_ai(const struct hostent *he,
     841             :                                unsigned short port,
     842             :                                const struct addrinfo *hints,
     843             :                                struct addrinfo **pai,
     844             :                                bool skip_canonname);
     845             : 
     846             : #ifdef HAVE_GETGROUPLIST
     847             : static int nwrap_getgrouplist(const char *user,
     848             :                               gid_t group,
     849             :                               long int *size,
     850             :                               gid_t **groupsp,
     851             :                               long int limit);
     852             : #endif
     853             : 
     854             : /*
     855             :  * VECTORS
     856             :  */
     857             : 
     858             : #define DEFAULT_VECTOR_CAPACITY 16
     859             : 
     860             : struct nwrap_vector {
     861             :         void **items;
     862             :         size_t count;
     863             :         size_t capacity;
     864             : };
     865             : 
     866             : /* Macro returns pointer to first element of vector->items array.
     867             :  *
     868             :  * nwrap_vector is used as a memory backend which take care of
     869             :  * memory allocations and other stuff like memory growing.
     870             :  * nwrap_vectors should not be considered as some abstract structures.
     871             :  * On this level, vectors are more handy than direct realloc/malloc
     872             :  * calls.
     873             :  *
     874             :  * nwrap_vector->items is array inside nwrap_vector which can be
     875             :  * directly pointed by libc structure assembled by cwrap itself.
     876             :  *
     877             :  * EXAMPLE:
     878             :  *
     879             :  * 1) struct hostent contains char **h_addr_list element.
     880             :  * 2) nwrap_vector holds array of pointers to addresses.
     881             :  *    It's easier to use vector to store results of
     882             :  *    file parsing etc.
     883             :  *
     884             :  * Now, pretend that cwrap assembled struct hostent and
     885             :  * we need to set h_addr_list to point to nwrap_vector.
     886             :  * Idea behind is to shield users from internal nwrap_vector
     887             :  * implementation.
     888             :  * (Yes, not fully - array terminated by NULL is needed because
     889             :  * it's result expected by libc function caller.)
     890             :  *
     891             :  *
     892             :  * CODE EXAMPLE:
     893             :  *
     894             :  * struct hostent he;
     895             :  * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
     896             :  * ... don't care about failed allocation now ...
     897             :  *
     898             :  * ... fill nwrap vector ...
     899             :  *
     900             :  * struct hostent he;
     901             :  * he.h_addr_list = nwrap_vector_head(vector);
     902             :  *
     903             :  */
     904             : #define nwrap_vector_head(vect) ((void *)((vect)->items))
     905             : 
     906             : #define nwrap_vector_foreach(item, vect, iter) \
     907             :         for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
     908             :              item != NULL; \
     909             :              (item) = (vect).items[++iter])
     910             : 
     911             : #define nwrap_vector_is_initialized(vector) ((vector)->items != NULL)
     912             : 
     913      458684 : static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
     914             : {
     915      458684 :         if (vector == NULL) {
     916           0 :                 return false;
     917             :         }
     918             : 
     919             :         /* count is initialized by ZERO_STRUCTP */
     920      458684 :         ZERO_STRUCTP(vector);
     921      458684 :         vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
     922      458684 :         if (vector->items == NULL) {
     923           0 :                 return false;
     924             :         }
     925      458684 :         vector->capacity = DEFAULT_VECTOR_CAPACITY;
     926      458684 :         memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
     927             : 
     928      458684 :         return true;
     929             : }
     930             : 
     931     2833091 : static bool nwrap_vector_add_item(struct nwrap_vector *vector, void *const item)
     932             : {
     933     2833091 :         assert (vector != NULL);
     934             : 
     935     2833091 :         if (vector->items == NULL) {
     936      458684 :                 nwrap_vector_init(vector);
     937             :         }
     938             : 
     939     2833091 :         if (vector->count == vector->capacity) {
     940             :                 /* Items array _MUST_ be NULL terminated because it's passed
     941             :                  * as result to caller which expect NULL terminated array from libc.
     942             :                  */
     943       69844 :                 void **items = realloc(vector->items, sizeof(void *) * ((vector->capacity * 2) + 1));
     944       69844 :                 if (items == NULL) {
     945           0 :                         return false;
     946             :                 }
     947       69844 :                 vector->items = items;
     948             : 
     949             :                 /* Don't count ending NULL to capacity */
     950       69844 :                 vector->capacity *= 2;
     951             :         }
     952             : 
     953     2833091 :         vector->items[vector->count] = item;
     954             : 
     955     2833091 :         vector->count += 1;
     956     2833091 :         vector->items[vector->count] = NULL;
     957             : 
     958     2833091 :         return true;
     959             : }
     960             : 
     961           0 : static bool nwrap_vector_merge(struct nwrap_vector *dst,
     962             :                                struct nwrap_vector *src)
     963             : {
     964           0 :         void **dst_items = NULL;
     965           0 :         size_t count;
     966             : 
     967           0 :         if (src->count == 0) {
     968           0 :                 return true;
     969             :         }
     970             : 
     971           0 :         count = dst->count + src->count;
     972             : 
     973             :         /* We don't need reallocation if we have enough capacity. */
     974           0 :         if (src->count > (dst->capacity - dst->count)) {
     975           0 :                 dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
     976           0 :                 if (dst_items == NULL) {
     977           0 :                         return false;
     978             :                 }
     979           0 :                 dst->items = dst_items;
     980           0 :                 dst->capacity = count;
     981             :         }
     982             : 
     983           0 :         memcpy((void *)(((long *)dst->items) + dst->count),
     984           0 :                src->items,
     985           0 :                src->count * sizeof(void *));
     986           0 :         dst->count = count;
     987             : 
     988           0 :         return true;
     989             : }
     990             : 
     991             : struct nwrap_cache {
     992             :         const char *path;
     993             :         int fd;
     994             :         FILE *fp;
     995             :         struct stat st;
     996             :         void *private_data;
     997             : 
     998             :         struct nwrap_vector lines;
     999             : 
    1000             :         bool (*parse_line)(struct nwrap_cache *, char *line);
    1001             :         void (*unload)(struct nwrap_cache *);
    1002             : };
    1003             : 
    1004             : /* passwd */
    1005             : struct nwrap_pw {
    1006             :         struct nwrap_cache *cache;
    1007             : 
    1008             :         struct passwd *list;
    1009             :         int num;
    1010             :         int idx;
    1011             : };
    1012             : 
    1013             : struct nwrap_cache __nwrap_cache_pw;
    1014             : struct nwrap_pw nwrap_pw_global;
    1015             : 
    1016             : static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
    1017             : static void nwrap_pw_unload(struct nwrap_cache *nwrap);
    1018             : 
    1019             : /* shadow */
    1020             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    1021             : struct nwrap_sp {
    1022             :         struct nwrap_cache *cache;
    1023             : 
    1024             :         struct spwd *list;
    1025             :         int num;
    1026             :         int idx;
    1027             : };
    1028             : 
    1029             : struct nwrap_cache __nwrap_cache_sp;
    1030             : struct nwrap_sp nwrap_sp_global;
    1031             : 
    1032             : static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line);
    1033             : static void nwrap_sp_unload(struct nwrap_cache *nwrap);
    1034             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    1035             : 
    1036             : /* group */
    1037             : struct nwrap_gr {
    1038             :         struct nwrap_cache *cache;
    1039             : 
    1040             :         struct group *list;
    1041             :         int num;
    1042             :         int idx;
    1043             : };
    1044             : 
    1045             : struct nwrap_cache __nwrap_cache_gr;
    1046             : struct nwrap_gr nwrap_gr_global;
    1047             : 
    1048             : /* hosts */
    1049             : static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line);
    1050             : static void nwrap_he_unload(struct nwrap_cache *nwrap);
    1051             : 
    1052             : struct nwrap_addrdata {
    1053             :         unsigned char host_addr[16]; /* IPv4 or IPv6 address */
    1054             : };
    1055             : 
    1056             : static size_t max_hostents = 100;
    1057             : 
    1058             : struct nwrap_entdata {
    1059             :         struct nwrap_addrdata addr;
    1060             :         struct hostent ht;
    1061             : 
    1062             :         struct nwrap_vector nwrap_addrdata;
    1063             : 
    1064             :         ssize_t aliases_count;
    1065             : };
    1066             : 
    1067             : struct nwrap_entlist {
    1068             :         struct nwrap_entlist *next;
    1069             :         struct nwrap_entdata *ed;
    1070             : };
    1071             : 
    1072             : struct nwrap_he {
    1073             :         struct nwrap_cache *cache;
    1074             : 
    1075             :         struct nwrap_vector entries;
    1076             :         struct nwrap_vector lists;
    1077             : 
    1078             :         int num;
    1079             :         int idx;
    1080             : };
    1081             : 
    1082             : static struct nwrap_cache __nwrap_cache_he;
    1083             : static struct nwrap_he nwrap_he_global;
    1084             : 
    1085             : 
    1086             : /*********************************************************
    1087             :  * NWRAP PROTOTYPES
    1088             :  *********************************************************/
    1089             : 
    1090             : static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
    1091             : static void nwrap_gr_unload(struct nwrap_cache *nwrap);
    1092             : #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
    1093             : /* xlC and other oldschool compilers support (only) this */
    1094             : #pragma init (nwrap_constructor)
    1095             : #endif
    1096             : void nwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
    1097             : #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
    1098             : #pragma fini (nwrap_destructor)
    1099             : #endif
    1100             : void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
    1101             : 
    1102             : /*********************************************************
    1103             :  * NWRAP LIBC LOADER FUNCTIONS
    1104             :  *********************************************************/
    1105             : 
    1106             : enum nwrap_lib {
    1107             :     NWRAP_LIBC,
    1108             :     NWRAP_LIBNSL,
    1109             :     NWRAP_LIBSOCKET,
    1110             : };
    1111             : 
    1112      974820 : static const char *nwrap_str_lib(enum nwrap_lib lib)
    1113             : {
    1114      974820 :         switch (lib) {
    1115      566964 :         case NWRAP_LIBC:
    1116      566964 :                 return "libc";
    1117      324940 :         case NWRAP_LIBNSL:
    1118      324940 :                 return "libnsl";
    1119       64988 :         case NWRAP_LIBSOCKET:
    1120       64988 :                 return "libsocket";
    1121             :         }
    1122             : 
    1123             :         /* Compiler would warn us about unhandled enum value if we get here */
    1124           0 :         return "unknown";
    1125             : }
    1126             : 
    1127      974820 : static void *nwrap_load_lib_handle(enum nwrap_lib lib)
    1128             : {
    1129      974820 :         int flags = RTLD_LAZY;
    1130      974820 :         void *handle = NULL;
    1131       29880 :         int i;
    1132             : 
    1133             : #ifdef RTLD_DEEPBIND
    1134      974820 :         const char *env_preload = getenv("LD_PRELOAD");
    1135      974820 :         const char *env_deepbind = getenv("NSS_WRAPPER_DISABLE_DEEPBIND");
    1136      974820 :         bool enable_deepbind = true;
    1137             : 
    1138             :         /* Don't do a deepbind if we run with libasan */
    1139      974820 :         if (env_preload != NULL && strlen(env_preload) < 1024) {
    1140      974820 :                 const char *p = strstr(env_preload, "libasan.so");
    1141      974820 :                 if (p != NULL) {
    1142           0 :                         enable_deepbind = false;
    1143             :                 }
    1144             :         }
    1145             : 
    1146      974820 :         if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
    1147           0 :                 enable_deepbind = false;
    1148             :         }
    1149             : 
    1150      974820 :         if (enable_deepbind) {
    1151      974820 :                 flags |= RTLD_DEEPBIND;
    1152             :         }
    1153             : #endif
    1154             : 
    1155      974820 :         switch (lib) {
    1156      390340 :         case NWRAP_LIBNSL:
    1157             : #ifdef HAVE_LIBNSL
    1158      292240 :                 handle = nwrap_main_global->libc->nsl_handle;
    1159      292240 :                 if (handle == NULL) {
    1160      263016 :                         for (i = 10; i >= 0; i--) {
    1161      263016 :                                 char soname[256] = {0};
    1162             : 
    1163      263016 :                                 snprintf(soname, sizeof(soname), "libnsl.so.%d", i);
    1164      263016 :                                 handle = dlopen(soname, flags);
    1165      263016 :                                 if (handle != NULL) {
    1166       28228 :                                         break;
    1167             :                                 }
    1168             :                         }
    1169             : 
    1170       29224 :                         nwrap_main_global->libc->nsl_handle = handle;
    1171             :                 }
    1172      282280 :                 break;
    1173             : #endif
    1174             :                 /* FALL TROUGH */
    1175      584480 :         case NWRAP_LIBSOCKET:
    1176             : #ifdef HAVE_LIBSOCKET
    1177             :                 handle = nwrap_main_global->libc->sock_handle;
    1178             :                 if (handle == NULL) {
    1179             :                         for (i = 10; i >= 0; i--) {
    1180             :                                 char soname[256] = {0};
    1181             : 
    1182             :                                 snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
    1183             :                                 handle = dlopen(soname, flags);
    1184             :                                 if (handle != NULL) {
    1185             :                                         break;
    1186             :                                 }
    1187             :                         }
    1188             : 
    1189             :                         nwrap_main_global->libc->sock_handle = handle;
    1190             :                 }
    1191             :                 break;
    1192             : #endif
    1193             :                 /* FALL TROUGH */
    1194             :         case NWRAP_LIBC:
    1195      682580 :                 handle = nwrap_main_global->libc->handle;
    1196      682580 :                 if (handle == NULL) {
    1197      162470 :                         for (i = 10; i >= 0; i--) {
    1198      162470 :                                 char soname[256] = {0};
    1199             : 
    1200      162470 :                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
    1201      162470 :                                 handle = dlopen(soname, flags);
    1202      162470 :                                 if (handle != NULL) {
    1203       31498 :                                         break;
    1204             :                                 }
    1205             :                         }
    1206             : 
    1207       32494 :                         nwrap_main_global->libc->handle = handle;
    1208             :                 }
    1209      662660 :                 break;
    1210             :         }
    1211             : 
    1212      974820 :         if (handle == NULL) {
    1213             : #ifdef RTLD_NEXT
    1214           0 :                 handle = nwrap_main_global->libc->handle
    1215           0 :                        = nwrap_main_global->libc->sock_handle
    1216           0 :                        = nwrap_main_global->libc->nsl_handle
    1217           0 :                        = RTLD_NEXT;
    1218             : #else
    1219             :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    1220             :                           "Failed to dlopen library: %s\n",
    1221             :                           dlerror());
    1222             :                 exit(-1);
    1223             : #endif
    1224             :         }
    1225             : 
    1226      974820 :         return handle;
    1227             : }
    1228             : 
    1229      974820 : static void *_nwrap_bind_symbol(enum nwrap_lib lib, const char *fn_name)
    1230             : {
    1231       29880 :         void *handle;
    1232       29880 :         void *func;
    1233             : 
    1234      974820 :         nwrap_init();
    1235             : 
    1236      974820 :         handle = nwrap_load_lib_handle(lib);
    1237             : 
    1238      974820 :         func = dlsym(handle, fn_name);
    1239      974820 :         if (func == NULL) {
    1240           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    1241             :                                 "Failed to find %s: %s\n",
    1242             :                                 fn_name, dlerror());
    1243           0 :                 exit(-1);
    1244             :         }
    1245             : 
    1246      986772 :         NWRAP_LOG(NWRAP_LOG_TRACE,
    1247             :                         "Loaded %s from %s",
    1248             :                         fn_name, nwrap_str_lib(lib));
    1249      974820 :         return func;
    1250             : }
    1251             : 
    1252             : #define nwrap_mutex_lock(m) _nwrap_mutex_lock(m, #m, __func__, __LINE__)
    1253    17860353 : static void _nwrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
    1254             : {
    1255      273609 :         int ret;
    1256             : 
    1257    17860353 :         ret = pthread_mutex_lock(mutex);
    1258    17860353 :         if (ret != 0) {
    1259           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s",
    1260             :                           getpid(), getppid(), caller, line, name, strerror(ret));
    1261           0 :                 abort();
    1262             :         }
    1263    17860353 : }
    1264             : 
    1265             : #define nwrap_mutex_unlock(m) _nwrap_mutex_unlock(m, #m, __func__, __LINE__)
    1266    17803803 : static void _nwrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
    1267             : {
    1268      273153 :         int ret;
    1269             : 
    1270    17803803 :         ret = pthread_mutex_unlock(mutex);
    1271    17803803 :         if (ret != 0) {
    1272           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s",
    1273             :                           getpid(), getppid(), caller, line, name, strerror(ret));
    1274           0 :                 abort();
    1275             :         }
    1276    17803803 : }
    1277             : 
    1278             : #define nwrap_bind_symbol_libc(sym_name) \
    1279             :         if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
    1280             :                 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
    1281             :                         _nwrap_bind_symbol(NWRAP_LIBC, #sym_name); \
    1282             :         } \
    1283             : 
    1284             : #define nwrap_bind_symbol_libc_posix(sym_name) \
    1285             :         if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
    1286             :                 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
    1287             :                         _nwrap_bind_symbol(NWRAP_LIBC, "__posix_" #sym_name); \
    1288             :         } \
    1289             : 
    1290             : #define nwrap_bind_symbol_libnsl(sym_name) \
    1291             :         if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
    1292             :                 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
    1293             :                         _nwrap_bind_symbol(NWRAP_LIBNSL, #sym_name); \
    1294             :         } \
    1295             : 
    1296             : #define nwrap_bind_symbol_libsocket(sym_name) \
    1297             :         if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
    1298             :                 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
    1299             :                         _nwrap_bind_symbol(NWRAP_LIBSOCKET, #sym_name); \
    1300             :         } \
    1301             : 
    1302             : static void nwrap_bind_symbol_all(void);
    1303             : 
    1304             : /* INTERNAL HELPER FUNCTIONS */
    1305      518902 : static void nwrap_lines_unload(struct nwrap_cache *const nwrap)
    1306             : {
    1307        8174 :         size_t p;
    1308        8174 :         void *item;
    1309     3507518 :         nwrap_vector_foreach(item, nwrap->lines, p) {
    1310             :                 /* Maybe some vectors were merged ... */
    1311     2980442 :                 SAFE_FREE(item);
    1312             :         }
    1313      518902 :         SAFE_FREE(nwrap->lines.items);
    1314      518902 :         ZERO_STRUCTP(&nwrap->lines);
    1315      518902 : }
    1316             : 
    1317             : /*
    1318             :  * IMPORTANT
    1319             :  *
    1320             :  * Functions expeciall from libc need to be loaded individually, you can't load
    1321             :  * all at once or gdb will segfault at startup. The same applies to valgrind and
    1322             :  * has probably something todo with with the linker.
    1323             :  * So we need load each function at the point it is called the first time.
    1324             :  */
    1325         972 : static struct passwd *libc_getpwnam(const char *name)
    1326             : {
    1327         972 :         nwrap_bind_symbol_all();
    1328             : 
    1329         972 :         return nwrap_main_global->libc->symbols._libc_getpwnam.f(name);
    1330             : }
    1331             : 
    1332             : #ifdef HAVE_GETPWNAM_R
    1333         150 : static int libc_getpwnam_r(const char *name,
    1334             :                            struct passwd *pwd,
    1335             :                            char *buf,
    1336             :                            size_t buflen,
    1337             :                            struct passwd **result)
    1338             : {
    1339         150 :         nwrap_bind_symbol_all();
    1340             : 
    1341         150 :         return nwrap_main_global->libc->symbols._libc_getpwnam_r.f(name,
    1342             :                                                                    pwd,
    1343             :                                                                    buf,
    1344             :                                                                    buflen,
    1345             :                                                                    result);
    1346             : }
    1347             : #endif
    1348             : 
    1349        3584 : static struct passwd *libc_getpwuid(uid_t uid)
    1350             : {
    1351        3584 :         nwrap_bind_symbol_all();
    1352             : 
    1353        3584 :         return nwrap_main_global->libc->symbols._libc_getpwuid.f(uid);
    1354             : }
    1355             : 
    1356             : #ifdef HAVE_GETPWUID_R
    1357         321 : static int libc_getpwuid_r(uid_t uid,
    1358             :                            struct passwd *pwd,
    1359             :                            char *buf,
    1360             :                            size_t buflen,
    1361             :                            struct passwd **result)
    1362             : {
    1363         321 :         nwrap_bind_symbol_all();
    1364             : 
    1365         321 :         return nwrap_main_global->libc->symbols._libc_getpwuid_r.f(uid,
    1366             :                                                                    pwd,
    1367             :                                                                    buf,
    1368             :                                                                    buflen,
    1369             :                                                                    result);
    1370             : }
    1371             : #endif
    1372             : 
    1373     2013777 : static inline void str_tolower(char *dst, char *src)
    1374             : {
    1375     2013777 :         register char *src_tmp = src;
    1376     2013777 :         register char *dst_tmp = dst;
    1377             : 
    1378    33899332 :         while (*src_tmp != '\0') {
    1379    31885555 :                 *dst_tmp = tolower(*src_tmp);
    1380    31885555 :                 ++src_tmp;
    1381    31885555 :                 ++dst_tmp;
    1382             :         }
    1383     2013777 : }
    1384             : 
    1385     1421669 : static bool str_tolower_copy(char **dst_name, const char *const src_name)
    1386             : {
    1387       24169 :         char *h_name_lower;
    1388             : 
    1389     1421669 :         if ((dst_name == NULL) || (src_name == NULL)) {
    1390           0 :                 return false;
    1391             :         }
    1392             : 
    1393     1421669 :         h_name_lower = strdup(src_name);
    1394     1421669 :         if (h_name_lower == NULL) {
    1395           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while strdup");
    1396           0 :                 return false;
    1397             :         }
    1398             : 
    1399     1421669 :         str_tolower(h_name_lower, h_name_lower);
    1400     1421669 :         *dst_name = h_name_lower;
    1401     1421669 :         return true;
    1402             : }
    1403             : 
    1404           0 : static void libc_setpwent(void)
    1405             : {
    1406           0 :         nwrap_bind_symbol_all();
    1407             : 
    1408           0 :         nwrap_main_global->libc->symbols._libc_setpwent.f();
    1409           0 : }
    1410             : 
    1411           0 : static struct passwd *libc_getpwent(void)
    1412             : {
    1413           0 :         nwrap_bind_symbol_all();
    1414             : 
    1415           0 :         return nwrap_main_global->libc->symbols._libc_getpwent.f();
    1416             : }
    1417             : 
    1418             : #ifdef HAVE_GETPWENT_R
    1419             : #  ifdef HAVE_SOLARIS_GETPWENT_R
    1420             : static struct passwd *libc_getpwent_r(struct passwd *pwdst,
    1421             :                                       char *buf,
    1422             :                                       int buflen)
    1423             : {
    1424             :         nwrap_bind_symbol_all();
    1425             : 
    1426             :         return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
    1427             :                                                                    buf,
    1428             :                                                                    buflen);
    1429             : }
    1430             : #  else /* HAVE_SOLARIS_GETPWENT_R */
    1431           0 : static int libc_getpwent_r(struct passwd *pwdst,
    1432             :                            char *buf,
    1433             :                            size_t buflen,
    1434             :                            struct passwd **pwdstp)
    1435             : {
    1436           0 :         nwrap_bind_symbol_all();
    1437             : 
    1438           0 :         return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
    1439             :                                                                    buf,
    1440             :                                                                    buflen,
    1441             :                                                                    pwdstp);
    1442             : }
    1443             : #  endif /* HAVE_SOLARIS_GETPWENT_R */
    1444             : #endif /* HAVE_GETPWENT_R */
    1445             : 
    1446         636 : static void libc_endpwent(void)
    1447             : {
    1448         636 :         nwrap_bind_symbol_all();
    1449             : 
    1450         636 :         nwrap_main_global->libc->symbols._libc_endpwent.f();
    1451         636 : }
    1452             : 
    1453           0 : static int libc_initgroups(const char *user, gid_t gid)
    1454             : {
    1455           0 :         nwrap_bind_symbol_all();
    1456             : 
    1457           0 :         return nwrap_main_global->libc->symbols._libc_initgroups.f(user, gid);
    1458             : }
    1459             : 
    1460           0 : static struct group *libc_getgrnam(const char *name)
    1461             : {
    1462           0 :         nwrap_bind_symbol_all();
    1463             : 
    1464           0 :         return nwrap_main_global->libc->symbols._libc_getgrnam.f(name);
    1465             : }
    1466             : 
    1467             : #ifdef HAVE_GETGRNAM_R
    1468         217 : static int libc_getgrnam_r(const char *name,
    1469             :                            struct group *grp,
    1470             :                            char *buf,
    1471             :                            size_t buflen,
    1472             :                            struct group **result)
    1473             : {
    1474         217 :         nwrap_bind_symbol_all();
    1475             : 
    1476         217 :         return nwrap_main_global->libc->symbols._libc_getgrnam_r.f(name,
    1477             :                                                                    grp,
    1478             :                                                                    buf,
    1479             :                                                                    buflen,
    1480             :                                                                    result);
    1481             : }
    1482             : #endif
    1483             : 
    1484           4 : static struct group *libc_getgrgid(gid_t gid)
    1485             : {
    1486           4 :         nwrap_bind_symbol_all();
    1487             : 
    1488           4 :         return nwrap_main_global->libc->symbols._libc_getgrgid.f(gid);
    1489             : }
    1490             : 
    1491             : #ifdef HAVE_GETGRGID_R
    1492         238 : static int libc_getgrgid_r(gid_t gid,
    1493             :                            struct group *grp,
    1494             :                            char *buf,
    1495             :                            size_t buflen,
    1496             :                            struct group **result)
    1497             : {
    1498         238 :         nwrap_bind_symbol_all();
    1499             : 
    1500         238 :         return nwrap_main_global->libc->symbols._libc_getgrgid_r.f(gid,
    1501             :                                                                    grp,
    1502             :                                                                    buf,
    1503             :                                                                    buflen,
    1504             :                                                                    result);
    1505             : }
    1506             : #endif
    1507             : 
    1508           0 : static void libc_setgrent(void)
    1509             : {
    1510           0 :         nwrap_bind_symbol_all();
    1511             : 
    1512           0 :         nwrap_main_global->libc->symbols._libc_setgrent.f();
    1513           0 : }
    1514             : 
    1515           0 : static struct group *libc_getgrent(void)
    1516             : {
    1517           0 :         nwrap_bind_symbol_all();
    1518             : 
    1519           0 :         return nwrap_main_global->libc->symbols._libc_getgrent.f();
    1520             : }
    1521             : 
    1522             : #ifdef HAVE_GETGRENT_R
    1523             : #  ifdef HAVE_SOLARIS_GETGRENT_R
    1524             : static struct group *libc_getgrent_r(struct group *group,
    1525             :                                      char *buf,
    1526             :                                      size_t buflen)
    1527             : {
    1528             :         nwrap_bind_symbol_all();
    1529             : 
    1530             :         return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
    1531             :                                                                    buf,
    1532             :                                                                    buflen);
    1533             : }
    1534             : #  else /* HAVE_SOLARIS_GETGRENT_R */
    1535           0 : static int libc_getgrent_r(struct group *group,
    1536             :                            char *buf,
    1537             :                            size_t buflen,
    1538             :                            struct group **result)
    1539             : {
    1540           0 :         nwrap_bind_symbol_all();
    1541             : 
    1542           0 :         return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
    1543             :                                                                    buf,
    1544             :                                                                    buflen,
    1545             :                                                                    result);
    1546             : }
    1547             : #  endif /* HAVE_SOLARIS_GETGRENT_R */
    1548             : #endif /* HAVE_GETGRENT_R */
    1549             : 
    1550           0 : static void libc_endgrent(void)
    1551             : {
    1552           0 :         nwrap_bind_symbol_all();
    1553             : 
    1554           0 :         nwrap_main_global->libc->symbols._libc_endgrent.f();
    1555           0 : }
    1556             : 
    1557             : #ifdef HAVE_GETGROUPLIST
    1558           3 : static int libc_getgrouplist(const char *user,
    1559             :                              gid_t group,
    1560             :                              gid_t *groups,
    1561             :                              int *ngroups)
    1562             : {
    1563           3 :         nwrap_bind_symbol_all();
    1564             : 
    1565           3 :         return nwrap_main_global->libc->symbols._libc_getgrouplist.f(user,
    1566             :                                                                      group,
    1567             :                                                                      groups,
    1568             :                                                                      ngroups);
    1569             : }
    1570             : #endif
    1571             : 
    1572           0 : static void libc_sethostent(int stayopen)
    1573             : {
    1574           0 :         nwrap_bind_symbol_all();
    1575             : 
    1576           0 :         nwrap_main_global->libc->symbols._libc_sethostent.f(stayopen);
    1577           0 : }
    1578             : 
    1579           0 : static struct hostent *libc_gethostent(void)
    1580             : {
    1581           0 :         nwrap_bind_symbol_all();
    1582             : 
    1583           0 :         return nwrap_main_global->libc->symbols._libc_gethostent.f();
    1584             : }
    1585             : 
    1586           0 : static void libc_endhostent(void)
    1587             : {
    1588           0 :         nwrap_bind_symbol_all();
    1589             : 
    1590           0 :         nwrap_main_global->libc->symbols._libc_endhostent.f();
    1591           0 : }
    1592             : 
    1593           0 : static struct hostent *libc_gethostbyname(const char *name)
    1594             : {
    1595           0 :         nwrap_bind_symbol_all();
    1596             : 
    1597           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyname.f(name);
    1598             : }
    1599             : 
    1600             : #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
    1601           0 : static struct hostent *libc_gethostbyname2(const char *name, int af)
    1602             : {
    1603           0 :         nwrap_bind_symbol_all();
    1604             : 
    1605           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyname2.f(name, af);
    1606             : }
    1607             : #endif
    1608             : 
    1609             : #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
    1610           0 : static int libc_gethostbyname2_r(const char *name,
    1611             :                                  int af,
    1612             :                                  struct hostent *ret,
    1613             :                                  char *buf,
    1614             :                                  size_t buflen,
    1615             :                                  struct hostent **result,
    1616             :                                  int *h_errnop)
    1617             : {
    1618           0 :         nwrap_bind_symbol_all();
    1619             : 
    1620           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyname2_r.f(name,
    1621             :                                                                          af,
    1622             :                                                                          ret,
    1623             :                                                                          buf,
    1624             :                                                                          buflen,
    1625             :                                                                          result,
    1626             :                                                                          h_errnop);
    1627             : }
    1628             : #endif
    1629             : 
    1630           0 : static struct hostent *libc_gethostbyaddr(const void *addr,
    1631             :                                           socklen_t len,
    1632             :                                           int type)
    1633             : {
    1634           0 :         nwrap_bind_symbol_all();
    1635             : 
    1636           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyaddr.f(addr,
    1637             :                                                                       len,
    1638             :                                                                       type);
    1639             : }
    1640             : 
    1641        9584 : static int libc_gethostname(char *name, size_t len)
    1642             : {
    1643        9584 :         nwrap_bind_symbol_all();
    1644             : 
    1645        9584 :         return nwrap_main_global->libc->symbols._libc_gethostname.f(name, len);
    1646             : }
    1647             : 
    1648             : #ifdef HAVE_GETHOSTBYNAME_R
    1649           0 : static int libc_gethostbyname_r(const char *name,
    1650             :                                 struct hostent *ret,
    1651             :                                 char *buf,
    1652             :                                 size_t buflen,
    1653             :                                 struct hostent **result,
    1654             :                                 int *h_errnop)
    1655             : {
    1656           0 :         nwrap_bind_symbol_all();
    1657             : 
    1658           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyname_r.f(name,
    1659             :                                                                         ret,
    1660             :                                                                         buf,
    1661             :                                                                         buflen,
    1662             :                                                                         result,
    1663             :                                                                         h_errnop);
    1664             : }
    1665             : #endif
    1666             : 
    1667             : #ifdef HAVE_GETHOSTBYADDR_R
    1668           0 : static int libc_gethostbyaddr_r(const void *addr,
    1669             :                                 socklen_t len,
    1670             :                                 int type,
    1671             :                                 struct hostent *ret,
    1672             :                                 char *buf,
    1673             :                                 size_t buflen,
    1674             :                                 struct hostent **result,
    1675             :                                 int *h_errnop)
    1676             : {
    1677           0 :         nwrap_bind_symbol_all();
    1678             : 
    1679           0 :         return nwrap_main_global->libc->symbols._libc_gethostbyaddr_r.f(addr,
    1680             :                                                                         len,
    1681             :                                                                         type,
    1682             :                                                                         ret,
    1683             :                                                                         buf,
    1684             :                                                                         buflen,
    1685             :                                                                         result,
    1686             :                                                                         h_errnop);
    1687             : }
    1688             : #endif
    1689             : 
    1690     1180337 : static int libc_getaddrinfo(const char *node,
    1691             :                             const char *service,
    1692             :                             const struct addrinfo *hints,
    1693             :                             struct addrinfo **res)
    1694             : {
    1695     1180337 :         nwrap_bind_symbol_all();
    1696             : 
    1697     1180337 :         return nwrap_main_global->libc->symbols._libc_getaddrinfo.f(node,
    1698             :                                                                     service,
    1699             :                                                                     hints,
    1700             :                                                                     res);
    1701             : }
    1702             : 
    1703        7758 : static int libc_getnameinfo(const struct sockaddr *sa,
    1704             :                             socklen_t salen,
    1705             :                             char *host,
    1706             :                             size_t hostlen,
    1707             :                             char *serv,
    1708             :                             size_t servlen,
    1709             :                             int flags)
    1710             : {
    1711        7758 :         nwrap_bind_symbol_all();
    1712             : 
    1713        7758 :         return nwrap_main_global->libc->symbols._libc_getnameinfo.f(sa,
    1714             :                                                                     salen,
    1715             :                                                                     host,
    1716             :                                                                     hostlen,
    1717             :                                                                     serv,
    1718             :                                                                     servlen,
    1719             :                                                                     flags);
    1720             : }
    1721             : 
    1722       32494 : static void __nwrap_bind_symbol_all_once(void)
    1723             : {
    1724       32494 :         nwrap_bind_symbol_libc(getpwnam);
    1725             : #ifdef HAVE_GETPWNAM_R
    1726             : # ifdef HAVE___POSIX_GETPWNAM_R
    1727             :         nwrap_bind_symbol_libc_posix(getpwnam_r);
    1728             : # else
    1729       32494 :         nwrap_bind_symbol_libc(getpwnam_r);
    1730             : # endif
    1731             : #endif
    1732       32494 :         nwrap_bind_symbol_libc(getpwuid);
    1733             : #ifdef HAVE_GETPWUID_R
    1734             : # ifdef HAVE___POSIX_GETPWUID_R
    1735             :         nwrap_bind_symbol_libc_posix(getpwuid_r);
    1736             : # else
    1737       32494 :         nwrap_bind_symbol_libc(getpwuid_r);
    1738             : # endif
    1739             : #endif
    1740       32494 :         nwrap_bind_symbol_libc(setpwent);
    1741       32494 :         nwrap_bind_symbol_libc(getpwent);
    1742             : #ifdef HAVE_GETPWENT_R
    1743       32494 :         nwrap_bind_symbol_libc(getpwent_r);
    1744             : #endif
    1745       32494 :         nwrap_bind_symbol_libc(endpwent);
    1746       32494 :         nwrap_bind_symbol_libc(initgroups);
    1747       32494 :         nwrap_bind_symbol_libc(getgrnam);
    1748             : #ifdef HAVE_GETGRNAM_R
    1749             : # ifdef HAVE___POSIX_GETGRNAM_R
    1750             :         nwrap_bind_symbol_libc_posix(getgrnam_r);
    1751             : # else
    1752       32494 :         nwrap_bind_symbol_libc(getgrnam_r);
    1753             : # endif
    1754             : #endif
    1755       32494 :         nwrap_bind_symbol_libc(getgrgid);
    1756             : #ifdef HAVE_GETGRGID_R
    1757             : # ifdef HAVE___POSIX_GETGRGID_R
    1758             :         nwrap_bind_symbol_libc_posix(getgrgid_r);
    1759             : # else
    1760       32494 :         nwrap_bind_symbol_libc(getgrgid_r);
    1761             : # endif
    1762             : #endif
    1763       32494 :         nwrap_bind_symbol_libc(setgrent);
    1764       32494 :         nwrap_bind_symbol_libc(getgrent);
    1765       32494 :         nwrap_bind_symbol_libc(getgrent_r);
    1766       32494 :         nwrap_bind_symbol_libc(endgrent);
    1767       32494 :         nwrap_bind_symbol_libc(getgrouplist);
    1768       32494 :         nwrap_bind_symbol_libnsl(sethostent);
    1769       32494 :         nwrap_bind_symbol_libnsl(gethostent);
    1770       32494 :         nwrap_bind_symbol_libnsl(endhostent);
    1771       32494 :         nwrap_bind_symbol_libnsl(gethostbyname);
    1772             : #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
    1773       32494 :         nwrap_bind_symbol_libnsl(gethostbyname2);
    1774             : #endif
    1775             : #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
    1776       32494 :         nwrap_bind_symbol_libnsl(gethostbyname2_r);
    1777             : #endif
    1778       32494 :         nwrap_bind_symbol_libnsl(gethostbyaddr);
    1779       32494 :         nwrap_bind_symbol_libnsl(gethostname);
    1780             : #ifdef HAVE_GETHOSTBYNAME_R
    1781       32494 :         nwrap_bind_symbol_libnsl(gethostbyname_r);
    1782             : #endif
    1783             : #ifdef HAVE_GETHOSTBYADDR_R
    1784       32494 :         nwrap_bind_symbol_libnsl(gethostbyaddr_r);
    1785             : #endif
    1786       32494 :         nwrap_bind_symbol_libsocket(getaddrinfo);
    1787       32494 :         nwrap_bind_symbol_libsocket(getnameinfo);
    1788       32494 : }
    1789             : 
    1790     1203804 : static void nwrap_bind_symbol_all(void)
    1791             : {
    1792      116617 :         static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
    1793             : 
    1794     1203804 :         pthread_once(&all_symbol_binding_once, __nwrap_bind_symbol_all_once);
    1795     1087187 : }
    1796             : 
    1797             : /*********************************************************
    1798             :  * NWRAP NSS MODULE LOADER FUNCTIONS
    1799             :  *********************************************************/
    1800             : 
    1801      591383 : static void *_nwrap_bind_nss_module_symbol(struct nwrap_backend *b,
    1802             :                                            const char *fn_name)
    1803             : {
    1804      591383 :         void *res = NULL;
    1805      591383 :         char *s = NULL;
    1806        1586 :         int rc;
    1807             : 
    1808      591383 :         if (b->so_handle == NULL) {
    1809           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "No handle");
    1810           0 :                 return NULL;
    1811             :         }
    1812             : 
    1813      591383 :         rc = asprintf(&s, "_nss_%s_%s", b->name, fn_name);
    1814      591383 :         if (rc == -1) {
    1815           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
    1816           0 :                 return NULL;
    1817             :         }
    1818             : 
    1819      591383 :         res = dlsym(b->so_handle, s);
    1820      591383 :         if (res == NULL) {
    1821       90982 :                 NWRAP_LOG(NWRAP_LOG_WARN,
    1822             :                           "Cannot find function %s in %s",
    1823             :                           s, b->so_path);
    1824             :         }
    1825      591383 :         SAFE_FREE(s);
    1826      589797 :         return res;
    1827             : }
    1828             : 
    1829             : #define nwrap_nss_module_bind_symbol(sym_name) \
    1830             :         if (symbols->_nss_##sym_name.obj == NULL) { \
    1831             :                 symbols->_nss_##sym_name.obj = \
    1832             :                         _nwrap_bind_nss_module_symbol(b, #sym_name); \
    1833             :         }
    1834             : 
    1835             : #define nwrap_nss_module_bind_symbol2(sym_name, alt_name) \
    1836             :         if (symbols->_nss_##sym_name.obj == NULL) { \
    1837             :                 symbols->_nss_##sym_name.obj = \
    1838             :                         _nwrap_bind_nss_module_symbol(b, #alt_name); \
    1839             :         }
    1840             : 
    1841             : static struct nwrap_nss_module_symbols *
    1842       45491 : nwrap_bind_nss_module_symbols(struct nwrap_backend *b)
    1843             : {
    1844         122 :         struct nwrap_nss_module_symbols *symbols;
    1845             : 
    1846       45491 :         if (!b->so_handle) {
    1847           0 :                 return NULL;
    1848             :         }
    1849             : 
    1850       45491 :         symbols = calloc(1, sizeof(struct nwrap_nss_module_symbols));
    1851       45491 :         if (symbols == NULL) {
    1852           0 :                 return NULL;
    1853             :         }
    1854             : 
    1855       45491 :         nwrap_nss_module_bind_symbol(getpwnam_r);
    1856       45491 :         nwrap_nss_module_bind_symbol(getpwuid_r);
    1857       45491 :         nwrap_nss_module_bind_symbol(setpwent);
    1858       45491 :         nwrap_nss_module_bind_symbol(getpwent_r);
    1859       45491 :         nwrap_nss_module_bind_symbol(endpwent);
    1860       45491 :         nwrap_nss_module_bind_symbol(initgroups_dyn);
    1861       45491 :         nwrap_nss_module_bind_symbol(getgrnam_r);
    1862       45491 :         nwrap_nss_module_bind_symbol(getgrgid_r);
    1863       45491 :         nwrap_nss_module_bind_symbol(setgrent);
    1864       45491 :         nwrap_nss_module_bind_symbol(getgrent_r);
    1865       45491 :         nwrap_nss_module_bind_symbol(endgrent);
    1866       45491 :         nwrap_nss_module_bind_symbol(gethostbyaddr_r);
    1867       45491 :         nwrap_nss_module_bind_symbol(gethostbyname2_r);
    1868             : 
    1869       45369 :         return symbols;
    1870             : }
    1871             : 
    1872       45491 : static void *nwrap_load_module(const char *so_path)
    1873             : {
    1874         122 :         void *h;
    1875             : 
    1876       45491 :         if (!so_path || !strlen(so_path)) {
    1877           0 :                 return NULL;
    1878             :         }
    1879             : 
    1880       45491 :         h = dlopen(so_path, RTLD_LAZY);
    1881       45491 :         if (!h) {
    1882           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    1883             :                           "Cannot open shared library %s",
    1884             :                           so_path);
    1885           0 :                 return NULL;
    1886             :         }
    1887             : 
    1888       45369 :         return h;
    1889             : }
    1890             : 
    1891      100856 : static bool nwrap_module_init(const char *name,
    1892             :                               struct nwrap_ops *ops,
    1893             :                               const char *so_path,
    1894             :                               size_t *num_backends,
    1895             :                               struct nwrap_backend **backends)
    1896             : {
    1897      100856 :         struct nwrap_backend *b = NULL;
    1898      100856 :         size_t n = *num_backends + 1;
    1899             : 
    1900      100856 :         b = realloc(*backends, sizeof(struct nwrap_backend) * n);
    1901      100856 :         if (b == NULL) {
    1902           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
    1903           0 :                 return false;
    1904             :         }
    1905      100856 :         *backends = b;
    1906             : 
    1907      100856 :         b = &((*backends)[*num_backends]);
    1908             : 
    1909      100856 :         *b = (struct nwrap_backend) {
    1910             :                 .name = name,
    1911             :                 .ops = ops,
    1912             :                 .so_path = so_path,
    1913             :         };
    1914             : 
    1915      100856 :         if (so_path != NULL) {
    1916       45491 :                 b->so_handle = nwrap_load_module(so_path);
    1917       45491 :                 b->symbols = nwrap_bind_nss_module_symbols(b);
    1918       45491 :                 if (b->symbols == NULL) {
    1919           0 :                         return false;
    1920             :                 }
    1921             :         }
    1922             : 
    1923      100856 :         *num_backends = n;
    1924             : 
    1925      100856 :         return true;
    1926             : }
    1927             : 
    1928       55365 : static void nwrap_libc_init(struct nwrap_main *r)
    1929             : {
    1930       55365 :         r->libc = calloc(1, sizeof(struct nwrap_libc));
    1931       55365 :         if (r->libc == NULL) {
    1932           0 :                 printf("Failed to allocate memory for libc");
    1933           0 :                 exit(-1);
    1934             :         }
    1935       55365 : }
    1936             : 
    1937       55365 : static void nwrap_backend_init(struct nwrap_main *r)
    1938             : {
    1939       55365 :         const char *module_so_path = getenv("NSS_WRAPPER_MODULE_SO_PATH");
    1940       55365 :         const char *module_fn_name = getenv("NSS_WRAPPER_MODULE_FN_PREFIX");
    1941             : 
    1942       55365 :         r->num_backends = 0;
    1943       55365 :         r->backends = NULL;
    1944             : 
    1945       55365 :         if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
    1946             :                                &r->num_backends,
    1947             :                                &r->backends)) {
    1948           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    1949             :                           "Failed to initialize 'files' backend");
    1950           0 :                 return;
    1951             :         }
    1952             : 
    1953       55365 :         if (module_so_path != NULL &&
    1954       45596 :             module_so_path[0] != '\0' &&
    1955       45491 :             module_fn_name != NULL &&
    1956       45491 :             module_fn_name[0] != '\0') {
    1957       45491 :                 if (!nwrap_module_init(module_fn_name,
    1958             :                                        &nwrap_module_ops,
    1959             :                                        module_so_path,
    1960             :                                        &r->num_backends,
    1961             :                                        &r->backends)) {
    1962           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    1963             :                                   "Failed to initialize '%s' backend",
    1964             :                                   module_fn_name);
    1965           0 :                         return;
    1966             :                 }
    1967             :         }
    1968             : }
    1969             : 
    1970     1135716 : static int _nss_wrapper_init_mutex(pthread_mutex_t *m, const char *name)
    1971             : {
    1972       29508 :         pthread_mutexattr_t ma;
    1973     1135716 :         bool need_destroy = false;
    1974     1135716 :         int ret = 0;
    1975             : 
    1976             : #define __CHECK(cmd) do { \
    1977             :         ret = cmd; \
    1978             :         if (ret != 0) { \
    1979             :                 NWRAP_LOG(NWRAP_LOG_ERROR, \
    1980             :                           "%s: %s - failed %d", \
    1981             :                           name, #cmd, ret); \
    1982             :                 goto done; \
    1983             :         } \
    1984             : } while(0)
    1985             : 
    1986     1135716 :         *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
    1987     1135716 :         __CHECK(pthread_mutexattr_init(&ma));
    1988     1135716 :         need_destroy = true;
    1989     1135716 :         __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
    1990     1135716 :         __CHECK(pthread_mutex_init(m, &ma));
    1991     1135716 : done:
    1992     1106208 :         if (need_destroy) {
    1993     1135716 :                 pthread_mutexattr_destroy(&ma);
    1994             :         }
    1995     1135716 :         return ret;
    1996             : }
    1997             : 
    1998     7266324 : static void nwrap_init(void)
    1999             : {
    2000      214573 :         const char *env;
    2001      214573 :         char *endptr;
    2002      214573 :         size_t max_hostents_tmp;
    2003      214573 :         int ok;
    2004             : 
    2005     7266324 :         nwrap_mutex_lock(&nwrap_initialized_mutex);
    2006     7266324 :         if (nwrap_initialized) {
    2007     7210959 :                 nwrap_mutex_unlock(&nwrap_initialized_mutex);
    2008     7210959 :                 return;
    2009             :         }
    2010             : 
    2011             :         /*
    2012             :          * Still holding nwrap_initialized lock here.
    2013             :          * We don't use NWRAP_(UN)LOCK_ALL macros here because we
    2014             :          * want to avoid overhead when other threads do their job.
    2015             :          */
    2016       55365 :         nwrap_mutex_lock(&nwrap_global_mutex);
    2017       55365 :         nwrap_mutex_lock(&nwrap_gr_global_mutex);
    2018       55365 :         nwrap_mutex_lock(&nwrap_he_global_mutex);
    2019       55365 :         nwrap_mutex_lock(&nwrap_pw_global_mutex);
    2020       55365 :         nwrap_mutex_lock(&nwrap_sp_global_mutex);
    2021             : 
    2022       55365 :         nwrap_initialized = true;
    2023             : 
    2024       55365 :         env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
    2025       55365 :         if (env != NULL) {
    2026       55365 :                 max_hostents_tmp = (size_t)strtoul(env, &endptr, 10);
    2027       55365 :                 if ((*env == '\0') ||
    2028       55365 :                     (*endptr != '\0') ||
    2029             :                     (max_hostents_tmp == 0)) {
    2030           0 :                         NWRAP_LOG(NWRAP_LOG_DEBUG,
    2031             :                                   "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
    2032             :                                   "value or value is too small. "
    2033             :                                   "Using default value: %lu.",
    2034             :                                   (unsigned long)max_hostents);
    2035             :                 } else {
    2036       55365 :                         max_hostents = max_hostents_tmp;
    2037             :                 }
    2038             :         }
    2039             :         /* Initialize hash table */
    2040       55365 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    2041             :                   "Initializing hash table of size %lu items.",
    2042             :                   (unsigned long)max_hostents);
    2043       55365 :         ok = hcreate(max_hostents);
    2044       55365 :         if (!ok) {
    2045           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2046             :                           "Failed to initialize hash table");
    2047           0 :                 exit(-1);
    2048             :         }
    2049             : 
    2050       55365 :         nwrap_main_global = &__nwrap_main_global;
    2051             : 
    2052       55365 :         nwrap_libc_init(nwrap_main_global);
    2053             : 
    2054       55365 :         nwrap_backend_init(nwrap_main_global);
    2055             : 
    2056             :         /* passwd */
    2057       55365 :         nwrap_pw_global.cache = &__nwrap_cache_pw;
    2058             : 
    2059       55365 :         nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
    2060       55365 :         nwrap_pw_global.cache->fp = NULL;
    2061       55365 :         nwrap_pw_global.cache->fd = -1;
    2062       55365 :         nwrap_pw_global.cache->private_data = &nwrap_pw_global;
    2063       55365 :         nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
    2064       55365 :         nwrap_pw_global.cache->unload = nwrap_pw_unload;
    2065             : 
    2066             :         /* shadow */
    2067             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    2068       55365 :         nwrap_sp_global.cache = &__nwrap_cache_sp;
    2069             : 
    2070       55365 :         nwrap_sp_global.cache->path = getenv("NSS_WRAPPER_SHADOW");
    2071       55365 :         nwrap_sp_global.cache->fp = NULL;
    2072       55365 :         nwrap_sp_global.cache->fd = -1;
    2073       55365 :         nwrap_sp_global.cache->private_data = &nwrap_sp_global;
    2074       55365 :         nwrap_sp_global.cache->parse_line = nwrap_sp_parse_line;
    2075       55365 :         nwrap_sp_global.cache->unload = nwrap_sp_unload;
    2076             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    2077             : 
    2078             :         /* group */
    2079       55365 :         nwrap_gr_global.cache = &__nwrap_cache_gr;
    2080             : 
    2081       55365 :         nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
    2082       55365 :         nwrap_gr_global.cache->fp = NULL;
    2083       55365 :         nwrap_gr_global.cache->fd = -1;
    2084       55365 :         nwrap_gr_global.cache->private_data = &nwrap_gr_global;
    2085       55365 :         nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
    2086       55365 :         nwrap_gr_global.cache->unload = nwrap_gr_unload;
    2087             : 
    2088             :         /* hosts */
    2089       55365 :         nwrap_he_global.cache = &__nwrap_cache_he;
    2090             : 
    2091       55365 :         nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS");
    2092       55365 :         nwrap_he_global.cache->fp = NULL;
    2093       55365 :         nwrap_he_global.cache->fd = -1;
    2094       55365 :         nwrap_he_global.cache->private_data = &nwrap_he_global;
    2095       55365 :         nwrap_he_global.cache->parse_line = nwrap_he_parse_line;
    2096       55365 :         nwrap_he_global.cache->unload = nwrap_he_unload;
    2097             : 
    2098             :         /* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
    2099       55365 :         nwrap_mutex_unlock(&nwrap_sp_global_mutex);
    2100       55365 :         nwrap_mutex_unlock(&nwrap_pw_global_mutex);
    2101       55365 :         nwrap_mutex_unlock(&nwrap_he_global_mutex);
    2102       55365 :         nwrap_mutex_unlock(&nwrap_gr_global_mutex);
    2103       55365 :         nwrap_mutex_unlock(&nwrap_global_mutex);
    2104       55365 :         nwrap_mutex_unlock(&nwrap_initialized_mutex);
    2105             : }
    2106             : 
    2107      732214 : bool nss_wrapper_enabled(void)
    2108             : {
    2109      732214 :         nwrap_init();
    2110             : 
    2111      732214 :         if (nwrap_pw_global.cache->path == NULL ||
    2112      725939 :             nwrap_pw_global.cache->path[0] == '\0') {
    2113        4481 :                 return false;
    2114             :         }
    2115      725939 :         if (nwrap_gr_global.cache->path == NULL ||
    2116      725939 :             nwrap_gr_global.cache->path[0] == '\0') {
    2117           0 :                 return false;
    2118             :         }
    2119             : 
    2120      723071 :         return true;
    2121             : }
    2122             : 
    2123             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    2124           0 : bool nss_wrapper_shadow_enabled(void)
    2125             : {
    2126           0 :         nwrap_init();
    2127             : 
    2128           0 :         if (nwrap_sp_global.cache->path == NULL ||
    2129           0 :             nwrap_sp_global.cache->path[0] == '\0') {
    2130           0 :                 return false;
    2131             :         }
    2132             : 
    2133           0 :         return true;
    2134             : }
    2135             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    2136             : 
    2137     3889972 : bool nss_wrapper_hosts_enabled(void)
    2138             : {
    2139     3889972 :         nwrap_init();
    2140             : 
    2141     3889972 :         if (nwrap_he_global.cache->path == NULL ||
    2142     3771760 :             nwrap_he_global.cache->path[0] == '\0') {
    2143      118212 :                 return false;
    2144             :         }
    2145             : 
    2146     3690993 :         return true;
    2147             : }
    2148             : 
    2149      181852 : static bool nwrap_hostname_enabled(void)
    2150             : {
    2151      181852 :         nwrap_init();
    2152             : 
    2153      181852 :         if (getenv("NSS_WRAPPER_HOSTNAME") == NULL) {
    2154        9584 :                 return false;
    2155             :         }
    2156             : 
    2157      171497 :         return true;
    2158             : }
    2159             : 
    2160       88566 : static bool nwrap_parse_file(struct nwrap_cache *nwrap)
    2161             : {
    2162       88566 :         char *line = NULL;
    2163         206 :         ssize_t n;
    2164             :         /* Unused but getline needs it */
    2165         206 :         size_t len;
    2166         206 :         bool ok;
    2167             : 
    2168       88566 :         if (nwrap->st.st_size == 0) {
    2169           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0");
    2170           0 :                 return true;
    2171             :         }
    2172             : 
    2173             :         /* Support for 32-bit system I guess */
    2174       88566 :         if (nwrap->st.st_size > INT32_MAX) {
    2175           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2176             :                           "Size[%u] larger than INT32_MAX",
    2177             :                           (unsigned)nwrap->st.st_size);
    2178           0 :                 return false;
    2179             :         }
    2180             : 
    2181       88566 :         rewind(nwrap->fp);
    2182             : 
    2183        1344 :         do {
    2184     1749873 :                 n = getline(&line, &len, nwrap->fp);
    2185     1749873 :                 if (n < 0) {
    2186       88566 :                         SAFE_FREE(line);
    2187       88566 :                         if (feof(nwrap->fp)) {
    2188       88360 :                                 break;
    2189             :                         }
    2190             : 
    2191           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2192             :                                   "Unable to read line from file: %s",
    2193             :                                   nwrap->path);
    2194           0 :                         return false;
    2195             :                 }
    2196             : 
    2197     1661307 :                 if (line[n - 1] == '\n') {
    2198     1661307 :                         line[n - 1] = '\0';
    2199             :                 }
    2200             : 
    2201     1661307 :                 if (line[0] == '\0') {
    2202           0 :                         SAFE_FREE(line);
    2203           0 :                         continue;
    2204             :                 }
    2205             : 
    2206     1661307 :                 ok = nwrap->parse_line(nwrap, line);
    2207     1661307 :                 if (!ok) {
    2208           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2209             :                                   "Unable to parse line file: %s",
    2210             :                                   line);
    2211           0 :                         SAFE_FREE(line);
    2212           0 :                         return false;
    2213             :                 }
    2214             : 
    2215             :                 /* Line is parsed without issues so add it to list */
    2216     1661307 :                 ok = nwrap_vector_add_item(&(nwrap->lines), (void *const) line);
    2217     1661307 :                 if (!ok) {
    2218           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2219             :                                   "Unable to add line to vector");
    2220           0 :                         return false;
    2221             :                 }
    2222             : 
    2223             :                 /* This forces getline to allocate new memory for line. */
    2224     1661307 :                 line = NULL;
    2225     1661307 :         } while (!feof(nwrap->fp));
    2226             : 
    2227       88360 :         return true;
    2228             : }
    2229             : 
    2230      518902 : static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
    2231             : {
    2232      518902 :         nwrap->unload(nwrap);
    2233             : 
    2234      518902 :         nwrap_lines_unload(nwrap);
    2235      510728 : }
    2236             : 
    2237     1766288 : static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap)
    2238             : {
    2239       25423 :         struct stat st;
    2240       25423 :         int ret;
    2241       25423 :         bool ok;
    2242     1766288 :         bool retried = false;
    2243             : 
    2244     1766288 :         assert(nwrap != NULL);
    2245             : 
    2246     1428363 : reopen:
    2247     1773238 :         if (nwrap->fd < 0) {
    2248       78538 :                 nwrap->fp = fopen(nwrap->path, "re");
    2249       78538 :                 if (nwrap->fp == NULL) {
    2250           0 :                         nwrap->fd = -1;
    2251           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2252             :                                   "Unable to open '%s' readonly %d:%s",
    2253             :                                   nwrap->path, nwrap->fd,
    2254             :                                   strerror(errno));
    2255           0 :                         return false;
    2256             : 
    2257             :                 }
    2258       78538 :                 nwrap->fd = fileno(nwrap->fp);
    2259       78538 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path);
    2260             :         }
    2261             : 
    2262     1773238 :         ret = fstat(nwrap->fd, &st);
    2263     1773238 :         if (ret != 0 && errno == EBADF && retried == false) {
    2264             :                 /* maybe something closed the fd on our behalf */
    2265           0 :                 NWRAP_LOG(NWRAP_LOG_TRACE,
    2266             :                           "fstat(%s) - %d:%s - reopen",
    2267             :                           nwrap->path,
    2268             :                           ret,
    2269             :                           strerror(errno));
    2270           0 :                 retried = true;
    2271           0 :                 memset(&nwrap->st, 0, sizeof(nwrap->st));
    2272           0 :                 fclose(nwrap->fp);
    2273           0 :                 nwrap->fp = NULL;
    2274           0 :                 nwrap->fd = -1;
    2275           0 :                 goto reopen;
    2276             :         }
    2277     1773238 :         else if (ret != 0) {
    2278           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2279             :                           "fstat(%s) - %d:%s",
    2280             :                           nwrap->path,
    2281             :                           ret,
    2282             :                           strerror(errno));
    2283           0 :                 fclose(nwrap->fp);
    2284           0 :                 nwrap->fp = NULL;
    2285           0 :                 nwrap->fd = -1;
    2286           0 :                 return false;
    2287             :         }
    2288             : 
    2289     1773238 :         if (retried == false && st.st_nlink == 0) {
    2290             :                 /* maybe someone has replaced the file... */
    2291        6950 :                 NWRAP_LOG(NWRAP_LOG_TRACE,
    2292             :                           "st_nlink == 0, reopen %s",
    2293             :                           nwrap->path);
    2294        6950 :                 retried = true;
    2295        6950 :                 memset(&nwrap->st, 0, sizeof(nwrap->st));
    2296        6950 :                 fclose(nwrap->fp);
    2297        6950 :                 nwrap->fp = NULL;
    2298        6950 :                 nwrap->fd = -1;
    2299        6950 :                 goto reopen;
    2300             :         }
    2301             : 
    2302     1766288 :         if (st.st_mtime == nwrap->st.st_mtime) {
    2303     1677722 :                 NWRAP_LOG(NWRAP_LOG_TRACE,
    2304             :                           "st_mtime[%u] hasn't changed, skip reload",
    2305             :                           (unsigned)st.st_mtime);
    2306     1677722 :                 return true;
    2307             :         }
    2308             : 
    2309       88566 :         NWRAP_LOG(NWRAP_LOG_TRACE,
    2310             :                   "st_mtime has changed [%u] => [%u], start reload",
    2311             :                   (unsigned)st.st_mtime,
    2312             :                   (unsigned)nwrap->st.st_mtime);
    2313             : 
    2314       88566 :         nwrap->st = st;
    2315             : 
    2316       88566 :         nwrap_files_cache_unload(nwrap);
    2317             : 
    2318       88566 :         ok = nwrap_parse_file(nwrap);
    2319       88566 :         if (!ok) {
    2320           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path);
    2321           0 :                 nwrap_files_cache_unload(nwrap);
    2322           0 :                 return false;
    2323             :         }
    2324             : 
    2325       88566 :         NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path);
    2326       88566 :         return true;
    2327             : }
    2328             : 
    2329             : /*
    2330             :  * the caller has to call nwrap_unload() on failure
    2331             :  */
    2332     1176883 : static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
    2333             : {
    2334         854 :         struct nwrap_pw *nwrap_pw;
    2335         854 :         char *c;
    2336         854 :         char *p;
    2337         854 :         char *e;
    2338         854 :         struct passwd *pw;
    2339         854 :         size_t list_size;
    2340             : 
    2341     1176883 :         nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
    2342             : 
    2343     1176883 :         list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
    2344     1176883 :         pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
    2345     1176883 :         if (!pw) {
    2346           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2347             :                           "realloc(%u) failed",
    2348             :                           (unsigned)list_size);
    2349           0 :                 return false;
    2350             :         }
    2351     1176883 :         nwrap_pw->list = pw;
    2352             : 
    2353     1176883 :         pw = &nwrap_pw->list[nwrap_pw->num];
    2354             : 
    2355     1176883 :         c = line;
    2356             : 
    2357             :         /* name */
    2358     1176883 :         p = strchr(c, ':');
    2359     1176883 :         if (!p) {
    2360           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2361             :                           "Invalid line[%s]: '%s'",
    2362             :                           line,
    2363             :                           c);
    2364           0 :                 return false;
    2365             :         }
    2366     1176883 :         *p = '\0';
    2367     1176883 :         p++;
    2368     1176883 :         pw->pw_name = c;
    2369     1176883 :         c = p;
    2370             : 
    2371     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", pw->pw_name);
    2372             : 
    2373             :         /* password */
    2374     1176883 :         p = strchr(c, ':');
    2375     1176883 :         if (!p) {
    2376           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2377           0 :                 return false;
    2378             :         }
    2379     1176883 :         *p = '\0';
    2380     1176883 :         p++;
    2381     1176883 :         pw->pw_passwd = c;
    2382     1176883 :         c = p;
    2383             : 
    2384     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]\n", pw->pw_passwd);
    2385             : 
    2386             :         /* uid */
    2387     1176883 :         p = strchr(c, ':');
    2388     1176883 :         if (!p) {
    2389           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2390           0 :                 return false;
    2391             :         }
    2392     1176883 :         *p = '\0';
    2393     1176883 :         p++;
    2394     1176883 :         e = NULL;
    2395     1176883 :         pw->pw_uid = (uid_t)strtoul(c, &e, 10);
    2396     1176883 :         if (c == e) {
    2397           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2398             :                           "Invalid line[%s]: '%s' - %s",
    2399             :                           line, c, strerror(errno));
    2400           0 :                 return false;
    2401             :         }
    2402     1176883 :         if (e == NULL) {
    2403           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2404             :                           "Invalid line[%s]: '%s' - %s",
    2405             :                           line, c, strerror(errno));
    2406           0 :                 return false;
    2407             :         }
    2408     1176883 :         if (e[0] != '\0') {
    2409           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2410             :                           "Invalid line[%s]: '%s' - %s",
    2411             :                           line, c, strerror(errno));
    2412           0 :                 return false;
    2413             :         }
    2414     1176883 :         c = p;
    2415             : 
    2416     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "uid[%u]", pw->pw_uid);
    2417             : 
    2418             :         /* gid */
    2419     1176883 :         p = strchr(c, ':');
    2420     1176883 :         if (!p) {
    2421           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2422           0 :                 return false;
    2423             :         }
    2424     1176883 :         *p = '\0';
    2425     1176883 :         p++;
    2426     1176883 :         e = NULL;
    2427     1176883 :         pw->pw_gid = (gid_t)strtoul(c, &e, 10);
    2428     1176883 :         if (c == e) {
    2429           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2430             :                           "Invalid line[%s]: '%s' - %s",
    2431             :                           line, c, strerror(errno));
    2432           0 :                 return false;
    2433             :         }
    2434     1176883 :         if (e == NULL) {
    2435           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2436             :                           "Invalid line[%s]: '%s' - %s",
    2437             :                           line, c, strerror(errno));
    2438           0 :                 return false;
    2439             :         }
    2440     1176883 :         if (e[0] != '\0') {
    2441           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2442             :                           "Invalid line[%s]: '%s' - %s",
    2443             :                           line, c, strerror(errno));
    2444           0 :                 return false;
    2445             :         }
    2446     1176883 :         c = p;
    2447             : 
    2448     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid);
    2449             : 
    2450             : #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
    2451             :         pw->pw_class = discard_const_p(char, "");
    2452             : 
    2453             :         NWRAP_LOG(NWRAP_LOG_TRACE, "class[%s]", pw->pw_class);
    2454             : #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
    2455             : 
    2456             : #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
    2457             :         pw->pw_change = 0;
    2458             : 
    2459             :         NWRAP_LOG(NWRAP_LOG_TRACE,
    2460             :                   "change[%lu]",
    2461             :                   (unsigned long)pw->pw_change);
    2462             : #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
    2463             : 
    2464             : #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
    2465             :         pw->pw_expire = 0;
    2466             : 
    2467             :         NWRAP_LOG(NWRAP_LOG_TRACE,
    2468             :                   "expire[%lu]",
    2469             :                   (unsigned long)pw->pw_expire);
    2470             : #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
    2471             : 
    2472             :         /* gecos */
    2473     1176883 :         p = strchr(c, ':');
    2474     1176883 :         if (!p) {
    2475           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "invalid line[%s]: '%s'", line, c);
    2476           0 :                 return false;
    2477             :         }
    2478     1176883 :         *p = '\0';
    2479     1176883 :         p++;
    2480     1176883 :         pw->pw_gecos = c;
    2481     1176883 :         c = p;
    2482             : 
    2483     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "gecos[%s]", pw->pw_gecos);
    2484             : 
    2485             :         /* dir */
    2486     1176883 :         p = strchr(c, ':');
    2487     1176883 :         if (!p) {
    2488           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "'%s'", c);
    2489           0 :                 return false;
    2490             :         }
    2491     1176883 :         *p = '\0';
    2492     1176883 :         p++;
    2493     1176883 :         pw->pw_dir = c;
    2494     1176883 :         c = p;
    2495             : 
    2496     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "dir[%s]", pw->pw_dir);
    2497             : 
    2498             :         /* shell */
    2499     1176883 :         pw->pw_shell = c;
    2500     1176883 :         NWRAP_LOG(NWRAP_LOG_TRACE, "shell[%s]", pw->pw_shell);
    2501             : 
    2502     1176883 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    2503             :                   "Added user[%s:%s:%u:%u:%s:%s:%s]",
    2504             :                   pw->pw_name, pw->pw_passwd,
    2505             :                   pw->pw_uid, pw->pw_gid,
    2506             :                   pw->pw_gecos, pw->pw_dir, pw->pw_shell);
    2507             : 
    2508     1176883 :         nwrap_pw->num++;
    2509     1176883 :         return true;
    2510             : }
    2511             : 
    2512      154489 : static void nwrap_pw_unload(struct nwrap_cache *nwrap)
    2513             : {
    2514        2114 :         struct nwrap_pw *nwrap_pw;
    2515      154489 :         nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
    2516             : 
    2517      154489 :         SAFE_FREE(nwrap_pw->list);
    2518      154489 :         nwrap_pw->num = 0;
    2519      154489 :         nwrap_pw->idx = 0;
    2520      154489 : }
    2521             : 
    2522        5713 : static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
    2523             :                            char *buf, size_t buflen, struct passwd **dstp)
    2524             : {
    2525           6 :         char *first;
    2526           6 :         char *last;
    2527           6 :         off_t ofs;
    2528             : 
    2529        5713 :         first = src->pw_name;
    2530             : 
    2531        5713 :         last = src->pw_shell;
    2532       62843 :         while (*last) last++;
    2533             : 
    2534        5713 :         ofs = PTR_DIFF(last + 1, first);
    2535             : 
    2536        5713 :         if (ofs > (off_t) buflen) {
    2537           0 :                 return ERANGE;
    2538             :         }
    2539             : 
    2540        5713 :         memcpy(buf, first, ofs);
    2541             : 
    2542        5713 :         ofs = PTR_DIFF(src->pw_name, first);
    2543        5713 :         dst->pw_name = buf + ofs;
    2544        5713 :         ofs = PTR_DIFF(src->pw_passwd, first);
    2545        5713 :         dst->pw_passwd = buf + ofs;
    2546        5713 :         dst->pw_uid = src->pw_uid;
    2547        5713 :         dst->pw_gid = src->pw_gid;
    2548             : #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
    2549             :         ofs = PTR_DIFF(src->pw_class, first);
    2550             :         dst->pw_class = buf + ofs;
    2551             : #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
    2552             : 
    2553             : #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
    2554             :         dst->pw_change = 0;
    2555             : #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
    2556             : 
    2557             : #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
    2558             :         dst->pw_expire = 0;
    2559             : #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
    2560             : 
    2561        5713 :         ofs = PTR_DIFF(src->pw_gecos, first);
    2562        5713 :         dst->pw_gecos = buf + ofs;
    2563        5713 :         ofs = PTR_DIFF(src->pw_dir, first);
    2564        5713 :         dst->pw_dir = buf + ofs;
    2565        5713 :         ofs = PTR_DIFF(src->pw_shell, first);
    2566        5713 :         dst->pw_shell = buf + ofs;
    2567             : 
    2568        5713 :         if (dstp) {
    2569        5713 :                 *dstp = dst;
    2570             :         }
    2571             : 
    2572        5707 :         return 0;
    2573             : }
    2574             : 
    2575             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    2576           0 : static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line)
    2577             : {
    2578           0 :         struct nwrap_sp *nwrap_sp;
    2579           0 :         struct spwd *sp;
    2580           0 :         size_t list_size;
    2581           0 :         char *c;
    2582           0 :         char *e;
    2583           0 :         char *p;
    2584             : 
    2585           0 :         nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
    2586             : 
    2587           0 :         list_size = sizeof(*nwrap_sp->list) * (nwrap_sp->num+1);
    2588           0 :         sp = (struct spwd *)realloc(nwrap_sp->list, list_size);
    2589           0 :         if (sp == NULL) {
    2590           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2591             :                           "realloc(%u) failed",
    2592             :                           (unsigned)list_size);
    2593           0 :                 return false;
    2594             :         }
    2595           0 :         nwrap_sp->list = sp;
    2596             : 
    2597           0 :         sp = &nwrap_sp->list[nwrap_sp->num];
    2598             : 
    2599           0 :         c = line;
    2600             : 
    2601             :         /* name */
    2602           0 :         p = strchr(c, ':');
    2603           0 :         if (p == NULL) {
    2604           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2605             :                           "name -- Invalid line[%s]: '%s'",
    2606             :                           line,
    2607             :                           c);
    2608           0 :                 return false;
    2609             :         }
    2610           0 :         *p = '\0';
    2611           0 :         p++;
    2612           0 :         sp->sp_namp = c;
    2613           0 :         c = p;
    2614             : 
    2615           0 :         NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", sp->sp_namp);
    2616             : 
    2617             :         /* pwd */
    2618           0 :         p = strchr(c, ':');
    2619           0 :         if (p == NULL) {
    2620           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2621             :                           "pwd -- Invalid line[%s]: '%s'",
    2622             :                           line,
    2623             :                           c);
    2624           0 :                 return false;
    2625             :         }
    2626           0 :         *p = '\0';
    2627           0 :         p++;
    2628           0 :         sp->sp_pwdp = c;
    2629           0 :         c = p;
    2630             : 
    2631             :         /* lstchg (long) */
    2632           0 :         if (c[0] == ':') {
    2633           0 :                 sp->sp_lstchg = -1;
    2634           0 :                 p++;
    2635             :         } else {
    2636           0 :                 p = strchr(c, ':');
    2637           0 :                 if (p == NULL) {
    2638           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2639             :                                   "lstchg -- Invalid line[%s]: '%s'",
    2640             :                                   line,
    2641             :                                   c);
    2642           0 :                         return false;
    2643             :                 }
    2644           0 :                 *p = '\0';
    2645           0 :                 p++;
    2646           0 :                 sp->sp_lstchg = strtol(c, &e, 10);
    2647           0 :                 if (c == e) {
    2648           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2649             :                                   "lstchg -- Invalid line[%s]: '%s' - %s",
    2650             :                                   line, c, strerror(errno));
    2651           0 :                         return false;
    2652             :                 }
    2653           0 :                 if (e == NULL) {
    2654           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2655             :                                   "lstchg -- Invalid line[%s]: '%s' - %s",
    2656             :                                   line, c, strerror(errno));
    2657           0 :                         return false;
    2658             :                 }
    2659           0 :                 if (e[0] != '\0') {
    2660           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2661             :                                   "lstchg -- Invalid line[%s]: '%s' - %s",
    2662             :                                   line, c, strerror(errno));
    2663           0 :                         return false;
    2664             :                 }
    2665             :         }
    2666           0 :         c = p;
    2667             : 
    2668             :         /* min (long) */
    2669           0 :         if (c[0] == ':') {
    2670           0 :                 sp->sp_min = -1;
    2671           0 :                 p++;
    2672             :         } else {
    2673           0 :                 p = strchr(c, ':');
    2674           0 :                 if (p == NULL) {
    2675           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2676             :                                   "min -- Invalid line[%s]: '%s'",
    2677             :                                   line,
    2678             :                                   c);
    2679           0 :                         return false;
    2680             :                 }
    2681           0 :                 *p = '\0';
    2682           0 :                 p++;
    2683           0 :                 sp->sp_min = strtol(c, &e, 10);
    2684           0 :                 if (c == e) {
    2685           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2686             :                                   "min -- Invalid line[%s]: '%s' - %s",
    2687             :                                   line, c, strerror(errno));
    2688           0 :                         return false;
    2689             :                 }
    2690           0 :                 if (e == NULL) {
    2691           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2692             :                                   "min -- Invalid line[%s]: '%s' - %s",
    2693             :                                   line, c, strerror(errno));
    2694           0 :                         return false;
    2695             :                 }
    2696           0 :                 if (e[0] != '\0') {
    2697           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2698             :                                   "min -- Invalid line[%s]: '%s' - %s",
    2699             :                                   line, c, strerror(errno));
    2700           0 :                         return false;
    2701             :                 }
    2702             :         }
    2703           0 :         c = p;
    2704             : 
    2705             :         /* max (long) */
    2706           0 :         if (c[0] == ':') {
    2707           0 :                 sp->sp_max = -1;
    2708           0 :                 p++;
    2709             :         } else {
    2710           0 :                 p = strchr(c, ':');
    2711           0 :                 if (p == NULL) {
    2712           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2713             :                                   "max -- Invalid line[%s]: '%s'",
    2714             :                                   line,
    2715             :                                   c);
    2716           0 :                         return false;
    2717             :                 }
    2718           0 :                 *p = '\0';
    2719           0 :                 p++;
    2720           0 :                 sp->sp_max = strtol(c, &e, 10);
    2721           0 :                 if (c == e) {
    2722           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2723             :                                   "max -- Invalid line[%s]: '%s' - %s",
    2724             :                                   line, c, strerror(errno));
    2725           0 :                         return false;
    2726             :                 }
    2727           0 :                 if (e == NULL) {
    2728           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2729             :                                   "max -- Invalid line[%s]: '%s' - %s",
    2730             :                                   line, c, strerror(errno));
    2731           0 :                         return false;
    2732             :                 }
    2733           0 :                 if (e[0] != '\0') {
    2734           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2735             :                                   "max -- Invalid line[%s]: '%s' - %s",
    2736             :                                   line, c, strerror(errno));
    2737           0 :                         return false;
    2738             :                 }
    2739             :         }
    2740           0 :         c = p;
    2741             : 
    2742             :         /* warn (long) */
    2743           0 :         if (c[0] == ':') {
    2744           0 :                 sp->sp_warn = -1;
    2745           0 :                 p++;
    2746             :         } else {
    2747           0 :                 p = strchr(c, ':');
    2748           0 :                 if (p == NULL) {
    2749           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2750             :                                   "warn -- Invalid line[%s]: '%s'",
    2751             :                                   line,
    2752             :                                   c);
    2753           0 :                         return false;
    2754             :                 }
    2755           0 :                 *p = '\0';
    2756           0 :                 p++;
    2757           0 :                 sp->sp_warn = strtol(c, &e, 10);
    2758           0 :                 if (c == e) {
    2759           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2760             :                                   "warn -- Invalid line[%s]: '%s' - %s",
    2761             :                                   line, c, strerror(errno));
    2762           0 :                         return false;
    2763             :                 }
    2764           0 :                 if (e == NULL) {
    2765           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2766             :                                   "warn -- Invalid line[%s]: '%s' - %s",
    2767             :                                   line, c, strerror(errno));
    2768           0 :                         return false;
    2769             :                 }
    2770           0 :                 if (e[0] != '\0') {
    2771           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2772             :                                   "warn -- Invalid line[%s]: '%s' - %s",
    2773             :                                   line, c, strerror(errno));
    2774           0 :                         return false;
    2775             :                 }
    2776             :         }
    2777           0 :         c = p;
    2778             : 
    2779             :         /* inact (long) */
    2780           0 :         if (c[0] == ':') {
    2781           0 :                 sp->sp_inact = -1;
    2782           0 :                 p++;
    2783             :         } else {
    2784           0 :                 p = strchr(c, ':');
    2785           0 :                 if (p == NULL) {
    2786           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2787             :                                   "inact -- Invalid line[%s]: '%s'",
    2788             :                                   line,
    2789             :                                   c);
    2790           0 :                         return false;
    2791             :                 }
    2792           0 :                 *p = '\0';
    2793           0 :                 p++;
    2794           0 :                 sp->sp_inact = strtol(c, &e, 10);
    2795           0 :                 if (c == e) {
    2796           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2797             :                                   "inact -- Invalid line[%s]: '%s' - %s",
    2798             :                                   line, c, strerror(errno));
    2799           0 :                         return false;
    2800             :                 }
    2801           0 :                 if (e == NULL) {
    2802           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2803             :                                   "inact -- Invalid line[%s]: '%s' - %s",
    2804             :                                   line, c, strerror(errno));
    2805           0 :                         return false;
    2806             :                 }
    2807           0 :                 if (e[0] != '\0') {
    2808           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2809             :                                   "inact -- Invalid line[%s]: '%s' - %s",
    2810             :                                   line, c, strerror(errno));
    2811           0 :                         return false;
    2812             :                 }
    2813             :         }
    2814           0 :         c = p;
    2815             : 
    2816             :         /* expire (long) */
    2817           0 :         if (c[0] == ':') {
    2818           0 :                 sp->sp_expire = -1;
    2819           0 :                 p++;
    2820             :         } else {
    2821           0 :                 p = strchr(c, ':');
    2822           0 :                 if (p == NULL) {
    2823           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2824             :                                   "expire -- Invalid line[%s]: '%s'",
    2825             :                                   line,
    2826             :                                   c);
    2827           0 :                         return false;
    2828             :                 }
    2829           0 :                 *p = '\0';
    2830           0 :                 p++;
    2831           0 :                 sp->sp_expire = strtol(c, &e, 10);
    2832           0 :                 if (c == e) {
    2833           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2834             :                                   "expire -- Invalid line[%s]: '%s' - %s",
    2835             :                                   line, c, strerror(errno));
    2836           0 :                         return false;
    2837             :                 }
    2838           0 :                 if (e == NULL) {
    2839           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2840             :                                   "expire -- Invalid line[%s]: '%s' - %s",
    2841             :                                   line, c, strerror(errno));
    2842           0 :                         return false;
    2843             :                 }
    2844           0 :                 if (e[0] != '\0') {
    2845           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2846             :                                   "expire -- Invalid line[%s]: '%s' - %s",
    2847             :                                   line, c, strerror(errno));
    2848           0 :                         return false;
    2849             :                 }
    2850             :         }
    2851           0 :         c = p;
    2852             : 
    2853           0 :         nwrap_sp->num++;
    2854           0 :         return true;
    2855             : }
    2856             : 
    2857      107584 : static void nwrap_sp_unload(struct nwrap_cache *nwrap)
    2858             : {
    2859        1992 :         struct nwrap_sp *nwrap_sp;
    2860      107584 :         nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
    2861             : 
    2862      107584 :         SAFE_FREE(nwrap_sp->list);
    2863      107584 :         nwrap_sp->num = 0;
    2864      107584 :         nwrap_sp->idx = 0;
    2865      107584 : }
    2866             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    2867             : 
    2868             : /*
    2869             :  * the caller has to call nwrap_unload() on failure
    2870             :  */
    2871      192514 : static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
    2872             : {
    2873          12 :         struct nwrap_gr *nwrap_gr;
    2874          12 :         char *c;
    2875          12 :         char *p;
    2876          12 :         char *e;
    2877          12 :         struct group *gr;
    2878          12 :         size_t list_size;
    2879          12 :         unsigned nummem;
    2880             : 
    2881      192514 :         nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
    2882             : 
    2883      192514 :         list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
    2884      192514 :         gr = (struct group *)realloc(nwrap_gr->list, list_size);
    2885      192514 :         if (!gr) {
    2886           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
    2887           0 :                 return false;
    2888             :         }
    2889      192514 :         nwrap_gr->list = gr;
    2890             : 
    2891      192514 :         gr = &nwrap_gr->list[nwrap_gr->num];
    2892             : 
    2893      192514 :         c = line;
    2894             : 
    2895             :         /* name */
    2896      192514 :         p = strchr(c, ':');
    2897      192514 :         if (!p) {
    2898           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2899           0 :                 return false;
    2900             :         }
    2901      192514 :         *p = '\0';
    2902      192514 :         p++;
    2903      192514 :         gr->gr_name = c;
    2904      192514 :         c = p;
    2905             : 
    2906      192514 :         NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
    2907             : 
    2908             :         /* password */
    2909      192514 :         p = strchr(c, ':');
    2910      192514 :         if (!p) {
    2911           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2912           0 :                 return false;
    2913             :         }
    2914      192514 :         *p = '\0';
    2915      192514 :         p++;
    2916      192514 :         gr->gr_passwd = c;
    2917      192514 :         c = p;
    2918             : 
    2919      192514 :         NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
    2920             : 
    2921             :         /* gid */
    2922      192514 :         p = strchr(c, ':');
    2923      192514 :         if (!p) {
    2924           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
    2925           0 :                 return false;
    2926             :         }
    2927      192514 :         *p = '\0';
    2928      192514 :         p++;
    2929      192514 :         e = NULL;
    2930      192514 :         gr->gr_gid = (gid_t)strtoul(c, &e, 10);
    2931      192514 :         if (c == e) {
    2932           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2933             :                           "Invalid line[%s]: '%s' - %s",
    2934             :                           line, c, strerror(errno));
    2935           0 :                 return false;
    2936             :         }
    2937      192514 :         if (e == NULL) {
    2938           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2939             :                           "Invalid line[%s]: '%s' - %s",
    2940             :                           line, c, strerror(errno));
    2941           0 :                 return false;
    2942             :         }
    2943      192514 :         if (e[0] != '\0') {
    2944           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    2945             :                           "Invalid line[%s]: '%s' - %s",
    2946             :                           line, c, strerror(errno));
    2947           0 :                 return false;
    2948             :         }
    2949      192514 :         c = p;
    2950             : 
    2951      192514 :         NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]", gr->gr_gid);
    2952             : 
    2953             :         /* members */
    2954      192514 :         gr->gr_mem = (char **)malloc(sizeof(char *));
    2955      192514 :         if (!gr->gr_mem) {
    2956           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
    2957           0 :                 return false;
    2958             :         }
    2959      192514 :         gr->gr_mem[0] = NULL;
    2960             : 
    2961      201471 :         for(nummem = 0; p != NULL && p[0] != '\0'; nummem++) {
    2962           2 :                 char **m;
    2963           2 :                 size_t m_size;
    2964        8957 :                 c = p;
    2965        8957 :                 p = strchr(c, ',');
    2966        8957 :                 if (p) {
    2967           0 :                         *p = '\0';
    2968           0 :                         p++;
    2969             :                 }
    2970             : 
    2971        8957 :                 if (strlen(c) == 0) {
    2972           0 :                         break;
    2973             :                 }
    2974             : 
    2975        8957 :                 m_size = sizeof(char *) * (nummem+2);
    2976        8957 :                 m = (char **)realloc(gr->gr_mem, m_size);
    2977        8957 :                 if (!m) {
    2978           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    2979             :                                   "realloc(%zd) failed",
    2980             :                                   m_size);
    2981           0 :                         return false;
    2982             :                 }
    2983        8957 :                 gr->gr_mem = m;
    2984        8957 :                 gr->gr_mem[nummem] = c;
    2985        8957 :                 gr->gr_mem[nummem+1] = NULL;
    2986             : 
    2987        8957 :                 NWRAP_LOG(NWRAP_LOG_TRACE,
    2988             :                           "member[%u]: '%s'",
    2989             :                           nummem, gr->gr_mem[nummem]);
    2990             :         }
    2991             : 
    2992      192514 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    2993             :                   "Added group[%s:%s:%u:] with %u members",
    2994             :                   gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem);
    2995             : 
    2996      192514 :         nwrap_gr->num++;
    2997      192514 :         return true;
    2998             : }
    2999             : 
    3000      110141 : static void nwrap_gr_unload(struct nwrap_cache *nwrap)
    3001             : {
    3002        1994 :         int i;
    3003        1994 :         struct nwrap_gr *nwrap_gr;
    3004      110141 :         nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
    3005             : 
    3006      110141 :         if (nwrap_gr->list) {
    3007      667942 :                 for (i=0; i < nwrap_gr->num; i++) {
    3008      629962 :                         SAFE_FREE(nwrap_gr->list[i].gr_mem);
    3009             :                 }
    3010       37980 :                 SAFE_FREE(nwrap_gr->list);
    3011             :         }
    3012             : 
    3013      110141 :         nwrap_gr->num = 0;
    3014      110141 :         nwrap_gr->idx = 0;
    3015      110141 : }
    3016             : 
    3017      884018 : static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
    3018             : {
    3019         816 :         struct nwrap_entlist *el;
    3020             : 
    3021      884018 :         if (ed == NULL) {
    3022           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3023             :                           "entry is NULL, can't create list item");
    3024           0 :                 return NULL;
    3025             :         }
    3026             : 
    3027      884018 :         el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist));
    3028      884018 :         if (el == NULL) {
    3029           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed");
    3030           0 :                 return NULL;
    3031             :         }
    3032             : 
    3033      884018 :         el->next = NULL;
    3034      884018 :         el->ed = ed;
    3035             : 
    3036      884018 :         return el;
    3037             : }
    3038             : 
    3039      587964 : static bool nwrap_ed_inventarize_add_new(char *const h_name,
    3040             :                                          struct nwrap_entdata *const ed)
    3041             : {
    3042         544 :         ENTRY e;
    3043         544 :         ENTRY *p;
    3044         544 :         struct nwrap_entlist *el;
    3045         544 :         bool ok;
    3046             : 
    3047      587964 :         if (h_name == NULL) {
    3048           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
    3049           0 :                 return false;
    3050             :         }
    3051             : 
    3052      587964 :         el = nwrap_entlist_init(ed);
    3053      587964 :         if (el == NULL) {
    3054           0 :                 return false;
    3055             :         }
    3056             : 
    3057      587964 :         e.key = h_name;
    3058      587964 :         e.data = (void *)el;
    3059             : 
    3060      587964 :         p = hsearch(e, ENTER);
    3061      587964 :         if (p == NULL) {
    3062           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3063             :                           "Hash table is full (%s)!",
    3064             :                           strerror(errno));
    3065           0 :                 return false;
    3066             :         }
    3067             : 
    3068      587964 :         ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
    3069      587964 :         if (!ok) {
    3070           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3071             :                           "Failed to add list entry to vector.");
    3072           0 :                 return false;
    3073             :         }
    3074             : 
    3075      587420 :         return true;
    3076             : }
    3077             : 
    3078      296054 : static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
    3079             :                                                  struct nwrap_entlist *const el)
    3080             : {
    3081         272 :         struct nwrap_entlist *cursor;
    3082         272 :         struct nwrap_entlist *el_new;
    3083             : 
    3084      296054 :         if (el == NULL) {
    3085           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add");
    3086           0 :                 return false;
    3087             :         }
    3088             : 
    3089             : 
    3090      296054 :         for (cursor = el; cursor->next != NULL; cursor = cursor->next)
    3091             :         {
    3092           0 :                 if (cursor->ed == ed) {
    3093             :                         /* The entry already exists in this list. */
    3094           0 :                         return true;
    3095             :                 }
    3096             :         }
    3097             : 
    3098      296054 :         if (cursor->ed == ed) {
    3099             :                 /* The entry already exists in this list. */
    3100           0 :                 return true;
    3101             :         }
    3102             : 
    3103      296054 :         el_new = nwrap_entlist_init(ed);
    3104      296054 :         if (el_new == NULL) {
    3105           0 :                 return false;
    3106             :         }
    3107             : 
    3108      296054 :         cursor->next = el_new;
    3109      296054 :         return true;
    3110             : }
    3111             : 
    3112      884018 : static bool nwrap_ed_inventarize(char *const name,
    3113             :                                  struct nwrap_entdata *const ed)
    3114             : {
    3115         816 :         ENTRY e;
    3116         816 :         ENTRY *p;
    3117         816 :         bool ok;
    3118             : 
    3119      884018 :         e.key = name;
    3120      884018 :         e.data = NULL;
    3121             : 
    3122      884018 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
    3123             : 
    3124      884018 :         p = hsearch(e, FIND);
    3125      884018 :         if (p == NULL) {
    3126      587964 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name);
    3127      587964 :                 ok = nwrap_ed_inventarize_add_new(name, ed);
    3128             :         } else {
    3129      296054 :                 struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
    3130             : 
    3131      296054 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name);
    3132      296054 :                 ok = nwrap_ed_inventarize_add_to_existing(ed, el);
    3133             :         }
    3134             : 
    3135      884018 :         return ok;
    3136             : }
    3137             : 
    3138      291910 : static bool nwrap_add_hname(struct nwrap_entdata *const ed)
    3139             : {
    3140      291910 :         char *const h_name = (char *const)(ed->ht.h_name);
    3141         272 :         unsigned i;
    3142         272 :         bool ok;
    3143             : 
    3144      291910 :         ok = nwrap_ed_inventarize(h_name, ed);
    3145      291910 :         if (!ok) {
    3146           0 :                 return false;
    3147             :         }
    3148             : 
    3149      291910 :         if (ed->ht.h_aliases == NULL) {
    3150           0 :                 return true;
    3151             :         }
    3152             : 
    3153             :         /* Itemize aliases */
    3154      592108 :         for (i = 0; ed->ht.h_aliases[i] != NULL; ++i) {
    3155         272 :                 char *h_name_alias;
    3156             : 
    3157      300198 :                 h_name_alias = ed->ht.h_aliases[i];
    3158             : 
    3159      300198 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
    3160             : 
    3161      300198 :                 if (!nwrap_ed_inventarize(h_name_alias, ed)) {
    3162           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    3163             :                                   "Unable to add alias: %s", h_name_alias);
    3164           0 :                         return false;
    3165             :                 }
    3166             :         }
    3167             : 
    3168      291638 :         return true;
    3169             : }
    3170             : 
    3171      291910 : static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
    3172             : {
    3173      291910 :         struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data;
    3174      291910 :         bool do_aliases = true;
    3175      291910 :         ssize_t aliases_count = 0;
    3176         272 :         char *p;
    3177         272 :         char *i;
    3178         272 :         char *n;
    3179             : 
    3180         272 :         char *ip;
    3181         272 :         bool ok;
    3182             : 
    3183         272 :         struct nwrap_entdata *ed = (struct nwrap_entdata *)
    3184      291910 :                                    malloc(sizeof(struct nwrap_entdata));
    3185      291910 :         if (ed == NULL) {
    3186           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3187             :                           "Unable to allocate memory for nwrap_entdata");
    3188           0 :                 return false;
    3189             :         }
    3190      291910 :         ZERO_STRUCTP(ed);
    3191             : 
    3192      291910 :         i = line;
    3193             : 
    3194             :         /*
    3195             :          * IP
    3196             :          */
    3197             : 
    3198             :         /* Walk to first char */
    3199      291910 :         for (p = i; *p != '.' && *p != ':' && !isxdigit((int) *p); p++) {
    3200           0 :                 if (*p == '\0') {
    3201           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    3202             :                                   "Invalid line[%s]: '%s'",
    3203             :                                   line, i);
    3204           0 :                         free(ed);
    3205           0 :                         return false;
    3206             :                 }
    3207             :         }
    3208             : 
    3209     7527775 :         for (i = p; !isspace((int)*p); p++) {
    3210     7235865 :                 if (*p == '\0') {
    3211           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    3212             :                                   "Invalid line[%s]: '%s'",
    3213             :                                   line, i);
    3214           0 :                         free(ed);
    3215           0 :                         return false;
    3216             :                 }
    3217             :         }
    3218             : 
    3219      291910 :         *p = '\0';
    3220             : 
    3221      291910 :         if (inet_pton(AF_INET, i, ed->addr.host_addr)) {
    3222      145955 :                 ed->ht.h_addrtype = AF_INET;
    3223      145955 :                 ed->ht.h_length = 4;
    3224             : #ifdef HAVE_IPV6
    3225      145955 :         } else if (inet_pton(AF_INET6, i, ed->addr.host_addr)) {
    3226      145955 :                 ed->ht.h_addrtype = AF_INET6;
    3227      145955 :                 ed->ht.h_length = 16;
    3228             : #endif
    3229             :         } else {
    3230           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3231             :                           "Invalid line[%s]: '%s'",
    3232             :                           line, i);
    3233             : 
    3234           0 :                 free(ed);
    3235           0 :                 return false;
    3236             :         }
    3237      291910 :         ip = i;
    3238             : 
    3239      291910 :         ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
    3240      291638 :                                    (void *const)ed->addr.host_addr);
    3241      291910 :         if (!ok) {
    3242           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
    3243           0 :                 free(ed);
    3244           0 :                 return false;
    3245             :         }
    3246      291910 :         ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
    3247             : 
    3248      291910 :         p++;
    3249             : 
    3250             :         /*
    3251             :          * FQDN
    3252             :          */
    3253             : 
    3254             :         /* Walk to first char */
    3255      291910 :         for (n = p; *p != '_' && !isalnum((int) *p); p++) {
    3256           0 :                 if (*p == '\0') {
    3257           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR,
    3258             :                                   "Invalid line[%s]: '%s'",
    3259             :                                   line, n);
    3260             : 
    3261           0 :                         free(ed);
    3262           0 :                         return false;
    3263             :                 }
    3264             :         }
    3265             : 
    3266     9041166 :         for (n = p; !isspace((int)*p); p++) {
    3267     8749256 :                 if (*p == '\0') {
    3268           0 :                         do_aliases = false;
    3269           0 :                         break;
    3270             :                 }
    3271             :         }
    3272             : 
    3273      291910 :         *p = '\0';
    3274             : 
    3275             :         /* Convert to lowercase. This operate on same memory region */
    3276      291910 :         str_tolower(n, n);
    3277      291910 :         ed->ht.h_name = n;
    3278             : 
    3279             :         /* glib's getent always dereferences he->h_aliases */
    3280      291910 :         ed->ht.h_aliases = malloc(sizeof(char *));
    3281      291910 :         if (ed->ht.h_aliases == NULL) {
    3282           0 :                 free(ed);
    3283           0 :                 return false;
    3284             :         }
    3285      291910 :         ed->ht.h_aliases[0] = NULL;
    3286             : 
    3287             :         /*
    3288             :          * Aliases
    3289             :          */
    3290      592108 :         while (do_aliases) {
    3291         272 :                 char **aliases;
    3292         272 :                 char *a;
    3293             : 
    3294      300198 :                 p++;
    3295             : 
    3296             :                 /* Walk to first char */
    3297      300198 :                 for (a = p; *p != '_' && !isalnum((int) *p); p++) {
    3298           0 :                         if (*p == '\0') {
    3299           0 :                                 do_aliases = false;
    3300           0 :                                 break;
    3301             :                         }
    3302             :                 }
    3303             :                 /* Only trailing spaces are left */
    3304      300198 :                 if (!do_aliases) {
    3305           0 :                         break;
    3306             :                 }
    3307             : 
    3308     3527906 :                 for (a = p; !isspace((int)*p); p++) {
    3309     3519618 :                         if (*p == '\0') {
    3310      291638 :                                 do_aliases = false;
    3311      291638 :                                 break;
    3312             :                         }
    3313             :                 }
    3314             : 
    3315      300198 :                 *p = '\0';
    3316             : 
    3317      300198 :                 aliases = realloc(ed->ht.h_aliases, sizeof(char *) * (aliases_count + 2));
    3318      300198 :                 if (aliases == NULL) {
    3319           0 :                         free(ed);
    3320           0 :                         return false;
    3321             :                 }
    3322      300198 :                 ed->ht.h_aliases = aliases;
    3323             : 
    3324      300198 :                 str_tolower(a, a);
    3325      300198 :                 aliases[aliases_count] = a;
    3326      300198 :                 aliases[aliases_count + 1] = NULL;
    3327             : 
    3328      300198 :                 aliases_count += 1;
    3329             :         }
    3330             : 
    3331      291910 :         ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
    3332      291910 :         if (!ok) {
    3333           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
    3334           0 :                 free(ed);
    3335           0 :                 return false;
    3336             :         }
    3337             : 
    3338      291910 :         ed->aliases_count = aliases_count;
    3339             :         /* Inventarize item */
    3340      291910 :         ok = nwrap_add_hname(ed);
    3341      291910 :         if (!ok) {
    3342           0 :                 return false;
    3343             :         }
    3344             : 
    3345      291910 :         ok = nwrap_ed_inventarize(ip, ed);
    3346      291910 :         if (!ok) {
    3347           0 :                 return false;
    3348             :         }
    3349             : 
    3350      291910 :         nwrap_he->num++;
    3351      291910 :         return true;
    3352             : }
    3353             : 
    3354      146688 : static void nwrap_he_unload(struct nwrap_cache *nwrap)
    3355             : {
    3356      146688 :         struct nwrap_he *nwrap_he =
    3357             :                 (struct nwrap_he *)nwrap->private_data;
    3358        2074 :         struct nwrap_entdata *ed;
    3359        2074 :         struct nwrap_entlist *el;
    3360        2074 :         size_t i;
    3361        2074 :         int rc;
    3362             : 
    3363      690008 :         nwrap_vector_foreach (ed, nwrap_he->entries, i)
    3364             :         {
    3365      541246 :                 SAFE_FREE(ed->nwrap_addrdata.items);
    3366      541246 :                 SAFE_FREE(ed->ht.h_aliases);
    3367      541246 :                 SAFE_FREE(ed);
    3368             :         }
    3369      146688 :         SAFE_FREE(nwrap_he->entries.items);
    3370      146688 :         nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
    3371             : 
    3372     1242058 :         nwrap_vector_foreach(el, nwrap_he->lists, i)
    3373             :         {
    3374     2738642 :                 while (el != NULL) {
    3375       10362 :                         struct nwrap_entlist *el_next;
    3376             : 
    3377     1645346 :                         el_next = el->next;
    3378     1645346 :                         SAFE_FREE(el);
    3379     1645346 :                         el = el_next;
    3380             :                 }
    3381             :         }
    3382      146688 :         SAFE_FREE(nwrap_he->lists.items);
    3383      146688 :         nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
    3384             : 
    3385      146688 :         nwrap_he->num = 0;
    3386      146688 :         nwrap_he->idx = 0;
    3387             : 
    3388             :         /*
    3389             :          * If we unload the file, the pointers in the hash table point to
    3390             :          * invalid memory. So we need to destroy the hash table and recreate
    3391             :          * it.
    3392             :          */
    3393      146688 :         hdestroy();
    3394      146688 :         rc = hcreate(max_hostents);
    3395      146688 :         if (rc == 0) {
    3396           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to initialize hash table");
    3397           0 :                 exit(-1);
    3398             :         }
    3399      146688 : }
    3400             : 
    3401             : 
    3402             : /* user functions */
    3403      116718 : static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
    3404             :                                            const char *name)
    3405             : {
    3406        1098 :         int i;
    3407        1098 :         bool ok;
    3408             : 
    3409        1098 :         (void) b; /* unused */
    3410             : 
    3411      116718 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
    3412             : 
    3413      116718 :         ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
    3414      116718 :         if (!ok) {
    3415           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
    3416           0 :                 return NULL;
    3417             :         }
    3418             : 
    3419     1982308 :         for (i=0; i<nwrap_pw_global.num; i++) {
    3420     1912732 :                 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
    3421       47142 :                         NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
    3422       47142 :                         return &nwrap_pw_global.list[i];
    3423             :                 }
    3424     1865590 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3425             :                           "user[%s] does not match [%s]",
    3426             :                           name,
    3427             :                           nwrap_pw_global.list[i].pw_name);
    3428             :         }
    3429             : 
    3430       69576 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
    3431             : 
    3432       69576 :         errno = ENOENT;
    3433       69576 :         return NULL;
    3434             : }
    3435             : 
    3436       46495 : static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
    3437             :                                   const char *name, struct passwd *pwdst,
    3438             :                                   char *buf, size_t buflen, struct passwd **pwdstp)
    3439             : {
    3440           4 :         struct passwd *pw;
    3441             : 
    3442       46495 :         pw = nwrap_files_getpwnam(b, name);
    3443       46495 :         if (!pw) {
    3444       45355 :                 if (errno == 0) {
    3445           0 :                         return ENOENT;
    3446             :                 }
    3447       45355 :                 return errno;
    3448             :         }
    3449             : 
    3450        1140 :         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
    3451             : }
    3452             : 
    3453      158553 : static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
    3454             :                                            uid_t uid)
    3455             : {
    3456         150 :         int i;
    3457         150 :         bool ok;
    3458             : 
    3459         150 :         (void) b; /* unused */
    3460             : 
    3461      158553 :         ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
    3462      158553 :         if (!ok) {
    3463           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
    3464           0 :                 return NULL;
    3465             :         }
    3466             : 
    3467      554843 :         for (i=0; i<nwrap_pw_global.num; i++) {
    3468      548533 :                 if (nwrap_pw_global.list[i].pw_uid == uid) {
    3469      152243 :                         NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] found", uid);
    3470      152243 :                         return &nwrap_pw_global.list[i];
    3471             :                 }
    3472      396290 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3473             :                           "uid[%u] does not match [%u]",
    3474             :                           uid,
    3475             :                           nwrap_pw_global.list[i].pw_uid);
    3476             :         }
    3477             : 
    3478        6310 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] not found\n", uid);
    3479             : 
    3480        6310 :         errno = ENOENT;
    3481        6310 :         return NULL;
    3482             : }
    3483             : 
    3484        4422 : static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
    3485             :                                   uid_t uid, struct passwd *pwdst,
    3486             :                                   char *buf, size_t buflen, struct passwd **pwdstp)
    3487             : {
    3488           2 :         struct passwd *pw;
    3489             : 
    3490        4422 :         pw = nwrap_files_getpwuid(b, uid);
    3491        4422 :         if (!pw) {
    3492         701 :                 if (errno == 0) {
    3493           0 :                         return ENOENT;
    3494             :                 }
    3495         701 :                 return errno;
    3496             :         }
    3497             : 
    3498        3721 :         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
    3499             : }
    3500             : 
    3501             : /* user enum functions */
    3502         365 : static void nwrap_files_setpwent(struct nwrap_backend *b)
    3503             : {
    3504           0 :         (void) b; /* unused */
    3505             : 
    3506         365 :         nwrap_pw_global.idx = 0;
    3507         365 : }
    3508             : 
    3509       55787 : static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
    3510             : {
    3511           0 :         struct passwd *pw;
    3512             : 
    3513           0 :         (void) b; /* unused */
    3514             : 
    3515       55787 :         if (nwrap_pw_global.idx == 0) {
    3516           0 :                 bool ok;
    3517         365 :                 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
    3518         365 :                 if (!ok) {
    3519           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
    3520           0 :                         return NULL;
    3521             :                 }
    3522             :         }
    3523             : 
    3524       55787 :         if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
    3525        1845 :                 errno = ENOENT;
    3526        1845 :                 return NULL;
    3527             :         }
    3528             : 
    3529       53942 :         pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
    3530             : 
    3531       53942 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3532             :                   "return user[%s] uid[%u]",
    3533             :                   pw->pw_name, pw->pw_uid);
    3534             : 
    3535       53942 :         return pw;
    3536             : }
    3537             : 
    3538        1608 : static int nwrap_files_getpwent_r(struct nwrap_backend *b,
    3539             :                                   struct passwd *pwdst, char *buf,
    3540             :                                   size_t buflen, struct passwd **pwdstp)
    3541             : {
    3542           0 :         struct passwd *pw;
    3543             : 
    3544        1608 :         pw = nwrap_files_getpwent(b);
    3545        1608 :         if (!pw) {
    3546         756 :                 if (errno == 0) {
    3547           0 :                         return ENOENT;
    3548             :                 }
    3549         756 :                 return errno;
    3550             :         }
    3551             : 
    3552         852 :         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
    3553             : }
    3554             : 
    3555       12554 : static void nwrap_files_endpwent(struct nwrap_backend *b)
    3556             : {
    3557          57 :         (void) b; /* unused */
    3558             : 
    3559       12554 :         nwrap_pw_global.idx = 0;
    3560       12554 : }
    3561             : 
    3562             : /* shadow */
    3563             : 
    3564             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    3565             : 
    3566             : #ifdef HAVE_SETSPENT
    3567             : static void nwrap_files_setspent(void)
    3568             : {
    3569             :         nwrap_sp_global.idx = 0;
    3570             : }
    3571             : 
    3572             : static struct spwd *nwrap_files_getspent(void)
    3573             : {
    3574             :         struct spwd *sp;
    3575             : 
    3576             :         if (nwrap_sp_global.idx == 0) {
    3577             :                 bool ok;
    3578             : 
    3579             :                 ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
    3580             :                 if (!ok) {
    3581             :                         NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
    3582             :                         return NULL;
    3583             :                 }
    3584             :         }
    3585             : 
    3586             :         if (nwrap_sp_global.idx >= nwrap_sp_global.num) {
    3587             :                 errno = ENOENT;
    3588             :                 return NULL;
    3589             :         }
    3590             : 
    3591             :         sp = &nwrap_sp_global.list[nwrap_sp_global.idx++];
    3592             : 
    3593             :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3594             :                   "return user[%s]",
    3595             :                   sp->sp_namp);
    3596             : 
    3597             :         return sp;
    3598             : }
    3599             : 
    3600             : static void nwrap_files_endspent(void)
    3601             : {
    3602             :         nwrap_sp_global.idx = 0;
    3603             : }
    3604             : #endif /* HAVE_SETSPENT */
    3605             : 
    3606           0 : static struct spwd *nwrap_files_getspnam(const char *name)
    3607             : {
    3608           0 :         int i;
    3609           0 :         bool ok;
    3610             : 
    3611           0 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
    3612             : 
    3613           0 :         ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
    3614           0 :         if (!ok) {
    3615           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
    3616           0 :                 return NULL;
    3617             :         }
    3618             : 
    3619           0 :         for (i=0; i<nwrap_sp_global.num; i++) {
    3620           0 :                 if (strcmp(nwrap_sp_global.list[i].sp_namp, name) == 0) {
    3621           0 :                         NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
    3622           0 :                         return &nwrap_sp_global.list[i];
    3623             :                 }
    3624           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3625             :                           "user[%s] does not match [%s]",
    3626             :                           name,
    3627             :                           nwrap_sp_global.list[i].sp_namp);
    3628             :         }
    3629             : 
    3630           0 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
    3631             : 
    3632           0 :         errno = ENOENT;
    3633           0 :         return NULL;
    3634             : }
    3635             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    3636             : 
    3637             : /* misc functions */
    3638       57294 : static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
    3639             :                                       const char *user,
    3640             :                                       gid_t group,
    3641             :                                       long int *start,
    3642             :                                       long int *size,
    3643             :                                       gid_t **groups,
    3644             :                                       long int limit,
    3645             :                                       int *errnop)
    3646             : {
    3647           0 :         struct group *grp;
    3648       57294 :         int i = 0;
    3649             : 
    3650           0 :         (void)errnop; /* unused */
    3651       57294 :         nwrap_files_setgrent(b);
    3652     1810544 :         while ((grp = nwrap_files_getgrent(b)) != NULL) {
    3653     1753250 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3654             :                           "Inspecting %s for group membership",
    3655             :                           grp->gr_name);
    3656             : 
    3657     1977094 :                 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
    3658      223844 :                         if (group != grp->gr_gid &&
    3659      220835 :                             (strcmp(user, grp->gr_mem[i]) == 0)) {
    3660       51492 :                                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3661             :                                           "%s is member of %s",
    3662             :                                           user,
    3663             :                                           grp->gr_name);
    3664             : 
    3665       51492 :                                 if (*start == *size) {
    3666           0 :                                         long int newsize;
    3667           0 :                                         gid_t *newgroups;
    3668             : 
    3669           0 :                                         newsize = 2 * (*size);
    3670           0 :                                         if (limit > 0 && newsize > limit) {
    3671           0 :                                                 newsize = MAX(limit, *size);
    3672             :                                         }
    3673           0 :                                         newgroups = (gid_t *) realloc((*groups),
    3674             :                                                         newsize * sizeof(**groups));
    3675           0 :                                         if (!newgroups) {
    3676           0 :                                                 errno = ENOMEM;
    3677           0 :                                                 return -1;
    3678             :                                         }
    3679           0 :                                         *groups = newgroups;
    3680           0 :                                         *size = newsize;
    3681             :                                 }
    3682       51492 :                                 (*groups)[*start] = grp->gr_gid;
    3683       51492 :                                 (*start)++;
    3684             :                         }
    3685             :                 }
    3686             :         }
    3687             : 
    3688       57294 :         nwrap_files_endgrent(b);
    3689       57294 :         return *start;
    3690             : }
    3691             : 
    3692             : /* group functions */
    3693        4361 : static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
    3694             :                                           const char *name)
    3695             : {
    3696           6 :         int i;
    3697           6 :         bool ok;
    3698             : 
    3699           6 :         (void) b; /* unused */
    3700             : 
    3701        4361 :         ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
    3702        4361 :         if (!ok) {
    3703           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
    3704           0 :                 return NULL;
    3705             :         }
    3706             : 
    3707      179633 :         for (i=0; i<nwrap_gr_global.num; i++) {
    3708      177571 :                 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
    3709        2299 :                         NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] found", name);
    3710        2299 :                         return &nwrap_gr_global.list[i];
    3711             :                 }
    3712      175272 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3713             :                           "group[%s] does not match [%s]",
    3714             :                           name,
    3715             :                           nwrap_gr_global.list[i].gr_name);
    3716             :         }
    3717             : 
    3718        2062 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] not found", name);
    3719             : 
    3720        2062 :         errno = ENOENT;
    3721        2062 :         return NULL;
    3722             : }
    3723             : 
    3724        1864 : static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
    3725             :                                   const char *name, struct group *grdst,
    3726             :                                   char *buf, size_t buflen, struct group **grdstp)
    3727             : {
    3728           6 :         struct group *gr;
    3729             : 
    3730        1864 :         gr = nwrap_files_getgrnam(b, name);
    3731        1864 :         if (!gr) {
    3732         994 :                 if (errno == 0) {
    3733           0 :                         return ENOENT;
    3734             :                 }
    3735         994 :                 return errno;
    3736             :         }
    3737             : 
    3738         870 :         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
    3739             : }
    3740             : 
    3741        7191 : static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
    3742             :                                           gid_t gid)
    3743             : {
    3744           0 :         int i;
    3745           0 :         bool ok;
    3746             : 
    3747           0 :         (void) b; /* unused */
    3748             : 
    3749        7191 :         ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
    3750        7191 :         if (!ok) {
    3751           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
    3752           0 :                 return NULL;
    3753             :         }
    3754             : 
    3755      212642 :         for (i=0; i<nwrap_gr_global.num; i++) {
    3756      210769 :                 if (nwrap_gr_global.list[i].gr_gid == gid) {
    3757        5318 :                         NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] found", gid);
    3758        5318 :                         return &nwrap_gr_global.list[i];
    3759             :                 }
    3760      205451 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3761             :                           "gid[%u] does not match [%u]",
    3762             :                           gid,
    3763             :                           nwrap_gr_global.list[i].gr_gid);
    3764             :         }
    3765             : 
    3766        1873 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] not found", gid);
    3767             : 
    3768        1873 :         errno = ENOENT;
    3769        1873 :         return NULL;
    3770             : }
    3771             : 
    3772        4142 : static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
    3773             :                                   gid_t gid, struct group *grdst,
    3774             :                                   char *buf, size_t buflen, struct group **grdstp)
    3775             : {
    3776           0 :         struct group *gr;
    3777             : 
    3778        4142 :         gr = nwrap_files_getgrgid(b, gid);
    3779        4142 :         if (!gr) {
    3780         709 :                 if (errno == 0) {
    3781           0 :                         return ENOENT;
    3782             :                 }
    3783         709 :                 return errno;
    3784             :         }
    3785             : 
    3786        3433 :         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
    3787             : }
    3788             : 
    3789             : /* group enum functions */
    3790       57320 : static void nwrap_files_setgrent(struct nwrap_backend *b)
    3791             : {
    3792           0 :         (void) b; /* unused */
    3793             : 
    3794       57320 :         nwrap_gr_global.idx = 0;
    3795       57320 : }
    3796             : 
    3797     1813532 : static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
    3798             : {
    3799           0 :         struct group *gr;
    3800             : 
    3801           0 :         (void) b; /* unused */
    3802             : 
    3803     1813532 :         if (nwrap_gr_global.idx == 0) {
    3804           0 :                 bool ok;
    3805             : 
    3806       57320 :                 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
    3807       57320 :                 if (!ok) {
    3808           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
    3809           0 :                         return NULL;
    3810             :                 }
    3811             :         }
    3812             : 
    3813     1813532 :         if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
    3814       58806 :                 errno = ENOENT;
    3815       58806 :                 return NULL;
    3816             :         }
    3817             : 
    3818     1754726 :         gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
    3819             : 
    3820     1754726 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3821             :                   "return group[%s] gid[%u]",
    3822             :                   gr->gr_name, gr->gr_gid);
    3823             : 
    3824     1754726 :         return gr;
    3825             : }
    3826             : 
    3827        1448 : static int nwrap_files_getgrent_r(struct nwrap_backend *b,
    3828             :                                   struct group *grdst, char *buf,
    3829             :                                   size_t buflen, struct group **grdstp)
    3830             : {
    3831           0 :         struct group *gr;
    3832             : 
    3833        1448 :         gr = nwrap_files_getgrent(b);
    3834        1448 :         if (!gr) {
    3835         716 :                 if (errno == 0) {
    3836           0 :                         return ENOENT;
    3837             :                 }
    3838         716 :                 return errno;
    3839             :         }
    3840             : 
    3841         732 :         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
    3842             : }
    3843             : 
    3844       57320 : static void nwrap_files_endgrent(struct nwrap_backend *b)
    3845             : {
    3846           0 :         (void) b; /* unused */
    3847             : 
    3848       57320 :         nwrap_gr_global.idx = 0;
    3849       57320 : }
    3850             : 
    3851             : /* hosts functions */
    3852           0 : static int nwrap_files_internal_gethostbyname(const char *name, int af,
    3853             :                                               struct hostent *result,
    3854             :                                               struct nwrap_vector *addr_list)
    3855             : {
    3856           0 :         struct nwrap_entlist *el;
    3857           0 :         struct hostent *he;
    3858           0 :         char *h_name_lower;
    3859           0 :         ENTRY e;
    3860           0 :         ENTRY *e_p;
    3861           0 :         char canon_name[DNS_NAME_MAX] = { 0 };
    3862           0 :         size_t name_len;
    3863           0 :         bool he_found = false;
    3864           0 :         bool ok;
    3865             : 
    3866             :         /*
    3867             :          * We need to make sure we have zeroed return pointer for consumers
    3868             :          * which don't check return values, e.g. OpenLDAP.
    3869             :          */
    3870           0 :         ZERO_STRUCTP(result);
    3871             : 
    3872           0 :         ok = nwrap_files_cache_reload(nwrap_he_global.cache);
    3873           0 :         if (!ok) {
    3874           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
    3875           0 :                 goto no_ent;
    3876             :         }
    3877             : 
    3878           0 :         name_len = strlen(name);
    3879           0 :         if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
    3880           0 :                 memcpy(canon_name, name, name_len - 1);
    3881           0 :                 canon_name[name_len] = '\0';
    3882           0 :                 name = canon_name;
    3883             :         }
    3884             : 
    3885           0 :         if (!str_tolower_copy(&h_name_lower, name)) {
    3886           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    3887             :                           "Out of memory while converting to lower case");
    3888           0 :                 goto no_ent;
    3889             :         }
    3890             : 
    3891             :         /* Look at hash table for element */
    3892           0 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
    3893           0 :         e.key = h_name_lower;
    3894           0 :         e.data = NULL;
    3895           0 :         e_p = hsearch(e, FIND);
    3896           0 :         if (e_p == NULL) {
    3897           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
    3898           0 :                 SAFE_FREE(h_name_lower);
    3899           0 :                 goto no_ent;
    3900             :         }
    3901           0 :         SAFE_FREE(h_name_lower);
    3902             : 
    3903             :         /* Always cleanup vector and results */
    3904           0 :         if (!nwrap_vector_is_initialized(addr_list)) {
    3905           0 :                 if (!nwrap_vector_init(addr_list)) {
    3906           0 :                         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3907             :                                   "Unable to initialize memory for addr_list vector");
    3908           0 :                         goto no_ent;
    3909             :                 }
    3910             :         } else {
    3911             :                 /* When vector is initialized data are valid no more.
    3912             :                  * Quick way how to free vector is: */
    3913           0 :                 addr_list->count = 0;
    3914             :         }
    3915             : 
    3916             :         /* Iterate through results */
    3917           0 :         for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
    3918             :         {
    3919           0 :                 he = &(el->ed->ht);
    3920             : 
    3921             :                 /* Filter by address familiy if provided */
    3922           0 :                 if (af != AF_UNSPEC && he->h_addrtype != af) {
    3923           0 :                         continue;
    3924             :                 }
    3925             : 
    3926             :                 /*
    3927             :                  * GLIBC HACK?
    3928             :                  * glibc doesn't return ipv6 addresses when AF_UNSPEC is used
    3929             :                  */
    3930           0 :                 if (af == AF_UNSPEC && he->h_addrtype != AF_INET) {
    3931           0 :                         continue;
    3932             :                 }
    3933             : 
    3934           0 :                 if (!he_found) {
    3935           0 :                         memcpy(result, he, sizeof(struct hostent));
    3936           0 :                         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3937             :                                   "Name found. Returning record for %s",
    3938             :                                   he->h_name);
    3939           0 :                         he_found = true;
    3940             :                 }
    3941           0 :                 nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata);
    3942           0 :                 result->h_addr_list = nwrap_vector_head(addr_list);
    3943             :         }
    3944             : 
    3945           0 :         if (he_found) {
    3946           0 :                 return 0;
    3947             :         }
    3948           0 :         NWRAP_LOG(NWRAP_LOG_DEBUG,
    3949             :                   "Name found in database. No records matches type.");
    3950             : 
    3951           0 : no_ent:
    3952           0 :         errno = ENOENT;
    3953           0 :         return -1;
    3954             : }
    3955             : 
    3956           0 : static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
    3957             :                                         const char *name, int af,
    3958             :                                         struct hostent *hedst,
    3959             :                                         char *buf, size_t buflen,
    3960             :                                         struct hostent **hedstp)
    3961             : {
    3962           0 :         struct nwrap_vector *addr_list = NULL;
    3963           0 :         union {
    3964             :                 char *ptr;
    3965             :                 char **list;
    3966             :         } g;
    3967           0 :         int rc;
    3968             : 
    3969           0 :         (void) b; /* unused */
    3970           0 :         (void) af; /* unused */
    3971             : 
    3972           0 :         if (name == NULL || hedst == NULL || buf == NULL || buflen == 0) {
    3973           0 :                 errno = EINVAL;
    3974           0 :                 return -1;
    3975             :         }
    3976           0 :         *hedstp = NULL;
    3977           0 :         buf[0] = '\0';
    3978             : 
    3979           0 :         addr_list = calloc(1, sizeof(struct nwrap_vector));
    3980           0 :         if (addr_list == NULL) {
    3981           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR,
    3982             :                           "Unable to allocate memory for address list");
    3983           0 :                 errno = ENOENT;
    3984           0 :                 return -1;
    3985             :         }
    3986             : 
    3987           0 :         rc = nwrap_files_internal_gethostbyname(name, af, hedst,
    3988             :                                                 addr_list);
    3989           0 :         if (rc == -1) {
    3990           0 :                 SAFE_FREE(addr_list->items);
    3991           0 :                 SAFE_FREE(addr_list);
    3992           0 :                 errno = ENOENT;
    3993           0 :                 return -1;
    3994             :         }
    3995             : 
    3996             :         /* +1 i for ending NULL pointer */
    3997           0 :         if (buflen < ((addr_list->count + 1) * sizeof(void *))) {
    3998           0 :                 SAFE_FREE(addr_list->items);
    3999           0 :                 SAFE_FREE(addr_list);
    4000           0 :                 return ERANGE;
    4001             :         }
    4002             : 
    4003             :         /* Copy all to user provided buffer and change
    4004             :          * pointers in returned structure.
    4005             :          * +1 is for ending NULL pointer. */
    4006           0 :         memcpy(buf, addr_list->items, (addr_list->count + 1) * sizeof(void *));
    4007             : 
    4008           0 :         SAFE_FREE(addr_list->items);
    4009           0 :         SAFE_FREE(addr_list);
    4010             : 
    4011           0 :         g.ptr = buf;
    4012           0 :         hedst->h_addr_list = g.list;
    4013           0 :         *hedstp = hedst;
    4014           0 :         return 0;
    4015             : }
    4016             : 
    4017             : #ifdef HAVE_GETHOSTBYNAME_R
    4018           0 : static int nwrap_gethostbyname_r(const char *name,
    4019             :                                  struct hostent *ret,
    4020             :                                  char *buf, size_t buflen,
    4021             :                                  struct hostent **result, int *h_errnop)
    4022             : {
    4023           0 :         int rc;
    4024           0 :         size_t i;
    4025             : 
    4026           0 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    4027           0 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    4028           0 :                 rc = b->ops->nw_gethostbyname2_r(b, name, AF_UNSPEC, ret,
    4029             :                                                  buf, buflen, result);
    4030           0 :                 if (rc == 0) {
    4031           0 :                         return 0;
    4032           0 :                 } else if (rc == ERANGE) {
    4033           0 :                         return ERANGE;
    4034             :                 }
    4035             :         }
    4036           0 :         *h_errnop = h_errno;
    4037           0 :         return ENOENT;
    4038             : }
    4039             : 
    4040             : int gethostbyname_r(const char *name,
    4041             :                     struct hostent *ret,
    4042             :                     char *buf, size_t buflen,
    4043             :                     struct hostent **result, int *h_errnop)
    4044             : {
    4045           0 :         if (!nss_wrapper_hosts_enabled()) {
    4046           0 :                 return libc_gethostbyname_r(name,
    4047             :                                             ret,
    4048             :                                             buf,
    4049             :                                             buflen,
    4050             :                                             result,
    4051             :                                             h_errnop);
    4052             :         }
    4053             : 
    4054           0 :         return nwrap_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
    4055             : }
    4056             : #endif
    4057             : 
    4058             : #ifdef HAVE_GETHOSTBYNAME2_R
    4059           0 : static int nwrap_gethostbyname2_r(const char *name, int af,
    4060             :                                  struct hostent *ret,
    4061             :                                  char *buf, size_t buflen,
    4062             :                                  struct hostent **result, int *h_errnop)
    4063             : {
    4064           0 :         int rc;
    4065           0 :         size_t i;
    4066             : 
    4067           0 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    4068           0 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    4069           0 :                 rc = b->ops->nw_gethostbyname2_r(b, name, af, ret,
    4070             :                                                  buf, buflen, result);
    4071           0 :                 if (rc == 0) {
    4072           0 :                         return 0;
    4073           0 :                 } else if (rc == ERANGE) {
    4074           0 :                         return ERANGE;
    4075             :                 }
    4076             :         }
    4077           0 :         *h_errnop = h_errno;
    4078           0 :         return ENOENT;
    4079             : }
    4080             : 
    4081             : int gethostbyname2_r(const char *name, int af,
    4082             :                      struct hostent *ret,
    4083             :                      char *buf, size_t buflen,
    4084             :                      struct hostent **result, int *h_errnop)
    4085             : {
    4086           0 :         if (!nss_wrapper_hosts_enabled()) {
    4087           0 :                 return libc_gethostbyname2_r(name, af, ret, buf, buflen,
    4088             :                                              result, h_errnop);
    4089             :         }
    4090             : 
    4091           0 :         return nwrap_gethostbyname2_r(name, af, ret, buf, buflen, result,
    4092             :                                       h_errnop);
    4093             : }
    4094             : #endif
    4095             : 
    4096     1421673 : static int nwrap_files_getaddrinfo(const char *name,
    4097             :                                    unsigned short port,
    4098             :                                    const struct addrinfo *hints,
    4099             :                                    struct addrinfo **ai)
    4100             : {
    4101       24169 :         struct nwrap_entlist *el;
    4102       24169 :         struct hostent *he;
    4103     1421673 :         struct addrinfo *ai_head = NULL;
    4104     1421673 :         struct addrinfo *ai_cur = NULL;
    4105       24169 :         char *h_name_lower;
    4106       24169 :         size_t name_len;
    4107     1421673 :         char canon_name[DNS_NAME_MAX] = { 0 };
    4108     1421673 :         bool skip_canonname = false;
    4109     1421673 :         ENTRY e = {
    4110             :                 .key = NULL,
    4111             :         };
    4112     1421673 :         ENTRY *e_p = NULL;
    4113       24169 :         int rc;
    4114       24169 :         bool ok;
    4115             : 
    4116     1421673 :         ok = nwrap_files_cache_reload(nwrap_he_global.cache);
    4117     1421673 :         if (!ok) {
    4118           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
    4119           0 :                 return EAI_SYSTEM;
    4120             :         }
    4121             : 
    4122     1421673 :         name_len = strlen(name);
    4123     1421673 :         if (name_len == 0) {
    4124           4 :                 return EAI_NONAME;
    4125             :         }
    4126             : 
    4127     1421669 :         if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
    4128          74 :                 memcpy(canon_name, name, name_len - 1);
    4129          74 :                 canon_name[name_len] = '\0';
    4130          74 :                 name = canon_name;
    4131             :         }
    4132             : 
    4133     1421669 :         if (!str_tolower_copy(&h_name_lower, name)) {
    4134           0 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    4135             :                           "Out of memory while converting to lower case");
    4136           0 :                 return EAI_MEMORY;
    4137             :         }
    4138             : 
    4139     1421669 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
    4140     1421669 :         e.key = h_name_lower;
    4141     1421669 :         e.data = NULL;
    4142     1421669 :         e_p = hsearch(e, FIND);
    4143     1421669 :         if (e_p == NULL) {
    4144     1069879 :                 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
    4145     1069879 :                 SAFE_FREE(h_name_lower);
    4146     1069879 :                 errno = ENOENT;
    4147     1069879 :                 return EAI_NONAME;
    4148             :         }
    4149      351790 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
    4150      351790 :         SAFE_FREE(h_name_lower);
    4151             : 
    4152      351790 :         rc = EAI_NONAME;
    4153      752923 :         for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
    4154             :         {
    4155        4611 :                 int rc2;
    4156      401133 :                 struct addrinfo *ai_new = NULL;
    4157             : 
    4158      401133 :                 he = &(el->ed->ht);
    4159             : 
    4160      401133 :                 if (hints->ai_family != AF_UNSPEC &&
    4161         756 :                     he->h_addrtype != hints->ai_family)
    4162             :                 {
    4163          27 :                         NWRAP_LOG(NWRAP_LOG_DEBUG,
    4164             :                                   "Entry found but with wrong AF - "
    4165             :                                   "remembering EAI_ADDRINFO.");
    4166          27 :                         rc = EAI_ADDRFAMILY;
    4167          27 :                         continue;
    4168             :                 }
    4169             : 
    4170             :                 /* Function allocates memory and returns it in ai. */
    4171      401106 :                 rc2 = nwrap_convert_he_ai(he,
    4172             :                                          port,
    4173             :                                          hints,
    4174             :                                          &ai_new,
    4175             :                                          skip_canonname);
    4176      401106 :                 if (rc2 != 0) {
    4177           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
    4178           0 :                         if (ai_head != NULL) {
    4179           0 :                                 freeaddrinfo(ai_head);
    4180             :                         }
    4181           0 :                         return rc2;
    4182             :                 }
    4183      401106 :                 skip_canonname = true;
    4184             : 
    4185      401106 :                 if (ai_head == NULL) {
    4186      351790 :                         ai_head = ai_new;
    4187             :                 }
    4188      401106 :                 if (ai_cur != NULL) {
    4189       49316 :                         ai_cur->ai_next = ai_new;
    4190             :                 }
    4191      401106 :                 ai_cur = ai_new;
    4192             :         }
    4193             : 
    4194      351790 :         if (ai_head != NULL) {
    4195      351790 :                 rc = 0;
    4196             :         }
    4197             : 
    4198      351790 :         *ai = ai_head;
    4199             : 
    4200      351790 :         return rc;
    4201             : }
    4202             : 
    4203         107 : static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
    4204             :                                                  const void *addr,
    4205             :                                                  socklen_t len, int type)
    4206             : {
    4207           0 :         struct hostent *he;
    4208         107 :         char ip[NWRAP_INET_ADDRSTRLEN] = {0};
    4209           0 :         struct nwrap_entdata *ed;
    4210           0 :         const char *a;
    4211           0 :         size_t i;
    4212           0 :         bool ok;
    4213             : 
    4214           0 :         (void) b; /* unused */
    4215           0 :         (void) len; /* unused */
    4216             : 
    4217         107 :         ok = nwrap_files_cache_reload(nwrap_he_global.cache);
    4218         107 :         if (!ok) {
    4219           0 :                 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
    4220           0 :                 return NULL;
    4221             :         }
    4222             : 
    4223         107 :         a = inet_ntop(type, addr, ip, sizeof(ip));
    4224         107 :         if (a == NULL) {
    4225           0 :                 errno = EINVAL;
    4226           0 :                 return NULL;
    4227             :         }
    4228             : 
    4229         499 :         nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
    4230             :         {
    4231         499 :                 he = &(ed->ht);
    4232         499 :                 if (he->h_addrtype != type) {
    4233         196 :                         continue;
    4234             :                 }
    4235             : 
    4236         303 :                 if (memcmp(addr, he->h_addr_list[0], he->h_length) == 0) {
    4237         107 :                         return he;
    4238             :                 }
    4239             :         }
    4240             : 
    4241           0 :         errno = ENOENT;
    4242           0 :         return NULL;
    4243             : }
    4244             : 
    4245             : #ifdef HAVE_GETHOSTBYADDR_R
    4246           9 : static int nwrap_gethostbyaddr_r(const void *addr, socklen_t len, int type,
    4247             :                                  struct hostent *ret,
    4248             :                                  char *buf, size_t buflen,
    4249             :                                  struct hostent **result, int *h_errnop)
    4250             : {
    4251           0 :         size_t i;
    4252           9 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    4253           9 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    4254           9 :                 *result = b->ops->nw_gethostbyaddr(b, addr, len, type);
    4255           9 :                 if (*result != NULL) {
    4256           9 :                         break;
    4257             :                 }
    4258             :         }
    4259             : 
    4260           9 :         if (*result != NULL) {
    4261           9 :                 memset(buf, '\0', buflen);
    4262           9 :                 *ret = **result;
    4263           9 :                 return 0;
    4264             :         }
    4265             : 
    4266           0 :         *h_errnop = h_errno;
    4267           0 :         return -1;
    4268             : }
    4269             : 
    4270             : int gethostbyaddr_r(const void *addr, socklen_t len, int type,
    4271             :                     struct hostent *ret,
    4272             :                     char *buf, size_t buflen,
    4273             :                     struct hostent **result, int *h_errnop)
    4274             : {
    4275           9 :         if (!nss_wrapper_hosts_enabled()) {
    4276           0 :                 return libc_gethostbyaddr_r(addr,
    4277             :                                             len,
    4278             :                                             type,
    4279             :                                             ret,
    4280             :                                             buf,
    4281             :                                             buflen,
    4282             :                                             result,
    4283             :                                             h_errnop);
    4284             :         }
    4285             : 
    4286           9 :         return nwrap_gethostbyaddr_r(addr, len, type, ret, buf, buflen, result, h_errnop);
    4287             : }
    4288             : #endif
    4289             : 
    4290             : /* hosts enum functions */
    4291           0 : static void nwrap_files_sethostent(void)
    4292             : {
    4293           0 :         nwrap_he_global.idx = 0;
    4294           0 : }
    4295             : 
    4296           0 : static struct hostent *nwrap_files_gethostent(void)
    4297             : {
    4298           0 :         struct hostent *he;
    4299             : 
    4300           0 :         if (nwrap_he_global.idx == 0) {
    4301           0 :                 bool ok;
    4302             : 
    4303           0 :                 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
    4304           0 :                 if (!ok) {
    4305           0 :                         NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file");
    4306           0 :                         return NULL;
    4307             :                 }
    4308             :         }
    4309             : 
    4310           0 :         if (nwrap_he_global.idx >= nwrap_he_global.num) {
    4311           0 :                 errno = ENOENT;
    4312           0 :                 return NULL;
    4313             :         }
    4314             : 
    4315           0 :         he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
    4316             : 
    4317           0 :         NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
    4318             : 
    4319           0 :         return he;
    4320             : }
    4321             : 
    4322           0 : static void nwrap_files_endhostent(void)
    4323             : {
    4324           0 :         nwrap_he_global.idx = 0;
    4325           0 : }
    4326             : 
    4327             : /*
    4328             :  * module backend
    4329             :  */
    4330             : 
    4331             : 
    4332       16117 : static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
    4333             :                                             const char *name)
    4334             : {
    4335         758 :         static struct passwd pwd;
    4336         758 :         static char buf[1000];
    4337         758 :         NSS_STATUS status;
    4338             : 
    4339       16117 :         if (b->symbols->_nss_getpwnam_r.f == NULL) {
    4340           0 :                 return NULL;
    4341             :         }
    4342             : 
    4343       16117 :         status = b->symbols->_nss_getpwnam_r.f(name,
    4344             :                                                &pwd,
    4345             :                                                buf,
    4346             :                                                sizeof(buf),
    4347             :                                                &errno);
    4348       16117 :         if (status == NSS_STATUS_NOTFOUND) {
    4349        3577 :                 return NULL;
    4350             :         }
    4351       12524 :         if (status != NSS_STATUS_SUCCESS) {
    4352          21 :                 return NULL;
    4353             :         }
    4354             : 
    4355       11761 :         return &pwd;
    4356             : }
    4357             : 
    4358       45355 : static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
    4359             :                                    const char *name, struct passwd *pwdst,
    4360             :                                    char *buf, size_t buflen, struct passwd **pwdstp)
    4361             : {
    4362           0 :         int ret;
    4363             : 
    4364       45355 :         *pwdstp = NULL;
    4365             : 
    4366       45355 :         if (b->symbols->_nss_getpwnam_r.f == NULL) {
    4367           0 :                 return NSS_STATUS_NOTFOUND;
    4368             :         }
    4369             : 
    4370       45355 :         ret = b->symbols->_nss_getpwnam_r.f(name, pwdst, buf, buflen, &errno);
    4371       45355 :         switch (ret) {
    4372       45355 :         case NSS_STATUS_SUCCESS:
    4373       45355 :                 *pwdstp = pwdst;
    4374       45355 :                 return 0;
    4375           0 :         case NSS_STATUS_NOTFOUND:
    4376           0 :                 if (errno != 0) {
    4377           0 :                         return errno;
    4378             :                 }
    4379           0 :                 return ENOENT;
    4380           0 :         case NSS_STATUS_TRYAGAIN:
    4381           0 :                 if (errno != 0) {
    4382           0 :                         return errno;
    4383             :                 }
    4384           0 :                 return ERANGE;
    4385           0 :         default:
    4386           0 :                 if (errno != 0) {
    4387           0 :                         return errno;
    4388             :                 }
    4389           0 :                 return ret;
    4390             :         }
    4391             : }
    4392             : 
    4393        5281 : static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
    4394             :                                             uid_t uid)
    4395             : {
    4396           0 :         static struct passwd pwd;
    4397           0 :         static char buf[1000];
    4398           0 :         NSS_STATUS status;
    4399             : 
    4400        5281 :         if (b->symbols->_nss_getpwuid_r.f == NULL) {
    4401           0 :                 return NULL;
    4402             :         }
    4403             : 
    4404        5281 :         status = b->symbols->_nss_getpwuid_r.f(uid,
    4405             :                                                &pwd,
    4406             :                                                buf,
    4407             :                                                sizeof(buf),
    4408             :                                                &errno);
    4409        5281 :         if (status == NSS_STATUS_NOTFOUND) {
    4410        3355 :                 return NULL;
    4411             :         }
    4412        1926 :         if (status != NSS_STATUS_SUCCESS) {
    4413          82 :                 return NULL;
    4414             :         }
    4415        1844 :         return &pwd;
    4416             : }
    4417             : 
    4418         701 : static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
    4419             :                                    uid_t uid, struct passwd *pwdst,
    4420             :                                    char *buf, size_t buflen, struct passwd **pwdstp)
    4421             : {
    4422           0 :         int ret;
    4423             : 
    4424         701 :         *pwdstp = NULL;
    4425             : 
    4426         701 :         if (b->symbols->_nss_getpwuid_r.f == NULL) {
    4427           0 :                 return ENOENT;
    4428             :         }
    4429             : 
    4430         701 :         ret = b->symbols->_nss_getpwuid_r.f(uid, pwdst, buf, buflen, &errno);
    4431         701 :         switch (ret) {
    4432         696 :         case NSS_STATUS_SUCCESS:
    4433         696 :                 *pwdstp = pwdst;
    4434         696 :                 return 0;
    4435           0 :         case NSS_STATUS_NOTFOUND:
    4436           0 :                 if (errno != 0) {
    4437           0 :                         return errno;
    4438             :                 }
    4439           0 :                 return ENOENT;
    4440           0 :         case NSS_STATUS_TRYAGAIN:
    4441           0 :                 if (errno != 0) {
    4442           0 :                         return errno;
    4443             :                 }
    4444           0 :                 return ERANGE;
    4445           5 :         default:
    4446           5 :                 if (errno != 0) {
    4447           5 :                         return errno;
    4448             :                 }
    4449           0 :                 return ret;
    4450             :         }
    4451             : }
    4452             : 
    4453         365 : static void nwrap_module_setpwent(struct nwrap_backend *b)
    4454             : {
    4455         365 :         if (b->symbols->_nss_setpwent.f == NULL) {
    4456           0 :                 return;
    4457             :         }
    4458             : 
    4459         365 :         b->symbols->_nss_setpwent.f();
    4460             : }
    4461             : 
    4462        1089 : static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
    4463             : {
    4464           0 :         static struct passwd pwd;
    4465           0 :         static char buf[1000];
    4466           0 :         NSS_STATUS status;
    4467             : 
    4468        1089 :         if (b->symbols->_nss_getpwent_r.f == NULL) {
    4469           0 :                 return NULL;
    4470             :         }
    4471             : 
    4472        1089 :         status = b->symbols->_nss_getpwent_r.f(&pwd, buf, sizeof(buf), &errno);
    4473        1089 :         if (status == NSS_STATUS_NOTFOUND) {
    4474         340 :                 return NULL;
    4475             :         }
    4476         749 :         if (status != NSS_STATUS_SUCCESS) {
    4477           9 :                 return NULL;
    4478             :         }
    4479         740 :         return &pwd;
    4480             : }
    4481             : 
    4482         756 : static int nwrap_module_getpwent_r(struct nwrap_backend *b,
    4483             :                                    struct passwd *pwdst, char *buf,
    4484             :                                    size_t buflen, struct passwd **pwdstp)
    4485             : {
    4486           0 :         int ret;
    4487             : 
    4488         756 :         *pwdstp = NULL;
    4489             : 
    4490         756 :         if (b->symbols->_nss_getpwent_r.f == NULL) {
    4491           0 :                 return ENOENT;
    4492             :         }
    4493             : 
    4494         756 :         ret = b->symbols->_nss_getpwent_r.f(pwdst, buf, buflen, &errno);
    4495         756 :         switch (ret) {
    4496         740 :         case NSS_STATUS_SUCCESS:
    4497         740 :                 *pwdstp = pwdst;
    4498         740 :                 return 0;
    4499          16 :         case NSS_STATUS_NOTFOUND:
    4500          16 :                 if (errno != 0) {
    4501          16 :                         return errno;
    4502             :                 }
    4503           0 :                 return ENOENT;
    4504           0 :         case NSS_STATUS_TRYAGAIN:
    4505           0 :                 if (errno != 0) {
    4506           0 :                         return errno;
    4507             :                 }
    4508           0 :                 return ERANGE;
    4509           0 :         default:
    4510           0 :                 if (errno != 0) {
    4511           0 :                         return errno;
    4512             :                 }
    4513           0 :                 return ret;
    4514             :         }
    4515             : }
    4516             : 
    4517       12532 : static void nwrap_module_endpwent(struct nwrap_backend *b)
    4518             : {
    4519       12532 :         if (b->symbols->_nss_endpwent.f == NULL) {
    4520           0 :                 return;
    4521             :         }
    4522             : 
    4523       12532 :         b->symbols->_nss_endpwent.f();
    4524             : }
    4525             : 
    4526       57212 : static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
    4527             :                                        const char *user,
    4528             :                                        gid_t group,
    4529             :                                        long int *start,
    4530             :                                        long int *size,
    4531             :                                        gid_t **groups,
    4532             :                                        long int limit,
    4533             :                                        int *errnop)
    4534             : {
    4535       57212 :         if (b->symbols->_nss_initgroups_dyn.f == NULL) {
    4536           0 :                 return NSS_STATUS_UNAVAIL;
    4537             :         }
    4538             : 
    4539       57212 :         return b->symbols->_nss_initgroups_dyn.f(user,
    4540             :                                              group,
    4541             :                                              start,
    4542             :                                              size,
    4543             :                                              groups,
    4544             :                                              limit,
    4545             :                                              errnop);
    4546             : }
    4547             : 
    4548        1068 : static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
    4549             :                                            const char *name)
    4550             : {
    4551           0 :         static struct group grp;
    4552           0 :         static char *buf;
    4553           0 :         static int buflen = 1000;
    4554           0 :         NSS_STATUS status;
    4555             : 
    4556        1068 :         if (b->symbols->_nss_getgrnam_r.f == NULL) {
    4557           0 :                 return NULL;
    4558             :         }
    4559             : 
    4560        1068 :         if (!buf) {
    4561         344 :                 buf = (char *)malloc(buflen);
    4562             :         }
    4563        1068 : again:
    4564        1068 :         status = b->symbols->_nss_getgrnam_r.f(name, &grp, buf, buflen, &errno);
    4565        1068 :         if (status == NSS_STATUS_TRYAGAIN) {
    4566           0 :                 buflen *= 2;
    4567           0 :                 buf = (char *)realloc(buf, buflen);
    4568           0 :                 if (!buf) {
    4569           0 :                         return NULL;
    4570             :                 }
    4571           0 :                 goto again;
    4572             :         }
    4573        1068 :         if (status == NSS_STATUS_NOTFOUND) {
    4574         320 :                 SAFE_FREE(buf);
    4575         320 :                 return NULL;
    4576             :         }
    4577         748 :         if (status != NSS_STATUS_SUCCESS) {
    4578           0 :                 SAFE_FREE(buf);
    4579           0 :                 return NULL;
    4580             :         }
    4581         748 :         return &grp;
    4582             : }
    4583             : 
    4584         886 : static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
    4585             :                                    const char *name, struct group *grdst,
    4586             :                                    char *buf, size_t buflen, struct group **grdstp)
    4587             : {
    4588           0 :         int ret;
    4589             : 
    4590         886 :         *grdstp = NULL;
    4591             : 
    4592         886 :         if (b->symbols->_nss_getgrnam_r.f == NULL) {
    4593           0 :                 return ENOENT;
    4594             :         }
    4595             : 
    4596         886 :         ret = b->symbols->_nss_getgrnam_r.f(name, grdst, buf, buflen, &errno);
    4597         886 :         switch (ret) {
    4598         704 :         case NSS_STATUS_SUCCESS:
    4599         704 :                 *grdstp = grdst;
    4600         704 :                 return 0;
    4601         182 :         case NSS_STATUS_NOTFOUND:
    4602         182 :                 if (errno != 0) {
    4603         182 :                         return errno;
    4604             :                 }
    4605           0 :                 return ENOENT;
    4606           0 :         case NSS_STATUS_TRYAGAIN:
    4607           0 :                 if (errno != 0) {
    4608           0 :                         return errno;
    4609             :                 }
    4610           0 :                 return ERANGE;
    4611           0 :         default:
    4612           0 :                 if (errno != 0) {
    4613           0 :                         return errno;
    4614             :                 }
    4615           0 :                 return ret;
    4616             :         }
    4617             : }
    4618             : 
    4619        1164 : static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
    4620             :                                            gid_t gid)
    4621             : {
    4622           0 :         static struct group grp;
    4623           0 :         static char *buf;
    4624           0 :         static int buflen = 1000;
    4625           0 :         NSS_STATUS status;
    4626             : 
    4627        1164 :         if (b->symbols->_nss_getgrgid_r.f == NULL) {
    4628           0 :                 return NULL;
    4629             :         }
    4630             : 
    4631        1164 :         if (!buf) {
    4632          58 :                 buf = (char *)malloc(buflen);
    4633             :         }
    4634             : 
    4635        1164 : again:
    4636        1164 :         status = b->symbols->_nss_getgrgid_r.f(gid, &grp, buf, buflen, &errno);
    4637        1164 :         if (status == NSS_STATUS_TRYAGAIN) {
    4638           0 :                 buflen *= 2;
    4639           0 :                 buf = (char *)realloc(buf, buflen);
    4640           0 :                 if (!buf) {
    4641           0 :                         return NULL;
    4642             :                 }
    4643           0 :                 goto again;
    4644             :         }
    4645        1164 :         if (status == NSS_STATUS_NOTFOUND) {
    4646          10 :                 SAFE_FREE(buf);
    4647          10 :                 return NULL;
    4648             :         }
    4649        1154 :         if (status != NSS_STATUS_SUCCESS) {
    4650           0 :                 SAFE_FREE(buf);
    4651           0 :                 return NULL;
    4652             :         }
    4653        1154 :         return &grp;
    4654             : }
    4655             : 
    4656         709 : static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
    4657             :                                    gid_t gid, struct group *grdst,
    4658             :                                    char *buf, size_t buflen, struct group **grdstp)
    4659             : {
    4660           0 :         int ret;
    4661             : 
    4662         709 :         *grdstp = NULL;
    4663             : 
    4664         709 :         if (b->symbols->_nss_getgrgid_r.f == NULL) {
    4665           0 :                 return ENOENT;
    4666             :         }
    4667             : 
    4668         709 :         ret = b->symbols->_nss_getgrgid_r.f(gid, grdst, buf, buflen, &errno);
    4669         709 :         switch (ret) {
    4670         704 :         case NSS_STATUS_SUCCESS:
    4671         704 :                 *grdstp = grdst;
    4672         704 :                 return 0;
    4673           0 :         case NSS_STATUS_NOTFOUND:
    4674           0 :                 if (errno != 0) {
    4675           0 :                         return errno;
    4676             :                 }
    4677           0 :                 return ENOENT;
    4678           0 :         case NSS_STATUS_TRYAGAIN:
    4679           0 :                 if (errno != 0) {
    4680           0 :                         return errno;
    4681             :                 }
    4682           0 :                 return ERANGE;
    4683           5 :         default:
    4684           5 :                 if (errno != 0) {
    4685           5 :                         return errno;
    4686             :                 }
    4687           0 :                 return ret;
    4688             :         }
    4689             : }
    4690             : 
    4691          26 : static void nwrap_module_setgrent(struct nwrap_backend *b)
    4692             : {
    4693          26 :         if (b->symbols->_nss_setgrent.f == NULL) {
    4694           0 :                 return;
    4695             :         }
    4696             : 
    4697          26 :         b->symbols->_nss_setgrent.f();
    4698             : }
    4699             : 
    4700         796 : static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
    4701             : {
    4702           0 :         static struct group grp;
    4703           0 :         static char *buf;
    4704           0 :         static int buflen = 1024;
    4705           0 :         NSS_STATUS status;
    4706             : 
    4707         796 :         if (b->symbols->_nss_getgrent_r.f == NULL) {
    4708           0 :                 return NULL;
    4709             :         }
    4710             : 
    4711         796 :         if (!buf) {
    4712          14 :                 buf = (char *)malloc(buflen);
    4713             :         }
    4714             : 
    4715         796 : again:
    4716         796 :         status = b->symbols->_nss_getgrent_r.f(&grp, buf, buflen, &errno);
    4717         796 :         if (status == NSS_STATUS_TRYAGAIN) {
    4718           0 :                 buflen *= 2;
    4719           0 :                 buf = (char *)realloc(buf, buflen);
    4720           0 :                 if (!buf) {
    4721           0 :                         return NULL;
    4722             :                 }
    4723           0 :                 goto again;
    4724             :         }
    4725         796 :         if (status == NSS_STATUS_NOTFOUND) {
    4726          14 :                 SAFE_FREE(buf);
    4727          14 :                 return NULL;
    4728             :         }
    4729         782 :         if (status != NSS_STATUS_SUCCESS) {
    4730           0 :                 SAFE_FREE(buf);
    4731           0 :                 return NULL;
    4732             :         }
    4733         782 :         return &grp;
    4734             : }
    4735             : 
    4736         716 : static int nwrap_module_getgrent_r(struct nwrap_backend *b,
    4737             :                                    struct group *grdst, char *buf,
    4738             :                                    size_t buflen, struct group **grdstp)
    4739             : {
    4740           0 :         int ret;
    4741             : 
    4742         716 :         *grdstp = NULL;
    4743             : 
    4744         716 :         if (b->symbols->_nss_getgrent_r.f == NULL) {
    4745           0 :                 return ENOENT;
    4746             :         }
    4747             : 
    4748         716 :         ret = b->symbols->_nss_getgrent_r.f(grdst, buf, buflen, &errno);
    4749         716 :         switch (ret) {
    4750         704 :         case NSS_STATUS_SUCCESS:
    4751         704 :                 *grdstp = grdst;
    4752         704 :                 return 0;
    4753          12 :         case NSS_STATUS_NOTFOUND:
    4754          12 :                 if (errno != 0) {
    4755          12 :                         return errno;
    4756             :                 }
    4757           0 :                 return ENOENT;
    4758           0 :         case NSS_STATUS_TRYAGAIN:
    4759           0 :                 if (errno != 0) {
    4760           0 :                         return errno;
    4761             :                 }
    4762           0 :                 return ERANGE;
    4763           0 :         default:
    4764           0 :                 if (errno != 0) {
    4765           0 :                         return errno;
    4766             :                 }
    4767           0 :                 return ret;
    4768             :         }
    4769             : }
    4770             : 
    4771          26 : static void nwrap_module_endgrent(struct nwrap_backend *b)
    4772             : {
    4773          26 :         if (b->symbols->_nss_endgrent.f == NULL) {
    4774           0 :                 return;
    4775             :         }
    4776             : 
    4777          26 :         b->symbols->_nss_endgrent.f();
    4778             : }
    4779             : 
    4780           0 : static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
    4781             :                                                   const void *addr,
    4782             :                                                   socklen_t len, int type)
    4783             : {
    4784           0 :         static struct hostent he;
    4785           0 :         static char *buf = NULL;
    4786           0 :         static size_t buflen = 1000;
    4787           0 :         NSS_STATUS status;
    4788             : 
    4789           0 :         if (b->symbols->_nss_gethostbyaddr_r.f == NULL) {
    4790           0 :                 return NULL;
    4791             :         }
    4792             : 
    4793           0 :         if (buf == NULL) {
    4794           0 :                 buf = (char *)malloc(buflen);
    4795           0 :                 if (buf == NULL) {
    4796           0 :                         return NULL;
    4797             :                 }
    4798             :         }
    4799           0 : again:
    4800           0 :         status = b->symbols->_nss_gethostbyaddr_r.f(addr,
    4801             :                                                     len,
    4802             :                                                     type,
    4803             :                                                     &he,
    4804             :                                                     buf,
    4805             :                                                     buflen,
    4806             :                                                     &errno,
    4807             :                                                     &h_errno);
    4808           0 :         if (status == NSS_STATUS_TRYAGAIN) {
    4809           0 :                 char *p = NULL;
    4810             : 
    4811           0 :                 buflen *= 2;
    4812           0 :                 p = (char *)realloc(buf, buflen);
    4813           0 :                 if (p == NULL) {
    4814           0 :                         SAFE_FREE(buf);
    4815           0 :                         return NULL;
    4816             :                 }
    4817           0 :                 buf = p;
    4818           0 :                 goto again;
    4819             :         }
    4820           0 :         if (status == NSS_STATUS_NOTFOUND) {
    4821           0 :                 SAFE_FREE(buf);
    4822           0 :                 return NULL;
    4823             :         }
    4824           0 :         if (status != NSS_STATUS_SUCCESS) {
    4825           0 :                 SAFE_FREE(buf);
    4826           0 :                 return NULL;
    4827             :         }
    4828             : 
    4829           0 :         return &he;
    4830             : }
    4831             : 
    4832           0 : static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
    4833             :                                          const char *name, int af,
    4834             :                                          struct hostent *hedst,
    4835             :                                          char *buf, size_t buflen,
    4836             :                                          struct hostent **hedstp)
    4837             : {
    4838           0 :         NSS_STATUS status;
    4839             : 
    4840           0 :         *hedstp = NULL;
    4841             : 
    4842           0 :         if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
    4843           0 :                 return ENOENT;
    4844             :         }
    4845             : 
    4846           0 :         status = b->symbols->_nss_gethostbyname2_r.f(name,
    4847             :                                                      af,
    4848             :                                                      hedst,
    4849             :                                                      buf,
    4850             :                                                      buflen,
    4851             :                                                      &errno,
    4852             :                                                      &h_errno);
    4853           0 :         switch (status) {
    4854           0 :         case NSS_STATUS_SUCCESS:
    4855           0 :                 *hedstp = hedst;
    4856           0 :                 return 0;
    4857           0 :         case NSS_STATUS_NOTFOUND:
    4858           0 :                 if (errno != 0) {
    4859           0 :                         return errno;
    4860             :                 }
    4861           0 :                 return ENOENT;
    4862           0 :         case NSS_STATUS_TRYAGAIN:
    4863           0 :                 if (errno != 0) {
    4864           0 :                         return errno;
    4865             :                 }
    4866           0 :                 return ERANGE;
    4867           0 :         default:
    4868           0 :                 if (errno != 0) {
    4869           0 :                         return errno;
    4870             :                 }
    4871           0 :                 return status;
    4872             :         }
    4873             : }
    4874             : 
    4875           0 : static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
    4876             :                                                   const char *name)
    4877             : {
    4878           0 :         static struct hostent he;
    4879           0 :         static char *buf = NULL;
    4880           0 :         static size_t buflen = 1000;
    4881           0 :         NSS_STATUS status;
    4882             : 
    4883           0 :         if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
    4884           0 :                 return NULL;
    4885             :         }
    4886             : 
    4887           0 :         if (buf == NULL) {
    4888           0 :                 buf = (char *)malloc(buflen);
    4889           0 :                 if (buf == NULL) {
    4890           0 :                         return NULL;
    4891             :                 }
    4892             :         }
    4893             : 
    4894           0 : again:
    4895           0 :         status = b->symbols->_nss_gethostbyname2_r.f(name,
    4896             :                                                      AF_UNSPEC,
    4897             :                                                      &he,
    4898             :                                                      buf,
    4899             :                                                      buflen,
    4900             :                                                      &errno,
    4901             :                                                      &h_errno);
    4902           0 :         if (status == NSS_STATUS_TRYAGAIN) {
    4903           0 :                 char *p = NULL;
    4904             : 
    4905           0 :                 buflen *= 2;
    4906           0 :                 p = (char *)realloc(buf, buflen);
    4907           0 :                 if (p == NULL) {
    4908           0 :                         SAFE_FREE(buf);
    4909           0 :                         return NULL;
    4910             :                 }
    4911           0 :                 buf = p;
    4912           0 :                 goto again;
    4913             :         }
    4914           0 :         if (status == NSS_STATUS_NOTFOUND) {
    4915           0 :                 SAFE_FREE(buf);
    4916           0 :                 return NULL;
    4917             :         }
    4918           0 :         if (status != NSS_STATUS_SUCCESS) {
    4919           0 :                 SAFE_FREE(buf);
    4920           0 :                 return NULL;
    4921             :         }
    4922             : 
    4923           0 :         return &he;
    4924             : }
    4925             : 
    4926           0 : static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
    4927             :                                                    const char *name, int af)
    4928             : {
    4929           0 :         static struct hostent he;
    4930           0 :         static char *buf = NULL;
    4931           0 :         static size_t buflen = 1000;
    4932           0 :         NSS_STATUS status;
    4933             : 
    4934           0 :         if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
    4935           0 :                 return NULL;
    4936             :         }
    4937             : 
    4938           0 :         if (buf == NULL) {
    4939           0 :                 buf = (char *)malloc(buflen);
    4940           0 :                 if (buf == NULL) {
    4941           0 :                         return NULL;
    4942             :                 }
    4943             :         }
    4944             : 
    4945           0 : again:
    4946           0 :         status = b->symbols->_nss_gethostbyname2_r.f(name,
    4947             :                                                      af,
    4948             :                                                      &he,
    4949             :                                                      buf,
    4950             :                                                      buflen,
    4951             :                                                      &errno,
    4952             :                                                      &h_errno);
    4953           0 :         if (status == NSS_STATUS_TRYAGAIN) {
    4954           0 :                 char *p = NULL;
    4955             : 
    4956           0 :                 buflen *= 2;
    4957           0 :                 p = (char *)realloc(buf, buflen);
    4958           0 :                 if (p == NULL) {
    4959           0 :                         SAFE_FREE(buf);
    4960           0 :                         return NULL;
    4961             :                 }
    4962           0 :                 buf = p;
    4963           0 :                 goto again;
    4964             :         }
    4965           0 :         if (status == NSS_STATUS_NOTFOUND) {
    4966           0 :                 SAFE_FREE(buf);
    4967           0 :                 return NULL;
    4968             :         }
    4969           0 :         if (status != NSS_STATUS_SUCCESS) {
    4970           0 :                 SAFE_FREE(buf);
    4971           0 :                 return NULL;
    4972             :         }
    4973             : 
    4974           0 :         return &he;
    4975             : }
    4976             : 
    4977             : /****************************************************************************
    4978             :  *   GETPWNAM
    4979             :  ***************************************************************************/
    4980             : 
    4981       70223 : static struct passwd *nwrap_getpwnam(const char *name)
    4982             : {
    4983        1094 :         size_t i;
    4984        1094 :         struct passwd *pwd;
    4985             : 
    4986       98058 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    4987       86340 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    4988       86340 :                 pwd = b->ops->nw_getpwnam(b, name);
    4989       86340 :                 if (pwd) {
    4990       58505 :                         return pwd;
    4991             :                 }
    4992             :         }
    4993             : 
    4994       11366 :         return NULL;
    4995             : }
    4996             : 
    4997             : struct passwd *getpwnam(const char *name)
    4998             : {
    4999       71195 :         if (!nss_wrapper_enabled()) {
    5000         972 :                 return libc_getpwnam(name);
    5001             :         }
    5002             : 
    5003       70223 :         return nwrap_getpwnam(name);
    5004             : }
    5005             : 
    5006             : /****************************************************************************
    5007             :  *   GETPWNAM_R
    5008             :  ***************************************************************************/
    5009             : 
    5010       46495 : static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
    5011             :                             char *buf, size_t buflen, struct passwd **pwdstp)
    5012             : {
    5013           4 :         size_t i;
    5014           4 :         int ret;
    5015             : 
    5016       91850 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5017       91850 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5018       91850 :                 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
    5019       91850 :                 if (ret == ENOENT) {
    5020       45355 :                         continue;
    5021             :                 }
    5022       46491 :                 return ret;
    5023             :         }
    5024             : 
    5025           0 :         return ENOENT;
    5026             : }
    5027             : 
    5028             : #ifdef HAVE_GETPWNAM_R
    5029             : # ifdef HAVE_SOLARIS_GETPWNAM_R
    5030             : int getpwnam_r(const char *name, struct passwd *pwdst,
    5031             :                char *buf, int buflen, struct passwd **pwdstp)
    5032             : # else /* HAVE_SOLARIS_GETPWNAM_R */
    5033             : int getpwnam_r(const char *name, struct passwd *pwdst,
    5034             :                char *buf, size_t buflen, struct passwd **pwdstp)
    5035             : # endif /* HAVE_SOLARIS_GETPWNAM_R */
    5036             : {
    5037       46645 :         if (!nss_wrapper_enabled()) {
    5038         150 :                 return libc_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
    5039             :         }
    5040             : 
    5041       46495 :         return nwrap_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
    5042             : }
    5043             : #endif
    5044             : 
    5045             : /****************************************************************************
    5046             :  *   GETPWUID
    5047             :  ***************************************************************************/
    5048             : 
    5049      154131 : static struct passwd *nwrap_getpwuid(uid_t uid)
    5050             : {
    5051         148 :         size_t i;
    5052         148 :         struct passwd *pwd;
    5053             : 
    5054      163177 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5055      159412 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5056      159412 :                 pwd = b->ops->nw_getpwuid(b, uid);
    5057      159412 :                 if (pwd) {
    5058      150366 :                         return pwd;
    5059             :                 }
    5060             :         }
    5061             : 
    5062        3765 :         return NULL;
    5063             : }
    5064             : 
    5065             : struct passwd *getpwuid(uid_t uid)
    5066             : {
    5067      157715 :         if (!nss_wrapper_enabled()) {
    5068        3584 :                 return libc_getpwuid(uid);
    5069             :         }
    5070             : 
    5071      154131 :         return nwrap_getpwuid(uid);
    5072             : }
    5073             : 
    5074             : /****************************************************************************
    5075             :  *   GETPWUID_R
    5076             :  ***************************************************************************/
    5077             : 
    5078        4422 : static int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
    5079             :                             char *buf, size_t buflen, struct passwd **pwdstp)
    5080             : {
    5081           2 :         size_t i;
    5082           2 :         int ret;
    5083             : 
    5084        5128 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5085        5123 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5086        5123 :                 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
    5087        5123 :                 if (ret == ENOENT) {
    5088         706 :                         continue;
    5089             :                 }
    5090        4415 :                 return ret;
    5091             :         }
    5092             : 
    5093           5 :         return ENOENT;
    5094             : }
    5095             : 
    5096             : #ifdef HAVE_SOLARIS_GETPWUID_R
    5097             : int getpwuid_r(uid_t uid, struct passwd *pwdst,
    5098             :                char *buf, int buflen, struct passwd **pwdstp)
    5099             : #else
    5100             : int getpwuid_r(uid_t uid, struct passwd *pwdst,
    5101             :                char *buf, size_t buflen, struct passwd **pwdstp)
    5102             : #endif
    5103             : {
    5104        4743 :         if (!nss_wrapper_enabled()) {
    5105         321 :                 return libc_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
    5106             :         }
    5107             : 
    5108        4422 :         return nwrap_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
    5109             : }
    5110             : 
    5111             : /****************************************************************************
    5112             :  *   SETPWENT
    5113             :  ***************************************************************************/
    5114             : 
    5115         365 : static void nwrap_setpwent(void)
    5116             : {
    5117             :         size_t i;
    5118             : 
    5119        1095 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5120         730 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5121         730 :                 b->ops->nw_setpwent(b);
    5122             :         }
    5123         365 : }
    5124             : 
    5125             : void setpwent(void)
    5126             : {
    5127         365 :         if (!nss_wrapper_enabled()) {
    5128           0 :                 libc_setpwent();
    5129           0 :                 return;
    5130             :         }
    5131             : 
    5132         365 :         nwrap_setpwent();
    5133             : }
    5134             : 
    5135             : /****************************************************************************
    5136             :  *   GETPWENT
    5137             :  ***************************************************************************/
    5138             : 
    5139       54179 : static struct passwd *nwrap_getpwent(void)
    5140             : {
    5141           0 :         size_t i;
    5142           0 :         struct passwd *pwd;
    5143             : 
    5144       55617 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5145       55268 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5146       55268 :                 pwd = b->ops->nw_getpwent(b);
    5147       55268 :                 if (pwd) {
    5148       53830 :                         return pwd;
    5149             :                 }
    5150             :         }
    5151             : 
    5152         349 :         return NULL;
    5153             : }
    5154             : 
    5155             : struct passwd *getpwent(void)
    5156             : {
    5157       54179 :         if (!nss_wrapper_enabled()) {
    5158           0 :                 return libc_getpwent();
    5159             :         }
    5160             : 
    5161       54179 :         return nwrap_getpwent();
    5162             : }
    5163             : 
    5164             : /****************************************************************************
    5165             :  *   GETPWENT_R
    5166             :  ***************************************************************************/
    5167             : 
    5168             : #ifdef HAVE_GETPWENT_R
    5169        1608 : static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
    5170             :                             size_t buflen, struct passwd **pwdstp)
    5171             : {
    5172           0 :         size_t i;
    5173           0 :         int ret;
    5174             : 
    5175        2380 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5176        2364 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5177        2364 :                 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
    5178        2364 :                 if (ret == ENOENT) {
    5179         772 :                         continue;
    5180             :                 }
    5181        1592 :                 return ret;
    5182             :         }
    5183             : 
    5184          16 :         return ENOENT;
    5185             : }
    5186             : 
    5187             : #  ifdef HAVE_SOLARIS_GETPWENT_R
    5188             : struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
    5189             : {
    5190             :         struct passwd *pwdstp = NULL;
    5191             :         int rc;
    5192             : 
    5193             :         if (!nss_wrapper_enabled()) {
    5194             :                 return libc_getpwent_r(pwdst, buf, buflen);
    5195             :         }
    5196             :         rc = nwrap_getpwent_r(pwdst, buf, buflen, &pwdstp);
    5197             :         if (rc < 0) {
    5198             :                 return NULL;
    5199             :         }
    5200             : 
    5201             :         return pwdstp;
    5202             : }
    5203             : #  else /* HAVE_SOLARIS_GETPWENT_R */
    5204             : int getpwent_r(struct passwd *pwdst, char *buf,
    5205             :                size_t buflen, struct passwd **pwdstp)
    5206             : {
    5207        1608 :         if (!nss_wrapper_enabled()) {
    5208           0 :                 return libc_getpwent_r(pwdst, buf, buflen, pwdstp);
    5209             :         }
    5210             : 
    5211        1608 :         return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
    5212             : }
    5213             : #  endif /* HAVE_SOLARIS_GETPWENT_R */
    5214             : #endif /* HAVE_GETPWENT_R */
    5215             : 
    5216             : /****************************************************************************
    5217             :  *   ENDPWENT
    5218             :  ***************************************************************************/
    5219             : 
    5220       12497 : static void nwrap_endpwent(void)
    5221             : {
    5222             :         size_t i;
    5223             : 
    5224       37640 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5225       25086 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5226       25086 :                 b->ops->nw_endpwent(b);
    5227             :         }
    5228       12497 : }
    5229             : 
    5230             : void endpwent(void)
    5231             : {
    5232       13190 :         if (!nss_wrapper_enabled()) {
    5233         636 :                 libc_endpwent();
    5234         636 :                 return;
    5235             :         }
    5236             : 
    5237       12911 :         nwrap_endpwent();
    5238             : }
    5239             : 
    5240             : /****************************************************************************
    5241             :  *   INITGROUPS
    5242             :  ***************************************************************************/
    5243             : 
    5244           0 : static int nwrap_initgroups(const char *user, gid_t group)
    5245             : {
    5246             : #if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
    5247             :         /* No extra groups allowed.  */
    5248             :         return 0;
    5249             : #elif !defined(HAVE_GETGROUPLIST)
    5250             :         return 0;
    5251             : #else
    5252           0 :         long int size;
    5253           0 :         long int limit;
    5254           0 :         gid_t *groups;
    5255           0 :         int ngroups;
    5256           0 :         int result;
    5257           0 :         const char *env = getenv("UID_WRAPPER");
    5258             : 
    5259           0 :         if (env == NULL || env[0] != '1') {
    5260           0 :                 NWRAP_LOG(NWRAP_LOG_WARN,
    5261             :                           "initgroups() requires uid_wrapper to work!");
    5262           0 :                 return 0;
    5263             :         }
    5264             : 
    5265           0 :         limit = sysconf(_SC_NGROUPS_MAX);
    5266           0 :         if (limit > 0) {
    5267           0 :                 size = MIN(limit, 64);
    5268             :         } else {
    5269           0 :                 size = 16;
    5270             :         }
    5271             : 
    5272           0 :         groups = (gid_t *)malloc(size * sizeof(gid_t));
    5273           0 :         if (groups == NULL) {
    5274             :                 /* No more memory.  */
    5275           0 :                 return -1;
    5276             :         }
    5277             : 
    5278           0 :         ngroups = nwrap_getgrouplist(user, group, &size, &groups, limit);
    5279             : 
    5280             :         /* Try to set the maximum number of groups the kernel can handle.  */
    5281           0 :         do {
    5282           0 :                 result = setgroups(ngroups, groups);
    5283           0 :         } while (result == -1 && errno == EINVAL && --ngroups > 0);
    5284             : 
    5285           0 :         free(groups);
    5286             : 
    5287           0 :         return result;
    5288             : #endif
    5289             : }
    5290             : 
    5291             : int initgroups(const char *user, gid_t group)
    5292             : {
    5293           0 :         if (!nss_wrapper_enabled()) {
    5294           0 :                 return libc_initgroups(user, group);
    5295             :         }
    5296             : 
    5297           0 :         return nwrap_initgroups(user, group);
    5298             : }
    5299             : 
    5300             : /****************************************************************************
    5301             :  *   GETGRNAM
    5302             :  ***************************************************************************/
    5303             : 
    5304        2497 : static struct group *nwrap_getgrnam(const char *name)
    5305             : {
    5306           0 :         size_t i;
    5307           0 :         struct group *grp;
    5308             : 
    5309        3885 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5310        3565 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5311        3565 :                 grp = b->ops->nw_getgrnam(b, name);
    5312        3565 :                 if (grp) {
    5313        2177 :                         return grp;
    5314             :                 }
    5315             :         }
    5316             : 
    5317         320 :         return NULL;
    5318             : }
    5319             : 
    5320             : struct group *getgrnam(const char *name)
    5321             : {
    5322        2497 :         if (!nss_wrapper_enabled()) {
    5323           0 :                 return libc_getgrnam(name);
    5324             :         }
    5325             : 
    5326        2497 :         return nwrap_getgrnam(name);
    5327             : }
    5328             : 
    5329             : /****************************************************************************
    5330             :  *   GETGRNAM_R
    5331             :  ***************************************************************************/
    5332             : 
    5333        1864 : static int nwrap_getgrnam_r(const char *name, struct group *grdst,
    5334             :                             char *buf, size_t buflen, struct group **grdstp)
    5335             : {
    5336           6 :         size_t i;
    5337           6 :         int ret;
    5338             : 
    5339        2958 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5340        2750 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5341        2750 :                 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
    5342        2750 :                 if (ret == ENOENT) {
    5343        1094 :                         continue;
    5344             :                 }
    5345        1654 :                 return ret;
    5346             :         }
    5347             : 
    5348         204 :         return ENOENT;
    5349             : }
    5350             : 
    5351             : #ifdef HAVE_GETGRNAM_R
    5352             : # ifdef HAVE_SOLARIS_GETGRNAM_R
    5353             : int getgrnam_r(const char *name, struct group *grp,
    5354             :                 char *buf, int buflen, struct group **pgrp)
    5355             : # else /* HAVE_SOLARIS_GETGRNAM_R */
    5356             : int getgrnam_r(const char *name, struct group *grp,
    5357             :                char *buf, size_t buflen, struct group **pgrp)
    5358             : # endif /* HAVE_SOLARIS_GETGRNAM_R */
    5359             : {
    5360        2081 :         if (!nss_wrapper_enabled()) {
    5361         217 :                 return libc_getgrnam_r(name,
    5362             :                                        grp,
    5363             :                                        buf,
    5364             :                                        buflen,
    5365             :                                        pgrp);
    5366             :         }
    5367             : 
    5368        1864 :         return nwrap_getgrnam_r(name, grp, buf, buflen, pgrp);
    5369             : }
    5370             : #endif /* HAVE_GETGRNAM_R */
    5371             : 
    5372             : /****************************************************************************
    5373             :  *   GETGRGID
    5374             :  ***************************************************************************/
    5375             : 
    5376        3049 : static struct group *nwrap_getgrgid(gid_t gid)
    5377             : {
    5378           0 :         size_t i;
    5379           0 :         struct group *grp;
    5380             : 
    5381        4223 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5382        4213 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5383        4213 :                 grp = b->ops->nw_getgrgid(b, gid);
    5384        4213 :                 if (grp) {
    5385        3039 :                         return grp;
    5386             :                 }
    5387             :         }
    5388             : 
    5389          10 :         return NULL;
    5390             : }
    5391             : 
    5392             : struct group *getgrgid(gid_t gid)
    5393             : {
    5394        3053 :         if (!nss_wrapper_enabled()) {
    5395           4 :                 return libc_getgrgid(gid);
    5396             :         }
    5397             : 
    5398        3049 :         return nwrap_getgrgid(gid);
    5399             : }
    5400             : 
    5401             : /****************************************************************************
    5402             :  *   GETGRGID_R
    5403             :  ***************************************************************************/
    5404             : 
    5405        4142 : static int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
    5406             :                             char *buf, size_t buflen, struct group **grdstp)
    5407             : {
    5408           0 :         size_t i;
    5409           0 :         int ret;
    5410             : 
    5411        4856 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5412        4851 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5413        4851 :                 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
    5414        4851 :                 if (ret == ENOENT) {
    5415         714 :                         continue;
    5416             :                 }
    5417        4137 :                 return ret;
    5418             :         }
    5419             : 
    5420           5 :         return ENOENT;
    5421             : }
    5422             : 
    5423             : #ifdef HAVE_GETGRGID_R
    5424             : # ifdef HAVE_SOLARIS_GETGRGID_R
    5425             : int getgrgid_r(gid_t gid, struct group *grdst,
    5426             :                char *buf, int buflen, struct group **grdstp)
    5427             : # else /* HAVE_SOLARIS_GETGRGID_R */
    5428             : int getgrgid_r(gid_t gid, struct group *grdst,
    5429             :                char *buf, size_t buflen, struct group **grdstp)
    5430             : # endif /* HAVE_SOLARIS_GETGRGID_R */
    5431             : {
    5432        4380 :         if (!nss_wrapper_enabled()) {
    5433         238 :                 return libc_getgrgid_r(gid, grdst, buf, buflen, grdstp);
    5434             :         }
    5435             : 
    5436        4142 :         return nwrap_getgrgid_r(gid, grdst, buf, buflen, grdstp);
    5437             : }
    5438             : #endif
    5439             : 
    5440             : /****************************************************************************
    5441             :  *   SETGRENT
    5442             :  ***************************************************************************/
    5443             : 
    5444          26 : static void nwrap_setgrent(void)
    5445             : {
    5446             :         size_t i;
    5447             : 
    5448          78 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5449          52 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5450          52 :                 b->ops->nw_setgrent(b);
    5451             :         }
    5452          26 : }
    5453             : 
    5454             : #ifdef HAVE_BSD_SETGRENT
    5455             : int setgrent(void)
    5456             : #else
    5457             : void setgrent(void)
    5458             : #endif
    5459             : {
    5460          26 :         if (!nss_wrapper_enabled()) {
    5461           0 :                 libc_setgrent();
    5462           0 :                 goto out;
    5463             :         }
    5464             : 
    5465          26 :         nwrap_setgrent();
    5466             : 
    5467          26 : out:
    5468             : #ifdef HAVE_BSD_SETGRENT
    5469             :         return 0;
    5470             : #else
    5471          26 :         return;
    5472             : #endif
    5473             : }
    5474             : 
    5475             : /****************************************************************************
    5476             :  *   GETGRENT
    5477             :  ***************************************************************************/
    5478             : 
    5479        1540 : static struct group *nwrap_getgrent(void)
    5480             : {
    5481           0 :         size_t i;
    5482           0 :         struct group *grp;
    5483             : 
    5484        2350 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5485        2336 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5486        2336 :                 grp = b->ops->nw_getgrent(b);
    5487        2336 :                 if (grp) {
    5488        1526 :                         return grp;
    5489             :                 }
    5490             :         }
    5491             : 
    5492          14 :         return NULL;
    5493             : }
    5494             : 
    5495             : struct group *getgrent(void)
    5496             : {
    5497        1540 :         if (!nss_wrapper_enabled()) {
    5498           0 :                 return libc_getgrent();
    5499             :         }
    5500             : 
    5501        1540 :         return nwrap_getgrent();
    5502             : }
    5503             : 
    5504             : /****************************************************************************
    5505             :  *   GETGRENT_R
    5506             :  ***************************************************************************/
    5507             : 
    5508             : #ifdef HAVE_GETGRENT_R
    5509        1448 : static int nwrap_getgrent_r(struct group *grdst, char *buf,
    5510             :                             size_t buflen, struct group **grdstp)
    5511             : {
    5512           0 :         size_t i;
    5513           0 :         int ret;
    5514             : 
    5515        2176 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5516        2164 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5517        2164 :                 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
    5518        2164 :                 if (ret == ENOENT) {
    5519         728 :                         continue;
    5520             :                 }
    5521        1436 :                 return ret;
    5522             :         }
    5523             : 
    5524          12 :         return ENOENT;
    5525             : }
    5526             : 
    5527             : #  ifdef HAVE_SOLARIS_GETGRENT_R
    5528             : struct group *getgrent_r(struct group *src, char *buf, int buflen)
    5529             : {
    5530             :         struct group *grdstp = NULL;
    5531             :         int rc;
    5532             : 
    5533             :         if (!nss_wrapper_enabled()) {
    5534             :                 return libc_getgrent_r(src, buf, buflen);
    5535             :         }
    5536             : 
    5537             :         rc = nwrap_getgrent_r(src, buf, buflen, &grdstp);
    5538             :         if (rc < 0) {
    5539             :                 return NULL;
    5540             :         }
    5541             : 
    5542             :         return grdstp;
    5543             : }
    5544             : #  else /* HAVE_SOLARIS_GETGRENT_R */
    5545             : int getgrent_r(struct group *src, char *buf,
    5546             :                size_t buflen, struct group **grdstp)
    5547             : {
    5548        1448 :         if (!nss_wrapper_enabled()) {
    5549           0 :                 return libc_getgrent_r(src, buf, buflen, grdstp);
    5550             :         }
    5551             : 
    5552        1448 :         return nwrap_getgrent_r(src, buf, buflen, grdstp);
    5553             : }
    5554             : #  endif /* HAVE_SOLARIS_GETGRENT_R */
    5555             : #endif /* HAVE_GETGRENT_R */
    5556             : 
    5557             : /****************************************************************************
    5558             :  *   ENDGRENT
    5559             :  ***************************************************************************/
    5560             : 
    5561          26 : static void nwrap_endgrent(void)
    5562             : {
    5563             :         size_t i;
    5564             : 
    5565          78 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5566          52 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5567          52 :                 b->ops->nw_endgrent(b);
    5568             :         }
    5569          26 : }
    5570             : 
    5571             : void endgrent(void)
    5572             : {
    5573          26 :         if (!nss_wrapper_enabled()) {
    5574           0 :                 libc_endgrent();
    5575           0 :                 return;
    5576             :         }
    5577             : 
    5578          26 :         nwrap_endgrent();
    5579             : }
    5580             : 
    5581             : /****************************************************************************
    5582             :  *   GETGROUPLIST
    5583             :  ***************************************************************************/
    5584             : 
    5585             : #ifdef HAVE_GETGROUPLIST
    5586       57294 : static int nwrap_getgrouplist(const char *user,
    5587             :                               gid_t group,
    5588             :                               long int *size,
    5589             :                               gid_t **groupsp,
    5590             :                               long int limit)
    5591             : {
    5592       57294 :         enum nss_status status = NSS_STATUS_UNAVAIL;
    5593             :         /* Start is one, because we have the first group as parameter.  */
    5594       57294 :         long int start = 1;
    5595           0 :         size_t i;
    5596             : 
    5597             :         /* Never store more than the starting *SIZE number of elements.  */
    5598       57294 :         assert(*size > 0);
    5599       57294 :         (*groupsp)[0] = group;
    5600             : 
    5601      171800 :         for (i = 0; i < nwrap_main_global->num_backends; i++) {
    5602      114506 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5603      114506 :                 long int prev_start = start;
    5604      114506 :                 long int cnt = prev_start;
    5605             : 
    5606      114506 :                 status = b->ops->nw_initgroups_dyn(b,
    5607             :                                                    user,
    5608             :                                                    group,
    5609             :                                                    &start,
    5610             :                                                    size,
    5611             :                                                    groupsp,
    5612             :                                                    limit,
    5613             :                                                    &errno);
    5614             : 
    5615             :                 /* Remove duplicates.  */
    5616      166046 :                 while (cnt < start) {
    5617             :                         long int inner;
    5618      103080 :                         for (inner = 0; inner < prev_start; ++inner)
    5619       51540 :                                 if ((*groupsp)[inner] == (*groupsp)[cnt])
    5620           0 :                                         break;
    5621             : 
    5622       51540 :                         if (inner < prev_start)
    5623           0 :                                 (*groupsp)[cnt] = (*groupsp)[--start];
    5624             :                         else
    5625       51540 :                                 ++cnt;
    5626             :                 }
    5627      114506 :                 NWRAP_LOG(NWRAP_LOG_DEBUG,
    5628             :                           "Resource '%s' returned status=%d and increased "
    5629             :                           "count of groups to %ld",
    5630             :                           b->name,
    5631             :                           status,
    5632             :                           start);
    5633             :         }
    5634       57294 :         return start;
    5635             : }
    5636             : 
    5637             : int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
    5638             : {
    5639           3 :         long int size;
    5640           3 :         int total, retval;
    5641           3 :         gid_t *newgroups;
    5642             : 
    5643       57297 :         if (!nss_wrapper_enabled()) {
    5644           3 :                 return libc_getgrouplist(user, group, groups, ngroups);
    5645             :         }
    5646             : 
    5647       57294 :         size = MAX(1, *ngroups);
    5648       57294 :         newgroups = (gid_t *)malloc(size * sizeof(gid_t));
    5649       57294 :         if (newgroups == NULL) {
    5650           0 :                 return -1;
    5651             :         }
    5652             : 
    5653       57294 :         total = nwrap_getgrouplist(user, group, &size, &newgroups, -1);
    5654             : 
    5655       57294 :         if (groups != NULL) {
    5656       57294 :                 memcpy(groups, newgroups, MIN(*ngroups, total) * sizeof(gid_t));
    5657             :         }
    5658             : 
    5659       57294 :         free(newgroups);
    5660             : 
    5661       57294 :         retval = total > *ngroups ? -1 : total;
    5662       57294 :         *ngroups = total;
    5663             : 
    5664       57294 :         return retval;
    5665             : }
    5666             : #endif
    5667             : 
    5668             : /**********************************************************
    5669             :  * SHADOW
    5670             :  **********************************************************/
    5671             : 
    5672             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    5673             : 
    5674             : #ifdef HAVE_SETSPENT
    5675             : static void nwrap_setspent(void)
    5676             : {
    5677             :         nwrap_files_setspent();
    5678             : }
    5679             : 
    5680             : void setspent(void)
    5681             : {
    5682             :         if (!nss_wrapper_shadow_enabled()) {
    5683             :                 return;
    5684             :         }
    5685             : 
    5686             :         nwrap_setspent();
    5687             : }
    5688             : 
    5689             : static struct spwd *nwrap_getspent(void)
    5690             : {
    5691             :         return nwrap_files_getspent();
    5692             : }
    5693             : 
    5694             : struct spwd *getspent(void)
    5695             : {
    5696             :         if (!nss_wrapper_shadow_enabled()) {
    5697             :                 return NULL;
    5698             :         }
    5699             : 
    5700             :         return nwrap_getspent();
    5701             : }
    5702             : 
    5703             : static void nwrap_endspent(void)
    5704             : {
    5705             :         nwrap_files_endspent();
    5706             : }
    5707             : 
    5708             : void endspent(void)
    5709             : {
    5710             :         if (!nss_wrapper_shadow_enabled()) {
    5711             :                 return;
    5712             :         }
    5713             : 
    5714             :         nwrap_endspent();
    5715             : }
    5716             : #endif /* HAVE_SETSPENT */
    5717             : 
    5718           0 : static struct spwd *nwrap_getspnam(const char *name)
    5719             : {
    5720           0 :         return nwrap_files_getspnam(name);
    5721             : }
    5722             : 
    5723             : struct spwd *getspnam(const char *name)
    5724             : {
    5725           0 :         if (!nss_wrapper_shadow_enabled()) {
    5726           0 :                 return NULL;
    5727             :         }
    5728             : 
    5729           0 :         return nwrap_getspnam(name);
    5730             : }
    5731             : 
    5732             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    5733             : 
    5734             : /**********************************************************
    5735             :  * NETDB
    5736             :  **********************************************************/
    5737             : 
    5738           0 : static void nwrap_sethostent(int stayopen) {
    5739           0 :         (void) stayopen; /* ignored */
    5740             : 
    5741           0 :         nwrap_files_sethostent();
    5742           0 : }
    5743             : 
    5744             : #ifdef HAVE_SOLARIS_SETHOSTENT
    5745             : int sethostent(int stayopen)
    5746             : {
    5747             :         if (!nss_wrapper_hosts_enabled()) {
    5748             :                 libc_sethostent(stayopen);
    5749             :                 return 0;
    5750             :         }
    5751             : 
    5752             :         nwrap_sethostent(stayopen);
    5753             : 
    5754             :         return 0;
    5755             : }
    5756             : #else /* HAVE_SOLARIS_SETHOSTENT */
    5757             : void sethostent(int stayopen)
    5758             : {
    5759           0 :         if (!nss_wrapper_hosts_enabled()) {
    5760           0 :                 libc_sethostent(stayopen);
    5761           0 :                 return;
    5762             :         }
    5763             : 
    5764           0 :         nwrap_sethostent(stayopen);
    5765             : }
    5766             : #endif /* HAVE_SOLARIS_SETHOSTENT */
    5767             : 
    5768           0 : static struct hostent *nwrap_gethostent(void)
    5769             : {
    5770           0 :         return nwrap_files_gethostent();
    5771             : }
    5772             : 
    5773             : struct hostent *gethostent(void) {
    5774           0 :         if (!nss_wrapper_hosts_enabled()) {
    5775           0 :                 return libc_gethostent();
    5776             :         }
    5777             : 
    5778           0 :         return nwrap_gethostent();
    5779             : }
    5780             : 
    5781           0 : static void nwrap_endhostent(void) {
    5782           0 :         nwrap_files_endhostent();
    5783           0 : }
    5784             : 
    5785             : #ifdef HAVE_SOLARIS_ENDHOSTENT
    5786             : int endhostent(void)
    5787             : {
    5788             :         if (!nss_wrapper_hosts_enabled()) {
    5789             :                 libc_endhostent();
    5790             :                 return 0;
    5791             :         }
    5792             : 
    5793             :         nwrap_endhostent();
    5794             : 
    5795             :         return 0;
    5796             : }
    5797             : #else /* HAVE_SOLARIS_ENDHOSTENT */
    5798             : void endhostent(void)
    5799             : {
    5800           0 :         if (!nss_wrapper_hosts_enabled()) {
    5801           0 :                 libc_endhostent();
    5802           0 :                 return;
    5803             :         }
    5804             : 
    5805           0 :         nwrap_endhostent();
    5806             : }
    5807             : #endif /* HAVE_SOLARIS_ENDHOSTENT */
    5808             : 
    5809             : 
    5810             : #ifdef BSD
    5811             : /* BSD implementation stores data in thread local storage but GLIBC does not */
    5812             : static __thread struct hostent user_he;
    5813             : static __thread struct nwrap_vector user_addrlist;
    5814             : #else
    5815             : static struct hostent user_he;
    5816             : static struct nwrap_vector user_addrlist;
    5817             : #endif /* BSD */
    5818             : 
    5819           0 : static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
    5820             :                                                  const char *name)
    5821             : {
    5822           0 :         int ret;
    5823             : 
    5824           0 :         (void) b; /* unused */
    5825             : 
    5826           0 :         ret = nwrap_files_internal_gethostbyname(name, AF_UNSPEC, &user_he,
    5827             :                                                  &user_addrlist);
    5828           0 :         if (ret == 0) {
    5829           0 :                 return &user_he;
    5830             :         }
    5831             : 
    5832           0 :         return NULL;
    5833             : }
    5834             : 
    5835           0 : static struct hostent *nwrap_gethostbyname(const char *name)
    5836             : {
    5837           0 :         size_t i;
    5838           0 :         struct hostent *he = NULL;
    5839             : 
    5840           0 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5841           0 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5842           0 :                 he = b->ops->nw_gethostbyname(b, name);
    5843           0 :                 if (he != NULL) {
    5844           0 :                         return he;
    5845             :                 }
    5846             :         }
    5847             : 
    5848           0 :         return NULL;
    5849             : }
    5850             : 
    5851             : struct hostent *gethostbyname(const char *name)
    5852             : {
    5853           0 :         if (!nss_wrapper_hosts_enabled()) {
    5854           0 :                 return libc_gethostbyname(name);
    5855             :         }
    5856             : 
    5857           0 :         return nwrap_gethostbyname(name);
    5858             : }
    5859             : 
    5860             : /* This is a GNU extension - Also can be found on BSD systems */
    5861             : #ifdef HAVE_GETHOSTBYNAME2
    5862             : #ifdef BSD
    5863             : /* BSD implementation stores data in  thread local storage but GLIBC not */
    5864             : static __thread struct hostent user_he2;
    5865             : static __thread struct nwrap_vector user_addrlist2;
    5866             : #else
    5867             : static struct hostent user_he2;
    5868             : static struct nwrap_vector user_addrlist2;
    5869             : #endif /* BSD */
    5870             : 
    5871           0 : static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
    5872             :                                                   const char *name, int af)
    5873             : {
    5874           0 :         int ret;
    5875             : 
    5876           0 :         (void) b; /* unused */
    5877             : 
    5878           0 :         ret = nwrap_files_internal_gethostbyname(name, af, &user_he2,
    5879             :                                                  &user_addrlist2);
    5880           0 :         if (ret == 0) {
    5881           0 :                 return &user_he2;
    5882             :         }
    5883             : 
    5884           0 :         return NULL;
    5885             : }
    5886             : 
    5887           0 : static struct hostent *nwrap_gethostbyname2(const char *name, int af)
    5888             : {
    5889           0 :         size_t i;
    5890           0 :         struct hostent *he = NULL;
    5891             : 
    5892           0 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5893           0 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5894           0 :                 he = b->ops->nw_gethostbyname2(b, name, af);
    5895           0 :                 if (he != NULL) {
    5896           0 :                         return he;
    5897             :                 }
    5898             :         }
    5899             : 
    5900           0 :         return NULL;
    5901             : }
    5902             : 
    5903             : struct hostent *gethostbyname2(const char *name, int af)
    5904             : {
    5905           0 :         if (!nss_wrapper_hosts_enabled()) {
    5906           0 :                 return libc_gethostbyname2(name, af);
    5907             :         }
    5908             : 
    5909           0 :         return nwrap_gethostbyname2(name, af);
    5910             : }
    5911             : #endif
    5912             : 
    5913           0 : static struct hostent *nwrap_gethostbyaddr(const void *addr,
    5914             :                                            socklen_t len, int type)
    5915             : {
    5916           0 :         size_t i;
    5917           0 :         struct hostent *he = NULL;
    5918             : 
    5919           0 :         for (i=0; i < nwrap_main_global->num_backends; i++) {
    5920           0 :                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    5921           0 :                 he = b->ops->nw_gethostbyaddr(b, addr, len, type);
    5922           0 :                 if (he != NULL) {
    5923           0 :                         return he;
    5924             :                 }
    5925             :         }
    5926             : 
    5927           0 :         return NULL;
    5928             : }
    5929             : 
    5930             : struct hostent *gethostbyaddr(const void *addr,
    5931             :                               socklen_t len, int type)
    5932             : {
    5933           0 :         if (!nss_wrapper_hosts_enabled()) {
    5934           0 :                 return libc_gethostbyaddr(addr, len, type);
    5935             :         }
    5936             : 
    5937           0 :         return nwrap_gethostbyaddr(addr, len, type);
    5938             : }
    5939             : 
    5940             : static const struct addrinfo default_hints =
    5941             : {
    5942             :         .ai_flags = AI_ADDRCONFIG|AI_V4MAPPED,
    5943             :         .ai_family = AF_UNSPEC,
    5944             :         .ai_socktype = 0,
    5945             :         .ai_protocol = 0,
    5946             :         .ai_addrlen = 0,
    5947             :         .ai_addr = NULL,
    5948             :         .ai_canonname = NULL,
    5949             :         .ai_next = NULL
    5950             : };
    5951             : 
    5952      401106 : static int nwrap_convert_he_ai(const struct hostent *he,
    5953             :                                unsigned short port,
    5954             :                                const struct addrinfo *hints,
    5955             :                                struct addrinfo **pai,
    5956             :                                bool skip_canonname)
    5957             : {
    5958        4611 :         struct addrinfo *ai;
    5959        4611 :         socklen_t socklen;
    5960             : 
    5961      401106 :         if (he == NULL) {
    5962           0 :                 return EAI_MEMORY;
    5963             :         }
    5964             : 
    5965      401106 :         switch (he->h_addrtype) {
    5966      287425 :                 case AF_INET:
    5967      287425 :                         socklen = sizeof(struct sockaddr_in);
    5968      287425 :                         break;
    5969             : #ifdef HAVE_IPV6
    5970      109172 :                 case AF_INET6:
    5971      109172 :                         socklen = sizeof(struct sockaddr_in6);
    5972      109172 :                         break;
    5973             : #endif
    5974           0 :                 default:
    5975           0 :                         return EAI_FAMILY;
    5976             :         }
    5977             : 
    5978      401106 :         ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + socklen);
    5979      401106 :         if (ai == NULL) {
    5980           0 :                 return EAI_MEMORY;
    5981             :         }
    5982             : 
    5983      401106 :         ai->ai_flags = hints->ai_flags;
    5984      401106 :         ai->ai_family = he->h_addrtype;
    5985      401106 :         ai->ai_socktype = hints->ai_socktype;
    5986      401106 :         ai->ai_protocol = hints->ai_protocol;
    5987      401106 :         ai->ai_canonname = NULL;
    5988             : 
    5989      401106 :         if (ai->ai_socktype == 0) {
    5990         723 :                 ai->ai_socktype = SOCK_DGRAM;
    5991             :         }
    5992      401106 :         if (ai->ai_protocol == 0) {
    5993      362686 :                 if (ai->ai_socktype == SOCK_DGRAM) {
    5994       34315 :                         ai->ai_protocol = IPPROTO_UDP;
    5995      328371 :                 } else if (ai->ai_socktype == SOCK_STREAM) {
    5996      328371 :                         ai->ai_protocol = IPPROTO_TCP;
    5997             :                 }
    5998             :         }
    5999             : 
    6000      401106 :         ai->ai_addrlen = socklen;
    6001      401106 :         ai->ai_addr = (void *)(ai + 1);
    6002             : 
    6003             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
    6004             :         ai->ai_addr->sa_len = socklen;
    6005             : #endif
    6006      401106 :         ai->ai_addr->sa_family = he->h_addrtype;
    6007             : 
    6008      401106 :         switch (he->h_addrtype) {
    6009      291934 :                 case AF_INET:
    6010             :                 {
    6011        4509 :                         union {
    6012             :                                 struct sockaddr *sa;
    6013             :                                 struct sockaddr_in *in;
    6014             :                         } addr;
    6015             : 
    6016      291934 :                         addr.sa = ai->ai_addr;
    6017             : 
    6018      291934 :                         memset(addr.in, 0, sizeof(struct sockaddr_in));
    6019             : 
    6020      291934 :                         addr.in->sin_port = htons(port);
    6021      291934 :                         addr.in->sin_family = AF_INET;
    6022             : 
    6023      291934 :                         memset(addr.in->sin_zero,
    6024             :                                '\0',
    6025             :                                sizeof (addr.in->sin_zero));
    6026      291934 :                         memcpy(&(addr.in->sin_addr),
    6027      291934 :                                he->h_addr_list[0],
    6028      291934 :                                he->h_length);
    6029             : 
    6030             :                 }
    6031      291934 :                 break;
    6032             : #ifdef HAVE_IPV6
    6033      109172 :                 case AF_INET6:
    6034             :                 {
    6035         102 :                         union {
    6036             :                                 struct sockaddr *sa;
    6037             :                                 struct sockaddr_in6 *in6;
    6038             :                         } addr;
    6039             : 
    6040      109172 :                         addr.sa = ai->ai_addr;
    6041             : 
    6042      109172 :                         memset(addr.in6, 0, sizeof(struct sockaddr_in6));
    6043             : 
    6044      109172 :                         addr.in6->sin6_port = htons(port);
    6045      109172 :                         addr.in6->sin6_family = AF_INET6;
    6046             : 
    6047      109172 :                         memcpy(&addr.in6->sin6_addr,
    6048      109172 :                                he->h_addr_list[0],
    6049      109172 :                                he->h_length);
    6050             :                 }
    6051      109172 :                 break;
    6052             : #endif
    6053             :         }
    6054             : 
    6055      401106 :         ai->ai_next = NULL;
    6056             : 
    6057      401106 :         if (he->h_name && !skip_canonname) {
    6058      351790 :                 ai->ai_canonname = strdup(he->h_name);
    6059      351790 :                 if (ai->ai_canonname == NULL) {
    6060           0 :                         freeaddrinfo(ai);
    6061           0 :                         return EAI_MEMORY;
    6062             :                 }
    6063             :         }
    6064             : 
    6065      401106 :         *pai = ai;
    6066      401106 :         return 0;
    6067             : }
    6068             : 
    6069     1450872 : static int nwrap_getaddrinfo(const char *node,
    6070             :                              const char *service,
    6071             :                              const struct addrinfo *hints,
    6072             :                              struct addrinfo **res)
    6073             : {
    6074     1450872 :         struct addrinfo *ai = NULL;
    6075     1450872 :         unsigned short port = 0;
    6076       24169 :         struct {
    6077             :                 int family;
    6078             :                 union {
    6079             :                         struct in_addr v4;
    6080             : #ifdef HAVE_IPV6
    6081             :                         struct in6_addr v6;
    6082             :                 } in;
    6083             : #endif
    6084     1450872 :         } addr = {
    6085             :                 .family = AF_UNSPEC,
    6086             :         };
    6087       24169 :         int rc;
    6088             : 
    6089     1450872 :         if (node == NULL && service == NULL) {
    6090           0 :                 return EAI_NONAME;
    6091             :         }
    6092             : 
    6093     1450872 :         if (hints == NULL) {
    6094           0 :                 hints = &default_hints;
    6095             :         }
    6096             : 
    6097             :         /* EAI_BADFLAGS
    6098             :               hints.ai_flags   contains   invalid  flags;  or,  hints.ai_flags
    6099             :               included AI_CANONNAME and name was NULL.
    6100             :         */
    6101     1450872 :         if ((hints->ai_flags & AI_CANONNAME) && (node == NULL)) {
    6102           0 :                 return EAI_BADFLAGS;
    6103             :         }
    6104             : 
    6105             :         /* If no node has been specified, let glibc deal with it */
    6106     1450872 :         if (node == NULL) {
    6107           0 :                 int ret;
    6108           0 :                 struct addrinfo *p = NULL;
    6109             : 
    6110           0 :                 ret = libc_getaddrinfo(node, service, hints, &p);
    6111             : 
    6112           0 :                 if (ret == 0) {
    6113           0 :                         *res = p;
    6114             :                 }
    6115           0 :                 return ret;
    6116             :         }
    6117             : 
    6118     1450872 :         if (service != NULL && service[0] != '\0') {
    6119      414401 :                 const char *proto = NULL;
    6120        5293 :                 struct servent *s;
    6121        5293 :                 char *end_ptr;
    6122        5293 :                 long sl;
    6123             : 
    6124      414401 :                 errno = 0;
    6125      414401 :                 sl = strtol(service, &end_ptr, 10);
    6126             : 
    6127      414401 :                 if (*end_ptr == '\0') {
    6128      414401 :                         port = sl;
    6129      414401 :                         goto valid_port;
    6130           0 :                 } else if (hints->ai_flags & AI_NUMERICSERV) {
    6131           0 :                         return EAI_NONAME;
    6132             :                 }
    6133             : 
    6134           0 :                 if (hints->ai_protocol != 0) {
    6135           0 :                         struct protoent *pent;
    6136             : 
    6137           0 :                         pent = getprotobynumber(hints->ai_protocol);
    6138           0 :                         if (pent != NULL) {
    6139           0 :                                 proto = pent->p_name;
    6140             :                         }
    6141             :                 }
    6142             : 
    6143           0 :                 s = getservbyname(service, proto);
    6144           0 :                 if (s == NULL) {
    6145           0 :                         return EAI_NONAME;
    6146             :                 }
    6147           0 :                 port = ntohs(s->s_port);
    6148             :         }
    6149             : 
    6150     1036471 : valid_port:
    6151             : 
    6152     1450872 :         rc = inet_pton(AF_INET, node, &addr.in.v4);
    6153     1450872 :         if (rc == 1) {
    6154     1065251 :                 addr.family = AF_INET;
    6155             :         }
    6156             : #ifdef HAVE_IPV6
    6157     1450872 :         if (addr.family == AF_UNSPEC) {
    6158      385621 :                 rc = inet_pton(AF_INET6, node, &addr.in.v6);
    6159      385621 :                 if (rc == 1) {
    6160      306973 :                         addr.family = AF_INET6;
    6161             :                 }
    6162             :         }
    6163             : #endif
    6164             : 
    6165     1450872 :         if (addr.family == AF_UNSPEC) {
    6166       78648 :                if (hints->ai_flags & AI_NUMERICHOST) {
    6167       29199 :                         return EAI_NONAME;
    6168             :                 }
    6169     1372224 :         } else if ((hints->ai_family != AF_UNSPEC) &&
    6170       12777 :                    (hints->ai_family != addr.family))
    6171             :         {
    6172           0 :                 return EAI_ADDRFAMILY;
    6173             :         }
    6174             : 
    6175     1421673 :         rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
    6176     1421673 :         if (rc != 0) {
    6177       19558 :                 int ret;
    6178     1069883 :                 struct addrinfo *p = NULL;
    6179             : 
    6180     1069883 :                 ret = libc_getaddrinfo(node, service, hints, &p);
    6181             : 
    6182     1069883 :                 if (ret == 0) {
    6183             :                         /*
    6184             :                          * nwrap_files_getaddrinfo failed, but libc was
    6185             :                          * successful -- use the result from libc.
    6186             :                          */
    6187     1069797 :                         *res = p;
    6188     1069797 :                         return 0;
    6189             :                 }
    6190             : 
    6191          86 :                 return rc;
    6192             :         }
    6193             : 
    6194             :         /*
    6195             :          * If the socktype was not specified, duplicate
    6196             :          * each ai returned, so that we have variants for
    6197             :          * both UDP and TCP.
    6198             :          */
    6199      351790 :         if (hints->ai_socktype == 0) {
    6200           0 :                 struct addrinfo *ai_cur;
    6201             : 
    6202             :                 /* freeaddrinfo() frees ai_canonname and ai so allocate them */
    6203        1098 :                 for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
    6204           0 :                         struct addrinfo *ai_new;
    6205             : 
    6206             :                         /* duplicate the current entry */
    6207             : 
    6208         723 :                         ai_new = malloc(sizeof(struct addrinfo));
    6209         723 :                         if (ai_new == NULL) {
    6210           0 :                                 freeaddrinfo(ai);
    6211           0 :                                 return EAI_MEMORY;
    6212             :                         }
    6213             : 
    6214         723 :                         memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
    6215         723 :                         ai_new->ai_next = NULL;
    6216             : 
    6217             :                         /* We need a deep copy or freeaddrinfo() will blow up */
    6218         723 :                         if (ai_cur->ai_canonname != NULL) {
    6219         375 :                                 ai_new->ai_canonname =
    6220         375 :                                         strdup(ai_cur->ai_canonname);
    6221             :                         }
    6222             : 
    6223         723 :                         if (ai_cur->ai_socktype == SOCK_DGRAM) {
    6224         723 :                                 ai_new->ai_socktype = SOCK_STREAM;
    6225           0 :                         } else if (ai_cur->ai_socktype == SOCK_STREAM) {
    6226           0 :                                 ai_new->ai_socktype = SOCK_DGRAM;
    6227             :                         }
    6228         723 :                         if (ai_cur->ai_protocol == IPPROTO_TCP) {
    6229           0 :                                 ai_new->ai_protocol = IPPROTO_UDP;
    6230         723 :                         } else if (ai_cur->ai_protocol == IPPROTO_UDP) {
    6231         723 :                                 ai_new->ai_protocol = IPPROTO_TCP;
    6232             :                         }
    6233             : 
    6234             :                         /* now insert the new entry */
    6235             : 
    6236         723 :                         ai_new->ai_next = ai_cur->ai_next;
    6237         723 :                         ai_cur->ai_next = ai_new;
    6238             : 
    6239             :                         /* and move on (don't duplicate the new entry) */
    6240             : 
    6241         723 :                         ai_cur = ai_new;
    6242             :                 }
    6243             :         }
    6244             : 
    6245      351790 :         *res = ai;
    6246             : 
    6247      351790 :         return 0;
    6248             : }
    6249             : 
    6250             : int getaddrinfo(const char *node, const char *service,
    6251             :                 const struct addrinfo *hints,
    6252             :                 struct addrinfo **res)
    6253             : {
    6254     1561326 :         if (!nss_wrapper_hosts_enabled()) {
    6255      110454 :                 return libc_getaddrinfo(node, service, hints, res);
    6256             :         }
    6257             : 
    6258     1450872 :         return nwrap_getaddrinfo(node, service, hints, res);
    6259             : }
    6260             : 
    6261     2320879 : static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
    6262             :                              char *host, size_t hostlen,
    6263             :                              char *serv, size_t servlen,
    6264             :                              int flags)
    6265             : {
    6266       56598 :         struct hostent *he;
    6267       56598 :         struct servent *service;
    6268       56598 :         const char *proto;
    6269       56598 :         const void *addr;
    6270       56598 :         socklen_t addrlen;
    6271       56598 :         uint16_t port;
    6272       56598 :         sa_family_t type;
    6273       56598 :         size_t i;
    6274             : 
    6275     2320879 :         if (sa == NULL || salen < sizeof(sa_family_t)) {
    6276           0 :                 return EAI_FAMILY;
    6277             :         }
    6278             : 
    6279     2320879 :         if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL) {
    6280           0 :                 return EAI_NONAME;
    6281             :         }
    6282             : 
    6283     2320879 :         type = sa->sa_family;
    6284     2320879 :         switch (type) {
    6285     1894113 :         case AF_INET: {
    6286       48400 :                 union {
    6287             :                         const struct sockaddr *sa;
    6288             :                         const struct sockaddr_in *in;
    6289             :                 } a;
    6290             : 
    6291     1894113 :                 if (salen < sizeof(struct sockaddr_in)) {
    6292       56598 :                         return EAI_FAMILY;
    6293             :                 }
    6294             : 
    6295     1894113 :                 a.sa = sa;
    6296             : 
    6297     1894113 :                 addr = &(a.in->sin_addr);
    6298     1894113 :                 addrlen = sizeof(a.in->sin_addr);
    6299     1894113 :                 port = ntohs(a.in->sin_port);
    6300     1894113 :                 break;
    6301             :         }
    6302             : #ifdef HAVE_IPV6
    6303      426760 :         case AF_INET6: {
    6304        8198 :                 union {
    6305             :                         const struct sockaddr *sa;
    6306             :                         const struct sockaddr_in6 *in6;
    6307             :                 } a;
    6308             : 
    6309      426760 :                 if (salen < sizeof(struct sockaddr_in6)) {
    6310       56598 :                         return EAI_FAMILY;
    6311             :                 }
    6312             : 
    6313      426760 :                 a.sa = sa;
    6314             : 
    6315      426760 :                 addr = &(a.in6->sin6_addr);
    6316      426760 :                 addrlen = sizeof(a.in6->sin6_addr);
    6317      426760 :                 port = ntohs(a.in6->sin6_port);
    6318      426760 :                 break;
    6319             :         }
    6320             : #endif
    6321           6 :         default:
    6322           6 :                 return EAI_FAMILY;
    6323             :         }
    6324             : 
    6325     2320873 :         if (host != NULL) {
    6326     2320873 :                 he = NULL;
    6327     2320873 :                 if ((flags & NI_NUMERICHOST) == 0) {
    6328          98 :                         for (i=0; i < nwrap_main_global->num_backends; i++) {
    6329          98 :                                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
    6330          98 :                                 he = b->ops->nw_gethostbyaddr(b, addr, addrlen, type);
    6331          98 :                                 if (he != NULL) {
    6332          98 :                                         break;
    6333             :                                 }
    6334             :                         }
    6335          98 :                         if ((flags & NI_NAMEREQD) && (he == NULL || he->h_name == NULL))
    6336           0 :                                 return EAI_NONAME;
    6337             :                 }
    6338     2264275 :                 if (he != NULL && he->h_name != NULL) {
    6339          98 :                         if (strlen(he->h_name) >= hostlen)
    6340           0 :                                 return EAI_OVERFLOW;
    6341          98 :                         snprintf(host, hostlen, "%s", he->h_name);
    6342          98 :                         if (flags & NI_NOFQDN)
    6343           0 :                                 host[strcspn(host, ".")] = '\0';
    6344             :                 } else {
    6345     2320775 :                         if (inet_ntop(type, addr, host, hostlen) == NULL)
    6346           0 :                                 return (errno == ENOSPC) ? EAI_OVERFLOW : EAI_FAIL;
    6347             :                 }
    6348             :         }
    6349             : 
    6350     2320873 :         if (serv != NULL) {
    6351       16948 :                 service = NULL;
    6352       16948 :                 if ((flags & NI_NUMERICSERV) == 0) {
    6353           0 :                         proto = (flags & NI_DGRAM) ? "udp" : "tcp";
    6354           0 :                         service = getservbyport(htons(port), proto);
    6355             :                 }
    6356       16948 :                 if (service != NULL) {
    6357           0 :                         if (strlen(service->s_name) >= servlen)
    6358           0 :                                 return EAI_OVERFLOW;
    6359           0 :                         snprintf(serv, servlen, "%s", service->s_name);
    6360             :                 } else {
    6361       16948 :                         if (snprintf(serv, servlen, "%u", port) >= (int) servlen)
    6362           0 :                                 return EAI_OVERFLOW;
    6363             :                 }
    6364             :         }
    6365             : 
    6366     2264275 :         return 0;
    6367             : }
    6368             : 
    6369             : #ifdef HAVE_LINUX_GETNAMEINFO
    6370             : int getnameinfo(const struct sockaddr *sa, socklen_t salen,
    6371             :                 char *host, socklen_t hostlen,
    6372             :                 char *serv, socklen_t servlen,
    6373             :                 int flags)
    6374             : #elif defined(HAVE_LINUX_GETNAMEINFO_UNSIGNED)
    6375             : int getnameinfo(const struct sockaddr *sa, socklen_t salen,
    6376             :                 char *host, socklen_t hostlen,
    6377             :                 char *serv, socklen_t servlen,
    6378             :                 unsigned int flags)
    6379             : #else
    6380             : int getnameinfo(const struct sockaddr *sa, socklen_t salen,
    6381             :                 char *host, size_t hostlen,
    6382             :                 char *serv, size_t servlen,
    6383             :                 int flags)
    6384             : #endif
    6385             : {
    6386     2328637 :         if (!nss_wrapper_hosts_enabled()) {
    6387        7758 :                 return libc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
    6388             :         }
    6389             : 
    6390     2320879 :         return nwrap_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
    6391             : }
    6392             : 
    6393      172268 : static int nwrap_gethostname(char *name, size_t len)
    6394             : {
    6395      172268 :         const char *hostname = getenv("NSS_WRAPPER_HOSTNAME");
    6396             : 
    6397      172268 :         if (strlen(hostname) >= len) {
    6398           0 :                 errno = ENAMETOOLONG;
    6399           0 :                 return -1;
    6400             :         }
    6401      172268 :         snprintf(name, len, "%s", hostname);
    6402             : 
    6403      172268 :         return 0;
    6404             : }
    6405             : 
    6406             : #ifdef HAVE_SOLARIS_GETHOSTNAME
    6407             : int gethostname(char *name, int len)
    6408             : #else /* HAVE_SOLARIS_GETHOSTNAME */
    6409             : int gethostname(char *name, size_t len)
    6410             : #endif /* HAVE_SOLARIS_GETHOSTNAME */
    6411             : {
    6412      181852 :         if (!nwrap_hostname_enabled()) {
    6413        9584 :                 return libc_gethostname(name, len);
    6414             :         }
    6415             : 
    6416      172268 :         return nwrap_gethostname(name, len);
    6417             : }
    6418             : 
    6419     1487466 : static void nwrap_thread_prepare(void)
    6420             : {
    6421     1487466 :         nwrap_init();
    6422     1487466 :         NWRAP_LOCK_ALL;
    6423     1487466 : }
    6424             : 
    6425     1478041 : static void nwrap_thread_parent(void)
    6426             : {
    6427     1478041 :         NWRAP_UNLOCK_ALL;
    6428     1478041 : }
    6429             : 
    6430        9425 : static void nwrap_thread_child(void)
    6431             : {
    6432        9425 :         NWRAP_REINIT_ALL;
    6433        9425 : }
    6434             : 
    6435             : /****************************
    6436             :  * CONSTRUCTOR
    6437             :  ***************************/
    6438      179861 : void nwrap_constructor(void)
    6439             : {
    6440      179861 :         NWRAP_REINIT_ALL;
    6441             : 
    6442             :         /*
    6443             :          * If we hold a lock and the application forks, then the child
    6444             :          * is not able to unlock the mutex and we are in a deadlock.
    6445             :          *
    6446             :          * Setting these handlers should prevent such deadlocks.
    6447             :          */
    6448      179861 :         pthread_atfork(&nwrap_thread_prepare,
    6449             :                        &nwrap_thread_parent,
    6450             :                        &nwrap_thread_child);
    6451             : 
    6452             :         /* Do not call nwrap_init() here. */
    6453      179861 : }
    6454             : 
    6455             : /****************************
    6456             :  * DESTRUCTOR
    6457             :  ***************************/
    6458             : 
    6459             : /*
    6460             :  * This function is called when the library is unloaded and makes sure that
    6461             :  * sockets get closed and the unix file for the socket are unlinked.
    6462             :  */
    6463      232068 : void nwrap_destructor(void)
    6464             : {
    6465        5774 :         size_t i;
    6466             : 
    6467      232068 :         NWRAP_LOCK_ALL;
    6468      232068 :         if (nwrap_main_global != NULL) {
    6469      107584 :                 struct nwrap_main *m = nwrap_main_global;
    6470             : 
    6471             :                 /* libc */
    6472      107584 :                 if (m->libc != NULL) {
    6473      107584 :                         if (m->libc->handle != NULL
    6474             : #ifdef RTLD_NEXT
    6475       57842 :                             && m->libc->handle != RTLD_NEXT
    6476             : #endif
    6477             :                            ) {
    6478       57745 :                                 dlclose(m->libc->handle);
    6479             :                         }
    6480      107584 :                         if (m->libc->nsl_handle != NULL
    6481             : #ifdef RTLD_NEXT
    6482       45361 :                             && m->libc->nsl_handle != RTLD_NEXT
    6483             : #endif
    6484             :                            ) {
    6485       45264 :                                 dlclose(m->libc->nsl_handle);
    6486             :                         }
    6487      107584 :                         if (m->libc->sock_handle != NULL
    6488             : #ifdef RTLD_NEXT
    6489        1992 :                             && m->libc->sock_handle != RTLD_NEXT
    6490             : #endif
    6491             :                            ) {
    6492           0 :                                 dlclose(m->libc->sock_handle);
    6493             :                         }
    6494      107584 :                         SAFE_FREE(m->libc);
    6495             :                 }
    6496             : 
    6497             :                 /* backends */
    6498      107584 :                 if (m->backends != NULL) {
    6499      312701 :                         for (i = 0; i < m->num_backends; i++) {
    6500      205117 :                                 struct nwrap_backend *b = &(m->backends[i]);
    6501             : 
    6502      205117 :                                 if (b->so_handle != NULL) {
    6503       97533 :                                         dlclose(b->so_handle);
    6504             :                                 }
    6505      205117 :                                 SAFE_FREE(b->symbols);
    6506             :                         }
    6507      107584 :                         SAFE_FREE(m->backends);
    6508             :                 }
    6509             :         }
    6510             : 
    6511      232068 :         if (nwrap_pw_global.cache != NULL) {
    6512      107584 :                 struct nwrap_cache *c = nwrap_pw_global.cache;
    6513             : 
    6514      107584 :                 nwrap_files_cache_unload(c);
    6515      107584 :                 if (c->fd >= 0) {
    6516       76616 :                         fclose(c->fp);
    6517       76616 :                         c->fd = -1;
    6518             :                 }
    6519             : 
    6520      107584 :                 SAFE_FREE(nwrap_pw_global.list);
    6521      107584 :                 nwrap_pw_global.num = 0;
    6522             :         }
    6523             : 
    6524      232068 :         if (nwrap_gr_global.cache != NULL) {
    6525      107584 :                 struct nwrap_cache *c = nwrap_gr_global.cache;
    6526             : 
    6527      107584 :                 nwrap_files_cache_unload(c);
    6528      107584 :                 if (c->fd >= 0) {
    6529       36750 :                         fclose(c->fp);
    6530       36750 :                         c->fd = -1;
    6531             :                 }
    6532             : 
    6533      107584 :                 SAFE_FREE(nwrap_gr_global.list);
    6534      107584 :                 nwrap_pw_global.num = 0;
    6535             :         }
    6536             : 
    6537             : #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
    6538      232068 :         if (nwrap_sp_global.cache != NULL) {
    6539      107584 :                 struct nwrap_cache *c = nwrap_sp_global.cache;
    6540             : 
    6541      107584 :                 nwrap_files_cache_unload(c);
    6542      107584 :                 if (c->fd >= 0) {
    6543           0 :                         fclose(c->fp);
    6544           0 :                         c->fd = -1;
    6545             :                 }
    6546             : 
    6547      107584 :                 nwrap_sp_global.num = 0;
    6548             :         }
    6549             : #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
    6550             : 
    6551      232068 :         if (nwrap_he_global.cache != NULL) {
    6552      107584 :                 struct nwrap_cache *c = nwrap_he_global.cache;
    6553             : 
    6554      107584 :                 nwrap_files_cache_unload(c);
    6555      107584 :                 if (c->fd >= 0) {
    6556       80435 :                         fclose(c->fp);
    6557       80435 :                         c->fd = -1;
    6558             :                 }
    6559             : 
    6560      107584 :                 nwrap_he_global.num = 0;
    6561             :         }
    6562             : 
    6563      232068 :         free(user_addrlist.items);
    6564             : #ifdef HAVE_GETHOSTBYNAME2
    6565      232068 :         free(user_addrlist2.items);
    6566             : #endif
    6567             : 
    6568      232068 :         hdestroy();
    6569      232068 :         NWRAP_UNLOCK_ALL;
    6570      232068 : }

Generated by: LCOV version 1.14