diff options
Diffstat (limited to 'module/spl')
-rw-r--r-- | module/spl/Makefile.in | 1 | ||||
-rw-r--r-- | module/spl/spl-cred.c | 308 | ||||
-rw-r--r-- | module/spl/spl-debug.c | 2 |
3 files changed, 311 insertions, 0 deletions
diff --git a/module/spl/Makefile.in b/module/spl/Makefile.in index e9c8d3470..ad29af406 100644 --- a/module/spl/Makefile.in +++ b/module/spl/Makefile.in @@ -23,3 +23,4 @@ spl-objs += spl-mutex.o spl-objs += spl-kstat.o spl-objs += spl-condvar.o spl-objs += spl-xdr.o +spl-objs += spl-cred.o diff --git a/module/spl/spl-cred.c b/module/spl/spl-cred.c new file mode 100644 index 000000000..c5994aa20 --- /dev/null +++ b/module/spl/spl-cred.c @@ -0,0 +1,308 @@ +/* + * This file is part of the SPL: Solaris Porting Layer. + * + * Copyright (c) 2009 Lawrence Livermore National Security, LLC. + * Produced at Lawrence Livermore National Laboratory + * Written by: + * Brian Behlendorf <[email protected]>, + * UCRL-CODE-235197 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <sys/cred.h> + +#ifdef DEBUG_SUBSYSTEM +#undef DEBUG_SUBSYSTEM +#endif + +#define DEBUG_SUBSYSTEM S_CRED + +#ifdef HAVE_GROUPS_SEARCH +/* Symbol may be exported by custom kernel patch */ +#define cr_groups_search(gi, grp) groups_search(gi, grp) +#else +/* Implementation from 2.6.30 kernel */ +static int +cr_groups_search(const struct group_info *group_info, gid_t grp) +{ + unsigned int left, right; + + if (!group_info) + return 0; + + left = 0; + right = group_info->ngroups; + while (left < right) { + unsigned int mid = (left+right)/2; + int cmp = grp - GROUP_AT(group_info, mid); + if (cmp > 0) + left = mid + 1; + else if (cmp < 0) + right = mid; + else + return 1; + } + return 0; +} +#endif + +#ifdef HAVE_CRED_STRUCT + +/* + * As of 2.6.29 a clean credential API appears in the linux kernel. + * We attempt to layer the Solaris API on top of the linux API. + */ + +/* Hold a reference on the credential and group info */ +void +crhold(cred_t *cr) +{ + (void)get_cred((const cred_t *)cr); + (void)get_group_info(cr->group_info); +} + +/* Free a reference on the credential and group info */ +void +crfree(cred_t *cr) +{ + put_group_info(cr->group_info); + put_cred((const cred_t *)cr); +} + +/* Return the effective user id */ +uid_t +crgetuid(const cred_t *cr) +{ + return cr->euid; +} + +/* Return the real user id */ +uid_t +crgetruid(const cred_t *cr) +{ + return cr->uid; +} + +/* Return the saved user id */ +uid_t +crgetsuid(const cred_t *cr) +{ + return cr->suid; +} + +/* Return the effective group id */ +gid_t +crgetgid(const cred_t *cr) +{ + return cr->egid; +} + +/* Return the real group id */ +gid_t +crgetrgid(const cred_t *cr) +{ + return cr->gid; +} + +/* Return the saved group id */ +gid_t +crgetsgid(const cred_t *cr) +{ + return cr->sgid; +} + +/* Return the number of supplemental groups */ +int +crgetngroups(const cred_t *cr) +{ + struct group_info *gi; + int rc; + + gi = get_group_info(cr->group_info); + rc = gi->ngroups; + put_group_info(gi); + + return rc; +} + +/* + * Return an array of supplemental gids. The returned address is safe + * to use as long as the caller has taken a reference with crhold(). + * The caller is responsible for releasing the reference with crfree(). + */ +gid_t * +crgetgroups(const cred_t *cr) +{ + struct group_info *gi; + gid_t *gids; + + gi = get_group_info(cr->group_info); + gids = gi->blocks[0]; + put_group_info(gi); + + return gids; +} + +/* Check if the passed gid is available is in supplied credential. */ +int +groupmember(gid_t gid, const cred_t *cr) +{ + struct group_info *gi; + int rc; + + gi = get_group_info(cr->group_info); + rc = cr_groups_search(cr->group_info, gid); + put_group_info(gi); + + return rc; +} + +#else /* HAVE_CRED_STRUCT */ + +/* + * Until very recently all credential information was embedded in + * the linux task struct. For this reason to simulate a Solaris + * cred_t we need to pass the entire task structure around. + */ + +/* Hold a reference on the credential and group info */ +void +crhold(cred_t *cr) +{ + get_task_struct(cr); +} + +/* Free a reference on the credential and group info */ +void +crfree(cred_t *cr) +{ + put_task_struct(cr); +} + +/* Return the effective user id */ +uid_t +crgetuid(const cred_t *cr) { + return cr->euid; +} + +/* Return the effective real id */ +uid_t +crgetruid(const cred_t *cr) { + return cr->uid; +} + +/* Return the effective saved id */ +uid_t +crgetsuid(const cred_t *cr) { + return cr->suid; +} + +/* Return the effective group id */ +gid_t +crgetgid(const cred_t *cr) { + return cr->egid; +} + +/* Return the real group id */ +gid_t +crgetrgid(const cred_t *cr) { + return cr->gid; +} + +/* Return the saved group id */ +gid_t +crgetsgid(const cred_t *cr) { + return cr->sgid; +} + +/* Return the number of supplemental groups */ +int +crgetngroups(const cred_t *cr) +{ + int lock, rc; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + rc = cr->group_info->ngroups; + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return rc; +} + +/* + * Return an array of supplemental gids. The returned address is safe + * to use as long as the caller has taken a reference with crhold(). + * The caller is responsible for releasing the reference with crfree(). + */ +gid_t * +crgetgroups(const cred_t *cr) +{ + gid_t *gids; + int lock; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + gids = cr->group_info->blocks[0]; + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return gids; +} + +/* Check if the passed gid is available is in supplied credential. */ +int +groupmember(gid_t gid, const cred_t *cr) +{ + int lock, rc; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + rc = cr_groups_search(cr->group_info, gid); + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return rc; +} + +#endif /* HAVE_CRED_STRUCT */ + +EXPORT_SYMBOL(crhold); +EXPORT_SYMBOL(crfree); +EXPORT_SYMBOL(crgetuid); +EXPORT_SYMBOL(crgetruid); +EXPORT_SYMBOL(crgetsuid); +EXPORT_SYMBOL(crgetgid); +EXPORT_SYMBOL(crgetrgid); +EXPORT_SYMBOL(crgetsgid); +EXPORT_SYMBOL(crgetngroups); +EXPORT_SYMBOL(crgetgroups); +EXPORT_SYMBOL(groupmember); diff --git a/module/spl/spl-debug.c b/module/spl/spl-debug.c index a60740519..6d71f4b82 100644 --- a/module/spl/spl-debug.c +++ b/module/spl/spl-debug.c @@ -157,6 +157,8 @@ spl_debug_subsys2str(int subsys) return "proc"; case S_MODULE: return "module"; + case S_CRED: + return "cred"; } } |