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