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 *dentry, 36 const char *name, void *value, size_t size) 37 { 38 int xflags = handler->flags; 39 struct xfs_inode *ip = XFS_I(d_inode(dentry)); 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 *dentry, 78 const char *name, const void *value, size_t size, int flags) 79 { 80 int xflags = handler->flags; 81 struct xfs_inode *ip = XFS_I(d_inode(dentry)); 82 int error; 83 84 /* Convert Linux syscall to XFS internal ATTR flags */ 85 if (flags & XATTR_CREATE) 86 xflags |= ATTR_CREATE; 87 if (flags & XATTR_REPLACE) 88 xflags |= ATTR_REPLACE; 89 90 if (!value) 91 return xfs_attr_remove(ip, (unsigned char *)name, xflags); 92 error = xfs_attr_set(ip, (unsigned char *)name, 93 (void *)value, size, xflags); 94 if (!error) 95 xfs_forget_acl(d_inode(dentry), name, xflags); 96 97 return error; 98 } 99 100 static const struct xattr_handler xfs_xattr_user_handler = { 101 .prefix = XATTR_USER_PREFIX, 102 .flags = 0, /* no flags implies user namespace */ 103 .get = xfs_xattr_get, 104 .set = xfs_xattr_set, 105 }; 106 107 static const struct xattr_handler xfs_xattr_trusted_handler = { 108 .prefix = XATTR_TRUSTED_PREFIX, 109 .flags = ATTR_ROOT, 110 .get = xfs_xattr_get, 111 .set = xfs_xattr_set, 112 }; 113 114 static const struct xattr_handler xfs_xattr_security_handler = { 115 .prefix = XATTR_SECURITY_PREFIX, 116 .flags = ATTR_SECURE, 117 .get = xfs_xattr_get, 118 .set = xfs_xattr_set, 119 }; 120 121 const struct xattr_handler *xfs_xattr_handlers[] = { 122 &xfs_xattr_user_handler, 123 &xfs_xattr_trusted_handler, 124 &xfs_xattr_security_handler, 125 #ifdef CONFIG_XFS_POSIX_ACL 126 &posix_acl_access_xattr_handler, 127 &posix_acl_default_xattr_handler, 128 #endif 129 NULL 130 }; 131 132 static int 133 __xfs_xattr_put_listent( 134 struct xfs_attr_list_context *context, 135 char *prefix, 136 int prefix_len, 137 unsigned char *name, 138 int namelen) 139 { 140 char *offset; 141 int arraytop; 142 143 if (!context->alist) 144 goto compute_size; 145 146 arraytop = context->count + prefix_len + namelen + 1; 147 if (arraytop > context->firstu) { 148 context->count = -1; /* insufficient space */ 149 return 1; 150 } 151 offset = (char *)context->alist + context->count; 152 strncpy(offset, prefix, prefix_len); 153 offset += prefix_len; 154 strncpy(offset, (char *)name, namelen); /* real name */ 155 offset += namelen; 156 *offset = '\0'; 157 158 compute_size: 159 context->count += prefix_len + namelen + 1; 160 return 0; 161 } 162 163 static int 164 xfs_xattr_put_listent( 165 struct xfs_attr_list_context *context, 166 int flags, 167 unsigned char *name, 168 int namelen, 169 int valuelen, 170 unsigned char *value) 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(struct dentry *dentry, char *data, size_t size) 225 { 226 struct xfs_attr_list_context context; 227 struct attrlist_cursor_kern cursor = { 0 }; 228 struct inode *inode = d_inode(dentry); 229 230 /* 231 * First read the regular on-disk attributes. 232 */ 233 memset(&context, 0, sizeof(context)); 234 context.dp = XFS_I(inode); 235 context.cursor = &cursor; 236 context.resynch = 1; 237 context.alist = size ? data : NULL; 238 context.bufsize = size; 239 context.firstu = context.bufsize; 240 context.put_listent = xfs_xattr_put_listent; 241 242 xfs_attr_list_int(&context); 243 if (context.count < 0) 244 return -ERANGE; 245 246 return context.count; 247 } 248