xref: /illumos-gate/usr/src/lib/libproject/common/getprojent.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
28*7c478bd9Sstevel@tonic-gate #include <user_attr.h>
29*7c478bd9Sstevel@tonic-gate #include <pwd.h>
30*7c478bd9Sstevel@tonic-gate #include <grp.h>
31*7c478bd9Sstevel@tonic-gate #include <userdefs.h>
32*7c478bd9Sstevel@tonic-gate #include <project.h>
33*7c478bd9Sstevel@tonic-gate #include <memory.h>
34*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
35*7c478bd9Sstevel@tonic-gate #include <stdio.h>
36*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
37*7c478bd9Sstevel@tonic-gate #include <string.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #pragma weak setprojent = _setprojent
42*7c478bd9Sstevel@tonic-gate #pragma weak endprojent = _endprojent
43*7c478bd9Sstevel@tonic-gate #pragma weak getprojent = _getprojent
44*7c478bd9Sstevel@tonic-gate #pragma weak fgetprojent = _fgetprojent
45*7c478bd9Sstevel@tonic-gate #pragma weak getprojbyid = _getprojbyid
46*7c478bd9Sstevel@tonic-gate #pragma weak getprojbyname = _getprojbyname
47*7c478bd9Sstevel@tonic-gate #pragma weak getdefaultproj = _getdefaultproj
48*7c478bd9Sstevel@tonic-gate #pragma weak inproj = _inproj
49*7c478bd9Sstevel@tonic-gate #pragma weak getprojidbyname = _getprojidbyname
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #define	DEFAULT_PROJECT	1
52*7c478bd9Sstevel@tonic-gate #define	NORMAL_PROJECT	0
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static int ismember(struct project *, const char *, gid_t, int);
55*7c478bd9Sstevel@tonic-gate static int str2project(const char *, int, void *, char *, int);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
58*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context);
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate void
_nss_initf_project(nss_db_params_t * p)61*7c478bd9Sstevel@tonic-gate _nss_initf_project(nss_db_params_t *p)
62*7c478bd9Sstevel@tonic-gate {
63*7c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_PROJECT;
64*7c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_PROJECT;
65*7c478bd9Sstevel@tonic-gate }
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate void
_setprojent(void)68*7c478bd9Sstevel@tonic-gate _setprojent(void)
69*7c478bd9Sstevel@tonic-gate {
70*7c478bd9Sstevel@tonic-gate 	nss_setent(&db_root, _nss_initf_project, &context);
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate void
_endprojent(void)74*7c478bd9Sstevel@tonic-gate _endprojent(void)
75*7c478bd9Sstevel@tonic-gate {
76*7c478bd9Sstevel@tonic-gate 	nss_endent(&db_root, _nss_initf_project, &context);
77*7c478bd9Sstevel@tonic-gate 	nss_delete(&db_root);
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate struct project *
_getprojent(struct project * result,void * buffer,size_t buflen)81*7c478bd9Sstevel@tonic-gate _getprojent(struct project *result, void *buffer, size_t buflen)
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project);
86*7c478bd9Sstevel@tonic-gate 	(void) nss_getent(&db_root, _nss_initf_project, &context, &arg);
87*7c478bd9Sstevel@tonic-gate 	return ((struct project *)NSS_XbyY_FINI(&arg));
88*7c478bd9Sstevel@tonic-gate }
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate struct project *
_fgetprojent(FILE * f,struct project * result,void * buffer,size_t buflen)91*7c478bd9Sstevel@tonic-gate _fgetprojent(FILE *f, struct project *result, void *buffer, size_t buflen)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
94*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project);
97*7c478bd9Sstevel@tonic-gate 	_nss_XbyY_fgets(f, &arg);
98*7c478bd9Sstevel@tonic-gate 	return ((struct project *)NSS_XbyY_FINI(&arg));
99*7c478bd9Sstevel@tonic-gate }
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate struct project *
_getprojbyid(projid_t projid,struct project * result,void * buffer,size_t buflen)102*7c478bd9Sstevel@tonic-gate _getprojbyid(projid_t projid, struct project *result,
103*7c478bd9Sstevel@tonic-gate     void *buffer, size_t buflen)
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project);
108*7c478bd9Sstevel@tonic-gate 	arg.key.projid = projid;
109*7c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_project,
110*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_PROJECT_BYID, &arg);
111*7c478bd9Sstevel@tonic-gate 	return ((struct project *)NSS_XbyY_FINI(&arg));
112*7c478bd9Sstevel@tonic-gate }
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate struct project *
_getprojbyname(const char * name,struct project * result,void * buffer,size_t buflen)115*7c478bd9Sstevel@tonic-gate _getprojbyname(const char *name, struct project *result,
116*7c478bd9Sstevel@tonic-gate     void *buffer, size_t buflen)
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
119*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project);
120*7c478bd9Sstevel@tonic-gate 	arg.key.name = name;
121*7c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_project,
122*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_PROJECT_BYNAME, &arg);
123*7c478bd9Sstevel@tonic-gate 	return ((struct project *)NSS_XbyY_FINI(&arg));
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate  * The following routine checks if user specified by the second argument
128*7c478bd9Sstevel@tonic-gate  * is allowed to join the project specified as project structure in first
129*7c478bd9Sstevel@tonic-gate  * argument.  Information about user's default group and whether or not
130*7c478bd9Sstevel@tonic-gate  * the project specified in the first argument is user's default project
131*7c478bd9Sstevel@tonic-gate  * (i.e., user_attr, "default", "user.username", or "group.groupname"
132*7c478bd9Sstevel@tonic-gate  * should also be provided.  If is_default is set to DEFAULT_PROJECT,
133*7c478bd9Sstevel@tonic-gate  * then this function returns 1 (true), unless specified user explicitly
134*7c478bd9Sstevel@tonic-gate  * excluded with "!user", or "!group" wildcards.
135*7c478bd9Sstevel@tonic-gate  */
136*7c478bd9Sstevel@tonic-gate static int
ismember(struct project * proj,const char * user,gid_t gid,int is_default)137*7c478bd9Sstevel@tonic-gate ismember(struct project *proj, const char *user, gid_t gid, int is_default)
138*7c478bd9Sstevel@tonic-gate {
139*7c478bd9Sstevel@tonic-gate 	char grbuf[NSS_BUFLEN_GROUP];
140*7c478bd9Sstevel@tonic-gate 	char groupname[MAXGLEN + 1];
141*7c478bd9Sstevel@tonic-gate 	int res = is_default;
142*7c478bd9Sstevel@tonic-gate 	struct group grp;
143*7c478bd9Sstevel@tonic-gate 	int group_ok = 0;
144*7c478bd9Sstevel@tonic-gate 	char **u, **g;
145*7c478bd9Sstevel@tonic-gate 	char *member;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (getgrgid_r(gid, &grp, grbuf, NSS_BUFLEN_GROUP) != NULL) {
148*7c478bd9Sstevel@tonic-gate 		group_ok = 1;
149*7c478bd9Sstevel@tonic-gate 		(void) snprintf(groupname, MAXGLEN, grp.gr_name);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/*
153*7c478bd9Sstevel@tonic-gate 	 * Scan project's user list.
154*7c478bd9Sstevel@tonic-gate 	 */
155*7c478bd9Sstevel@tonic-gate 	for (u = proj->pj_users; *u; u++) {
156*7c478bd9Sstevel@tonic-gate 		member = *u;
157*7c478bd9Sstevel@tonic-gate 		if (member[0] == '!' &&
158*7c478bd9Sstevel@tonic-gate 		    (strcmp(member + 1, user) == 0 ||
159*7c478bd9Sstevel@tonic-gate 		    strcmp(member + 1, "*") == 0))
160*7c478bd9Sstevel@tonic-gate 			return (0);
161*7c478bd9Sstevel@tonic-gate 		if (strcmp(member, "*") == 0 || strcmp(member, user) == 0)
162*7c478bd9Sstevel@tonic-gate 			res = 1;
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 * Scan project's group list.
167*7c478bd9Sstevel@tonic-gate 	 */
168*7c478bd9Sstevel@tonic-gate 	for (g = proj->pj_groups; *g; g++) {
169*7c478bd9Sstevel@tonic-gate 		member = *g;
170*7c478bd9Sstevel@tonic-gate 		/*
171*7c478bd9Sstevel@tonic-gate 		 * Check if user's default group is included here.
172*7c478bd9Sstevel@tonic-gate 		 */
173*7c478bd9Sstevel@tonic-gate 		if (group_ok) {
174*7c478bd9Sstevel@tonic-gate 			if (member[0] == '!' &&
175*7c478bd9Sstevel@tonic-gate 			    (strcmp(member + 1, groupname) == 0 ||
176*7c478bd9Sstevel@tonic-gate 			    strcmp(member + 1, "*") == 0))
177*7c478bd9Sstevel@tonic-gate 				return (0);
178*7c478bd9Sstevel@tonic-gate 			if (strcmp(member, "*") == 0 ||
179*7c478bd9Sstevel@tonic-gate 			    strcmp(member, groupname) == 0)
180*7c478bd9Sstevel@tonic-gate 				res = 1;
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 		/*
183*7c478bd9Sstevel@tonic-gate 		 * Check if user is a member of one of project's groups.
184*7c478bd9Sstevel@tonic-gate 		 */
185*7c478bd9Sstevel@tonic-gate 		if (getgrnam_r(member, &grp, grbuf, NSS_BUFLEN_GROUP) != NULL) {
186*7c478bd9Sstevel@tonic-gate 			for (u = grp.gr_mem; *u; u++)
187*7c478bd9Sstevel@tonic-gate 				if (strcmp(*u, user) == 0)
188*7c478bd9Sstevel@tonic-gate 					res = 1;
189*7c478bd9Sstevel@tonic-gate 		}
190*7c478bd9Sstevel@tonic-gate 	}
191*7c478bd9Sstevel@tonic-gate 	return (res);
192*7c478bd9Sstevel@tonic-gate }
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate struct project *
_getdefaultproj(const char * user,struct project * result,void * buffer,size_t buflen)195*7c478bd9Sstevel@tonic-gate _getdefaultproj(const char *user, struct project *result,
196*7c478bd9Sstevel@tonic-gate     void *buffer, size_t buflen)
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	char projname[PROJNAME_MAX + 1];
199*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
200*7c478bd9Sstevel@tonic-gate 	userattr_t *uattr;
201*7c478bd9Sstevel@tonic-gate 	struct passwd p;
202*7c478bd9Sstevel@tonic-gate 	struct group g;
203*7c478bd9Sstevel@tonic-gate 	char *attrproj;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	/*
208*7c478bd9Sstevel@tonic-gate 	 * Need user's default group ID for ismember() calls later
209*7c478bd9Sstevel@tonic-gate 	 */
210*7c478bd9Sstevel@tonic-gate 	if (getpwnam_r(user, &p, buffer, buflen) == NULL)
211*7c478bd9Sstevel@tonic-gate 		return (NULL);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	/*
214*7c478bd9Sstevel@tonic-gate 	 * Check user_attr database first
215*7c478bd9Sstevel@tonic-gate 	 */
216*7c478bd9Sstevel@tonic-gate 	if ((uattr = getusernam(user)) != NULL) {
217*7c478bd9Sstevel@tonic-gate 		if ((attrproj = kva_match(uattr->attr, "project")) != NULL) {
218*7c478bd9Sstevel@tonic-gate 			arg.key.name = attrproj;
219*7c478bd9Sstevel@tonic-gate 			(void) nss_search(&db_root, _nss_initf_project,
220*7c478bd9Sstevel@tonic-gate 			    NSS_DBOP_PROJECT_BYNAME, &arg);
221*7c478bd9Sstevel@tonic-gate 			if ((result = NSS_XbyY_FINI(&arg)) != NULL) {
222*7c478bd9Sstevel@tonic-gate 				free_userattr(uattr);
223*7c478bd9Sstevel@tonic-gate 				return (result);
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 		}
226*7c478bd9Sstevel@tonic-gate 		free_userattr(uattr);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	/*
230*7c478bd9Sstevel@tonic-gate 	 * Check user.{username} and group.{groupname} projects
231*7c478bd9Sstevel@tonic-gate 	 */
232*7c478bd9Sstevel@tonic-gate 	(void) snprintf(projname, PROJNAME_MAX, "user.%s", user);
233*7c478bd9Sstevel@tonic-gate 	arg.key.name = projname;
234*7c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_project,
235*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_PROJECT_BYNAME, &arg);
236*7c478bd9Sstevel@tonic-gate 	if ((result = NSS_XbyY_FINI(&arg)) != NULL &&
237*7c478bd9Sstevel@tonic-gate 	    ismember(result, user, p.pw_gid, DEFAULT_PROJECT))
238*7c478bd9Sstevel@tonic-gate 		return (result);
239*7c478bd9Sstevel@tonic-gate 	if (getgrgid_r(p.pw_gid, &g, buffer, buflen) != NULL) {
240*7c478bd9Sstevel@tonic-gate 		(void) snprintf(projname, PROJNAME_MAX, "group.%s", g.gr_name);
241*7c478bd9Sstevel@tonic-gate 		arg.key.name = projname;
242*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, _nss_initf_project,
243*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PROJECT_BYNAME, &arg);
244*7c478bd9Sstevel@tonic-gate 		if ((result = NSS_XbyY_FINI(&arg)) != NULL &&
245*7c478bd9Sstevel@tonic-gate 		    ismember(result, user, p.pw_gid, DEFAULT_PROJECT))
246*7c478bd9Sstevel@tonic-gate 			return (result);
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 	arg.key.name = "default";
249*7c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_project,
250*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_PROJECT_BYNAME, &arg);
251*7c478bd9Sstevel@tonic-gate 	if ((result = NSS_XbyY_FINI(&arg)) != NULL &&
252*7c478bd9Sstevel@tonic-gate 	    ismember(result, user, p.pw_gid, DEFAULT_PROJECT))
253*7c478bd9Sstevel@tonic-gate 		return (result);
254*7c478bd9Sstevel@tonic-gate 	return (NULL);
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate int
_inproj(const char * user,const char * name,void * buffer,size_t buflen)258*7c478bd9Sstevel@tonic-gate _inproj(const char *user, const char *name, void *buffer, size_t buflen)
259*7c478bd9Sstevel@tonic-gate {
260*7c478bd9Sstevel@tonic-gate 	char projname[PROJNAME_MAX + 1];
261*7c478bd9Sstevel@tonic-gate 	char grbuf[NSS_BUFLEN_GROUP];
262*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
263*7c478bd9Sstevel@tonic-gate 	struct project proj;
264*7c478bd9Sstevel@tonic-gate 	struct passwd pwd;
265*7c478bd9Sstevel@tonic-gate 	userattr_t *uattr;
266*7c478bd9Sstevel@tonic-gate 	struct group grp;
267*7c478bd9Sstevel@tonic-gate 	char *attrproj;
268*7c478bd9Sstevel@tonic-gate 	gid_t gid;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, &proj, buffer, buflen, str2project);
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	/*
273*7c478bd9Sstevel@tonic-gate 	 * 0. Sanity checks.
274*7c478bd9Sstevel@tonic-gate 	 */
275*7c478bd9Sstevel@tonic-gate 	if (getpwnam_r(user, &pwd, buffer, buflen) == NULL)
276*7c478bd9Sstevel@tonic-gate 		return (0);		/* user does not exist */
277*7c478bd9Sstevel@tonic-gate 	gid = pwd.pw_gid;
278*7c478bd9Sstevel@tonic-gate 	if (getprojbyname(name, &proj, buffer, buflen) == NULL)
279*7c478bd9Sstevel@tonic-gate 		return (0);		/* project does not exist */
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/*
282*7c478bd9Sstevel@tonic-gate 	 * 1. Check for special "default" project.
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	if (strcmp("default", name) == 0)
285*7c478bd9Sstevel@tonic-gate 		return (ismember(&proj, user, gid, DEFAULT_PROJECT));
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/*
288*7c478bd9Sstevel@tonic-gate 	 * 2. Check user_attr database.
289*7c478bd9Sstevel@tonic-gate 	 */
290*7c478bd9Sstevel@tonic-gate 	if ((uattr = getusernam(user)) != NULL) {
291*7c478bd9Sstevel@tonic-gate 		if ((attrproj = kva_match(uattr->attr, "project")) != NULL) {
292*7c478bd9Sstevel@tonic-gate 			if (strcmp(attrproj, name) == 0) {
293*7c478bd9Sstevel@tonic-gate 				free_userattr(uattr);
294*7c478bd9Sstevel@tonic-gate 				return (ismember(&proj, user, gid,
295*7c478bd9Sstevel@tonic-gate 				    DEFAULT_PROJECT));
296*7c478bd9Sstevel@tonic-gate 			}
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 		free_userattr(uattr);
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	/*
302*7c478bd9Sstevel@tonic-gate 	 * 3. Check if this is a special "user.username" project.
303*7c478bd9Sstevel@tonic-gate 	 *
304*7c478bd9Sstevel@tonic-gate 	 * User "username" is considered to be a member of project
305*7c478bd9Sstevel@tonic-gate 	 * "user.username" even if project's user lists do not
306*7c478bd9Sstevel@tonic-gate 	 * include "username".
307*7c478bd9Sstevel@tonic-gate 	 */
308*7c478bd9Sstevel@tonic-gate 	(void) snprintf(projname, PROJNAME_MAX, "user.%s", user);
309*7c478bd9Sstevel@tonic-gate 	if (strcmp(projname, name) == 0)
310*7c478bd9Sstevel@tonic-gate 		return (ismember(&proj, user, gid, DEFAULT_PROJECT));
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/*
313*7c478bd9Sstevel@tonic-gate 	 * 4. Check if this is a special "group.groupname" project.
314*7c478bd9Sstevel@tonic-gate 	 *
315*7c478bd9Sstevel@tonic-gate 	 * User "username" with default group "groupname" is considered
316*7c478bd9Sstevel@tonic-gate 	 * to be a member of project "group.groupname" even if project's
317*7c478bd9Sstevel@tonic-gate 	 * group list does not include "groupname".
318*7c478bd9Sstevel@tonic-gate 	 */
319*7c478bd9Sstevel@tonic-gate 	if (getgrgid_r(gid, &grp, grbuf, NSS_LINELEN_GROUP) != NULL) {
320*7c478bd9Sstevel@tonic-gate 		(void) snprintf(projname, PROJNAME_MAX,
321*7c478bd9Sstevel@tonic-gate 		    "group.%s", grp.gr_name);
322*7c478bd9Sstevel@tonic-gate 		if (strcmp(projname, name) == 0)
323*7c478bd9Sstevel@tonic-gate 			return (ismember(&proj, user, gid, DEFAULT_PROJECT));
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	/*
327*7c478bd9Sstevel@tonic-gate 	 * 5. Handle all other (non-default) projects.
328*7c478bd9Sstevel@tonic-gate 	 */
329*7c478bd9Sstevel@tonic-gate 	return (ismember(&proj, user, gid, NORMAL_PROJECT));
330*7c478bd9Sstevel@tonic-gate }
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate /*
333*7c478bd9Sstevel@tonic-gate  * Just a quick wrapper around getprojbyname so that the caller does not
334*7c478bd9Sstevel@tonic-gate  * need to allocate the buffer.
335*7c478bd9Sstevel@tonic-gate  */
336*7c478bd9Sstevel@tonic-gate projid_t
_getprojidbyname(const char * name)337*7c478bd9Sstevel@tonic-gate _getprojidbyname(const char *name)
338*7c478bd9Sstevel@tonic-gate {
339*7c478bd9Sstevel@tonic-gate 	struct project proj;
340*7c478bd9Sstevel@tonic-gate 	char buf[PROJECT_BUFSZ];
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (getprojbyname(name, &proj, &buf, PROJECT_BUFSZ) != NULL)
343*7c478bd9Sstevel@tonic-gate 		return (proj.pj_projid);
344*7c478bd9Sstevel@tonic-gate 	else
345*7c478bd9Sstevel@tonic-gate 		return ((projid_t)-1);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate static char *
gettok(char ** nextpp,char sep)349*7c478bd9Sstevel@tonic-gate gettok(char **nextpp, char sep)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	char *p = *nextpp;
352*7c478bd9Sstevel@tonic-gate 	char *q = p;
353*7c478bd9Sstevel@tonic-gate 	char c;
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
356*7c478bd9Sstevel@tonic-gate 		return (NULL);
357*7c478bd9Sstevel@tonic-gate 	while ((c = *q) != '\0' && c != sep)
358*7c478bd9Sstevel@tonic-gate 		q++;
359*7c478bd9Sstevel@tonic-gate 	if (c == '\0')
360*7c478bd9Sstevel@tonic-gate 		*nextpp = 0;
361*7c478bd9Sstevel@tonic-gate 	else {
362*7c478bd9Sstevel@tonic-gate 		*q++ = '\0';
363*7c478bd9Sstevel@tonic-gate 		*nextpp = q;
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 	return (p);
366*7c478bd9Sstevel@tonic-gate }
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate /*
370*7c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
371*7c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
372*7c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
373*7c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
374*7c478bd9Sstevel@tonic-gate  */
375*7c478bd9Sstevel@tonic-gate static int
str2project(const char * instr,int lenstr,void * ent,char * buffer,int buflen)376*7c478bd9Sstevel@tonic-gate str2project(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
377*7c478bd9Sstevel@tonic-gate {
378*7c478bd9Sstevel@tonic-gate 	struct project *project = ent;
379*7c478bd9Sstevel@tonic-gate 	char *p, *next;
380*7c478bd9Sstevel@tonic-gate 	char *users, *groups;
381*7c478bd9Sstevel@tonic-gate 	char **uglist;
382*7c478bd9Sstevel@tonic-gate 	char **limit;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (lenstr + 1 > buflen)
385*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
386*7c478bd9Sstevel@tonic-gate 	/*
387*7c478bd9Sstevel@tonic-gate 	 * We copy the input string into the output buffer and
388*7c478bd9Sstevel@tonic-gate 	 * operate on it in place.
389*7c478bd9Sstevel@tonic-gate 	 */
390*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, instr, lenstr);
391*7c478bd9Sstevel@tonic-gate 	buffer[lenstr] = '\0';
392*7c478bd9Sstevel@tonic-gate 	next = buffer;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	limit = (char **)ROUND_DOWN(buffer + buflen, sizeof (char *));
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	/*
397*7c478bd9Sstevel@tonic-gate 	 * Parsers for passwd and group have always been pretty rigid;
398*7c478bd9Sstevel@tonic-gate 	 * we wouldn't want to buck a Unix tradition
399*7c478bd9Sstevel@tonic-gate 	 */
400*7c478bd9Sstevel@tonic-gate 	p = gettok(&next, ':');
401*7c478bd9Sstevel@tonic-gate 	if (p == NULL || *p == '\0' || strlen(p) > PROJNAME_MAX) {
402*7c478bd9Sstevel@tonic-gate 		/*
403*7c478bd9Sstevel@tonic-gate 		 * empty or very long project names are not allowed
404*7c478bd9Sstevel@tonic-gate 		 */
405*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 	project->pj_name = p;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	p = gettok(&next, ':');
410*7c478bd9Sstevel@tonic-gate 	if (p == NULL || *p == '\0') {
411*7c478bd9Sstevel@tonic-gate 		/*
412*7c478bd9Sstevel@tonic-gate 		 * projid field shouldn't be empty
413*7c478bd9Sstevel@tonic-gate 		 */
414*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	project->pj_projid = (projid_t)strtol(p, NULL, 10);
417*7c478bd9Sstevel@tonic-gate 	if (project->pj_projid < 0) {
418*7c478bd9Sstevel@tonic-gate 		/*
419*7c478bd9Sstevel@tonic-gate 		 * projids should be positive number
420*7c478bd9Sstevel@tonic-gate 		 */
421*7c478bd9Sstevel@tonic-gate 		project->pj_projid = 0;
422*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	p = gettok(&next, ':');
426*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
427*7c478bd9Sstevel@tonic-gate 		/*
428*7c478bd9Sstevel@tonic-gate 		 * comment field can be empty but should not be last field
429*7c478bd9Sstevel@tonic-gate 		 */
430*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 	project->pj_comment = p;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	if ((users = gettok(&next, ':')) == NULL) {
435*7c478bd9Sstevel@tonic-gate 		/*
436*7c478bd9Sstevel@tonic-gate 		 * users field should not be last field
437*7c478bd9Sstevel@tonic-gate 		 */
438*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	if ((groups = gettok(&next, ':')) == NULL) {
442*7c478bd9Sstevel@tonic-gate 		/*
443*7c478bd9Sstevel@tonic-gate 		 * groups field should not be last field
444*7c478bd9Sstevel@tonic-gate 		 */
445*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (next == NULL) {
449*7c478bd9Sstevel@tonic-gate 		/*
450*7c478bd9Sstevel@tonic-gate 		 * attributes field should be last
451*7c478bd9Sstevel@tonic-gate 		 */
452*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	project->pj_attr = next;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	uglist = (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *));
458*7c478bd9Sstevel@tonic-gate 	*uglist = NULL;
459*7c478bd9Sstevel@tonic-gate 	project->pj_users = uglist;
460*7c478bd9Sstevel@tonic-gate 	while (uglist < limit) {
461*7c478bd9Sstevel@tonic-gate 		p = gettok(&users, ',');
462*7c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == '\0') {
463*7c478bd9Sstevel@tonic-gate 			*uglist = 0;
464*7c478bd9Sstevel@tonic-gate 			break;
465*7c478bd9Sstevel@tonic-gate 		}
466*7c478bd9Sstevel@tonic-gate 		*uglist++ = p;
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 	if (uglist >= limit)
469*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	uglist++;
472*7c478bd9Sstevel@tonic-gate 	*uglist = NULL;
473*7c478bd9Sstevel@tonic-gate 	project->pj_groups = uglist;
474*7c478bd9Sstevel@tonic-gate 	while (uglist < limit) {
475*7c478bd9Sstevel@tonic-gate 		p = gettok(&groups, ',');
476*7c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == '\0') {
477*7c478bd9Sstevel@tonic-gate 			*uglist = 0;
478*7c478bd9Sstevel@tonic-gate 			break;
479*7c478bd9Sstevel@tonic-gate 		}
480*7c478bd9Sstevel@tonic-gate 		*uglist++ = p;
481*7c478bd9Sstevel@tonic-gate 	}
482*7c478bd9Sstevel@tonic-gate 	if (uglist >= limit)
483*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
486*7c478bd9Sstevel@tonic-gate }
487