1113596Snectar/*-
2113596Snectar * Copyright (c) 2003 Networks Associates Technology, Inc.
3113596Snectar * All rights reserved.
41573Srgrimes *
5113596Snectar * This software was developed for the FreeBSD Project by
6113596Snectar * Jacques A. Vidrine, Safeport Network Services, and Network
7113596Snectar * Associates Laboratories, the Security Research Division of Network
8113596Snectar * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9113596Snectar * ("CBOSS"), as part of the DARPA CHATS research program.
10113596Snectar *
111573Srgrimes * Redistribution and use in source and binary forms, with or without
121573Srgrimes * modification, are permitted provided that the following conditions
131573Srgrimes * are met:
141573Srgrimes * 1. Redistributions of source code must retain the above copyright
151573Srgrimes *    notice, this list of conditions and the following disclaimer.
161573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171573Srgrimes *    notice, this list of conditions and the following disclaimer in the
181573Srgrimes *    documentation and/or other materials provided with the distribution.
191573Srgrimes *
20113596Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23113596Snectar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
31113596Snectar *
321573Srgrimes */
3390016Sbde#include <sys/cdefs.h>
3489999Sobrien__FBSDID("$FreeBSD: releng/10.3/lib/libc/gen/getgrent.c 290582 2015-11-09 07:34:30Z ngie $");
351573Srgrimes
36113596Snectar#include "namespace.h"
37113596Snectar#include <sys/param.h>
38113596Snectar#ifdef YP
39113596Snectar#include <rpc/rpc.h>
40113596Snectar#include <rpcsvc/yp_prot.h>
41113596Snectar#include <rpcsvc/ypclnt.h>
42113596Snectar#endif
43174547Sbushman#include <assert.h>
44113596Snectar#include <ctype.h>
4565532Snectar#include <errno.h>
46113596Snectar#ifdef HESIOD
47113596Snectar#include <hesiod.h>
48113596Snectar#endif
4965532Snectar#include <grp.h>
5065532Snectar#include <nsswitch.h>
51113596Snectar#include <pthread.h>
52113596Snectar#include <pthread_np.h>
531573Srgrimes#include <stdio.h>
541573Srgrimes#include <stdlib.h>
552936Swollman#include <string.h>
5665532Snectar#include <syslog.h>
57113596Snectar#include <unistd.h>
58113596Snectar#include "un-namespace.h"
59113596Snectar#include "libc_private.h"
60113596Snectar#include "nss_tls.h"
61158115Sume#ifdef NS_CACHING
62158115Sume#include "nscache.h"
63158115Sume#endif
641573Srgrimes
65113596Snectarenum constants {
66113596Snectar	GRP_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
67113596Snectar	GRP_STORAGE_MAX		= 1 << 20, /* 1 MByte */
68113596Snectar	SETGRENT		= 1,
69113596Snectar	ENDGRENT		= 2,
70113596Snectar	HESIOD_NAME_MAX		= 256,
71113596Snectar};
7265532Snectar
73113596Snectarstatic const ns_src defaultsrc[] = {
74113643Snectar	{ NSSRC_COMPAT, NS_SUCCESS },
75113596Snectar	{ NULL, 0 }
76113596Snectar};
7765532Snectar
78113596Snectarint	 __gr_match_entry(const char *, size_t, enum nss_lookup_type,
79113596Snectar	    const char *, gid_t);
80113596Snectarint	 __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
81113596Snectar	    int *);
8265532Snectar
83113596Snectarstatic	int	 is_comment_line(const char *, size_t);
8465532Snectar
85113596Snectarunion key {
86113596Snectar	const char	*name;
87113596Snectar	gid_t		 gid;
88113596Snectar};
89113596Snectarstatic	struct group *getgr(int (*)(union key, struct group *, char *, size_t,
90113596Snectar		    struct group **), union key);
91113596Snectarstatic	int	 wrap_getgrnam_r(union key, struct group *, char *, size_t,
92113596Snectar		    struct group **);
93113596Snectarstatic	int	 wrap_getgrgid_r(union key, struct group *, char *, size_t,
94113596Snectar		    struct group **);
95113596Snectarstatic	int	 wrap_getgrent_r(union key, struct group *, char *, size_t,
96113596Snectar		    struct group **);
9765532Snectar
98113596Snectarstruct files_state {
99113596Snectar	FILE	*fp;
100113596Snectar	int	 stayopen;
101113596Snectar};
102113596Snectarstatic	void	 files_endstate(void *);
103113596SnectarNSS_TLS_HANDLING(files);
104113596Snectarstatic	int	 files_setgrent(void *, void *, va_list);
105113596Snectarstatic	int	 files_group(void *, void *, va_list);
10665532Snectar
1071573Srgrimes
10865532Snectar#ifdef HESIOD
109113596Snectarstruct dns_state {
110113596Snectar	long	counter;
111113596Snectar};
112113596Snectarstatic	void	 dns_endstate(void *);
113113596SnectarNSS_TLS_HANDLING(dns);
114113596Snectarstatic	int	 dns_setgrent(void *, void *, va_list);
115113596Snectarstatic	int	 dns_group(void *, void *, va_list);
11665532Snectar#endif
117113596Snectar
118113596Snectar
119113596Snectar#ifdef YP
120113596Snectarstruct nis_state {
121113596Snectar	char	 domain[MAXHOSTNAMELEN];
122113596Snectar	int	 done;
123113596Snectar	char	*key;
124113596Snectar	int	 keylen;
125113596Snectar};
126113596Snectarstatic	void	 nis_endstate(void *);
127113596SnectarNSS_TLS_HANDLING(nis);
128113596Snectarstatic	int	 nis_setgrent(void *, void *, va_list);
129113596Snectarstatic	int	 nis_group(void *, void *, va_list);
13065532Snectar#endif
13120911Swosch
132113596Snectarstruct compat_state {
133113596Snectar	FILE	*fp;
134113596Snectar	int	 stayopen;
135113596Snectar	char	*name;
136113596Snectar	enum _compat {
137113596Snectar		COMPAT_MODE_OFF = 0,
138113596Snectar		COMPAT_MODE_ALL,
139113596Snectar		COMPAT_MODE_NAME
140113596Snectar	}	 compat;
141113596Snectar};
142113596Snectarstatic	void	 compat_endstate(void *);
143113596SnectarNSS_TLS_HANDLING(compat);
144113596Snectarstatic	int	 compat_setgrent(void *, void *, va_list);
145113596Snectarstatic	int	 compat_group(void *, void *, va_list);
14665532Snectar
147174547Sbushmanstatic	int	gr_addgid(gid_t, gid_t *, int, int *);
148174547Sbushmanstatic	int	getgroupmembership_fallback(void *, void *, va_list);
149174547Sbushman
150158115Sume#ifdef NS_CACHING
151158115Sumestatic	int	 grp_id_func(char *, size_t *, va_list, void *);
152158115Sumestatic	int	 grp_marshal_func(char *, size_t *, void *, va_list, void *);
153158115Sumestatic	int	 grp_unmarshal_func(char *, size_t, void *, va_list, void *);
15420911Swosch
155158115Sumestatic int
156158115Sumegrp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
157158115Sume{
158158115Sume	char	*name;
159158115Sume	gid_t	gid;
160158115Sume
161158115Sume	size_t	desired_size, size;
162158115Sume	int	res = NS_UNAVAIL;
163158115Sume	enum nss_lookup_type lookup_type;
164158115Sume
165158115Sume
166158115Sume	lookup_type = (enum nss_lookup_type)cache_mdata;
167158115Sume	switch (lookup_type) {
168158115Sume	case nss_lt_name:
169158115Sume		name = va_arg(ap, char *);
170158115Sume		size = strlen(name);
171158115Sume		desired_size = sizeof(enum nss_lookup_type) + size + 1;
172158115Sume		if (desired_size > *buffer_size) {
173158115Sume			res = NS_RETURN;
174158115Sume			goto fin;
175158115Sume		}
176158115Sume
177158115Sume		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
178158115Sume		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
179158115Sume
180158115Sume		res = NS_SUCCESS;
181158115Sume		break;
182158115Sume	case nss_lt_id:
183158115Sume		gid = va_arg(ap, gid_t);
184158115Sume		desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t);
185158115Sume		if (desired_size > *buffer_size) {
186158115Sume			res = NS_RETURN;
187158115Sume			goto fin;
188158115Sume		}
189158115Sume
190158115Sume		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
191158115Sume		memcpy(buffer + sizeof(enum nss_lookup_type), &gid,
192158115Sume		    sizeof(gid_t));
193158115Sume
194158115Sume		res = NS_SUCCESS;
195158115Sume		break;
196158115Sume	default:
197158115Sume		/* should be unreachable */
198158115Sume		return (NS_UNAVAIL);
199158115Sume	}
200158115Sume
201158115Sumefin:
202158115Sume	*buffer_size = desired_size;
203158115Sume	return (res);
204158115Sume}
205158115Sume
206158115Sumestatic int
207158115Sumegrp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
208158115Sume    void *cache_mdata)
209158115Sume{
210158115Sume	char *name;
211158115Sume	gid_t gid;
212158115Sume	struct group *grp;
213158115Sume	char *orig_buf;
214158115Sume	size_t orig_buf_size;
215158115Sume
216158115Sume	struct group new_grp;
217158115Sume	size_t desired_size, size, mem_size;
218158115Sume	char *p, **mem;
219158115Sume
220158115Sume	switch ((enum nss_lookup_type)cache_mdata) {
221158115Sume	case nss_lt_name:
222158115Sume		name = va_arg(ap, char *);
223158115Sume		break;
224158115Sume	case nss_lt_id:
225158115Sume		gid = va_arg(ap, gid_t);
226158115Sume		break;
227158115Sume	case nss_lt_all:
228158115Sume		break;
229158115Sume	default:
230158115Sume		/* should be unreachable */
231158115Sume		return (NS_UNAVAIL);
232158115Sume	}
233158115Sume
234158115Sume	grp = va_arg(ap, struct group *);
235158115Sume	orig_buf = va_arg(ap, char *);
236158115Sume	orig_buf_size = va_arg(ap, size_t);
237158115Sume
238158115Sume	desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *);
239158115Sume
240158115Sume	if (grp->gr_name != NULL)
241158115Sume		desired_size += strlen(grp->gr_name) + 1;
242158115Sume	if (grp->gr_passwd != NULL)
243158115Sume		desired_size += strlen(grp->gr_passwd) + 1;
244158115Sume
245158115Sume	if (grp->gr_mem != NULL) {
246158115Sume		mem_size = 0;
247158115Sume		for (mem = grp->gr_mem; *mem; ++mem) {
248158115Sume			desired_size += strlen(*mem) + 1;
249158115Sume			++mem_size;
250158115Sume		}
251158115Sume
252158115Sume		desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *);
253158115Sume	}
254158115Sume
255158115Sume	if (desired_size > *buffer_size) {
256158115Sume		/* this assignment is here for future use */
257158115Sume		*buffer_size = desired_size;
258158115Sume		return (NS_RETURN);
259158115Sume	}
260158115Sume
261158115Sume	memcpy(&new_grp, grp, sizeof(struct group));
262158115Sume	memset(buffer, 0, desired_size);
263158115Sume
264158115Sume	*buffer_size = desired_size;
265158115Sume	p = buffer + sizeof(struct group) + sizeof(char *);
266158115Sume	memcpy(buffer + sizeof(struct group), &p, sizeof(char *));
267158115Sume	p = (char *)_ALIGN(p);
268158115Sume
269158115Sume	if (new_grp.gr_name != NULL) {
270158115Sume		size = strlen(new_grp.gr_name);
271158115Sume		memcpy(p, new_grp.gr_name, size);
272158115Sume		new_grp.gr_name = p;
273158115Sume		p += size + 1;
274158115Sume	}
275158115Sume
276158115Sume	if (new_grp.gr_passwd != NULL) {
277158115Sume		size = strlen(new_grp.gr_passwd);
278158115Sume		memcpy(p, new_grp.gr_passwd, size);
279158115Sume		new_grp.gr_passwd = p;
280158115Sume		p += size + 1;
281158115Sume	}
282158115Sume
283158115Sume	if (new_grp.gr_mem != NULL) {
284158115Sume		p = (char *)_ALIGN(p);
285158115Sume		memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size);
286158115Sume		new_grp.gr_mem = (char **)p;
287158115Sume		p += sizeof(char *) * (mem_size + 1);
288158115Sume
289158115Sume		for (mem = new_grp.gr_mem; *mem; ++mem) {
290158115Sume			size = strlen(*mem);
291158115Sume			memcpy(p, *mem, size);
292158115Sume			*mem = p;
293158115Sume			p += size + 1;
294158115Sume		}
295158115Sume	}
296158115Sume
297158115Sume	memcpy(buffer, &new_grp, sizeof(struct group));
298158115Sume	return (NS_SUCCESS);
299158115Sume}
300158115Sume
301158115Sumestatic int
302158115Sumegrp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
303158115Sume    void *cache_mdata)
304158115Sume{
305158115Sume	char *name;
306158115Sume	gid_t gid;
307158115Sume	struct group *grp;
308158115Sume	char *orig_buf;
309158115Sume	size_t orig_buf_size;
310158115Sume	int *ret_errno;
311158115Sume
312158115Sume	char *p;
313158115Sume	char **mem;
314158115Sume
315158115Sume	switch ((enum nss_lookup_type)cache_mdata) {
316158115Sume	case nss_lt_name:
317158115Sume		name = va_arg(ap, char *);
318158115Sume		break;
319158115Sume	case nss_lt_id:
320158115Sume		gid = va_arg(ap, gid_t);
321158115Sume		break;
322158115Sume	case nss_lt_all:
323158115Sume		break;
324158115Sume	default:
325158115Sume		/* should be unreachable */
326158115Sume		return (NS_UNAVAIL);
327158115Sume	}
328158115Sume
329158115Sume	grp = va_arg(ap, struct group *);
330158115Sume	orig_buf = va_arg(ap, char *);
331158115Sume	orig_buf_size = va_arg(ap, size_t);
332158115Sume	ret_errno = va_arg(ap, int *);
333158115Sume
334158115Sume	if (orig_buf_size <
335158115Sume	    buffer_size - sizeof(struct group) - sizeof(char *)) {
336158115Sume		*ret_errno = ERANGE;
337158115Sume		return (NS_RETURN);
338158115Sume	}
339158115Sume
340158115Sume	memcpy(grp, buffer, sizeof(struct group));
341158115Sume	memcpy(&p, buffer + sizeof(struct group), sizeof(char *));
342158115Sume
343158115Sume	orig_buf = (char *)_ALIGN(orig_buf);
344158115Sume	memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) +
345158115Sume	    _ALIGN(p) - (size_t)p,
346158115Sume	    buffer_size - sizeof(struct group) - sizeof(char *) -
347158115Sume	    _ALIGN(p) + (size_t)p);
348158115Sume	p = (char *)_ALIGN(p);
349158115Sume
350158115Sume	NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *);
351158115Sume	NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *);
352158115Sume	if (grp->gr_mem != NULL) {
353158115Sume		NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **);
354158115Sume
355158115Sume		for (mem = grp->gr_mem; *mem; ++mem)
356158115Sume			NS_APPLY_OFFSET(*mem, orig_buf, p, char *);
357158115Sume	}
358158115Sume
359158115Sume	if (retval != NULL)
360158115Sume		*((struct group **)retval) = grp;
361158115Sume
362158115Sume	return (NS_SUCCESS);
363158115Sume}
364158115Sume
365158115SumeNSS_MP_CACHE_HANDLING(group);
366158115Sume#endif /* NS_CACHING */
367158115Sume
368158115Sume#ifdef NS_CACHING
369174547Sbushmanstatic const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
370174547Sbushman	group, (void *)nss_lt_all,
371174547Sbushman	NULL, NULL);
372158115Sume#endif
373158115Sume
374174547Sbushmanstatic const ns_dtab setgrent_dtab[] = {
375174547Sbushman	{ NSSRC_FILES, files_setgrent, (void *)SETGRENT },
376113596Snectar#ifdef HESIOD
377174547Sbushman	{ NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
378113596Snectar#endif
3792936Swollman#ifdef YP
380174547Sbushman	{ NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
3812936Swollman#endif
382174547Sbushman	{ NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
383158115Sume#ifdef NS_CACHING
384174547Sbushman	NS_CACHE_CB(&setgrent_cache_info)
385158115Sume#endif
386174547Sbushman	{ NULL, NULL, NULL }
387174547Sbushman};
3882936Swollman
389158115Sume#ifdef NS_CACHING
390174547Sbushmanstatic const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
391174547Sbushman	group, (void *)nss_lt_all,
392174547Sbushman	NULL, NULL);
393158115Sume#endif
394158115Sume
395174547Sbushmanstatic const ns_dtab endgrent_dtab[] = {
396174547Sbushman	{ NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
39765532Snectar#ifdef HESIOD
398174547Sbushman	{ NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
3992936Swollman#endif
400113596Snectar#ifdef YP
401174547Sbushman	{ NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
40265532Snectar#endif
403174547Sbushman	{ NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
404158115Sume#ifdef NS_CACHING
405174547Sbushman	NS_CACHE_CB(&endgrent_cache_info)
406158115Sume#endif
407174547Sbushman	{ NULL, NULL, NULL }
408174547Sbushman};
40965532Snectar
410158115Sume#ifdef NS_CACHING
411174547Sbushmanstatic const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
412174547Sbushman	group, (void *)nss_lt_all,
413174547Sbushman	grp_marshal_func, grp_unmarshal_func);
414158115Sume#endif
415158115Sume
416174547Sbushmanstatic const ns_dtab getgrent_r_dtab[] = {
417174547Sbushman	{ NSSRC_FILES, files_group, (void *)nss_lt_all },
418113596Snectar#ifdef HESIOD
419174547Sbushman	{ NSSRC_DNS, dns_group, (void *)nss_lt_all },
420113596Snectar#endif
421113596Snectar#ifdef YP
422174547Sbushman	{ NSSRC_NIS, nis_group, (void *)nss_lt_all },
423113596Snectar#endif
424174547Sbushman	{ NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
425158115Sume#ifdef NS_CACHING
426174547Sbushman	NS_CACHE_CB(&getgrent_r_cache_info)
427158115Sume#endif
428174547Sbushman	{ NULL, NULL, NULL }
429174547Sbushman};
430174547Sbushman
431174547Sbushmanstatic int
432174547Sbushmangr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt)
433174547Sbushman{
434174547Sbushman	int     ret, dupc;
435174547Sbushman
436174547Sbushman	for (dupc = 0; dupc < MIN(maxgrp, *grpcnt); dupc++) {
437174547Sbushman		if (groups[dupc] == gid)
438174547Sbushman			return 1;
439174547Sbushman	}
440174547Sbushman
441174547Sbushman	ret = 1;
442174547Sbushman	if (*grpcnt < maxgrp)
443174547Sbushman		groups[*grpcnt] = gid;
444174547Sbushman	else
445174547Sbushman		ret = 0;
446174547Sbushman
447174547Sbushman	(*grpcnt)++;
448174547Sbushman
449174547Sbushman	return ret;
450174547Sbushman}
451174547Sbushman
452174547Sbushmanstatic int
453174547Sbushmangetgroupmembership_fallback(void *retval, void *mdata, va_list ap)
454174547Sbushman{
455174547Sbushman	const ns_src src[] = {
456174547Sbushman		{ mdata, NS_SUCCESS },
457174547Sbushman		{ NULL, 0}
458113596Snectar	};
459174547Sbushman	struct group	grp;
460174547Sbushman	struct group	*grp_p;
461174547Sbushman	char		*buf;
462174547Sbushman	size_t		bufsize;
463174547Sbushman	const char	*uname;
464174547Sbushman	gid_t		*groups;
465174547Sbushman	gid_t		agroup;
466174547Sbushman	int 		maxgrp, *grpcnt;
467174547Sbushman	int		i, rv, ret_errno;
468174547Sbushman
469174547Sbushman	/*
470174547Sbushman	 * As this is a fallback method, only provided src
471174547Sbushman	 * list will be respected during methods search.
472174547Sbushman	 */
473174547Sbushman	assert(src[0].name != NULL);
474174547Sbushman
475174547Sbushman	uname = va_arg(ap, const char *);
476174547Sbushman	agroup = va_arg(ap, gid_t);
477174547Sbushman	groups = va_arg(ap, gid_t *);
478174547Sbushman	maxgrp = va_arg(ap, int);
479174547Sbushman	grpcnt = va_arg(ap, int *);
480174547Sbushman
481174547Sbushman	rv = NS_UNAVAIL;
482174547Sbushman
483174547Sbushman	buf = malloc(GRP_STORAGE_INITIAL);
484174547Sbushman	if (buf == NULL)
485174547Sbushman		goto out;
486174547Sbushman
487174547Sbushman	bufsize = GRP_STORAGE_INITIAL;
488174547Sbushman
489174547Sbushman	gr_addgid(agroup, groups, maxgrp, grpcnt);
490174547Sbushman
491174547Sbushman	_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
492174547Sbushman	for (;;) {
493174547Sbushman		do {
494174547Sbushman			ret_errno = 0;
495174547Sbushman			grp_p = NULL;
496174547Sbushman			rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP,
497174547Sbushman			    "getgrent_r", src, &grp, buf, bufsize, &ret_errno);
498174547Sbushman
499174547Sbushman			if (grp_p == NULL && ret_errno == ERANGE) {
500174547Sbushman				free(buf);
501174547Sbushman				if ((bufsize << 1) > GRP_STORAGE_MAX) {
502174547Sbushman					buf = NULL;
503174547Sbushman					errno = ERANGE;
504174547Sbushman					goto out;
505174547Sbushman				}
506174547Sbushman
507174547Sbushman				bufsize <<= 1;
508174547Sbushman				buf = malloc(bufsize);
509174547Sbushman				if (buf == NULL) {
510174547Sbushman					goto out;
511174547Sbushman				}
512174547Sbushman			}
513174547Sbushman		} while (grp_p == NULL && ret_errno == ERANGE);
514174547Sbushman
515174547Sbushman		if (ret_errno != 0) {
516174547Sbushman			errno = ret_errno;
517174547Sbushman			goto out;
518174547Sbushman		}
519174547Sbushman
520174547Sbushman		if (grp_p == NULL)
521174547Sbushman			break;
522174547Sbushman
523174547Sbushman		for (i = 0; grp.gr_mem[i]; i++) {
524174547Sbushman			if (strcmp(grp.gr_mem[i], uname) == 0)
525174547Sbushman			    gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt);
526174547Sbushman		}
527174547Sbushman	}
528174547Sbushman
529174547Sbushman	_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src);
530174547Sbushmanout:
531174547Sbushman	free(buf);
532174547Sbushman	return (rv);
5331573Srgrimes}
5341573Srgrimes
535174547Sbushman/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
536174547Sbushmanint
537174547Sbushmansetgrent(void)
538174547Sbushman{
539174547Sbushman	(void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
540174547Sbushman	return (1);
541174547Sbushman}
542113596Snectar
543174547Sbushman
544113596Snectarint
545174547Sbushmansetgroupent(int stayopen)
546174547Sbushman{
547174547Sbushman	(void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc,
548174547Sbushman	    stayopen);
549174547Sbushman	return (1);
550174547Sbushman}
551174547Sbushman
552174547Sbushman
553174547Sbushmanvoid
554174547Sbushmanendgrent(void)
555174547Sbushman{
556174547Sbushman	(void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc);
557174547Sbushman}
558174547Sbushman
559174547Sbushman
560174547Sbushmanint
561113596Snectargetgrent_r(struct group *grp, char *buffer, size_t bufsize,
562113596Snectar    struct group **result)
5631573Srgrimes{
564113596Snectar	int	rv, ret_errno;
5651573Srgrimes
566113596Snectar	ret_errno = 0;
567113596Snectar	*result = NULL;
568174547Sbushman	rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
569113596Snectar	    grp, buffer, bufsize, &ret_errno);
570113596Snectar	if (rv == NS_SUCCESS)
571113596Snectar		return (0);
572113596Snectar	else
573113596Snectar		return (ret_errno);
5741573Srgrimes}
5751573Srgrimes
576113596Snectar
577113596Snectarint
578113596Snectargetgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
579113596Snectar    struct group **result)
5801573Srgrimes{
581158115Sume#ifdef NS_CACHING
582158115Sume	static const nss_cache_info cache_info =
583158115Sume    		NS_COMMON_CACHE_INFO_INITIALIZER(
584158115Sume		group, (void *)nss_lt_name,
585158115Sume		grp_id_func, grp_marshal_func, grp_unmarshal_func);
586158115Sume#endif
587158115Sume
588113596Snectar	static const ns_dtab dtab[] = {
589113596Snectar		{ NSSRC_FILES, files_group, (void *)nss_lt_name },
590113596Snectar#ifdef HESIOD
591113596Snectar		{ NSSRC_DNS, dns_group, (void *)nss_lt_name },
592113596Snectar#endif
593113596Snectar#ifdef YP
594113596Snectar		{ NSSRC_NIS, nis_group, (void *)nss_lt_name },
595113596Snectar#endif
596113596Snectar		{ NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
597158115Sume#ifdef NS_CACHING
598158115Sume		NS_CACHE_CB(&cache_info)
599158115Sume#endif
600113596Snectar		{ NULL, NULL, NULL }
601113596Snectar	};
602113596Snectar	int	rv, ret_errno;
6031573Srgrimes
604113596Snectar	ret_errno = 0;
605113596Snectar	*result = NULL;
606113596Snectar	rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
607113596Snectar	    name, grp, buffer, bufsize, &ret_errno);
608113596Snectar	if (rv == NS_SUCCESS)
609113596Snectar		return (0);
610113596Snectar	else
611113596Snectar		return (ret_errno);
6121573Srgrimes}
6131573Srgrimes
614113596Snectar
615113596Snectarint
616113596Snectargetgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
617113596Snectar    struct group **result)
6181573Srgrimes{
619158115Sume#ifdef NS_CACHING
620158115Sume	static const nss_cache_info cache_info =
621158115Sume    		NS_COMMON_CACHE_INFO_INITIALIZER(
622158115Sume		group, (void *)nss_lt_id,
623158115Sume		grp_id_func, grp_marshal_func, grp_unmarshal_func);
624158115Sume#endif
625158115Sume
626113596Snectar	static const ns_dtab dtab[] = {
627113596Snectar		{ NSSRC_FILES, files_group, (void *)nss_lt_id },
62865532Snectar#ifdef HESIOD
629113596Snectar		{ NSSRC_DNS, dns_group, (void *)nss_lt_id },
63065532Snectar#endif
631113596Snectar#ifdef YP
632113596Snectar		{ NSSRC_NIS, nis_group, (void *)nss_lt_id },
63365532Snectar#endif
634113596Snectar		{ NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
635158115Sume#ifdef NS_CACHING
636158115Sume		NS_CACHE_CB(&cache_info)
637158115Sume#endif
638113596Snectar		{ NULL, NULL, NULL }
639113596Snectar	};
640113596Snectar	int	rv, ret_errno;
641113596Snectar
642113596Snectar	ret_errno = 0;
643113596Snectar	*result = NULL;
644113596Snectar	rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
645113596Snectar	    gid, grp, buffer, bufsize, &ret_errno);
646113596Snectar	if (rv == NS_SUCCESS)
647113596Snectar		return (0);
648113596Snectar	else
649113596Snectar		return (ret_errno);
65065532Snectar}
65120911Swosch
652113596Snectar
653174547Sbushman
654174547Sbushmanint
655174547Sbushman__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups,
656174547Sbushman	int maxgrp, int *grpcnt)
657174547Sbushman{
658174547Sbushman	static const ns_dtab dtab[] = {
659174547Sbushman		NS_FALLBACK_CB(getgroupmembership_fallback)
660174547Sbushman		{ NULL, NULL, NULL }
661174547Sbushman	};
662174547Sbushman
663174547Sbushman	assert(uname != NULL);
664174547Sbushman	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
665174547Sbushman	assert(grpcnt != NULL);
666174547Sbushman
667174547Sbushman	*grpcnt = 0;
668290582Sngie	(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
669174547Sbushman	    defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
670174547Sbushman
671174547Sbushman	/* too many groups found? */
672174547Sbushman	return (*grpcnt > maxgrp ? -1 : 0);
673174547Sbushman}
674174547Sbushman
675174547Sbushman
676113596Snectarstatic struct group	 grp;
677113596Snectarstatic char		*grp_storage;
678113596Snectarstatic size_t		 grp_storage_size;
679113596Snectar
680113596Snectarstatic struct group *
681113596Snectargetgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
682113596Snectar    union key key)
68365532Snectar{
684113596Snectar	int		 rv;
685113596Snectar	struct group	*res;
686113596Snectar
687113596Snectar	if (grp_storage == NULL) {
688113596Snectar		grp_storage = malloc(GRP_STORAGE_INITIAL);
689113596Snectar		if (grp_storage == NULL)
690113596Snectar			return (NULL);
691113596Snectar		grp_storage_size = GRP_STORAGE_INITIAL;
69220911Swosch	}
693113596Snectar	do {
694113596Snectar		rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
695113596Snectar		if (res == NULL && rv == ERANGE) {
696113596Snectar			free(grp_storage);
697113596Snectar			if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
698113596Snectar				grp_storage = NULL;
699129367Skientzle				errno = ERANGE;
700113596Snectar				return (NULL);
701113596Snectar			}
702113596Snectar			grp_storage_size <<= 1;
703113596Snectar			grp_storage = malloc(grp_storage_size);
704113596Snectar			if (grp_storage == NULL)
705113596Snectar				return (NULL);
706113596Snectar		}
707113596Snectar	} while (res == NULL && rv == ERANGE);
708129367Skientzle	if (rv != 0)
709129367Skientzle		errno = rv;
710113596Snectar	return (res);
7111573Srgrimes}
7121573Srgrimes
713113596Snectar
714113596Snectarstatic int
715113596Snectarwrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
716113596Snectar    struct group **res)
7171573Srgrimes{
718113596Snectar	return (getgrnam_r(key.name, grp, buffer, bufsize, res));
7191573Srgrimes}
7201573Srgrimes
721113596Snectar
722113596Snectarstatic int
723113596Snectarwrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
724113596Snectar    struct group **res)
7251573Srgrimes{
726113596Snectar	return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
7271573Srgrimes}
7281573Srgrimes
729113596Snectar
730113596Snectarstatic int
731113596Snectarwrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
732113596Snectar    size_t bufsize, struct group **res)
7331573Srgrimes{
734113596Snectar	return (getgrent_r(grp, buffer, bufsize, res));
7351573Srgrimes}
7361573Srgrimes
73765532Snectar
738113596Snectarstruct group *
739113596Snectargetgrnam(const char *name)
740113596Snectar{
741113596Snectar	union key key;
74265532Snectar
743113596Snectar	key.name = name;
744113596Snectar	return (getgr(wrap_getgrnam_r, key));
745113596Snectar}
746113596Snectar
747113596Snectar
748113596Snectarstruct group *
749113596Snectargetgrgid(gid_t gid)
7501573Srgrimes{
751113596Snectar	union key key;
75220911Swosch
753113596Snectar	key.gid = gid;
754113596Snectar	return (getgr(wrap_getgrgid_r, key));
75565532Snectar}
75620911Swosch
7571573Srgrimes
758113596Snectarstruct group *
759113596Snectargetgrent(void)
76065532Snectar{
761113596Snectar	union key key;
76220911Swosch
763113596Snectar	key.gid = 0; /* not used */
764113596Snectar	return (getgr(wrap_getgrent_r, key));
765113596Snectar}
76665532Snectar
76765532Snectar
768113596Snectarstatic int
769113596Snectaris_comment_line(const char *s, size_t n)
770113596Snectar{
771113596Snectar	const char	*eom;
77220911Swosch
773113596Snectar	eom = &s[n];
774113596Snectar
775113596Snectar	for (; s < eom; s++)
776113596Snectar		if (*s == '#' || !isspace((unsigned char)*s))
77765532Snectar			break;
778113596Snectar	return (*s == '#' || s == eom);
779113596Snectar}
78065532Snectar
781113596Snectar
782113596Snectar/*
783113596Snectar * files backend
784113596Snectar */
785113596Snectarstatic void
786113596Snectarfiles_endstate(void *p)
787113596Snectar{
788113596Snectar
789113596Snectar	if (p == NULL)
790113596Snectar		return;
791113596Snectar	if (((struct files_state *)p)->fp != NULL)
792113596Snectar		fclose(((struct files_state *)p)->fp);
793113596Snectar	free(p);
794113596Snectar}
795113596Snectar
796113596Snectar
797113596Snectarstatic int
798113596Snectarfiles_setgrent(void *retval, void *mdata, va_list ap)
799113596Snectar{
800113596Snectar	struct files_state *st;
801113596Snectar	int		 rv, stayopen;
802113596Snectar
803113596Snectar	rv = files_getstate(&st);
804113596Snectar	if (rv != 0)
805113596Snectar		return (NS_UNAVAIL);
806113596Snectar	switch ((enum constants)mdata) {
807113596Snectar	case SETGRENT:
808113596Snectar		stayopen = va_arg(ap, int);
809113596Snectar		if (st->fp != NULL)
810113596Snectar			rewind(st->fp);
811113596Snectar		else if (stayopen)
812244092Sjilles			st->fp = fopen(_PATH_GROUP, "re");
813113596Snectar		break;
814113596Snectar	case ENDGRENT:
815113596Snectar		if (st->fp != NULL) {
816113596Snectar			fclose(st->fp);
817113596Snectar			st->fp = NULL;
818112404Srobert		}
819113596Snectar		break;
820113596Snectar	default:
821113596Snectar		break;
82265532Snectar	}
823113596Snectar	return (NS_UNAVAIL);
82465532Snectar}
82520911Swosch
82620911Swosch
82765532Snectarstatic int
828113596Snectarfiles_group(void *retval, void *mdata, va_list ap)
82965532Snectar{
830113596Snectar	struct files_state	*st;
831113596Snectar	enum nss_lookup_type	 how;
832113596Snectar	const char		*name, *line;
833113596Snectar	struct group		*grp;
834113596Snectar	gid_t			 gid;
835113596Snectar	char			*buffer;
836113596Snectar	size_t			 bufsize, linesize;
837159144Smaxim	off_t			 pos;
838113596Snectar	int			 rv, stayopen, *errnop;
83965532Snectar
840113596Snectar	name = NULL;
841113596Snectar	gid = (gid_t)-1;
842113596Snectar	how = (enum nss_lookup_type)mdata;
843113596Snectar	switch (how) {
844113596Snectar	case nss_lt_name:
845113596Snectar		name = va_arg(ap, const char *);
846113596Snectar		break;
847113596Snectar	case nss_lt_id:
848113596Snectar		gid = va_arg(ap, gid_t);
849113596Snectar		break;
850113596Snectar	case nss_lt_all:
851113596Snectar		break;
852113596Snectar	default:
853113596Snectar		return (NS_NOTFOUND);
854113596Snectar	}
855113596Snectar	grp = va_arg(ap, struct group *);
856113596Snectar	buffer = va_arg(ap, char *);
857113596Snectar	bufsize = va_arg(ap, size_t);
858113596Snectar	errnop = va_arg(ap, int *);
859113596Snectar	*errnop = files_getstate(&st);
860113596Snectar	if (*errnop != 0)
861113596Snectar		return (NS_UNAVAIL);
862113596Snectar	if (st->fp == NULL &&
863244092Sjilles	    ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
864113596Snectar		*errnop = errno;
865113596Snectar		return (NS_UNAVAIL);
866113596Snectar	}
867113596Snectar	if (how == nss_lt_all)
868113596Snectar		stayopen = 1;
869113596Snectar	else {
870113596Snectar		rewind(st->fp);
871113596Snectar		stayopen = st->stayopen;
872113596Snectar	}
873113596Snectar	rv = NS_NOTFOUND;
874159144Smaxim	pos = ftello(st->fp);
875113596Snectar	while ((line = fgetln(st->fp, &linesize)) != NULL) {
876113596Snectar		if (line[linesize-1] == '\n')
877113596Snectar			linesize--;
878113596Snectar		rv = __gr_match_entry(line, linesize, how, name, gid);
879113596Snectar		if (rv != NS_SUCCESS)
880113596Snectar			continue;
881113596Snectar		/* We need room at least for the line, a string NUL
882113596Snectar		 * terminator, alignment padding, and one (char *)
883113596Snectar		 * pointer for the member list terminator.
884113596Snectar		 */
885113596Snectar		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
886113596Snectar			*errnop = ERANGE;
887113596Snectar			rv = NS_RETURN;
88811286Swpaul			break;
8898172Swpaul		}
890113596Snectar		memcpy(buffer, line, linesize);
891113596Snectar		buffer[linesize] = '\0';
892113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
893113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
894113596Snectar		if (rv & NS_TERMINATE)
89565532Snectar			break;
896160355Smaxim		pos = ftello(st->fp);
89765532Snectar	}
898113596Snectar	if (!stayopen && st->fp != NULL) {
899113596Snectar		fclose(st->fp);
900113596Snectar		st->fp = NULL;
90165532Snectar	}
902113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
903113596Snectar		*(struct group **)retval = grp;
904162391Smaxim	else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
905160355Smaxim		fseeko(st->fp, pos, SEEK_SET);
906113596Snectar	return (rv);
90765532Snectar}
90865532Snectar
909113596Snectar
910113596Snectar#ifdef HESIOD
91165532Snectar/*
912113596Snectar * dns backend
91365532Snectar */
914113596Snectarstatic void
915113596Snectardns_endstate(void *p)
916113596Snectar{
91765532Snectar
918113596Snectar	free(p);
919113596Snectar}
920113596Snectar
921113596Snectar
92265532Snectarstatic int
923113596Snectardns_setgrent(void *retval, void *cb_data, va_list ap)
92465532Snectar{
925113596Snectar	struct dns_state	*st;
926113596Snectar	int			 rv;
92765532Snectar
928113596Snectar	rv = dns_getstate(&st);
929113596Snectar	if (rv != 0)
930113596Snectar		return (NS_UNAVAIL);
931113596Snectar	st->counter = 0;
932113596Snectar	return (NS_UNAVAIL);
933113596Snectar}
934113596Snectar
935113596Snectar
936113596Snectarstatic int
937113596Snectardns_group(void *retval, void *mdata, va_list ap)
938113596Snectar{
939113596Snectar	char			 buf[HESIOD_NAME_MAX];
940113596Snectar	struct dns_state	*st;
941113596Snectar	struct group		*grp;
942113596Snectar	const char		*name, *label;
943113596Snectar	void			*ctx;
944113596Snectar	char			*buffer, **hes;
945113596Snectar	size_t			 bufsize, adjsize, linesize;
946113596Snectar	gid_t			 gid;
947113596Snectar	enum nss_lookup_type	 how;
948113596Snectar	int			 rv, *errnop;
949113596Snectar
950113596Snectar	ctx = NULL;
951113596Snectar	hes = NULL;
952113596Snectar	name = NULL;
953113596Snectar	gid = (gid_t)-1;
954113596Snectar	how = (enum nss_lookup_type)mdata;
955113596Snectar	switch (how) {
956113596Snectar	case nss_lt_name:
957113596Snectar		name = va_arg(ap, const char *);
958113596Snectar		break;
959113596Snectar	case nss_lt_id:
960113596Snectar		gid = va_arg(ap, gid_t);
961113596Snectar		break;
962113596Snectar	case nss_lt_all:
963113596Snectar		break;
96465532Snectar	}
965113596Snectar	grp     = va_arg(ap, struct group *);
966113596Snectar	buffer  = va_arg(ap, char *);
967113596Snectar	bufsize = va_arg(ap, size_t);
968113596Snectar	errnop  = va_arg(ap, int *);
969113596Snectar	*errnop = dns_getstate(&st);
970113596Snectar	if (*errnop != 0)
971113596Snectar		return (NS_UNAVAIL);
972113596Snectar	if (hesiod_init(&ctx) != 0) {
973113596Snectar		*errnop = errno;
974113596Snectar		rv = NS_UNAVAIL;
975113596Snectar		goto fin;
976113596Snectar	}
977113596Snectar	do {
978113596Snectar		rv = NS_NOTFOUND;
979113596Snectar		switch (how) {
980113596Snectar		case nss_lt_name:
981113596Snectar			label = name;
982113596Snectar			break;
983113596Snectar		case nss_lt_id:
984113596Snectar			if (snprintf(buf, sizeof(buf), "%lu",
985113596Snectar			    (unsigned long)gid) >= sizeof(buf))
986113596Snectar				goto fin;
987113596Snectar			label = buf;
988113596Snectar			break;
989113596Snectar		case nss_lt_all:
990113596Snectar			if (st->counter < 0)
991113596Snectar				goto fin;
992113596Snectar			if (snprintf(buf, sizeof(buf), "group-%ld",
993113596Snectar			    st->counter++) >= sizeof(buf))
994113596Snectar				goto fin;
995113596Snectar			label = buf;
996113596Snectar			break;
997113596Snectar		}
998113596Snectar		hes = hesiod_resolve(ctx, label,
999113596Snectar		    how == nss_lt_id ? "gid" : "group");
1000113596Snectar		if ((how == nss_lt_id && hes == NULL &&
1001113596Snectar		    (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
1002113596Snectar		    hes == NULL) {
1003113596Snectar			if (how == nss_lt_all)
1004113596Snectar				st->counter = -1;
1005113596Snectar			if (errno != ENOENT)
1006113596Snectar				*errnop = errno;
1007113596Snectar			goto fin;
1008113596Snectar		}
1009113596Snectar		rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
1010113596Snectar		if (rv != NS_SUCCESS) {
1011113596Snectar			hesiod_free_list(ctx, hes);
1012113596Snectar			hes = NULL;
1013113596Snectar			continue;
1014113596Snectar		}
1015113596Snectar		/* We need room at least for the line, a string NUL
1016113596Snectar		 * terminator, alignment padding, and one (char *)
1017113596Snectar		 * pointer for the member list terminator.
1018113596Snectar		 */
1019113596Snectar		adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
1020114443Snectar		linesize = strlcpy(buffer, hes[0], adjsize);
1021113596Snectar		if (linesize >= adjsize) {
1022113596Snectar			*errnop = ERANGE;
1023113596Snectar			rv = NS_RETURN;
1024113596Snectar			goto fin;
1025113596Snectar		}
1026113596Snectar		hesiod_free_list(ctx, hes);
1027113596Snectar		hes = NULL;
1028113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
1029113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1030113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1031113596Snectarfin:
1032113596Snectar	if (hes != NULL)
1033113596Snectar		hesiod_free_list(ctx, hes);
1034113596Snectar	if (ctx != NULL)
1035113596Snectar		hesiod_end(ctx);
1036113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1037113596Snectar		*(struct group **)retval = grp;
1038113596Snectar	return (rv);
103965532Snectar}
1040113596Snectar#endif /* HESIOD */
104165532Snectar
1042113596Snectar
1043113596Snectar#ifdef YP
104465532Snectar/*
1045113596Snectar * nis backend
104665532Snectar */
1047113596Snectarstatic void
1048113596Snectarnis_endstate(void *p)
1049113596Snectar{
105065532Snectar
1051113596Snectar	if (p == NULL)
1052113596Snectar		return;
1053113596Snectar	free(((struct nis_state *)p)->key);
1054113596Snectar	free(p);
1055113596Snectar}
105665532Snectar
1057113596Snectar
105865532Snectarstatic int
1059113596Snectarnis_setgrent(void *retval, void *cb_data, va_list ap)
106065532Snectar{
1061113596Snectar	struct nis_state	*st;
1062113596Snectar	int			 rv;
106365532Snectar
1064113596Snectar	rv = nis_getstate(&st);
1065113596Snectar	if (rv != 0)
1066113596Snectar		return (NS_UNAVAIL);
1067113596Snectar	st->done = 0;
1068113596Snectar	free(st->key);
1069113596Snectar	st->key = NULL;
1070113596Snectar	return (NS_UNAVAIL);
107165532Snectar}
107265532Snectar
107365532Snectar
107465532Snectarstatic int
1075113596Snectarnis_group(void *retval, void *mdata, va_list ap)
107665532Snectar{
1077113596Snectar	char		 *map;
1078113596Snectar	struct nis_state *st;
1079113596Snectar	struct group	*grp;
1080113596Snectar	const char	*name;
1081113596Snectar	char		*buffer, *key, *result;
1082113596Snectar	size_t		 bufsize;
1083113596Snectar	gid_t		 gid;
1084113596Snectar	enum nss_lookup_type how;
1085113596Snectar	int		*errnop, keylen, resultlen, rv;
1086113596Snectar
1087113596Snectar	name = NULL;
1088113596Snectar	gid = (gid_t)-1;
1089113596Snectar	how = (enum nss_lookup_type)mdata;
1090113596Snectar	switch (how) {
1091113596Snectar	case nss_lt_name:
1092113596Snectar		name = va_arg(ap, const char *);
1093113596Snectar		map = "group.byname";
1094113596Snectar		break;
1095113596Snectar	case nss_lt_id:
1096113596Snectar		gid = va_arg(ap, gid_t);
1097113596Snectar		map = "group.bygid";
1098113596Snectar		break;
1099113596Snectar	case nss_lt_all:
1100113596Snectar		map = "group.byname";
1101113596Snectar		break;
1102113596Snectar	}
1103113596Snectar	grp     = va_arg(ap, struct group *);
1104113596Snectar	buffer  = va_arg(ap, char *);
1105113596Snectar	bufsize = va_arg(ap, size_t);
1106113596Snectar	errnop  = va_arg(ap, int *);
1107113596Snectar	*errnop = nis_getstate(&st);
1108113596Snectar	if (*errnop != 0)
1109113596Snectar		return (NS_UNAVAIL);
1110113596Snectar	if (st->domain[0] == '\0') {
1111113596Snectar		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
1112113596Snectar			*errnop = errno;
1113113596Snectar			return (NS_UNAVAIL);
1114113596Snectar		}
1115113596Snectar	}
1116113596Snectar	result = NULL;
1117113596Snectar	do {
1118113596Snectar		rv = NS_NOTFOUND;
1119113596Snectar		switch (how) {
1120113596Snectar		case nss_lt_name:
1121114443Snectar			if (strlcpy(buffer, name, bufsize) >= bufsize)
1122113596Snectar				goto erange;
1123113596Snectar			break;
1124113596Snectar		case nss_lt_id:
1125113596Snectar			if (snprintf(buffer, bufsize, "%lu",
1126113596Snectar			    (unsigned long)gid) >= bufsize)
1127113596Snectar				goto erange;
1128113596Snectar			break;
1129113596Snectar		case nss_lt_all:
1130113596Snectar			if (st->done)
1131113596Snectar				goto fin;
1132113596Snectar			break;
1133113596Snectar		}
1134113596Snectar		result = NULL;
1135113596Snectar		if (how == nss_lt_all) {
1136113596Snectar			if (st->key == NULL)
1137113596Snectar				rv = yp_first(st->domain, map, &st->key,
1138113596Snectar				    &st->keylen, &result, &resultlen);
1139113596Snectar			else {
1140113596Snectar				key = st->key;
1141113596Snectar				keylen = st->keylen;
1142113596Snectar				st->key = NULL;
1143113596Snectar				rv = yp_next(st->domain, map, key, keylen,
1144113596Snectar				    &st->key, &st->keylen, &result,
1145113596Snectar				    &resultlen);
1146113596Snectar				free(key);
1147113596Snectar			}
1148113596Snectar			if (rv != 0) {
1149113596Snectar				free(result);
1150113596Snectar				free(st->key);
1151113596Snectar				st->key = NULL;
1152113596Snectar				if (rv == YPERR_NOMORE) {
1153113596Snectar					st->done = 1;
1154113596Snectar					rv = NS_NOTFOUND;
1155113596Snectar				} else
1156113596Snectar					rv = NS_UNAVAIL;
1157113596Snectar				goto fin;
1158113596Snectar			}
1159113596Snectar		} else {
1160113596Snectar			rv = yp_match(st->domain, map, buffer, strlen(buffer),
1161113596Snectar			    &result, &resultlen);
1162113596Snectar			if (rv == YPERR_KEY) {
1163113596Snectar				rv = NS_NOTFOUND;
1164113596Snectar				continue;
1165113596Snectar			} else if (rv != 0) {
1166113596Snectar				free(result);
1167113596Snectar				rv = NS_UNAVAIL;
1168113596Snectar				continue;
1169113596Snectar			}
1170113596Snectar		}
1171113596Snectar		/* We need room at least for the line, a string NUL
1172113596Snectar		 * terminator, alignment padding, and one (char *)
1173113596Snectar		 * pointer for the member list terminator.
1174113596Snectar		 */
1175113596Snectar		if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
1176113596Snectar			goto erange;
1177113596Snectar		memcpy(buffer, result, resultlen);
1178113596Snectar		buffer[resultlen] = '\0';
1179113596Snectar		free(result);
1180113596Snectar		rv = __gr_match_entry(buffer, resultlen, how, name, gid);
1181113596Snectar		if (rv == NS_SUCCESS)
1182113596Snectar			rv = __gr_parse_entry(buffer, resultlen, grp,
1183113596Snectar			    &buffer[resultlen+1], bufsize - resultlen - 1,
1184113596Snectar			    errnop);
1185113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1186113596Snectarfin:
1187113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1188113596Snectar		*(struct group **)retval = grp;
1189113596Snectar	return (rv);
1190113596Snectarerange:
1191113596Snectar	*errnop = ERANGE;
1192113596Snectar	return (NS_RETURN);
1193113596Snectar}
1194113596Snectar#endif /* YP */
119565532Snectar
119618046Swpaul
119765532Snectar
1198113596Snectar/*
1199113596Snectar * compat backend
1200113596Snectar */
1201113596Snectarstatic void
1202113596Snectarcompat_endstate(void *p)
1203113596Snectar{
1204113596Snectar	struct compat_state *st;
120565532Snectar
1206113596Snectar	if (p == NULL)
1207113596Snectar		return;
1208113596Snectar	st = (struct compat_state *)p;
1209113596Snectar	free(st->name);
1210113596Snectar	if (st->fp != NULL)
1211113596Snectar		fclose(st->fp);
1212113596Snectar	free(p);
1213113596Snectar}
121465532Snectar
121565532Snectar
1216113596Snectarstatic int
1217113596Snectarcompat_setgrent(void *retval, void *mdata, va_list ap)
1218113596Snectar{
1219114021Snectar	static const ns_src compatsrc[] = {
1220114021Snectar#ifdef YP
1221114021Snectar		{ NSSRC_NIS, NS_SUCCESS },
1222114021Snectar#endif
1223114021Snectar		{ NULL, 0 }
1224114021Snectar	};
1225114021Snectar	ns_dtab dtab[] = {
1226114021Snectar#ifdef HESIOD
1227114021Snectar		{ NSSRC_DNS, dns_setgrent, NULL },
1228114021Snectar#endif
1229114021Snectar#ifdef YP
1230114021Snectar		{ NSSRC_NIS, nis_setgrent, NULL },
1231114021Snectar#endif
1232114021Snectar		{ NULL, NULL, NULL }
1233114021Snectar	};
1234113596Snectar	struct compat_state *st;
1235113596Snectar	int		 rv, stayopen;
1236113596Snectar
1237114021Snectar#define set_setent(x, y) do {	 				\
1238114021Snectar	int i;							\
1239114021Snectar								\
1240114021Snectar	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
1241114021Snectar		x[i].mdata = (void *)y;				\
1242114021Snectar} while (0)
1243114021Snectar
1244113596Snectar	rv = compat_getstate(&st);
1245113596Snectar	if (rv != 0)
1246113596Snectar		return (NS_UNAVAIL);
1247113596Snectar	switch ((enum constants)mdata) {
1248113596Snectar	case SETGRENT:
1249113596Snectar		stayopen = va_arg(ap, int);
1250113596Snectar		if (st->fp != NULL)
1251113596Snectar			rewind(st->fp);
1252113596Snectar		else if (stayopen)
1253244092Sjilles			st->fp = fopen(_PATH_GROUP, "re");
1254114021Snectar		set_setent(dtab, mdata);
1255114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
1256114021Snectar		    compatsrc, 0);
1257113596Snectar		break;
1258113596Snectar	case ENDGRENT:
1259113596Snectar		if (st->fp != NULL) {
1260113596Snectar			fclose(st->fp);
1261113596Snectar			st->fp = NULL;
126265532Snectar		}
1263114021Snectar		set_setent(dtab, mdata);
1264114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
1265114021Snectar		    compatsrc, 0);
1266113596Snectar		break;
1267113596Snectar	default:
1268113596Snectar		break;
12691573Srgrimes	}
1270113596Snectar	st->compat = COMPAT_MODE_OFF;
1271113596Snectar	free(st->name);
1272113596Snectar	st->name = NULL;
1273113596Snectar	return (NS_UNAVAIL);
1274114021Snectar#undef set_setent
12751573Srgrimes}
12762936Swollman
1277113596Snectar
12789331Swpaulstatic int
1279113596Snectarcompat_group(void *retval, void *mdata, va_list ap)
12802936Swollman{
128165532Snectar	static const ns_src compatsrc[] = {
1282113596Snectar#ifdef YP
1283113596Snectar		{ NSSRC_NIS, NS_SUCCESS },
1284113596Snectar#endif
1285113596Snectar		{ NULL, 0 }
128665532Snectar	};
1287113596Snectar	ns_dtab dtab[] = {
1288113596Snectar#ifdef YP
1289113596Snectar		{ NSSRC_NIS, nis_group, NULL },
1290113596Snectar#endif
1291113596Snectar#ifdef HESIOD
1292113596Snectar		{ NSSRC_DNS, dns_group, NULL },
1293113596Snectar#endif
1294113596Snectar		{ NULL, NULL, NULL }
1295113596Snectar	};
1296113596Snectar	struct compat_state	*st;
1297113596Snectar	enum nss_lookup_type	 how;
1298113596Snectar	const char		*name, *line;
1299113596Snectar	struct group		*grp;
1300113596Snectar	gid_t			 gid;
1301113596Snectar	char			*buffer, *p;
1302113596Snectar	void			*discard;
1303113596Snectar	size_t			 bufsize, linesize;
1304159144Smaxim	off_t			 pos;
1305113596Snectar	int			 rv, stayopen, *errnop;
13062936Swollman
1307113596Snectar#define set_lookup_type(x, y) do { 				\
1308113596Snectar	int i;							\
1309113596Snectar								\
1310113596Snectar	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
1311113596Snectar		x[i].mdata = (void *)y;				\
1312113596Snectar} while (0)
13132936Swollman
1314113596Snectar	name = NULL;
1315113596Snectar	gid = (gid_t)-1;
1316113596Snectar	how = (enum nss_lookup_type)mdata;
1317113596Snectar	switch (how) {
1318113596Snectar	case nss_lt_name:
1319113596Snectar		name = va_arg(ap, const char *);
1320113596Snectar		break;
1321113596Snectar	case nss_lt_id:
1322113596Snectar		gid = va_arg(ap, gid_t);
1323113596Snectar		break;
1324113596Snectar	case nss_lt_all:
1325113596Snectar		break;
1326113596Snectar	default:
1327113596Snectar		return (NS_NOTFOUND);
1328113596Snectar	}
1329113596Snectar	grp = va_arg(ap, struct group *);
1330113596Snectar	buffer = va_arg(ap, char *);
1331113596Snectar	bufsize = va_arg(ap, size_t);
1332113596Snectar	errnop = va_arg(ap, int *);
1333113596Snectar	*errnop = compat_getstate(&st);
1334113596Snectar	if (*errnop != 0)
1335113596Snectar		return (NS_UNAVAIL);
1336113596Snectar	if (st->fp == NULL &&
1337244092Sjilles	    ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
1338113596Snectar		*errnop = errno;
1339113596Snectar		rv = NS_UNAVAIL;
1340113596Snectar		goto fin;
1341113596Snectar	}
1342113596Snectar	if (how == nss_lt_all)
1343113596Snectar		stayopen = 1;
1344113596Snectar	else {
1345113596Snectar		rewind(st->fp);
1346113596Snectar		stayopen = st->stayopen;
1347113596Snectar	}
1348113596Snectardocompat:
1349113596Snectar	switch (st->compat) {
1350113596Snectar	case COMPAT_MODE_ALL:
1351113596Snectar		set_lookup_type(dtab, how);
1352113596Snectar		switch (how) {
1353113596Snectar		case nss_lt_all:
1354113596Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1355113596Snectar			    "getgrent_r", compatsrc, grp, buffer, bufsize,
1356113596Snectar			    errnop);
1357113596Snectar			break;
1358113596Snectar		case nss_lt_id:
1359113882Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1360113596Snectar			    "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
1361113596Snectar			    errnop);
1362113596Snectar			break;
1363113596Snectar		case nss_lt_name:
1364113882Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1365113596Snectar			    "getgrnam_r", compatsrc, name, grp, buffer,
1366113596Snectar			    bufsize, errnop);
1367113596Snectar			break;
13682936Swollman		}
1369113596Snectar		if (rv & NS_TERMINATE)
1370113596Snectar			goto fin;
1371113596Snectar		st->compat = COMPAT_MODE_OFF;
1372113596Snectar		break;
1373113596Snectar	case COMPAT_MODE_NAME:
1374113596Snectar		set_lookup_type(dtab, nss_lt_name);
1375113882Snectar		rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1376113596Snectar		    "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
1377113596Snectar		    errnop);
1378113596Snectar		switch (rv) {
1379113596Snectar		case NS_SUCCESS:
1380113596Snectar			switch (how) {
1381113596Snectar			case nss_lt_name:
1382113596Snectar				if (strcmp(name, grp->gr_name) != 0)
1383113596Snectar					rv = NS_NOTFOUND;
1384113596Snectar				break;
1385113596Snectar			case nss_lt_id:
1386113596Snectar				if (gid != grp->gr_gid)
1387113596Snectar					rv = NS_NOTFOUND;
1388113596Snectar				break;
1389113596Snectar			default:
1390113596Snectar				break;
13912936Swollman			}
1392113596Snectar			break;
1393113596Snectar		case NS_RETURN:
1394113596Snectar			goto fin;
1395113596Snectar		default:
1396113596Snectar			break;
1397113596Snectar		}
1398113596Snectar		free(st->name);
1399113596Snectar		st->name = NULL;
1400113596Snectar		st->compat = COMPAT_MODE_OFF;
1401113596Snectar		if (rv == NS_SUCCESS)
1402113596Snectar			goto fin;
1403113596Snectar		break;
1404113596Snectar	default:
1405113596Snectar		break;
1406113596Snectar	}
1407113596Snectar	rv = NS_NOTFOUND;
1408159144Smaxim	pos = ftello(st->fp);
1409113596Snectar	while ((line = fgetln(st->fp, &linesize)) != NULL) {
1410113596Snectar		if (line[linesize-1] == '\n')
1411113596Snectar			linesize--;
1412113596Snectar		if (linesize > 2 && line[0] == '+') {
1413113596Snectar			p = memchr(&line[1], ':', linesize);
1414113596Snectar			if (p == NULL || p == &line[1])
1415113596Snectar				st->compat = COMPAT_MODE_ALL;
1416113596Snectar			else {
1417113596Snectar				st->name = malloc(p - line);
1418113596Snectar				if (st->name == NULL) {
1419113596Snectar					syslog(LOG_ERR,
1420113596Snectar					 "getgrent memory allocation failure");
1421113596Snectar					*errnop = ENOMEM;
1422113596Snectar					rv = NS_UNAVAIL;
1423113596Snectar					break;
1424113596Snectar				}
1425113596Snectar				memcpy(st->name, &line[1], p - line - 1);
1426113596Snectar				st->name[p - line - 1] = '\0';
1427113596Snectar				st->compat = COMPAT_MODE_NAME;
14282936Swollman			}
1429113596Snectar			goto docompat;
1430113596Snectar		}
1431113596Snectar		rv = __gr_match_entry(line, linesize, how, name, gid);
1432113596Snectar		if (rv != NS_SUCCESS)
1433113596Snectar			continue;
1434113596Snectar		/* We need room at least for the line, a string NUL
1435113596Snectar		 * terminator, alignment padding, and one (char *)
1436113596Snectar		 * pointer for the member list terminator.
1437113596Snectar		 */
1438113596Snectar		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
1439113596Snectar			*errnop = ERANGE;
1440113596Snectar			rv = NS_RETURN;
14412936Swollman			break;
1442113596Snectar		}
1443113596Snectar		memcpy(buffer, line, linesize);
1444113596Snectar		buffer[linesize] = '\0';
1445113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
1446113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1447113596Snectar		if (rv & NS_TERMINATE)
1448113596Snectar			break;
1449160355Smaxim		pos = ftello(st->fp);
1450113596Snectar	}
1451113596Snectarfin:
1452113596Snectar	if (!stayopen && st->fp != NULL) {
1453113596Snectar		fclose(st->fp);
1454113596Snectar		st->fp = NULL;
1455113596Snectar	}
1456113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1457113596Snectar		*(struct group **)retval = grp;
1458162391Smaxim	else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
1459160355Smaxim		fseeko(st->fp, pos, SEEK_SET);
1460113596Snectar	return (rv);
1461113596Snectar#undef set_lookup_type
14622936Swollman}
14632936Swollman
1464113596Snectar
1465113596Snectar/*
1466113596Snectar * common group line matching and parsing
1467113596Snectar */
1468113596Snectarint
1469113596Snectar__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
1470113596Snectar    const char *name, gid_t gid)
14712936Swollman{
1472113596Snectar	size_t		 namesize;
1473113596Snectar	const char	*p, *eol;
1474113596Snectar	char		*q;
1475113596Snectar	unsigned long	 n;
1476113596Snectar	int		 i, needed;
14772936Swollman
1478113596Snectar	if (linesize == 0 || is_comment_line(line, linesize))
1479113596Snectar		return (NS_NOTFOUND);
1480113596Snectar	switch (how) {
1481113596Snectar	case nss_lt_name:	needed = 1; break;
1482113596Snectar	case nss_lt_id:		needed = 2; break;
1483113596Snectar	default:		needed = 2; break;
14842936Swollman	}
1485113596Snectar	eol = &line[linesize];
1486113596Snectar	for (p = line, i = 0; i < needed && p < eol; p++)
1487113596Snectar		if (*p == ':')
1488113596Snectar			i++;
1489113596Snectar	if (i < needed)
1490113596Snectar		return (NS_NOTFOUND);
1491113596Snectar	switch (how) {
1492113596Snectar	case nss_lt_name:
1493113596Snectar		namesize = strlen(name);
1494113596Snectar		if (namesize + 1 == (size_t)(p - line) &&
1495113596Snectar		    memcmp(line, name, namesize) == 0)
1496113596Snectar			return (NS_SUCCESS);
1497113596Snectar		break;
1498113596Snectar	case nss_lt_id:
1499113596Snectar		n = strtoul(p, &q, 10);
1500113596Snectar		if (q < eol && *q == ':' && gid == (gid_t)n)
1501113596Snectar			return (NS_SUCCESS);
1502113596Snectar		break;
1503113596Snectar	case nss_lt_all:
1504113596Snectar		return (NS_SUCCESS);
1505113596Snectar	default:
1506113596Snectar		break;
1507113596Snectar	}
1508113596Snectar	return (NS_NOTFOUND);
1509113596Snectar}
15102936Swollman
15112936Swollman
1512113596Snectarint
1513113596Snectar__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
1514113596Snectar    size_t membufsize, int *errnop)
15152936Swollman{
1516113727Snectar	char	       *s_gid, *s_mem, *p, **members;
1517113596Snectar	unsigned long	n;
1518113596Snectar	int		maxmembers;
15192936Swollman
1520113596Snectar	memset(grp, 0, sizeof(*grp));
1521113596Snectar	members = (char **)_ALIGN(membuf);
1522113596Snectar	membufsize -= (char *)members - membuf;
1523113596Snectar	maxmembers = membufsize / sizeof(*members);
1524113596Snectar	if (maxmembers <= 0 ||
1525113596Snectar	    (grp->gr_name = strsep(&line, ":")) == NULL ||
1526113596Snectar	    grp->gr_name[0] == '\0' ||
1527113596Snectar	    (grp->gr_passwd = strsep(&line, ":")) == NULL ||
1528113596Snectar	    (s_gid = strsep(&line, ":")) == NULL ||
1529113596Snectar	    s_gid[0] == '\0')
1530113596Snectar		return (NS_NOTFOUND);
1531113596Snectar	s_mem = line;
1532113596Snectar	n = strtoul(s_gid, &s_gid, 10);
1533113596Snectar	if (s_gid[0] != '\0')
1534113596Snectar		return (NS_NOTFOUND);
1535113596Snectar	grp->gr_gid = (gid_t)n;
1536113596Snectar	grp->gr_mem = members;
1537113596Snectar	while (maxmembers > 1 && s_mem != NULL) {
1538113727Snectar		p = strsep(&s_mem, ",");
1539113727Snectar		if (p != NULL && *p != '\0') {
1540113727Snectar			*members++ = p;
1541113727Snectar			maxmembers--;
1542113727Snectar		}
1543113596Snectar	}
1544113596Snectar	*members = NULL;
1545113596Snectar	if (s_mem == NULL)
1546113596Snectar		return (NS_SUCCESS);
1547113596Snectar	else {
1548113596Snectar		*errnop = ERANGE;
1549113596Snectar		return (NS_RETURN);
1550113596Snectar	}
15512936Swollman}
1552174547Sbushman
1553174547Sbushman
1554