Whamcloud - gitweb
567c88430b626503a66503c50d2b84e6b7c870b8
[fs/lustre-release.git] / lustre / mdt / mdt_idmap.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004-2006 Cluster File Systems, Inc.
5  *   Author: Lai Siyao <lsy@clusterfs.com>
6  *   Author: Fan Yong <fanyong@clusterfs.com>
7  *
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #ifndef EXPORT_SYMTAB
26 #define EXPORT_SYMTAB
27 #endif
28 #define DEBUG_SUBSYSTEM S_MDS
29
30 #ifndef AUTOCONF_INCLUDED
31 #include <linux/config.h>
32 #endif
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/mm.h>
36 #include <linux/kmod.h>
37 #include <linux/string.h>
38 #include <linux/stat.h>
39 #include <linux/errno.h>
40 #include <linux/version.h>
41 #include <linux/unistd.h>
42 #include <asm/system.h>
43 #include <asm/uaccess.h>
44 #include <linux/fs.h>
45 #include <linux/stat.h>
46 #include <asm/uaccess.h>
47 #include <linux/slab.h>
48 #include <asm/segment.h>
49
50 #include <libcfs/kp30.h>
51 #include <obd.h>
52 #include <obd_class.h>
53 #include <obd_support.h>
54 #include <lustre_net.h>
55 #include <lustre_import.h>
56 #include <lustre_dlm.h>
57 #include <lustre_sec.h>
58 #include <lustre_lib.h>
59 #include <lustre_ucache.h>
60
61 #include "mdt_internal.h"
62
63 enum {
64         MDT_IDMAP_NOTFOUND      = -1,
65 };
66
67 struct mdt_idmap_entry {
68         struct list_head mie_rmt_hash; /* hashed as mie_rmt_id; */
69         struct list_head mie_lcl_hash; /* hashed as mie_lcl_id; */
70         int              mie_refcount;
71         uid_t            mie_rmt_id;   /* remote uid/gid */
72         uid_t            mie_lcl_id;   /* local uid/gid */
73 };
74
75 /* uid/gid mapping */
76 static struct mdt_idmap_table *mdt_idmap_alloc(void)
77 {
78         struct mdt_idmap_table *tbl;
79         int i, j;
80
81         OBD_ALLOC_PTR(tbl);
82         if (!tbl)
83                 return NULL;
84
85         spin_lock_init(&tbl->mit_lock);
86         for (i = 0; i < ARRAY_SIZE(tbl->mit_idmaps); i++)
87                 for (j = 0; j < ARRAY_SIZE(tbl->mit_idmaps[i]); j++)
88                         INIT_LIST_HEAD(&tbl->mit_idmaps[i][j]);
89
90         return tbl;
91 }
92
93 static struct mdt_idmap_entry *idmap_entry_alloc(__u32 mie_rmt_id,
94                                                  __u32 mie_lcl_id)
95 {
96         struct mdt_idmap_entry *e;
97
98         OBD_ALLOC_PTR(e);
99         if (!e)
100                 return NULL;
101
102         INIT_LIST_HEAD(&e->mie_rmt_hash);
103         INIT_LIST_HEAD(&e->mie_lcl_hash);
104         e->mie_refcount = 1;
105         e->mie_rmt_id = mie_rmt_id;
106         e->mie_lcl_id = mie_lcl_id;
107
108         return e;
109 }
110
111 static void idmap_entry_free(struct mdt_idmap_entry *e)
112 {
113         if (!list_empty(&e->mie_rmt_hash))
114                 list_del(&e->mie_rmt_hash);
115         if (!list_empty(&e->mie_lcl_hash))
116                 list_del(&e->mie_lcl_hash);
117         OBD_FREE_PTR(e);
118 }
119
120 int mdt_init_idmap(struct mdt_thread_info *info)
121 {
122         struct ptlrpc_request *req = mdt_info_req(info);
123         char *client = libcfs_nid2str(req->rq_peer.nid);
124         struct mdt_export_data *med = mdt_req2med(req);
125         struct obd_device *obd = req->rq_export->exp_obd;
126         struct obd_connect_data *data, *reply;
127         int rc = 0, remote;
128         ENTRY;
129
130         data = req_capsule_client_get(&info->mti_pill, &RMF_CONNECT_DATA);
131         reply = req_capsule_server_get(&info->mti_pill, &RMF_CONNECT_DATA);
132         if (data == NULL || reply == NULL)
133                 RETURN(-EFAULT);
134
135         if (!req->rq_auth_gss || req->rq_auth_usr_mdt) {
136                 med->med_rmtclient = 0;
137                 reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
138                 //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
139                 RETURN(0);
140         }
141
142         remote = data->ocd_connect_flags & OBD_CONNECT_RMT_CLIENT;
143
144         if (remote) {
145                 med->med_rmtclient = 1;
146                 if (!req->rq_auth_remote)
147                         CWARN("client (local realm) %s -> target %s asked "
148                               "to be remote!\n", client, obd->obd_name);
149         } else if (req->rq_auth_remote) {
150                 med->med_rmtclient = 1;
151                 CWARN("client (remote realm) %s -> target %s forced "
152                       "to be remote!\n", client, obd->obd_name);
153         }
154
155         if (med->med_rmtclient) {
156                 med->med_nllu = data->ocd_nllu;
157                 med->med_nllg = data->ocd_nllg;
158                 if (!med->med_idmap)
159                         med->med_idmap = mdt_idmap_alloc();
160                 if (!med->med_idmap) {
161                         CERROR("client %s -> target %s failed to alloc idmap!\n"
162                                , client, obd->obd_name);
163                         RETURN(-ENOMEM);
164                 }
165
166                 reply->ocd_connect_flags &= ~OBD_CONNECT_LCL_CLIENT;
167                 //reply->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT;
168                 CDEBUG(D_SEC, "client %s -> target %s is remote.\n",
169                        client, obd->obd_name);
170
171                 /* NB, MDT_CONNECT establish root idmap too! */
172                 rc = mdt_handle_idmap(info);
173         } else {
174                 if (req->rq_auth_uid == INVALID_UID) {
175                         CERROR("client %s -> target %s: user is not "
176                                "authenticated!\n", client, obd->obd_name);
177                         RETURN(-EACCES);
178                 }
179                 reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
180                 //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
181         }
182
183         RETURN(rc);
184 }
185
186 static void idmap_clear_mie_rmt_hash(struct list_head *list)
187 {
188         struct mdt_idmap_entry *e;
189         int i;
190
191         for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) {
192                 while (!list_empty(&list[i])) {
193                         e = list_entry(list[i].next, struct mdt_idmap_entry,
194                                        mie_rmt_hash);
195                         idmap_entry_free(e);
196                 }
197         }
198 }
199
200 void mdt_cleanup_idmap(struct mdt_export_data *med)
201 {
202         struct mdt_idmap_table *tbl = med->med_idmap;
203         int i;
204
205         LASSERT(med->med_rmtclient);
206         LASSERT(tbl);
207
208         spin_lock(&tbl->mit_lock);
209         idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_UIDMAP_IDX]);
210         idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_GIDMAP_IDX]);
211
212         /* paranoid checking */
213         for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) {
214                 LASSERT(list_empty(&tbl->mit_idmaps[LCL_UIDMAP_IDX][i]));
215                 LASSERT(list_empty(&tbl->mit_idmaps[LCL_GIDMAP_IDX][i]));
216         }
217         spin_unlock(&tbl->mit_lock);
218
219         OBD_FREE_PTR(tbl);
220         med->med_idmap = NULL;
221 }
222
223 static inline void mdt_revoke_export_locks(struct obd_export *exp)
224 {
225         /* don't revoke locks during recovery */
226         if (exp->exp_obd->obd_recovering)
227                 return;
228
229         ldlm_revoke_export_locks(exp);
230 }
231
232 static
233 struct mdt_idmap_entry *idmap_lookup_entry(struct list_head *mie_rmt_hash,
234                                            uid_t mie_rmt_id, uid_t mie_lcl_id)
235 {
236         struct list_head *rmt_head =
237                          &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)];
238         struct mdt_idmap_entry *e;
239
240         list_for_each_entry(e, rmt_head, mie_rmt_hash) {
241                 if ((e->mie_rmt_id == mie_rmt_id) &&
242                     (e->mie_lcl_id == mie_lcl_id))
243                         return e;
244         }
245         return NULL;
246 }
247
248 /*
249  * return value
250  * NULL: not found entry
251  * ERR_PTR(-EACCES): found multi->single mapped entry
252  * others: found normal entry
253  */
254 static
255 struct mdt_idmap_entry *idmap_search_entry(struct list_head *mie_rmt_hash,
256                                            uid_t mie_rmt_id,
257                                            struct list_head *mie_lcl_hash,
258                                            uid_t mie_lcl_id,
259                                            const char *warn_msg)
260 {
261         struct list_head *rmt_head =
262                          &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)];
263         struct list_head *lcl_head =
264                          &mie_lcl_hash[MDT_IDMAP_HASHFUNC(mie_lcl_id)];
265         struct mdt_idmap_entry *e;
266
267         list_for_each_entry(e, rmt_head, mie_rmt_hash) {
268                 if (e->mie_rmt_id == mie_rmt_id) {
269                         if (e->mie_lcl_id == mie_lcl_id) {
270                                 e->mie_refcount++;
271                                 return e;
272                         } else {
273                                 CERROR("%s: rmt id %u already be mapped to %u"
274                                        " (new %u)\n", warn_msg, e->mie_rmt_id,
275                                        e->mie_lcl_id, mie_lcl_id);
276                                 return ERR_PTR(-EACCES);
277                         }
278                 }
279         }
280
281         list_for_each_entry(e, lcl_head, mie_lcl_hash) {
282                 if (e->mie_lcl_id == mie_lcl_id) {
283                         if (e->mie_rmt_id == mie_rmt_id) {
284                                 e->mie_refcount++;
285                                 return e;
286                         } else {
287                                 CERROR("%s: lcl id %u already be mapped from %u"
288                                        " (new %u)\n", warn_msg, e->mie_lcl_id,
289                                        e->mie_rmt_id, mie_rmt_id);
290                                 return ERR_PTR(-EACCES);
291                         }
292                 }
293         }
294
295         return NULL;
296 }
297
298 static
299 struct mdt_idmap_entry *idmap_insert_entry(struct list_head *mie_rmt_hash,
300                                            struct list_head *mie_lcl_hash,
301                                            struct mdt_idmap_entry *new,
302                                            const char *warn_msg)
303 {
304         struct list_head *rmt_head =
305                          &mie_rmt_hash[MDT_IDMAP_HASHFUNC(new->mie_rmt_id)];
306         struct list_head *lcl_head =
307                          &mie_lcl_hash[MDT_IDMAP_HASHFUNC(new->mie_lcl_id)];
308         struct mdt_idmap_entry *e;
309
310         e = idmap_search_entry(mie_rmt_hash, new->mie_rmt_id,
311                                mie_lcl_hash, new->mie_lcl_id,
312                                warn_msg);
313         if (e == NULL) {
314                 list_add_tail(&new->mie_rmt_hash, rmt_head);
315                 list_add_tail(&new->mie_lcl_hash, lcl_head);
316         }
317         return e;
318 }
319
320 static int idmap_remove_entry(struct list_head *mie_rmt_hash,
321                               struct list_head *mie_lcl_hash,
322                               __u32 mie_rmt_id, __u32 mie_lcl_id)
323 {
324         struct mdt_idmap_entry *e;
325         int rc = -ENOENT;
326
327         e = idmap_lookup_entry(mie_rmt_hash, mie_rmt_id, mie_lcl_id);
328         if (e != NULL) {
329                         e->mie_refcount--;
330                         if ((rc = e->mie_refcount) <= 0)
331                                 idmap_entry_free(e);
332         }
333         return rc;
334 }
335
336 static int mdt_idmap_add(struct mdt_idmap_table *tbl,
337                          uid_t ruid, uid_t luid,
338                          gid_t rgid, gid_t lgid)
339 {
340         struct mdt_idmap_entry *ue0, *ue1, *ge0, *ge1;
341         ENTRY;
342
343         LASSERT(tbl);
344
345         spin_lock(&tbl->mit_lock);
346         ue0 = idmap_search_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX], ruid,
347                                  tbl->mit_idmaps[LCL_UIDMAP_IDX], luid,
348                                  "UID mapping");
349         spin_unlock(&tbl->mit_lock);
350         if (!ue0) {
351                 ue0 = idmap_entry_alloc(ruid, luid);
352                 if (!ue0)
353                         RETURN(-ENOMEM);
354
355                 spin_lock(&tbl->mit_lock);
356                 ue1 = idmap_insert_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX],
357                                          tbl->mit_idmaps[LCL_UIDMAP_IDX],
358                                          ue0, "UID mapping");
359                 if (ue1 != NULL) {
360                         idmap_entry_free(ue0);
361                         ue0 = ue1;
362                 }
363                 spin_unlock(&tbl->mit_lock);
364
365                 if (IS_ERR(ue1))
366                         RETURN(PTR_ERR(ue1));
367         } else if (IS_ERR(ue0)) {
368                 RETURN(PTR_ERR(ue0));
369         }
370
371         spin_lock(&tbl->mit_lock);
372         ge0 = idmap_search_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX], rgid,
373                                  tbl->mit_idmaps[LCL_GIDMAP_IDX], lgid,
374                                  "GID mapping");
375         spin_unlock(&tbl->mit_lock);
376         if (!ge0) {
377                 ge0 = idmap_entry_alloc(rgid, lgid);
378                 spin_lock(&tbl->mit_lock);
379                 if (!ge0) {
380                         ue0->mie_refcount--;
381                         if (ue0->mie_refcount <= 0)
382                                 idmap_entry_free(ue0);
383                         spin_unlock(&tbl->mit_lock);
384                         RETURN(-ENOMEM);
385                 }
386
387                 ge1 = idmap_insert_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX],
388                                          tbl->mit_idmaps[LCL_GIDMAP_IDX],
389                                          ge0, "GID mapping");
390                 if (ge1 != NULL) {
391                         ue0->mie_refcount--;
392                         if (ue0->mie_refcount <= 0)
393                                 idmap_entry_free(ue0);
394                         idmap_entry_free(ge0);
395                 }
396                 spin_unlock(&tbl->mit_lock);
397
398                 if (IS_ERR(ge1))
399                         RETURN(PTR_ERR(ge1));
400         } else if (IS_ERR(ge0)) {
401                 spin_lock(&tbl->mit_lock);
402                 ue0->mie_refcount--;
403                 if (ue0->mie_refcount <= 0)
404                         idmap_entry_free(ue0);
405                 spin_unlock(&tbl->mit_lock);
406                 RETURN(PTR_ERR(ge0));
407         }
408
409         RETURN(0);
410 }
411
412 static int mdt_idmap_del(struct mdt_idmap_table *tbl,
413                          uid_t ruid, uid_t luid,
414                          gid_t rgid, gid_t lgid)
415 {
416         ENTRY;
417
418         if (!tbl)
419                 RETURN(0);
420
421         spin_lock(&tbl->mit_lock);
422         idmap_remove_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX],
423                            tbl->mit_idmaps[LCL_UIDMAP_IDX],
424                            ruid, luid);
425         idmap_remove_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX],
426                            tbl->mit_idmaps[LCL_GIDMAP_IDX],
427                            rgid, lgid);
428         spin_unlock(&tbl->mit_lock);
429
430         RETURN(0);
431 }
432
433 int mdt_handle_idmap(struct mdt_thread_info *info)
434 {
435         struct ptlrpc_request *req = mdt_info_req(info);
436         struct mdt_device *mdt = info->mti_mdt;
437         struct mdt_export_data *med;
438         struct ptlrpc_user_desc *pud = req->rq_user_desc;
439         struct mdt_identity *identity;
440         __u32 opc;
441         int rc = 0;
442
443         ENTRY;
444
445         if (!req->rq_export)
446                 RETURN(0);
447
448         med = mdt_req2med(req);
449         if (!med->med_rmtclient)
450                 RETURN(0);
451
452         opc = lustre_msg_get_opc(req->rq_reqmsg);
453         /* Bypass other opc */
454         if ((opc != SEC_CTX_INIT) && (opc != SEC_CTX_INIT_CONT) &&
455             (opc != SEC_CTX_FINI) && (opc != MDS_CONNECT))
456                 RETURN(0);
457
458         LASSERT(pud);
459         LASSERT(med->med_idmap);
460
461         if (req->rq_auth_mapped_uid == INVALID_UID) {
462                 CERROR("invalid authorized mapped uid, please check "
463                        "/etc/lustre/idmap.conf!\n");
464                 RETURN(-EACCES);
465         }
466
467         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
468                 CERROR("remote client must run with identity_get enabled!\n");
469                 RETURN(-EACCES);
470         }
471
472         identity = mdt_identity_get(mdt->mdt_identity_cache,
473                                     req->rq_auth_mapped_uid);
474         if (!identity) {
475                 CERROR("can't get mdt identity(%u), no mapping added\n",
476                        req->rq_auth_mapped_uid);
477                 RETURN(-EACCES);
478         }
479
480         switch (opc) {
481         case SEC_CTX_INIT:
482         case SEC_CTX_INIT_CONT:
483         case MDS_CONNECT:
484                 rc = mdt_idmap_add(med->med_idmap,
485                                    pud->pud_uid, identity->mi_uid,
486                                    pud->pud_gid, identity->mi_gid);
487                 break;
488         case SEC_CTX_FINI:
489                 rc = mdt_idmap_del(med->med_idmap,
490                                    pud->pud_uid, identity->mi_uid,
491                                    pud->pud_gid, identity->mi_gid);
492                 break;
493         }
494
495         mdt_identity_put(mdt->mdt_identity_cache, identity);
496
497         if (rc)
498                 RETURN(rc);
499
500         switch (opc) {
501         case SEC_CTX_INIT:
502         case SEC_CTX_INIT_CONT:
503         case SEC_CTX_FINI:
504                 mdt_revoke_export_locks(req->rq_export);
505                 break;
506         }
507         RETURN(0);
508 }
509
510 static __u32 idmap_lookup_id(struct list_head *hash, int reverse, __u32 id)
511 {
512         struct list_head *head = &hash[MDT_IDMAP_HASHFUNC(id)];
513         struct mdt_idmap_entry *e;
514
515         if (!reverse) {
516                 list_for_each_entry(e, head, mie_rmt_hash) {
517                         if (e->mie_rmt_id == id)
518                                 return e->mie_lcl_id;
519                 }
520         } else {
521                 list_for_each_entry(e, head, mie_lcl_hash) {
522                         if (e->mie_lcl_id == id)
523                                 return e->mie_rmt_id;
524                 }
525         }
526         return MDT_IDMAP_NOTFOUND;
527 }
528
529 static int mdt_idmap_lookup_uid(struct mdt_idmap_table *tbl, int reverse,
530                                 uid_t uid)
531 {
532         struct list_head *hash;
533
534         if (!tbl)
535                 return MDT_IDMAP_NOTFOUND;
536
537         hash = tbl->mit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX];
538
539         spin_lock(&tbl->mit_lock);
540         uid = idmap_lookup_id(hash, reverse, uid);
541         spin_unlock(&tbl->mit_lock);
542
543         return uid;
544 }
545
546 static int mdt_idmap_lookup_gid(struct mdt_idmap_table *tbl, int reverse,
547                                 gid_t gid)
548 {
549         struct list_head *hash;
550
551         if (!tbl)
552                 return MDT_IDMAP_NOTFOUND;
553
554         hash = tbl->mit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX];
555
556         spin_lock(&tbl->mit_lock);
557         gid = idmap_lookup_id(hash, reverse, gid);
558         spin_unlock(&tbl->mit_lock);
559
560         return gid;
561 }
562
563 int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req,
564                               struct ptlrpc_user_desc *pud)
565 {
566         struct mdt_export_data *med = mdt_req2med(req);
567         struct mdt_idmap_table *idmap = med->med_idmap;
568         uid_t uid, fsuid;
569         gid_t gid, fsgid;
570
571         /* Only remote client need desc_to_idmap. */
572         if (!med->med_rmtclient)
573                 return 0;
574
575         uid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_uid);
576         if (uid == MDT_IDMAP_NOTFOUND) {
577                 CERROR("no mapping for uid %u\n", pud->pud_uid);
578                 return -EACCES;
579         }
580
581         if (pud->pud_uid == pud->pud_fsuid) {
582                 fsuid = uid;
583         } else {
584                 fsuid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_fsuid);
585                 if (fsuid == MDT_IDMAP_NOTFOUND) {
586                         CERROR("no mapping for fsuid %u\n", pud->pud_fsuid);
587                         return -EACCES;
588                 }
589         }
590
591         gid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_gid);
592         if (gid == MDT_IDMAP_NOTFOUND) {
593                 CERROR("no mapping for gid %u\n", pud->pud_gid);
594                 return -EACCES;
595         }
596
597         if (pud->pud_gid == pud->pud_fsgid) {
598                 fsgid = gid;
599         } else {
600                 fsgid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_fsgid);
601                 if (fsgid == MDT_IDMAP_NOTFOUND) {
602                         CERROR("no mapping for fsgid %u\n", pud->pud_fsgid);
603                         return -EACCES;
604                 }
605         }
606
607         pud->pud_uid = uid;
608         pud->pud_gid = gid;
609         pud->pud_fsuid = fsuid;
610         pud->pud_fsgid = fsgid;
611
612         return 0;
613 }
614
615 /*
616  * Reverse map
617  * Do not ignore rootsquash.
618  */
619 void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body)
620 {
621         struct ptlrpc_request   *req = mdt_info_req(info);
622         struct md_ucred         *uc = mdt_ucred(info);
623         struct mdt_export_data  *med = mdt_req2med(req);
624         struct mdt_idmap_table  *idmap = med->med_idmap;
625         uid_t uid;
626         gid_t gid;
627
628         if (!med->med_rmtclient)
629                 return;
630
631         if (body->valid & OBD_MD_FLUID) {
632                 if (((uc->mu_valid == UCRED_OLD) ||
633                     (uc->mu_valid == UCRED_NEW)) &&
634                     !(uc->mu_squash & SQUASH_UID)) {
635                         if (body->uid == uc->mu_uid)
636                                 uid = uc->mu_o_uid;
637                         else if (body->uid == uc->mu_fsuid)
638                                 uid = uc->mu_o_fsuid;
639                         else
640                                 uid = mdt_idmap_lookup_uid(idmap, 1, body->uid);
641                 } else {
642                         uid = mdt_idmap_lookup_uid(idmap, 1, body->uid);
643                 }
644
645                 if (uid == MDT_IDMAP_NOTFOUND) {
646                         uid = med->med_nllu;
647                         if (body->valid & OBD_MD_FLMODE)
648                                 body->mode = (body->mode & ~S_IRWXU) |
649                                              ((body->mode & S_IRWXO) << 6);
650                 }
651
652                 body->uid = uid;
653         }
654
655         if (body->valid & OBD_MD_FLGID) {
656                 if (((uc->mu_valid == UCRED_OLD) ||
657                     (uc->mu_valid == UCRED_NEW)) &&
658                     !(uc->mu_squash & SQUASH_GID)) {
659                         if (body->gid == uc->mu_gid)
660                                 gid = uc->mu_o_gid;
661                         else if (body->gid == uc->mu_fsgid)
662                                 gid = uc->mu_o_fsgid;
663                         else
664                                 gid = mdt_idmap_lookup_gid(idmap, 1, body->gid);
665                 } else {
666                         gid = mdt_idmap_lookup_gid(idmap, 1, body->gid);
667                 }
668
669                 if (gid == MDT_IDMAP_NOTFOUND) {
670                         gid = med->med_nllg;
671                         if (body->valid & OBD_MD_FLMODE)
672                                 body->mode = (body->mode & ~S_IRWXG) |
673                                              ((body->mode & S_IRWXO) << 3);
674                 }
675
676                 body->gid = gid;
677         }
678 }
679
680 /* NB: return error if no mapping, so this will look strange:
681  * if client hasn't kinit the to map xid for the mapped xid, client
682  * will always get -EPERM, and the same for rootsquash case. */
683 int mdt_remote_perm_reverse_idmap(struct ptlrpc_request *req,
684                                   struct mdt_remote_perm *perm)
685 {
686         struct mdt_export_data *med = mdt_req2med(req);
687         uid_t uid, fsuid;
688         gid_t gid, fsgid;
689
690         LASSERT(med->med_rmtclient);
691
692         uid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_uid);
693         if (uid == MDT_IDMAP_NOTFOUND) {
694                 CERROR("no mapping for uid %u\n", perm->rp_uid);
695                 return -EPERM;
696         }
697
698         gid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_gid);
699         if (gid == MDT_IDMAP_NOTFOUND) {
700                 CERROR("no mapping for gid %u\n", perm->rp_gid);
701                 return -EPERM;
702         }
703
704         if (perm->rp_uid != perm->rp_fsuid) {
705                 fsuid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_fsuid);
706                 if (fsuid == MDT_IDMAP_NOTFOUND) {
707                         CERROR("no mapping for fsuid %u\n", perm->rp_fsuid);
708                         return -EPERM;
709                 }
710         } else {
711                 fsuid = uid;
712         }
713
714         if (perm->rp_gid != perm->rp_fsgid) {
715                 fsgid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_fsgid);
716                 if (fsgid == MDT_IDMAP_NOTFOUND) {
717                         CERROR("no mapping for fsgid %u\n", perm->rp_fsgid);
718                         return -EPERM;
719                 }
720         } else {
721                 fsgid = gid;
722         }
723
724         perm->rp_uid = uid;
725         perm->rp_gid = gid;
726         perm->rp_fsuid = fsuid;
727         perm->rp_fsgid = fsgid;
728         return 0;
729 }
730
731 /* Process remote client and rootsquash */
732 int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
733 {
734         struct ptlrpc_request   *req = mdt_info_req(info);
735         struct md_ucred         *uc = mdt_ucred(info);
736         struct lu_attr          *attr = &info->mti_attr.ma_attr;
737         struct mdt_export_data  *med = mdt_req2med(req);
738         struct mdt_idmap_table  *idmap = med->med_idmap;
739
740         ENTRY;
741
742         if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW))
743                 RETURN(-EINVAL);
744
745         if (!med->med_rmtclient && (uc->mu_squash == SQUASH_NONE))
746                 RETURN(0);
747
748         if (op != REINT_SETATTR) {
749                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1))
750                         attr->la_uid = uc->mu_fsuid;
751                 if (op != REINT_CREATE) {
752                         if ((attr->la_valid & LA_GID) && (attr->la_gid != -1))
753                                 attr->la_gid = uc->mu_fsgid;
754                 } else {
755                         /* for S_ISGID, inherit gid from his parent */
756                         if (!(attr->la_mode & S_ISGID) && (attr->la_gid != -1))
757                                 attr->la_gid = uc->mu_fsgid;
758                 }
759         } else if (med->med_rmtclient) {
760                 /* NB: -1 case will be handled by mdt_fix_attr() later. */
761                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) {
762                         uid_t uid;
763
764                         if (attr->la_uid == uc->mu_o_uid)
765                                 uid = uc->mu_uid;
766                         else if (attr->la_uid == uc->mu_o_fsuid)
767                                 uid = uc->mu_fsuid;
768                         else
769                                 uid = mdt_idmap_lookup_uid(idmap, 0,
770                                                            attr->la_uid);
771
772                         if (uid == MDT_IDMAP_NOTFOUND) {
773                                 CWARN("Deny chown to uid %u\n", attr->la_uid);
774                                 RETURN(-EPERM);
775                         }
776
777                         attr->la_uid = uid;
778                 }
779                 if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) {
780                         gid_t gid;
781
782                         if (attr->la_gid == uc->mu_o_gid)
783                                 gid = uc->mu_gid;
784                         else if (attr->la_gid == uc->mu_o_fsgid)
785                                 gid = uc->mu_fsgid;
786                         else
787                                 gid = mdt_idmap_lookup_gid(idmap, 0,
788                                                            attr->la_gid);
789
790                         if (gid == MDT_IDMAP_NOTFOUND) {
791                                 CWARN("Deny chown to gid %u\n", attr->la_gid);
792                                 RETURN(-EPERM);
793                         }
794
795                         attr->la_gid = gid;
796                 }
797         }
798
799         RETURN(0);
800 }