Home | History | Annotate | Line # | Download | only in gen
getgrent.c revision 1.47
      1  1.47       agc /*	$NetBSD: getgrent.c,v 1.47 2003/08/07 16:42:49 agc Exp $	*/
      2  1.11       cgd 
      3   1.1       cgd /*
      4  1.11       cgd  * Copyright (c) 1989, 1993
      5  1.11       cgd  *	The Regents of the University of California.  All rights reserved.
      6  1.47       agc  *
      7  1.47       agc  * Redistribution and use in source and binary forms, with or without
      8  1.47       agc  * modification, are permitted provided that the following conditions
      9  1.47       agc  * are met:
     10  1.47       agc  * 1. Redistributions of source code must retain the above copyright
     11  1.47       agc  *    notice, this list of conditions and the following disclaimer.
     12  1.47       agc  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.47       agc  *    notice, this list of conditions and the following disclaimer in the
     14  1.47       agc  *    documentation and/or other materials provided with the distribution.
     15  1.47       agc  * 3. Neither the name of the University nor the names of its contributors
     16  1.47       agc  *    may be used to endorse or promote products derived from this software
     17  1.47       agc  *    without specific prior written permission.
     18  1.47       agc  *
     19  1.47       agc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  1.47       agc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  1.47       agc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  1.47       agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  1.47       agc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  1.47       agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  1.47       agc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  1.47       agc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  1.47       agc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  1.47       agc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  1.47       agc  * SUCH DAMAGE.
     30  1.47       agc  */
     31  1.47       agc 
     32  1.47       agc /*
     33  1.13      phil  * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
     34   1.1       cgd  *
     35   1.1       cgd  * Redistribution and use in source and binary forms, with or without
     36   1.1       cgd  * modification, are permitted provided that the following conditions
     37   1.1       cgd  * are met:
     38   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     39   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     40   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     41   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     42   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     43   1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     44   1.1       cgd  *    must display the following acknowledgement:
     45   1.1       cgd  *	This product includes software developed by the University of
     46   1.1       cgd  *	California, Berkeley and its contributors.
     47   1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     48   1.1       cgd  *    may be used to endorse or promote products derived from this software
     49   1.1       cgd  *    without specific prior written permission.
     50   1.1       cgd  *
     51   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61   1.1       cgd  * SUCH DAMAGE.
     62   1.1       cgd  */
     63   1.1       cgd 
     64  1.20  christos #include <sys/cdefs.h>
     65   1.1       cgd #if defined(LIBC_SCCS) && !defined(lint)
     66  1.11       cgd #if 0
     67  1.11       cgd static char sccsid[] = "@(#)getgrent.c	8.2 (Berkeley) 3/21/94";
     68  1.11       cgd #else
     69  1.47       agc __RCSID("$NetBSD: getgrent.c,v 1.47 2003/08/07 16:42:49 agc Exp $");
     70  1.11       cgd #endif
     71   1.1       cgd #endif /* LIBC_SCCS and not lint */
     72   1.1       cgd 
     73  1.21       jtc #include "namespace.h"
     74  1.33     lukem 
     75   1.1       cgd #include <sys/types.h>
     76  1.33     lukem 
     77  1.37     lukem #include <assert.h>
     78  1.33     lukem #include <errno.h>
     79  1.27     lukem #include <grp.h>
     80  1.18     lukem #include <limits.h>
     81  1.27     lukem #include <nsswitch.h>
     82   1.1       cgd #include <stdio.h>
     83   1.1       cgd #include <stdlib.h>
     84   1.2   deraadt #include <string.h>
     85  1.27     lukem #include <syslog.h>
     86  1.35     lukem 
     87  1.35     lukem #include <stdarg.h>
     88  1.33     lukem 
     89  1.27     lukem #ifdef HESIOD
     90  1.27     lukem #include <hesiod.h>
     91  1.27     lukem #endif
     92   1.2   deraadt #ifdef YP
     93   1.2   deraadt #include <rpc/rpc.h>
     94   1.2   deraadt #include <rpcsvc/yp_prot.h>
     95   1.2   deraadt #include <rpcsvc/ypclnt.h>
     96  1.21       jtc #endif
     97  1.21       jtc 
     98  1.34     lukem #if defined(YP) || defined(HESIOD)
     99  1.34     lukem #define _GROUP_COMPAT
    100  1.34     lukem #endif
    101  1.34     lukem 
    102  1.45     elric struct group *_getgrent_user(const char *);
    103  1.45     elric 
    104  1.21       jtc #ifdef __weak_alias
    105  1.39   mycroft __weak_alias(endgrent,_endgrent)
    106  1.39   mycroft __weak_alias(getgrent,_getgrent)
    107  1.39   mycroft __weak_alias(getgrgid,_getgrgid)
    108  1.39   mycroft __weak_alias(getgrnam,_getgrnam)
    109  1.39   mycroft __weak_alias(setgrent,_setgrent)
    110  1.39   mycroft __weak_alias(setgroupent,_setgroupent)
    111   1.2   deraadt #endif
    112   1.1       cgd 
    113  1.27     lukem static FILE		*_gr_fp;
    114  1.27     lukem static struct group	_gr_group;
    115  1.27     lukem static int		_gr_stayopen;
    116  1.36     lukem static int		_gr_filesdone;
    117  1.27     lukem 
    118  1.41     lukem static void grcleanup(void);
    119  1.45     elric static int grscan(int, gid_t, const char *, const char *);
    120  1.42     lukem static int grstart(void);
    121  1.45     elric static int grmatchline(int, gid_t, const char *, const char *);
    122   1.1       cgd 
    123   1.1       cgd #define	MAXGRP		200
    124   1.1       cgd #define	MAXLINELENGTH	1024
    125  1.27     lukem 
    126  1.27     lukem static __aconst char	*members[MAXGRP];
    127  1.27     lukem static char		line[MAXLINELENGTH];
    128   1.1       cgd 
    129   1.2   deraadt #ifdef YP
    130  1.34     lukem static char	*__ypcurrent, *__ypdomain;
    131  1.34     lukem static int	 __ypcurrentlen;
    132  1.36     lukem static int	 _gr_ypdone;
    133  1.27     lukem #endif
    134  1.27     lukem 
    135  1.27     lukem #ifdef HESIOD
    136  1.45     elric static int		 _gr_hesnum;
    137  1.45     elric static struct group	*_gr_hesgrplist = NULL;
    138  1.45     elric static int		 _gr_hesgrplistnum;
    139  1.45     elric static int		 _gr_hesgrplistmax;
    140   1.2   deraadt #endif
    141   1.2   deraadt 
    142  1.34     lukem #ifdef _GROUP_COMPAT
    143  1.34     lukem enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME };
    144  1.34     lukem static enum _grmode	 __grmode;
    145  1.34     lukem #endif
    146  1.34     lukem 
    147   1.1       cgd struct group *
    148  1.41     lukem getgrent(void)
    149   1.1       cgd {
    150  1.41     lukem 
    151  1.45     elric 	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
    152  1.45     elric  		return (NULL);
    153  1.45     elric 	return &_gr_group;
    154  1.45     elric }
    155  1.45     elric 
    156  1.45     elric /*
    157  1.46    simonb  * _getgrent_user() is designed only to be called by getgrouplist(3) and
    158  1.45     elric  * hence makes no guarantees about filling the entire structure that it
    159  1.45     elric  * returns.  It may only fill in the group name and gid fields.
    160  1.45     elric  */
    161  1.45     elric 
    162  1.45     elric struct group *
    163  1.45     elric _getgrent_user(const char *user)
    164  1.45     elric {
    165  1.45     elric 
    166  1.45     elric 	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, user))
    167  1.36     lukem  		return (NULL);
    168  1.27     lukem 	return &_gr_group;
    169   1.1       cgd }
    170   1.1       cgd 
    171   1.1       cgd struct group *
    172  1.41     lukem getgrnam(const char *name)
    173   1.1       cgd {
    174   1.1       cgd 	int rval;
    175   1.1       cgd 
    176  1.37     lukem 	_DIAGASSERT(name != NULL);
    177  1.37     lukem 
    178  1.42     lukem 	if (!grstart())
    179  1.27     lukem 		return NULL;
    180  1.45     elric 	rval = grscan(1, 0, name, NULL);
    181   1.1       cgd 	if (!_gr_stayopen)
    182   1.1       cgd 		endgrent();
    183  1.27     lukem 	return (rval) ? &_gr_group : NULL;
    184   1.1       cgd }
    185   1.1       cgd 
    186   1.1       cgd struct group *
    187  1.41     lukem getgrgid(gid_t gid)
    188   1.1       cgd {
    189   1.1       cgd 	int rval;
    190   1.1       cgd 
    191  1.42     lukem 	if (!grstart())
    192  1.27     lukem 		return NULL;
    193  1.45     elric 	rval = grscan(1, gid, NULL, NULL);
    194   1.1       cgd 	if (!_gr_stayopen)
    195   1.1       cgd 		endgrent();
    196  1.27     lukem 	return (rval) ? &_gr_group : NULL;
    197   1.1       cgd }
    198   1.1       cgd 
    199  1.36     lukem void
    200  1.41     lukem grcleanup(void)
    201   1.1       cgd {
    202  1.41     lukem 
    203  1.36     lukem 	_gr_filesdone = 0;
    204  1.27     lukem #ifdef YP
    205  1.27     lukem 	if (__ypcurrent)
    206  1.27     lukem 		free(__ypcurrent);
    207  1.27     lukem 	__ypcurrent = NULL;
    208  1.36     lukem 	_gr_ypdone = 0;
    209  1.27     lukem #endif
    210  1.27     lukem #ifdef HESIOD
    211  1.36     lukem 	_gr_hesnum = 0;
    212  1.45     elric 	if (!_gr_hesgrplist)
    213  1.45     elric 		free(_gr_hesgrplist);
    214  1.45     elric 	_gr_hesgrplist = NULL;
    215  1.45     elric 	_gr_hesgrplistnum = -1;
    216  1.45     elric 	_gr_hesgrplistmax = 0;
    217  1.27     lukem #endif
    218  1.34     lukem #ifdef _GROUP_COMPAT
    219  1.34     lukem 	__grmode = GRMODE_NONE;
    220  1.34     lukem #endif
    221  1.36     lukem }
    222  1.36     lukem 
    223  1.36     lukem static int
    224  1.42     lukem grstart(void)
    225  1.36     lukem {
    226  1.41     lukem 
    227  1.36     lukem 	grcleanup();
    228   1.1       cgd 	if (_gr_fp) {
    229   1.1       cgd 		rewind(_gr_fp);
    230  1.27     lukem 		return 1;
    231   1.1       cgd 	}
    232  1.27     lukem 	return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
    233   1.1       cgd }
    234   1.1       cgd 
    235   1.5       jtc void
    236  1.41     lukem setgrent(void)
    237   1.1       cgd {
    238  1.41     lukem 
    239   1.5       jtc 	(void) setgroupent(0);
    240   1.1       cgd }
    241   1.1       cgd 
    242   1.1       cgd int
    243  1.41     lukem setgroupent(int stayopen)
    244   1.1       cgd {
    245  1.41     lukem 
    246  1.42     lukem 	if (!grstart())
    247  1.27     lukem 		return 0;
    248   1.1       cgd 	_gr_stayopen = stayopen;
    249  1.27     lukem 	return 1;
    250   1.1       cgd }
    251   1.1       cgd 
    252   1.1       cgd void
    253  1.41     lukem endgrent(void)
    254   1.1       cgd {
    255  1.41     lukem 
    256  1.36     lukem 	grcleanup();
    257   1.1       cgd 	if (_gr_fp) {
    258   1.1       cgd 		(void)fclose(_gr_fp);
    259   1.1       cgd 		_gr_fp = NULL;
    260   1.1       cgd 	}
    261   1.1       cgd }
    262   1.1       cgd 
    263  1.27     lukem 
    264  1.41     lukem static int _local_grscan(void *, void *, va_list);
    265  1.27     lukem 
    266  1.29  christos /*ARGSUSED*/
    267  1.27     lukem static int
    268  1.41     lukem _local_grscan(void *rv, void *cb_data, va_list ap)
    269  1.27     lukem {
    270  1.27     lukem 	int		 search = va_arg(ap, int);
    271  1.27     lukem 	gid_t		 gid = va_arg(ap, gid_t);
    272  1.27     lukem 	const char	*name = va_arg(ap, const char *);
    273  1.45     elric 	const char	*user = va_arg(ap, const char *);
    274  1.27     lukem 
    275  1.36     lukem 	if (_gr_filesdone)
    276  1.36     lukem 		return NS_NOTFOUND;
    277  1.27     lukem 	for (;;) {
    278  1.27     lukem 		if (!fgets(line, sizeof(line), _gr_fp)) {
    279  1.36     lukem 			if (!search)
    280  1.36     lukem 				_gr_filesdone = 1;
    281  1.27     lukem 			return NS_NOTFOUND;
    282  1.27     lukem 		}
    283  1.27     lukem 		/* skip lines that are too big */
    284  1.27     lukem 		if (!strchr(line, '\n')) {
    285  1.27     lukem 			int ch;
    286  1.27     lukem 
    287  1.27     lukem 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
    288  1.27     lukem 				;
    289  1.27     lukem 			continue;
    290  1.27     lukem 		}
    291  1.45     elric 		if (grmatchline(search, gid, name, user))
    292  1.27     lukem 			return NS_SUCCESS;
    293  1.27     lukem 	}
    294  1.27     lukem 	/* NOTREACHED */
    295  1.27     lukem }
    296  1.27     lukem 
    297  1.27     lukem #ifdef HESIOD
    298  1.41     lukem static int _dns_grscan(void *, void *, va_list);
    299  1.45     elric static int _dns_grplist(const char *);
    300  1.27     lukem 
    301  1.29  christos /*ARGSUSED*/
    302   1.2   deraadt static int
    303  1.41     lukem _dns_grscan(void *rv, void *cb_data, va_list ap)
    304   1.1       cgd {
    305  1.27     lukem 	int		 search = va_arg(ap, int);
    306  1.27     lukem 	gid_t		 gid = va_arg(ap, gid_t);
    307  1.27     lukem 	const char	*name = va_arg(ap, const char *);
    308  1.45     elric 	const char	*user = va_arg(ap, const char *);
    309  1.27     lukem 
    310  1.27     lukem 	char		**hp;
    311  1.33     lukem 	void		 *context;
    312  1.33     lukem 	int		  r;
    313  1.33     lukem 
    314  1.33     lukem 	r = NS_UNAVAIL;
    315  1.45     elric 	if (!search && user && _gr_hesgrplistmax != -1) {
    316  1.45     elric 		r = _dns_grplist(user);
    317  1.45     elric 		/* if we did not find user.grplist, just iterate */
    318  1.45     elric 		if (!_gr_hesgrplist) {
    319  1.45     elric 			_gr_hesgrplistmax = -1;
    320  1.45     elric 			if (r != NS_NOTFOUND)
    321  1.45     elric 				return r;
    322  1.45     elric 		} else
    323  1.45     elric 			return r;
    324  1.45     elric 	}
    325  1.36     lukem 	if (!search && _gr_hesnum == -1)
    326  1.36     lukem 		return NS_NOTFOUND;
    327  1.33     lukem 	if (hesiod_init(&context) == -1)
    328  1.33     lukem 		return (r);
    329   1.1       cgd 
    330   1.1       cgd 	for (;;) {
    331  1.27     lukem 		if (search) {
    332  1.27     lukem 			if (name)
    333  1.43    itojun 				strlcpy(line, name, sizeof(line));
    334  1.27     lukem 			else
    335  1.28     lukem 				snprintf(line, sizeof(line), "%u",
    336  1.28     lukem 				    (unsigned int)gid);
    337  1.27     lukem 		} else {
    338  1.36     lukem 			snprintf(line, sizeof(line), "group-%u", _gr_hesnum);
    339  1.36     lukem 			_gr_hesnum++;
    340  1.27     lukem 		}
    341   1.2   deraadt 
    342  1.44     elric 		hp = NULL;
    343  1.44     elric 		if (search && !name) {
    344  1.44     elric 			hp = hesiod_resolve(context, line, "gid");
    345  1.44     elric 			if (hp == NULL && errno != ENOENT)
    346  1.44     elric 				break;
    347  1.44     elric 		}
    348  1.44     elric 		if (hp == NULL)
    349  1.44     elric 			hp = hesiod_resolve(context, line, "group");
    350  1.27     lukem 		if (hp == NULL) {
    351  1.33     lukem 			if (errno == ENOENT) {
    352  1.36     lukem 				if (!search)
    353  1.36     lukem 					_gr_hesnum = -1;
    354  1.36     lukem 				r = NS_NOTFOUND;
    355   1.2   deraadt 			}
    356  1.33     lukem 			break;
    357  1.27     lukem 		}
    358  1.27     lukem 
    359  1.27     lukem 						/* only check first elem */
    360  1.43    itojun 		strlcpy(line, hp[0], sizeof(line));
    361  1.33     lukem 		hesiod_free_list(context, hp);
    362  1.45     elric 		if (grmatchline(search, gid, name, user)) {
    363  1.33     lukem 			r = NS_SUCCESS;
    364  1.33     lukem 			break;
    365  1.33     lukem 		} else if (search) {
    366  1.33     lukem 			r = NS_NOTFOUND;
    367  1.33     lukem 			break;
    368  1.33     lukem 		}
    369  1.27     lukem 	}
    370  1.33     lukem 	hesiod_end(context);
    371  1.33     lukem 	return (r);
    372  1.27     lukem }
    373  1.45     elric 
    374  1.45     elric static int
    375  1.45     elric _dns_grplist(const char *user)
    376  1.45     elric {
    377  1.45     elric 	void	 *context;
    378  1.45     elric 	int	  r;
    379  1.45     elric 	char	**hp;
    380  1.45     elric 	char	 *cp;
    381  1.45     elric 
    382  1.45     elric 	r = NS_UNAVAIL;
    383  1.45     elric 	if (!_gr_hesgrplist) {
    384  1.45     elric 		if (hesiod_init(&context) == -1)
    385  1.45     elric 			return r;
    386  1.45     elric 
    387  1.45     elric 		_gr_hesgrplistnum = -1;
    388  1.45     elric 		hp = hesiod_resolve(context, user, "grplist");
    389  1.45     elric 		if (!hp) {
    390  1.45     elric 			if (errno == ENOENT)
    391  1.45     elric 				r = NS_NOTFOUND;
    392  1.45     elric 			hesiod_end(context);
    393  1.45     elric 			return r;
    394  1.45     elric 		}
    395  1.45     elric 
    396  1.45     elric 		strlcpy(line, hp[0], sizeof(line));
    397  1.45     elric 		hesiod_free_list(context, hp);
    398  1.45     elric 
    399  1.45     elric 		_gr_hesgrplistmax = 0;
    400  1.45     elric 		for (cp=line; *cp; cp++)
    401  1.45     elric 			if (*cp == ':')
    402  1.45     elric 				_gr_hesgrplistmax++;
    403  1.45     elric 		_gr_hesgrplistmax /= 2;
    404  1.45     elric 		_gr_hesgrplistmax++;
    405  1.45     elric 
    406  1.45     elric 		_gr_hesgrplist = malloc(_gr_hesgrplistmax *
    407  1.45     elric 		    sizeof(*_gr_hesgrplist));
    408  1.45     elric 		if (!_gr_hesgrplist) {
    409  1.45     elric 			hesiod_end(context);
    410  1.45     elric 			return NS_UNAVAIL;
    411  1.45     elric 		}
    412  1.45     elric 
    413  1.45     elric 		cp = line;
    414  1.45     elric 		_gr_hesgrplistmax = 0;
    415  1.45     elric 		for (;;) {
    416  1.45     elric 			char	*name;
    417  1.45     elric 			char	*num;
    418  1.45     elric 			gid_t	 gid;
    419  1.45     elric 			char	*ep;
    420  1.45     elric 
    421  1.45     elric 			/* XXXrcd: error handling */
    422  1.45     elric 			if (!(name = strsep(&cp, ":")))
    423  1.45     elric 				break;
    424  1.45     elric 			if (!(num = strsep(&cp, ":")))
    425  1.45     elric 				break;
    426  1.45     elric 			gid = (gid_t) strtoul(num, &ep, 10);
    427  1.45     elric 			if (gid > GID_MAX || *ep != '\0')
    428  1.45     elric 				break;
    429  1.45     elric 
    430  1.45     elric 			_gr_hesgrplist[_gr_hesgrplistmax].gr_name = name;
    431  1.45     elric 			_gr_hesgrplist[_gr_hesgrplistmax].gr_gid  = gid;
    432  1.45     elric 			_gr_hesgrplistmax++;
    433  1.45     elric 		}
    434  1.45     elric 
    435  1.45     elric 		hesiod_end(context);
    436  1.45     elric 	}
    437  1.45     elric 
    438  1.45     elric 	/* we assume that _gr_hesgrplist is now defined */
    439  1.45     elric 	if (++_gr_hesgrplistnum >= _gr_hesgrplistmax)
    440  1.45     elric 		return NS_NOTFOUND;
    441  1.45     elric 
    442  1.45     elric 	/*
    443  1.45     elric 	 * Now we copy the relevant information into _gr_group, so that
    444  1.45     elric 	 * it can be returned.  Note that we only fill in the bare necessities
    445  1.45     elric 	 * as this will be used exclusively by getgrouplist(3) and we do
    446  1.45     elric 	 * not want to have to look up all of the information.
    447  1.45     elric 	 */
    448  1.45     elric 	_gr_group.gr_name   = _gr_hesgrplist[_gr_hesgrplistnum].gr_name;
    449  1.45     elric 	_gr_group.gr_passwd = NULL;
    450  1.45     elric 	_gr_group.gr_gid    = _gr_hesgrplist[_gr_hesgrplistnum].gr_gid;
    451  1.45     elric 	_gr_group.gr_mem    = NULL;
    452  1.45     elric 
    453  1.45     elric 	return NS_SUCCESS;
    454  1.45     elric }
    455  1.41     lukem #endif	/* HESIOD */
    456  1.27     lukem 
    457  1.27     lukem #ifdef YP
    458  1.41     lukem static int _nis_grscan(void *, void *, va_list);
    459  1.27     lukem 
    460  1.29  christos /*ARGSUSED*/
    461  1.27     lukem static int
    462  1.41     lukem _nis_grscan(void *rv, void *cb_data, va_list ap)
    463  1.27     lukem {
    464  1.27     lukem 	int		 search = va_arg(ap, int);
    465  1.27     lukem 	gid_t		 gid = va_arg(ap, gid_t);
    466  1.27     lukem 	const char	*name = va_arg(ap, const char *);
    467  1.45     elric 	const char	*user = va_arg(ap, const char *);
    468  1.27     lukem 
    469  1.27     lukem 	char	*key, *data;
    470  1.27     lukem 	int	 keylen, datalen;
    471  1.27     lukem 	int	 r;
    472  1.27     lukem 
    473  1.27     lukem 	if(__ypdomain == NULL) {
    474  1.27     lukem 		switch (yp_get_default_domain(&__ypdomain)) {
    475  1.27     lukem 		case 0:
    476  1.27     lukem 			break;
    477  1.27     lukem 		case YPERR_RESRC:
    478  1.27     lukem 			return NS_TRYAGAIN;
    479  1.27     lukem 		default:
    480  1.27     lukem 			return NS_UNAVAIL;
    481  1.27     lukem 		}
    482  1.27     lukem 	}
    483  1.27     lukem 
    484  1.27     lukem 	if (search) {			/* specific group or gid */
    485  1.27     lukem 		if (name)
    486  1.43    itojun 			strlcpy(line, name, sizeof(line));
    487  1.27     lukem 		else
    488  1.28     lukem 			snprintf(line, sizeof(line), "%u", (unsigned int)gid);
    489  1.27     lukem 		data = NULL;
    490  1.27     lukem 		r = yp_match(__ypdomain,
    491  1.27     lukem 				(name) ? "group.byname" : "group.bygid",
    492  1.27     lukem 				line, (int)strlen(line), &data, &datalen);
    493  1.27     lukem 		switch (r) {
    494  1.27     lukem 		case 0:
    495  1.27     lukem 			break;
    496  1.27     lukem 		case YPERR_KEY:
    497  1.27     lukem 			if (data)
    498  1.27     lukem 				free(data);
    499  1.27     lukem 			return NS_NOTFOUND;
    500  1.27     lukem 		default:
    501  1.27     lukem 			if (data)
    502  1.16     lukem 				free(data);
    503  1.27     lukem 			return NS_UNAVAIL;
    504  1.27     lukem 		}
    505  1.27     lukem 		data[datalen] = '\0';			/* clear trailing \n */
    506  1.43    itojun 		strlcpy(line, data, sizeof(line));
    507  1.27     lukem 		free(data);
    508  1.45     elric 		if (grmatchline(search, gid, name, user))
    509  1.27     lukem 			return NS_SUCCESS;
    510  1.27     lukem 		else
    511  1.27     lukem 			return NS_NOTFOUND;
    512  1.27     lukem 	}
    513  1.27     lukem 
    514  1.36     lukem 						/* ! search */
    515  1.36     lukem 	if (_gr_ypdone)
    516  1.36     lukem 		return NS_NOTFOUND;
    517  1.36     lukem 	for (;;) {
    518  1.27     lukem 		data = NULL;
    519  1.27     lukem 		if(__ypcurrent) {
    520  1.27     lukem 			key = NULL;
    521  1.27     lukem 			r = yp_next(__ypdomain, "group.byname",
    522  1.27     lukem 				__ypcurrent, __ypcurrentlen,
    523  1.27     lukem 				&key, &keylen, &data, &datalen);
    524  1.27     lukem 			free(__ypcurrent);
    525  1.27     lukem 			switch (r) {
    526  1.27     lukem 			case 0:
    527  1.13      phil 				break;
    528  1.27     lukem 			case YPERR_NOMORE:
    529  1.27     lukem 				__ypcurrent = NULL;
    530  1.27     lukem 				if (key)
    531  1.27     lukem 					free(key);
    532  1.27     lukem 				if (data)
    533   1.2   deraadt 					free(data);
    534  1.36     lukem 				_gr_ypdone = 1;
    535  1.36     lukem 				return NS_NOTFOUND;
    536  1.27     lukem 			default:
    537  1.27     lukem 				if (key)
    538  1.27     lukem 					free(key);
    539  1.27     lukem 				if (data)
    540  1.27     lukem 					free(data);
    541  1.27     lukem 				return NS_UNAVAIL;
    542  1.27     lukem 			}
    543  1.27     lukem 			__ypcurrent = key;
    544  1.27     lukem 			__ypcurrentlen = keylen;
    545  1.27     lukem 		} else {
    546  1.27     lukem 			if (yp_first(__ypdomain, "group.byname",
    547  1.27     lukem 					&__ypcurrent, &__ypcurrentlen,
    548  1.27     lukem 					&data, &datalen)) {
    549  1.40     lukem 				if (data)
    550  1.27     lukem 					free(data);
    551  1.27     lukem 				return NS_UNAVAIL;
    552  1.27     lukem 			}
    553  1.27     lukem 		}
    554  1.27     lukem 		data[datalen] = '\0';			/* clear trailing \n */
    555  1.43    itojun 		strlcpy(line, data, sizeof(line));
    556  1.27     lukem 		free(data);
    557  1.45     elric 		if (grmatchline(search, gid, name, user))
    558  1.27     lukem 			return NS_SUCCESS;
    559  1.27     lukem 	}
    560  1.27     lukem 	/* NOTREACHED */
    561  1.27     lukem }
    562  1.41     lukem #endif	/* YP */
    563  1.27     lukem 
    564  1.34     lukem #ifdef _GROUP_COMPAT
    565  1.27     lukem /*
    566  1.27     lukem  * log an error if "files" or "compat" is specified in group_compat database
    567  1.27     lukem  */
    568  1.41     lukem static int _bad_grscan(void *, void *, va_list);
    569  1.27     lukem 
    570  1.29  christos /*ARGSUSED*/
    571  1.27     lukem static int
    572  1.41     lukem _bad_grscan(void *rv, void *cb_data, va_list ap)
    573  1.27     lukem {
    574  1.27     lukem 	static int warned;
    575  1.27     lukem 
    576  1.37     lukem 	_DIAGASSERT(cb_data != NULL);
    577  1.37     lukem 
    578  1.27     lukem 	if (!warned) {
    579  1.27     lukem 		syslog(LOG_ERR,
    580  1.27     lukem 			"nsswitch.conf group_compat database can't use '%s'",
    581  1.27     lukem 			(char *)cb_data);
    582  1.27     lukem 	}
    583  1.27     lukem 	warned = 1;
    584  1.27     lukem 	return NS_UNAVAIL;
    585  1.27     lukem }
    586  1.27     lukem 
    587  1.27     lukem /*
    588  1.27     lukem  * when a name lookup in compat mode is required, look it up in group_compat
    589  1.27     lukem  * nsswitch database. only Hesiod and NIS is supported - it doesn't make
    590  1.27     lukem  * sense to lookup compat names from 'files' or 'compat'
    591  1.27     lukem  */
    592  1.27     lukem 
    593  1.45     elric static int __grscancompat(int, gid_t, const char *, const char *);
    594  1.27     lukem 
    595  1.27     lukem static int
    596  1.45     elric __grscancompat(int search, gid_t gid, const char *name, const char *user)
    597  1.27     lukem {
    598  1.31     lukem 	static const ns_dtab dtab[] = {
    599  1.30     lukem 		NS_FILES_CB(_bad_grscan, "files")
    600  1.30     lukem 		NS_DNS_CB(_dns_grscan, NULL)
    601  1.30     lukem 		NS_NIS_CB(_nis_grscan, NULL)
    602  1.30     lukem 		NS_COMPAT_CB(_bad_grscan, "compat")
    603  1.27     lukem 		{ 0 }
    604  1.27     lukem 	};
    605  1.32     lukem 	static const ns_src defaultnis[] = {
    606  1.32     lukem 		{ NSSRC_NIS, 	NS_SUCCESS },
    607  1.32     lukem 		{ 0 }
    608  1.32     lukem 	};
    609  1.27     lukem 
    610  1.37     lukem 	_DIAGASSERT(name != NULL);
    611  1.37     lukem 
    612  1.30     lukem 	return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat",
    613  1.45     elric 	    defaultnis, search, gid, name, user));
    614  1.27     lukem }
    615  1.41     lukem #endif	/* GROUP_COMPAT */
    616  1.27     lukem 
    617  1.27     lukem 
    618  1.41     lukem static int _compat_grscan(void *, void *, va_list);
    619  1.27     lukem 
    620  1.29  christos /*ARGSUSED*/
    621  1.27     lukem static int
    622  1.41     lukem _compat_grscan(void *rv, void *cb_data, va_list ap)
    623  1.27     lukem {
    624  1.27     lukem 	int		 search = va_arg(ap, int);
    625  1.27     lukem 	gid_t		 gid = va_arg(ap, gid_t);
    626  1.27     lukem 	const char	*name = va_arg(ap, const char *);
    627  1.45     elric 	const char	*user = va_arg(ap, const char *);
    628  1.27     lukem 
    629  1.34     lukem #ifdef _GROUP_COMPAT
    630  1.27     lukem 	static char	*grname = NULL;
    631  1.34     lukem #endif
    632  1.27     lukem 
    633  1.27     lukem 	for (;;) {
    634  1.34     lukem #ifdef _GROUP_COMPAT
    635  1.27     lukem 		if(__grmode != GRMODE_NONE) {
    636  1.27     lukem 			int	 r;
    637  1.27     lukem 
    638  1.27     lukem 			switch(__grmode) {
    639  1.27     lukem 			case GRMODE_FULL:
    640  1.45     elric 				r = __grscancompat(search, gid, name, user);
    641  1.27     lukem 				if (r == NS_SUCCESS)
    642  1.27     lukem 					return r;
    643  1.27     lukem 				__grmode = GRMODE_NONE;
    644  1.27     lukem 				break;
    645  1.27     lukem 			case GRMODE_NAME:
    646  1.27     lukem 				if(grname == (char *)NULL) {
    647  1.27     lukem 					__grmode = GRMODE_NONE;
    648  1.27     lukem 					break;
    649  1.27     lukem 				}
    650  1.45     elric 				r = __grscancompat(1, 0, grname, user);
    651  1.27     lukem 				free(grname);
    652  1.27     lukem 				grname = (char *)NULL;
    653  1.27     lukem 				if (r != NS_SUCCESS)
    654  1.27     lukem 					break;
    655  1.27     lukem 				if (!search)
    656  1.27     lukem 					return NS_SUCCESS;
    657  1.27     lukem 				if (name) {
    658  1.27     lukem 					if (! strcmp(_gr_group.gr_name, name))
    659  1.27     lukem 						return NS_SUCCESS;
    660  1.13      phil 				} else {
    661  1.27     lukem 					if (_gr_group.gr_gid == gid)
    662  1.27     lukem 						return NS_SUCCESS;
    663   1.2   deraadt 				}
    664  1.20  christos 				break;
    665  1.27     lukem 			case GRMODE_NONE:
    666  1.27     lukem 				abort();
    667   1.2   deraadt 			}
    668  1.27     lukem 			continue;
    669   1.2   deraadt 		}
    670  1.41     lukem #endif	/* _GROUP_COMPAT */
    671  1.27     lukem 
    672   1.1       cgd 		if (!fgets(line, sizeof(line), _gr_fp))
    673  1.27     lukem 			return NS_NOTFOUND;
    674   1.1       cgd 		/* skip lines that are too big */
    675   1.6       jtc 		if (!strchr(line, '\n')) {
    676   1.1       cgd 			int ch;
    677   1.1       cgd 
    678   1.1       cgd 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
    679   1.1       cgd 				;
    680   1.1       cgd 			continue;
    681   1.1       cgd 		}
    682  1.27     lukem 
    683  1.34     lukem #ifdef _GROUP_COMPAT
    684  1.13      phil 		if (line[0] == '+') {
    685  1.27     lukem 			char	*tptr, *bp;
    686  1.27     lukem 
    687  1.13      phil 			switch(line[1]) {
    688  1.13      phil 			case ':':
    689  1.13      phil 			case '\0':
    690  1.13      phil 			case '\n':
    691  1.27     lukem 				__grmode = GRMODE_FULL;
    692  1.13      phil 				break;
    693  1.13      phil 			default:
    694  1.27     lukem 				__grmode = GRMODE_NAME;
    695  1.27     lukem 				bp = line;
    696  1.27     lukem 				tptr = strsep(&bp, ":\n");
    697  1.27     lukem 				grname = strdup(tptr + 1);
    698  1.13      phil 				break;
    699   1.2   deraadt 			}
    700   1.9   deraadt 			continue;
    701   1.1       cgd 		}
    702  1.41     lukem #endif	/* _GROUP_COMPAT */
    703  1.45     elric 		if (grmatchline(search, gid, name, user))
    704  1.27     lukem 			return NS_SUCCESS;
    705   1.1       cgd 	}
    706   1.1       cgd 	/* NOTREACHED */
    707  1.27     lukem }
    708  1.27     lukem 
    709  1.27     lukem static int
    710  1.45     elric grscan(int search, gid_t gid, const char *name, const char *user)
    711  1.27     lukem {
    712  1.27     lukem 	int		r;
    713  1.31     lukem 	static const ns_dtab dtab[] = {
    714  1.30     lukem 		NS_FILES_CB(_local_grscan, NULL)
    715  1.30     lukem 		NS_DNS_CB(_dns_grscan, NULL)
    716  1.30     lukem 		NS_NIS_CB(_nis_grscan, NULL)
    717  1.30     lukem 		NS_COMPAT_CB(_compat_grscan, NULL)
    718  1.27     lukem 		{ 0 }
    719  1.27     lukem 	};
    720  1.32     lukem 	static const ns_src compatsrc[] = {
    721  1.32     lukem 		{ NSSRC_COMPAT, NS_SUCCESS },
    722  1.32     lukem 		{ 0 }
    723  1.32     lukem 	};
    724  1.27     lukem 
    725  1.37     lukem 	/* name may be NULL if search is nonzero */
    726  1.37     lukem 
    727  1.32     lukem 	r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc,
    728  1.45     elric 	    search, gid, name, user);
    729  1.27     lukem 	return (r == NS_SUCCESS) ? 1 : 0;
    730  1.27     lukem }
    731  1.27     lukem 
    732  1.27     lukem static int
    733  1.45     elric grmatchline(int search, gid_t gid, const char *name, const char *user)
    734  1.27     lukem {
    735  1.27     lukem 	unsigned long	id;
    736  1.27     lukem 	__aconst char	**m;
    737  1.27     lukem 	char		*cp, *bp, *ep;
    738  1.37     lukem 
    739  1.37     lukem 	/* name may be NULL if search is nonzero */
    740  1.27     lukem 
    741  1.27     lukem 	if (line[0] == '+')
    742  1.27     lukem 		return 0;	/* sanity check to prevent recursion */
    743  1.27     lukem 	bp = line;
    744  1.27     lukem 	_gr_group.gr_name = strsep(&bp, ":\n");
    745  1.27     lukem 	if (search && name && strcmp(_gr_group.gr_name, name))
    746  1.27     lukem 		return 0;
    747  1.27     lukem 	_gr_group.gr_passwd = strsep(&bp, ":\n");
    748  1.27     lukem 	if (!(cp = strsep(&bp, ":\n")))
    749  1.27     lukem 		return 0;
    750  1.27     lukem 	id = strtoul(cp, &ep, 10);
    751  1.27     lukem 	if (id > GID_MAX || *ep != '\0')
    752  1.27     lukem 		return 0;
    753  1.27     lukem 	_gr_group.gr_gid = (gid_t)id;
    754  1.27     lukem 	if (search && name == NULL && _gr_group.gr_gid != gid)
    755  1.27     lukem 		return 0;
    756  1.27     lukem 	cp = NULL;
    757  1.27     lukem 	if (bp == NULL)
    758  1.27     lukem 		return 0;
    759  1.27     lukem 	for (_gr_group.gr_mem = m = members;; bp++) {
    760  1.27     lukem 		if (m == &members[MAXGRP - 1])
    761  1.27     lukem 			break;
    762  1.27     lukem 		if (*bp == ',') {
    763  1.27     lukem 			if (cp) {
    764  1.27     lukem 				*bp = '\0';
    765  1.27     lukem 				*m++ = cp;
    766  1.27     lukem 				cp = NULL;
    767  1.27     lukem 			}
    768  1.27     lukem 		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
    769  1.27     lukem 			if (cp) {
    770  1.27     lukem 				*bp = '\0';
    771  1.27     lukem 				*m++ = cp;
    772  1.27     lukem 			}
    773  1.27     lukem 			break;
    774  1.27     lukem 		} else if (cp == NULL)
    775  1.27     lukem 			cp = bp;
    776  1.27     lukem 	}
    777  1.27     lukem 	*m = NULL;
    778  1.45     elric 	if (user) {
    779  1.45     elric 		for (m = members; *m; m++)
    780  1.45     elric 			if (!strcmp(user, *m))
    781  1.45     elric 				return 1;
    782  1.45     elric 		return 0;
    783  1.45     elric 	}
    784  1.27     lukem 	return 1;
    785   1.1       cgd }
    786