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