4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/idmap.c
38 * Lustre user identity mapping.
40 * Author: Fan Yong <fanyong@clusterfs.com>
43 #define DEBUG_SUBSYSTEM S_SEC
45 #include <libcfs/lucache.h>
47 #include <lustre_idmap.h>
48 #include <md_object.h>
49 #include <obd_support.h>
51 #define lustre_get_group_info(group_info) do { \
52 atomic_inc(&(group_info)->usage); \
55 #define lustre_put_group_info(group_info) do { \
56 if (atomic_dec_and_test(&(group_info)->usage)) \
57 groups_free(group_info); \
61 * groups_search() is copied from linux kernel!
64 static int lustre_groups_search(struct group_info *group_info,
73 right = group_info->ngroups;
74 while (left < right) {
75 int mid = (left + right) / 2;
77 from_kgid(&init_user_ns, CFS_GROUP_AT(group_info, mid));
89 void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist)
92 int count = ginfo->ngroups;
94 /* fill group_info from gid array */
95 for (i = 0; i < ginfo->nblocks && count > 0; i++) {
96 int cp_count = min(CFS_NGROUPS_PER_BLOCK, count);
97 int off = i * CFS_NGROUPS_PER_BLOCK;
98 int len = cp_count * sizeof(*glist);
100 memcpy(ginfo->blocks[i], glist + off, len);
104 EXPORT_SYMBOL(lustre_groups_from_list);
106 /* groups_sort() is copied from linux kernel! */
107 /* a simple shell-metzner sort */
108 void lustre_groups_sort(struct group_info *group_info)
110 int base, max, stride;
111 int gidsetsize = group_info->ngroups;
113 for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
118 max = gidsetsize - stride;
119 for (base = 0; base < max; base++) {
121 int right = left + stride;
122 gid_t tmp = from_kgid(&init_user_ns,
123 CFS_GROUP_AT(group_info, right));
126 tmp < from_kgid(&init_user_ns,
127 CFS_GROUP_AT(group_info, left))) {
128 CFS_GROUP_AT(group_info, right) =
129 CFS_GROUP_AT(group_info, left);
133 CFS_GROUP_AT(group_info, right) =
134 make_kgid(&init_user_ns, tmp);
139 EXPORT_SYMBOL(lustre_groups_sort);
141 int lustre_in_group_p(struct lu_ucred *mu, gid_t grp)
145 if (grp != mu->uc_fsgid) {
146 struct group_info *group_info = NULL;
148 if (mu->uc_ginfo || !mu->uc_identity ||
149 mu->uc_valid == UCRED_OLD)
150 if (grp == mu->uc_suppgids[0] ||
151 grp == mu->uc_suppgids[1])
155 group_info = mu->uc_ginfo;
156 else if (mu->uc_identity)
157 group_info = mu->uc_identity->mi_ginfo;
162 lustre_get_group_info(group_info);
163 rc = lustre_groups_search(group_info, grp);
164 lustre_put_group_info(group_info);
168 EXPORT_SYMBOL(lustre_in_group_p);
170 struct lustre_idmap_entry {
171 cfs_list_t lie_rmt_uid_hash; /* hashed as lie_rmt_uid; */
172 cfs_list_t lie_lcl_uid_hash; /* hashed as lie_lcl_uid; */
173 cfs_list_t lie_rmt_gid_hash; /* hashed as lie_rmt_gid; */
174 cfs_list_t lie_lcl_gid_hash; /* hashed as lie_lcl_gid; */
175 uid_t lie_rmt_uid; /* remote uid */
176 uid_t lie_lcl_uid; /* local uid */
177 gid_t lie_rmt_gid; /* remote gid */
178 gid_t lie_lcl_gid; /* local gid */
181 static inline __u32 lustre_idmap_hashfunc(__u32 id)
183 return id & (CFS_IDMAP_HASHSIZE - 1);
187 struct lustre_idmap_entry *idmap_entry_alloc(uid_t rmt_uid, uid_t lcl_uid,
188 gid_t rmt_gid, gid_t lcl_gid)
190 struct lustre_idmap_entry *e;
196 CFS_INIT_LIST_HEAD(&e->lie_rmt_uid_hash);
197 CFS_INIT_LIST_HEAD(&e->lie_lcl_uid_hash);
198 CFS_INIT_LIST_HEAD(&e->lie_rmt_gid_hash);
199 CFS_INIT_LIST_HEAD(&e->lie_lcl_gid_hash);
200 e->lie_rmt_uid = rmt_uid;
201 e->lie_lcl_uid = lcl_uid;
202 e->lie_rmt_gid = rmt_gid;
203 e->lie_lcl_gid = lcl_gid;
208 static void idmap_entry_free(struct lustre_idmap_entry *e)
210 if (!cfs_list_empty(&e->lie_rmt_uid_hash))
211 cfs_list_del(&e->lie_rmt_uid_hash);
212 if (!cfs_list_empty(&e->lie_lcl_uid_hash))
213 cfs_list_del(&e->lie_lcl_uid_hash);
214 if (!cfs_list_empty(&e->lie_rmt_gid_hash))
215 cfs_list_del(&e->lie_rmt_gid_hash);
216 if (!cfs_list_empty(&e->lie_lcl_gid_hash))
217 cfs_list_del(&e->lie_lcl_gid_hash);
223 * NULL: not found entry
224 * ERR_PTR(-EACCES): found 1(remote):N(local) mapped entry
225 * others: found normal entry
228 struct lustre_idmap_entry *idmap_search_entry(struct lustre_idmap_table *t,
229 uid_t rmt_uid, uid_t lcl_uid,
230 gid_t rmt_gid, gid_t lcl_gid)
233 struct lustre_idmap_entry *e;
235 head = &t->lit_idmaps[RMT_UIDMAP_IDX][lustre_idmap_hashfunc(rmt_uid)];
236 cfs_list_for_each_entry(e, head, lie_rmt_uid_hash)
237 if (e->lie_rmt_uid == rmt_uid) {
238 if (e->lie_lcl_uid == lcl_uid) {
239 if (e->lie_rmt_gid == rmt_gid &&
240 e->lie_lcl_gid == lcl_gid)
241 /* must be quaternion match */
244 /* 1:N uid mapping */
245 CERROR("rmt uid %u already be mapped to %u"
246 " (new %u)\n", e->lie_rmt_uid,
247 e->lie_lcl_uid, lcl_uid);
248 return ERR_PTR(-EACCES);
252 head = &t->lit_idmaps[RMT_GIDMAP_IDX][lustre_idmap_hashfunc(rmt_gid)];
253 cfs_list_for_each_entry(e, head, lie_rmt_gid_hash)
254 if (e->lie_rmt_gid == rmt_gid) {
255 if (e->lie_lcl_gid == lcl_gid) {
256 if (unlikely(e->lie_rmt_uid == rmt_uid &&
257 e->lie_lcl_uid == lcl_uid))
258 /* after uid mapping search above,
259 * we should never come here */
262 /* 1:N gid mapping */
263 CERROR("rmt gid %u already be mapped to %u"
264 " (new %u)\n", e->lie_rmt_gid,
265 e->lie_lcl_gid, lcl_gid);
266 return ERR_PTR(-EACCES);
273 static __u32 idmap_lookup_uid(cfs_list_t *hash, int reverse,
276 cfs_list_t *head = &hash[lustre_idmap_hashfunc(uid)];
277 struct lustre_idmap_entry *e;
280 cfs_list_for_each_entry(e, head, lie_rmt_uid_hash)
281 if (e->lie_rmt_uid == uid)
282 return e->lie_lcl_uid;
284 cfs_list_for_each_entry(e, head, lie_lcl_uid_hash)
285 if (e->lie_lcl_uid == uid)
286 return e->lie_rmt_uid;
289 return CFS_IDMAP_NOTFOUND;
292 static __u32 idmap_lookup_gid(cfs_list_t *hash, int reverse, __u32 gid)
294 cfs_list_t *head = &hash[lustre_idmap_hashfunc(gid)];
295 struct lustre_idmap_entry *e;
298 cfs_list_for_each_entry(e, head, lie_rmt_gid_hash)
299 if (e->lie_rmt_gid == gid)
300 return e->lie_lcl_gid;
302 cfs_list_for_each_entry(e, head, lie_lcl_gid_hash)
303 if (e->lie_lcl_gid == gid)
304 return e->lie_rmt_gid;
307 return CFS_IDMAP_NOTFOUND;
310 int lustre_idmap_add(struct lustre_idmap_table *t,
311 uid_t ruid, uid_t luid,
312 gid_t rgid, gid_t lgid)
314 struct lustre_idmap_entry *e0, *e1;
318 spin_lock(&t->lit_lock);
319 e0 = idmap_search_entry(t, ruid, luid, rgid, lgid);
320 spin_unlock(&t->lit_lock);
322 e0 = idmap_entry_alloc(ruid, luid, rgid, lgid);
326 spin_lock(&t->lit_lock);
327 e1 = idmap_search_entry(t, ruid, luid, rgid, lgid);
329 cfs_list_add_tail(&e0->lie_rmt_uid_hash,
330 &t->lit_idmaps[RMT_UIDMAP_IDX]
331 [lustre_idmap_hashfunc(ruid)]);
332 cfs_list_add_tail(&e0->lie_lcl_uid_hash,
333 &t->lit_idmaps[LCL_UIDMAP_IDX]
334 [lustre_idmap_hashfunc(luid)]);
335 cfs_list_add_tail(&e0->lie_rmt_gid_hash,
336 &t->lit_idmaps[RMT_GIDMAP_IDX]
337 [lustre_idmap_hashfunc(rgid)]);
338 cfs_list_add_tail(&e0->lie_lcl_gid_hash,
339 &t->lit_idmaps[LCL_GIDMAP_IDX]
340 [lustre_idmap_hashfunc(lgid)]);
342 spin_unlock(&t->lit_lock);
344 idmap_entry_free(e0);
348 } else if (IS_ERR(e0)) {
354 EXPORT_SYMBOL(lustre_idmap_add);
356 int lustre_idmap_del(struct lustre_idmap_table *t,
357 uid_t ruid, uid_t luid,
358 gid_t rgid, gid_t lgid)
360 struct lustre_idmap_entry *e;
365 spin_lock(&t->lit_lock);
366 e = idmap_search_entry(t, ruid, luid, rgid, lgid);
371 spin_unlock(&t->lit_lock);
375 EXPORT_SYMBOL(lustre_idmap_del);
377 int lustre_idmap_lookup_uid(struct lu_ucred *mu,
378 struct lustre_idmap_table *t,
379 int reverse, uid_t uid)
383 if (mu && (mu->uc_valid == UCRED_OLD || mu->uc_valid == UCRED_NEW)) {
385 if (uid == mu->uc_o_uid)
387 else if (uid == mu->uc_o_fsuid)
390 if (uid == mu->uc_uid)
392 else if (uid == mu->uc_fsuid)
393 return mu->uc_o_fsuid;
398 return CFS_IDMAP_NOTFOUND;
400 hash = t->lit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX];
402 spin_lock(&t->lit_lock);
403 uid = idmap_lookup_uid(hash, reverse, uid);
404 spin_unlock(&t->lit_lock);
408 EXPORT_SYMBOL(lustre_idmap_lookup_uid);
410 int lustre_idmap_lookup_gid(struct lu_ucred *mu, struct lustre_idmap_table *t,
411 int reverse, gid_t gid)
415 if (mu && (mu->uc_valid == UCRED_OLD || mu->uc_valid == UCRED_NEW)) {
417 if (gid == mu->uc_o_gid)
419 else if (gid == mu->uc_o_fsgid)
422 if (gid == mu->uc_gid)
424 else if (gid == mu->uc_fsgid)
425 return mu->uc_o_fsgid;
430 return CFS_IDMAP_NOTFOUND;
432 hash = t->lit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX];
434 spin_lock(&t->lit_lock);
435 gid = idmap_lookup_gid(hash, reverse, gid);
436 spin_unlock(&t->lit_lock);
440 EXPORT_SYMBOL(lustre_idmap_lookup_gid);
442 struct lustre_idmap_table *lustre_idmap_init(void)
444 struct lustre_idmap_table *t;
448 if(unlikely(t == NULL))
449 return (ERR_PTR(-ENOMEM));
451 spin_lock_init(&t->lit_lock);
452 for (i = 0; i < ARRAY_SIZE(t->lit_idmaps); i++)
453 for (j = 0; j < ARRAY_SIZE(t->lit_idmaps[i]); j++)
454 CFS_INIT_LIST_HEAD(&t->lit_idmaps[i][j]);
458 EXPORT_SYMBOL(lustre_idmap_init);
460 void lustre_idmap_fini(struct lustre_idmap_table *t)
463 struct lustre_idmap_entry *e;
467 list = t->lit_idmaps[RMT_UIDMAP_IDX];
468 spin_lock(&t->lit_lock);
469 for (i = 0; i < CFS_IDMAP_HASHSIZE; i++)
470 while (!cfs_list_empty(&list[i])) {
471 e = cfs_list_entry(list[i].next,
472 struct lustre_idmap_entry,
476 spin_unlock(&t->lit_lock);
480 EXPORT_SYMBOL(lustre_idmap_fini);