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