1/* 2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. 3 * Copyright (C) 2007 The Regents of the University of California. 4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>. 6 * UCRL-CODE-235197 7 * 8 * This file is part of the SPL, Solaris Porting Layer. 9 * 10 * The SPL is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * The SPL is distributed in the hope that it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with the SPL. If not, see <http://www.gnu.org/licenses/>. 22 * 23 * Solaris Porting Layer (SPL) Credential Implementation. 24 */ 25 26#include <sys/cred.h> 27 28static int 29cr_groups_search(const struct group_info *group_info, kgid_t grp) 30{ 31 unsigned int left, right, mid; 32 int cmp; 33 34 if (!group_info) 35 return (0); 36 37 left = 0; 38 right = group_info->ngroups; 39 while (left < right) { 40 mid = (left + right) / 2; 41 cmp = KGID_TO_SGID(grp) - 42 KGID_TO_SGID(GROUP_AT(group_info, mid)); 43 44 if (cmp > 0) 45 left = mid + 1; 46 else if (cmp < 0) 47 right = mid; 48 else 49 return (1); 50 } 51 return (0); 52} 53 54/* Hold a reference on the credential */ 55void 56crhold(cred_t *cr) 57{ 58 (void) get_cred((const cred_t *)cr); 59} 60 61/* Free a reference on the credential */ 62void 63crfree(cred_t *cr) 64{ 65 put_cred((const cred_t *)cr); 66} 67 68/* Return the number of supplemental groups */ 69int 70crgetngroups(const cred_t *cr) 71{ 72 struct group_info *gi; 73 int rc; 74 75 gi = cr->group_info; 76 rc = gi->ngroups; 77#ifndef HAVE_GROUP_INFO_GID 78 /* 79 * For Linux <= 4.8, 80 * crgetgroups will only returns gi->blocks[0], which contains only 81 * the first NGROUPS_PER_BLOCK groups. 82 */ 83 if (rc > NGROUPS_PER_BLOCK) { 84 WARN_ON_ONCE(1); 85 rc = NGROUPS_PER_BLOCK; 86 } 87#endif 88 return (rc); 89} 90 91/* 92 * Return an array of supplemental gids. The returned address is safe 93 * to use as long as the caller has taken a reference with crhold(). 94 * 95 * Linux 4.9 API change, group_info changed from 2d array via ->blocks to 1d 96 * array via ->gid. 97 */ 98gid_t * 99crgetgroups(const cred_t *cr) 100{ 101 struct group_info *gi; 102 gid_t *gids = NULL; 103 104 gi = cr->group_info; 105#ifdef HAVE_GROUP_INFO_GID 106 gids = KGIDP_TO_SGIDP(gi->gid); 107#else 108 if (gi->nblocks > 0) 109 gids = KGIDP_TO_SGIDP(gi->blocks[0]); 110#endif 111 return (gids); 112} 113 114/* Check if the passed gid is available in supplied credential. */ 115int 116groupmember(gid_t gid, const cred_t *cr) 117{ 118 struct group_info *gi; 119 int rc; 120 121 gi = cr->group_info; 122 rc = cr_groups_search(gi, SGID_TO_KGID(gid)); 123 124 return (rc); 125} 126 127/* Return the effective user id */ 128uid_t 129crgetuid(const cred_t *cr) 130{ 131 return (KUID_TO_SUID(cr->fsuid)); 132} 133 134/* Return the real user id */ 135uid_t 136crgetruid(const cred_t *cr) 137{ 138 return (KUID_TO_SUID(cr->uid)); 139} 140 141/* Return the effective group id */ 142gid_t 143crgetgid(const cred_t *cr) 144{ 145 return (KGID_TO_SGID(cr->fsgid)); 146} 147 148/* Return the initial user ns or nop_mnt_idmap */ 149zidmap_t * 150zfs_get_init_idmap(void) 151{ 152#ifdef HAVE_IOPS_CREATE_IDMAP 153 return ((zidmap_t *)&nop_mnt_idmap); 154#else 155 return ((zidmap_t *)&init_user_ns); 156#endif 157} 158 159EXPORT_SYMBOL(zfs_get_init_idmap); 160EXPORT_SYMBOL(crhold); 161EXPORT_SYMBOL(crfree); 162EXPORT_SYMBOL(crgetuid); 163EXPORT_SYMBOL(crgetruid); 164EXPORT_SYMBOL(crgetgid); 165EXPORT_SYMBOL(crgetngroups); 166EXPORT_SYMBOL(crgetgroups); 167EXPORT_SYMBOL(groupmember); 168