4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <user_attr.h>
36 #include <nss_dbdefs.h>
40 #include <sys/param.h>
43 #pragma weak setprojent = _setprojent
44 #pragma weak endprojent = _endprojent
45 #pragma weak getprojent = _getprojent
46 #pragma weak fgetprojent = _fgetprojent
47 #pragma weak getprojbyid = _getprojbyid
48 #pragma weak getprojbyname = _getprojbyname
49 #pragma weak getdefaultproj = _getdefaultproj
50 #pragma weak inproj = _inproj
51 #pragma weak getprojidbyname = _getprojidbyname
53 #define DEFAULT_PROJECT 1
54 #define NORMAL_PROJECT 0
56 static int ismember(struct project
*, const char *, gid_t
, int);
57 static int str2project(const char *, int, void *, char *, int);
59 static DEFINE_NSS_DB_ROOT(db_root
);
60 static DEFINE_NSS_GETENT(context
);
63 _nss_initf_project(nss_db_params_t
*p
)
65 p
->name
= NSS_DBNAM_PROJECT
;
66 p
->default_config
= NSS_DEFCONF_PROJECT
;
72 nss_setent(&db_root
, _nss_initf_project
, &context
);
78 nss_endent(&db_root
, _nss_initf_project
, &context
);
83 _getprojent(struct project
*result
, void *buffer
, size_t buflen
)
87 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2project
);
88 (void) nss_getent(&db_root
, _nss_initf_project
, &context
, &arg
);
89 return ((struct project
*)NSS_XbyY_FINI(&arg
));
93 _fgetprojent(FILE *f
, struct project
*result
, void *buffer
, size_t buflen
)
95 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t
*);
98 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2project
);
99 _nss_XbyY_fgets(f
, &arg
);
100 return ((struct project
*)NSS_XbyY_FINI(&arg
));
104 _getprojbyid(projid_t projid
, struct project
*result
,
105 void *buffer
, size_t buflen
)
109 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2project
);
110 arg
.key
.projid
= projid
;
111 (void) nss_search(&db_root
, _nss_initf_project
,
112 NSS_DBOP_PROJECT_BYID
, &arg
);
113 return ((struct project
*)NSS_XbyY_FINI(&arg
));
117 _getprojbyname(const char *name
, struct project
*result
,
118 void *buffer
, size_t buflen
)
121 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2project
);
123 (void) nss_search(&db_root
, _nss_initf_project
,
124 NSS_DBOP_PROJECT_BYNAME
, &arg
);
125 return ((struct project
*)NSS_XbyY_FINI(&arg
));
129 * The following routine checks if user specified by the second argument
130 * is allowed to join the project specified as project structure in first
131 * argument. Information about user's default group and whether or not
132 * the project specified in the first argument is user's default project
133 * (i.e., user_attr, "default", "user.username", or "group.groupname"
134 * should also be provided. If is_default is set to DEFAULT_PROJECT,
135 * then this function returns 1 (true), unless specified user explicitly
136 * excluded with "!user", or "!group" wildcards.
139 ismember(struct project
*proj
, const char *user
, gid_t gid
, int is_default
)
141 char grbuf
[NSS_BUFLEN_GROUP
];
142 char groupname
[MAXGLEN
+ 1];
143 int res
= is_default
;
149 if (getgrgid_r(gid
, &grp
, grbuf
, NSS_BUFLEN_GROUP
) != NULL
) {
151 (void) snprintf(groupname
, MAXGLEN
, grp
.gr_name
);
155 * Scan project's user list.
157 for (u
= proj
->pj_users
; *u
; u
++) {
159 if (member
[0] == '!' &&
160 (strcmp(member
+ 1, user
) == 0 ||
161 strcmp(member
+ 1, "*") == 0))
163 if (strcmp(member
, "*") == 0 || strcmp(member
, user
) == 0)
168 * Scan project's group list.
170 for (g
= proj
->pj_groups
; *g
; g
++) {
173 * Check if user's default group is included here.
176 if (member
[0] == '!' &&
177 (strcmp(member
+ 1, groupname
) == 0 ||
178 strcmp(member
+ 1, "*") == 0))
180 if (strcmp(member
, "*") == 0 ||
181 strcmp(member
, groupname
) == 0)
185 * Check if user is a member of one of project's groups.
187 if (getgrnam_r(member
, &grp
, grbuf
, NSS_BUFLEN_GROUP
) != NULL
) {
188 for (u
= grp
.gr_mem
; *u
; u
++)
189 if (strcmp(*u
, user
) == 0)
197 _getdefaultproj(const char *user
, struct project
*result
,
198 void *buffer
, size_t buflen
)
200 char projname
[PROJNAME_MAX
+ 1];
208 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2project
);
211 * Need user's default group ID for ismember() calls later
213 getpwnam_r(user
, &p
, buffer
, buflen
, &pwd
);
218 * Check user_attr database first
220 if ((uattr
= getusernam(user
)) != NULL
) {
221 if ((attrproj
= kva_match(uattr
->attr
, "project")) != NULL
) {
222 arg
.key
.name
= attrproj
;
223 (void) nss_search(&db_root
, _nss_initf_project
,
224 NSS_DBOP_PROJECT_BYNAME
, &arg
);
225 if ((result
= NSS_XbyY_FINI(&arg
)) != NULL
) {
226 free_userattr(uattr
);
230 free_userattr(uattr
);
234 * Check user.{username} and group.{groupname} projects
236 (void) snprintf(projname
, PROJNAME_MAX
, "user.%s", user
);
237 arg
.key
.name
= projname
;
238 (void) nss_search(&db_root
, _nss_initf_project
,
239 NSS_DBOP_PROJECT_BYNAME
, &arg
);
240 if ((result
= NSS_XbyY_FINI(&arg
)) != NULL
&&
241 ismember(result
, user
, p
.pw_gid
, DEFAULT_PROJECT
))
243 if (getgrgid_r(p
.pw_gid
, &g
, buffer
, buflen
) != NULL
) {
244 (void) snprintf(projname
, PROJNAME_MAX
, "group.%s", g
.gr_name
);
245 arg
.key
.name
= projname
;
246 (void) nss_search(&db_root
, _nss_initf_project
,
247 NSS_DBOP_PROJECT_BYNAME
, &arg
);
248 if ((result
= NSS_XbyY_FINI(&arg
)) != NULL
&&
249 ismember(result
, user
, p
.pw_gid
, DEFAULT_PROJECT
))
252 arg
.key
.name
= "default";
253 (void) nss_search(&db_root
, _nss_initf_project
,
254 NSS_DBOP_PROJECT_BYNAME
, &arg
);
255 if ((result
= NSS_XbyY_FINI(&arg
)) != NULL
&&
256 ismember(result
, user
, p
.pw_gid
, DEFAULT_PROJECT
))
262 _inproj(const char *user
, const char *name
, void *buffer
, size_t buflen
)
264 char projname
[PROJNAME_MAX
+ 1];
265 char grbuf
[NSS_BUFLEN_GROUP
];
273 struct passwd
*result
;
275 NSS_XbyY_INIT(&arg
, &proj
, buffer
, buflen
, str2project
);
280 getpwnam_r(user
, &pwd
, buffer
, buflen
, &result
);
282 return (0); /* user does not exist */
284 if (getprojbyname(name
, &proj
, buffer
, buflen
) == NULL
)
285 return (0); /* project does not exist */
288 * 1. Check for special "default" project.
290 if (strcmp("default", name
) == 0)
291 return (ismember(&proj
, user
, gid
, DEFAULT_PROJECT
));
294 * 2. Check user_attr database.
296 if ((uattr
= getusernam(user
)) != NULL
) {
297 if ((attrproj
= kva_match(uattr
->attr
, "project")) != NULL
) {
298 if (strcmp(attrproj
, name
) == 0) {
299 free_userattr(uattr
);
300 return (ismember(&proj
, user
, gid
,
304 free_userattr(uattr
);
308 * 3. Check if this is a special "user.username" project.
310 * User "username" is considered to be a member of project
311 * "user.username" even if project's user lists do not
312 * include "username".
314 (void) snprintf(projname
, PROJNAME_MAX
, "user.%s", user
);
315 if (strcmp(projname
, name
) == 0)
316 return (ismember(&proj
, user
, gid
, DEFAULT_PROJECT
));
319 * 4. Check if this is a special "group.groupname" project.
321 * User "username" with default group "groupname" is considered
322 * to be a member of project "group.groupname" even if project's
323 * group list does not include "groupname".
325 if (getgrgid_r(gid
, &grp
, grbuf
, NSS_LINELEN_GROUP
) != NULL
) {
326 (void) snprintf(projname
, PROJNAME_MAX
,
327 "group.%s", grp
.gr_name
);
328 if (strcmp(projname
, name
) == 0)
329 return (ismember(&proj
, user
, gid
, DEFAULT_PROJECT
));
333 * 5. Handle all other (non-default) projects.
335 return (ismember(&proj
, user
, gid
, NORMAL_PROJECT
));
339 * Just a quick wrapper around getprojbyname so that the caller does not
340 * need to allocate the buffer.
343 _getprojidbyname(const char *name
)
346 char buf
[PROJECT_BUFSZ
];
348 if (getprojbyname(name
, &proj
, &buf
, PROJECT_BUFSZ
) != NULL
)
349 return (proj
.pj_projid
);
351 return ((projid_t
)-1);
355 gettok(char **nextpp
, char sep
)
363 while ((c
= *q
) != '\0' && c
!= sep
)
376 * Return values: 0 = success, 1 = parse error, 2 = erange ...
377 * The structure pointer passed in is a structure in the caller's space
378 * wherein the field pointers would be set to areas in the buffer if
379 * need be. instring and buffer should be separate areas.
382 str2project(const char *instr
, int lenstr
, void *ent
, char *buffer
, int buflen
)
384 struct project
*project
= ent
;
386 char *users
, *groups
;
390 if (lenstr
+ 1 > buflen
)
391 return (NSS_STR_PARSE_ERANGE
);
393 * We copy the input string into the output buffer and
394 * operate on it in place.
396 (void) memcpy(buffer
, instr
, lenstr
);
397 buffer
[lenstr
] = '\0';
400 limit
= (char **)ROUND_DOWN(buffer
+ buflen
, sizeof (char *));
403 * Parsers for passwd and group have always been pretty rigid;
404 * we wouldn't want to buck a Unix tradition
406 p
= gettok(&next
, ':');
407 if (p
== NULL
|| *p
== '\0' || strlen(p
) > PROJNAME_MAX
) {
409 * empty or very long project names are not allowed
411 return (NSS_STR_PARSE_ERANGE
);
413 project
->pj_name
= p
;
415 p
= gettok(&next
, ':');
416 if (p
== NULL
|| *p
== '\0') {
418 * projid field shouldn't be empty
420 return (NSS_STR_PARSE_PARSE
);
422 project
->pj_projid
= (projid_t
)strtol(p
, NULL
, 10);
423 if (project
->pj_projid
< 0) {
425 * projids should be positive number
427 project
->pj_projid
= 0;
428 return (NSS_STR_PARSE_PARSE
);
431 p
= gettok(&next
, ':');
434 * comment field can be empty but should not be last field
436 return (NSS_STR_PARSE_PARSE
);
438 project
->pj_comment
= p
;
440 if ((users
= gettok(&next
, ':')) == NULL
) {
442 * users field should not be last field
444 return (NSS_STR_PARSE_PARSE
);
447 if ((groups
= gettok(&next
, ':')) == NULL
) {
449 * groups field should not be last field
451 return (NSS_STR_PARSE_PARSE
);
456 * attributes field should be last
458 return (NSS_STR_PARSE_PARSE
);
461 project
->pj_attr
= next
;
463 uglist
= (char **)ROUND_UP(buffer
+ lenstr
+ 1, sizeof (char *));
465 project
->pj_users
= uglist
;
466 while (uglist
< limit
) {
467 p
= gettok(&users
, ',');
468 if (p
== NULL
|| *p
== '\0') {
475 return (NSS_STR_PARSE_ERANGE
);
479 project
->pj_groups
= uglist
;
480 while (uglist
< limit
) {
481 p
= gettok(&groups
, ',');
482 if (p
== NULL
|| *p
== '\0') {
489 return (NSS_STR_PARSE_ERANGE
);
491 return (NSS_STR_PARSE_SUCCESS
);