1 /* 2 * Copyright (C) 2008 Christoph Hellwig. 3 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include "xfs.h" 20 #include "xfs_format.h" 21 #include "xfs_log_format.h" 22 #include "xfs_trans_resv.h" 23 #include "xfs_mount.h" 24 #include "xfs_da_format.h" 25 #include "xfs_inode.h" 26 #include "xfs_attr.h" 27 #include "xfs_attr_leaf.h" 28 #include "xfs_acl.h" 29 30 #include <linux/posix_acl_xattr.h> 31 #include <linux/xattr.h> 32 33 34 static int 35 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 36 struct inode *inode, const char *name, void *value, size_t size) 37 { 38 int xflags = handler->flags; 39 struct xfs_inode *ip = XFS_I(inode); 40 int error, asize = size; 41 42 /* Convert Linux syscall to XFS internal ATTR flags */ 43 if (!size) { 44 xflags |= ATTR_KERNOVAL; 45 value = NULL; 46 } 47 48 error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); 49 if (error) 50 return error; 51 return asize; 52 } 53 54 void 55 xfs_forget_acl( 56 struct inode *inode, 57 const char *name, 58 int xflags) 59 { 60 /* 61 * Invalidate any cached ACLs if the user has bypassed the ACL 62 * interface. We don't validate the content whatsoever so it is caller 63 * responsibility to provide data in valid format and ensure i_mode is 64 * consistent. 65 */ 66 if (xflags & ATTR_ROOT) { 67 #ifdef CONFIG_XFS_POSIX_ACL 68 if (!strcmp(name, SGI_ACL_FILE)) 69 forget_cached_acl(inode, ACL_TYPE_ACCESS); 70 else if (!strcmp(name, SGI_ACL_DEFAULT)) 71 forget_cached_acl(inode, ACL_TYPE_DEFAULT); 72 #endif 73 } 74 } 75 76 static int 77 xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused, 78 struct inode *inode, const char *name, const void *value, 79 size_t size, int flags) 80 { 81 int xflags = handler->flags; 82 struct xfs_inode *ip = XFS_I(inode); 83 int error; 84 85 /* Convert Linux syscall to XFS internal ATTR flags */ 86 if (flags & XATTR_CREATE) 87 xflags |= ATTR_CREATE; 88 if (flags & XATTR_REPLACE) 89 xflags |= ATTR_REPLACE; 90 91 if (!value) 92 return xfs_attr_remove(ip, (unsigned char *)name, xflags); 93 error = xfs_attr_set(ip, (unsigned char *)name, 94 (void *)value, size, xflags); 95 if (!error) 96 xfs_forget_acl(inode, name, xflags); 97 98 return error; 99 } 100 101 static const struct xattr_handler xfs_xattr_user_handler = { 102 .prefix = XATTR_USER_PREFIX, 103 .flags = 0, /* no flags implies user namespace */ 104 .get = xfs_xattr_get, 105 .set = xfs_xattr_set, 106 }; 107 108 static const struct xattr_handler xfs_xattr_trusted_handler = { 109 .prefix = XATTR_TRUSTED_PREFIX, 110 .flags = ATTR_ROOT, 111 .get = xfs_xattr_get, 112 .set = xfs_xattr_set, 113 }; 114 115 static const struct xattr_handler xfs_xattr_security_handler = { 116 .prefix = XATTR_SECURITY_PREFIX, 117 .flags = ATTR_SECURE, 118 .get = xfs_xattr_get, 119 .set = xfs_xattr_set, 120 }; 121 122 const struct xattr_handler *xfs_xattr_handlers[] = { 123 &xfs_xattr_user_handler, 124 &xfs_xattr_trusted_handler, 125 &xfs_xattr_security_handler, 126 #ifdef CONFIG_XFS_POSIX_ACL 127 &posix_acl_access_xattr_handler, 128 &posix_acl_default_xattr_handler, 129 #endif 130 NULL 131 }; 132 133 static int 134 __xfs_xattr_put_listent( 135 struct xfs_attr_list_context *context, 136 char *prefix, 137 int prefix_len, 138 unsigned char *name, 139 int namelen) 140 { 141 char *offset; 142 int arraytop; 143 144 if (!context->alist) 145 goto compute_size; 146 147 arraytop = context->count + prefix_len + namelen + 1; 148 if (arraytop > context->firstu) { 149 context->count = -1; /* insufficient space */ 150 context->seen_enough = 1; 151 return 0; 152 } 153 offset = (char *)context->alist + context->count; 154 strncpy(offset, prefix, prefix_len); 155 offset += prefix_len; 156 strncpy(offset, (char *)name, namelen); /* real name */ 157 offset += namelen; 158 *offset = '\0'; 159 160 compute_size: 161 context->count += prefix_len + namelen + 1; 162 return 0; 163 } 164 165 static int 166 xfs_xattr_put_listent( 167 struct xfs_attr_list_context *context, 168 int flags, 169 unsigned char *name, 170 int namelen, 171 int valuelen) 172 { 173 char *prefix; 174 int prefix_len; 175 176 ASSERT(context->count >= 0); 177 178 if (flags & XFS_ATTR_ROOT) { 179 #ifdef CONFIG_XFS_POSIX_ACL 180 if (namelen == SGI_ACL_FILE_SIZE && 181 strncmp(name, SGI_ACL_FILE, 182 SGI_ACL_FILE_SIZE) == 0) { 183 int ret = __xfs_xattr_put_listent( 184 context, XATTR_SYSTEM_PREFIX, 185 XATTR_SYSTEM_PREFIX_LEN, 186 XATTR_POSIX_ACL_ACCESS, 187 strlen(XATTR_POSIX_ACL_ACCESS)); 188 if (ret) 189 return ret; 190 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 191 strncmp(name, SGI_ACL_DEFAULT, 192 SGI_ACL_DEFAULT_SIZE) == 0) { 193 int ret = __xfs_xattr_put_listent( 194 context, XATTR_SYSTEM_PREFIX, 195 XATTR_SYSTEM_PREFIX_LEN, 196 XATTR_POSIX_ACL_DEFAULT, 197 strlen(XATTR_POSIX_ACL_DEFAULT)); 198 if (ret) 199 return ret; 200 } 201 #endif 202 203 /* 204 * Only show root namespace entries if we are actually allowed to 205 * see them. 206 */ 207 if (!capable(CAP_SYS_ADMIN)) 208 return 0; 209 210 prefix = XATTR_TRUSTED_PREFIX; 211 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 212 } else if (flags & XFS_ATTR_SECURE) { 213 prefix = XATTR_SECURITY_PREFIX; 214 prefix_len = XATTR_SECURITY_PREFIX_LEN; 215 } else { 216 prefix = XATTR_USER_PREFIX; 217 prefix_len = XATTR_USER_PREFIX_LEN; 218 } 219 220 return __xfs_xattr_put_listent(context, prefix, prefix_len, name, 221 namelen); 222 } 223 224 ssize_t 225 xfs_vn_listxattr( 226 struct dentry *dentry, 227 char *data, 228 size_t size) 229 { 230 struct xfs_attr_list_context context; 231 struct attrlist_cursor_kern cursor = { 0 }; 232 struct inode *inode = d_inode(dentry); 233 int error; 234 235 /* 236 * First read the regular on-disk attributes. 237 */ 238 memset(&context, 0, sizeof(context)); 239 context.dp = XFS_I(inode); 240 context.cursor = &cursor; 241 context.resynch = 1; 242 context.alist = size ? data : NULL; 243 context.bufsize = size; 244 context.firstu = context.bufsize; 245 context.put_listent = xfs_xattr_put_listent; 246 247 error = xfs_attr_list_int(&context); 248 if (error) 249 return error; 250 if (context.count < 0) 251 return -ERANGE; 252 253 return context.count; 254 } 255