Whamcloud - gitweb
land b_colibri_devel on HEAD:
[fs/lustre-release.git] / lustre / mdd / mdd_permission.c
1 /* -*- MODE: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  mdd/mdd_handler.c
5  *  Lustre Metadata Server (mdd) routines
6  *
7  *  Copyright (C) 2006 Cluster File Systems, Inc.
8  *   Author: fangyong@clusterfs.com 
9  *           lsy@clusterfs.com
10  *   This file is part of the Lustre file system, http://www.lustre.org
11  *   Lustre is a trademark of Cluster File Systems, Inc.
12  *
13  *   You may have signed or agreed to another license before downloading
14  *   this software.  If so, you are bound by the terms and conditions
15  *   of that agreement, and the following does not apply to you.  See the
16  *   LICENSE file included with this distribution for more information.
17  *
18  *   If you did not agree to a different license, then this copy of Lustre
19  *   is open source software; you can redistribute it and/or modify it
20  *   under the terms of version 2 of the GNU General Public License as
21  *   published by the Free Software Foundation.
22  *
23  *   In either case, Lustre is distributed in the hope that it will be
24  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
25  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  *   license text for more details.
27  */
28 #ifndef EXPORT_SYMTAB
29 # define EXPORT_SYMTAB
30 #endif
31 #define DEBUG_SUBSYSTEM S_MDS
32
33 #include <linux/module.h>
34 #include <linux/jbd.h>
35 #include <obd.h>
36 #include <obd_class.h>
37 #include <lustre_ver.h>
38 #include <obd_support.h>
39 #include <lprocfs_status.h>
40
41 #include <linux/ldiskfs_fs.h>
42 #include <lustre_mds.h>
43 #include <lustre/lustre_idl.h>
44
45 #include "mdd_internal.h"
46
47 #ifdef CONFIG_FS_POSIX_ACL
48
49 /*
50  * Get default acl EA only.
51  * Hold read_lock for mdd_obj.
52  */
53 int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, 
54                     struct md_attr *ma)
55 {
56         struct lu_buf *buf;
57         int rc;
58         ENTRY;
59
60         if (ma->ma_valid & MA_ACL_DEF)
61                 RETURN(0);
62         
63         buf = mdd_buf_get(env, ma->ma_acl, ma->ma_acl_size);
64         rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_ACL_DEFAULT,
65                            BYPASS_CAPA);
66         if (rc > 0) {
67                 ma->ma_acl_size = rc;
68                 ma->ma_valid |= MA_ACL_DEF;
69                 rc = 0;
70         } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) {
71                 rc = 0;
72         }
73         RETURN(rc);
74 }
75
76 /*
77  * Hold write_lock for o.
78  */
79 int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, 
80                   struct thandle *handle)
81 {
82         struct lu_buf           *buf;
83         posix_acl_xattr_header  *head;
84         posix_acl_xattr_entry   *entry;
85         int                      entry_count;
86         int                      rc;
87
88         ENTRY;
89
90         buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, 
91                           sizeof(mdd_env_info(env)->mti_xattr_buf));
92         
93         rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA);
94         if ((rc == -EOPNOTSUPP) || (rc == -ENODATA))
95                 RETURN(0);
96         else if (rc <= 0)
97                 RETURN(rc);
98
99         buf->lb_len = rc;
100         head = (posix_acl_xattr_header *)(buf->lb_buf);
101         entry = head->a_entries;
102         entry_count = (buf->lb_len - sizeof(head->a_version)) /
103                       sizeof(posix_acl_xattr_entry);
104         if (entry_count <= 0)
105                 RETURN(0);
106        
107         rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count);
108         if (rc)
109                 RETURN(rc);
110
111         rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS,
112                            0, handle, BYPASS_CAPA);
113         RETURN(rc);
114 }
115
116 /*
117  * Hold write_lock for obj.
118  */
119 int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj,
120                    struct lu_buf *buf, __u32 *mode, struct thandle *handle)
121 {
122         posix_acl_xattr_header  *head;
123         posix_acl_xattr_entry   *entry;
124         int                      entry_count;
125         int                      rc;
126
127         ENTRY;
128
129         head = (posix_acl_xattr_header *)(buf->lb_buf);
130         entry = head->a_entries;
131         entry_count = (buf->lb_len - sizeof(head->a_version)) /
132                       sizeof(posix_acl_xattr_entry);
133         if (entry_count <= 0)
134                 RETURN(0);
135        
136         if (S_ISDIR(*mode)) {
137                 rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_DEFAULT, 0, 
138                                    handle, BYPASS_CAPA);
139                 if (rc)
140                         RETURN(rc);
141         }
142
143         rc = lustre_posix_acl_create_masq(entry, mode, entry_count);
144         if (rc <= 0)
145                 RETURN(rc);
146
147         rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, handle,
148                            BYPASS_CAPA);
149         RETURN(rc);
150 }
151
152 /*
153  * Hold read_lock for pobj.
154  * Hold write_lock for cobj.
155  */
156 int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj,
157                  struct mdd_object *cobj, __u32 *mode, struct thandle *handle)
158 {
159         struct lu_buf   *buf;
160         int             rc;
161         ENTRY;
162
163         if (S_ISLNK(*mode))
164                 RETURN(0);
165
166         buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, 
167                           sizeof(mdd_env_info(env)->mti_xattr_buf));
168         rc = mdo_xattr_get(env, pobj, buf, XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA);
169         if ((rc == -EOPNOTSUPP) || (rc == -ENODATA))
170                 RETURN(0);
171         else if (rc <= 0)
172                 RETURN(rc);
173
174         buf->lb_len = rc;
175         rc = __mdd_acl_init(env, cobj, buf, mode, handle);
176         RETURN(rc);
177 }
178 #endif
179
180 /*
181  * Hold read_lock for obj.
182  */
183 static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj,
184                          struct lu_attr *la, int mask)
185 {
186 #ifdef CONFIG_FS_POSIX_ACL
187         struct md_ucred  *uc  = md_ucred(env);
188         posix_acl_xattr_header *head;
189         posix_acl_xattr_entry *entry;
190         struct lu_buf   *buf;
191         int entry_count;
192         int rc;
193         ENTRY;
194
195         buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, 
196                           sizeof(mdd_env_info(env)->mti_xattr_buf));
197         rc = mdo_xattr_get(env, obj, buf, XATTR_NAME_ACL_ACCESS,
198                            mdd_object_capa(env, obj));
199         if (rc <= 0)
200                 RETURN(rc ? : -EACCES);
201
202         buf->lb_len = rc;
203         head = (posix_acl_xattr_header *)(buf->lb_buf);
204         entry = head->a_entries;
205         entry_count = (buf->lb_len - sizeof(head->a_version)) /
206                       sizeof(posix_acl_xattr_entry);
207
208         rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count);
209         RETURN(rc);
210 #else
211         ENTRY;
212         RETURN(-EAGAIN);
213 #endif
214 }
215
216 int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj,
217                               struct lu_attr *la, int mask, int needlock)
218 {
219         struct md_ucred *uc = md_ucred(env);
220         __u32 mode;
221         int rc;
222         ENTRY;
223
224         if (mask == 0)
225                 RETURN(0);
226
227         /* These means unnecessary for permission check */
228         if ((uc == NULL) || (uc->mu_valid == UCRED_INIT))
229                 RETURN(0);
230
231         /* Invalid user credit */
232         if (uc->mu_valid == UCRED_INVALID)
233                 RETURN(-EACCES);
234
235         /*
236          * Nobody gets write access to an immutable file.
237          */
238         if ((mask & MAY_WRITE) && mdd_is_immutable(obj))
239                 RETURN(-EACCES);
240
241         if (la == NULL) {
242                 la = &mdd_env_info(env)->mti_la;
243                 rc = mdd_la_get(env, obj, la, BYPASS_CAPA);
244                 if (rc)
245                         RETURN(rc);
246         }
247
248         mode = la->la_mode;
249         if (uc->mu_fsuid == la->la_uid) {
250                 mode >>= 6;
251         } else {
252                 if (mode & S_IRWXG) {
253                         if (needlock)
254                                 mdd_read_lock(env, obj);
255                         rc = mdd_check_acl(env, obj, la, mask);
256                         if (needlock)
257                                 mdd_read_unlock(env, obj);
258                         if (rc == -EACCES)
259                                 goto check_capabilities;
260                         else if ((rc != -EAGAIN) && (rc != -EOPNOTSUPP) &&
261                                  (rc != -ENODATA))
262                                 RETURN(rc);
263                 }
264                 if (lustre_in_group_p(uc, la->la_gid))
265                         mode >>= 3;
266         }
267
268         if (((mode & mask & S_IRWXO) == mask))
269                 RETURN(0);
270
271 check_capabilities:
272         if (!(mask & MAY_EXEC) ||
273             (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode))
274                 if (mdd_capable(uc, CAP_DAC_OVERRIDE))
275                         RETURN(0);
276
277         if ((mask == MAY_READ) ||
278             (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE)))
279                 if (mdd_capable(uc, CAP_DAC_READ_SEARCH))
280                         RETURN(0);
281
282         RETURN(-EACCES);
283 }
284
285 int mdd_permission(const struct lu_env *env, 
286                    struct md_object *pobj, struct md_object *cobj,
287                    struct md_attr *ma, int mask)
288 {
289         struct mdd_object *mdd_pobj, *mdd_cobj;
290         struct md_ucred *uc = NULL;
291         struct lu_attr *la = NULL;
292         int check_create, check_link;
293         int check_unlink;
294         int check_rename_src, check_rename_tar;
295         int check_vtx_part, check_vtx_full;
296         int check_rgetfacl;
297         int rc = 0;
298         ENTRY;
299
300         LASSERT(cobj);
301         mdd_cobj = md2mdd_obj(cobj);
302
303         /* For cross_open case, the "mask" is open flags,
304          * so convert it to permission mask first.
305          * XXX: MDS_OPEN_CROSS must be NOT equal to permission mask MAY_*. */
306         if (unlikely(mask & MDS_OPEN_CROSS)) {
307                 la = &mdd_env_info(env)->mti_la;
308                 rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
309                 if (rc)
310                         RETURN(rc);
311
312                 mask = accmode(env, la, mask & ~MDS_OPEN_CROSS);
313         }
314
315         check_create = mask & MAY_CREATE;
316         check_link = mask & MAY_LINK;
317         check_unlink = mask & MAY_UNLINK;
318         check_rename_src = mask & MAY_RENAME_SRC;
319         check_rename_tar = mask & MAY_RENAME_TAR;
320         check_vtx_part = mask & MAY_VTX_PART;
321         check_vtx_full = mask & MAY_VTX_FULL;
322         check_rgetfacl = mask & MAY_RGETFACL;
323
324         mask &= ~(MAY_CREATE | MAY_LINK |
325                 MAY_UNLINK |
326                 MAY_RENAME_SRC | MAY_RENAME_TAR |
327                 MAY_VTX_PART | MAY_VTX_FULL |
328                 MAY_RGETFACL);
329
330         rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask);
331
332         if (!rc && (check_create || check_link))
333                 rc = mdd_may_create(env, mdd_cobj, NULL, 1, check_link);
334
335         if (!rc && check_unlink) {
336                 LASSERT(ma);
337                 rc = mdd_may_unlink(env, mdd_cobj, ma);
338         }
339
340         if (!rc && (check_rename_src || check_rename_tar)) {
341                 LASSERT(pobj);
342                 LASSERT(ma);
343                 mdd_pobj = md2mdd_obj(pobj);
344                 rc = mdd_may_delete(env, mdd_pobj, mdd_cobj, ma, 1,
345                                     check_rename_tar);
346         }
347
348         if (!rc && (check_vtx_part || check_vtx_full)) {
349                 uc = md_ucred(env);
350                 LASSERT(ma);
351                 if (likely(!la)) {
352                         la = &mdd_env_info(env)->mti_la;
353                         rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
354                         if (rc)
355                                 RETURN(rc);
356                 }
357
358                 if (!(la->la_mode & S_ISVTX) || (la->la_uid == uc->mu_fsuid) ||
359                     (check_vtx_full && (ma->ma_attr.la_valid & LA_UID) &&
360                     (ma->ma_attr.la_uid == uc->mu_fsuid))) {
361                         ma->ma_attr_flags |= MDS_VTX_BYPASS;
362                 } else {
363                         ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
364                         if (check_vtx_full)
365                                 rc = -EPERM;
366                 }
367         }
368
369         if (unlikely(!rc && check_rgetfacl)) {
370                 if (likely(!uc))
371                         uc = md_ucred(env);
372
373                 if (likely(!la)) {
374                         la = &mdd_env_info(env)->mti_la;
375                         rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
376                         if (rc)
377                                 RETURN(rc);
378                 }
379
380                 if (la->la_uid != uc->mu_fsuid && !mdd_capable(uc, CAP_FOWNER))
381                         rc = -EPERM;
382         }
383
384         RETURN(rc);
385 }
386
387 int mdd_capa_get(const struct lu_env *env, struct md_object *obj,
388                  struct lustre_capa *capa, int renewal)
389 {
390         struct mdd_object *mdd_obj = md2mdd_obj(obj);
391         struct obd_capa *oc;
392         int rc = 0;
393         ENTRY;
394
395         oc = mdo_capa_get(env, mdd_obj, renewal ? capa : NULL,
396                           capa->lc_opc);
397         if (IS_ERR(oc)) {
398                 rc = PTR_ERR(oc);
399         } else {
400                 capa_cpy(capa, oc);
401                 capa_put(oc);
402         }
403
404         RETURN(rc);
405 }