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