build: commit all the waf build files in the tree
[nivanova/samba-autobuild/.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  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the author nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifdef _SAMBA_BUILD_
36
37 /* defining this gives us the posix getpwnam_r() calls on solaris
38    Thanks to heimdal for this */
39 #define _POSIX_PTHREAD_SEMANTICS
40
41 #define NSS_WRAPPER_NOT_REPLACE
42 #include "../replace/replace.h"
43 #include "system/passwd.h"
44 #include "system/filesys.h"
45 #include "../nsswitch/nsstest.h"
46
47 #else /* _SAMBA_BUILD_ */
48
49 #error nss_wrapper_only_supported_in_samba_yet
50
51 #endif
52
53 #ifndef _PUBLIC_
54 #define _PUBLIC_
55 #endif
56
57 /* not all systems have _r functions... */
58 #ifndef HAVE_GETPWNAM_R
59 #define getpwnam_r(name, pwdst, buf, buflen, pwdstp)    ENOSYS
60 #endif
61 #ifndef HAVE_GETPWUID_R
62 #define getpwuid_r(uid, pwdst, buf, buflen, pwdstp)     ENOSYS
63 #endif
64 #ifndef HAVE_GETPWENT_R
65 #define getpwent_r(pwdst, buf, buflen, pwdstp)          ENOSYS
66 #endif
67 #ifndef HAVE_GETGRNAM_R
68 #define getgrnam_r(name, grdst, buf, buflen, grdstp)    ENOSYS
69 #endif
70 #ifndef HAVE_GETGRGID_R
71 #define getgrgid_r(gid, grdst, buf, buflen, grdstp)     ENOSYS
72 #endif
73 #ifndef HAVE_GETGRENT_R
74 #define getgrent_r(grdst, buf, buflen, grdstp)          ENOSYS
75 #endif
76
77 /* not all systems have getgrouplist */
78 #ifndef HAVE_GETGROUPLIST
79 #define getgrouplist(user, group, groups, ngroups)      0
80 #endif
81
82 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
83  * for now */
84 #define REWRITE_CALLS
85
86 #ifdef REWRITE_CALLS
87
88 #define real_getpwnam           getpwnam
89 #define real_getpwnam_r         getpwnam_r
90 #define real_getpwuid           getpwuid
91 #define real_getpwuid_r         getpwuid_r
92
93 #define real_setpwent           setpwent
94 #define real_getpwent           getpwent
95 #define real_getpwent_r         getpwent_r
96 #define real_endpwent           endpwent
97
98 /*
99 #define real_getgrlst           getgrlst
100 #define real_getgrlst_r         getgrlst_r
101 #define real_initgroups_dyn     initgroups_dyn
102 */
103 #define real_initgroups         initgroups
104 #define real_getgrouplist       getgrouplist
105
106 #define real_getgrnam           getgrnam
107 #define real_getgrnam_r         getgrnam_r
108 #define real_getgrgid           getgrgid
109 #define real_getgrgid_r         getgrgid_r
110
111 #define real_setgrent           setgrent
112 #define real_getgrent           getgrent
113 #define real_getgrent_r         getgrent_r
114 #define real_endgrent           endgrent
115
116 #endif
117
118 #if 0
119 # ifdef DEBUG
120 # define NWRAP_ERROR(args)      DEBUG(0, args)
121 # else
122 # define NWRAP_ERROR(args)      printf args
123 # endif
124 #else
125 #define NWRAP_ERROR(args)
126 #endif
127
128 #if 0
129 # ifdef DEBUG
130 # define NWRAP_DEBUG(args)      DEBUG(0, args)
131 # else
132 # define NWRAP_DEBUG(args)      printf args
133 # endif
134 #else
135 #define NWRAP_DEBUG(args)
136 #endif
137
138 #if 0
139 # ifdef DEBUG
140 # define NWRAP_VERBOSE(args)    DEBUG(0, args)
141 # else
142 # define NWRAP_VERBOSE(args)    printf args
143 # endif
144 #else
145 #define NWRAP_VERBOSE(args)
146 #endif
147
148 struct nwrap_module_nss_fns {
149         NSS_STATUS (*_nss_getpwnam_r)(const char *name, struct passwd *result, char *buffer,
150                                       size_t buflen, int *errnop);
151         NSS_STATUS (*_nss_getpwuid_r)(uid_t uid, struct passwd *result, char *buffer,
152                                       size_t buflen, int *errnop);
153         NSS_STATUS (*_nss_setpwent)(void);
154         NSS_STATUS (*_nss_getpwent_r)(struct passwd *result, char *buffer,
155                                       size_t buflen, int *errnop);
156         NSS_STATUS (*_nss_endpwent)(void);
157         NSS_STATUS (*_nss_initgroups)(const char *user, gid_t group, long int *start,
158                                       long int *size, gid_t **groups, long int limit, int *errnop);
159         NSS_STATUS (*_nss_getgrnam_r)(const char *name, struct group *result, char *buffer,
160                                       size_t buflen, int *errnop);
161         NSS_STATUS (*_nss_getgrgid_r)(gid_t gid, struct group *result, char *buffer,
162                                       size_t buflen, int *errnop);
163         NSS_STATUS (*_nss_setgrent)(void);
164         NSS_STATUS (*_nss_getgrent_r)(struct group *result, char *buffer,
165                                       size_t buflen, int *errnop);
166         NSS_STATUS (*_nss_endgrent)(void);
167 };
168
169 struct nwrap_backend {
170         const char *name;
171         const char *so_path;
172         void *so_handle;
173         struct nwrap_ops *ops;
174         struct nwrap_module_nss_fns *fns;
175 };
176
177 struct nwrap_ops {
178         struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
179                                        const char *name);
180         int             (*nw_getpwnam_r)(struct nwrap_backend *b,
181                                          const char *name, struct passwd *pwdst,
182                                          char *buf, size_t buflen, struct passwd **pwdstp);
183         struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
184                                        uid_t uid);
185         int             (*nw_getpwuid_r)(struct nwrap_backend *b,
186                                          uid_t uid, struct passwd *pwdst,
187                                          char *buf, size_t buflen, struct passwd **pwdstp);
188         void            (*nw_setpwent)(struct nwrap_backend *b);
189         struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
190         int             (*nw_getpwent_r)(struct nwrap_backend *b,
191                                          struct passwd *pwdst, char *buf,
192                                          size_t buflen, struct passwd **pwdstp);
193         void            (*nw_endpwent)(struct nwrap_backend *b);
194         int             (*nw_initgroups)(struct nwrap_backend *b,
195                                          const char *user, gid_t group);
196         struct group *  (*nw_getgrnam)(struct nwrap_backend *b,
197                                        const char *name);
198         int             (*nw_getgrnam_r)(struct nwrap_backend *b,
199                                          const char *name, struct group *grdst,
200                                          char *buf, size_t buflen, struct group **grdstp);
201         struct group *  (*nw_getgrgid)(struct nwrap_backend *b,
202                                        gid_t gid);
203         int             (*nw_getgrgid_r)(struct nwrap_backend *b,
204                                          gid_t gid, struct group *grdst,
205                                          char *buf, size_t buflen, struct group **grdstp);
206         void            (*nw_setgrent)(struct nwrap_backend *b);
207         struct group *  (*nw_getgrent)(struct nwrap_backend *b);
208         int             (*nw_getgrent_r)(struct nwrap_backend *b,
209                                          struct group *grdst, char *buf,
210                                          size_t buflen, struct group **grdstp);
211         void            (*nw_endgrent)(struct nwrap_backend *b);
212 };
213
214 /* prototypes for files backend */
215
216
217 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
218                                            const char *name);
219 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
220                                   const char *name, struct passwd *pwdst,
221                                   char *buf, size_t buflen, struct passwd **pwdstp);
222 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
223                                            uid_t uid);
224 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
225                                   uid_t uid, struct passwd *pwdst,
226                                   char *buf, size_t buflen, struct passwd **pwdstp);
227 static void nwrap_files_setpwent(struct nwrap_backend *b);
228 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
229 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
230                                   struct passwd *pwdst, char *buf,
231                                   size_t buflen, struct passwd **pwdstp);
232 static void nwrap_files_endpwent(struct nwrap_backend *b);
233 static int nwrap_files_initgroups(struct nwrap_backend *b,
234                                   const char *user, gid_t group);
235 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
236                                           const char *name);
237 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
238                                   const char *name, struct group *grdst,
239                                   char *buf, size_t buflen, struct group **grdstp);
240 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
241                                           gid_t gid);
242 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
243                                   gid_t gid, struct group *grdst,
244                                   char *buf, size_t buflen, struct group **grdstp);
245 static void nwrap_files_setgrent(struct nwrap_backend *b);
246 static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
247 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
248                                   struct group *grdst, char *buf,
249                                   size_t buflen, struct group **grdstp);
250 static void nwrap_files_endgrent(struct nwrap_backend *b);
251
252 /* prototypes for module backend */
253
254 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
255 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
256                                    struct passwd *pwdst, char *buf,
257                                    size_t buflen, struct passwd **pwdstp);
258 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
259                                             const char *name);
260 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
261                                    const char *name, struct passwd *pwdst,
262                                    char *buf, size_t buflen, struct passwd **pwdstp);
263 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
264                                             uid_t uid);
265 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
266                                    uid_t uid, struct passwd *pwdst,
267                                    char *buf, size_t buflen, struct passwd **pwdstp);
268 static void nwrap_module_setpwent(struct nwrap_backend *b);
269 static void nwrap_module_endpwent(struct nwrap_backend *b);
270 static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
271 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
272                                    struct group *grdst, char *buf,
273                                    size_t buflen, struct group **grdstp);
274 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
275                                            const char *name);
276 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
277                                    const char *name, struct group *grdst,
278                                    char *buf, size_t buflen, struct group **grdstp);
279 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
280                                            gid_t gid);
281 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
282                                    gid_t gid, struct group *grdst,
283                                    char *buf, size_t buflen, struct group **grdstp);
284 static void nwrap_module_setgrent(struct nwrap_backend *b);
285 static void nwrap_module_endgrent(struct nwrap_backend *b);
286 static int nwrap_module_initgroups(struct nwrap_backend *b,
287                                    const char *user, gid_t group);
288
289 struct nwrap_ops nwrap_files_ops = {
290         .nw_getpwnam    = nwrap_files_getpwnam,
291         .nw_getpwnam_r  = nwrap_files_getpwnam_r,
292         .nw_getpwuid    = nwrap_files_getpwuid,
293         .nw_getpwuid_r  = nwrap_files_getpwuid_r,
294         .nw_setpwent    = nwrap_files_setpwent,
295         .nw_getpwent    = nwrap_files_getpwent,
296         .nw_getpwent_r  = nwrap_files_getpwent_r,
297         .nw_endpwent    = nwrap_files_endpwent,
298         .nw_initgroups  = nwrap_files_initgroups,
299         .nw_getgrnam    = nwrap_files_getgrnam,
300         .nw_getgrnam_r  = nwrap_files_getgrnam_r,
301         .nw_getgrgid    = nwrap_files_getgrgid,
302         .nw_getgrgid_r  = nwrap_files_getgrgid_r,
303         .nw_setgrent    = nwrap_files_setgrent,
304         .nw_getgrent    = nwrap_files_getgrent,
305         .nw_getgrent_r  = nwrap_files_getgrent_r,
306         .nw_endgrent    = nwrap_files_endgrent,
307 };
308
309 struct nwrap_ops nwrap_module_ops = {
310         .nw_getpwnam    = nwrap_module_getpwnam,
311         .nw_getpwnam_r  = nwrap_module_getpwnam_r,
312         .nw_getpwuid    = nwrap_module_getpwuid,
313         .nw_getpwuid_r  = nwrap_module_getpwuid_r,
314         .nw_setpwent    = nwrap_module_setpwent,
315         .nw_getpwent    = nwrap_module_getpwent,
316         .nw_getpwent_r  = nwrap_module_getpwent_r,
317         .nw_endpwent    = nwrap_module_endpwent,
318         .nw_initgroups  = nwrap_module_initgroups,
319         .nw_getgrnam    = nwrap_module_getgrnam,
320         .nw_getgrnam_r  = nwrap_module_getgrnam_r,
321         .nw_getgrgid    = nwrap_module_getgrgid,
322         .nw_getgrgid_r  = nwrap_module_getgrgid_r,
323         .nw_setgrent    = nwrap_module_setgrent,
324         .nw_getgrent    = nwrap_module_getgrent,
325         .nw_getgrent_r  = nwrap_module_getgrent_r,
326         .nw_endgrent    = nwrap_module_endgrent,
327 };
328
329 struct nwrap_main {
330         const char *nwrap_switch;
331         int num_backends;
332         struct nwrap_backend *backends;
333 };
334
335 struct nwrap_main *nwrap_main_global;
336 struct nwrap_main __nwrap_main_global;
337
338 struct nwrap_cache {
339         const char *path;
340         int fd;
341         struct stat st;
342         uint8_t *buf;
343         void *private_data;
344         bool (*parse_line)(struct nwrap_cache *, char *line);
345         void (*unload)(struct nwrap_cache *);
346 };
347
348 struct nwrap_pw {
349         struct nwrap_cache *cache;
350
351         struct passwd *list;
352         int num;
353         int idx;
354 };
355
356 struct nwrap_cache __nwrap_cache_pw;
357 struct nwrap_pw nwrap_pw_global;
358
359 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
360 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
361
362 struct nwrap_gr {
363         struct nwrap_cache *cache;
364
365         struct group *list;
366         int num;
367         int idx;
368 };
369
370 struct nwrap_cache __nwrap_cache_gr;
371 struct nwrap_gr nwrap_gr_global;
372
373 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
374 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
375
376 static void *nwrap_load_module_fn(struct nwrap_backend *b,
377                                   const char *fn_name)
378 {
379         void *res;
380         char *s;
381
382         if (!b->so_handle) {
383                 NWRAP_ERROR(("%s: no handle\n",
384                              __location__));
385                 return NULL;
386         }
387
388         if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
389                 NWRAP_ERROR(("%s: out of memory\n",
390                              __location__));
391                 return NULL;
392         }
393
394         res = dlsym(b->so_handle, s);
395         if (!res) {
396                 NWRAP_ERROR(("%s: cannot find function %s in %s\n",
397                              __location__, s, b->so_path));
398         }
399         free(s);
400         s = NULL;
401         return res;
402 }
403
404 static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *b)
405 {
406         struct nwrap_module_nss_fns *fns;
407
408         if (!b->so_handle) {
409                 return NULL;
410         }
411
412         fns = (struct nwrap_module_nss_fns *)malloc(sizeof(struct nwrap_module_nss_fns));
413         if (!fns) {
414                 return NULL;
415         }
416
417         fns->_nss_getpwnam_r    = (NSS_STATUS (*)(const char *, struct passwd *, char *, size_t, int *))
418                                   nwrap_load_module_fn(b, "getpwnam_r");
419         fns->_nss_getpwuid_r    = (NSS_STATUS (*)(uid_t, struct passwd *, char *, size_t, int *))
420                                   nwrap_load_module_fn(b, "getpwuid_r");
421         fns->_nss_setpwent      = (NSS_STATUS(*)(void))
422                                   nwrap_load_module_fn(b, "setpwent");
423         fns->_nss_getpwent_r    = (NSS_STATUS (*)(struct passwd *, char *, size_t, int *))
424                                   nwrap_load_module_fn(b, "getpwent_r");
425         fns->_nss_endpwent      = (NSS_STATUS(*)(void))
426                                   nwrap_load_module_fn(b, "endpwent");
427         fns->_nss_initgroups    = (NSS_STATUS (*)(const char *, gid_t, long int *, long int *, gid_t **, long int, int *))
428                                   nwrap_load_module_fn(b, "initgroups_dyn");
429         fns->_nss_getgrnam_r    = (NSS_STATUS (*)(const char *, struct group *, char *, size_t, int *))
430                                   nwrap_load_module_fn(b, "getgrnam_r");
431         fns->_nss_getgrgid_r    = (NSS_STATUS (*)(gid_t, struct group *, char *, size_t, int *))
432                                   nwrap_load_module_fn(b, "getgrgid_r");
433         fns->_nss_setgrent      = (NSS_STATUS(*)(void))
434                                   nwrap_load_module_fn(b, "setgrent");
435         fns->_nss_getgrent_r    = (NSS_STATUS (*)(struct group *, char *, size_t, int *))
436                                   nwrap_load_module_fn(b, "getgrent_r");
437         fns->_nss_endgrent      = (NSS_STATUS(*)(void))
438                                   nwrap_load_module_fn(b, "endgrent");
439
440         return fns;
441 }
442
443 static void *nwrap_load_module(const char *so_path)
444 {
445         void *h;
446
447         if (!so_path || !strlen(so_path)) {
448                 return NULL;
449         }
450
451         h = dlopen(so_path, RTLD_LAZY);
452         if (!h) {
453                 NWRAP_ERROR(("%s: cannot open shared library %s\n",
454                              __location__, so_path));
455                 return NULL;
456         }
457
458         return h;
459 }
460
461 static bool nwrap_module_init(const char *name,
462                               struct nwrap_ops *ops,
463                               const char *so_path,
464                               int *num_backends,
465                               struct nwrap_backend **backends)
466 {
467         *backends = (struct nwrap_backend *)realloc(*backends,
468                 sizeof(struct nwrap_backend) * ((*num_backends) + 1));
469         if (!*backends) {
470                 NWRAP_ERROR(("%s: out of memory\n",
471                              __location__));
472                 return false;
473         }
474
475         (*backends)[*num_backends].name = name;
476         (*backends)[*num_backends].ops = ops;
477         (*backends)[*num_backends].so_path = so_path;
478         (*backends)[*num_backends].so_handle = nwrap_load_module(so_path);
479         (*backends)[*num_backends].fns = nwrap_load_module_fns(&((*backends)[*num_backends]));
480
481         (*num_backends)++;
482
483         return true;
484 }
485
486 static void nwrap_backend_init(struct nwrap_main *r)
487 {
488         const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH");
489
490         r->num_backends = 0;
491         r->backends = NULL;
492
493         if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
494                                &r->num_backends,
495                                &r->backends)) {
496                 NWRAP_ERROR(("%s: failed to initialize 'files' backend\n",
497                              __location__));
498                 return;
499         }
500
501         if (winbind_so_path && strlen(winbind_so_path)) {
502                 if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path,
503                                        &r->num_backends,
504                                        &r->backends)) {
505                         NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n",
506                                      __location__));
507                         return;
508                 }
509         }
510 }
511
512 static void nwrap_init(void)
513 {
514         static bool initialized;
515
516         if (initialized) return;
517         initialized = true;
518
519         nwrap_main_global = &__nwrap_main_global;
520
521         nwrap_backend_init(nwrap_main_global);
522
523         nwrap_pw_global.cache = &__nwrap_cache_pw;
524
525         nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
526         nwrap_pw_global.cache->fd = -1;
527         nwrap_pw_global.cache->private_data = &nwrap_pw_global;
528         nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
529         nwrap_pw_global.cache->unload = nwrap_pw_unload;
530
531         nwrap_gr_global.cache = &__nwrap_cache_gr;
532
533         nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
534         nwrap_gr_global.cache->fd = -1;
535         nwrap_gr_global.cache->private_data = &nwrap_gr_global;
536         nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
537         nwrap_gr_global.cache->unload = nwrap_gr_unload;
538 }
539
540 static bool nwrap_enabled(void)
541 {
542         nwrap_init();
543
544         if (!nwrap_pw_global.cache->path) {
545                 return false;
546         }
547         if (nwrap_pw_global.cache->path[0] == '\0') {
548                 return false;
549         }
550         if (!nwrap_gr_global.cache->path) {
551                 return false;
552         }
553         if (nwrap_gr_global.cache->path[0] == '\0') {
554                 return false;
555         }
556
557         return true;
558 }
559
560 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
561 {
562         int ret;
563         uint8_t *buf = NULL;
564         char *nline;
565
566         if (nwrap->st.st_size == 0) {
567                 NWRAP_DEBUG(("%s: size == 0\n",
568                              __location__));
569                 goto done;
570         }
571
572         if (nwrap->st.st_size > INT32_MAX) {
573                 NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
574                              __location__, (unsigned)nwrap->st.st_size));
575                 goto failed;
576         }
577
578         ret = lseek(nwrap->fd, 0, SEEK_SET);
579         if (ret != 0) {
580                 NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
581                 goto failed;
582         }
583
584         buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
585         if (!buf) {
586                 NWRAP_ERROR(("%s: malloc failed\n",__location__));
587                 goto failed;
588         }
589
590         ret = read(nwrap->fd, buf, nwrap->st.st_size);
591         if (ret != nwrap->st.st_size) {
592                 NWRAP_ERROR(("%s: read(%u) gave %d\n",
593                              __location__, (unsigned)nwrap->st.st_size, ret));
594                 goto failed;
595         }
596
597         buf[nwrap->st.st_size] = '\0';
598
599         nline = (char *)buf;
600         while (nline && nline[0]) {
601                 char *line;
602                 char *e;
603                 bool ok;
604
605                 line = nline;
606                 nline = NULL;
607
608                 e = strchr(line, '\n');
609                 if (e) {
610                         e[0] = '\0';
611                         e++;
612                         if (e[0] == '\r') {
613                                 e[0] = '\0';
614                                 e++;
615                         }
616                         nline = e;
617                 }
618
619                 NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
620
621                 if (strlen(line) == 0) {
622                         continue;
623                 }
624
625                 ok = nwrap->parse_line(nwrap, line);
626                 if (!ok) {
627                         goto failed;
628                 }
629         }
630
631 done:
632         nwrap->buf = buf;
633         return true;
634
635 failed:
636         if (buf) free(buf);
637         return false;
638 }
639
640 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
641 {
642         nwrap->unload(nwrap);
643
644         if (nwrap->buf) free(nwrap->buf);
645
646         nwrap->buf = NULL;
647 }
648
649 static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
650 {
651         struct stat st;
652         int ret;
653         bool ok;
654         bool retried = false;
655
656 reopen:
657         if (nwrap->fd < 0) {
658                 nwrap->fd = open(nwrap->path, O_RDONLY);
659                 if (nwrap->fd < 0) {
660                         NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
661                                      __location__,
662                                      nwrap->path, nwrap->fd,
663                                      strerror(errno)));
664                         return;
665                 }
666                 NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
667         }
668
669         ret = fstat(nwrap->fd, &st);
670         if (ret != 0) {
671                 NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
672                              __location__,
673                              nwrap->path,
674                              ret, strerror(errno)));
675                 return;
676         }
677
678         if (retried == false && st.st_nlink == 0) {
679                 /* maybe someone has replaced the file... */
680                 NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
681                              __location__, nwrap->path));
682                 retried = true;
683                 memset(&nwrap->st, 0, sizeof(nwrap->st));
684                 close(nwrap->fd);
685                 nwrap->fd = -1;
686                 goto reopen;
687         }
688
689         if (st.st_mtime == nwrap->st.st_mtime) {
690                 NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
691                                __location__, (unsigned)st.st_mtime));
692                 return;
693         }
694         NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
695                      __location__, (unsigned)st.st_mtime,
696                      (unsigned)nwrap->st.st_mtime));
697
698         nwrap->st = st;
699
700         nwrap_files_cache_unload(nwrap);
701
702         ok = nwrap_parse_file(nwrap);
703         if (!ok) {
704                 NWRAP_ERROR(("%s: failed to reload %s\n",
705                              __location__, nwrap->path));
706                 nwrap_files_cache_unload(nwrap);
707         }
708         NWRAP_DEBUG(("%s: reloaded %s\n",
709                      __location__, nwrap->path));
710 }
711
712 /*
713  * the caller has to call nwrap_unload() on failure
714  */
715 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
716 {
717         struct nwrap_pw *nwrap_pw;
718         char *c;
719         char *p;
720         char *e;
721         struct passwd *pw;
722         size_t list_size;
723
724         nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
725
726         list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
727         pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
728         if (!pw) {
729                 NWRAP_ERROR(("%s:realloc(%u) failed\n",
730                              __location__, list_size));
731                 return false;
732         }
733         nwrap_pw->list = pw;
734
735         pw = &nwrap_pw->list[nwrap_pw->num];
736
737         c = line;
738
739         /* name */
740         p = strchr(c, ':');
741         if (!p) {
742                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
743                              __location__, line, c));
744                 return false;
745         }
746         *p = '\0';
747         p++;
748         pw->pw_name = c;
749         c = p;
750
751         NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
752
753         /* password */
754         p = strchr(c, ':');
755         if (!p) {
756                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
757                              __location__, line, c));
758                 return false;
759         }
760         *p = '\0';
761         p++;
762         pw->pw_passwd = c;
763         c = p;
764
765         NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
766
767         /* uid */
768         p = strchr(c, ':');
769         if (!p) {
770                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
771                              __location__, line, c));
772                 return false;
773         }
774         *p = '\0';
775         p++;
776         e = NULL;
777         pw->pw_uid = (uid_t)strtoul(c, &e, 10);
778         if (c == e) {
779                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
780                              __location__, line, c, strerror(errno)));
781                 return false;
782         }
783         if (e == NULL) {
784                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
785                              __location__, line, c, strerror(errno)));
786                 return false;
787         }
788         if (e[0] != '\0') {
789                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
790                              __location__, line, c, strerror(errno)));
791                 return false;
792         }
793         c = p;
794
795         NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
796
797         /* gid */
798         p = strchr(c, ':');
799         if (!p) {
800                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
801                              __location__, line, c));
802                 return false;
803         }
804         *p = '\0';
805         p++;
806         e = NULL;
807         pw->pw_gid = (gid_t)strtoul(c, &e, 10);
808         if (c == e) {
809                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
810                              __location__, line, c, strerror(errno)));
811                 return false;
812         }
813         if (e == NULL) {
814                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
815                              __location__, line, c, strerror(errno)));
816                 return false;
817         }
818         if (e[0] != '\0') {
819                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
820                              __location__, line, c, strerror(errno)));
821                 return false;
822         }
823         c = p;
824
825         NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
826
827         /* gecos */
828         p = strchr(c, ':');
829         if (!p) {
830                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
831                              __location__, line, c));
832                 return false;
833         }
834         *p = '\0';
835         p++;
836         pw->pw_gecos = c;
837         c = p;
838
839         NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
840
841         /* dir */
842         p = strchr(c, ':');
843         if (!p) {
844                 NWRAP_ERROR(("%s:'%s'\n",__location__,c));
845                 return false;
846         }
847         *p = '\0';
848         p++;
849         pw->pw_dir = c;
850         c = p;
851
852         NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
853
854         /* shell */
855         pw->pw_shell = c;
856         NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
857
858         NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
859                      pw->pw_name, pw->pw_passwd,
860                      pw->pw_uid, pw->pw_gid,
861                      pw->pw_gecos, pw->pw_dir, pw->pw_shell));
862
863         nwrap_pw->num++;
864         return true;
865 }
866
867 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
868 {
869         struct nwrap_pw *nwrap_pw;
870         nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
871
872         if (nwrap_pw->list) free(nwrap_pw->list);
873
874         nwrap_pw->list = NULL;
875         nwrap_pw->num = 0;
876         nwrap_pw->idx = 0;
877 }
878
879 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
880                            char *buf, size_t buflen, struct passwd **dstp)
881 {
882         char *first;
883         char *last;
884         off_t ofs;
885
886         first = src->pw_name;
887
888         last = src->pw_shell;
889         while (*last) last++;
890
891         ofs = PTR_DIFF(last + 1, first);
892
893         if (ofs > buflen) {
894                 return ERANGE;
895         }
896
897         memcpy(buf, first, ofs);
898
899         ofs = PTR_DIFF(src->pw_name, first);
900         dst->pw_name = buf + ofs;
901         ofs = PTR_DIFF(src->pw_passwd, first);
902         dst->pw_passwd = buf + ofs;
903         dst->pw_uid = src->pw_uid;
904         dst->pw_gid = src->pw_gid;
905         ofs = PTR_DIFF(src->pw_gecos, first);
906         dst->pw_gecos = buf + ofs;
907         ofs = PTR_DIFF(src->pw_dir, first);
908         dst->pw_dir = buf + ofs;
909         ofs = PTR_DIFF(src->pw_shell, first);
910         dst->pw_shell = buf + ofs;
911
912         if (dstp) {
913                 *dstp = dst;
914         }
915
916         return 0;
917 }
918
919 /*
920  * the caller has to call nwrap_unload() on failure
921  */
922 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
923 {
924         struct nwrap_gr *nwrap_gr;
925         char *c;
926         char *p;
927         char *e;
928         struct group *gr;
929         size_t list_size;
930         unsigned nummem;
931
932         nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
933
934         list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
935         gr = (struct group *)realloc(nwrap_gr->list, list_size);
936         if (!gr) {
937                 NWRAP_ERROR(("%s:realloc failed\n",__location__));
938                 return false;
939         }
940         nwrap_gr->list = gr;
941
942         gr = &nwrap_gr->list[nwrap_gr->num];
943
944         c = line;
945
946         /* name */
947         p = strchr(c, ':');
948         if (!p) {
949                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
950                              __location__, line, c));
951                 return false;
952         }
953         *p = '\0';
954         p++;
955         gr->gr_name = c;
956         c = p;
957
958         NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
959
960         /* password */
961         p = strchr(c, ':');
962         if (!p) {
963                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
964                              __location__, line, c));
965                 return false;
966         }
967         *p = '\0';
968         p++;
969         gr->gr_passwd = c;
970         c = p;
971
972         NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
973
974         /* gid */
975         p = strchr(c, ':');
976         if (!p) {
977                 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
978                              __location__, line, c));
979                 return false;
980         }
981         *p = '\0';
982         p++;
983         e = NULL;
984         gr->gr_gid = (gid_t)strtoul(c, &e, 10);
985         if (c == e) {
986                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
987                              __location__, line, c, strerror(errno)));
988                 return false;
989         }
990         if (e == NULL) {
991                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
992                              __location__, line, c, strerror(errno)));
993                 return false;
994         }
995         if (e[0] != '\0') {
996                 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
997                              __location__, line, c, strerror(errno)));
998                 return false;
999         }
1000         c = p;
1001
1002         NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
1003
1004         /* members */
1005         gr->gr_mem = (char **)malloc(sizeof(char *));
1006         if (!gr->gr_mem) {
1007                 NWRAP_ERROR(("%s:calloc failed\n",__location__));
1008                 return false;
1009         }
1010         gr->gr_mem[0] = NULL;
1011
1012         for(nummem=0; p; nummem++) {
1013                 char **m;
1014                 size_t m_size;
1015                 c = p;
1016                 p = strchr(c, ',');
1017                 if (p) {
1018                         *p = '\0';
1019                         p++;
1020                 }
1021
1022                 if (strlen(c) == 0) {
1023                         break;
1024                 }
1025
1026                 m_size = sizeof(char *) * (nummem+2);
1027                 m = (char **)realloc(gr->gr_mem, m_size);
1028                 if (!m) {
1029                         NWRAP_ERROR(("%s:realloc(%u) failed\n",
1030                                       __location__, m_size));
1031                         return false;
1032                 }
1033                 gr->gr_mem = m;
1034                 gr->gr_mem[nummem] = c;
1035                 gr->gr_mem[nummem+1] = NULL;
1036
1037                 NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
1038         }
1039
1040         NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
1041                      gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
1042
1043         nwrap_gr->num++;
1044         return true;
1045 }
1046
1047 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
1048 {
1049         int i;
1050         struct nwrap_gr *nwrap_gr;
1051         nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
1052
1053         if (nwrap_gr->list) {
1054                 for (i=0; i < nwrap_gr->num; i++) {
1055                         if (nwrap_gr->list[i].gr_mem) {
1056                                 free(nwrap_gr->list[i].gr_mem);
1057                         }
1058                 }
1059                 free(nwrap_gr->list);
1060         }
1061
1062         nwrap_gr->list = NULL;
1063         nwrap_gr->num = 0;
1064         nwrap_gr->idx = 0;
1065 }
1066
1067 static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
1068                            char *buf, size_t buflen, struct group **dstp)
1069 {
1070         char *first;
1071         char **lastm;
1072         char *last = NULL;
1073         off_t ofsb;
1074         off_t ofsm;
1075         off_t ofs;
1076         unsigned i;
1077
1078         first = src->gr_name;
1079
1080         lastm = src->gr_mem;
1081         while (*lastm) {
1082                 last = *lastm;
1083                 lastm++;
1084         }
1085
1086         if (last == NULL) {
1087                 last = src->gr_passwd;
1088         }
1089         while (*last) last++;
1090
1091         ofsb = PTR_DIFF(last + 1, first);
1092         ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
1093
1094         if ((ofsb + ofsm) > buflen) {
1095                 return ERANGE;
1096         }
1097
1098         memcpy(buf, first, ofsb);
1099         memcpy(buf + ofsb, src->gr_mem, ofsm);
1100
1101         ofs = PTR_DIFF(src->gr_name, first);
1102         dst->gr_name = buf + ofs;
1103         ofs = PTR_DIFF(src->gr_passwd, first);
1104         dst->gr_passwd = buf + ofs;
1105         dst->gr_gid = src->gr_gid;
1106
1107         dst->gr_mem = (char **)(buf + ofsb);
1108         for (i=0; src->gr_mem[i]; i++) {
1109                 ofs = PTR_DIFF(src->gr_mem[i], first);
1110                 dst->gr_mem[i] = buf + ofs;
1111         }
1112
1113         if (dstp) {
1114                 *dstp = dst;
1115         }
1116
1117         return 0;
1118 }
1119
1120 /* user functions */
1121 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
1122                                            const char *name)
1123 {
1124         int i;
1125
1126         nwrap_files_cache_reload(nwrap_pw_global.cache);
1127
1128         for (i=0; i<nwrap_pw_global.num; i++) {
1129                 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
1130                         NWRAP_DEBUG(("%s: user[%s] found\n",
1131                                      __location__, name));
1132                         return &nwrap_pw_global.list[i];
1133                 }
1134                 NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
1135                                __location__, name,
1136                                nwrap_pw_global.list[i].pw_name));
1137         }
1138
1139         NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
1140
1141         errno = ENOENT;
1142         return NULL;
1143 }
1144
1145 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
1146                                   const char *name, struct passwd *pwdst,
1147                                   char *buf, size_t buflen, struct passwd **pwdstp)
1148 {
1149         struct passwd *pw;
1150
1151         pw = nwrap_files_getpwnam(b, name);
1152         if (!pw) {
1153                 if (errno == 0) {
1154                         return ENOENT;
1155                 }
1156                 return errno;
1157         }
1158
1159         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1160 }
1161
1162 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
1163                                            uid_t uid)
1164 {
1165         int i;
1166
1167         nwrap_files_cache_reload(nwrap_pw_global.cache);
1168
1169         for (i=0; i<nwrap_pw_global.num; i++) {
1170                 if (nwrap_pw_global.list[i].pw_uid == uid) {
1171                         NWRAP_DEBUG(("%s: uid[%u] found\n",
1172                                      __location__, uid));
1173                         return &nwrap_pw_global.list[i];
1174                 }
1175                 NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
1176                                __location__, uid,
1177                                nwrap_pw_global.list[i].pw_uid));
1178         }
1179
1180         NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
1181
1182         errno = ENOENT;
1183         return NULL;
1184 }
1185
1186 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
1187                                   uid_t uid, struct passwd *pwdst,
1188                                   char *buf, size_t buflen, struct passwd **pwdstp)
1189 {
1190         struct passwd *pw;
1191
1192         pw = nwrap_files_getpwuid(b, uid);
1193         if (!pw) {
1194                 if (errno == 0) {
1195                         return ENOENT;
1196                 }
1197                 return errno;
1198         }
1199
1200         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1201 }
1202
1203 /* user enum functions */
1204 static void nwrap_files_setpwent(struct nwrap_backend *b)
1205 {
1206         nwrap_pw_global.idx = 0;
1207 }
1208
1209 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
1210 {
1211         struct passwd *pw;
1212
1213         if (nwrap_pw_global.idx == 0) {
1214                 nwrap_files_cache_reload(nwrap_pw_global.cache);
1215         }
1216
1217         if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
1218                 errno = ENOENT;
1219                 return NULL;
1220         }
1221
1222         pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
1223
1224         NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
1225                        __location__, pw->pw_name, pw->pw_uid));
1226
1227         return pw;
1228 }
1229
1230 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
1231                                   struct passwd *pwdst, char *buf,
1232                                   size_t buflen, struct passwd **pwdstp)
1233 {
1234         struct passwd *pw;
1235
1236         pw = nwrap_files_getpwent(b);
1237         if (!pw) {
1238                 if (errno == 0) {
1239                         return ENOENT;
1240                 }
1241                 return errno;
1242         }
1243
1244         return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1245 }
1246
1247 static void nwrap_files_endpwent(struct nwrap_backend *b)
1248 {
1249         nwrap_pw_global.idx = 0;
1250 }
1251
1252 /* misc functions */
1253 static int nwrap_files_initgroups(struct nwrap_backend *b,
1254                                   const char *user, gid_t group)
1255 {
1256         /* TODO: maybe we should also fake this... */
1257         return EPERM;
1258 }
1259
1260 /* group functions */
1261 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
1262                                           const char *name)
1263 {
1264         int i;
1265
1266         nwrap_files_cache_reload(nwrap_gr_global.cache);
1267
1268         for (i=0; i<nwrap_gr_global.num; i++) {
1269                 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
1270                         NWRAP_DEBUG(("%s: group[%s] found\n",
1271                                      __location__, name));
1272                         return &nwrap_gr_global.list[i];
1273                 }
1274                 NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
1275                                __location__, name,
1276                                nwrap_gr_global.list[i].gr_name));
1277         }
1278
1279         NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
1280
1281         errno = ENOENT;
1282         return NULL;
1283 }
1284
1285 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
1286                                   const char *name, struct group *grdst,
1287                                   char *buf, size_t buflen, struct group **grdstp)
1288 {
1289         struct group *gr;
1290
1291         gr = nwrap_files_getgrnam(b, name);
1292         if (!gr) {
1293                 if (errno == 0) {
1294                         return ENOENT;
1295                 }
1296                 return errno;
1297         }
1298
1299         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1300 }
1301
1302 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
1303                                           gid_t gid)
1304 {
1305         int i;
1306
1307         nwrap_files_cache_reload(nwrap_gr_global.cache);
1308
1309         for (i=0; i<nwrap_gr_global.num; i++) {
1310                 if (nwrap_gr_global.list[i].gr_gid == gid) {
1311                         NWRAP_DEBUG(("%s: gid[%u] found\n",
1312                                      __location__, gid));
1313                         return &nwrap_gr_global.list[i];
1314                 }
1315                 NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
1316                                __location__, gid,
1317                                nwrap_gr_global.list[i].gr_gid));
1318         }
1319
1320         NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
1321
1322         errno = ENOENT;
1323         return NULL;
1324 }
1325
1326 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
1327                                   gid_t gid, struct group *grdst,
1328                                   char *buf, size_t buflen, struct group **grdstp)
1329 {
1330         struct group *gr;
1331
1332         gr = nwrap_files_getgrgid(b, gid);
1333         if (!gr) {
1334                 if (errno == 0) {
1335                         return ENOENT;
1336                 }
1337                 return errno;
1338         }
1339
1340         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1341 }
1342
1343 /* group enum functions */
1344 static void nwrap_files_setgrent(struct nwrap_backend *b)
1345 {
1346         nwrap_gr_global.idx = 0;
1347 }
1348
1349 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
1350 {
1351         struct group *gr;
1352
1353         if (nwrap_gr_global.idx == 0) {
1354                 nwrap_files_cache_reload(nwrap_gr_global.cache);
1355         }
1356
1357         if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
1358                 errno = ENOENT;
1359                 return NULL;
1360         }
1361
1362         gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
1363
1364         NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
1365                        __location__, gr->gr_name, gr->gr_gid));
1366
1367         return gr;
1368 }
1369
1370 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
1371                                   struct group *grdst, char *buf,
1372                                   size_t buflen, struct group **grdstp)
1373 {
1374         struct group *gr;
1375
1376         gr = nwrap_files_getgrent(b);
1377         if (!gr) {
1378                 if (errno == 0) {
1379                         return ENOENT;
1380                 }
1381                 return errno;
1382         }
1383
1384         return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1385 }
1386
1387 static void nwrap_files_endgrent(struct nwrap_backend *b)
1388 {
1389         nwrap_gr_global.idx = 0;
1390 }
1391
1392 /*
1393  * module backend
1394  */
1395
1396 #ifndef SAFE_FREE
1397 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
1398 #endif
1399
1400 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
1401                                             const char *name)
1402 {
1403         static struct passwd pwd;
1404         static char buf[1000];
1405         NSS_STATUS status;
1406
1407         if (!b->fns->_nss_getpwnam_r) {
1408                 return NULL;
1409         }
1410
1411         status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
1412         if (status == NSS_STATUS_NOTFOUND) {
1413                 return NULL;
1414         }
1415         if (status != NSS_STATUS_SUCCESS) {
1416                 return NULL;
1417         }
1418         return &pwd;
1419 }
1420
1421 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
1422                                    const char *name, struct passwd *pwdst,
1423                                    char *buf, size_t buflen, struct passwd **pwdstp)
1424 {
1425         int ret;
1426
1427         if (!b->fns->_nss_getpwnam_r) {
1428                 return NSS_STATUS_NOTFOUND;
1429         }
1430
1431         ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
1432         switch (ret) {
1433         case NSS_STATUS_SUCCESS:
1434                 return 0;
1435         case NSS_STATUS_NOTFOUND:
1436                 if (errno != 0) {
1437                         return errno;
1438                 }
1439                 return ENOENT;
1440         case NSS_STATUS_TRYAGAIN:
1441                 if (errno != 0) {
1442                         return errno;
1443                 }
1444                 return ERANGE;
1445         default:
1446                 if (errno != 0) {
1447                         return errno;
1448                 }
1449                 return ret;
1450         }
1451 }
1452
1453 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
1454                                             uid_t uid)
1455 {
1456         static struct passwd pwd;
1457         static char buf[1000];
1458         NSS_STATUS status;
1459
1460         if (!b->fns->_nss_getpwuid_r) {
1461                 return NULL;
1462         }
1463
1464         status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
1465         if (status == NSS_STATUS_NOTFOUND) {
1466                 return NULL;
1467         }
1468         if (status != NSS_STATUS_SUCCESS) {
1469                 return NULL;
1470         }
1471         return &pwd;
1472 }
1473
1474 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
1475                                    uid_t uid, struct passwd *pwdst,
1476                                    char *buf, size_t buflen, struct passwd **pwdstp)
1477 {
1478         int ret;
1479
1480         if (!b->fns->_nss_getpwuid_r) {
1481                 return ENOENT;
1482         }
1483
1484         ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
1485         switch (ret) {
1486         case NSS_STATUS_SUCCESS:
1487                 return 0;
1488         case NSS_STATUS_NOTFOUND:
1489                 if (errno != 0) {
1490                         return errno;
1491                 }
1492                 return ENOENT;
1493         case NSS_STATUS_TRYAGAIN:
1494                 if (errno != 0) {
1495                         return errno;
1496                 }
1497                 return ERANGE;
1498         default:
1499                 if (errno != 0) {
1500                         return errno;
1501                 }
1502                 return ret;
1503         }
1504 }
1505
1506 static void nwrap_module_setpwent(struct nwrap_backend *b)
1507 {
1508         if (!b->fns->_nss_setpwent) {
1509                 return;
1510         }
1511
1512         b->fns->_nss_setpwent();
1513 }
1514
1515 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
1516 {
1517         static struct passwd pwd;
1518         static char buf[1000];
1519         NSS_STATUS status;
1520
1521         if (!b->fns->_nss_getpwent_r) {
1522                 return NULL;
1523         }
1524
1525         status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
1526         if (status == NSS_STATUS_NOTFOUND) {
1527                 return NULL;
1528         }
1529         if (status != NSS_STATUS_SUCCESS) {
1530                 return NULL;
1531         }
1532         return &pwd;
1533 }
1534
1535 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
1536                                    struct passwd *pwdst, char *buf,
1537                                    size_t buflen, struct passwd **pwdstp)
1538 {
1539         int ret;
1540
1541         if (!b->fns->_nss_getpwent_r) {
1542                 return ENOENT;
1543         }
1544
1545         ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
1546         switch (ret) {
1547         case NSS_STATUS_SUCCESS:
1548                 return 0;
1549         case NSS_STATUS_NOTFOUND:
1550                 if (errno != 0) {
1551                         return errno;
1552                 }
1553                 return ENOENT;
1554         case NSS_STATUS_TRYAGAIN:
1555                 if (errno != 0) {
1556                         return errno;
1557                 }
1558                 return ERANGE;
1559         default:
1560                 if (errno != 0) {
1561                         return errno;
1562                 }
1563                 return ret;
1564         }
1565 }
1566
1567 static void nwrap_module_endpwent(struct nwrap_backend *b)
1568 {
1569         if (!b->fns->_nss_endpwent) {
1570                 return;
1571         }
1572
1573         b->fns->_nss_endpwent();
1574 }
1575
1576 static int nwrap_module_initgroups(struct nwrap_backend *b,
1577                                    const char *user, gid_t group)
1578 {
1579         gid_t *groups;
1580         long int start;
1581         long int size;
1582
1583         if (!b->fns->_nss_initgroups) {
1584                 return NSS_STATUS_UNAVAIL;
1585         }
1586
1587         return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
1588 }
1589
1590 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
1591                                            const char *name)
1592 {
1593         static struct group grp;
1594         static char *buf;
1595         static int buflen = 1000;
1596         NSS_STATUS status;
1597
1598         if (!b->fns->_nss_getgrnam_r) {
1599                 return NULL;
1600         }
1601
1602         if (!buf) {
1603                 buf = (char *)malloc(buflen);
1604         }
1605 again:
1606         status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
1607         if (status == NSS_STATUS_TRYAGAIN) {
1608                 buflen *= 2;
1609                 buf = (char *)realloc(buf, buflen);
1610                 if (!buf) {
1611                         return NULL;
1612                 }
1613                 goto again;
1614         }
1615         if (status == NSS_STATUS_NOTFOUND) {
1616                 SAFE_FREE(buf);
1617                 return NULL;
1618         }
1619         if (status != NSS_STATUS_SUCCESS) {
1620                 SAFE_FREE(buf);
1621                 return NULL;
1622         }
1623         return &grp;
1624 }
1625
1626 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
1627                                    const char *name, struct group *grdst,
1628                                    char *buf, size_t buflen, struct group **grdstp)
1629 {
1630         int ret;
1631
1632         if (!b->fns->_nss_getgrnam_r) {
1633                 return ENOENT;
1634         }
1635
1636         ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
1637         switch (ret) {
1638         case NSS_STATUS_SUCCESS:
1639                 return 0;
1640         case NSS_STATUS_NOTFOUND:
1641                 if (errno != 0) {
1642                         return errno;
1643                 }
1644                 return ENOENT;
1645         case NSS_STATUS_TRYAGAIN:
1646                 if (errno != 0) {
1647                         return errno;
1648                 }
1649                 return ERANGE;
1650         default:
1651                 if (errno != 0) {
1652                         return errno;
1653                 }
1654                 return ret;
1655         }
1656 }
1657
1658 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
1659                                            gid_t gid)
1660 {
1661         static struct group grp;
1662         static char *buf;
1663         static int buflen = 1000;
1664         NSS_STATUS status;
1665
1666         if (!b->fns->_nss_getgrgid_r) {
1667                 return NULL;
1668         }
1669
1670         if (!buf) {
1671                 buf = (char *)malloc(buflen);
1672         }
1673
1674 again:
1675         status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
1676         if (status == NSS_STATUS_TRYAGAIN) {
1677                 buflen *= 2;
1678                 buf = (char *)realloc(buf, buflen);
1679                 if (!buf) {
1680                         return NULL;
1681                 }
1682                 goto again;
1683         }
1684         if (status == NSS_STATUS_NOTFOUND) {
1685                 SAFE_FREE(buf);
1686                 return NULL;
1687         }
1688         if (status != NSS_STATUS_SUCCESS) {
1689                 SAFE_FREE(buf);
1690                 return NULL;
1691         }
1692         return &grp;
1693 }
1694
1695 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
1696                                    gid_t gid, struct group *grdst,
1697                                    char *buf, size_t buflen, struct group **grdstp)
1698 {
1699         int ret;
1700
1701         if (!b->fns->_nss_getgrgid_r) {
1702                 return ENOENT;
1703         }
1704
1705         ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
1706         switch (ret) {
1707         case NSS_STATUS_SUCCESS:
1708                 return 0;
1709         case NSS_STATUS_NOTFOUND:
1710                 if (errno != 0) {
1711                         return errno;
1712                 }
1713                 return ENOENT;
1714         case NSS_STATUS_TRYAGAIN:
1715                 if (errno != 0) {
1716                         return errno;
1717                 }
1718                 return ERANGE;
1719         default:
1720                 if (errno != 0) {
1721                         return errno;
1722                 }
1723                 return ret;
1724         }
1725 }
1726
1727 static void nwrap_module_setgrent(struct nwrap_backend *b)
1728 {
1729         if (!b->fns->_nss_setgrent) {
1730                 return;
1731         }
1732
1733         b->fns->_nss_setgrent();
1734 }
1735
1736 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
1737 {
1738         static struct group grp;
1739         static char *buf;
1740         static int buflen = 1024;
1741         NSS_STATUS status;
1742
1743         if (!b->fns->_nss_getgrent_r) {
1744                 return NULL;
1745         }
1746
1747         if (!buf) {
1748                 buf = (char *)malloc(buflen);
1749         }
1750
1751 again:
1752         status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
1753         if (status == NSS_STATUS_TRYAGAIN) {
1754                 buflen *= 2;
1755                 buf = (char *)realloc(buf, buflen);
1756                 if (!buf) {
1757                         return NULL;
1758                 }
1759                 goto again;
1760         }
1761         if (status == NSS_STATUS_NOTFOUND) {
1762                 SAFE_FREE(buf);
1763                 return NULL;
1764         }
1765         if (status != NSS_STATUS_SUCCESS) {
1766                 SAFE_FREE(buf);
1767                 return NULL;
1768         }
1769         return &grp;
1770 }
1771
1772 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
1773                                    struct group *grdst, char *buf,
1774                                    size_t buflen, struct group **grdstp)
1775 {
1776         int ret;
1777
1778         if (!b->fns->_nss_getgrent_r) {
1779                 return ENOENT;
1780         }
1781
1782         ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
1783         switch (ret) {
1784         case NSS_STATUS_SUCCESS:
1785                 return 0;
1786         case NSS_STATUS_NOTFOUND:
1787                 if (errno != 0) {
1788                         return errno;
1789                 }
1790                 return ENOENT;
1791         case NSS_STATUS_TRYAGAIN:
1792                 if (errno != 0) {
1793                         return errno;
1794                 }
1795                 return ERANGE;
1796         default:
1797                 if (errno != 0) {
1798                         return errno;
1799                 }
1800                 return ret;
1801         }
1802 }
1803
1804 static void nwrap_module_endgrent(struct nwrap_backend *b)
1805 {
1806         if (!b->fns->_nss_endgrent) {
1807                 return;
1808         }
1809
1810         b->fns->_nss_endgrent();
1811 }
1812
1813 /*
1814  * PUBLIC interface
1815  */
1816
1817 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
1818 {
1819         int i;
1820         struct passwd *pwd;
1821
1822         if (!nwrap_enabled()) {
1823                 return real_getpwnam(name);
1824         }
1825
1826         for (i=0; i < nwrap_main_global->num_backends; i++) {
1827                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1828                 pwd = b->ops->nw_getpwnam(b, name);
1829                 if (pwd) {
1830                         return pwd;
1831                 }
1832         }
1833
1834         return NULL;
1835 }
1836
1837 _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
1838                               char *buf, size_t buflen, struct passwd **pwdstp)
1839 {
1840         int i,ret;
1841
1842         if (!nwrap_enabled()) {
1843                 return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
1844         }
1845
1846         for (i=0; i < nwrap_main_global->num_backends; i++) {
1847                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1848                 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
1849                 if (ret == ENOENT) {
1850                         continue;
1851                 }
1852                 return ret;
1853         }
1854
1855         return ENOENT;
1856 }
1857
1858 _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
1859 {
1860         int i;
1861         struct passwd *pwd;
1862
1863         if (!nwrap_enabled()) {
1864                 return real_getpwuid(uid);
1865         }
1866
1867         for (i=0; i < nwrap_main_global->num_backends; i++) {
1868                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1869                 pwd = b->ops->nw_getpwuid(b, uid);
1870                 if (pwd) {
1871                         return pwd;
1872                 }
1873         }
1874
1875         return NULL;
1876 }
1877
1878 _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
1879                               char *buf, size_t buflen, struct passwd **pwdstp)
1880 {
1881         int i,ret;
1882
1883         if (!nwrap_enabled()) {
1884                 return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
1885         }
1886
1887         for (i=0; i < nwrap_main_global->num_backends; i++) {
1888                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1889                 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
1890                 if (ret == ENOENT) {
1891                         continue;
1892                 }
1893                 return ret;
1894         }
1895
1896         return ENOENT;
1897 }
1898
1899 _PUBLIC_ void nwrap_setpwent(void)
1900 {
1901         int i;
1902
1903         if (!nwrap_enabled()) {
1904                 real_setpwent();
1905                 return;
1906         }
1907
1908         for (i=0; i < nwrap_main_global->num_backends; i++) {
1909                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1910                 b->ops->nw_setpwent(b);
1911         }
1912 }
1913
1914 _PUBLIC_ struct passwd *nwrap_getpwent(void)
1915 {
1916         int i;
1917         struct passwd *pwd;
1918
1919         if (!nwrap_enabled()) {
1920                 return real_getpwent();
1921         }
1922
1923         for (i=0; i < nwrap_main_global->num_backends; i++) {
1924                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1925                 pwd = b->ops->nw_getpwent(b);
1926                 if (pwd) {
1927                         return pwd;
1928                 }
1929         }
1930
1931         return NULL;
1932 }
1933
1934 _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
1935                               size_t buflen, struct passwd **pwdstp)
1936 {
1937         int i,ret;
1938
1939         if (!nwrap_enabled()) {
1940 #ifdef SOLARIS_GETPWENT_R
1941                 struct passwd *pw;
1942                 pw = real_getpwent_r(pwdst, buf, buflen);
1943                 if (!pw) {
1944                         if (errno == 0) {
1945                                 return ENOENT;
1946                         }
1947                         return errno;
1948                 }
1949                 if (pwdstp) {
1950                         *pwdstp = pw;
1951                 }
1952                 return 0;
1953 #else
1954                 return real_getpwent_r(pwdst, buf, buflen, pwdstp);
1955 #endif
1956         }
1957
1958         for (i=0; i < nwrap_main_global->num_backends; i++) {
1959                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1960                 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
1961                 if (ret == ENOENT) {
1962                         continue;
1963                 }
1964                 return ret;
1965         }
1966
1967         return ENOENT;
1968 }
1969
1970 _PUBLIC_ void nwrap_endpwent(void)
1971 {
1972         int i;
1973
1974         if (!nwrap_enabled()) {
1975                 real_endpwent();
1976                 return;
1977         }
1978
1979         for (i=0; i < nwrap_main_global->num_backends; i++) {
1980                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1981                 b->ops->nw_endpwent(b);
1982         }
1983 }
1984
1985 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
1986 {
1987         int i;
1988
1989         if (!nwrap_enabled()) {
1990                 return real_initgroups(user, group);
1991         }
1992
1993         for (i=0; i < nwrap_main_global->num_backends; i++) {
1994                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1995                 return b->ops->nw_initgroups(b, user, group);
1996         }
1997
1998         errno = ENOENT;
1999         return -1;
2000 }
2001
2002 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
2003 {
2004         int i;
2005         struct group *grp;
2006
2007         if (!nwrap_enabled()) {
2008                 return real_getgrnam(name);
2009         }
2010
2011         for (i=0; i < nwrap_main_global->num_backends; i++) {
2012                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2013                 grp = b->ops->nw_getgrnam(b, name);
2014                 if (grp) {
2015                         return grp;
2016                 }
2017         }
2018
2019         return NULL;
2020 }
2021
2022 _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
2023                               char *buf, size_t buflen, struct group **grdstp)
2024 {
2025         int i,ret;
2026
2027         if (!nwrap_enabled()) {
2028                 return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
2029         }
2030
2031         for (i=0; i < nwrap_main_global->num_backends; i++) {
2032                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2033                 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
2034                 if (ret == ENOENT) {
2035                         continue;
2036                 }
2037                 return ret;
2038         }
2039
2040         return ENOENT;
2041 }
2042
2043 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
2044 {
2045         int i;
2046         struct group *grp;
2047
2048         if (!nwrap_enabled()) {
2049                 return real_getgrgid(gid);
2050         }
2051
2052         for (i=0; i < nwrap_main_global->num_backends; i++) {
2053                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2054                 grp = b->ops->nw_getgrgid(b, gid);
2055                 if (grp) {
2056                         return grp;
2057                 }
2058         }
2059
2060         return NULL;
2061 }
2062
2063 _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
2064                               char *buf, size_t buflen, struct group **grdstp)
2065 {
2066         int i,ret;
2067
2068         if (!nwrap_enabled()) {
2069                 return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
2070         }
2071
2072         for (i=0; i < nwrap_main_global->num_backends; i++) {
2073                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2074                 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
2075                 if (ret == ENOENT) {
2076                         continue;
2077                 }
2078                 return ret;
2079         }
2080
2081         return ENOENT;
2082 }
2083
2084 _PUBLIC_ void nwrap_setgrent(void)
2085 {
2086         int i;
2087
2088         if (!nwrap_enabled()) {
2089                 real_setgrent();
2090                 return;
2091         }
2092
2093         for (i=0; i < nwrap_main_global->num_backends; i++) {
2094                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2095                 b->ops->nw_setgrent(b);
2096         }
2097 }
2098
2099 _PUBLIC_ struct group *nwrap_getgrent(void)
2100 {
2101         int i;
2102         struct group *grp;
2103
2104         if (!nwrap_enabled()) {
2105                 return real_getgrent();
2106         }
2107
2108         for (i=0; i < nwrap_main_global->num_backends; i++) {
2109                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2110                 grp = b->ops->nw_getgrent(b);
2111                 if (grp) {
2112                         return grp;
2113                 }
2114         }
2115
2116         return NULL;
2117 }
2118
2119 _PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
2120                               size_t buflen, struct group **grdstp)
2121 {
2122         int i,ret;
2123
2124         if (!nwrap_enabled()) {
2125 #ifdef SOLARIS_GETGRENT_R
2126                 struct group *gr;
2127                 gr = real_getgrent_r(grdst, buf, buflen);
2128                 if (!gr) {
2129                         if (errno == 0) {
2130                                 return ENOENT;
2131                         }
2132                         return errno;
2133                 }
2134                 if (grdstp) {
2135                         *grdstp = gr;
2136                 }
2137                 return 0;
2138 #else
2139                 return real_getgrent_r(grdst, buf, buflen, grdstp);
2140 #endif
2141         }
2142
2143         for (i=0; i < nwrap_main_global->num_backends; i++) {
2144                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2145                 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
2146                 if (ret == ENOENT) {
2147                         continue;
2148                 }
2149                 return ret;
2150         }
2151
2152         return ENOENT;
2153 }
2154
2155 _PUBLIC_ void nwrap_endgrent(void)
2156 {
2157         int i;
2158
2159         if (!nwrap_enabled()) {
2160                 real_endgrent();
2161                 return;
2162         }
2163
2164         for (i=0; i < nwrap_main_global->num_backends; i++) {
2165                 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2166                 b->ops->nw_endgrent(b);
2167         }
2168 }
2169
2170 _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
2171 {
2172         struct group *grp;
2173         gid_t *groups_tmp;
2174         int count = 1;
2175         const char *name_of_group = NULL;
2176
2177         if (!nwrap_enabled()) {
2178                 return real_getgrouplist(user, group, groups, ngroups);
2179         }
2180
2181         NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user));
2182
2183         groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
2184         if (!groups_tmp) {
2185                 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2186                 errno = ENOMEM;
2187                 return -1;
2188         }
2189
2190         memcpy(groups_tmp, &group, sizeof(gid_t));
2191
2192         grp = nwrap_getgrgid(group);
2193         if (grp) {
2194                 name_of_group = grp->gr_name;
2195         }
2196
2197         nwrap_setgrent();
2198         while ((grp = nwrap_getgrent()) != NULL) {
2199                 int i = 0;
2200
2201                 NWRAP_VERBOSE(("%s: inspecting %s for group membership\n",
2202                                __location__, grp->gr_name));
2203
2204                 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
2205
2206                         if ((strcmp(user, grp->gr_mem[i]) == 0) &&
2207                             (strcmp(name_of_group, grp->gr_name) != 0)) {
2208
2209                                 NWRAP_DEBUG(("%s: %s is member of %s\n",
2210                                         __location__, user, grp->gr_name));
2211
2212                                 groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
2213                                 if (!groups_tmp) {
2214                                         NWRAP_ERROR(("%s:calloc failed\n",__location__));
2215                                         errno = ENOMEM;
2216                                         return -1;
2217                                 }
2218
2219                                 memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
2220                                 count++;
2221                         }
2222                 }
2223         }
2224
2225         nwrap_endgrent();
2226
2227         NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n",
2228                        __location__, user, *ngroups));
2229
2230         if (*ngroups < count) {
2231                 *ngroups = count;
2232                 free(groups_tmp);
2233                 return -1;
2234         }
2235
2236         *ngroups = count;
2237         memcpy(groups, groups_tmp, count * sizeof(gid_t));
2238         free(groups_tmp);
2239
2240         return count;
2241 }