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