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