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$");
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	int rv;
663174547Sbushman
664174547Sbushman	assert(uname != NULL);
665174547Sbushman	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
666174547Sbushman	assert(grpcnt != NULL);
667174547Sbushman
668174547Sbushman	*grpcnt = 0;
669174547Sbushman	rv = _nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
670174547Sbushman	    defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
671174547Sbushman
672174547Sbushman	/* too many groups found? */
673174547Sbushman	return (*grpcnt > maxgrp ? -1 : 0);
674174547Sbushman}
675174547Sbushman
676174547Sbushman
677113596Snectarstatic struct group	 grp;
678113596Snectarstatic char		*grp_storage;
679113596Snectarstatic size_t		 grp_storage_size;
680113596Snectar
681113596Snectarstatic struct group *
682113596Snectargetgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
683113596Snectar    union key key)
68465532Snectar{
685113596Snectar	int		 rv;
686113596Snectar	struct group	*res;
687113596Snectar
688113596Snectar	if (grp_storage == NULL) {
689113596Snectar		grp_storage = malloc(GRP_STORAGE_INITIAL);
690113596Snectar		if (grp_storage == NULL)
691113596Snectar			return (NULL);
692113596Snectar		grp_storage_size = GRP_STORAGE_INITIAL;
69320911Swosch	}
694113596Snectar	do {
695113596Snectar		rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
696113596Snectar		if (res == NULL && rv == ERANGE) {
697113596Snectar			free(grp_storage);
698113596Snectar			if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
699113596Snectar				grp_storage = NULL;
700129367Skientzle				errno = ERANGE;
701113596Snectar				return (NULL);
702113596Snectar			}
703113596Snectar			grp_storage_size <<= 1;
704113596Snectar			grp_storage = malloc(grp_storage_size);
705113596Snectar			if (grp_storage == NULL)
706113596Snectar				return (NULL);
707113596Snectar		}
708113596Snectar	} while (res == NULL && rv == ERANGE);
709129367Skientzle	if (rv != 0)
710129367Skientzle		errno = rv;
711113596Snectar	return (res);
7121573Srgrimes}
7131573Srgrimes
714113596Snectar
715113596Snectarstatic int
716113596Snectarwrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
717113596Snectar    struct group **res)
7181573Srgrimes{
719113596Snectar	return (getgrnam_r(key.name, grp, buffer, bufsize, res));
7201573Srgrimes}
7211573Srgrimes
722113596Snectar
723113596Snectarstatic int
724113596Snectarwrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
725113596Snectar    struct group **res)
7261573Srgrimes{
727113596Snectar	return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
7281573Srgrimes}
7291573Srgrimes
730113596Snectar
731113596Snectarstatic int
732113596Snectarwrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
733113596Snectar    size_t bufsize, struct group **res)
7341573Srgrimes{
735113596Snectar	return (getgrent_r(grp, buffer, bufsize, res));
7361573Srgrimes}
7371573Srgrimes
73865532Snectar
739113596Snectarstruct group *
740113596Snectargetgrnam(const char *name)
741113596Snectar{
742113596Snectar	union key key;
74365532Snectar
744113596Snectar	key.name = name;
745113596Snectar	return (getgr(wrap_getgrnam_r, key));
746113596Snectar}
747113596Snectar
748113596Snectar
749113596Snectarstruct group *
750113596Snectargetgrgid(gid_t gid)
7511573Srgrimes{
752113596Snectar	union key key;
75320911Swosch
754113596Snectar	key.gid = gid;
755113596Snectar	return (getgr(wrap_getgrgid_r, key));
75665532Snectar}
75720911Swosch
7581573Srgrimes
759113596Snectarstruct group *
760113596Snectargetgrent(void)
76165532Snectar{
762113596Snectar	union key key;
76320911Swosch
764113596Snectar	key.gid = 0; /* not used */
765113596Snectar	return (getgr(wrap_getgrent_r, key));
766113596Snectar}
76765532Snectar
76865532Snectar
769113596Snectarstatic int
770113596Snectaris_comment_line(const char *s, size_t n)
771113596Snectar{
772113596Snectar	const char	*eom;
77320911Swosch
774113596Snectar	eom = &s[n];
775113596Snectar
776113596Snectar	for (; s < eom; s++)
777113596Snectar		if (*s == '#' || !isspace((unsigned char)*s))
77865532Snectar			break;
779113596Snectar	return (*s == '#' || s == eom);
780113596Snectar}
78165532Snectar
782113596Snectar
783113596Snectar/*
784113596Snectar * files backend
785113596Snectar */
786113596Snectarstatic void
787113596Snectarfiles_endstate(void *p)
788113596Snectar{
789113596Snectar
790113596Snectar	if (p == NULL)
791113596Snectar		return;
792113596Snectar	if (((struct files_state *)p)->fp != NULL)
793113596Snectar		fclose(((struct files_state *)p)->fp);
794113596Snectar	free(p);
795113596Snectar}
796113596Snectar
797113596Snectar
798113596Snectarstatic int
799113596Snectarfiles_setgrent(void *retval, void *mdata, va_list ap)
800113596Snectar{
801113596Snectar	struct files_state *st;
802113596Snectar	int		 rv, stayopen;
803113596Snectar
804113596Snectar	rv = files_getstate(&st);
805113596Snectar	if (rv != 0)
806113596Snectar		return (NS_UNAVAIL);
807113596Snectar	switch ((enum constants)mdata) {
808113596Snectar	case SETGRENT:
809113596Snectar		stayopen = va_arg(ap, int);
810113596Snectar		if (st->fp != NULL)
811113596Snectar			rewind(st->fp);
812113596Snectar		else if (stayopen)
813244092Sjilles			st->fp = fopen(_PATH_GROUP, "re");
814113596Snectar		break;
815113596Snectar	case ENDGRENT:
816113596Snectar		if (st->fp != NULL) {
817113596Snectar			fclose(st->fp);
818113596Snectar			st->fp = NULL;
819112404Srobert		}
820113596Snectar		break;
821113596Snectar	default:
822113596Snectar		break;
82365532Snectar	}
824113596Snectar	return (NS_UNAVAIL);
82565532Snectar}
82620911Swosch
82720911Swosch
82865532Snectarstatic int
829113596Snectarfiles_group(void *retval, void *mdata, va_list ap)
83065532Snectar{
831113596Snectar	struct files_state	*st;
832113596Snectar	enum nss_lookup_type	 how;
833113596Snectar	const char		*name, *line;
834113596Snectar	struct group		*grp;
835113596Snectar	gid_t			 gid;
836113596Snectar	char			*buffer;
837113596Snectar	size_t			 bufsize, linesize;
838159144Smaxim	off_t			 pos;
839113596Snectar	int			 rv, stayopen, *errnop;
84065532Snectar
841113596Snectar	name = NULL;
842113596Snectar	gid = (gid_t)-1;
843113596Snectar	how = (enum nss_lookup_type)mdata;
844113596Snectar	switch (how) {
845113596Snectar	case nss_lt_name:
846113596Snectar		name = va_arg(ap, const char *);
847113596Snectar		break;
848113596Snectar	case nss_lt_id:
849113596Snectar		gid = va_arg(ap, gid_t);
850113596Snectar		break;
851113596Snectar	case nss_lt_all:
852113596Snectar		break;
853113596Snectar	default:
854113596Snectar		return (NS_NOTFOUND);
855113596Snectar	}
856113596Snectar	grp = va_arg(ap, struct group *);
857113596Snectar	buffer = va_arg(ap, char *);
858113596Snectar	bufsize = va_arg(ap, size_t);
859113596Snectar	errnop = va_arg(ap, int *);
860113596Snectar	*errnop = files_getstate(&st);
861113596Snectar	if (*errnop != 0)
862113596Snectar		return (NS_UNAVAIL);
863113596Snectar	if (st->fp == NULL &&
864244092Sjilles	    ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
865113596Snectar		*errnop = errno;
866113596Snectar		return (NS_UNAVAIL);
867113596Snectar	}
868113596Snectar	if (how == nss_lt_all)
869113596Snectar		stayopen = 1;
870113596Snectar	else {
871113596Snectar		rewind(st->fp);
872113596Snectar		stayopen = st->stayopen;
873113596Snectar	}
874113596Snectar	rv = NS_NOTFOUND;
875159144Smaxim	pos = ftello(st->fp);
876113596Snectar	while ((line = fgetln(st->fp, &linesize)) != NULL) {
877113596Snectar		if (line[linesize-1] == '\n')
878113596Snectar			linesize--;
879113596Snectar		rv = __gr_match_entry(line, linesize, how, name, gid);
880113596Snectar		if (rv != NS_SUCCESS)
881113596Snectar			continue;
882113596Snectar		/* We need room at least for the line, a string NUL
883113596Snectar		 * terminator, alignment padding, and one (char *)
884113596Snectar		 * pointer for the member list terminator.
885113596Snectar		 */
886113596Snectar		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
887113596Snectar			*errnop = ERANGE;
888113596Snectar			rv = NS_RETURN;
88911286Swpaul			break;
8908172Swpaul		}
891113596Snectar		memcpy(buffer, line, linesize);
892113596Snectar		buffer[linesize] = '\0';
893113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
894113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
895113596Snectar		if (rv & NS_TERMINATE)
89665532Snectar			break;
897160355Smaxim		pos = ftello(st->fp);
89865532Snectar	}
899113596Snectar	if (!stayopen && st->fp != NULL) {
900113596Snectar		fclose(st->fp);
901113596Snectar		st->fp = NULL;
90265532Snectar	}
903113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
904113596Snectar		*(struct group **)retval = grp;
905162391Smaxim	else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
906160355Smaxim		fseeko(st->fp, pos, SEEK_SET);
907113596Snectar	return (rv);
90865532Snectar}
90965532Snectar
910113596Snectar
911113596Snectar#ifdef HESIOD
91265532Snectar/*
913113596Snectar * dns backend
91465532Snectar */
915113596Snectarstatic void
916113596Snectardns_endstate(void *p)
917113596Snectar{
91865532Snectar
919113596Snectar	free(p);
920113596Snectar}
921113596Snectar
922113596Snectar
92365532Snectarstatic int
924113596Snectardns_setgrent(void *retval, void *cb_data, va_list ap)
92565532Snectar{
926113596Snectar	struct dns_state	*st;
927113596Snectar	int			 rv;
92865532Snectar
929113596Snectar	rv = dns_getstate(&st);
930113596Snectar	if (rv != 0)
931113596Snectar		return (NS_UNAVAIL);
932113596Snectar	st->counter = 0;
933113596Snectar	return (NS_UNAVAIL);
934113596Snectar}
935113596Snectar
936113596Snectar
937113596Snectarstatic int
938113596Snectardns_group(void *retval, void *mdata, va_list ap)
939113596Snectar{
940113596Snectar	char			 buf[HESIOD_NAME_MAX];
941113596Snectar	struct dns_state	*st;
942113596Snectar	struct group		*grp;
943113596Snectar	const char		*name, *label;
944113596Snectar	void			*ctx;
945113596Snectar	char			*buffer, **hes;
946113596Snectar	size_t			 bufsize, adjsize, linesize;
947113596Snectar	gid_t			 gid;
948113596Snectar	enum nss_lookup_type	 how;
949113596Snectar	int			 rv, *errnop;
950113596Snectar
951113596Snectar	ctx = NULL;
952113596Snectar	hes = NULL;
953113596Snectar	name = NULL;
954113596Snectar	gid = (gid_t)-1;
955113596Snectar	how = (enum nss_lookup_type)mdata;
956113596Snectar	switch (how) {
957113596Snectar	case nss_lt_name:
958113596Snectar		name = va_arg(ap, const char *);
959113596Snectar		break;
960113596Snectar	case nss_lt_id:
961113596Snectar		gid = va_arg(ap, gid_t);
962113596Snectar		break;
963113596Snectar	case nss_lt_all:
964113596Snectar		break;
96565532Snectar	}
966113596Snectar	grp     = va_arg(ap, struct group *);
967113596Snectar	buffer  = va_arg(ap, char *);
968113596Snectar	bufsize = va_arg(ap, size_t);
969113596Snectar	errnop  = va_arg(ap, int *);
970113596Snectar	*errnop = dns_getstate(&st);
971113596Snectar	if (*errnop != 0)
972113596Snectar		return (NS_UNAVAIL);
973113596Snectar	if (hesiod_init(&ctx) != 0) {
974113596Snectar		*errnop = errno;
975113596Snectar		rv = NS_UNAVAIL;
976113596Snectar		goto fin;
977113596Snectar	}
978113596Snectar	do {
979113596Snectar		rv = NS_NOTFOUND;
980113596Snectar		switch (how) {
981113596Snectar		case nss_lt_name:
982113596Snectar			label = name;
983113596Snectar			break;
984113596Snectar		case nss_lt_id:
985113596Snectar			if (snprintf(buf, sizeof(buf), "%lu",
986113596Snectar			    (unsigned long)gid) >= sizeof(buf))
987113596Snectar				goto fin;
988113596Snectar			label = buf;
989113596Snectar			break;
990113596Snectar		case nss_lt_all:
991113596Snectar			if (st->counter < 0)
992113596Snectar				goto fin;
993113596Snectar			if (snprintf(buf, sizeof(buf), "group-%ld",
994113596Snectar			    st->counter++) >= sizeof(buf))
995113596Snectar				goto fin;
996113596Snectar			label = buf;
997113596Snectar			break;
998113596Snectar		}
999113596Snectar		hes = hesiod_resolve(ctx, label,
1000113596Snectar		    how == nss_lt_id ? "gid" : "group");
1001113596Snectar		if ((how == nss_lt_id && hes == NULL &&
1002113596Snectar		    (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
1003113596Snectar		    hes == NULL) {
1004113596Snectar			if (how == nss_lt_all)
1005113596Snectar				st->counter = -1;
1006113596Snectar			if (errno != ENOENT)
1007113596Snectar				*errnop = errno;
1008113596Snectar			goto fin;
1009113596Snectar		}
1010113596Snectar		rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
1011113596Snectar		if (rv != NS_SUCCESS) {
1012113596Snectar			hesiod_free_list(ctx, hes);
1013113596Snectar			hes = NULL;
1014113596Snectar			continue;
1015113596Snectar		}
1016113596Snectar		/* We need room at least for the line, a string NUL
1017113596Snectar		 * terminator, alignment padding, and one (char *)
1018113596Snectar		 * pointer for the member list terminator.
1019113596Snectar		 */
1020113596Snectar		adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
1021114443Snectar		linesize = strlcpy(buffer, hes[0], adjsize);
1022113596Snectar		if (linesize >= adjsize) {
1023113596Snectar			*errnop = ERANGE;
1024113596Snectar			rv = NS_RETURN;
1025113596Snectar			goto fin;
1026113596Snectar		}
1027113596Snectar		hesiod_free_list(ctx, hes);
1028113596Snectar		hes = NULL;
1029113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
1030113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1031113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1032113596Snectarfin:
1033113596Snectar	if (hes != NULL)
1034113596Snectar		hesiod_free_list(ctx, hes);
1035113596Snectar	if (ctx != NULL)
1036113596Snectar		hesiod_end(ctx);
1037113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1038113596Snectar		*(struct group **)retval = grp;
1039113596Snectar	return (rv);
104065532Snectar}
1041113596Snectar#endif /* HESIOD */
104265532Snectar
1043113596Snectar
1044113596Snectar#ifdef YP
104565532Snectar/*
1046113596Snectar * nis backend
104765532Snectar */
1048113596Snectarstatic void
1049113596Snectarnis_endstate(void *p)
1050113596Snectar{
105165532Snectar
1052113596Snectar	if (p == NULL)
1053113596Snectar		return;
1054113596Snectar	free(((struct nis_state *)p)->key);
1055113596Snectar	free(p);
1056113596Snectar}
105765532Snectar
1058113596Snectar
105965532Snectarstatic int
1060113596Snectarnis_setgrent(void *retval, void *cb_data, va_list ap)
106165532Snectar{
1062113596Snectar	struct nis_state	*st;
1063113596Snectar	int			 rv;
106465532Snectar
1065113596Snectar	rv = nis_getstate(&st);
1066113596Snectar	if (rv != 0)
1067113596Snectar		return (NS_UNAVAIL);
1068113596Snectar	st->done = 0;
1069113596Snectar	free(st->key);
1070113596Snectar	st->key = NULL;
1071113596Snectar	return (NS_UNAVAIL);
107265532Snectar}
107365532Snectar
107465532Snectar
107565532Snectarstatic int
1076113596Snectarnis_group(void *retval, void *mdata, va_list ap)
107765532Snectar{
1078113596Snectar	char		 *map;
1079113596Snectar	struct nis_state *st;
1080113596Snectar	struct group	*grp;
1081113596Snectar	const char	*name;
1082113596Snectar	char		*buffer, *key, *result;
1083113596Snectar	size_t		 bufsize;
1084113596Snectar	gid_t		 gid;
1085113596Snectar	enum nss_lookup_type how;
1086113596Snectar	int		*errnop, keylen, resultlen, rv;
1087113596Snectar
1088113596Snectar	name = NULL;
1089113596Snectar	gid = (gid_t)-1;
1090113596Snectar	how = (enum nss_lookup_type)mdata;
1091113596Snectar	switch (how) {
1092113596Snectar	case nss_lt_name:
1093113596Snectar		name = va_arg(ap, const char *);
1094113596Snectar		map = "group.byname";
1095113596Snectar		break;
1096113596Snectar	case nss_lt_id:
1097113596Snectar		gid = va_arg(ap, gid_t);
1098113596Snectar		map = "group.bygid";
1099113596Snectar		break;
1100113596Snectar	case nss_lt_all:
1101113596Snectar		map = "group.byname";
1102113596Snectar		break;
1103113596Snectar	}
1104113596Snectar	grp     = va_arg(ap, struct group *);
1105113596Snectar	buffer  = va_arg(ap, char *);
1106113596Snectar	bufsize = va_arg(ap, size_t);
1107113596Snectar	errnop  = va_arg(ap, int *);
1108113596Snectar	*errnop = nis_getstate(&st);
1109113596Snectar	if (*errnop != 0)
1110113596Snectar		return (NS_UNAVAIL);
1111113596Snectar	if (st->domain[0] == '\0') {
1112113596Snectar		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
1113113596Snectar			*errnop = errno;
1114113596Snectar			return (NS_UNAVAIL);
1115113596Snectar		}
1116113596Snectar	}
1117113596Snectar	result = NULL;
1118113596Snectar	do {
1119113596Snectar		rv = NS_NOTFOUND;
1120113596Snectar		switch (how) {
1121113596Snectar		case nss_lt_name:
1122114443Snectar			if (strlcpy(buffer, name, bufsize) >= bufsize)
1123113596Snectar				goto erange;
1124113596Snectar			break;
1125113596Snectar		case nss_lt_id:
1126113596Snectar			if (snprintf(buffer, bufsize, "%lu",
1127113596Snectar			    (unsigned long)gid) >= bufsize)
1128113596Snectar				goto erange;
1129113596Snectar			break;
1130113596Snectar		case nss_lt_all:
1131113596Snectar			if (st->done)
1132113596Snectar				goto fin;
1133113596Snectar			break;
1134113596Snectar		}
1135113596Snectar		result = NULL;
1136113596Snectar		if (how == nss_lt_all) {
1137113596Snectar			if (st->key == NULL)
1138113596Snectar				rv = yp_first(st->domain, map, &st->key,
1139113596Snectar				    &st->keylen, &result, &resultlen);
1140113596Snectar			else {
1141113596Snectar				key = st->key;
1142113596Snectar				keylen = st->keylen;
1143113596Snectar				st->key = NULL;
1144113596Snectar				rv = yp_next(st->domain, map, key, keylen,
1145113596Snectar				    &st->key, &st->keylen, &result,
1146113596Snectar				    &resultlen);
1147113596Snectar				free(key);
1148113596Snectar			}
1149113596Snectar			if (rv != 0) {
1150113596Snectar				free(result);
1151113596Snectar				free(st->key);
1152113596Snectar				st->key = NULL;
1153113596Snectar				if (rv == YPERR_NOMORE) {
1154113596Snectar					st->done = 1;
1155113596Snectar					rv = NS_NOTFOUND;
1156113596Snectar				} else
1157113596Snectar					rv = NS_UNAVAIL;
1158113596Snectar				goto fin;
1159113596Snectar			}
1160113596Snectar		} else {
1161113596Snectar			rv = yp_match(st->domain, map, buffer, strlen(buffer),
1162113596Snectar			    &result, &resultlen);
1163113596Snectar			if (rv == YPERR_KEY) {
1164113596Snectar				rv = NS_NOTFOUND;
1165113596Snectar				continue;
1166113596Snectar			} else if (rv != 0) {
1167113596Snectar				free(result);
1168113596Snectar				rv = NS_UNAVAIL;
1169113596Snectar				continue;
1170113596Snectar			}
1171113596Snectar		}
1172113596Snectar		/* We need room at least for the line, a string NUL
1173113596Snectar		 * terminator, alignment padding, and one (char *)
1174113596Snectar		 * pointer for the member list terminator.
1175113596Snectar		 */
1176113596Snectar		if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
1177113596Snectar			goto erange;
1178113596Snectar		memcpy(buffer, result, resultlen);
1179113596Snectar		buffer[resultlen] = '\0';
1180113596Snectar		free(result);
1181113596Snectar		rv = __gr_match_entry(buffer, resultlen, how, name, gid);
1182113596Snectar		if (rv == NS_SUCCESS)
1183113596Snectar			rv = __gr_parse_entry(buffer, resultlen, grp,
1184113596Snectar			    &buffer[resultlen+1], bufsize - resultlen - 1,
1185113596Snectar			    errnop);
1186113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1187113596Snectarfin:
1188113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1189113596Snectar		*(struct group **)retval = grp;
1190113596Snectar	return (rv);
1191113596Snectarerange:
1192113596Snectar	*errnop = ERANGE;
1193113596Snectar	return (NS_RETURN);
1194113596Snectar}
1195113596Snectar#endif /* YP */
119665532Snectar
119718046Swpaul
119865532Snectar
1199113596Snectar/*
1200113596Snectar * compat backend
1201113596Snectar */
1202113596Snectarstatic void
1203113596Snectarcompat_endstate(void *p)
1204113596Snectar{
1205113596Snectar	struct compat_state *st;
120665532Snectar
1207113596Snectar	if (p == NULL)
1208113596Snectar		return;
1209113596Snectar	st = (struct compat_state *)p;
1210113596Snectar	free(st->name);
1211113596Snectar	if (st->fp != NULL)
1212113596Snectar		fclose(st->fp);
1213113596Snectar	free(p);
1214113596Snectar}
121565532Snectar
121665532Snectar
1217113596Snectarstatic int
1218113596Snectarcompat_setgrent(void *retval, void *mdata, va_list ap)
1219113596Snectar{
1220114021Snectar	static const ns_src compatsrc[] = {
1221114021Snectar#ifdef YP
1222114021Snectar		{ NSSRC_NIS, NS_SUCCESS },
1223114021Snectar#endif
1224114021Snectar		{ NULL, 0 }
1225114021Snectar	};
1226114021Snectar	ns_dtab dtab[] = {
1227114021Snectar#ifdef HESIOD
1228114021Snectar		{ NSSRC_DNS, dns_setgrent, NULL },
1229114021Snectar#endif
1230114021Snectar#ifdef YP
1231114021Snectar		{ NSSRC_NIS, nis_setgrent, NULL },
1232114021Snectar#endif
1233114021Snectar		{ NULL, NULL, NULL }
1234114021Snectar	};
1235113596Snectar	struct compat_state *st;
1236113596Snectar	int		 rv, stayopen;
1237113596Snectar
1238114021Snectar#define set_setent(x, y) do {	 				\
1239114021Snectar	int i;							\
1240114021Snectar								\
1241114021Snectar	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
1242114021Snectar		x[i].mdata = (void *)y;				\
1243114021Snectar} while (0)
1244114021Snectar
1245113596Snectar	rv = compat_getstate(&st);
1246113596Snectar	if (rv != 0)
1247113596Snectar		return (NS_UNAVAIL);
1248113596Snectar	switch ((enum constants)mdata) {
1249113596Snectar	case SETGRENT:
1250113596Snectar		stayopen = va_arg(ap, int);
1251113596Snectar		if (st->fp != NULL)
1252113596Snectar			rewind(st->fp);
1253113596Snectar		else if (stayopen)
1254244092Sjilles			st->fp = fopen(_PATH_GROUP, "re");
1255114021Snectar		set_setent(dtab, mdata);
1256114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
1257114021Snectar		    compatsrc, 0);
1258113596Snectar		break;
1259113596Snectar	case ENDGRENT:
1260113596Snectar		if (st->fp != NULL) {
1261113596Snectar			fclose(st->fp);
1262113596Snectar			st->fp = NULL;
126365532Snectar		}
1264114021Snectar		set_setent(dtab, mdata);
1265114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
1266114021Snectar		    compatsrc, 0);
1267113596Snectar		break;
1268113596Snectar	default:
1269113596Snectar		break;
12701573Srgrimes	}
1271113596Snectar	st->compat = COMPAT_MODE_OFF;
1272113596Snectar	free(st->name);
1273113596Snectar	st->name = NULL;
1274113596Snectar	return (NS_UNAVAIL);
1275114021Snectar#undef set_setent
12761573Srgrimes}
12772936Swollman
1278113596Snectar
12799331Swpaulstatic int
1280113596Snectarcompat_group(void *retval, void *mdata, va_list ap)
12812936Swollman{
128265532Snectar	static const ns_src compatsrc[] = {
1283113596Snectar#ifdef YP
1284113596Snectar		{ NSSRC_NIS, NS_SUCCESS },
1285113596Snectar#endif
1286113596Snectar		{ NULL, 0 }
128765532Snectar	};
1288113596Snectar	ns_dtab dtab[] = {
1289113596Snectar#ifdef YP
1290113596Snectar		{ NSSRC_NIS, nis_group, NULL },
1291113596Snectar#endif
1292113596Snectar#ifdef HESIOD
1293113596Snectar		{ NSSRC_DNS, dns_group, NULL },
1294113596Snectar#endif
1295113596Snectar		{ NULL, NULL, NULL }
1296113596Snectar	};
1297113596Snectar	struct compat_state	*st;
1298113596Snectar	enum nss_lookup_type	 how;
1299113596Snectar	const char		*name, *line;
1300113596Snectar	struct group		*grp;
1301113596Snectar	gid_t			 gid;
1302113596Snectar	char			*buffer, *p;
1303113596Snectar	void			*discard;
1304113596Snectar	size_t			 bufsize, linesize;
1305159144Smaxim	off_t			 pos;
1306113596Snectar	int			 rv, stayopen, *errnop;
13072936Swollman
1308113596Snectar#define set_lookup_type(x, y) do { 				\
1309113596Snectar	int i;							\
1310113596Snectar								\
1311113596Snectar	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
1312113596Snectar		x[i].mdata = (void *)y;				\
1313113596Snectar} while (0)
13142936Swollman
1315113596Snectar	name = NULL;
1316113596Snectar	gid = (gid_t)-1;
1317113596Snectar	how = (enum nss_lookup_type)mdata;
1318113596Snectar	switch (how) {
1319113596Snectar	case nss_lt_name:
1320113596Snectar		name = va_arg(ap, const char *);
1321113596Snectar		break;
1322113596Snectar	case nss_lt_id:
1323113596Snectar		gid = va_arg(ap, gid_t);
1324113596Snectar		break;
1325113596Snectar	case nss_lt_all:
1326113596Snectar		break;
1327113596Snectar	default:
1328113596Snectar		return (NS_NOTFOUND);
1329113596Snectar	}
1330113596Snectar	grp = va_arg(ap, struct group *);
1331113596Snectar	buffer = va_arg(ap, char *);
1332113596Snectar	bufsize = va_arg(ap, size_t);
1333113596Snectar	errnop = va_arg(ap, int *);
1334113596Snectar	*errnop = compat_getstate(&st);
1335113596Snectar	if (*errnop != 0)
1336113596Snectar		return (NS_UNAVAIL);
1337113596Snectar	if (st->fp == NULL &&
1338244092Sjilles	    ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
1339113596Snectar		*errnop = errno;
1340113596Snectar		rv = NS_UNAVAIL;
1341113596Snectar		goto fin;
1342113596Snectar	}
1343113596Snectar	if (how == nss_lt_all)
1344113596Snectar		stayopen = 1;
1345113596Snectar	else {
1346113596Snectar		rewind(st->fp);
1347113596Snectar		stayopen = st->stayopen;
1348113596Snectar	}
1349113596Snectardocompat:
1350113596Snectar	switch (st->compat) {
1351113596Snectar	case COMPAT_MODE_ALL:
1352113596Snectar		set_lookup_type(dtab, how);
1353113596Snectar		switch (how) {
1354113596Snectar		case nss_lt_all:
1355113596Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1356113596Snectar			    "getgrent_r", compatsrc, grp, buffer, bufsize,
1357113596Snectar			    errnop);
1358113596Snectar			break;
1359113596Snectar		case nss_lt_id:
1360113882Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1361113596Snectar			    "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
1362113596Snectar			    errnop);
1363113596Snectar			break;
1364113596Snectar		case nss_lt_name:
1365113882Snectar			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1366113596Snectar			    "getgrnam_r", compatsrc, name, grp, buffer,
1367113596Snectar			    bufsize, errnop);
1368113596Snectar			break;
13692936Swollman		}
1370113596Snectar		if (rv & NS_TERMINATE)
1371113596Snectar			goto fin;
1372113596Snectar		st->compat = COMPAT_MODE_OFF;
1373113596Snectar		break;
1374113596Snectar	case COMPAT_MODE_NAME:
1375113596Snectar		set_lookup_type(dtab, nss_lt_name);
1376113882Snectar		rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
1377113596Snectar		    "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
1378113596Snectar		    errnop);
1379113596Snectar		switch (rv) {
1380113596Snectar		case NS_SUCCESS:
1381113596Snectar			switch (how) {
1382113596Snectar			case nss_lt_name:
1383113596Snectar				if (strcmp(name, grp->gr_name) != 0)
1384113596Snectar					rv = NS_NOTFOUND;
1385113596Snectar				break;
1386113596Snectar			case nss_lt_id:
1387113596Snectar				if (gid != grp->gr_gid)
1388113596Snectar					rv = NS_NOTFOUND;
1389113596Snectar				break;
1390113596Snectar			default:
1391113596Snectar				break;
13922936Swollman			}
1393113596Snectar			break;
1394113596Snectar		case NS_RETURN:
1395113596Snectar			goto fin;
1396113596Snectar		default:
1397113596Snectar			break;
1398113596Snectar		}
1399113596Snectar		free(st->name);
1400113596Snectar		st->name = NULL;
1401113596Snectar		st->compat = COMPAT_MODE_OFF;
1402113596Snectar		if (rv == NS_SUCCESS)
1403113596Snectar			goto fin;
1404113596Snectar		break;
1405113596Snectar	default:
1406113596Snectar		break;
1407113596Snectar	}
1408113596Snectar	rv = NS_NOTFOUND;
1409159144Smaxim	pos = ftello(st->fp);
1410113596Snectar	while ((line = fgetln(st->fp, &linesize)) != NULL) {
1411113596Snectar		if (line[linesize-1] == '\n')
1412113596Snectar			linesize--;
1413113596Snectar		if (linesize > 2 && line[0] == '+') {
1414113596Snectar			p = memchr(&line[1], ':', linesize);
1415113596Snectar			if (p == NULL || p == &line[1])
1416113596Snectar				st->compat = COMPAT_MODE_ALL;
1417113596Snectar			else {
1418113596Snectar				st->name = malloc(p - line);
1419113596Snectar				if (st->name == NULL) {
1420113596Snectar					syslog(LOG_ERR,
1421113596Snectar					 "getgrent memory allocation failure");
1422113596Snectar					*errnop = ENOMEM;
1423113596Snectar					rv = NS_UNAVAIL;
1424113596Snectar					break;
1425113596Snectar				}
1426113596Snectar				memcpy(st->name, &line[1], p - line - 1);
1427113596Snectar				st->name[p - line - 1] = '\0';
1428113596Snectar				st->compat = COMPAT_MODE_NAME;
14292936Swollman			}
1430113596Snectar			goto docompat;
1431113596Snectar		}
1432113596Snectar		rv = __gr_match_entry(line, linesize, how, name, gid);
1433113596Snectar		if (rv != NS_SUCCESS)
1434113596Snectar			continue;
1435113596Snectar		/* We need room at least for the line, a string NUL
1436113596Snectar		 * terminator, alignment padding, and one (char *)
1437113596Snectar		 * pointer for the member list terminator.
1438113596Snectar		 */
1439113596Snectar		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
1440113596Snectar			*errnop = ERANGE;
1441113596Snectar			rv = NS_RETURN;
14422936Swollman			break;
1443113596Snectar		}
1444113596Snectar		memcpy(buffer, line, linesize);
1445113596Snectar		buffer[linesize] = '\0';
1446113596Snectar		rv = __gr_parse_entry(buffer, linesize, grp,
1447113596Snectar		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1448113596Snectar		if (rv & NS_TERMINATE)
1449113596Snectar			break;
1450160355Smaxim		pos = ftello(st->fp);
1451113596Snectar	}
1452113596Snectarfin:
1453113596Snectar	if (!stayopen && st->fp != NULL) {
1454113596Snectar		fclose(st->fp);
1455113596Snectar		st->fp = NULL;
1456113596Snectar	}
1457113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1458113596Snectar		*(struct group **)retval = grp;
1459162391Smaxim	else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
1460160355Smaxim		fseeko(st->fp, pos, SEEK_SET);
1461113596Snectar	return (rv);
1462113596Snectar#undef set_lookup_type
14632936Swollman}
14642936Swollman
1465113596Snectar
1466113596Snectar/*
1467113596Snectar * common group line matching and parsing
1468113596Snectar */
1469113596Snectarint
1470113596Snectar__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
1471113596Snectar    const char *name, gid_t gid)
14722936Swollman{
1473113596Snectar	size_t		 namesize;
1474113596Snectar	const char	*p, *eol;
1475113596Snectar	char		*q;
1476113596Snectar	unsigned long	 n;
1477113596Snectar	int		 i, needed;
14782936Swollman
1479113596Snectar	if (linesize == 0 || is_comment_line(line, linesize))
1480113596Snectar		return (NS_NOTFOUND);
1481113596Snectar	switch (how) {
1482113596Snectar	case nss_lt_name:	needed = 1; break;
1483113596Snectar	case nss_lt_id:		needed = 2; break;
1484113596Snectar	default:		needed = 2; break;
14852936Swollman	}
1486113596Snectar	eol = &line[linesize];
1487113596Snectar	for (p = line, i = 0; i < needed && p < eol; p++)
1488113596Snectar		if (*p == ':')
1489113596Snectar			i++;
1490113596Snectar	if (i < needed)
1491113596Snectar		return (NS_NOTFOUND);
1492113596Snectar	switch (how) {
1493113596Snectar	case nss_lt_name:
1494113596Snectar		namesize = strlen(name);
1495113596Snectar		if (namesize + 1 == (size_t)(p - line) &&
1496113596Snectar		    memcmp(line, name, namesize) == 0)
1497113596Snectar			return (NS_SUCCESS);
1498113596Snectar		break;
1499113596Snectar	case nss_lt_id:
1500113596Snectar		n = strtoul(p, &q, 10);
1501113596Snectar		if (q < eol && *q == ':' && gid == (gid_t)n)
1502113596Snectar			return (NS_SUCCESS);
1503113596Snectar		break;
1504113596Snectar	case nss_lt_all:
1505113596Snectar		return (NS_SUCCESS);
1506113596Snectar	default:
1507113596Snectar		break;
1508113596Snectar	}
1509113596Snectar	return (NS_NOTFOUND);
1510113596Snectar}
15112936Swollman
15122936Swollman
1513113596Snectarint
1514113596Snectar__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
1515113596Snectar    size_t membufsize, int *errnop)
15162936Swollman{
1517113727Snectar	char	       *s_gid, *s_mem, *p, **members;
1518113596Snectar	unsigned long	n;
1519113596Snectar	int		maxmembers;
15202936Swollman
1521113596Snectar	memset(grp, 0, sizeof(*grp));
1522113596Snectar	members = (char **)_ALIGN(membuf);
1523113596Snectar	membufsize -= (char *)members - membuf;
1524113596Snectar	maxmembers = membufsize / sizeof(*members);
1525113596Snectar	if (maxmembers <= 0 ||
1526113596Snectar	    (grp->gr_name = strsep(&line, ":")) == NULL ||
1527113596Snectar	    grp->gr_name[0] == '\0' ||
1528113596Snectar	    (grp->gr_passwd = strsep(&line, ":")) == NULL ||
1529113596Snectar	    (s_gid = strsep(&line, ":")) == NULL ||
1530113596Snectar	    s_gid[0] == '\0')
1531113596Snectar		return (NS_NOTFOUND);
1532113596Snectar	s_mem = line;
1533113596Snectar	n = strtoul(s_gid, &s_gid, 10);
1534113596Snectar	if (s_gid[0] != '\0')
1535113596Snectar		return (NS_NOTFOUND);
1536113596Snectar	grp->gr_gid = (gid_t)n;
1537113596Snectar	grp->gr_mem = members;
1538113596Snectar	while (maxmembers > 1 && s_mem != NULL) {
1539113727Snectar		p = strsep(&s_mem, ",");
1540113727Snectar		if (p != NULL && *p != '\0') {
1541113727Snectar			*members++ = p;
1542113727Snectar			maxmembers--;
1543113727Snectar		}
1544113596Snectar	}
1545113596Snectar	*members = NULL;
1546113596Snectar	if (s_mem == NULL)
1547113596Snectar		return (NS_SUCCESS);
1548113596Snectar	else {
1549113596Snectar		*errnop = ERANGE;
1550113596Snectar		return (NS_RETURN);
1551113596Snectar	}
15522936Swollman}
1553174547Sbushman
1554174547Sbushman
1555