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