Whamcloud - gitweb
Branch HEAD
[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 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/mm.h>
34 #include <linux/kmod.h>
35 #include <linux/string.h>
36 #include <linux/stat.h>
37 #include <linux/errno.h>
38 #include <linux/version.h>
39 #include <linux/unistd.h>
40 #include <asm/system.h>
41 #include <asm/uaccess.h>
42 #include <linux/fs.h>
43 #include <linux/stat.h>
44 #include <asm/uaccess.h>
45 #include <linux/slab.h>
46 #ifdef HAVE_SEGMENT_H
47 #include <asm/segment.h>
48 #endif
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 int mdt_init_idmap(struct mdt_thread_info *info)
64 {
65         struct ptlrpc_request *req = mdt_info_req(info);
66         char *client = libcfs_nid2str(req->rq_peer.nid);
67         struct mdt_export_data *med = mdt_req2med(req);
68         struct obd_device *obd = req->rq_export->exp_obd;
69         struct obd_connect_data *data, *reply;
70         int rc = 0, remote;
71         ENTRY;
72
73         data = req_capsule_client_get(info->mti_pill, &RMF_CONNECT_DATA);
74         reply = req_capsule_server_get(info->mti_pill, &RMF_CONNECT_DATA);
75         if (data == NULL || reply == NULL)
76                 RETURN(-EFAULT);
77
78         if (!req->rq_auth_gss || req->rq_auth_usr_mdt) {
79                 med->med_rmtclient = 0;
80                 reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
81                 RETURN(0);
82         }
83
84         remote = data->ocd_connect_flags & OBD_CONNECT_RMT_CLIENT;
85
86         if (remote) {
87                 med->med_rmtclient = 1;
88                 if (!req->rq_auth_remote)
89                         CWARN("client (local realm) %s -> target %s asked "
90                               "to be remote!\n", client, obd->obd_name);
91         } else if (req->rq_auth_remote) {
92                 med->med_rmtclient = 1;
93                 CWARN("client (remote realm) %s -> target %s forced "
94                       "to be remote!\n", client, obd->obd_name);
95         }
96
97         if (med->med_rmtclient) {
98                 down(&med->med_idmap_sem);
99                 if (!med->med_idmap)
100                         med->med_idmap = lustre_idmap_init();
101                 up(&med->med_idmap_sem);
102
103                 if (IS_ERR(med->med_idmap)) {
104                         long err = PTR_ERR(med->med_idmap);
105
106                         med->med_idmap = NULL;
107                         CERROR("client %s -> target %s "
108                                "failed to init idmap [%ld]!\n",
109                                client, obd->obd_name, err);
110                         RETURN(err);
111                 } else if (!med->med_idmap) {
112                         CERROR("client %s -> target %s "
113                                "failed to init(2) idmap!\n",
114                                client, obd->obd_name);
115                         RETURN(-ENOMEM);
116                 }
117
118                 reply->ocd_connect_flags &= ~OBD_CONNECT_LCL_CLIENT;
119                 CDEBUG(D_SEC, "client %s -> target %s is remote.\n",
120                        client, obd->obd_name);
121
122                 /* NB, MDS_CONNECT establish root idmap too! */
123                 rc = mdt_handle_idmap(info);
124         } else {
125                 if (req->rq_auth_uid == INVALID_UID) {
126                         CERROR("client %s -> target %s: user is not "
127                                "authenticated!\n", client, obd->obd_name);
128                         RETURN(-EACCES);
129                 }
130                 reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
131         }
132
133         RETURN(rc);
134 }
135
136 void mdt_cleanup_idmap(struct mdt_export_data *med)
137 {
138         LASSERT(med->med_rmtclient);
139
140         down(&med->med_idmap_sem);
141         if (med->med_idmap != NULL) {
142                 lustre_idmap_fini(med->med_idmap);
143         med->med_idmap = NULL;
144         }
145         up(&med->med_idmap_sem);
146 }
147
148 static inline void mdt_revoke_export_locks(struct obd_export *exp)
149 {
150         /* don't revoke locks during recovery */
151         if (exp->exp_obd->obd_recovering)
152                 return;
153
154         ldlm_revoke_export_locks(exp);
155 }
156
157 int mdt_handle_idmap(struct mdt_thread_info *info)
158 {
159         struct ptlrpc_request *req = mdt_info_req(info);
160         struct mdt_device *mdt = info->mti_mdt;
161         struct mdt_export_data *med;
162         struct ptlrpc_user_desc *pud = req->rq_user_desc;
163         struct md_identity *identity;
164         __u32 opc;
165         int rc = 0;
166         ENTRY;
167
168         if (!req->rq_export)
169                 RETURN(0);
170
171         med = mdt_req2med(req);
172         if (!med->med_rmtclient)
173                 RETURN(0);
174
175         opc = lustre_msg_get_opc(req->rq_reqmsg);
176         /* Bypass other opc */
177         if ((opc != SEC_CTX_INIT) && (opc != SEC_CTX_INIT_CONT) &&
178             (opc != SEC_CTX_FINI) && (opc != MDS_CONNECT))
179                 RETURN(0);
180
181         LASSERT(med->med_idmap);
182
183         if (unlikely(!pud)) {
184                 CERROR("remote client must run with rq_user_desc present\n");
185                 RETURN(-EACCES);
186         }
187
188         if (req->rq_auth_mapped_uid == INVALID_UID) {
189                 CERROR("invalid authorized mapped uid, please check "
190                        "/etc/lustre/idmap.conf!\n");
191                 RETURN(-EACCES);
192         }
193
194         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
195                 CERROR("remote client must run with identity_get enabled!\n");
196                 RETURN(-EACCES);
197         }
198
199         identity = mdt_identity_get(mdt->mdt_identity_cache,
200                                     req->rq_auth_mapped_uid);
201         if (!identity) {
202                 CERROR("can't get mdt identity(%u), no mapping added\n",
203                        req->rq_auth_mapped_uid);
204                 RETURN(-EACCES);
205         }
206
207         switch (opc) {
208         case SEC_CTX_INIT:
209         case SEC_CTX_INIT_CONT:
210         case MDS_CONNECT:
211                         rc = lustre_idmap_add(med->med_idmap,
212                                    pud->pud_uid, identity->mi_uid,
213                                    pud->pud_gid, identity->mi_gid);
214                 break;
215         case SEC_CTX_FINI:
216                         rc = lustre_idmap_del(med->med_idmap,
217                                    pud->pud_uid, identity->mi_uid,
218                                    pud->pud_gid, identity->mi_gid);
219                 break;
220         }
221
222         mdt_identity_put(mdt->mdt_identity_cache, identity);
223
224         if (rc)
225                 RETURN(rc);
226
227         switch (opc) {
228         case SEC_CTX_INIT:
229         case SEC_CTX_INIT_CONT:
230         case SEC_CTX_FINI:
231                 mdt_revoke_export_locks(req->rq_export);
232                 break;
233         }
234
235         RETURN(0);
236 }
237
238 int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req,
239                               struct ptlrpc_user_desc *pud)
240 {
241         struct mdt_export_data *med = mdt_req2med(req);
242         struct lustre_idmap_table *idmap = med->med_idmap;
243         uid_t uid, fsuid;
244         gid_t gid, fsgid;
245
246         /* Only remote client need desc_to_idmap. */
247         if (!med->med_rmtclient)
248                 return 0;
249
250         uid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_uid);
251         if (uid == CFS_IDMAP_NOTFOUND) {
252                 CERROR("no mapping for uid %u\n", pud->pud_uid);
253                 return -EACCES;
254         }
255
256         if (pud->pud_uid == pud->pud_fsuid) {
257                 fsuid = uid;
258         } else {
259                 fsuid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_fsuid);
260                 if (fsuid == CFS_IDMAP_NOTFOUND) {
261                         CERROR("no mapping for fsuid %u\n", pud->pud_fsuid);
262                         return -EACCES;
263                 }
264         }
265
266         gid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_gid);
267         if (gid == CFS_IDMAP_NOTFOUND) {
268                 CERROR("no mapping for gid %u\n", pud->pud_gid);
269                 return -EACCES;
270         }
271
272         if (pud->pud_gid == pud->pud_fsgid) {
273                 fsgid = gid;
274         } else {
275                 fsgid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_fsgid);
276                 if (fsgid == CFS_IDMAP_NOTFOUND) {
277                         CERROR("no mapping for fsgid %u\n", pud->pud_fsgid);
278                         return -EACCES;
279                 }
280         }
281
282         pud->pud_uid = uid;
283         pud->pud_gid = gid;
284         pud->pud_fsuid = fsuid;
285         pud->pud_fsgid = fsgid;
286
287         return 0;
288 }
289
290 /*
291  * Reverse mapping
292  */
293 void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body)
294 {
295         struct ptlrpc_request   *req = mdt_info_req(info);
296         struct md_ucred         *uc = mdt_ucred(info);
297         struct mdt_export_data  *med = mdt_req2med(req);
298         struct lustre_idmap_table *idmap = med->med_idmap;
299
300         if (!med->med_rmtclient)
301                 return;
302
303         if (body->valid & OBD_MD_FLUID) {
304                 uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 1, body->uid);
305
306                 if (uid == CFS_IDMAP_NOTFOUND) {
307                         uid = NOBODY_UID;
308                         if (body->valid & OBD_MD_FLMODE)
309                                 body->mode = (body->mode & ~S_IRWXU) |
310                                              ((body->mode & S_IRWXO) << 6);
311                 }
312
313                 body->uid = uid;
314         }
315
316         if (body->valid & OBD_MD_FLGID) {
317                 gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 1, body->gid);
318
319                 if (gid == CFS_IDMAP_NOTFOUND) {
320                         gid = NOBODY_GID;
321                         if (body->valid & OBD_MD_FLMODE)
322                                 body->mode = (body->mode & ~S_IRWXG) |
323                                              ((body->mode & S_IRWXO) << 3);
324                 }
325
326                 body->gid = gid;
327         }
328 }
329
330 /* Do not ignore root_squash for non-setattr case. */
331 int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
332 {
333         struct ptlrpc_request   *req = mdt_info_req(info);
334         struct md_ucred         *uc = mdt_ucred(info);
335         struct lu_attr          *attr = &info->mti_attr.ma_attr;
336         struct mdt_export_data  *med = mdt_req2med(req);
337         struct lustre_idmap_table *idmap = med->med_idmap;
338
339         if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW))
340                 return -EINVAL;
341
342         if (op != REINT_SETATTR) {
343                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1))
344                         attr->la_uid = uc->mu_fsuid;
345                 /* for S_ISGID, inherit gid from his parent, such work will be
346                  * done in cmm/mdd layer, here set all cases as uc->mu_fsgid. */
347                         if ((attr->la_valid & LA_GID) && (attr->la_gid != -1))
348                                 attr->la_gid = uc->mu_fsgid;
349         } else if (med->med_rmtclient) {
350                 /* NB: -1 case will be handled by mdt_fix_attr() later. */
351                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) {
352                         uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 0,
353                                                            attr->la_uid);
354
355                         if (uid == CFS_IDMAP_NOTFOUND) {
356                                 CWARN("Deny chown to uid %u\n", attr->la_uid);
357                                 return -EPERM;
358                         }
359
360                         attr->la_uid = uid;
361                 }
362                 if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) {
363                         gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 0,
364                                                            attr->la_gid);
365
366                         if (gid == CFS_IDMAP_NOTFOUND) {
367                                 CWARN("Deny chown to gid %u\n", attr->la_gid);
368                                 return -EPERM;
369                         }
370
371                         attr->la_gid = gid;
372                 }
373         }
374
375         return 0;
376 }