Hello World!|

liutimo

园龄:9年10个月粉丝:3关注:7

Client模块Poisx ACL代码分析

总结

在client模块中,使用 acl_ea_header来描述一组posix ACL规则,给文件或文件夹设置posix acl的本质就是给其设置名为 system.posix_acl_access 的 扩展属性,对应的value就是 acl_ea_header

我们先来看看client模块是如何使用 acl_ea_header来描述ACL规则的:

typedef struct {
ceph_le16 e_tag;
ceph_le16 e_perm;
ceph_le32 e_id;
} acl_ea_entry;
typedef struct {
ceph_le32 a_version;
acl_ea_entry a_entries[0];
} acl_ea_header;

acl_ea_entry表示一条acl规则,而acl_ea_header通过变长数组 a_entries 来记录一组acl规则。

acl_ea_entry各个字段的含义可以自行去阅读posix acl的定义。

除了基础知识中提到的,这里还要补充几点:

  1. client模块中,对 a_entires中的 acl_ea_entry 的顺序也做了要求,(不晓得是posix 规定的还是 client模块中规定的~)。具体实现在 posix_acl.c@posix_acl_check中。

  2. 当acl 规则等价于unix mode(eg:-rwxrwxrwx)时,我们通过ceph_getattr 获取system.posix_acl_access 扩展属性时,返回 ENODATA,并且此时 ll file不会显示+号。

    eg:
    $ touch 1.txt
    $ getfacl 1.txt
    # file: 1.txt
    # owner: 10331600@zte.intra
    # group: domain\040users@zte.intra
    user::rw-
    group::r--
    other::r--
    $ setfacl -m u::rwx 1.txt
    $ getfacl 1.txt
    # file: 1.txt
    # owner: 10331600@zte.intra
    # group: domain\040users@zte.intra
    user::rwx
    group::r--
    other::r--
    $ ll 1.txt
    -rwxr--r-- 1 10331600@zte.intra domain users@zte.intra 0 926 16:17 1.txt

posix acl函数分析

posix_acl.h中,提供了如下函数用于完成client端的acl鉴权。

int posix_acl_check(const void *xattr, size_t size);
int posix_acl_equiv_mode(const void *xattr, size_t size, mode_t *mode_p);
int posix_acl_inherit_mode(bufferptr& acl, mode_t *mode_p);
int posix_acl_access_chmod(bufferptr& acl, mode_t mode);
int posix_acl_permits(const bufferptr& acl, uid_t i_uid, gid_t i_gid,
const UserPerm& groups, unsigned want);

posix_acl_check

int posix_acl_check(const void *xattr, size_t size)
{
const acl_ea_header *header;
if (size < sizeof(*header))
return -1;
header = reinterpret_cast<const acl_ea_header*>(xattr);
ceph_le32 expected_version;
expected_version = ACL_EA_VERSION;
if (header->a_version != expected_version)
return -1;
const acl_ea_entry *entry = header->a_entries;
size -= sizeof(*header);
if (size % sizeof(*entry))
return -1;
int count = size / sizeof(*entry);
if (count == 0)
return 0;
int state = ACL_USER_OBJ;
int needs_mask = 0;
for (int i = 0; i < count; ++i) {
__u16 tag = entry->e_tag;
switch(tag) {
case ACL_USER_OBJ:
if (state == ACL_USER_OBJ) {
state = ACL_USER;
break;
}
return -1;
case ACL_USER:
if (state != ACL_USER)
return -1;
needs_mask = 1;
break;
case ACL_GROUP_OBJ:
if (state == ACL_USER) {
state = ACL_GROUP;
break;
}
return -1;
case ACL_GROUP:
if (state != ACL_GROUP)
return -1;
needs_mask = 1;
break;
case ACL_MASK:
if (state != ACL_GROUP)
return -1;
state = ACL_OTHER;
break;
case ACL_OTHER:
if (state == ACL_OTHER ||
(state == ACL_GROUP && !needs_mask)) {
state = 0;
break;
}
// fall-thru
default:
return -1;
}
++entry;
}
return state == 0 ? count : -1;
}

