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