DAOS 源码解析之 daos_security(上)
DAOS (Distributed Asynchronous Object Storage) 是一个开源的对象存储系统,专为大规模分布式非易失性内存设计,利用了 SCM 和 NVMe 等的下一代 NVM 技术。 DAOS 同时在硬件之上提供了键值存储接口,提供了诸如事务性非阻塞 I/O、具有自我修复的高级数据保护、端到端数据完整性、细粒度数据控制和弹性存储的高级数据保护,从而优化性能并降低成本。
本文以 Release 1.1.4 版本为标准,解析 include/daos_security.h
中的具体实现。include/daos_security.h
包含了 DAOS 安全和访问控制 API。有关访问控制的具体信息可参考 DAOS 分布式异步对象存储|安全模型。
访问控制列表
结构体 daos_acl
表示访问控制列表 (Access Control List, ACL) 的表头,后跟可变长度的访问控制项 (Access Control Entry, ACE) 列表。可以通过将主体 (principal
) 字段大小与访问控制项的结构大小相加得到当前项的大小,来遍历访问控制项列表。
struct daos_acl {
// 列表格式的版本
uint16_t dal_ver;
// 保留:用于 64 位对齐
uint16_t dal_reserv;
// 访问控制项列表的总长度(字节)
uint32_t dal_len;
// 可变长度的访问控制项列表(struct daos_ace)
uint8_t dal_ace[];
};
宏 DAOS_ACL_VERSION
表示 ACL 格式的版本:
#define DAOS_ACL_VERSION (1)
访问控制项
结构体 daos_ace
表示给定主体的访问控制项。每个主体最多有一个 ACE,在给定的 ACL 中列出其所有权限:
struct daos_ace {
// daos_acl_access_type 的位图表示,表示访问权限类型
uint8_t dae_access_types;
// 主体类型
uint8_t dae_principal_type;
// 主体字段字符串长度
uint16_t dae_principal_len;
// daos_acl_flags 的位图表示,表示访问标志
uint16_t dae_access_flags;
// 保留:用于 64 位对齐
uint16_t dae_reserv;
// daos_acl_perm 的位图表示,表示 ALLOW 访问权限
uint64_t dae_allow_perms;
// daos_acl_perm 的位图表示,表示 AUDIT 访问权限
uint64_t dae_audit_perms;
// daos_acl_perm 的位图表示,表示 ALARM 访问权限
uint64_t dae_alarm_perms;
// 以 null 结尾的字符串,表示特定用户/组的主体名称。
// 实际分配的字节必须向上取整以 64 位对齐。
// 表示特殊主体 OWNER, OWNER_GROUP 和 EVERYONE 时,该字符串为空。
char dae_principal[];
};
主体
daos_acl_principal_type
表示访问控制项的主体类型。
OWNER, OWNER_GROUP 和 EVERYONE 是不需要主体字符串的特殊主体类型。
enum daos_acl_principal_type {
// 所属用户
DAOS_ACL_OWNER,
// 用户
DAOS_ACL_USER,
// 所属组
DAOS_ACL_OWNER_GROUP,
// 组
DAOS_ACL_GROUP,
// 任何主体
DAOS_ACL_EVERYONE,
// 必须是最后一个
NUM_DAOS_ACL_TYPES
};
宏 DAOS_ACL_MAX_PRINCIPAL_LEN
表示主体字段 user@domain 字符串的最大长度,不包括 null 终止符:
#define DAOS_ACL_MAX_PRINCIPAL_LEN (255)
宏 DAOS_ACL_MAX_PRINCIPAL_BUF_LEN
表示主体字段 user@domain 字符串的最大长度,包括 null 终止符:
#define DAOS_ACL_MAX_PRINCIPAL_BUF_LEN (DAOS_ACL_MAX_PRINCIPAL_LEN + 1)
主体字段有三种特殊类型,它们没有主体名,下列宏定义了这三种类型的主体名:
#define DAOS_ACL_PRINCIPAL_OWNER "OWNER@"
#define DAOS_ACL_PRINCIPAL_OWNER_GRP "GROUP@"
#define DAOS_ACL_PRINCIPAL_EVERYONE "EVERYONE@"
宏 DAOS_ACL_MAX_ACE_LEN
表示 daos_acl::dal_ace
的最大长度,即 dal_len
的值:
#define DAOS_ACL_MAX_ACE_LEN (65536)
宏 DAOS_ACL_MAX_ACE_STR_LEN
表示访问控制项 (Access Control Entry, ACE) 字符串格式 <access>:<flags>:<principal>:<perms>
的最大长度:
#define DAOS_ACL_MAX_ACE_STR_LEN (DAOS_ACL_MAX_PRINCIPAL_LEN + 64)
访问权限类型
daos_acl_access_type
表示要为其设置的访问权限类型位,有三种访问权限:
enum daos_acl_access_type {
// 允许访问
DAOS_ACL_ACCESS_ALLOW = (1U << 0),
// 记录访问活动以供审核
DAOS_ACL_ACCESS_AUDIT = (1U << 1),
// 通知访问活动以报警
DAOS_ACL_ACCESS_ALARM = (1U << 2)
};
宏 DAOS_ACL_ACCESS_ALL
表示所有有效访问位的掩码:
#define DAOS_ACL_ACCESS_ALL (DAOS_ACL_ACCESS_ALLOW | \
DAOS_ACL_ACCESS_AUDIT | \
DAOS_ACL_ACCESS_ALARM)
访问标志
daos_acl_flags
表示访问标志位,提供有关如何解释 ACE 的附加信息:
enum daos_acl_flags {
// 表示组,而不是用户
DAOS_ACL_FLAG_GROUP = (1U << 0),
// Container 应该从 Pool 中继承访问权限
DAOS_ACL_FLAG_POOL_INHERIT = (1U << 1),
// 访问失败时应该进行审核/报警
DAOS_ACL_FLAG_ACCESS_FAIL = (1U << 2),
// 访问成功时应该进行审核/报警
DAOS_ACL_FLAG_ACCESS_SUCCESS = (1U << 3)
};
宏 DAOS_ACL_FLAG_ALL
表示所有有效标志位的掩码:
#define DAOS_ACL_FLAG_ALL (DAOS_ACL_FLAG_GROUP | \
DAOS_ACL_FLAG_POOL_INHERIT | \
DAOS_ACL_FLAG_ACCESS_FAIL | \
DAOS_ACL_FLAG_ACCESS_SUCCESS)
特定权限
daos_acl_perm
表示可选的特定权限位:
enum daos_acl_perm {
DAOS_ACL_PERM_READ = (1U << 0),
DAOS_ACL_PERM_WRITE = (1U << 1),
DAOS_ACL_PERM_CREATE_CONT = (1U << 2),
DAOS_ACL_PERM_DEL_CONT = (1U << 3),
DAOS_ACL_PERM_GET_PROP = (1U << 4),
DAOS_ACL_PERM_SET_PROP = (1U << 5),
DAOS_ACL_PERM_GET_ACL = (1U << 6),
DAOS_ACL_PERM_SET_ACL = (1U << 7),
DAOS_ACL_PERM_SET_OWNER = (1U << 8),
};
宏 DAOS_ACL_PERM_POOL_ALL
表示 DAPS Pool 的所有有效权限位的掩码:
#define DAOS_ACL_PERM_POOL_ALL (DAOS_ACL_PERM_READ | \
DAOS_ACL_PERM_GET_PROP | \
DAOS_ACL_PERM_WRITE | \
DAOS_ACL_PERM_CREATE_CONT | \
DAOS_ACL_PERM_DEL_CONT)
宏 DAOS_ACL_PERM_CONT_ALL
表示 DAPS Container 的所有有效权限位的掩码:
#define DAOS_ACL_PERM_CONT_ALL (DAOS_ACL_PERM_READ | \
DAOS_ACL_PERM_WRITE | \
DAOS_ACL_PERM_DEL_CONT | \
DAOS_ACL_PERM_GET_PROP | \
DAOS_ACL_PERM_SET_PROP | \
DAOS_ACL_PERM_GET_ACL | \
DAOS_ACL_PERM_SET_ACL | \
DAOS_ACL_PERM_SET_OWNER)
宏 DAOS_ACL_PERM_ALL
表示 DAOS 所有有效权限位的掩码:
#define DAOS_ACL_PERM_ALL (DAOS_ACL_PERM_POOL_ALL | \
DAOS_ACL_PERM_CONT_ALL)
daos_acl_create
daos_acl_create
函数用于分配 DAOS 访问控制列表。
参数:
aces [in]
:指向要放入 ACL 中的 ACE 的指针数组。num_aces [in]
:ACE 列表的长度。
返回值:
- 如果成功,返回分配的
daos_acl
指针。 - 如果失败,返回 NULL。
struct daos_acl *
daos_acl_create(struct daos_ace *aces[], uint16_t num_aces)
{
struct daos_acl * acl;
int ace_len;
struct daos_ace **sorted_aces;
// 计算添加到 daos_acl 结构上的 ACE 列表的总长度
// 调用 daos_ace_get_siz() 计算列表中每个 ACE 的大小并求和
// 如果其中一个 ACE 为 NULL,则返回 -DER_INVAL
ace_len = get_flattened_ace_size(aces, num_aces);
if (ace_len < 0) {
// ACE 列表中包含 NULL
return NULL;
}
// 复制 aces 中的 ACE,并按 ACE 的 dae_principal_type 优先级进行排序
sorted_aces = get_copy_sorted_by_principal_type(aces, num_aces);
if (sorted_aces == NULL) {
// 复制时申请内存失败
return NULL;
}
// 为 daos_acl::dal_ace 结构分配存储 ACE 列表的数据块
// get_total_acl_size() 将 ACE 列表的大小 ace_len 和
// 表头结构体 daos_acl 的大小相加
D_ALLOC(acl, get_total_acl_size(ace_len));
if (acl == NULL) {
// 分配失败,释放复制的排序列表 sorted_aces
free_ace_array(sorted_aces, num_aces);
return NULL;
}
// 设置 ACL 格式的版本
acl->dal_ver = DAOS_ACL_VERSION;
// 设置 ACE 列表的总长度(字节)
acl->dal_len = ace_len;
// 将 ACE 指针数组 sorted_aces 中的每个 ACE 项数据块展平,并
// 复制到给 acl->dal_ace 分配的单个数据块中
// 该操作假设调用者已分配足够大的缓冲区 (D_ALLOC) 来容纳展平的列表
flatten_aces(acl->dal_ace, acl->dal_len, sorted_aces, num_aces);
// 释放复制的排序列表 sorted_aces
free_ace_array(sorted_aces, num_aces);
return acl;
}
daos_acl_dup
daos_acl_dup
函数为 DAOS 访问控制列表分配新的副本
参数:
acl [in]
:要复制的 ACL。
返回值:
- 如果成功,返回新分配的 ACL 副本。
- 如果失败,返回 NULL。
struct daos_acl *
daos_acl_dup(struct daos_acl *acl)
{
struct daos_acl *acl_copy;
size_t acl_len;
if (acl == NULL) {
return NULL;
}
// 获取 ACL 的总大小(以字节为单位)
// 这包括表头的大小以及 ACE 列表的大小
acl_len = daos_acl_get_size(acl);
// 为新副本分配空间
D_ALLOC(acl_copy, acl_len);
if (acl_copy == NULL) {
// 分配失败
return NULL;
}
// 复制 ACL
memcpy(acl_copy, acl, acl_len);
return acl_copy;
}
daos_acl_free
daos_acl_free
函数释放 DAOS 访问控制列表。
参数:
acl [in]
:指向要释放的 ACL 结构的指针
void
daos_acl_free(struct daos_acl *acl)
{
// ACL 仅仅是一个连续的数据块,所以不需要特殊处理
// 直接释放相应内存
D_FREE(acl);
}
daos_acl_get_size
daos_acl_get_size
函数获取 DAOS 访问控制列表的总大小(以字节为单位),这包括表头的大小以及 ACE 列表的大小。
参数:
acl [in]
:要获取大小的 ACL。
返回值:
- 返回 ACL 的大小(以字节为单位)。
- 如果输入无效,返回
-DER_INVAL
。
ssize_t
daos_acl_get_size(struct daos_acl *acl)
{
if (acl == NULL) {
// 无效输入
return -DER_INVAL;
}
// ACL 的大小为 ACE 列表的大小和表头结构体 daos_acl 的大小之和
return get_total_acl_size(acl->dal_len);
}
daos_acl_get_next_ace
daos_acl_get_next_ace
函数获取访问控制列表中的下一个访问控制项,以便在列表中进行迭代。
参数:
acl [in]
:要遍历的 ACL。current_ace [in]
:确定下一项的当前的 ACE,当为 NULL 时获取第一个 ACE。
返回值:
- ACL 中的下一个 ACE,当到达列表结尾时,返回 NULL。
struct daos_ace *
daos_acl_get_next_ace(struct daos_acl *acl, struct daos_ace *current_ace)
{
size_t offset;
if (acl == NULL) {
// 无效的输入
return NULL;
}
if (current_ace == NULL && acl->dal_len > 0) {
// 当前 ACE 为 NULL,获取列表中的第一个 ACE
return (struct daos_ace *)acl->dal_ace;
}
if (!is_in_ace_list((uint8_t *)current_ace, acl)) {
// 当前项已是列表中的最后一项
return NULL;
}
D_ASSERT(current_ace != NULL);
// 当前项的大小等于主体字段大小与结构体 daos_ace 大小之和
offset = sizeof(struct daos_ace) + current_ace->dae_principal_len;
if (!is_in_ace_list((uint8_t *)current_ace + offset, acl)) {
return NULL;
}
// 计算偏移量,得到下一项的地址
return (struct daos_ace *)((uint8_t *)current_ace + offset);
}
daos_acl_get_ace_for_principal
daos_acl_get_ace_for_principal
函数通过主体寻找访问控制列表中的访问控制项。
参数:
acl [in]
:待搜索的 ACL。type [in]
:要搜索的主体类型。principal [in]
:要搜索的主体名(类型为 USER 或 GROUP),NULL(其他类型)。ace [ou t]
:指向 ACL 中匹配的 ACE 的指针(不是副本)。
返回值:
- 如果成功,返回 0。
- 如果失败,返回:
-DER_INVAL
:无效输入。-DER_NONEXIST
:不存在匹配的 ACE。
int
daos_acl_get_ace_for_principal(struct daos_acl *acl,
enum daos_acl_principal_type type,
const char *principal, struct daos_ace **ace)
{
struct daos_ace *result;
if (acl == NULL || ace == NULL || !type_is_valid(type) ||
(type_needs_name(type) && principal == NULL)) {
// 无效输入
return -DER_INVAL;
}
// 迭代 ACL
result = daos_acl_get_next_ace(acl, NULL);
while (result != NULL) {
if (result->dae_principal_type == type &&
principal_name_matches_ace(result, principal)) {
// 通过比较主体类型和主体名找到匹配的 ACE
break;
}
// 获取列表中的下一个 ACE
result = daos_acl_get_next_ace(acl, result);
}
if (result == NULL) {
// 不存在匹配的 ACE
return -DER_NONEXIST;
}
// 返回指向 ACL 中匹配的 ACE 的指针
*ace = result;
return 0;
}
daos_acl_add_ace
daos_acl_add_ace
函数在访问控制列表的适当位置插入访问控制项。
预期的顺序是按主体类型排序:Owner, Users, Owner-Group, Groups, Everyone。
访问控制列表可能需要重新分配内存,以便为新插入的访问控制项提供空间(原有内存空间将被释放)。
如果新的访问控制项是现有项的更新,它将替换旧的项。
参数:
acl [in]
:需要修改的 ACL。new_ace [in]
:需要添加的新 ACE。
返回值:
- 如果成功,返回 0。
- 如果失败,返回:
-DER_INVAL
:无效输入。-DER_NOMEM
:重新申请需要的内存失败。
int
daos_acl_add_ace(struct daos_acl **acl, struct daos_ace *new_ace)
{
uint32_t new_len;
ssize_t new_ace_len;
struct daos_acl *new_acl;
if (acl == NULL || *acl == NULL) {
// 无效的 ACL
return -DER_INVAL;
}
// 获取 ACE 的大小(单位为字节)
// ACE 的大小为结构体 daos_ace 的大小加主体字段的大小
new_ace_len = daos_ace_get_size(new_ace);
if (new_ace_len < 0) {
// 无效的 ACE
return -DER_INVAL;
}
// 判断当前 ACL 中是否含有该主体的 ACE
if (acl_already_has_principal(*acl, new_ace->dae_principal_type,
new_ace->dae_principal)) {
// 当前列表已包含该主体的 ACE
// 更新该 ACE,不需要重新分配空间
overwrite_ace_for_principal(*acl, new_ace);
return 0;
}
new_len = (*acl)->dal_len + new_ace_len;
// 为 ACL 重新申请内存,以添加新 ACE
D_ALLOC(new_acl, get_total_acl_size(new_len));
if (new_acl == NULL) {
// 申请内存失败
return -DER_NOMEM;
}
new_acl->dal_ver = (*acl)->dal_ver;
new_acl->dal_len = new_len;
// 复制原 ACE 列表,同时将新 ACE 按主体类型顺序插入列表
copy_acl_with_new_ace_inserted(*acl, new_acl, new_ace);
// 释放原 ACL 的内存空间
daos_acl_free(*acl);
*acl = new_acl;
return 0;
}
daos_acl_remove_ace
daos_acl_remove_ace
函数从访问控制列表中移除要求的访问控制项。
当访问控制项被成功移除后,访问控制列表需要重新分配内存(原有内存空间将被释放)。
参数:
acl [in]
:要修改的 ACL。type [in]
:要移除的 ACE 的主体类型。principal_name [in]
:要移除的主体名(类型为 USER 或 GROUP),NULL(其他类型)。
返回值:
- 如果成功,返回 0。
- 如果失败,返回:
-DER_INVAL
:无效输入。-DER_NOMEM
:重新申请需要的内存失败。-DER_NONEXIST
:要移除的 ACE 不在 ACL 中。
int
daos_acl_remove_ace(struct daos_acl **acl,
enum daos_acl_principal_type type,
const char *principal_name)
{
struct daos_ace *current;
struct daos_ace *ace_to_remove;
struct daos_acl *new_acl;
uint32_t new_len;
uint8_t * pen;
int rc;
// principal_meets_type_requirements() 判断主体类型是否有效
// 类型为 USER/GROUP 时,主体名不为 NULL 且长度不为 0
// 类型为其他类型时,主体名为 NULL
if (acl == NULL || *acl == NULL || !type_is_valid(type) ||
!principal_meets_type_requirements(type, principal_name)) {
// 无效输入
return -DER_INVAL;
}
// 通过主体名在 ACL 中寻找要移除的 ACE
rc = daos_acl_get_ace_for_principal(*acl, type, principal_name,
&ace_to_remove);
if (rc != 0) {
// 要移除的 ACE 不在列表中
return rc;
}
new_len = (*acl)->dal_len - daos_ace_get_size(ace_to_remove);
// 为 ACL 重新申请内存
D_ALLOC(new_acl, get_total_acl_size(new_len));
if (new_acl == NULL) {
// 申请内存失败
return -DER_NOMEM;
}
new_acl->dal_len = new_len;
new_acl->dal_ver = (*acl)->dal_ver;
// 迭代 ACL
pen = new_acl->dal_ace;
current = daos_acl_get_next_ace(*acl, NULL);
while (current != NULL) {
// 复制 ACE 到新的 ACL 中
// 如果当前项为要移除的项,跳过
if (!ace_matches_principal(current, type, principal_name)) {
pen = write_ace(current, pen);
}
current = daos_acl_get_next_ace(*acl, current);
}
// 释放原 ACL 的内存空间
daos_acl_free(*acl);
*acl = new_acl;
return 0;
}
daos_acl_dump
daos_acl_dump
函数将访问控制列表按详细的可读格式打印到标准输出,帮助调试。
参数:
acl [in]
:要打印的 ACL。
void
daos_acl_dump(struct daos_acl *acl)
{
struct daos_ace *current;
printf("Access Control List:\n");
if (acl == NULL) {
printf("\tNULL\n");
return;
}
printf("\tVersion: %hu\n", acl->dal_ver);
printf("\tLength: %u\n", acl->dal_len);
// 迭代 ACL
current = daos_acl_get_next_ace(acl, NULL);
while (current != NULL) {
// 将 ACE 按详细的可读格式打印到标准输出
daos_ace_dump(current, 1);
current = daos_acl_get_next_ace(acl, current);
}
}
daos_acl_validate
daos_acl_validate
函数解析并检查整个访问控制列表的有效性和内部一致性。
参数:
acl [in]
:要检查的 ACL。
返回值:
- 如果 ACL 是有效的,返回 0。
- 如果 ACL 无效,返回
-DER_INVAL
。 - 如果检查过程中内存不足,返回
-DER_NOMEM
。
int
daos_acl_validate(struct daos_acl *acl)
{
int rc;
if (acl == NULL) {
// 当前 ACL 为空,无效
return -DER_INVAL;
}
if (acl->dal_ver != DAOS_ACL_VERSION) {
// 当前 ACL 格式与预期格式不匹配,无效
return -DER_INVAL;
}
if (acl->dal_len > 0 && (acl->dal_len < sizeof(struct daos_ace) ||
(acl->dal_len > DAOS_ACL_MAX_ACE_LEN))) {
// 当前 ACL 长度超过最大长度限制,无效
D_ERROR("invalid dal_len %d, should with in [%zu, %d].\n",
acl->dal_len, sizeof(struct daos_ace),
DAOS_ACL_MAX_ACE_LEN);
return -DER_INVAL;
}
// 整体结构必须是 64 位对齐的
if (acl->dal_len % 8 != 0) {
// 当前 ACL 结构不是 64 位对齐的,无效
D_ERROR("invalid dal_len %d, not 8 bytes aligned.\n",
acl->dal_len);
return -DER_INVAL;
}
// 遍历 ACL 检查 ACE 的有效性
rc = validate_aces(acl);
if (rc != 0) {
// 存在无效的 ACE
return rc;
}
return 0;
}
daos_acl_pool_validate
daos_acl_pool_validate
函数检查访问控制列表是否可用于 DAOS Pool。
该检查调用了 daos_acl_validate
函数进行相应的检查。
参数:
acl [in]
:要检查的 ACL。
返回值:
- 如果 ACL 可用于 Pool,返回 0。
- 如果 ACL 无效,返回
-DER_INVAL
。 - 如果检查过程中内存不足,返回
-DER_NOMEM
。
int
daos_acl_pool_validate(struct daos_acl *acl)
{
// 首先调用 daos_acl_validate() 进行检查
// 其次检查 DAPS Pool 的有效权限位
return validate_acl_with_special_perms(acl, DAOS_ACL_PERM_POOL_ALL);
}
daos_acl_cont_validate
daos_acl_cont_validate
函数检查访问控制列表是否可用于 DAOS Container。
该检查调用了 daos_acl_validate
函数进行相应的检查。
参数:
acl [in]
:要检查的 ACL。
返回值:
- 如果 ACL 可用于 Container,返回 0。
- 如果 ACL 无效,返回
-DER_INVAL
。 - 如果检查过程中内存不足,返回
-DER_NOMEM
。
int
daos_acl_cont_validate(struct daos_acl *acl)
{
// 首先调用 daos_acl_validate() 进行检查
// 其次检查 DAPS Container 的有效权限位
return validate_acl_with_special_perms(acl, DAOS_ACL_PERM_CONT_ALL);
}
daos_ace_create
daos_ace_create
函数分配新的访问控制项(主体名内存对齐)。
只有类型为 USER 或 GROUP 的主体包含主体名。
参数:
type [in]
:ACE 的主体类型。principal_name [in]
:主体名,将添加到结构的末尾(对于没有主体名的类型,传递 NULL)。
返回值:
- 如果成功,返回设置了预期主体名、长度和类型的新 ACE 结构。
- 如果失败,返回 NULL。
struct daos_ace *
daos_ace_create(enum daos_acl_principal_type type, const char *principal_name)
{
struct daos_ace *ace;
size_t principal_array_len = 0;
if (!type_is_valid(type)) {
// 主体类型不是有效类型
return NULL;
}
if (type_needs_name(type)) {
if (principal_name == NULL || strlen(principal_name) == 0) {
// 主体类型是 USER/GROUP,但主体名无效
return NULL;
}
// 需要满足 64 位对齐
principal_array_len = D_ALIGNUP(strlen(principal_name) + 1, 8);
}
// 分配新 ACE 的内存空间
D_ALLOC(ace, sizeof(struct daos_ace) + principal_array_len);
if (ace != NULL) {
ace->dae_principal_type = type;
ace->dae_principal_len = principal_array_len;
strncpy(ace->dae_principal, principal_name,
principal_array_len);
if (type_is_group(type)) {
// 设置组的访问标志位
ace->dae_access_flags |= DAOS_ACL_FLAG_GROUP;
}
}
return ace;
}
daos_ace_free
daos_ace_free
函数释放由 daos_ace_alloc
函数分配的访问控制项。
参数:
ace [in]
:要释放的 ACE。
void
daos_ace_free(struct daos_ace *ace)
{
D_FREE(ace);
}
daos_ace_get_size
daos_ace_get_size
函数获取访问控制项的大小(单位字节)。访问控制项的长度是可变的。
参数:
ace [in]
:要获取大小的 ACE。
返回值:
- 如果成功,返回目标 ACE 的字节大小。
- 如果输入无效的 ACE,返回
-DER_INVAL
。
ssize_t
daos_ace_get_size(struct daos_ace *ace)
{
if (ace == NULL) {
// 无效输入
return -DER_INVAL;
}
// ACE 的大小为结构体 daos_ace 的大小加主体字段的大小
return sizeof(struct daos_ace) + ace->dae_principal_len;
}
daos_ace_dump
daos_ace_dump
函数将访问控制项按详细的可读格式打印到标准输出。
参数:
ace [in]
:要打印的 ACE。tabs [in]
:要在顶层缩进的制表符数量。
void
daos_ace_dump(struct daos_ace *ace, uint32_t tabs)
{
// 打印相应数量的制表符
indent(tabs);
printf("Access Control Entry:\n");
if (ace == NULL) {
indent(tabs + 1);
printf("NULL\n");
return;
}
// 打印各字段,制表符数量相对于顶层加一
print_principal(tabs + 1, ace);
print_all_access_types(tabs + 1, ace);
print_all_flags(tabs + 1, ace);
print_all_perm_types(tabs + 1, ace);
}
daos_ace_is_valid
daos_ace_is_valid
函数检查访问控制项结构的有效性和内部一致性。
参数:
ace [in]
:要检查的 ACE。
返回值:
- 如果 ACE 有效,返回 true,否则返回 false。
bool
daos_ace_is_valid(struct daos_ace *ace)
{
uint8_t valid_types = DAOS_ACL_ACCESS_ALL;
uint16_t valid_flags = DAOS_ACL_FLAG_ALL;
uint64_t valid_perms = DAOS_ACL_PERM_ALL;
bool name_exists;
bool flag_exists;
// 检查输入有效性
if (ace == NULL)
return false;
// 检查访问权限类型字段是否包含无效位
if (ace->dae_access_types & ~valid_types)
return false;
// 检查是否定义访问权限类型
if (ace->dae_access_types == 0)
return false;
// 检查访问权限标志字段是否包含无效位
if (ace->dae_access_flags & ~valid_flags)
return false;
// 检查访问权限字段是否包含无效位
if (!perms_valid_for_ace(ace, valid_perms))
return false;
// 主体为要求主体名的类型 USER/GROUP 时,主体名不得为空
name_exists = ace->dae_principal_len != 0;
if (type_needs_name(ace->dae_principal_type) != name_exists)
return false;
// 只有在主体类型为组时,访问权限标志才能设置组标志
flag_exists = (ace->dae_access_flags & DAOS_ACL_FLAG_GROUP) != 0;
if (type_is_group(ace->dae_principal_type) != flag_exists)
return false;
// 整体结构必须保持 64 位对齐
if (ace->dae_principal_len % 8 != 0)
return false;
// 主体名结尾需包含结束符 '\0'
if (ace->dae_principal_len > 0 && !principal_is_null_terminated(ace))
return false;
// 主体名长度不得超过最大长度限制
// 主体名格式须符合规定
if (ace->dae_principal_len > 0 &&
!daos_acl_principal_is_valid(ace->dae_principal))
return false;
// 检查是否定义访问权限
if (!permissions_match_access_type(ace, DAOS_ACL_ACCESS_ALLOW) ||
!permissions_match_access_type(ace, DAOS_ACL_ACCESS_AUDIT) ||
!permissions_match_access_type(ace, DAOS_ACL_ACCESS_ALARM))
return false;
// 检查访问权限类型与访问权限标志是否匹配
if (!access_matches_flags(ace))
return false;
return true;
}
daos_acl_principal_is_valid
daos_acl_principal_is_valid
函数检查访问控制列表中访问控制项的主体名是否使用正确格式的字符串。
检查不是非常严格,该函数验证主体名是否为 name@[domain] 格式,但不验证名称的字符合法,也不验证主体是否实际存在。
参数:
name [in]
:要验证的主体名。
返回值:
- 如果主题名格式正确,返回 true,否则返回 false。
bool
daos_acl_principal_is_valid(const char *name)
{
size_t len;
size_t i;
enum validity_state state = STATE_START;
if (name == NULL) {
// 无效输入
D_INFO("Name was NULL\n");
return false;
}
len = strnlen(name, DAOS_ACL_MAX_PRINCIPAL_BUF_LEN);
if (len == 0 || len > DAOS_ACL_MAX_PRINCIPAL_LEN) {
// 主体名长度超过最大长度限制
D_INFO("Invalid len: %lu\n", len);
return false;
}
// 利用有限状态机验证主体名是否符合正确格式
for (i = 0; i < (len + 1); i++) {
state = next_validity_state(state, name[i]);
if (state == STATE_INVALID) {
// 格式错误
D_INFO("Name was badly formatted: %s\n", name);
return false;
}
}
return true;
}
下一部分
请参阅 DAOS 源码解析之 daos_security(下)
相关信息
Emai: debugzhang@163.com
- 点赞
- 收藏
- 关注作者
评论(0)