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