总结
在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的定义。
除了基础知识中提到的,这里还要补充几点:
-
client模块中,对
a_entires
中的acl_ea_entry
的顺序也做了要求,(不晓得是posix 规定的还是 client模块中规定的~)。具体实现在posix_acl.c@posix_acl_check
中。 -
当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 9月 26 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_OBJ
、ACL_GROUP_OBJ
和ACL_OTHER
必须存在,其余可选。当
ACL_USER
、ACL_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_USER
、ACL_GROUP
和ACL_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到文件属性。
其余的函数后续看了再补充。
标签:int,acl,Poisx,Client,posix,mode,ACL,size From: https://www.cnblogs.com/liutimo/p/16734899.html