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