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