]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/spl/spl-cred.c
Add basic credential support and splat tests.
[mirror_spl-debian.git] / module / spl / spl-cred.c
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2009 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * UCRL-CODE-235197
9 *
10 * This is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This 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 this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25 #include <sys/cred.h>
26
27 #ifdef DEBUG_SUBSYSTEM
28 #undef DEBUG_SUBSYSTEM
29 #endif
30
31 #define DEBUG_SUBSYSTEM S_CRED
32
33 #ifdef HAVE_GROUPS_SEARCH
34 /* Symbol may be exported by custom kernel patch */
35 #define cr_groups_search(gi, grp) groups_search(gi, grp)
36 #else
37 /* Implementation from 2.6.30 kernel */
38 static int
39 cr_groups_search(const struct group_info *group_info, gid_t grp)
40 {
41 unsigned int left, right;
42
43 if (!group_info)
44 return 0;
45
46 left = 0;
47 right = group_info->ngroups;
48 while (left < right) {
49 unsigned int mid = (left+right)/2;
50 int cmp = grp - GROUP_AT(group_info, mid);
51 if (cmp > 0)
52 left = mid + 1;
53 else if (cmp < 0)
54 right = mid;
55 else
56 return 1;
57 }
58 return 0;
59 }
60 #endif
61
62 #ifdef HAVE_CRED_STRUCT
63
64 /*
65 * As of 2.6.29 a clean credential API appears in the linux kernel.
66 * We attempt to layer the Solaris API on top of the linux API.
67 */
68
69 /* Hold a reference on the credential and group info */
70 void
71 crhold(cred_t *cr)
72 {
73 (void)get_cred((const cred_t *)cr);
74 (void)get_group_info(cr->group_info);
75 }
76
77 /* Free a reference on the credential and group info */
78 void
79 crfree(cred_t *cr)
80 {
81 put_group_info(cr->group_info);
82 put_cred((const cred_t *)cr);
83 }
84
85 /* Return the effective user id */
86 uid_t
87 crgetuid(const cred_t *cr)
88 {
89 return cr->euid;
90 }
91
92 /* Return the real user id */
93 uid_t
94 crgetruid(const cred_t *cr)
95 {
96 return cr->uid;
97 }
98
99 /* Return the saved user id */
100 uid_t
101 crgetsuid(const cred_t *cr)
102 {
103 return cr->suid;
104 }
105
106 /* Return the effective group id */
107 gid_t
108 crgetgid(const cred_t *cr)
109 {
110 return cr->egid;
111 }
112
113 /* Return the real group id */
114 gid_t
115 crgetrgid(const cred_t *cr)
116 {
117 return cr->gid;
118 }
119
120 /* Return the saved group id */
121 gid_t
122 crgetsgid(const cred_t *cr)
123 {
124 return cr->sgid;
125 }
126
127 /* Return the number of supplemental groups */
128 int
129 crgetngroups(const cred_t *cr)
130 {
131 struct group_info *gi;
132 int rc;
133
134 gi = get_group_info(cr->group_info);
135 rc = gi->ngroups;
136 put_group_info(gi);
137
138 return rc;
139 }
140
141 /*
142 * Return an array of supplemental gids. The returned address is safe
143 * to use as long as the caller has taken a reference with crhold().
144 * The caller is responsible for releasing the reference with crfree().
145 */
146 gid_t *
147 crgetgroups(const cred_t *cr)
148 {
149 struct group_info *gi;
150 gid_t *gids;
151
152 gi = get_group_info(cr->group_info);
153 gids = gi->blocks[0];
154 put_group_info(gi);
155
156 return gids;
157 }
158
159 /* Check if the passed gid is available is in supplied credential. */
160 int
161 groupmember(gid_t gid, const cred_t *cr)
162 {
163 struct group_info *gi;
164 int rc;
165
166 gi = get_group_info(cr->group_info);
167 rc = cr_groups_search(cr->group_info, gid);
168 put_group_info(gi);
169
170 return rc;
171 }
172
173 #else /* HAVE_CRED_STRUCT */
174
175 /*
176 * Until very recently all credential information was embedded in
177 * the linux task struct. For this reason to simulate a Solaris
178 * cred_t we need to pass the entire task structure around.
179 */
180
181 /* Hold a reference on the credential and group info */
182 void
183 crhold(cred_t *cr)
184 {
185 get_task_struct(cr);
186 }
187
188 /* Free a reference on the credential and group info */
189 void
190 crfree(cred_t *cr)
191 {
192 put_task_struct(cr);
193 }
194
195 /* Return the effective user id */
196 uid_t
197 crgetuid(const cred_t *cr) {
198 return cr->euid;
199 }
200
201 /* Return the effective real id */
202 uid_t
203 crgetruid(const cred_t *cr) {
204 return cr->uid;
205 }
206
207 /* Return the effective saved id */
208 uid_t
209 crgetsuid(const cred_t *cr) {
210 return cr->suid;
211 }
212
213 /* Return the effective group id */
214 gid_t
215 crgetgid(const cred_t *cr) {
216 return cr->egid;
217 }
218
219 /* Return the real group id */
220 gid_t
221 crgetrgid(const cred_t *cr) {
222 return cr->gid;
223 }
224
225 /* Return the saved group id */
226 gid_t
227 crgetsgid(const cred_t *cr) {
228 return cr->sgid;
229 }
230
231 /* Return the number of supplemental groups */
232 int
233 crgetngroups(const cred_t *cr)
234 {
235 int lock, rc;
236
237 lock = (cr != current);
238 if (lock)
239 task_lock((struct task_struct *)cr);
240
241 get_group_info(cr->group_info);
242 rc = cr->group_info->ngroups;
243 put_group_info(cr->group_info);
244
245 if (lock)
246 task_unlock((struct task_struct *)cr);
247
248 return rc;
249 }
250
251 /*
252 * Return an array of supplemental gids. The returned address is safe
253 * to use as long as the caller has taken a reference with crhold().
254 * The caller is responsible for releasing the reference with crfree().
255 */
256 gid_t *
257 crgetgroups(const cred_t *cr)
258 {
259 gid_t *gids;
260 int lock;
261
262 lock = (cr != current);
263 if (lock)
264 task_lock((struct task_struct *)cr);
265
266 get_group_info(cr->group_info);
267 gids = cr->group_info->blocks[0];
268 put_group_info(cr->group_info);
269
270 if (lock)
271 task_unlock((struct task_struct *)cr);
272
273 return gids;
274 }
275
276 /* Check if the passed gid is available is in supplied credential. */
277 int
278 groupmember(gid_t gid, const cred_t *cr)
279 {
280 int lock, rc;
281
282 lock = (cr != current);
283 if (lock)
284 task_lock((struct task_struct *)cr);
285
286 get_group_info(cr->group_info);
287 rc = cr_groups_search(cr->group_info, gid);
288 put_group_info(cr->group_info);
289
290 if (lock)
291 task_unlock((struct task_struct *)cr);
292
293 return rc;
294 }
295
296 #endif /* HAVE_CRED_STRUCT */
297
298 EXPORT_SYMBOL(crhold);
299 EXPORT_SYMBOL(crfree);
300 EXPORT_SYMBOL(crgetuid);
301 EXPORT_SYMBOL(crgetruid);
302 EXPORT_SYMBOL(crgetsuid);
303 EXPORT_SYMBOL(crgetgid);
304 EXPORT_SYMBOL(crgetrgid);
305 EXPORT_SYMBOL(crgetsgid);
306 EXPORT_SYMBOL(crgetngroups);
307 EXPORT_SYMBOL(crgetgroups);
308 EXPORT_SYMBOL(groupmember);