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(struct dentry *dentry, const char *name, 36 void *value, size_t size, int xflags) 37 { 38 struct xfs_inode *ip = XFS_I(dentry->d_inode); 39 int error, asize = size; 40 41 if (strcmp(name, "") == 0) 42 return -EINVAL; 43 44 /* Convert Linux syscall to XFS internal ATTR flags */ 45 if (!size) { 46 xflags |= ATTR_KERNOVAL; 47 value = NULL; 48 } 49 50 error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); 51 if (error) 52 return error; 53 return asize; 54 } 55 56 static int 57 xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, 58 size_t size, int flags, int xflags) 59 { 60 struct xfs_inode *ip = XFS_I(dentry->d_inode); 61 62 if (strcmp(name, "") == 0) 63 return -EINVAL; 64 65 /* Convert Linux syscall to XFS internal ATTR flags */ 66 if (flags & XATTR_CREATE) 67 xflags |= ATTR_CREATE; 68 if (flags & XATTR_REPLACE) 69 xflags |= ATTR_REPLACE; 70 71 if (!value) 72 return xfs_attr_remove(ip, (unsigned char *)name, xflags); 73 return xfs_attr_set(ip, (unsigned char *)name, 74 (void *)value, size, xflags); 75 } 76 77 static const struct xattr_handler xfs_xattr_user_handler = { 78 .prefix = XATTR_USER_PREFIX, 79 .flags = 0, /* no flags implies user namespace */ 80 .get = xfs_xattr_get, 81 .set = xfs_xattr_set, 82 }; 83 84 static const struct xattr_handler xfs_xattr_trusted_handler = { 85 .prefix = XATTR_TRUSTED_PREFIX, 86 .flags = ATTR_ROOT, 87 .get = xfs_xattr_get, 88 .set = xfs_xattr_set, 89 }; 90 91 static const struct xattr_handler xfs_xattr_security_handler = { 92 .prefix = XATTR_SECURITY_PREFIX, 93 .flags = ATTR_SECURE, 94 .get = xfs_xattr_get, 95 .set = xfs_xattr_set, 96 }; 97 98 const struct xattr_handler *xfs_xattr_handlers[] = { 99 &xfs_xattr_user_handler, 100 &xfs_xattr_trusted_handler, 101 &xfs_xattr_security_handler, 102 #ifdef CONFIG_XFS_POSIX_ACL 103 &posix_acl_access_xattr_handler, 104 &posix_acl_default_xattr_handler, 105 #endif 106 NULL 107 }; 108 109 static unsigned int xfs_xattr_prefix_len(int flags) 110 { 111 if (flags & XFS_ATTR_SECURE) 112 return sizeof("security"); 113 else if (flags & XFS_ATTR_ROOT) 114 return sizeof("trusted"); 115 else 116 return sizeof("user"); 117 } 118 119 static const char *xfs_xattr_prefix(int flags) 120 { 121 if (flags & XFS_ATTR_SECURE) 122 return xfs_xattr_security_handler.prefix; 123 else if (flags & XFS_ATTR_ROOT) 124 return xfs_xattr_trusted_handler.prefix; 125 else 126 return xfs_xattr_user_handler.prefix; 127 } 128 129 static int 130 xfs_xattr_put_listent( 131 struct xfs_attr_list_context *context, 132 int flags, 133 unsigned char *name, 134 int namelen, 135 int valuelen, 136 unsigned char *value) 137 { 138 unsigned int prefix_len = xfs_xattr_prefix_len(flags); 139 char *offset; 140 int arraytop; 141 142 ASSERT(context->count >= 0); 143 144 /* 145 * Only show root namespace entries if we are actually allowed to 146 * see them. 147 */ 148 if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN)) 149 return 0; 150 151 arraytop = context->count + prefix_len + namelen + 1; 152 if (arraytop > context->firstu) { 153 context->count = -1; /* insufficient space */ 154 return 1; 155 } 156 offset = (char *)context->alist + context->count; 157 strncpy(offset, xfs_xattr_prefix(flags), prefix_len); 158 offset += prefix_len; 159 strncpy(offset, (char *)name, namelen); /* real name */ 160 offset += namelen; 161 *offset = '\0'; 162 context->count += prefix_len + namelen + 1; 163 return 0; 164 } 165 166 static int 167 xfs_xattr_put_listent_sizes( 168 struct xfs_attr_list_context *context, 169 int flags, 170 unsigned char *name, 171 int namelen, 172 int valuelen, 173 unsigned char *value) 174 { 175 context->count += xfs_xattr_prefix_len(flags) + namelen + 1; 176 return 0; 177 } 178 179 static int 180 list_one_attr(const char *name, const size_t len, void *data, 181 size_t size, ssize_t *result) 182 { 183 char *p = data + *result; 184 185 *result += len; 186 if (!size) 187 return 0; 188 if (*result > size) 189 return -ERANGE; 190 191 strcpy(p, name); 192 return 0; 193 } 194 195 ssize_t 196 xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) 197 { 198 struct xfs_attr_list_context context; 199 struct attrlist_cursor_kern cursor = { 0 }; 200 struct inode *inode = dentry->d_inode; 201 int error; 202 203 /* 204 * First read the regular on-disk attributes. 205 */ 206 memset(&context, 0, sizeof(context)); 207 context.dp = XFS_I(inode); 208 context.cursor = &cursor; 209 context.resynch = 1; 210 context.alist = data; 211 context.bufsize = size; 212 context.firstu = context.bufsize; 213 214 if (size) 215 context.put_listent = xfs_xattr_put_listent; 216 else 217 context.put_listent = xfs_xattr_put_listent_sizes; 218 219 xfs_attr_list_int(&context); 220 if (context.count < 0) 221 return -ERANGE; 222 223 /* 224 * Then add the two synthetic ACL attributes. 225 */ 226 if (posix_acl_access_exists(inode)) { 227 error = list_one_attr(POSIX_ACL_XATTR_ACCESS, 228 strlen(POSIX_ACL_XATTR_ACCESS) + 1, 229 data, size, &context.count); 230 if (error) 231 return error; 232 } 233 234 if (posix_acl_default_exists(inode)) { 235 error = list_one_attr(POSIX_ACL_XATTR_DEFAULT, 236 strlen(POSIX_ACL_XATTR_DEFAULT) + 1, 237 data, size, &context.count); 238 if (error) 239 return error; 240 } 241 242 return context.count; 243 } 244