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