Whamcloud - gitweb
LU-5568 lnet: fix kernel crash when network failed to start
[fs/lustre-release.git] / lustre / mdt / mdt_idmap.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
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
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/mdt/mdt_idmap.c
37  *
38  * Author: Lai Siyao <lsy@clusterfs.com>
39  * Author: Fan Yong <fanyong@clusterfs.com>
40  */
41
42 #define DEBUG_SUBSYSTEM S_MDS
43
44 #include <linux/module.h>
45 #include <linux/kernel.h>
46 #include <linux/mm.h>
47 #include <linux/kmod.h>
48 #include <linux/string.h>
49 #include <linux/stat.h>
50 #include <linux/errno.h>
51 #include <linux/version.h>
52 #include <linux/unistd.h>
53 #include <asm/uaccess.h>
54 #include <linux/fs.h>
55 #include <linux/stat.h>
56 #include <asm/uaccess.h>
57 #include <linux/slab.h>
58
59 #include <libcfs/libcfs.h>
60 #include <libcfs/lucache.h>
61 #include <obd.h>
62 #include <obd_class.h>
63 #include <obd_support.h>
64 #include <lustre_net.h>
65 #include <lustre_import.h>
66 #include <lustre_dlm.h>
67 #include <lustre_sec.h>
68 #include <lustre_lib.h>
69
70 #include "mdt_internal.h"
71
72 int mdt_init_idmap(struct tgt_session_info *tsi)
73 {
74         struct ptlrpc_request   *req = tgt_ses_req(tsi);
75         struct mdt_export_data *med = mdt_req2med(req);
76         struct obd_export *exp = req->rq_export;
77         char *client = libcfs_nid2str(req->rq_peer.nid);
78         int rc = 0;
79         ENTRY;
80
81         if (exp_connect_rmtclient(exp)) {
82                 mutex_lock(&med->med_idmap_mutex);
83                 if (!med->med_idmap)
84                         med->med_idmap = lustre_idmap_init();
85                 mutex_unlock(&med->med_idmap_mutex);
86
87                 if (IS_ERR(med->med_idmap)) {
88                         long err = PTR_ERR(med->med_idmap);
89
90                         med->med_idmap = NULL;
91                         CERROR("%s: client %s -> target %s "
92                                "failed to init idmap [%ld]!\n",
93                                tgt_name(tsi->tsi_tgt), client,
94                                tgt_name(tsi->tsi_tgt), err);
95                         RETURN(err);
96                 } else if (!med->med_idmap) {
97                         CERROR("%s: client %s -> target %s "
98                                "failed to init(2) idmap!\n",
99                                tgt_name(tsi->tsi_tgt), client,
100                                tgt_name(tsi->tsi_tgt));
101                         RETURN(-ENOMEM);
102                 }
103
104                 CDEBUG(D_SEC, "%s: client %s -> target %s is remote.\n",
105                         tgt_name(tsi->tsi_tgt), client,
106                         tgt_name(tsi->tsi_tgt));
107                 /* NB, MDS_CONNECT establish root idmap too! */
108                 rc = mdt_handle_idmap(tsi);
109         }
110         RETURN(rc);
111 }
112
113 void mdt_cleanup_idmap(struct mdt_export_data *med)
114 {
115         mutex_lock(&med->med_idmap_mutex);
116         if (med->med_idmap != NULL) {
117                 lustre_idmap_fini(med->med_idmap);
118                 med->med_idmap = NULL;
119         }
120         mutex_unlock(&med->med_idmap_mutex);
121 }
122
123 static inline void mdt_revoke_export_locks(struct obd_export *exp)
124 {
125         /* don't revoke locks during recovery */
126         if (exp->exp_obd->obd_recovering)
127                 return;
128
129         ldlm_revoke_export_locks(exp);
130 }
131
132 int mdt_handle_idmap(struct tgt_session_info *tsi)
133 {
134         struct ptlrpc_request   *req = tgt_ses_req(tsi);
135         struct mdt_device       *mdt = mdt_exp2dev(req->rq_export);
136         struct mdt_export_data *med;
137         struct ptlrpc_user_desc *pud = req->rq_user_desc;
138         struct md_identity *identity;
139         __u32 opc;
140         int rc = 0;
141         ENTRY;
142
143         if (!req->rq_export)
144                 RETURN(0);
145
146         med = mdt_req2med(req);
147         if (!exp_connect_rmtclient(req->rq_export))
148                 RETURN(0);
149
150         opc = lustre_msg_get_opc(req->rq_reqmsg);
151         /* Bypass other opc */
152         if ((opc != SEC_CTX_INIT) && (opc != SEC_CTX_INIT_CONT) &&
153             (opc != SEC_CTX_FINI) && (opc != MDS_CONNECT))
154                 RETURN(0);
155
156         LASSERT(med->med_idmap);
157
158         if (unlikely(!pud)) {
159                 CDEBUG(D_SEC, "remote client must run with rq_user_desc "
160                        "present\n");
161                 RETURN(-EACCES);
162         }
163
164         if (!uid_valid(make_kuid(&init_user_ns, req->rq_auth_mapped_uid))) {
165                 CDEBUG(D_SEC, "invalid authorized mapped uid, please check "
166                        "/etc/lustre/idmap.conf!\n");
167                 RETURN(-EACCES);
168         }
169
170         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
171                 CDEBUG(D_SEC, "remote client must run with identity_get "
172                        "enabled!\n");
173                 RETURN(-EACCES);
174         }
175
176         identity = mdt_identity_get(mdt->mdt_identity_cache,
177                                     req->rq_auth_mapped_uid);
178         if (IS_ERR(identity)) {
179                 CDEBUG(D_SEC, "can't get mdt identity(%u), no mapping added\n",
180                        req->rq_auth_mapped_uid);
181                 RETURN(-EACCES);
182         }
183
184         switch (opc) {
185                 case SEC_CTX_INIT:
186                 case SEC_CTX_INIT_CONT:
187                 case MDS_CONNECT:
188                         rc = lustre_idmap_add(med->med_idmap,
189                                               pud->pud_uid, identity->mi_uid,
190                                               pud->pud_gid, identity->mi_gid);
191                         break;
192                 case SEC_CTX_FINI:
193                         rc = lustre_idmap_del(med->med_idmap,
194                                               pud->pud_uid, identity->mi_uid,
195                                               pud->pud_gid, identity->mi_gid);
196                         break;
197         }
198
199         mdt_identity_put(mdt->mdt_identity_cache, identity);
200
201         if (rc)
202                 RETURN(rc);
203
204         switch (opc) {
205                 case SEC_CTX_INIT:
206                 case SEC_CTX_INIT_CONT:
207                 case SEC_CTX_FINI:
208                         mdt_revoke_export_locks(req->rq_export);
209                         break;
210         }
211
212         RETURN(0);
213 }
214
215 int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req,
216                               struct ptlrpc_user_desc *pud)
217 {
218         struct mdt_export_data    *med = mdt_req2med(req);
219         struct lustre_idmap_table *idmap = med->med_idmap;
220         uid_t uid, fsuid;
221         gid_t gid, fsgid;
222
223         /* Only remote client need desc_to_idmap. */
224         if (!exp_connect_rmtclient(req->rq_export))
225                 return 0;
226
227         uid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_uid);
228         if (uid == CFS_IDMAP_NOTFOUND) {
229                 CDEBUG(D_SEC, "no mapping for uid %u\n", pud->pud_uid);
230                 return -EACCES;
231         }
232
233         if (pud->pud_uid == pud->pud_fsuid) {
234                 fsuid = uid;
235         } else {
236                 fsuid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_fsuid);
237                 if (fsuid == CFS_IDMAP_NOTFOUND) {
238                         CDEBUG(D_SEC, "no mapping for fsuid %u\n",
239                                pud->pud_fsuid);
240                         return -EACCES;
241                 }
242         }
243
244         gid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_gid);
245         if (gid == CFS_IDMAP_NOTFOUND) {
246                 CDEBUG(D_SEC, "no mapping for gid %u\n", pud->pud_gid);
247                 return -EACCES;
248         }
249
250         if (pud->pud_gid == pud->pud_fsgid) {
251                 fsgid = gid;
252         } else {
253                 fsgid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_fsgid);
254                 if (fsgid == CFS_IDMAP_NOTFOUND) {
255                         CDEBUG(D_SEC, "no mapping for fsgid %u\n",
256                                pud->pud_fsgid);
257                         return -EACCES;
258                 }
259         }
260
261         pud->pud_uid = uid;
262         pud->pud_gid = gid;
263         pud->pud_fsuid = fsuid;
264         pud->pud_fsgid = fsgid;
265
266         return 0;
267 }
268
269 /*
270  * Reverse mapping
271  */
272 void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body)
273 {
274         struct ptlrpc_request     *req = mdt_info_req(info);
275         struct lu_ucred           *uc = mdt_ucred(info);
276         struct mdt_export_data    *med = mdt_req2med(req);
277         struct lustre_idmap_table *idmap = med->med_idmap;
278
279         if (!exp_connect_rmtclient(info->mti_exp))
280                 return;
281
282         if (body->mbo_valid & OBD_MD_FLUID) {
283                 uid_t uid;
284
285                 uid = lustre_idmap_lookup_uid(uc, idmap, 1, body->mbo_uid);
286
287                 if (uid == CFS_IDMAP_NOTFOUND) {
288                         uid = NOBODY_UID;
289                         if (body->mbo_valid & OBD_MD_FLMODE)
290                                 body->mbo_mode = (body->mbo_mode & ~S_IRWXU) |
291                                              ((body->mbo_mode & S_IRWXO) << 6);
292                 }
293
294                 body->mbo_uid = uid;
295         }
296
297         if (body->mbo_valid & OBD_MD_FLGID) {
298                 gid_t gid;
299
300                 gid = lustre_idmap_lookup_gid(uc, idmap, 1, body->mbo_gid);
301
302                 if (gid == CFS_IDMAP_NOTFOUND) {
303                         gid = NOBODY_GID;
304                         if (body->mbo_valid & OBD_MD_FLMODE)
305                                 body->mbo_mode = (body->mbo_mode & ~S_IRWXG) |
306                                              ((body->mbo_mode & S_IRWXO) << 3);
307                 }
308
309                 body->mbo_gid = gid;
310         }
311 }
312
313 /* Do not ignore root_squash for non-setattr case. */
314 int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
315 {
316         struct ptlrpc_request     *req = mdt_info_req(info);
317         struct lu_ucred           *uc = mdt_ucred_check(info);
318         struct lu_attr            *attr = &info->mti_attr.ma_attr;
319         struct mdt_export_data    *med = mdt_req2med(req);
320         struct lustre_idmap_table *idmap = med->med_idmap;
321
322         if (uc == NULL)
323                 return -EINVAL;
324
325         if (op != REINT_SETATTR) {
326                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1))
327                         attr->la_uid = uc->uc_fsuid;
328                 /* for S_ISGID, inherit gid from his parent, such work will be
329                  * done in cmm/mdd layer, here set all cases as uc->uc_fsgid. */
330                 if ((attr->la_valid & LA_GID) && (attr->la_gid != -1))
331                         attr->la_gid = uc->uc_fsgid;
332         } else if (exp_connect_rmtclient(info->mti_exp)) {
333                 /* NB: -1 case will be handled by mdt_fix_attr() later. */
334                 if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) {
335                         uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 0,
336                                                             attr->la_uid);
337
338                         if (uid == CFS_IDMAP_NOTFOUND) {
339                                 CDEBUG(D_SEC, "Deny chown to uid %u\n",
340                                        attr->la_uid);
341                                 return -EPERM;
342                         }
343
344                         attr->la_uid = uid;
345                 }
346                 if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) {
347                         gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 0,
348                                                             attr->la_gid);
349
350                         if (gid == CFS_IDMAP_NOTFOUND) {
351                                 CDEBUG(D_SEC, "Deny chown to gid %u\n",
352                                        attr->la_gid);
353                                 return -EPERM;
354                         }
355
356                         attr->la_gid = gid;
357                 }
358         }
359
360         return 0;
361 }