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