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