diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libproject/common/getprojent.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libproject/common/getprojent.c')
-rw-r--r-- | usr/src/lib/libproject/common/getprojent.c | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/usr/src/lib/libproject/common/getprojent.c b/usr/src/lib/libproject/common/getprojent.c new file mode 100644 index 0000000000..46b373c917 --- /dev/null +++ b/usr/src/lib/libproject/common/getprojent.c @@ -0,0 +1,488 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <user_attr.h> +#include <pwd.h> +#include <grp.h> +#include <userdefs.h> +#include <project.h> +#include <memory.h> +#include <nss_dbdefs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/mman.h> + +#pragma weak setprojent = _setprojent +#pragma weak endprojent = _endprojent +#pragma weak getprojent = _getprojent +#pragma weak fgetprojent = _fgetprojent +#pragma weak getprojbyid = _getprojbyid +#pragma weak getprojbyname = _getprojbyname +#pragma weak getdefaultproj = _getdefaultproj +#pragma weak inproj = _inproj +#pragma weak getprojidbyname = _getprojidbyname + +#define DEFAULT_PROJECT 1 +#define NORMAL_PROJECT 0 + +static int ismember(struct project *, const char *, gid_t, int); +static int str2project(const char *, int, void *, char *, int); + +static DEFINE_NSS_DB_ROOT(db_root); +static DEFINE_NSS_GETENT(context); + +void +_nss_initf_project(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PROJECT; + p->default_config = NSS_DEFCONF_PROJECT; +} + +void +_setprojent(void) +{ + nss_setent(&db_root, _nss_initf_project, &context); +} + +void +_endprojent(void) +{ + nss_endent(&db_root, _nss_initf_project, &context); + nss_delete(&db_root); +} + +struct project * +_getprojent(struct project *result, void *buffer, size_t buflen) +{ + nss_XbyY_args_t arg; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project); + (void) nss_getent(&db_root, _nss_initf_project, &context, &arg); + return ((struct project *)NSS_XbyY_FINI(&arg)); +} + +struct project * +_fgetprojent(FILE *f, struct project *result, void *buffer, size_t buflen) +{ + extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *); + nss_XbyY_args_t arg; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project); + _nss_XbyY_fgets(f, &arg); + return ((struct project *)NSS_XbyY_FINI(&arg)); +} + +struct project * +_getprojbyid(projid_t projid, struct project *result, + void *buffer, size_t buflen) +{ + nss_XbyY_args_t arg; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project); + arg.key.projid = projid; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYID, &arg); + return ((struct project *)NSS_XbyY_FINI(&arg)); +} + +struct project * +_getprojbyname(const char *name, struct project *result, + void *buffer, size_t buflen) +{ + nss_XbyY_args_t arg; + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project); + arg.key.name = name; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYNAME, &arg); + return ((struct project *)NSS_XbyY_FINI(&arg)); +} + +/* + * The following routine checks if user specified by the second argument + * is allowed to join the project specified as project structure in first + * argument. Information about user's default group and whether or not + * the project specified in the first argument is user's default project + * (i.e., user_attr, "default", "user.username", or "group.groupname" + * should also be provided. If is_default is set to DEFAULT_PROJECT, + * then this function returns 1 (true), unless specified user explicitly + * excluded with "!user", or "!group" wildcards. + */ +static int +ismember(struct project *proj, const char *user, gid_t gid, int is_default) +{ + char grbuf[NSS_BUFLEN_GROUP]; + char groupname[MAXGLEN + 1]; + int res = is_default; + struct group grp; + int group_ok = 0; + char **u, **g; + char *member; + + if (getgrgid_r(gid, &grp, grbuf, NSS_BUFLEN_GROUP) != NULL) { + group_ok = 1; + (void) snprintf(groupname, MAXGLEN, grp.gr_name); + } + + /* + * Scan project's user list. + */ + for (u = proj->pj_users; *u; u++) { + member = *u; + if (member[0] == '!' && + (strcmp(member + 1, user) == 0 || + strcmp(member + 1, "*") == 0)) + return (0); + if (strcmp(member, "*") == 0 || strcmp(member, user) == 0) + res = 1; + } + + /* + * Scan project's group list. + */ + for (g = proj->pj_groups; *g; g++) { + member = *g; + /* + * Check if user's default group is included here. + */ + if (group_ok) { + if (member[0] == '!' && + (strcmp(member + 1, groupname) == 0 || + strcmp(member + 1, "*") == 0)) + return (0); + if (strcmp(member, "*") == 0 || + strcmp(member, groupname) == 0) + res = 1; + } + /* + * Check if user is a member of one of project's groups. + */ + if (getgrnam_r(member, &grp, grbuf, NSS_BUFLEN_GROUP) != NULL) { + for (u = grp.gr_mem; *u; u++) + if (strcmp(*u, user) == 0) + res = 1; + } + } + return (res); +} + +struct project * +_getdefaultproj(const char *user, struct project *result, + void *buffer, size_t buflen) +{ + char projname[PROJNAME_MAX + 1]; + nss_XbyY_args_t arg; + userattr_t *uattr; + struct passwd p; + struct group g; + char *attrproj; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2project); + + /* + * Need user's default group ID for ismember() calls later + */ + if (getpwnam_r(user, &p, buffer, buflen) == NULL) + return (NULL); + + /* + * Check user_attr database first + */ + if ((uattr = getusernam(user)) != NULL) { + if ((attrproj = kva_match(uattr->attr, "project")) != NULL) { + arg.key.name = attrproj; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYNAME, &arg); + if ((result = NSS_XbyY_FINI(&arg)) != NULL) { + free_userattr(uattr); + return (result); + } + } + free_userattr(uattr); + } + + /* + * Check user.{username} and group.{groupname} projects + */ + (void) snprintf(projname, PROJNAME_MAX, "user.%s", user); + arg.key.name = projname; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYNAME, &arg); + if ((result = NSS_XbyY_FINI(&arg)) != NULL && + ismember(result, user, p.pw_gid, DEFAULT_PROJECT)) + return (result); + if (getgrgid_r(p.pw_gid, &g, buffer, buflen) != NULL) { + (void) snprintf(projname, PROJNAME_MAX, "group.%s", g.gr_name); + arg.key.name = projname; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYNAME, &arg); + if ((result = NSS_XbyY_FINI(&arg)) != NULL && + ismember(result, user, p.pw_gid, DEFAULT_PROJECT)) + return (result); + } + arg.key.name = "default"; + (void) nss_search(&db_root, _nss_initf_project, + NSS_DBOP_PROJECT_BYNAME, &arg); + if ((result = NSS_XbyY_FINI(&arg)) != NULL && + ismember(result, user, p.pw_gid, DEFAULT_PROJECT)) + return (result); + return (NULL); +} + +int +_inproj(const char *user, const char *name, void *buffer, size_t buflen) +{ + char projname[PROJNAME_MAX + 1]; + char grbuf[NSS_BUFLEN_GROUP]; + nss_XbyY_args_t arg; + struct project proj; + struct passwd pwd; + userattr_t *uattr; + struct group grp; + char *attrproj; + gid_t gid; + + NSS_XbyY_INIT(&arg, &proj, buffer, buflen, str2project); + + /* + * 0. Sanity checks. + */ + if (getpwnam_r(user, &pwd, buffer, buflen) == NULL) + return (0); /* user does not exist */ + gid = pwd.pw_gid; + if (getprojbyname(name, &proj, buffer, buflen) == NULL) + return (0); /* project does not exist */ + + /* + * 1. Check for special "default" project. + */ + if (strcmp("default", name) == 0) + return (ismember(&proj, user, gid, DEFAULT_PROJECT)); + + /* + * 2. Check user_attr database. + */ + if ((uattr = getusernam(user)) != NULL) { + if ((attrproj = kva_match(uattr->attr, "project")) != NULL) { + if (strcmp(attrproj, name) == 0) { + free_userattr(uattr); + return (ismember(&proj, user, gid, + DEFAULT_PROJECT)); + } + } + free_userattr(uattr); + } + + /* + * 3. Check if this is a special "user.username" project. + * + * User "username" is considered to be a member of project + * "user.username" even if project's user lists do not + * include "username". + */ + (void) snprintf(projname, PROJNAME_MAX, "user.%s", user); + if (strcmp(projname, name) == 0) + return (ismember(&proj, user, gid, DEFAULT_PROJECT)); + + /* + * 4. Check if this is a special "group.groupname" project. + * + * User "username" with default group "groupname" is considered + * to be a member of project "group.groupname" even if project's + * group list does not include "groupname". + */ + if (getgrgid_r(gid, &grp, grbuf, NSS_LINELEN_GROUP) != NULL) { + (void) snprintf(projname, PROJNAME_MAX, + "group.%s", grp.gr_name); + if (strcmp(projname, name) == 0) + return (ismember(&proj, user, gid, DEFAULT_PROJECT)); + } + + /* + * 5. Handle all other (non-default) projects. + */ + return (ismember(&proj, user, gid, NORMAL_PROJECT)); +} + +/* + * Just a quick wrapper around getprojbyname so that the caller does not + * need to allocate the buffer. + */ +projid_t +_getprojidbyname(const char *name) +{ + struct project proj; + char buf[PROJECT_BUFSZ]; + + if (getprojbyname(name, &proj, &buf, PROJECT_BUFSZ) != NULL) + return (proj.pj_projid); + else + return ((projid_t)-1); +} + +static char * +gettok(char **nextpp, char sep) +{ + char *p = *nextpp; + char *q = p; + char c; + + if (p == NULL) + return (NULL); + while ((c = *q) != '\0' && c != sep) + q++; + if (c == '\0') + *nextpp = 0; + else { + *q++ = '\0'; + *nextpp = q; + } + return (p); +} + + +/* + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * The structure pointer passed in is a structure in the caller's space + * wherein the field pointers would be set to areas in the buffer if + * need be. instring and buffer should be separate areas. + */ +static int +str2project(const char *instr, int lenstr, void *ent, char *buffer, int buflen) +{ + struct project *project = ent; + char *p, *next; + char *users, *groups; + char **uglist; + char **limit; + + if (lenstr + 1 > buflen) + return (NSS_STR_PARSE_ERANGE); + /* + * We copy the input string into the output buffer and + * operate on it in place. + */ + (void) memcpy(buffer, instr, lenstr); + buffer[lenstr] = '\0'; + next = buffer; + + limit = (char **)ROUND_DOWN(buffer + buflen, sizeof (char *)); + + /* + * Parsers for passwd and group have always been pretty rigid; + * we wouldn't want to buck a Unix tradition + */ + p = gettok(&next, ':'); + if (p == NULL || *p == '\0' || strlen(p) > PROJNAME_MAX) { + /* + * empty or very long project names are not allowed + */ + return (NSS_STR_PARSE_ERANGE); + } + project->pj_name = p; + + p = gettok(&next, ':'); + if (p == NULL || *p == '\0') { + /* + * projid field shouldn't be empty + */ + return (NSS_STR_PARSE_PARSE); + } + project->pj_projid = (projid_t)strtol(p, NULL, 10); + if (project->pj_projid < 0) { + /* + * projids should be positive number + */ + project->pj_projid = 0; + return (NSS_STR_PARSE_PARSE); + } + + p = gettok(&next, ':'); + if (p == NULL) { + /* + * comment field can be empty but should not be last field + */ + return (NSS_STR_PARSE_PARSE); + } + project->pj_comment = p; + + if ((users = gettok(&next, ':')) == NULL) { + /* + * users field should not be last field + */ + return (NSS_STR_PARSE_PARSE); + } + + if ((groups = gettok(&next, ':')) == NULL) { + /* + * groups field should not be last field + */ + return (NSS_STR_PARSE_PARSE); + } + + if (next == NULL) { + /* + * attributes field should be last + */ + return (NSS_STR_PARSE_PARSE); + } + + project->pj_attr = next; + + uglist = (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *)); + *uglist = NULL; + project->pj_users = uglist; + while (uglist < limit) { + p = gettok(&users, ','); + if (p == NULL || *p == '\0') { + *uglist = 0; + break; + } + *uglist++ = p; + } + if (uglist >= limit) + return (NSS_STR_PARSE_ERANGE); + + uglist++; + *uglist = NULL; + project->pj_groups = uglist; + while (uglist < limit) { + p = gettok(&groups, ','); + if (p == NULL || *p == '\0') { + *uglist = 0; + break; + } + *uglist++ = p; + } + if (uglist >= limit) + return (NSS_STR_PARSE_ERANGE); + + return (NSS_STR_PARSE_SUCCESS); +} |