462 lines
15 KiB
C
462 lines
15 KiB
C
#include <linux/fs.h>
|
|
#include <linux/xattr.h>
|
|
#include <linux/posix_acl_xattr.h>
|
|
|
|
#include "common/Common.h"
|
|
#include "FhgfsOpsInode.h"
|
|
#include "FhgfsOpsHelper.h"
|
|
|
|
#include "FhgfsXAttrHandlers.h"
|
|
#define FHGFS_XATTR_USER_PREFIX "user."
|
|
#define FHGFS_XATTR_SECURITY_PREFIX "security."
|
|
|
|
#ifdef KERNEL_HAS_GET_ACL
|
|
/**
|
|
* Called when an ACL Xattr is set. Responsible for setting the mode bits corresponding to the
|
|
* ACL mask.
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
#if defined(KERNEL_HAS_IDMAPPED_MOUNTS)
|
|
static int FhgfsXAttrSetACL(const struct xattr_handler* handler, struct mnt_idmap* id_map,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#elif defined(KERNEL_HAS_USER_NS_MOUNTS)
|
|
static int FhgfsXAttrSetACL(const struct xattr_handler* handler, struct user_namespace* mnt_userns,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#else
|
|
static int FhgfsXAttrSetACL(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, const void* value, size_t size, int flags)
|
|
#endif
|
|
{
|
|
int handler_flags = handler->flags;
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttrSetACL(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, const void* value, size_t size, int flags)
|
|
{
|
|
int handler_flags = handler->flags;
|
|
struct inode* inode = dentry->d_inode;
|
|
#else
|
|
static int FhgfsXAttrSetACL(struct dentry *dentry, const char *name, const void *value, size_t size,
|
|
int flags, int handler_flags)
|
|
{
|
|
struct inode* inode = dentry->d_inode;
|
|
#endif
|
|
char* attrName;
|
|
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__, "Called.");
|
|
|
|
// Enforce an empty name here (which means the name of the Xattr has to be
|
|
// fully given by the POSIX_ACL_XATTR_... defines)
|
|
if(strcmp(name, "") )
|
|
return -EINVAL;
|
|
|
|
if(!os_inode_owner_or_capable(inode) )
|
|
return -EPERM;
|
|
|
|
if(S_ISLNK(inode->i_mode) )
|
|
return -EOPNOTSUPP;
|
|
|
|
if(handler_flags == ACL_TYPE_ACCESS)
|
|
{
|
|
struct posix_acl* acl;
|
|
struct iattr attr;
|
|
int aclEquivRes;
|
|
int setAttrRes;
|
|
|
|
// if we set the access ACL, we also need to update the file mode permission bits.
|
|
attr.ia_mode = inode->i_mode;
|
|
attr.ia_valid = ATTR_MODE;
|
|
|
|
acl = os_posix_acl_from_xattr(value, size);
|
|
|
|
if(IS_ERR(acl) )
|
|
return PTR_ERR(acl);
|
|
|
|
aclEquivRes = posix_acl_equiv_mode(acl, &attr.ia_mode);
|
|
if(aclEquivRes == 0) // ACL can be exactly represented by file mode permission bits
|
|
{
|
|
value = NULL;
|
|
}
|
|
else if(aclEquivRes < 0)
|
|
{
|
|
posix_acl_release(acl);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if defined(KERNEL_HAS_IDMAPPED_MOUNTS)
|
|
setAttrRes = FhgfsOps_setattr(&nop_mnt_idmap, dentry, &attr);
|
|
#elif defined(KERNEL_HAS_USER_NS_MOUNTS)
|
|
setAttrRes = FhgfsOps_setattr(&init_user_ns, dentry, &attr);
|
|
#else
|
|
setAttrRes = FhgfsOps_setattr(dentry, &attr);
|
|
#endif
|
|
if(setAttrRes < 0)
|
|
return setAttrRes;
|
|
|
|
posix_acl_release(acl);
|
|
|
|
// Name of the Xattr to be set later
|
|
attrName = XATTR_NAME_POSIX_ACL_ACCESS;
|
|
}
|
|
else if(handler_flags == ACL_TYPE_DEFAULT)
|
|
{
|
|
// Note: The default acl is not reflected in any file mode permission bits.
|
|
// Just check for correctness here, and delete the xattr if the acl is empty.
|
|
struct posix_acl* acl;
|
|
acl = os_posix_acl_from_xattr(value, size);
|
|
|
|
if (IS_ERR(acl))
|
|
return PTR_ERR(acl);
|
|
|
|
if (acl == NULL)
|
|
value = NULL;
|
|
else
|
|
posix_acl_release(acl);
|
|
|
|
attrName = XATTR_NAME_POSIX_ACL_DEFAULT;
|
|
}
|
|
else
|
|
return -EOPNOTSUPP;
|
|
|
|
if(value)
|
|
return FhgfsOps_setxattr(dentry, attrName, value, size, flags);
|
|
else // value == NULL: Remove the ACL extended attribute.
|
|
{
|
|
int removeRes = FhgfsOps_removexattr(dentry, attrName);
|
|
if (removeRes == 0 || removeRes == -ENODATA) // If XA didn't exist anyway, return 0.
|
|
return 0;
|
|
else
|
|
return removeRes;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* The get-function of the xattr handler which handles the XATTR_NAME_POSIX_ACL_ACCESS and
|
|
* XATTR_NAME_POSIX_ACL_DEFAULT xattrs.
|
|
* @param name has to be a pointer to an empty string ("").
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
static int FhgfsXAttrGetACL(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, void* value, size_t size)
|
|
{
|
|
int handler_flags = handler->flags;
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttrGetACL(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, void* value, size_t size)
|
|
{
|
|
int handler_flags = handler->flags;
|
|
#else
|
|
int FhgfsXAttrGetACL(struct dentry* dentry, const char* name, void* value, size_t size,
|
|
int handler_flags)
|
|
{
|
|
#endif
|
|
char* attrName;
|
|
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__, "Called.");
|
|
|
|
// For simplicity we enforce an empty name here (which means the name of the Xattr has to be
|
|
// fully given by the POSIX_ACL_XATTR_... defines)
|
|
if(strcmp(name, "") )
|
|
return -EINVAL;
|
|
|
|
if(handler_flags == ACL_TYPE_ACCESS)
|
|
attrName = XATTR_NAME_POSIX_ACL_ACCESS;
|
|
else if(handler_flags == ACL_TYPE_DEFAULT)
|
|
attrName = XATTR_NAME_POSIX_ACL_DEFAULT;
|
|
else
|
|
return -EOPNOTSUPP;
|
|
|
|
return FhgfsOps_getxattr(dentry, attrName, value, size);
|
|
}
|
|
#endif // KERNEL_HAS_GET_ACL
|
|
|
|
/**
|
|
* The get-function which is used for all the user.* xattrs.
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
static int FhgfsXAttr_getUser(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, void* value, size_t size)
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttr_getUser(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, void* value, size_t size)
|
|
#elif defined(KERNEL_HAS_DENTRY_XATTR_HANDLER)
|
|
static int FhgfsXAttr_getUser(struct dentry* dentry, const char* name, void* value, size_t size,
|
|
int handler_flags)
|
|
#else
|
|
static int FhgfsXAttr_getUser(struct inode* inode, const char* name, void* value, size_t size)
|
|
#endif
|
|
{
|
|
FhgfsOpsErr res;
|
|
char* prefixedName = os_kmalloc(strlen(name) + sizeof(FHGFS_XATTR_USER_PREFIX) );
|
|
// Note: strlen does not count the terminating '\0', but sizeof does. So we have space for
|
|
// exactly one '\0' which coincidally is just what we need.
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__,
|
|
"(name: %s; size: %u)", name, size);
|
|
#else
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(inode->i_sb), NULL, inode, __func__,
|
|
"(name: %s; size: %u)", name, size);
|
|
#endif
|
|
|
|
// add name prefix which has been removed by the generic function
|
|
if(!prefixedName)
|
|
return -ENOMEM;
|
|
|
|
strcpy(prefixedName, FHGFS_XATTR_USER_PREFIX);
|
|
strcpy(prefixedName + sizeof(FHGFS_XATTR_USER_PREFIX) - 1, name); // sizeof-1 to remove the '\0'
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
res = FhgfsOps_getxattr(dentry, prefixedName, value, size);
|
|
#else
|
|
res = FhgfsOps_getxattr(inode, prefixedName, value, size);
|
|
#endif
|
|
|
|
kfree(prefixedName);
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* The set-function which is used for all the user.* xattrs.
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
|
|
#if defined(KERNEL_HAS_IDMAPPED_MOUNTS)
|
|
static int FhgfsXAttr_setUser(const struct xattr_handler* handler, struct mnt_idmap* id_map,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#elif defined(KERNEL_HAS_USER_NS_MOUNTS)
|
|
static int FhgfsXAttr_setUser(const struct xattr_handler* handler, struct user_namespace* mnt_userns,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#else
|
|
static int FhgfsXAttr_setUser(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, const void* value, size_t size, int flags)
|
|
#endif
|
|
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttr_setUser(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, const void* value, size_t size, int flags)
|
|
#elif defined(KERNEL_HAS_DENTRY_XATTR_HANDLER)
|
|
static int FhgfsXAttr_setUser(struct dentry* dentry, const char* name, const void* value, size_t size,
|
|
int flags, int handler_flags)
|
|
#endif // KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
{
|
|
FhgfsOpsErr res;
|
|
char* prefixedName = os_kmalloc(strlen(name) + sizeof(FHGFS_XATTR_USER_PREFIX) );
|
|
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__,
|
|
"(name: %s)", name);
|
|
#else
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(inode->i_sb), NULL, inode, __func__,
|
|
"(name: %s)", name);
|
|
#endif // KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
|
|
// add name prefix which has been removed by the generic function
|
|
if(!prefixedName)
|
|
return -ENOMEM;
|
|
strcpy(prefixedName, FHGFS_XATTR_USER_PREFIX);
|
|
strcpy(prefixedName + sizeof(FHGFS_XATTR_USER_PREFIX) - 1, name); // sizeof-1 to remove the '\0'
|
|
|
|
if (value)
|
|
{
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
res = FhgfsOps_setxattr(dentry, prefixedName, value, size, flags);
|
|
#else
|
|
res = FhgfsOps_setxattr(inode, prefixedName, value, size, flags);
|
|
#endif // KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
}
|
|
else
|
|
{
|
|
res = FhgfsOps_removexattr(dentry, prefixedName);
|
|
}
|
|
|
|
kfree(prefixedName);
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* The get-function which is used for all the security.* xattrs.
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
static int FhgfsXAttr_getSecurity(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, void* value, size_t size)
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttr_getSecurity(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, void* value, size_t size)
|
|
#elif defined(KERNEL_HAS_DENTRY_XATTR_HANDLER)
|
|
static int FhgfsXAttr_getSecurity(struct dentry* dentry, const char* name, void* value, size_t size,
|
|
int handler_flags)
|
|
#else
|
|
static int FhgfsXAttr_getSecurity(struct inode* inode, const char* name, void* value, size_t size)
|
|
#endif
|
|
{
|
|
FhgfsOpsErr res;
|
|
char* prefixedName = os_kmalloc(strlen(name) + sizeof(FHGFS_XATTR_SECURITY_PREFIX) );
|
|
// Note: strlen does not count the terminating '\0', but sizeof does. So we have space for
|
|
// exactly one '\0' which coincidally is just what we need.
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__,
|
|
"(name: %s; size: %u)", name, size);
|
|
#else
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(inode->i_sb), NULL, inode, __func__,
|
|
"(name: %s; size: %u)", name, size);
|
|
#endif // KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
|
|
// add name prefix which has been removed by the generic function
|
|
if(!prefixedName)
|
|
return -ENOMEM;
|
|
|
|
strcpy(prefixedName, FHGFS_XATTR_SECURITY_PREFIX);
|
|
strcpy(prefixedName + sizeof(FHGFS_XATTR_SECURITY_PREFIX) - 1, name); // sizeof-1 to remove '\0'
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
res = FhgfsOps_getxattr(dentry, prefixedName, value, size);
|
|
#else
|
|
res = FhgfsOps_getxattr(inode, prefixedName, value, size);
|
|
#endif // KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
|
|
kfree(prefixedName);
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* The set-function which is used for all the security.* xattrs.
|
|
*/
|
|
#if defined(KERNEL_HAS_XATTR_HANDLERS_INODE_ARG)
|
|
#if defined(KERNEL_HAS_IDMAPPED_MOUNTS)
|
|
static int FhgfsXAttr_setSecurity(const struct xattr_handler* handler, struct mnt_idmap* idmap,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#elif defined(KERNEL_HAS_USER_NS_MOUNTS)
|
|
static int FhgfsXAttr_setSecurity(const struct xattr_handler* handler, struct user_namespace* mnt_userns,
|
|
struct dentry* dentry, struct inode* inode, const char* name, const void* value, size_t size,
|
|
int flags)
|
|
#else
|
|
static int FhgfsXAttr_setSecurity(const struct xattr_handler* handler, struct dentry* dentry,
|
|
struct inode* inode, const char* name, const void* value, size_t size, int flags)
|
|
#endif
|
|
#elif defined(KERNEL_HAS_XATTR_HANDLER_PTR_ARG)
|
|
static int FhgfsXAttr_setSecurity(const struct xattr_handler* handler, struct dentry* dentry,
|
|
const char* name, const void* value, size_t size, int flags)
|
|
#elif defined(KERNEL_HAS_DENTRY_XATTR_HANDLER)
|
|
static int FhgfsXAttr_setSecurity(struct dentry* dentry, const char* name, const void* value, size_t size,
|
|
int flags, int handler_flags)
|
|
#endif
|
|
{
|
|
FhgfsOpsErr res;
|
|
char* prefixedName = os_kmalloc(strlen(name) + sizeof(FHGFS_XATTR_SECURITY_PREFIX) );
|
|
|
|
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(dentry->d_sb), dentry, NULL, __func__,
|
|
"(name: %s)", name);
|
|
#else
|
|
FhgfsOpsHelper_logOpDebug(FhgfsOps_getApp(inode->i_sb), NULL, inode, __func__,
|
|
"(name: %s)", name);
|
|
#endif
|
|
|
|
// add name prefix which has been removed by the generic function
|
|
if(!prefixedName)
|
|
return -ENOMEM;
|
|
strcpy(prefixedName, FHGFS_XATTR_SECURITY_PREFIX);
|
|
strcpy(prefixedName + sizeof(FHGFS_XATTR_SECURITY_PREFIX) - 1, name); // sizeof-1 to remove '\0'
|
|
|
|
if (value)
|
|
{
|
|
#ifdef KERNEL_HAS_DENTRY_XATTR_HANDLER
|
|
res = FhgfsOps_setxattr(dentry, prefixedName, value, size, flags);
|
|
#else
|
|
res = FhgfsOps_setxattr(inode, prefixedName, value, size, flags);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
res = FhgfsOps_removexattr(dentry, prefixedName);
|
|
}
|
|
|
|
kfree(prefixedName);
|
|
return res;
|
|
}
|
|
|
|
#ifdef KERNEL_HAS_GET_ACL
|
|
struct xattr_handler fhgfs_xattr_acl_access_handler =
|
|
{
|
|
#ifdef KERNEL_HAS_XATTR_HANDLER_NAME
|
|
.name = XATTR_NAME_POSIX_ACL_ACCESS,
|
|
#else
|
|
.prefix = XATTR_NAME_POSIX_ACL_ACCESS,
|
|
#endif
|
|
.flags = ACL_TYPE_ACCESS,
|
|
.list = NULL,
|
|
.get = FhgfsXAttrGetACL,
|
|
.set = FhgfsXAttrSetACL,
|
|
};
|
|
|
|
struct xattr_handler fhgfs_xattr_acl_default_handler =
|
|
{
|
|
#ifdef KERNEL_HAS_XATTR_HANDLER_NAME
|
|
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
|
|
#else
|
|
.prefix = XATTR_NAME_POSIX_ACL_DEFAULT,
|
|
#endif
|
|
.flags = ACL_TYPE_DEFAULT,
|
|
.list = NULL,
|
|
.get = FhgfsXAttrGetACL,
|
|
.set = FhgfsXAttrSetACL,
|
|
};
|
|
#endif // KERNEL_HAS_GET_ACL
|
|
|
|
struct xattr_handler fhgfs_xattr_user_handler =
|
|
{
|
|
.prefix = FHGFS_XATTR_USER_PREFIX,
|
|
.list = NULL,
|
|
.set = FhgfsXAttr_setUser,
|
|
.get = FhgfsXAttr_getUser,
|
|
};
|
|
|
|
struct xattr_handler fhgfs_xattr_security_handler =
|
|
{
|
|
.prefix = FHGFS_XATTR_SECURITY_PREFIX,
|
|
.list = NULL,
|
|
.set = FhgfsXAttr_setSecurity,
|
|
.get = FhgfsXAttr_getSecurity,
|
|
};
|
|
|
|
#if defined(KERNEL_HAS_CONST_XATTR_CONST_PTR_HANDLER)
|
|
const struct xattr_handler* const fhgfs_xattr_handlers[] =
|
|
#elif defined(KERNEL_HAS_CONST_XATTR_HANDLER)
|
|
const struct xattr_handler* fhgfs_xattr_handlers[] =
|
|
#else
|
|
struct xattr_handler* fhgfs_xattr_handlers[] =
|
|
#endif
|
|
{
|
|
#ifdef KERNEL_HAS_GET_ACL
|
|
&fhgfs_xattr_acl_access_handler,
|
|
&fhgfs_xattr_acl_default_handler,
|
|
#endif
|
|
&fhgfs_xattr_user_handler,
|
|
&fhgfs_xattr_security_handler,
|
|
NULL
|
|
};
|
|
|
|
#if defined(KERNEL_HAS_CONST_XATTR_CONST_PTR_HANDLER)
|
|
const struct xattr_handler* const fhgfs_xattr_handlers_noacl[] =
|
|
#elif defined(KERNEL_HAS_CONST_XATTR_HANDLER)
|
|
const struct xattr_handler* fhgfs_xattr_handlers_noacl[] =
|
|
#else
|
|
struct xattr_handler* fhgfs_xattr_handlers_noacl[] =
|
|
#endif
|
|
{
|
|
&fhgfs_xattr_user_handler,
|
|
&fhgfs_xattr_security_handler,
|
|
NULL
|
|
};
|
|
|