openGauss源码解析(200)

openGauss源码解析:安全管理源码解析(11)

2. 对象权限管理

数据库对象权限管理主要通过使用SQL命令“GRANT/REVOKE”授予或回收一个或多个角色在对象上的权限。“GRANT/REVOKE”命令都由函数ExecuteGrantStmt实现,该函数只有一个GrantStmt类型的参数,基本执行流程如图9-21所示。

图9-21 函数ExecuteGrantStmt执行流程

数据结构GrantStmt定义代码如下:

typedef struct GrantStmt {

NodeTag type;

bool is_grant; /* true = 授权, false = 回收 */

GrantTargetType targtype; /* 操作目标的类型 */

GrantObjectType objtype; /* 被操作对象的类型:表、数据库、模式、函数等 */

List* objects; /* 被操作对象的集合 */

List* privileges; /* 要操作权限列表 */

List* grantees; /* 被授权者的集合 */

bool grant_option; /* true = 再授予权限 */

DropBehavior behavior; /* 回收权限的行为 */

} GrantStmt;

函数ExecuteGrantStmt首先将GrantStmt结构转换为InternalGrant结构,并将权限列表转换为内部的AclMode表示形式。当privileges 取值为NIL时,表示授予或回收所有的权限,此时置InternalGrant的all_privs字段为true,privileges字段为ACL_NO_RIGHTS。

数据结构InternalGrant的代码如下:

typedef struct InternalGrant {

bool is_grant; /* true=授权, false=回收 */

GrantObjectType objtype; /* 被操作对象的类型:表、数据库、模式、函数等 */

List* objects; /* 被操作对象的集合 */

bool all_privs; /* 是否授予或回收所有的权限 */

AclMode privileges; /* AclMode形式表示的DML类操作对应的权限 */

AclMode ddl_privileges; /* AclMode形式表示的DDL类操作对应的权限 */

List* col_privs; /* 对列执行的DML类操作对应的权限 */

List* col_ddl_privs; /* 对列执行的DDL类操作对应的权限 */

List* grantees; /* 被授权者的集合 */

bool grant_option; /* true=再授予权限 */

DropBehavior behavior; /* 回收权限的行为 */

} InternalGrant;

函数ExecuteGrantStmt在完成结构转换之后,调用函数ExecGrantStmt_oids,根据对象类型分别调用相应对象的权限管理函数。接下来以表对象的权限管理过程为例介绍权限管理的算法。函数ExecGrant_Relation用来处理表对象权限的授予或回收操作,入参为InternalGrant类型的变量,存储着授权或回收操作的操作对象信息、被授权者信息和权限信息。函数ExecGrant_Relation的处理流程如图9-22所示。

图9-22 函数ExecGrant_Relation的处理流程

该函数的处理流程为:

(1) 从系统表pg_class中获取旧ACL。如果不存在旧的ACL,则新建一个ACL,并调用函数acldefault将默认的权限信息赋给该ACL。根据对象的不同,初始的缺省权限含有部分可赋予PUBLIC的权限。如果存在旧的ACL,则将旧的ACL存储为一个副本。
(2) 调用select_best_grantor函数来获取授权者对操作对象所拥有的授权权限avail_goptions;将参数avail_goptions传入函数restrict_and_check_grant,结合SQL命令中给出的操作权限,计算出实际需要授予或回收的权限。
(3) 调用merge_acl_with_grant函数生成新的ACL。如果是授予权限,则将要授予的权限添加到旧ACL中;如果是回收权限,则将要被回收的权限从旧ACL中删除。
(4) 将新的ACL更新到系统表pg_class对应元组的ACL字段,完成授权或回收过程。

该函数的相关代码如下:

static void ExecGrant_Relation(InternalGrant* istmt)

{

. . .

/* 循环处理每一个表对象 */

foreach (cell, istmt->objects) {

. . .

/* 判断所要操作的表对象是否存在,若不存在则提示报错 */

tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));

if (!HeapTupleIsValid(tuple))

ereport(

ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for relation %u", relOid)));

pg_class_tuple = (Form_pg_class)GETSTRUCT(tuple);

. . .

/* 系统表pg_class中获取旧ACL。若不存在旧的ACL,则新建一个ACL,若存在旧的ACL,则将旧的ACL存储为一个副本 */

ownerId = pg_class_tuple->relowner;

aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull);

if (isNull) {

switch (pg_class_tuple->relkind) {

case RELKIND_SEQUENCE:

old_acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);

break;

default:

old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);

break;

}

noldmembers = 0;

oldmembers = NULL;

} else {

old_acl = DatumGetAclPCopy(aclDatum);

noldmembers = aclmembers(old_acl, &oldmembers);

}

old_rel_acl = aclcopy(old_acl);

/* 处理表级别的权限 */

if (this_privileges != ACL_NO_RIGHTS) {

AclMode avail_goptions;

Acl* new_acl = NULL;

Oid grantorId;

HeapTuple newtuple = NULL;

Datum values[Natts_pg_class];

bool nulls[Natts_pg_class] = {false};

bool replaces[Natts_pg_class] = {false};

int nnewmembers;

Oid* newmembers = NULL;

AclObjectKind aclkind;

/* 获取授权者grantorId和授权者对该操作对象所拥有的授权权限avail_goptions */

select_best_grantor(GetUserId(), this_privileges, old_acl, ownerId, &grantorId, &avail_goptions);

switch (pg_class_tuple->relkind) {

case RELKIND_SEQUENCE:

aclkind = ACL_KIND_SEQUENCE;

break;

default:

aclkind = ACL_KIND_CLASS;

break;

}

/* 结合参数avail_goptions和SQL命令中给出的操作权限,计算出实际需要授予或回收的权限 */

this_privileges = restrict_and_check_grant(istmt->is_grant,

avail_goptions,

istmt->all_privs,

this_privileges,

relOid,

grantorId,

aclkind,

NameStr(pg_class_tuple->relname),

0,

NULL);

/* 生成新的ACL,并更新到系统表pg_class对应元组的ACL字段 */

new_acl = merge_acl_with_grant(old_acl,

istmt->is_grant,

istmt->grant_option,

istmt->behavior,

istmt->grantees,

this_privileges,

grantorId,

ownerId);

. . .

replaces[Anum_pg_class_relacl - 1] = true;

values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);

newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);

simple_heap_update(relation, &newtuple->t_self, newtuple);

. . .

}

/* 若存在列级授权或回收,则调用ExecGrant_Attribute 函数处理 */

. . .

if (have_col_privileges) {

AttrNumber i;

for (i = 0; i < num_col_privileges; i++) {

if (col_privileges[i] == ACL_NO_RIGHTS)

continue;

ExecGrant_Attribute(istmt,

relOid,

NameStr(pg_class_tuple->relname),

i + FirstLowInvalidHeapAttributeNumber,

ownerId,

col_privileges[i],

attRelation,

old_rel_acl);

}

}

. . .

}

heap_close(attRelation, RowExclusiveLock);

heap_close(relation, RowExclusiveLock);

}

posted @ 2024-05-07 09:25  openGauss-bot  阅读(5)  评论(0编辑  收藏  举报