]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/gnu/fs/xfs/xfs_cap.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / gnu / fs / xfs / xfs_cap.c
1 /*
2  * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include "xfs.h"
34
35 STATIC int xfs_cap_allow_set(xfs_vnode_t *);
36
37
38 /*
39  * Test for existence of capability attribute as efficiently as possible.
40  */
41 int
42 xfs_cap_vhascap(
43         xfs_vnode_t     *vp)
44 {
45         int             error;
46         int             len = sizeof(xfs_cap_set_t);
47         int             flags = ATTR_KERNOVAL|ATTR_ROOT;
48
49         XVOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error);
50         return (error == 0);
51 }
52
53 /*
54  * Convert from extended attribute representation to in-memory for XFS.
55  */
56 STATIC int
57 posix_cap_xattr_to_xfs(
58         posix_cap_xattr         *src,
59         size_t                  size,
60         xfs_cap_set_t           *dest)
61 {
62         if (!src || !dest)
63                 return EINVAL;
64
65         if (src->c_version != cpu_to_le32(POSIX_CAP_XATTR_VERSION))
66                 return EINVAL;
67         if (src->c_abiversion != cpu_to_le32(_LINUX_CAPABILITY_VERSION))
68                 return EINVAL;
69
70         if (size < sizeof(posix_cap_xattr))
71                 return EINVAL;
72
73         ASSERT(sizeof(dest->cap_effective) == sizeof(src->c_effective));
74
75         dest->cap_effective     = src->c_effective;
76         dest->cap_permitted     = src->c_permitted;
77         dest->cap_inheritable   = src->c_inheritable;
78
79         return 0;
80 }
81
82 /*
83  * Convert from in-memory XFS to extended attribute representation.
84  */
85 STATIC int
86 posix_cap_xfs_to_xattr(
87         xfs_cap_set_t           *src,
88         posix_cap_xattr         *xattr_cap,
89         size_t                  size)
90 {
91         size_t                  new_size = posix_cap_xattr_size();
92
93         if (size < new_size)
94                 return -ERANGE;
95
96         ASSERT(sizeof(xattr_cap->c_effective) == sizeof(src->cap_effective));
97
98         xattr_cap->c_version    = cpu_to_le32(POSIX_CAP_XATTR_VERSION);
99         xattr_cap->c_abiversion = cpu_to_le32(_LINUX_CAPABILITY_VERSION);
100         xattr_cap->c_effective  = src->cap_effective;
101         xattr_cap->c_permitted  = src->cap_permitted;
102         xattr_cap->c_inheritable= src->cap_inheritable;
103
104         return new_size;
105 }
106
107 int
108 xfs_cap_vget(
109         xfs_vnode_t     *vp,
110         void            *cap,
111         size_t          size)
112 {
113         int             error;
114         int             len = sizeof(xfs_cap_set_t);
115         int             flags = ATTR_ROOT;
116         xfs_cap_set_t   xfs_cap = { 0 };
117         posix_cap_xattr *xattr_cap = cap;
118         char            *data = (char *)&xfs_cap;
119
120         VN_HOLD(vp);
121         if ((error = _MAC_VACCESS(vp, NULL, VREAD)))
122                 goto out;
123
124         if (!size) {
125                 flags |= ATTR_KERNOVAL;
126                 data = NULL;
127         }
128         XVOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error);
129         if (error)
130                 goto out;
131         ASSERT(len == sizeof(xfs_cap_set_t));
132
133         error = (size)? -posix_cap_xattr_size() :
134                         -posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size);
135 out:
136         VN_RELE(vp);
137         return -error;
138 }
139
140 int
141 xfs_cap_vremove(
142         xfs_vnode_t     *vp)
143 {
144         int             error;
145
146         VN_HOLD(vp);
147         error = xfs_cap_allow_set(vp);
148         if (!error) {
149                 XVOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error);
150                 if (error == ENOATTR)
151                         error = 0;      /* 'scool */
152         }
153         VN_RELE(vp);
154         return -error;
155 }
156
157 int
158 xfs_cap_vset(
159         xfs_vnode_t             *vp,
160         void                    *cap,
161         size_t                  size)
162 {
163         posix_cap_xattr         *xattr_cap = cap;
164         xfs_cap_set_t           xfs_cap;
165         int                     error;
166
167         if (!cap)
168                 return -EINVAL;
169
170         error = posix_cap_xattr_to_xfs(xattr_cap, size, &xfs_cap);
171         if (error)
172                 return -error;
173
174         VN_HOLD(vp);
175         error = xfs_cap_allow_set(vp);
176         if (error)
177                 goto out;
178
179         XVOP_ATTR_SET(vp, SGI_CAP_LINUX, (char *)&xfs_cap,
180                         sizeof(xfs_cap_set_t), ATTR_ROOT, sys_cred, error);
181 out:
182         VN_RELE(vp);
183         return -error;
184 }
185
186 STATIC int
187 xfs_cap_allow_set(
188         xfs_vnode_t     *vp)
189 {
190         vattr_t         va;
191         int             error;
192
193         if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
194                 return EROFS;
195         if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
196                 return EPERM;
197         if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
198                 return error;
199         va.va_mask = XFS_AT_UID;
200         XVOP_GETATTR(vp, &va, 0, NULL, error);
201         if (error)
202                 return error;
203         if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
204                 return EPERM;
205         return error;
206 }
207