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