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 return 0; 151 } 152 offset = (char *)context->alist + context->count; 153 strncpy(offset, prefix, prefix_len); 154 offset += prefix_len; 155 strncpy(offset, (char *)name, namelen); /* real name */ 156 offset += namelen; 157 *offset = '\0'; 158 159 compute_size: 160 context->count += prefix_len + namelen + 1; 161 return 0; 162 } 163 164 static int 165 xfs_xattr_put_listent( 166 struct xfs_attr_list_context *context, 167 int flags, 168 unsigned char *name, 169 int namelen, 170 int valuelen) 171 { 172 char *prefix; 173 int prefix_len; 174 175 ASSERT(context->count >= 0); 176 177 if (flags & XFS_ATTR_ROOT) { 178 #ifdef CONFIG_XFS_POSIX_ACL 179 if (namelen == SGI_ACL_FILE_SIZE && 180 strncmp(name, SGI_ACL_FILE, 181 SGI_ACL_FILE_SIZE) == 0) { 182 int ret = __xfs_xattr_put_listent( 183 context, XATTR_SYSTEM_PREFIX, 184 XATTR_SYSTEM_PREFIX_LEN, 185 XATTR_POSIX_ACL_ACCESS, 186 strlen(XATTR_POSIX_ACL_ACCESS)); 187 if (ret) 188 return ret; 189 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 190 strncmp(name, SGI_ACL_DEFAULT, 191 SGI_ACL_DEFAULT_SIZE) == 0) { 192 int ret = __xfs_xattr_put_listent( 193 context, XATTR_SYSTEM_PREFIX, 194 XATTR_SYSTEM_PREFIX_LEN, 195 XATTR_POSIX_ACL_DEFAULT, 196 strlen(XATTR_POSIX_ACL_DEFAULT)); 197 if (ret) 198 return ret; 199 } 200 #endif 201 202 /* 203 * Only show root namespace entries if we are actually allowed to 204 * see them. 205 */ 206 if (!capable(CAP_SYS_ADMIN)) 207 return 0; 208 209 prefix = XATTR_TRUSTED_PREFIX; 210 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 211 } else if (flags & XFS_ATTR_SECURE) { 212 prefix = XATTR_SECURITY_PREFIX; 213 prefix_len = XATTR_SECURITY_PREFIX_LEN; 214 } else { 215 prefix = XATTR_USER_PREFIX; 216 prefix_len = XATTR_USER_PREFIX_LEN; 217 } 218 219 return __xfs_xattr_put_listent(context, prefix, prefix_len, name, 220 namelen); 221 } 222 223 ssize_t 224 xfs_vn_listxattr( 225 struct dentry *dentry, 226 char *data, 227 size_t size) 228 { 229 struct xfs_attr_list_context context; 230 struct attrlist_cursor_kern cursor = { 0 }; 231 struct inode *inode = d_inode(dentry); 232 int error; 233 234 /* 235 * First read the regular on-disk attributes. 236 */ 237 memset(&context, 0, sizeof(context)); 238 context.dp = XFS_I(inode); 239 context.cursor = &cursor; 240 context.resynch = 1; 241 context.alist = size ? data : NULL; 242 context.bufsize = size; 243 context.firstu = context.bufsize; 244 context.put_listent = xfs_xattr_put_listent; 245 246 error = xfs_attr_list_int(&context); 247 if (error) 248 return error; 249 if (context.count < 0) 250 return -ERANGE; 251 252 return context.count; 253 } 254