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 28 static int 29 cr_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 */ 55 void 56 crhold(cred_t *cr) 57 { 58 (void) get_cred((const cred_t *)cr); 59 } 60 61 /* Free a reference on the credential */ 62 void 63 crfree(cred_t *cr) 64 { 65 put_cred((const cred_t *)cr); 66 } 67 68 /* Return the number of supplemental groups */ 69 int 70 crgetngroups(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 */ 98 gid_t * 99 crgetgroups(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. */ 115 int 116 groupmember(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 */ 128 uid_t 129 crgetuid(const cred_t *cr) 130 { 131 return (KUID_TO_SUID(cr->fsuid)); 132 } 133 134 /* Return the real user id */ 135 uid_t 136 crgetruid(const cred_t *cr) 137 { 138 return (KUID_TO_SUID(cr->uid)); 139 } 140 141 /* Return the effective group id */ 142 gid_t 143 crgetgid(const cred_t *cr) 144 { 145 return (KGID_TO_SGID(cr->fsgid)); 146 } 147 148 /* Return the initial user ns or nop_mnt_idmap */ 149 zidmap_t * 150 zfs_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 159 EXPORT_SYMBOL(zfs_get_init_idmap); 160 EXPORT_SYMBOL(crhold); 161 EXPORT_SYMBOL(crfree); 162 EXPORT_SYMBOL(crgetuid); 163 EXPORT_SYMBOL(crgetruid); 164 EXPORT_SYMBOL(crgetgid); 165 EXPORT_SYMBOL(crgetngroups); 166 EXPORT_SYMBOL(crgetgroups); 167 EXPORT_SYMBOL(groupmember); 168