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);
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值