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