nwrap: Some code cleanup for nwrap_load_module_fn()
[nss_wrapper.git] / src / nss_wrapper.c
index 15547775b0afe80e7fcca79d59bb340713959ea8..3d9c3dc91ccce1700d80b64a5d8fef952b681390 100644 (file)
@@ -1,8 +1,11 @@
 /*
- * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
- * Copyright (C) Guenther Deschner 2009 <gd@samba.org>
- * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
+ * BSD 3-Clause License
  *
+ * Copyright (c) 2007,      Stefan Metzmacher <metze@samba.org>
+ * Copyright (c) 2009,      Guenther Deschner <gd@samba.org>
+ * Copyright (c) 2014-2015, Michael Adam <obnox@samba.org>
+ * Copyright (c) 2015,      Robin Hack <hack.robin@gmail.com>
+ * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,6 +55,8 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <netinet/in.h>
+
 #include <search.h>
 #include <assert.h>
 
@@ -140,6 +145,12 @@ typedef nss_status_t NSS_STATUS;
 #define PRINTF_ATTRIBUTE(a,b)
 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
 
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
+#else
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
 #else
@@ -152,6 +163,14 @@ typedef nss_status_t NSS_STATUS;
 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
 #endif
 
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+#endif
+
+#ifndef discard_const_p
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+#endif
+
 #ifdef HAVE_IPV6
 #define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
 #else
@@ -199,8 +218,11 @@ static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
        NWRAP_UNLOCK(nwrap_initialized); \
 } while (0);
 
+static void nwrap_init(void);
+
 static void nwrap_thread_prepare(void)
 {
+       nwrap_init();
        NWRAP_LOCK_ALL;
 }
 
@@ -221,9 +243,18 @@ enum nwrap_dbglvl_e {
        NWRAP_LOG_TRACE
 };
 
-#ifdef NDEBUG
-# define NWRAP_LOG(...)
+#ifndef HAVE_GETPROGNAME
+static const char *getprogname(void)
+{
+#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+       return program_invocation_short_name;
+#elif defined(HAVE_GETEXECNAME)
+       return getexecname();
 #else
+       return NULL;
+#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+}
+#endif /* HAVE_GETPROGNAME */
 
 static void nwrap_log(enum nwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
 # define NWRAP_LOG(dbglvl, ...) nwrap_log((dbglvl), __func__, __VA_ARGS__)
@@ -236,43 +267,49 @@ static void nwrap_log(enum nwrap_dbglvl_e dbglvl,
        va_list va;
        const char *d;
        unsigned int lvl = 0;
-       int pid = getpid();
+       const char *prefix = "NWRAP";
+       const char *progname = getprogname();
 
        d = getenv("NSS_WRAPPER_DEBUGLEVEL");
        if (d != NULL) {
                lvl = atoi(d);
        }
 
+       if (lvl < dbglvl) {
+               return;
+       }
+
        va_start(va, format);
        vsnprintf(buffer, sizeof(buffer), format, va);
        va_end(va);
 
-       if (lvl >= dbglvl) {
-               switch (dbglvl) {
-                       case NWRAP_LOG_ERROR:
-                               fprintf(stderr,
-                                       "NWRAP_ERROR(%d) - %s: %s\n",
-                                       pid, func, buffer);
-                               break;
-                       case NWRAP_LOG_WARN:
-                               fprintf(stderr,
-                                       "NWRAP_WARN(%d) - %s: %s\n",
-                                       pid, func, buffer);
-                               break;
-                       case NWRAP_LOG_DEBUG:
-                               fprintf(stderr,
-                                       "NWRAP_DEBUG(%d) - %s: %s\n",
-                                       pid, func, buffer);
-                               break;
-                       case NWRAP_LOG_TRACE:
-                               fprintf(stderr,
-                                       "NWRAP_TRACE(%d) - %s: %s\n",
-                                       pid, func, buffer);
-                               break;
-               }
+       switch (dbglvl) {
+               case NWRAP_LOG_ERROR:
+                       prefix = "NWRAP_ERROR";
+                       break;
+               case NWRAP_LOG_WARN:
+                       prefix = "NWRAP_WARN";
+                       break;
+               case NWRAP_LOG_DEBUG:
+                       prefix = "NWRAP_DEBUG";
+                       break;
+               case NWRAP_LOG_TRACE:
+                       prefix = "NWRAP_TRACE";
+                       break;
+       }
+
+       if (progname == NULL) {
+               progname = "<unknown>";
        }
+
+       fprintf(stderr,
+               "%s[%s (%u)] - %s: %s\n",
+               prefix,
+               progname,
+               (unsigned int)getpid(),
+               func,
+               buffer);
 }
-#endif /* NDEBUG NWRAP_LOG */
 
 struct nwrap_libc_fns {
        struct passwd *(*_libc_getpwnam)(const char *name);
@@ -282,11 +319,13 @@ struct nwrap_libc_fns {
        int (*_libc_getpwuid_r)(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result);
        void (*_libc_setpwent)(void);
        struct passwd *(*_libc_getpwent)(void);
-#ifdef HAVE_SOLARIS_GETPWENT_R
+#ifdef HAVE_GETPWENT_R
+#  ifdef HAVE_SOLARIS_GETPWENT_R
        struct passwd *(*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen);
-#else
+#  else /* HAVE_SOLARIS_GETPWENT_R */
        int (*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp);
-#endif
+#  endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
        void (*_libc_endpwent)(void);
        int (*_libc_initgroups)(const char *user, gid_t gid);
        struct group *(*_libc_getgrnam)(const char *name);
@@ -295,11 +334,13 @@ struct nwrap_libc_fns {
        int (*_libc_getgrgid_r)(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result);
        void (*_libc_setgrent)(void);
        struct group *(*_libc_getgrent)(void);
-#ifdef HAVE_SOLARIS_GETGRENT_R
+#ifdef HAVE_GETGRENT_R
+#  ifdef HAVE_SOLARIS_GETGRENT_R
        struct group *(*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen);
-#else
+#  else /* HAVE_SOLARIS_GETGRENT_R */
        int (*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen, struct group **result);
-#endif
+#  endif /* HAVE_SOLARIS_GETGRENT_R */
+#endif /* HAVE_GETGRENT_R */
        void (*_libc_endgrent)(void);
        int (*_libc_getgrouplist)(const char *user, gid_t group, gid_t *groups, int *ngroups);
 
@@ -354,6 +395,14 @@ struct nwrap_module_nss_fns {
        NSS_STATUS (*_nss_getgrent_r)(struct group *result, char *buffer,
                                      size_t buflen, int *errnop);
        NSS_STATUS (*_nss_endgrent)(void);
+       NSS_STATUS (*_nss_gethostbyaddr_r)(const void *addr, socklen_t addrlen,
+                                          int af, struct hostent *result,
+                                          char *buffer, size_t buflen,
+                                          int *errnop, int *h_errnop);
+       NSS_STATUS (*_nss_gethostbyname2_r)(const char *name, int af,
+                                           struct hostent *result,
+                                           char *buffer, size_t buflen,
+                                           int *errnop, int *h_errnop);
 };
 
 struct nwrap_backend {
@@ -364,6 +413,8 @@ struct nwrap_backend {
        struct nwrap_module_nss_fns *fns;
 };
 
+struct nwrap_vector;
+
 struct nwrap_ops {
        struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
                                       const char *name);
@@ -399,6 +450,18 @@ struct nwrap_ops {
                                         struct group *grdst, char *buf,
                                         size_t buflen, struct group **grdstp);
        void            (*nw_endgrent)(struct nwrap_backend *b);
+       struct hostent *(*nw_gethostbyaddr)(struct nwrap_backend *b,
+                                           const void *addr,
+                                           socklen_t len, int type);
+       struct hostent *(*nw_gethostbyname)(struct nwrap_backend *b,
+                                           const char *name);
+       struct hostent *(*nw_gethostbyname2)(struct nwrap_backend *b,
+                                            const char *name, int af);
+       int             (*nw_gethostbyname2_r)(struct nwrap_backend *b,
+                                              const char *name, int af,
+                                              struct hostent *hedst,
+                                              char *buf, size_t buflen,
+                                              struct hostent **hedstp);
 };
 
 /* Public prototypes */
@@ -444,6 +507,18 @@ static int nwrap_files_getgrent_r(struct nwrap_backend *b,
                                  struct group *grdst, char *buf,
                                  size_t buflen, struct group **grdstp);
 static void nwrap_files_endgrent(struct nwrap_backend *b);
+static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
+                                                const void *addr,
+                                                socklen_t len, int type);
+static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
+                                                const char *name);
+static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
+                                                 const char *name, int af);
+static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
+                                       const char *name, int af,
+                                       struct hostent *hedst,
+                                       char *buf, size_t buflen,
+                                       struct hostent **hedstp);
 
 /* prototypes for module backend */
 
@@ -481,6 +556,18 @@ static void nwrap_module_setgrent(struct nwrap_backend *b);
 static void nwrap_module_endgrent(struct nwrap_backend *b);
 static int nwrap_module_initgroups(struct nwrap_backend *b,
                                   const char *user, gid_t group);
+static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
+                                                 const void *addr,
+                                                 socklen_t len, int type);
+static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
+                                                 const char *name);
+static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
+                                                  const char *name, int af);
+static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
+                                        const char *name, int af,
+                                        struct hostent *hedst,
+                                        char *buf, size_t buflen,
+                                        struct hostent **hedstp);
 
 struct nwrap_ops nwrap_files_ops = {
        .nw_getpwnam    = nwrap_files_getpwnam,
@@ -500,6 +587,10 @@ struct nwrap_ops nwrap_files_ops = {
        .nw_getgrent    = nwrap_files_getgrent,
        .nw_getgrent_r  = nwrap_files_getgrent_r,
        .nw_endgrent    = nwrap_files_endgrent,
+       .nw_gethostbyaddr       = nwrap_files_gethostbyaddr,
+       .nw_gethostbyname       = nwrap_files_gethostbyname,
+       .nw_gethostbyname2      = nwrap_files_gethostbyname2,
+       .nw_gethostbyname2_r    = nwrap_files_gethostbyname2_r,
 };
 
 struct nwrap_ops nwrap_module_ops = {
@@ -520,6 +611,10 @@ struct nwrap_ops nwrap_module_ops = {
        .nw_getgrent    = nwrap_module_getgrent,
        .nw_getgrent_r  = nwrap_module_getgrent_r,
        .nw_endgrent    = nwrap_module_endgrent,
+       .nw_gethostbyaddr       = nwrap_module_gethostbyaddr,
+       .nw_gethostbyname       = nwrap_module_gethostbyname,
+       .nw_gethostbyname2      = nwrap_module_gethostbyname2,
+       .nw_gethostbyname2_r    = nwrap_module_gethostbyname2_r,
 };
 
 struct nwrap_libc {
@@ -530,7 +625,7 @@ struct nwrap_libc {
 };
 
 struct nwrap_main {
-       int num_backends;
+       size_t num_backends;
        struct nwrap_backend *backends;
        struct nwrap_libc *libc;
 };
@@ -768,8 +863,8 @@ struct nwrap_entlist {
 struct nwrap_he {
        struct nwrap_cache *cache;
 
-       struct nwrap_entdata *list;
-       struct nwrap_vector entdata;
+       struct nwrap_vector entries;
+       struct nwrap_vector lists;
 
        int num;
        int idx;
@@ -783,9 +878,9 @@ static struct nwrap_he nwrap_he_global;
  * NWRAP PROTOTYPES
  *********************************************************/
 
-static void nwrap_init(void);
 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
+void nwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
 void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
 
 /*********************************************************
@@ -798,7 +893,6 @@ enum nwrap_lib {
     NWRAP_LIBSOCKET,
 };
 
-#ifndef NDEBUG
 static const char *nwrap_str_lib(enum nwrap_lib lib)
 {
        switch (lib) {
@@ -813,7 +907,6 @@ static const char *nwrap_str_lib(enum nwrap_lib lib)
        /* Compiler would warn us about unhandled enum value if we get here */
        return "unknown";
 }
-#endif
 
 static void *nwrap_load_lib_handle(enum nwrap_lib lib)
 {
@@ -822,7 +915,25 @@ static void *nwrap_load_lib_handle(enum nwrap_lib lib)
        int i;
 
 #ifdef RTLD_DEEPBIND
-       flags |= RTLD_DEEPBIND;
+       const char *env_preload = getenv("LD_PRELOAD");
+       const char *env_deepbind = getenv("NSS_WRAPPER_DISABLE_DEEPBIND");
+       bool enable_deepbind = true;
+
+       /* Don't do a deepbind if we run with libasan */
+       if (env_preload != NULL && strlen(env_preload) < 1024) {
+               const char *p = strstr(env_preload, "libasan.so");
+               if (p != NULL) {
+                       enable_deepbind = false;
+               }
+       }
+
+       if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
+               enable_deepbind = false;
+       }
+
+       if (enable_deepbind) {
+               flags |= RTLD_DEEPBIND;
+       }
 #endif
 
        switch (lib) {
@@ -1056,7 +1167,8 @@ static struct passwd *libc_getpwent(void)
        return nwrap_main_global->libc->fns->_libc_getpwent();
 }
 
-#ifdef HAVE_SOLARIS_GETPWENT_R
+#ifdef HAVE_GETPWENT_R
+#  ifdef HAVE_SOLARIS_GETPWENT_R
 static struct passwd *libc_getpwent_r(struct passwd *pwdst,
                                      char *buf,
                                      int buflen)
@@ -1067,7 +1179,7 @@ static struct passwd *libc_getpwent_r(struct passwd *pwdst,
                                                              buf,
                                                              buflen);
 }
-#else /* HAVE_SOLARIS_GETPWENT_R */
+#  else /* HAVE_SOLARIS_GETPWENT_R */
 static int libc_getpwent_r(struct passwd *pwdst,
                           char *buf,
                           size_t buflen,
@@ -1080,7 +1192,8 @@ static int libc_getpwent_r(struct passwd *pwdst,
                                                              buflen,
                                                              pwdstp);
 }
-#endif /* HAVE_SOLARIS_GETPWENT_R */
+#  endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
 
 static void libc_endpwent(void)
 {
@@ -1173,7 +1286,7 @@ static struct group *libc_getgrent(void)
 }
 
 #ifdef HAVE_GETGRENT_R
-#ifdef HAVE_SOLARIS_GETGRENT_R
+#  ifdef HAVE_SOLARIS_GETGRENT_R
 static struct group *libc_getgrent_r(struct group *group,
                                     char *buf,
                                     size_t buflen)
@@ -1184,7 +1297,7 @@ static struct group *libc_getgrent_r(struct group *group,
                                                              buf,
                                                              buflen);
 }
-#else /* !HAVE_SOLARIS_GETGRENT_R */
+#  else /* HAVE_SOLARIS_GETGRENT_R */
 static int libc_getgrent_r(struct group *group,
                           char *buf,
                           size_t buflen,
@@ -1197,7 +1310,7 @@ static int libc_getgrent_r(struct group *group,
                                                              buflen,
                                                              result);
 }
-#endif /* HAVE_SOLARIS_GETGRENT_R */
+#  endif /* HAVE_SOLARIS_GETGRENT_R */
 #endif /* HAVE_GETGRENT_R */
 
 static void libc_endgrent(void)
@@ -1358,21 +1471,23 @@ static int libc_getnameinfo(const struct sockaddr *sa,
 static void *nwrap_load_module_fn(struct nwrap_backend *b,
                                  const char *fn_name)
 {
-       void *res;
-       char *s;
+       void *res = NULL;
+       char *s = NULL;
+       int rc;
 
-       if (!b->so_handle) {
+       if (b->so_handle == NULL) {
                NWRAP_LOG(NWRAP_LOG_ERROR, "No handle");
                return NULL;
        }
 
-       if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
+       rc = asprintf(&s, "_nss_%s_%s", b->name, fn_name);
+       if (rc == -1) {
                NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
                return NULL;
        }
 
        res = dlsym(b->so_handle, s);
-       if (!res) {
+       if (res == NULL) {
                NWRAP_LOG(NWRAP_LOG_ERROR,
                          "Cannot find function %s in %s",
                          s, b->so_path);
@@ -1416,6 +1531,10 @@ static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *
                nwrap_load_module_fn(b, "getgrent_r");
        *(void **)(&fns->_nss_endgrent) =
                nwrap_load_module_fn(b, "endgrent");
+       *(void **)(&fns->_nss_gethostbyaddr_r) =
+               nwrap_load_module_fn(b, "gethostbyaddr_r");
+       *(void **)(&fns->_nss_gethostbyname2_r) =
+               nwrap_load_module_fn(b, "gethostbyname2_r");
 
        return fns;
 }
@@ -1442,7 +1561,7 @@ static void *nwrap_load_module(const char *so_path)
 static bool nwrap_module_init(const char *name,
                              struct nwrap_ops *ops,
                              const char *so_path,
-                             int *num_backends,
+                             size_t *num_backends,
                              struct nwrap_backend **backends)
 {
        struct nwrap_backend *b;
@@ -1478,19 +1597,17 @@ static bool nwrap_module_init(const char *name,
 
 static void nwrap_libc_init(struct nwrap_main *r)
 {
-       r->libc = malloc(sizeof(struct nwrap_libc));
+       r->libc = calloc(1, sizeof(struct nwrap_libc));
        if (r->libc == NULL) {
                printf("Failed to allocate memory for libc");
                exit(-1);
        }
-       ZERO_STRUCTP(r->libc);
 
-       r->libc->fns = malloc(sizeof(struct nwrap_libc_fns));
+       r->libc->fns = calloc(1, sizeof(struct nwrap_libc_fns));
        if (r->libc->fns == NULL) {
                printf("Failed to allocate memory for libc functions");
                exit(-1);
        }
-       ZERO_STRUCTP(r->libc->fns);
 }
 
 static void nwrap_backend_init(struct nwrap_main *r)
@@ -1531,6 +1648,7 @@ static void nwrap_init(void)
        const char *env;
        char *endptr;
        size_t max_hostents_tmp;
+       int ok;
 
        NWRAP_LOCK(nwrap_initialized);
        if (nwrap_initialized) {
@@ -1551,31 +1669,30 @@ static void nwrap_init(void)
 
        nwrap_initialized = true;
 
-       /* Initialize pthread_atfork handlers */
-       pthread_atfork(&nwrap_thread_prepare, &nwrap_thread_parent,
-                      &nwrap_thread_child);
-
        env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
        if (env != NULL) {
-               max_hostents_tmp = (size_t)strtol(env, &endptr, 10);
-               if (((env != '\0') && (endptr == '\0')) ||
+               max_hostents_tmp = (size_t)strtoul(env, &endptr, 10);
+               if ((*env == '\0') ||
+                   (*endptr != '\0') ||
                    (max_hostents_tmp == 0)) {
                        NWRAP_LOG(NWRAP_LOG_DEBUG,
                                  "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
                                  "value or value is too small. "
                                  "Using default value: %lu.",
-                                 max_hostents);
+                                 (unsigned long)max_hostents);
                } else {
                        max_hostents = max_hostents_tmp;
                }
        }
        /* Initialize hash table */
        NWRAP_LOG(NWRAP_LOG_DEBUG,
-                 "Initializing hash table of size %lu items.", max_hostents);
-       if (hcreate(max_hostents) == 0) {
+                 "Initializing hash table of size %lu items.",
+                 (unsigned long)max_hostents);
+       ok = hcreate(max_hostents);
+       if (!ok) {
                NWRAP_LOG(NWRAP_LOG_ERROR,
                          "Failed to initialize hash table");
-               goto done;
+               exit(-1);
        }
 
        nwrap_main_global = &__nwrap_main_global;
@@ -1626,7 +1743,6 @@ static void nwrap_init(void)
        nwrap_he_global.cache->parse_line = nwrap_he_parse_line;
        nwrap_he_global.cache->unload = nwrap_he_unload;
 
-done:
        /* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
        NWRAP_UNLOCK_ALL;
 }
@@ -1960,6 +2076,28 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
 
        NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid);
 
+#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
+       pw->pw_class = discard_const_p(char, "");
+
+       NWRAP_LOG(NWRAP_LOG_TRACE, "class[%s]", pw->pw_class);
+#endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
+
+#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
+       pw->pw_change = 0;
+
+       NWRAP_LOG(NWRAP_LOG_TRACE,
+                 "change[%lu]",
+                 (unsigned long)pw->pw_change);
+#endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
+
+#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
+       pw->pw_expire = 0;
+
+       NWRAP_LOG(NWRAP_LOG_TRACE,
+                 "expire[%lu]",
+                 (unsigned long)pw->pw_expire);
+#endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
+
        /* gecos */
        p = strchr(c, ':');
        if (!p) {
@@ -2036,6 +2174,19 @@ static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
        dst->pw_passwd = buf + ofs;
        dst->pw_uid = src->pw_uid;
        dst->pw_gid = src->pw_gid;
+#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
+       ofs = PTR_DIFF(src->pw_class, first);
+       dst->pw_class = buf + ofs;
+#endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
+
+#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
+       dst->pw_change = 0;
+#endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
+
+#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
+       dst->pw_expire = 0;
+#endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
+
        ofs = PTR_DIFF(src->pw_gecos, first);
        dst->pw_gecos = buf + ofs;
        ofs = PTR_DIFF(src->pw_dir, first);
@@ -2436,7 +2587,7 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
        }
        gr->gr_mem[0] = NULL;
 
-       for(nummem=0; p; nummem++) {
+       for(nummem = 0; p != NULL && p[0] != '\0'; nummem++) {
                char **m;
                size_t m_size;
                c = p;
@@ -2495,50 +2646,84 @@ static void nwrap_gr_unload(struct nwrap_cache *nwrap)
 static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
                           char *buf, size_t buflen, struct group **dstp)
 {
-       char *first;
-       char **lastm;
-       char *last = NULL;
-       off_t ofsb;
-       off_t ofsm;
-       off_t ofs;
+       char *p = NULL;
+       uintptr_t align = 0;
+       unsigned int gr_mem_cnt = 0;
        unsigned i;
+       size_t total_len;
+       size_t gr_name_len = strlen(src->gr_name) + 1;
+       size_t gr_passwd_len = strlen(src->gr_passwd) + 1;
+       union {
+               char *ptr;
+               char **data;
+       } g_mem;
+
+       for (i = 0; src->gr_mem[i] != NULL; i++) {
+               gr_mem_cnt++;
+       }
+
+       /* Align the memory for storing pointers */
+       align = __alignof__(char *) - ((p - (char *)0) % __alignof__(char *));
+       total_len = align +
+                   (1 + gr_mem_cnt) * sizeof(char *) +
+                   gr_name_len + gr_passwd_len;
+
+       if (total_len > buflen) {
+               errno = ERANGE;
+               return -1;
+       }
+       buflen -= total_len;
 
-       first = src->gr_name;
+       /* gr_mem */
+       p = buf + align;
+       g_mem.ptr = p;
+       dst->gr_mem = g_mem.data;
 
-       lastm = src->gr_mem;
-       while (*lastm) {
-               last = *lastm;
-               lastm++;
-       }
+       /* gr_name */
+       p += (1 + gr_mem_cnt) * sizeof(char *);
+       dst->gr_name = p;
 
-       if (last == NULL) {
-               last = src->gr_passwd;
-       }
-       while (*last) last++;
+       /* gr_passwd */
+       p += gr_name_len;
+       dst->gr_passwd = p;
 
-       ofsb = PTR_DIFF(last + 1, first);
-       ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
+       /* gr_mem[x] */
+       p += gr_passwd_len;
 
-       if ((ofsb + ofsm) > (off_t) buflen) {
-               return ERANGE;
+       /* gr_gid */
+       dst->gr_gid = src->gr_gid;
+
+       memcpy(dst->gr_name, src->gr_name, gr_name_len);
+
+       memcpy(dst->gr_passwd, src->gr_passwd, gr_passwd_len);
+
+       /* Set the terminating entry */
+       dst->gr_mem[gr_mem_cnt] = NULL;
+
+       /* Now add the group members content */
+       total_len = 0;
+       for (i = 0; i < gr_mem_cnt; i++) {
+               size_t len = strlen(src->gr_mem[i]) + 1;
+
+               dst->gr_mem[i] = p;
+               total_len += len;
+               p += len;
        }
 
-       memcpy(buf, first, ofsb);
-       memcpy(buf + ofsb, src->gr_mem, ofsm);
+       if (total_len > buflen) {
+               errno = ERANGE;
+               return -1;
+       }
 
-       ofs = PTR_DIFF(src->gr_name, first);
-       dst->gr_name = buf + ofs;
-       ofs = PTR_DIFF(src->gr_passwd, first);
-       dst->gr_passwd = buf + ofs;
-       dst->gr_gid = src->gr_gid;
+       for (i = 0; i < gr_mem_cnt; i++) {
+               size_t len = strlen(src->gr_mem[i]) + 1;
 
-       dst->gr_mem = (char **)(buf + ofsb);
-       for (i=0; src->gr_mem[i]; i++) {
-               ofs = PTR_DIFF(src->gr_mem[i], first);
-               dst->gr_mem[i] = buf + ofs;
+               memcpy(dst->gr_mem[i],
+                      src->gr_mem[i],
+                      len);
        }
 
-       if (dstp) {
+       if (dstp != NULL) {
                *dstp = dst;
        }
 
@@ -2567,41 +2752,13 @@ static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
        return el;
 }
 
-static bool nwrap_add_ai(char *const ip_addr, struct nwrap_entdata *const ed)
-{
-       ENTRY e;
-       ENTRY *p;
-       struct nwrap_entlist *el;
-
-       if (ip_addr == NULL) {
-               NWRAP_LOG(NWRAP_LOG_ERROR, "ip_addr NULL - can't add");
-               return false;
-       }
-
-       el = nwrap_entlist_init(ed);
-       if (el == NULL) {
-               return false;
-       }
-
-       e.key = ip_addr;
-       e.data = el;
-
-       p = hsearch(e, ENTER);
-       if (p == NULL) {
-               NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full");
-               return false;
-       }
-
-       return true;
-}
-
-
-static bool nwrap_add_hname_add_new(char *const h_name,
-                                   struct nwrap_entdata *const ed)
+static bool nwrap_ed_inventarize_add_new(char *const h_name,
+                                        struct nwrap_entdata *const ed)
 {
        ENTRY e;
        ENTRY *p;
        struct nwrap_entlist *el;
+       bool ok;
 
        if (h_name == NULL) {
                NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
@@ -2618,15 +2775,24 @@ static bool nwrap_add_hname_add_new(char *const h_name,
 
        p = hsearch(e, ENTER);
        if (p == NULL) {
-               NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full!");
+               NWRAP_LOG(NWRAP_LOG_ERROR,
+                         "Hash table is full (%s)!",
+                         strerror(errno));
+               return false;
+       }
+
+       ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR,
+                         "Failed to add list entry to vector.");
                return false;
        }
 
        return true;
 }
 
-static bool nwrap_add_hname_add_to_existing(struct nwrap_entdata *const ed,
-                                           struct nwrap_entlist *const el)
+static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
+                                                struct nwrap_entlist *const el)
 {
        struct nwrap_entlist *cursor;
        struct nwrap_entlist *el_new;
@@ -2636,21 +2802,22 @@ static bool nwrap_add_hname_add_to_existing(struct nwrap_entdata *const ed,
                return false;
        }
 
-       el_new = nwrap_entlist_init(ed);
-       if (el_new == NULL) {
-               return false;
-       }
 
        for (cursor = el; cursor->next != NULL; cursor = cursor->next)
        {
                if (cursor->ed == ed) {
-                       free(el_new);
-                       return false;
+                       /* The entry already exists in this list. */
+                       return true;
                }
        }
 
        if (cursor->ed == ed) {
-               free(el_new);
+               /* The entry already exists in this list. */
+               return true;
+       }
+
+       el_new = nwrap_entlist_init(ed);
+       if (el_new == NULL) {
                return false;
        }
 
@@ -2658,25 +2825,27 @@ static bool nwrap_add_hname_add_to_existing(struct nwrap_entdata *const ed,
        return true;
 }
 
-static bool nwrap_add_hname_alias(char *const h_name_a,
-                                 struct nwrap_entdata *const ed)
+static bool nwrap_ed_inventarize(char *const name,
+                                struct nwrap_entdata *const ed)
 {
        ENTRY e;
        ENTRY *p;
        bool ok;
 
-       e.key = h_name_a;
+       e.key = name;
        e.data = NULL;
+
        NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
+
        p = hsearch(e, FIND);
        if (p == NULL) {
-               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name_a);
-               ok = nwrap_add_hname_add_new(h_name_a, ed);
+               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name);
+               ok = nwrap_ed_inventarize_add_new(name, ed);
        } else {
                struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
 
-               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name_a);
-               ok = nwrap_add_hname_add_to_existing(ed, el);
+               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name);
+               ok = nwrap_ed_inventarize_add_to_existing(ed, el);
        }
 
        return ok;
@@ -2685,25 +2854,10 @@ static bool nwrap_add_hname_alias(char *const h_name_a,
 static bool nwrap_add_hname(struct nwrap_entdata *const ed)
 {
        char *const h_name = (char *const)(ed->ht.h_name);
-       ENTRY e;
-       ENTRY *p;
        unsigned i;
        bool ok;
 
-       e.key = h_name;
-       e.data = NULL;
-       NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
-       p = hsearch(e, FIND);
-       if (p == NULL) {
-               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name);
-               ok = nwrap_add_hname_add_new(h_name, ed);
-       } else {
-               struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
-
-               NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name);
-               ok = nwrap_add_hname_add_to_existing(ed, el);
-       }
-
+       ok = nwrap_ed_inventarize(h_name, ed);
        if (!ok) {
                return false;
        }
@@ -2720,7 +2874,7 @@ static bool nwrap_add_hname(struct nwrap_entdata *const ed)
 
                NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
 
-               if (!nwrap_add_hname_alias(h_name_alias, ed)) {
+               if (!nwrap_ed_inventarize(h_name_alias, ed)) {
                        NWRAP_LOG(NWRAP_LOG_ERROR,
                                  "Unable to add alias: %s", h_name_alias);
                        return false;
@@ -2798,8 +2952,13 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
        }
        ip = i;
 
-       nwrap_vector_add_item(&(ed->nwrap_addrdata),
-                             (void *const)ed->addr.host_addr);
+       ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
+                                  (void *const)ed->addr.host_addr);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
+               free(ed);
+               return false;
+       }
        ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
 
        p++;
@@ -2885,7 +3044,12 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
                aliases_count += 1;
        }
 
-       nwrap_vector_add_item(&(nwrap_he->entdata), (void *const)ed);
+       ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
+               free(ed);
+               return false;
+       }
 
        ed->aliases_count = aliases_count;
        /* Inventarize item */
@@ -2894,7 +3058,7 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
                return false;
        }
 
-       ok = nwrap_add_ai(ip, ed);
+       ok = nwrap_ed_inventarize(ip, ed);
        if (!ok) {
                return false;
        }
@@ -2908,19 +3072,46 @@ static void nwrap_he_unload(struct nwrap_cache *nwrap)
        struct nwrap_he *nwrap_he =
                (struct nwrap_he *)nwrap->private_data;
        struct nwrap_entdata *ed;
+       struct nwrap_entlist *el;
        size_t i;
+       int rc;
 
-       nwrap_vector_foreach (ed, nwrap_he->entdata, i)
+       nwrap_vector_foreach (ed, nwrap_he->entries, i)
        {
                SAFE_FREE(ed->nwrap_addrdata.items);
                SAFE_FREE(ed->ht.h_aliases);
                SAFE_FREE(ed);
        }
-       SAFE_FREE(nwrap_he->entdata.items);
-       nwrap_he->entdata.count = nwrap_he->entdata.capacity = 0;
+       SAFE_FREE(nwrap_he->entries.items);
+       nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
+
+       nwrap_vector_foreach(el, nwrap_he->lists, i)
+       {
+               while (el != NULL) {
+                       struct nwrap_entlist *el_next;
+
+                       el_next = el->next;
+                       SAFE_FREE(el);
+                       el = el_next;
+               }
+       }
+       SAFE_FREE(nwrap_he->lists.items);
+       nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
 
        nwrap_he->num = 0;
        nwrap_he->idx = 0;
+
+       /*
+        * If we unload the file, the pointers in the hash table point to
+        * invalid memory. So we need to destroy the hash table and recreate
+        * it.
+        */
+       hdestroy();
+       rc = hcreate(max_hostents);
+       if (rc == 0) {
+               NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to initialize hash table");
+               exit(-1);
+       }
 }
 
 
@@ -3382,9 +3573,9 @@ static void nwrap_files_endgrent(struct nwrap_backend *b)
 }
 
 /* hosts functions */
-static int nwrap_files_gethostbyname(const char *name, int af,
-                                    struct hostent *result,
-                                    struct nwrap_vector *addr_list)
+static int nwrap_files_internal_gethostbyname(const char *name, int af,
+                                             struct hostent *result,
+                                             struct nwrap_vector *addr_list)
 {
        struct nwrap_entlist *el;
        struct hostent *he;
@@ -3404,7 +3595,8 @@ static int nwrap_files_gethostbyname(const char *name, int af,
 
        name_len = strlen(name);
        if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
-               strncpy(canon_name, name, name_len - 1);
+               memcpy(canon_name, name, name_len - 1);
+               canon_name[name_len] = '\0';
                name = canon_name;
        }
 
@@ -3479,15 +3671,22 @@ no_ent:
        return -1;
 }
 
-#ifdef HAVE_GETHOSTBYNAME_R
-static int nwrap_gethostbyname_r(const char *name,
-                                struct hostent *ret,
-                                char *buf, size_t buflen,
-                                struct hostent **result, int *h_errnop)
+static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
+                                       const char *name, int af,
+                                       struct hostent *hedst,
+                                       char *buf, size_t buflen,
+                                       struct hostent **hedstp)
 {
        struct nwrap_vector *addr_list = malloc(sizeof(struct nwrap_vector));
+       union {
+               char *ptr;
+               char **list;
+       } g;
        int rc;
 
+       (void) b; /* unused */
+       (void) af; /* unused */
+
        if (addr_list == NULL) {
                NWRAP_LOG(NWRAP_LOG_ERROR,
                          "Unable to allocate memory for address list");
@@ -3497,9 +3696,9 @@ static int nwrap_gethostbyname_r(const char *name,
 
        ZERO_STRUCTP(addr_list);
 
-       rc = nwrap_files_gethostbyname(name, AF_UNSPEC, ret, addr_list);
+       rc = nwrap_files_internal_gethostbyname(name, AF_UNSPEC, hedst,
+                                               addr_list);
        if (rc == -1) {
-               *h_errnop = h_errno;
                if (addr_list->items != NULL) {
                        free(addr_list->items);
                }
@@ -3522,11 +3721,33 @@ static int nwrap_gethostbyname_r(const char *name,
        free(addr_list->items);
        free(addr_list);
 
-       ret->h_addr_list = (char **)buf;
-       *result = ret;
+       g.ptr = buf;
+       hedst->h_addr_list = g.list;
+       *hedstp = hedst;
        return 0;
 }
 
+#ifdef HAVE_GETHOSTBYNAME_R
+static int nwrap_gethostbyname_r(const char *name,
+                                struct hostent *ret,
+                                char *buf, size_t buflen,
+                                struct hostent **result, int *h_errnop)
+{
+       int rc;
+       size_t i;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               rc = b->ops->nw_gethostbyname2_r(b, name, AF_UNSPEC, ret,
+                                                buf, buflen, result);
+               if (rc == 0) {
+                       return 0;
+               }
+       }
+       *h_errnop = h_errno;
+       return ENOENT;
+}
+
 int gethostbyname_r(const char *name,
                    struct hostent *ret,
                    char *buf, size_t buflen,
@@ -3545,23 +3766,60 @@ int gethostbyname_r(const char *name,
 }
 #endif
 
+#ifdef HAVE_GETHOSTBYNAME2_R
+static int nwrap_gethostbyname2_r(const char *name, int af,
+                                struct hostent *ret,
+                                char *buf, size_t buflen,
+                                struct hostent **result, int *h_errnop)
+{
+       int rc;
+       size_t i;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               rc = b->ops->nw_gethostbyname2_r(b, name, af, ret,
+                                                buf, buflen, result);
+               if (rc == 0) {
+                       return 0;
+               }
+       }
+       *h_errnop = h_errno;
+       return ENOENT;
+}
+
+int gethostbyname2_r(const char *name, int af,
+                    struct hostent *ret,
+                    char *buf, size_t buflen,
+                    struct hostent **result, int *h_errnop)
+{
+       if (!nss_wrapper_hosts_enabled()) {
+               return libc_gethostbyname2_r(name, af, ret, buf, buflen,
+                                            result, h_errnop);
+       }
+
+       return nwrap_gethostbyname2_r(name, af, ret, buf, buflen, result,
+                                     h_errnop);
+}
+#endif
+
 static int nwrap_files_getaddrinfo(const char *name,
                                   unsigned short port,
                                   const struct addrinfo *hints,
-                                  struct addrinfo **ai,
-                                  struct addrinfo **ai_tail)
+                                  struct addrinfo **ai)
 {
        struct nwrap_entlist *el;
        struct hostent *he;
-       struct addrinfo *_ai = NULL;
        struct addrinfo *ai_head = NULL;
-       struct addrinfo *ai_prev = NULL;
+       struct addrinfo *ai_cur = NULL;
        char *h_name_lower;
        size_t name_len;
        char canon_name[DNS_NAME_MAX] = { 0 };
        bool skip_canonname = false;
-       ENTRY e = { 0 };
+       ENTRY e = {
+               .key = NULL,
+       };
        ENTRY *e_p = NULL;
+       int rc;
        bool ok;
 
        ok = nwrap_files_cache_reload(nwrap_he_global.cache);
@@ -3571,8 +3829,9 @@ static int nwrap_files_getaddrinfo(const char *name,
        }
 
        name_len = strlen(name);
-       if (name_len < DNS_NAME_MAX && name[name_len - 1] == '.') {
-               strncpy(canon_name, name, name_len - 1);
+       if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
+               memcpy(canon_name, name, name_len - 1);
+               canon_name[name_len] = '\0';
                name = canon_name;
        }
 
@@ -3595,45 +3854,59 @@ static int nwrap_files_getaddrinfo(const char *name,
        NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
        SAFE_FREE(h_name_lower);
 
+       rc = EAI_NONAME;
        for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
        {
-               int rc;
+               int rc2;
+               struct addrinfo *ai_new = NULL;
 
                he = &(el->ed->ht);
 
                if (hints->ai_family != AF_UNSPEC &&
-                   he->h_addrtype != hints->ai_family) {
+                   he->h_addrtype != hints->ai_family)
+               {
+                       NWRAP_LOG(NWRAP_LOG_DEBUG,
+                                 "Entry found but with wrong AF - "
+                                 "remembering EAI_ADDRINFO.");
+                       rc = EAI_ADDRFAMILY;
                        continue;
                }
 
                /* Function allocates memory and returns it in ai. */
-               rc = nwrap_convert_he_ai(he,
+               rc2 = nwrap_convert_he_ai(he,
                                         port,
                                         hints,
-                                        &_ai,
+                                        &ai_new,
                                         skip_canonname);
-               if (rc != 0) {
-                       NWRAP_LOG(NWRAP_LOG_ERROR,
-                                 "Error in converting he to ai! Skipping.");
-                       return rc;
+               if (rc2 != 0) {
+                       NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
+                       if (ai_head != NULL) {
+                               freeaddrinfo(ai_head);
+                       }
+                       return rc2;
                }
                skip_canonname = true;
 
                if (ai_head == NULL) {
-                       ai_head = _ai;
+                       ai_head = ai_new;
                }
-               if (ai_prev != NULL) {
-                       ai_prev->ai_next = _ai;
+               if (ai_cur != NULL) {
+                       ai_cur->ai_next = ai_new;
                }
-               ai_prev = _ai;
+               ai_cur = ai_new;
+       }
+
+       if (ai_head != NULL) {
+               rc = 0;
        }
 
        *ai = ai_head;
-       *ai_tail = _ai;
-       return 0;
+
+       return rc;
 }
 
-static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
+static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
+                                                const void *addr,
                                                 socklen_t len, int type)
 {
        struct hostent *he;
@@ -3643,6 +3916,7 @@ static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
        size_t i;
        bool ok;
 
+       (void) b; /* unused */
        (void) len; /* unused */
 
        ok = nwrap_files_cache_reload(nwrap_he_global.cache);
@@ -3657,7 +3931,7 @@ static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
                return NULL;
        }
 
-       nwrap_vector_foreach(ed, nwrap_he_global.entdata, i)
+       nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
        {
                he = &(ed->ht);
                if (he->h_addrtype != type) {
@@ -3679,15 +3953,23 @@ static int nwrap_gethostbyaddr_r(const void *addr, socklen_t len, int type,
                                 char *buf, size_t buflen,
                                 struct hostent **result, int *h_errnop)
 {
-       *result = nwrap_files_gethostbyaddr(addr, len, type);
+       size_t i;
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               *result = b->ops->nw_gethostbyaddr(b, addr, len, type);
+               if (*result != NULL) {
+                       break;
+               }
+       }
+
        if (*result != NULL) {
                memset(buf, '\0', buflen);
                *ret = **result;
                return 0;
-       } else {
-               *h_errnop = h_errno;
-               return -1;
        }
+
+       *h_errnop = h_errno;
+       return -1;
 }
 
 int gethostbyaddr_r(const void *addr, socklen_t len, int type,
@@ -3735,7 +4017,7 @@ static struct hostent *nwrap_files_gethostent(void)
                return NULL;
        }
 
-       he = &((struct nwrap_entdata *)nwrap_he_global.entdata.items[nwrap_he_global.idx++])->ht;
+       he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
 
        NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
 
@@ -3780,9 +4062,7 @@ static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) b; /* unused */
-       (void) pwdst; /* unused */
-       (void) pwdstp; /* unused */
+       *pwdstp = NULL;
 
        if (!b->fns->_nss_getpwnam_r) {
                return NSS_STATUS_NOTFOUND;
@@ -3791,6 +4071,7 @@ static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *pwdstp = pwdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -3837,7 +4118,7 @@ static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) pwdstp; /* unused */
+       *pwdstp = NULL;
 
        if (!b->fns->_nss_getpwuid_r) {
                return ENOENT;
@@ -3846,6 +4127,7 @@ static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *pwdstp = pwdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -3900,7 +4182,7 @@ static int nwrap_module_getpwent_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) pwdstp; /* unused */
+       *pwdstp = NULL;
 
        if (!b->fns->_nss_getpwent_r) {
                return ENOENT;
@@ -3909,6 +4191,7 @@ static int nwrap_module_getpwent_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *pwdstp = pwdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -3993,7 +4276,7 @@ static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) grdstp; /* unused */
+       *grdstp = NULL;
 
        if (!b->fns->_nss_getgrnam_r) {
                return ENOENT;
@@ -4002,6 +4285,7 @@ static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *grdstp = grdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -4064,7 +4348,7 @@ static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) grdstp; /* unused */
+       *grdstp = NULL;
 
        if (!b->fns->_nss_getgrgid_r) {
                return ENOENT;
@@ -4073,6 +4357,7 @@ static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *grdstp = grdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -4143,7 +4428,7 @@ static int nwrap_module_getgrent_r(struct nwrap_backend *b,
 {
        int ret;
 
-       (void) grdstp; /* unused */
+       *grdstp = NULL;
 
        if (!b->fns->_nss_getgrent_r) {
                return ENOENT;
@@ -4152,6 +4437,7 @@ static int nwrap_module_getgrent_r(struct nwrap_backend *b,
        ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
        switch (ret) {
        case NSS_STATUS_SUCCESS:
+               *grdstp = grdst;
                return 0;
        case NSS_STATUS_NOTFOUND:
                if (errno != 0) {
@@ -4180,27 +4466,203 @@ static void nwrap_module_endgrent(struct nwrap_backend *b)
        b->fns->_nss_endgrent();
 }
 
-/****************************************************************************
- *   GETPWNAM
- ***************************************************************************/
-
-static struct passwd *nwrap_getpwnam(const char *name)
+static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
+                                                 const void *addr,
+                                                 socklen_t len, int type)
 {
-       int i;
-       struct passwd *pwd;
+       static struct hostent he;
+       static char *buf = NULL;
+       static size_t buflen = 1000;
+       NSS_STATUS status;
 
-       for (i=0; i < nwrap_main_global->num_backends; i++) {
-               struct nwrap_backend *b = &nwrap_main_global->backends[i];
-               pwd = b->ops->nw_getpwnam(b, name);
-               if (pwd) {
-                       return pwd;
-               }
+       if (b->fns->_nss_gethostbyaddr_r == NULL) {
+               return NULL;
        }
 
-       return NULL;
-}
+       if (buf == NULL) {
+               buf = (char *)malloc(buflen);
+               if (buf == NULL) {
+                       return NULL;
+               }
+       }
+again:
+       status = b->fns->_nss_gethostbyaddr_r(addr, len, type, &he,
+                                             buf, buflen, &errno, &h_errno);
+       if (status == NSS_STATUS_TRYAGAIN) {
+               char *p = NULL;
 
-struct passwd *getpwnam(const char *name)
+               buflen *= 2;
+               p = (char *)realloc(buf, buflen);
+               if (p == NULL) {
+                       SAFE_FREE(buf);
+                       return NULL;
+               }
+               buf = p;
+               goto again;
+       }
+       if (status == NSS_STATUS_NOTFOUND) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+
+       return &he;
+}
+
+static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
+                                        const char *name, int af,
+                                        struct hostent *hedst,
+                                        char *buf, size_t buflen,
+                                        struct hostent **hedstp)
+{
+       NSS_STATUS status;
+
+       *hedstp = NULL;
+
+       if (b->fns->_nss_gethostbyname2_r == NULL) {
+               return ENOENT;
+       }
+
+       status = b->fns->_nss_gethostbyname2_r(name, af, hedst,
+                                              buf, buflen, &errno, &h_errno);
+       switch (status) {
+       case NSS_STATUS_SUCCESS:
+               *hedstp = hedst;
+               return 0;
+       case NSS_STATUS_NOTFOUND:
+               if (errno != 0) {
+                       return errno;
+               }
+               return ENOENT;
+       case NSS_STATUS_TRYAGAIN:
+               if (errno != 0) {
+                       return errno;
+               }
+               return ERANGE;
+       default:
+               if (errno != 0) {
+                       return errno;
+               }
+               return status;
+       }
+}
+
+static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
+                                                 const char *name)
+{
+       static struct hostent he;
+       static char *buf = NULL;
+       static size_t buflen = 1000;
+       NSS_STATUS status;
+
+       if (b->fns->_nss_gethostbyname2_r == NULL) {
+               return NULL;
+       }
+
+       if (buf == NULL) {
+               buf = (char *)malloc(buflen);
+               if (buf == NULL) {
+                       return NULL;
+               }
+       }
+
+again:
+       status = b->fns->_nss_gethostbyname2_r(name, AF_UNSPEC, &he,
+                                              buf, buflen, &errno, &h_errno);
+       if (status == NSS_STATUS_TRYAGAIN) {
+               char *p = NULL;
+
+               buflen *= 2;
+               p = (char *)realloc(buf, buflen);
+               if (p == NULL) {
+                       SAFE_FREE(buf);
+                       return NULL;
+               }
+               buf = p;
+               goto again;
+       }
+       if (status == NSS_STATUS_NOTFOUND) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+
+       return &he;
+}
+
+static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
+                                                  const char *name, int af)
+{
+       static struct hostent he;
+       static char *buf = NULL;
+       static size_t buflen = 1000;
+       NSS_STATUS status;
+
+       if (b->fns->_nss_gethostbyname2_r == NULL) {
+               return NULL;
+       }
+
+       if (buf == NULL) {
+               buf = (char *)malloc(buflen);
+               if (buf == NULL) {
+                       return NULL;
+               }
+       }
+
+again:
+       status = b->fns->_nss_gethostbyname2_r(name, af, &he,
+                                              buf, buflen, &errno, &h_errno);
+       if (status == NSS_STATUS_TRYAGAIN) {
+               char *p = NULL;
+
+               buflen *= 2;
+               p = (char *)realloc(buf, buflen);
+               if (p == NULL) {
+                       SAFE_FREE(buf);
+                       return NULL;
+               }
+               buf = p;
+               goto again;
+       }
+       if (status == NSS_STATUS_NOTFOUND) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+
+       return &he;
+}
+
+/****************************************************************************
+ *   GETPWNAM
+ ***************************************************************************/
+
+static struct passwd *nwrap_getpwnam(const char *name)
+{
+       size_t i;
+       struct passwd *pwd;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               pwd = b->ops->nw_getpwnam(b, name);
+               if (pwd) {
+                       return pwd;
+               }
+       }
+
+       return NULL;
+}
+
+struct passwd *getpwnam(const char *name)
 {
        if (!nss_wrapper_enabled()) {
                return libc_getpwnam(name);
@@ -4216,7 +4678,8 @@ struct passwd *getpwnam(const char *name)
 static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
                            char *buf, size_t buflen, struct passwd **pwdstp)
 {
-       int i,ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4253,7 +4716,7 @@ int getpwnam_r(const char *name, struct passwd *pwdst,
 
 static struct passwd *nwrap_getpwuid(uid_t uid)
 {
-       int i;
+       size_t i;
        struct passwd *pwd;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
@@ -4283,7 +4746,8 @@ struct passwd *getpwuid(uid_t uid)
 static int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
                            char *buf, size_t buflen, struct passwd **pwdstp)
 {
-       int i,ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4318,7 +4782,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwdst,
 
 static void nwrap_setpwent(void)
 {
-       int i;
+       size_t i;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4342,7 +4806,7 @@ void setpwent(void)
 
 static struct passwd *nwrap_getpwent(void)
 {
-       int i;
+       size_t i;
        struct passwd *pwd;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
@@ -4369,10 +4833,12 @@ struct passwd *getpwent(void)
  *   GETPWENT_R
  ***************************************************************************/
 
+#ifdef HAVE_GETPWENT_R
 static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
                            size_t buflen, struct passwd **pwdstp)
 {
-       int i,ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4386,7 +4852,7 @@ static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
        return ENOENT;
 }
 
-#ifdef HAVE_SOLARIS_GETPWENT_R
+#  ifdef HAVE_SOLARIS_GETPWENT_R
 struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
 {
        struct passwd *pwdstp = NULL;
@@ -4402,7 +4868,7 @@ struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
 
        return pwdstp;
 }
-#else /* HAVE_SOLARIS_GETPWENT_R */
+#  else /* HAVE_SOLARIS_GETPWENT_R */
 int getpwent_r(struct passwd *pwdst, char *buf,
               size_t buflen, struct passwd **pwdstp)
 {
@@ -4412,7 +4878,8 @@ int getpwent_r(struct passwd *pwdst, char *buf,
 
        return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
 }
-#endif /* HAVE_SOLARIS_GETPWENT_R */
+#  endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
 
 /****************************************************************************
  *   ENDPWENT
@@ -4420,7 +4887,7 @@ int getpwent_r(struct passwd *pwdst, char *buf,
 
 static void nwrap_endpwent(void)
 {
-       int i;
+       size_t i;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4444,7 +4911,7 @@ void endpwent(void)
 
 static int nwrap_initgroups(const char *user, gid_t group)
 {
-       int i;
+       size_t i;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4475,7 +4942,7 @@ int initgroups(const char *user, gid_t group)
 
 static struct group *nwrap_getgrnam(const char *name)
 {
-       int i;
+       size_t i;
        struct group *grp;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
@@ -4505,7 +4972,8 @@ struct group *getgrnam(const char *name)
 static int nwrap_getgrnam_r(const char *name, struct group *grdst,
                            char *buf, size_t buflen, struct group **grdstp)
 {
-       int i, ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4546,7 +5014,7 @@ int getgrnam_r(const char *name, struct group *grp,
 
 static struct group *nwrap_getgrgid(gid_t gid)
 {
-       int i;
+       size_t i;
        struct group *grp;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
@@ -4576,7 +5044,8 @@ struct group *getgrgid(gid_t gid)
 static int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
                            char *buf, size_t buflen, struct group **grdstp)
 {
-       int i,ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4613,7 +5082,7 @@ int getgrgid_r(gid_t gid, struct group *grdst,
 
 static void nwrap_setgrent(void)
 {
-       int i;
+       size_t i;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4648,7 +5117,7 @@ out:
 
 static struct group *nwrap_getgrent(void)
 {
-       int i;
+       size_t i;
        struct group *grp;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
@@ -4675,10 +5144,12 @@ struct group *getgrent(void)
  *   GETGRENT_R
  ***************************************************************************/
 
+#ifdef HAVE_GETGRENT_R
 static int nwrap_getgrent_r(struct group *grdst, char *buf,
                            size_t buflen, struct group **grdstp)
 {
-       int i,ret;
+       size_t i;
+       int ret;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4692,7 +5163,7 @@ static int nwrap_getgrent_r(struct group *grdst, char *buf,
        return ENOENT;
 }
 
-#ifdef HAVE_SOLARIS_GETGRENT_R
+#  ifdef HAVE_SOLARIS_GETGRENT_R
 struct group *getgrent_r(struct group *src, char *buf, int buflen)
 {
        struct group *grdstp = NULL;
@@ -4709,7 +5180,7 @@ struct group *getgrent_r(struct group *src, char *buf, int buflen)
 
        return grdstp;
 }
-#else /* HAVE_SOLARIS_GETGRENT_R */
+#  else /* HAVE_SOLARIS_GETGRENT_R */
 int getgrent_r(struct group *src, char *buf,
               size_t buflen, struct group **grdstp)
 {
@@ -4719,7 +5190,8 @@ int getgrent_r(struct group *src, char *buf,
 
        return nwrap_getgrent_r(src, buf, buflen, grdstp);
 }
-#endif /* HAVE_SOLARIS_GETGRENT_R */
+#  endif /* HAVE_SOLARIS_GETGRENT_R */
+#endif /* HAVE_GETGRENT_R */
 
 /****************************************************************************
  *   ENDGRENT
@@ -4727,7 +5199,7 @@ int getgrent_r(struct group *src, char *buf,
 
 static void nwrap_endgrent(void)
 {
-       int i;
+       size_t i;
 
        for (i=0; i < nwrap_main_global->num_backends; i++) {
                struct nwrap_backend *b = &nwrap_main_global->backends[i];
@@ -4969,6 +5441,7 @@ void endhostent(void)
 }
 #endif /* HAVE_SOLARIS_ENDHOSTENT */
 
+
 #ifdef BSD
 /* BSD implementation stores data in thread local storage but GLIBC does not */
 static __thread struct hostent user_he;
@@ -4977,12 +5450,37 @@ static __thread struct nwrap_vector user_addrlist;
 static struct hostent user_he;
 static struct nwrap_vector user_addrlist;
 #endif /* BSD */
+
+static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
+                                                const char *name)
+{
+       int ret;
+
+       (void) b; /* unused */
+
+       ret = nwrap_files_internal_gethostbyname(name, AF_UNSPEC, &user_he,
+                                                &user_addrlist);
+       if (ret == 0) {
+               return &user_he;
+       }
+
+       return NULL;
+}
+
 static struct hostent *nwrap_gethostbyname(const char *name)
 {
-       if (nwrap_files_gethostbyname(name, AF_UNSPEC, &user_he, &user_addrlist) == -1) {
-               return NULL;
+       size_t i;
+       struct hostent *he = NULL;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               he = b->ops->nw_gethostbyname(b, name);
+               if (he != NULL) {
+                       return he;
+               }
        }
-       return &user_he;
+
+       return NULL;
 }
 
 struct hostent *gethostbyname(const char *name)
@@ -5004,12 +5502,37 @@ static __thread struct nwrap_vector user_addrlist2;
 static struct hostent user_he2;
 static struct nwrap_vector user_addrlist2;
 #endif /* BSD */
+
+static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
+                                                 const char *name, int af)
+{
+       int ret;
+
+       (void) b; /* unused */
+
+       ret = nwrap_files_internal_gethostbyname(name, af, &user_he2,
+                                                &user_addrlist2);
+       if (ret == 0) {
+               return &user_he2;
+       }
+
+       return NULL;
+}
+
 static struct hostent *nwrap_gethostbyname2(const char *name, int af)
 {
-       if (nwrap_files_gethostbyname(name, af, &user_he2, &user_addrlist2) == -1) {
-               return NULL;
+       size_t i;
+       struct hostent *he = NULL;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               he = b->ops->nw_gethostbyname2(b, name, af);
+               if (he != NULL) {
+                       return he;
+               }
        }
-       return &user_he2;
+
+       return NULL;
 }
 
 struct hostent *gethostbyname2(const char *name, int af)
@@ -5025,7 +5548,18 @@ struct hostent *gethostbyname2(const char *name, int af)
 static struct hostent *nwrap_gethostbyaddr(const void *addr,
                                           socklen_t len, int type)
 {
-       return nwrap_files_gethostbyaddr(addr, len, type);
+       size_t i;
+       struct hostent *he = NULL;
+
+       for (i=0; i < nwrap_main_global->num_backends; i++) {
+               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+               he = b->ops->nw_gethostbyaddr(b, addr, len, type);
+               if (he != NULL) {
+                       return he;
+               }
+       }
+
+       return NULL;
 }
 
 struct hostent *gethostbyaddr(const void *addr,
@@ -5081,12 +5615,23 @@ static int nwrap_convert_he_ai(const struct hostent *he,
                return EAI_MEMORY;
        }
 
-       ai->ai_flags = 0;
+       ai->ai_flags = hints->ai_flags;
        ai->ai_family = he->h_addrtype;
        ai->ai_socktype = hints->ai_socktype;
        ai->ai_protocol = hints->ai_protocol;
        ai->ai_canonname = NULL;
 
+       if (ai->ai_socktype == 0) {
+               ai->ai_socktype = SOCK_DGRAM;
+       }
+       if (ai->ai_protocol == 0) {
+               if (ai->ai_socktype == SOCK_DGRAM) {
+                       ai->ai_protocol = IPPROTO_UDP;
+               } else if (ai->ai_socktype == SOCK_STREAM) {
+                       ai->ai_protocol = IPPROTO_TCP;
+               }
+       }
+
        ai->ai_addrlen = socklen;
        ai->ai_addr = (void *)(ai + 1);
 
@@ -5098,31 +5643,43 @@ static int nwrap_convert_he_ai(const struct hostent *he,
        switch (he->h_addrtype) {
                case AF_INET:
                {
-                       struct sockaddr_in *sinp =
-                               (struct sockaddr_in *) ai->ai_addr;
+                       union {
+                               struct sockaddr *sa;
+                               struct sockaddr_in *in;
+                       } addr;
 
-                       memset(sinp, 0, sizeof(struct sockaddr_in));
+                       addr.sa = ai->ai_addr;
 
-                       sinp->sin_port = htons(port);
-                       sinp->sin_family = AF_INET;
+                       memset(addr.in, 0, sizeof(struct sockaddr_in));
 
-                       memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
-                       memcpy(&sinp->sin_addr, he->h_addr_list[0], he->h_length);
+                       addr.in->sin_port = htons(port);
+                       addr.in->sin_family = AF_INET;
+
+                       memset(addr.in->sin_zero,
+                              '\0',
+                              sizeof (addr.in->sin_zero));
+                       memcpy(&(addr.in->sin_addr),
+                              he->h_addr_list[0],
+                              he->h_length);
 
                }
                break;
 #ifdef HAVE_IPV6
                case AF_INET6:
                {
-                       struct sockaddr_in6 *sin6p =
-                               (struct sockaddr_in6 *) ai->ai_addr;
+                       union {
+                               struct sockaddr *sa;
+                               struct sockaddr_in6 *in6;
+                       } addr;
+
+                       addr.sa = ai->ai_addr;
 
-                       memset(sin6p, 0, sizeof(struct sockaddr_in6));
+                       memset(addr.in6, 0, sizeof(struct sockaddr_in6));
 
-                       sin6p->sin6_port = htons(port);
-                       sin6p->sin6_family = AF_INET6;
+                       addr.in6->sin6_port = htons(port);
+                       addr.in6->sin6_family = AF_INET6;
 
-                       memcpy(&sin6p->sin6_addr,
+                       memcpy(&addr.in6->sin6_addr,
                               he->h_addr_list[0],
                               he->h_length);
                }
@@ -5150,7 +5707,6 @@ static int nwrap_getaddrinfo(const char *node,
                             struct addrinfo **res)
 {
        struct addrinfo *ai = NULL;
-       struct addrinfo *ai_tail;
        unsigned short port = 0;
        struct {
                int family;
@@ -5227,11 +5783,10 @@ static int nwrap_getaddrinfo(const char *node,
        }
 
 valid_port:
-       if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET) {
-               rc = inet_pton(AF_INET, node, &addr.in.v4);
-               if (rc == 1) {
-                       addr.family = AF_INET;
-               }
+
+       rc = inet_pton(AF_INET, node, &addr.in.v4);
+       if (rc == 1) {
+               addr.family = AF_INET;
        }
 #ifdef HAVE_IPV6
        if (addr.family == AF_UNSPEC) {
@@ -5242,7 +5797,17 @@ valid_port:
        }
 #endif
 
-       rc = nwrap_files_getaddrinfo(node, port, hints, &ai, &ai_tail);
+       if (addr.family == AF_UNSPEC) {
+              if (hints->ai_flags & AI_NUMERICHOST) {
+                       return EAI_NONAME;
+               }
+       } else if ((hints->ai_family != AF_UNSPEC) &&
+                  (hints->ai_family != addr.family))
+       {
+               return EAI_ADDRFAMILY;
+       }
+
+       rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
        if (rc != 0) {
                int ret;
                struct addrinfo *p = NULL;
@@ -5261,60 +5826,55 @@ valid_port:
                return rc;
        }
 
-       if (ai->ai_flags == 0) {
-               ai->ai_flags = hints->ai_flags;
-       }
-       if (ai->ai_socktype == 0) {
-               ai->ai_socktype = SOCK_DGRAM;
-       }
-       if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_DGRAM) {
-               ai->ai_protocol = 17; /* UDP */
-       } else if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_STREAM) {
-               ai->ai_protocol = 6; /* TCP */
-       }
-
+       /*
+        * If the socktype was not specified, duplicate
+        * each ai returned, so that we have variants for
+        * both UDP and TCP.
+        */
        if (hints->ai_socktype == 0) {
-               /* Add second ai */
-               struct addrinfo *ai_head = ai;
-               struct addrinfo *ai_tmp;
-               struct addrinfo *ai_new_tail = ai_tail;
-
-               /* Add at least one more struct */
-               do {
-                       /* CHECKS! */
-                       ai_tmp = malloc(sizeof(struct addrinfo));
-                       memcpy(ai_tmp, ai_head, sizeof(struct addrinfo));
-                       ai_tmp->ai_next = NULL;
+               struct addrinfo *ai_cur;
 
-                       /* We need a deep copy or freeaddrinfo() will blow up */
-                       if (ai_head->ai_canonname != NULL) {
-                               ai_tmp->ai_canonname =
-                                       strdup(ai_head->ai_canonname);
+               /* freeaddrinfo() frees ai_canonname and ai so allocate them */
+               for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
+                       struct addrinfo *ai_new;
+
+                       /* duplicate the current entry */
+
+                       ai_new = malloc(sizeof(struct addrinfo));
+                       if (ai_new == NULL) {
+                               freeaddrinfo(ai);
+                               return EAI_MEMORY;
                        }
-                       /* ai_head should point inside hints. */
-                       ai_tmp->ai_addr = ai_head->ai_addr;
 
-                       if (ai_head->ai_flags == 0) {
-                               ai_tmp->ai_flags = hints->ai_flags;
+                       memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
+                       ai_new->ai_next = NULL;
+
+                       /* We need a deep copy or freeaddrinfo() will blow up */
+                       if (ai_cur->ai_canonname != NULL) {
+                               ai_new->ai_canonname =
+                                       strdup(ai_cur->ai_canonname);
                        }
-                       if (ai_head->ai_socktype == SOCK_DGRAM) {
-                               ai_tmp->ai_socktype = SOCK_STREAM;
-                       } else if (ai_head->ai_socktype == SOCK_STREAM) {
-                               ai_tmp->ai_socktype = SOCK_DGRAM;
+
+                       if (ai_cur->ai_socktype == SOCK_DGRAM) {
+                               ai_new->ai_socktype = SOCK_STREAM;
+                       } else if (ai_cur->ai_socktype == SOCK_STREAM) {
+                               ai_new->ai_socktype = SOCK_DGRAM;
                        }
-                       if (ai_head->ai_socktype == SOCK_DGRAM) {
-                               ai_tmp->ai_protocol = 17; /* UDP */
-                       } else if (ai_head->ai_socktype == SOCK_STREAM) {
-                               ai_tmp->ai_protocol = 6; /* TCP */
+                       if (ai_cur->ai_protocol == IPPROTO_TCP) {
+                               ai_new->ai_protocol = IPPROTO_UDP;
+                       } else if (ai_cur->ai_protocol == IPPROTO_UDP) {
+                               ai_new->ai_protocol = IPPROTO_TCP;
                        }
-                       ai_new_tail->ai_next = ai_tmp;
-                       ai_new_tail = ai_tmp;
 
-                       if (ai_head == ai_tail) {
-                               break;
-                       }
-                       ai_head = ai_head->ai_next;
-               } while (1);
+                       /* now insert the new entry */
+
+                       ai_new->ai_next = ai_cur->ai_next;
+                       ai_cur->ai_next = ai_new;
+
+                       /* and move on (don't duplicate the new entry) */
+
+                       ai_cur = ai_new;
+               }
        }
 
        *res = ai;
@@ -5345,6 +5905,7 @@ static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
        socklen_t addrlen;
        uint16_t port;
        sa_family_t type;
+       size_t i;
 
        if (sa == NULL || salen < sizeof(sa_family_t)) {
                return EAI_FAMILY;
@@ -5356,21 +5917,41 @@ static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
 
        type = sa->sa_family;
        switch (type) {
-       case AF_INET:
-               if (salen < sizeof(struct sockaddr_in))
+       case AF_INET: {
+               union {
+                       const struct sockaddr *sa;
+                       const struct sockaddr_in *in;
+               } a;
+
+               if (salen < sizeof(struct sockaddr_in)) {
                        return EAI_FAMILY;
-               addr = &((const struct sockaddr_in *)sa)->sin_addr;
-               addrlen = sizeof(((const struct sockaddr_in *)sa)->sin_addr);
-               port = ntohs(((const struct sockaddr_in *)sa)->sin_port);
+               }
+
+               a.sa = sa;
+
+               addr = &(a.in->sin_addr);
+               addrlen = sizeof(a.in->sin_addr);
+               port = ntohs(a.in->sin_port);
                break;
+       }
 #ifdef HAVE_IPV6
-       case AF_INET6:
-               if (salen < sizeof(struct sockaddr_in6))
+       case AF_INET6: {
+               union {
+                       const struct sockaddr *sa;
+                       const struct sockaddr_in6 *in6;
+               } a;
+
+               if (salen < sizeof(struct sockaddr_in6)) {
                        return EAI_FAMILY;
-               addr = &((const struct sockaddr_in6 *)sa)->sin6_addr;
-               addrlen = sizeof(((const struct sockaddr_in6 *)sa)->sin6_addr);
-               port = ntohs(((const struct sockaddr_in6 *)sa)->sin6_port);
+               }
+
+               a.sa = sa;
+
+               addr = &(a.in6->sin6_addr);
+               addrlen = sizeof(a.in6->sin6_addr);
+               port = ntohs(a.in6->sin6_port);
                break;
+       }
 #endif
        default:
                return EAI_FAMILY;
@@ -5379,14 +5960,20 @@ static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
        if (host != NULL) {
                he = NULL;
                if ((flags & NI_NUMERICHOST) == 0) {
-                       he = nwrap_files_gethostbyaddr(addr, addrlen, type);
+                       for (i=0; i < nwrap_main_global->num_backends; i++) {
+                               struct nwrap_backend *b = &nwrap_main_global->backends[i];
+                               he = b->ops->nw_gethostbyaddr(b, addr, addrlen, type);
+                               if (he != NULL) {
+                                       break;
+                               }
+                       }
                        if ((flags & NI_NAMEREQD) && (he == NULL || he->h_name == NULL))
                                return EAI_NONAME;
                }
                if (he != NULL && he->h_name != NULL) {
                        if (strlen(he->h_name) >= hostlen)
                                return EAI_OVERFLOW;
-                       strcpy(host, he->h_name);
+                       snprintf(host, hostlen, "%s", he->h_name);
                        if (flags & NI_NOFQDN)
                                host[strcspn(host, ".")] = '\0';
                } else {
@@ -5404,7 +5991,7 @@ static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
                if (service != NULL) {
                        if (strlen(service->s_name) >= servlen)
                                return EAI_OVERFLOW;
-                       strcpy(serv, service->s_name);
+                       snprintf(serv, servlen, "%s", service->s_name);
                } else {
                        if (snprintf(serv, servlen, "%u", port) >= (int) servlen)
                                return EAI_OVERFLOW;
@@ -5464,6 +6051,24 @@ int gethostname(char *name, size_t len)
        return nwrap_gethostname(name, len);
 }
 
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+void nwrap_constructor(void)
+{
+       /*
+        * If we hold a lock and the application forks, then the child
+        * is not able to unlock the mutex and we are in a deadlock.
+        *
+        * Setting these handlers should prevent such deadlocks.
+        */
+       pthread_atfork(&nwrap_thread_prepare,
+                      &nwrap_thread_parent,
+                      &nwrap_thread_child);
+
+       /* Do not call nwrap_init() here. */
+}
+
 /****************************
  * DESTRUCTOR
  ***************************/
@@ -5474,35 +6079,39 @@ int gethostname(char *name, size_t len)
  */
 void nwrap_destructor(void)
 {
-       int i;
+       size_t i;
 
        NWRAP_LOCK_ALL;
        if (nwrap_main_global != NULL) {
                struct nwrap_main *m = nwrap_main_global;
 
                /* libc */
-               SAFE_FREE(m->libc->fns);
-               if (m->libc->handle != NULL) {
-                       dlclose(m->libc->handle);
-               }
-               if (m->libc->nsl_handle != NULL) {
-                       dlclose(m->libc->nsl_handle);
-               }
-               if (m->libc->sock_handle != NULL) {
-                       dlclose(m->libc->sock_handle);
+               if (m->libc != NULL) {
+                       SAFE_FREE(m->libc->fns);
+                       if (m->libc->handle != NULL) {
+                               dlclose(m->libc->handle);
+                       }
+                       if (m->libc->nsl_handle != NULL) {
+                               dlclose(m->libc->nsl_handle);
+                       }
+                       if (m->libc->sock_handle != NULL) {
+                               dlclose(m->libc->sock_handle);
+                       }
+                       SAFE_FREE(m->libc);
                }
-               SAFE_FREE(m->libc);
 
                /* backends */
-               for (i = 0; i < m->num_backends; i++) {
-                       struct nwrap_backend *b = &(m->backends[i]);
+               if (m->backends != NULL) {
+                       for (i = 0; i < m->num_backends; i++) {
+                               struct nwrap_backend *b = &(m->backends[i]);
 
-                       if (b->so_handle != NULL) {
-                               dlclose(b->so_handle);
+                               if (b->so_handle != NULL) {
+                                       dlclose(b->so_handle);
+                               }
+                               SAFE_FREE(b->fns);
                        }
-                       SAFE_FREE(b->fns);
+                       SAFE_FREE(m->backends);
                }
-               SAFE_FREE(m->backends);
        }
 
        if (nwrap_pw_global.cache != NULL) {
@@ -5531,6 +6140,20 @@ void nwrap_destructor(void)
                nwrap_pw_global.num = 0;
        }
 
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+       if (nwrap_sp_global.cache != NULL) {
+               struct nwrap_cache *c = nwrap_sp_global.cache;
+
+               nwrap_files_cache_unload(c);
+               if (c->fd >= 0) {
+                       fclose(c->fp);
+                       c->fd = -1;
+               }
+
+               nwrap_sp_global.num = 0;
+       }
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
        if (nwrap_he_global.cache != NULL) {
                struct nwrap_cache *c = nwrap_he_global.cache;
 
@@ -5543,6 +6166,11 @@ void nwrap_destructor(void)
                nwrap_he_global.num = 0;
        }
 
+       free(user_addrlist.items);
+#ifdef HAVE_GETHOSTBYNAME2
+       free(user_addrlist2.items);
+#endif
+
        hdestroy();
        NWRAP_UNLOCK_ALL;
 }