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 35STATIC int xfs_cap_allow_set(xfs_vnode_t *); 36 37 38/* 39 * Test for existence of capability attribute as efficiently as possible. 40 */ 41int 42xfs_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 */ 56STATIC int 57posix_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 */ 85STATIC int 86posix_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 107int 108xfs_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); 135out: 136 VN_RELE(vp); 137 return -error; 138} 139 140int 141xfs_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 157int 158xfs_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); 181out: 182 VN_RELE(vp); 183 return -error; 184} 185 186STATIC int 187xfs_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 208