从这个代码片段中,我们可以看出:

  • 如何解析acl数据

  • acl条目的组成规则

    即a_entries中的ea_acl_entry 必须按照如下顺序组成:

    <ACL_USER_OBJ> [ACL_USER] <ACL_GROUP> [ACL_GROUP_OBJ] [ACL_MASK] <ACL_OTHER>

    ACL_USER_OBJACL_GROUP_OBJACL_OTHER必须存在,其余可选。

    ACL_USERACL_GROUP 任何一个存在时,都必须要有ACL_MASK

posix_acl_equiv_mode

int posix_acl_equiv_mode(const void *xattr, size_t size, mode_t *mode_p) {
if (posix_acl_check(xattr, size) < 0)
return -EINVAL;
int not_equiv = 0;
mode_t mode = 0;
const acl_ea_header *header = reinterpret_cast<const acl_ea_header *>(xattr);
const acl_ea_entry *entry = header->a_entries;
int count = (size - sizeof(*header)) / sizeof(*entry);
for (int i = 0; i < count; ++i) {
__u16 tag = entry->e_tag;
__u16 perm = entry->e_perm;
switch (tag) {
case ACL_USER_OBJ:
mode |= (perm & S_IRWXO) << 6;
break;
case ACL_GROUP_OBJ:
mode |= (perm & S_IRWXO) << 3;
break;
case ACL_OTHER:
mode |= perm & S_IRWXO;
break;
case ACL_MASK:
mode = (mode & ~S_IRWXG) | ((perm & S_IRWXO) << 3);
/* fall through */
case ACL_USER:
case ACL_GROUP:
not_equiv = 1;
break;
default:
return -EINVAL;
}
++entry;
}
if (mode_p)
*mode_p = (*mode_p & ~ACCESSPERMS) | mode;
return not_equiv;
}

先校验acl是否符合前面提到的规则,然后计算acl对应的 unix mode。

该函数除了计算 ACL规则对应的unix file/dir mode(保存在 mode_p对应的内存中)外,还会判断 acl 规则 是否等价于 unix file/dir mode。这里就和我们前面补充的第二点对应上了。

当存在 ACL_USERACL_GROUPACL_MASK时, posix_acl_equiv_mode 返回1(ACL不等价于 unix mode),否则返回0。我们再看一段用到了 posix_acl_equiv_mode的代码:

int Client::_setxattr(Inode *in, const char *name, const void *value,
size_t size, int flags, const UserPerm &perms) {
...
if (posix_acl_xattr) {
if (!strcmp(name, ACL_EA_ACCESS)) {
mode_t new_mode = in->mode;
if (value) {
int ret = posix_acl_equiv_mode(value, size, &new_mode);
if (ret < 0)
return ret;
if (ret == 0) {
value = NULL;
size = 0;
}
if (new_mode != in->mode) {
struct ceph_statx stx;
stx.stx_mode = new_mode;
ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, perms, NULL);
if (ret < 0)
return ret;
}
}
}
...
}
int ret = _do_setxattr(in, name, value, size, flags, 0, perms);
if (ret >= 0 && check_realm) {
// check if snaprealm was created for quota inode
if (in->quota.is_any_enable() &&
!(in->snaprealm && in->snaprealm->ino == in->ino))
ret = -EOPNOTSUPP;
}
return ret;
}

我们调用Client::_setxattr设置acl时, 如果posix_acl_equiv_mode 返回0时, value会被置为null。最终,只会设置与acl对等的 mode, 而不会设置acl到文件属性。

其余的函数后续看了再补充。

本文作者:liutimo

本文链接:https://www.cnblogs.com/liutimo/p/16734899.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   liutimo  阅读(179)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起