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