~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ocfs2/acl.c

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* -*- mode: c; c-basic-offset: 8; -*-
  2  * vim: noexpandtab sw=8 ts=8 sts=0:
  3  *
  4  * acl.c
  5  *
  6  * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
  7  *
  8  * CREDITS:
  9  * Lots of code in this file is copy from linux/fs/ext3/acl.c.
 10  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
 11  *
 12  * This program is free software; you can redistribute it and/or
 13  * modify it under the terms of the GNU General Public
 14  * License version 2 as published by the Free Software Foundation.
 15  *
 16  * This program is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19  * General Public License for more details.
 20  */
 21 
 22 #include <linux/init.h>
 23 #include <linux/module.h>
 24 #include <linux/slab.h>
 25 #include <linux/string.h>
 26 
 27 #include <cluster/masklog.h>
 28 
 29 #include "ocfs2.h"
 30 #include "alloc.h"
 31 #include "dlmglue.h"
 32 #include "file.h"
 33 #include "inode.h"
 34 #include "journal.h"
 35 #include "ocfs2_fs.h"
 36 
 37 #include "xattr.h"
 38 #include "acl.h"
 39 
 40 /*
 41  * Convert from xattr value to acl struct.
 42  */
 43 static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
 44 {
 45         int n, count;
 46         struct posix_acl *acl;
 47 
 48         if (!value)
 49                 return NULL;
 50         if (size < sizeof(struct posix_acl_entry))
 51                 return ERR_PTR(-EINVAL);
 52 
 53         count = size / sizeof(struct posix_acl_entry);
 54         if (count < 0)
 55                 return ERR_PTR(-EINVAL);
 56         if (count == 0)
 57                 return NULL;
 58 
 59         acl = posix_acl_alloc(count, GFP_NOFS);
 60         if (!acl)
 61                 return ERR_PTR(-ENOMEM);
 62         for (n = 0; n < count; n++) {
 63                 struct ocfs2_acl_entry *entry =
 64                         (struct ocfs2_acl_entry *)value;
 65 
 66                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
 67                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
 68                 switch(acl->a_entries[n].e_tag) {
 69                 case ACL_USER:
 70                         acl->a_entries[n].e_uid =
 71                                 make_kuid(&init_user_ns,
 72                                           le32_to_cpu(entry->e_id));
 73                         break;
 74                 case ACL_GROUP:
 75                         acl->a_entries[n].e_gid =
 76                                 make_kgid(&init_user_ns,
 77                                           le32_to_cpu(entry->e_id));
 78                         break;
 79                 default:
 80                         break;
 81                 }
 82                 value += sizeof(struct posix_acl_entry);
 83 
 84         }
 85         return acl;
 86 }
 87 
 88 /*
 89  * Convert acl struct to xattr value.
 90  */
 91 static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
 92 {
 93         struct ocfs2_acl_entry *entry = NULL;
 94         char *ocfs2_acl;
 95         size_t n;
 96 
 97         *size = acl->a_count * sizeof(struct posix_acl_entry);
 98 
 99         ocfs2_acl = kmalloc(*size, GFP_NOFS);
100         if (!ocfs2_acl)
101                 return ERR_PTR(-ENOMEM);
102 
103         entry = (struct ocfs2_acl_entry *)ocfs2_acl;
104         for (n = 0; n < acl->a_count; n++, entry++) {
105                 entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
106                 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
107                 switch(acl->a_entries[n].e_tag) {
108                 case ACL_USER:
109                         entry->e_id = cpu_to_le32(
110                                 from_kuid(&init_user_ns,
111                                           acl->a_entries[n].e_uid));
112                         break;
113                 case ACL_GROUP:
114                         entry->e_id = cpu_to_le32(
115                                 from_kgid(&init_user_ns,
116                                           acl->a_entries[n].e_gid));
117                         break;
118                 default:
119                         entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
120                         break;
121                 }
122         }
123         return ocfs2_acl;
124 }
125 
126 static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
127                                               int type,
128                                               struct buffer_head *di_bh)
129 {
130         int name_index;
131         char *value = NULL;
132         struct posix_acl *acl;
133         int retval;
134 
135         switch (type) {
136         case ACL_TYPE_ACCESS:
137                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
138                 break;
139         case ACL_TYPE_DEFAULT:
140                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
141                 break;
142         default:
143                 return ERR_PTR(-EINVAL);
144         }
145 
146         retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
147         if (retval > 0) {
148                 value = kmalloc(retval, GFP_NOFS);
149                 if (!value)
150                         return ERR_PTR(-ENOMEM);
151                 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
152                                                 "", value, retval);
153         }
154 
155         if (retval > 0)
156                 acl = ocfs2_acl_from_xattr(value, retval);
157         else if (retval == -ENODATA || retval == 0)
158                 acl = NULL;
159         else
160                 acl = ERR_PTR(retval);
161 
162         kfree(value);
163 
164         return acl;
165 }
166 
167 
168 /*
169  * Get posix acl.
170  */
171 static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type)
172 {
173         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
174         struct buffer_head *di_bh = NULL;
175         struct posix_acl *acl;
176         int ret;
177 
178         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
179                 return NULL;
180 
181         ret = ocfs2_inode_lock(inode, &di_bh, 0);
182         if (ret < 0) {
183                 mlog_errno(ret);
184                 acl = ERR_PTR(ret);
185                 return acl;
186         }
187 
188         acl = ocfs2_get_acl_nolock(inode, type, di_bh);
189 
190         ocfs2_inode_unlock(inode, 0);
191 
192         brelse(di_bh);
193 
194         return acl;
195 }
196 
197 /*
198  * Helper function to set i_mode in memory and disk. Some call paths
199  * will not have di_bh or a journal handle to pass, in which case it
200  * will create it's own.
201  */
202 static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
203                               handle_t *handle, umode_t new_mode)
204 {
205         int ret, commit_handle = 0;
206         struct ocfs2_dinode *di;
207 
208         if (di_bh == NULL) {
209                 ret = ocfs2_read_inode_block(inode, &di_bh);
210                 if (ret) {
211                         mlog_errno(ret);
212                         goto out;
213                 }
214         } else
215                 get_bh(di_bh);
216 
217         if (handle == NULL) {
218                 handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
219                                            OCFS2_INODE_UPDATE_CREDITS);
220                 if (IS_ERR(handle)) {
221                         ret = PTR_ERR(handle);
222                         mlog_errno(ret);
223                         goto out_brelse;
224                 }
225 
226                 commit_handle = 1;
227         }
228 
229         di = (struct ocfs2_dinode *)di_bh->b_data;
230         ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
231                                       OCFS2_JOURNAL_ACCESS_WRITE);
232         if (ret) {
233                 mlog_errno(ret);
234                 goto out_commit;
235         }
236 
237         inode->i_mode = new_mode;
238         inode->i_ctime = CURRENT_TIME;
239         di->i_mode = cpu_to_le16(inode->i_mode);
240         di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
241         di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
242 
243         ocfs2_journal_dirty(handle, di_bh);
244 
245 out_commit:
246         if (commit_handle)
247                 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
248 out_brelse:
249         brelse(di_bh);
250 out:
251         return ret;
252 }
253 
254 /*
255  * Set the access or default ACL of an inode.
256  */
257 static int ocfs2_set_acl(handle_t *handle,
258                          struct inode *inode,
259                          struct buffer_head *di_bh,
260                          int type,
261                          struct posix_acl *acl,
262                          struct ocfs2_alloc_context *meta_ac,
263                          struct ocfs2_alloc_context *data_ac)
264 {
265         int name_index;
266         void *value = NULL;
267         size_t size = 0;
268         int ret;
269 
270         if (S_ISLNK(inode->i_mode))
271                 return -EOPNOTSUPP;
272 
273         switch (type) {
274         case ACL_TYPE_ACCESS:
275                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
276                 if (acl) {
277                         umode_t mode;
278                         ret = posix_acl_update_mode(inode, &mode, &acl);
279                         if (ret)
280                                 return ret;
281                         ret = ocfs2_acl_set_mode(inode, di_bh,
282                                                  handle, mode);
283                         if (ret)
284                                 return ret;
285                 }
286                 break;
287         case ACL_TYPE_DEFAULT:
288                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
289                 if (!S_ISDIR(inode->i_mode))
290                         return acl ? -EACCES : 0;
291                 break;
292         default:
293                 return -EINVAL;
294         }
295 
296         if (acl) {
297                 value = ocfs2_acl_to_xattr(acl, &size);
298                 if (IS_ERR(value))
299                         return (int)PTR_ERR(value);
300         }
301 
302         if (handle)
303                 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
304                                              "", value, size, 0,
305                                              meta_ac, data_ac);
306         else
307                 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
308 
309         kfree(value);
310 
311         return ret;
312 }
313 
314 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
315 {
316         struct ocfs2_super *osb;
317         struct buffer_head *di_bh = NULL;
318         struct posix_acl *acl;
319         int ret = -EAGAIN;
320 
321         osb = OCFS2_SB(inode->i_sb);
322         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
323                 return NULL;
324 
325         ret = ocfs2_read_inode_block(inode, &di_bh);
326         if (ret < 0)
327                 return ERR_PTR(ret);
328 
329         acl = ocfs2_get_acl_nolock(inode, type, di_bh);
330 
331         brelse(di_bh);
332 
333         return acl;
334 }
335 
336 int ocfs2_acl_chmod(struct inode *inode)
337 {
338         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
339         struct posix_acl *acl;
340         int ret;
341 
342         if (S_ISLNK(inode->i_mode))
343                 return -EOPNOTSUPP;
344 
345         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
346                 return 0;
347 
348         acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS);
349         if (IS_ERR(acl) || !acl)
350                 return PTR_ERR(acl);
351         ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
352         if (ret)
353                 return ret;
354         ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
355                             acl, NULL, NULL);
356         posix_acl_release(acl);
357         return ret;
358 }
359 
360 /*
361  * Initialize the ACLs of a new inode. If parent directory has default ACL,
362  * then clone to new inode. Called from ocfs2_mknod.
363  */
364 int ocfs2_init_acl(handle_t *handle,
365                    struct inode *inode,
366                    struct inode *dir,
367                    struct buffer_head *di_bh,
368                    struct buffer_head *dir_bh,
369                    struct ocfs2_alloc_context *meta_ac,
370                    struct ocfs2_alloc_context *data_ac)
371 {
372         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
373         struct posix_acl *acl = NULL;
374         int ret = 0, ret2;
375         umode_t mode;
376 
377         if (!S_ISLNK(inode->i_mode)) {
378                 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
379                         acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
380                                                    dir_bh);
381                         if (IS_ERR(acl))
382                                 return PTR_ERR(acl);
383                 }
384                 if (!acl) {
385                         mode = inode->i_mode & ~current_umask();
386                         ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
387                         if (ret) {
388                                 mlog_errno(ret);
389                                 goto cleanup;
390                         }
391                 }
392         }
393         if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
394                 if (S_ISDIR(inode->i_mode)) {
395                         ret = ocfs2_set_acl(handle, inode, di_bh,
396                                             ACL_TYPE_DEFAULT, acl,
397                                             meta_ac, data_ac);
398                         if (ret)
399                                 goto cleanup;
400                 }
401                 mode = inode->i_mode;
402                 ret = posix_acl_create(&acl, GFP_NOFS, &mode);
403                 if (ret < 0)
404                         return ret;
405 
406                 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
407                 if (ret2) {
408                         mlog_errno(ret2);
409                         ret = ret2;
410                         goto cleanup;
411                 }
412                 if (ret > 0) {
413                         ret = ocfs2_set_acl(handle, inode,
414                                             di_bh, ACL_TYPE_ACCESS,
415                                             acl, meta_ac, data_ac);
416                 }
417         }
418 cleanup:
419         posix_acl_release(acl);
420         return ret;
421 }
422 
423 static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry,
424                                           char *list,
425                                           size_t list_len,
426                                           const char *name,
427                                           size_t name_len,
428                                           int type)
429 {
430         struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
431         const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
432 
433         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
434                 return 0;
435 
436         if (list && size <= list_len)
437                 memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
438         return size;
439 }
440 
441 static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry,
442                                            char *list,
443                                            size_t list_len,
444                                            const char *name,
445                                            size_t name_len,
446                                            int type)
447 {
448         struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
449         const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
450 
451         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
452                 return 0;
453 
454         if (list && size <= list_len)
455                 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
456         return size;
457 }
458 
459 static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name,
460                 void *buffer, size_t size, int type)
461 {
462         struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
463         struct posix_acl *acl;
464         int ret;
465 
466         if (strcmp(name, "") != 0)
467                 return -EINVAL;
468         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
469                 return -EOPNOTSUPP;
470 
471         acl = ocfs2_get_acl(dentry->d_inode, type);
472         if (IS_ERR(acl))
473                 return PTR_ERR(acl);
474         if (acl == NULL)
475                 return -ENODATA;
476         ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
477         posix_acl_release(acl);
478 
479         return ret;
480 }
481 
482 static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
483                 const void *value, size_t size, int flags, int type)
484 {
485         struct inode *inode = dentry->d_inode;
486         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
487         struct posix_acl *acl;
488         int ret = 0;
489 
490         if (strcmp(name, "") != 0)
491                 return -EINVAL;
492         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
493                 return -EOPNOTSUPP;
494 
495         if (!inode_owner_or_capable(inode))
496                 return -EPERM;
497 
498         if (value) {
499                 acl = posix_acl_from_xattr(&init_user_ns, value, size);
500                 if (IS_ERR(acl))
501                         return PTR_ERR(acl);
502                 else if (acl) {
503                         ret = posix_acl_valid(acl);
504                         if (ret)
505                                 goto cleanup;
506                 }
507         } else
508                 acl = NULL;
509 
510         ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL);
511 
512 cleanup:
513         posix_acl_release(acl);
514         return ret;
515 }
516 
517 const struct xattr_handler ocfs2_xattr_acl_access_handler = {
518         .prefix = POSIX_ACL_XATTR_ACCESS,
519         .flags  = ACL_TYPE_ACCESS,
520         .list   = ocfs2_xattr_list_acl_access,
521         .get    = ocfs2_xattr_get_acl,
522         .set    = ocfs2_xattr_set_acl,
523 };
524 
525 const struct xattr_handler ocfs2_xattr_acl_default_handler = {
526         .prefix = POSIX_ACL_XATTR_DEFAULT,
527         .flags  = ACL_TYPE_DEFAULT,
528         .list   = ocfs2_xattr_list_acl_default,
529         .get    = ocfs2_xattr_get_acl,
530         .set    = ocfs2_xattr_set_acl,
531 };
532 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp