4

⭐openGauss数据库源码解析系列文章—— 角色管理⭐

 2 years ago
source link: https://blog.csdn.net/GaussDB/article/details/120697765
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
❤️‍大家好,我是Gauss松鼠会,欢迎进来学习啦~❤️‍

在前面介绍过“9.1 安全管理整体架构和代码概览、9.2 安全认证”,本篇我们介绍第9章 安全管理源码解析中“9.3 角色管理”的相关精彩内容介绍。

9.3 角色管理

角色是拥有数据库对象和权限的实体,在不同的环境中角色可以认为是一个用户、一个组或者兼顾两者。角色管理包含了角色的创建、修改、删除、权限授予和回收操作。

9.3.1 角色创建

如果在openGauss上需要创建一个角色,可以使用SQL命令CREATE ROLE,其语法为:

CREATE ROLE role_name [ [ WITH ] option [ ... ] ] [ ENCRYPTED | UNENCRYPTED ] { PASSWORD | IDENTIFIED BY } { 'password' | DISABLE };

创建角色是通过函数CreateRole实现的,其函数接口为:

void CreateRole(CreateRoleStmt* stmt)

其中,CreateRoleStmt为创建角色时所需的数据结构,具体数据结构代码如下:

typedef struct CreateRoleStmt {
    NodeTag type;
    RoleStmtType stmt_type;  /* 将要创建的角色类型 ROLE/USER/GROUP  */
    char* role;              /* 角色名 */
    List* options;            /* 角色属性列表 */
} CreateRoleStmt;

字段stmt_type是枚举类型,相关代码如下:

typedef enum RoleStmtType {
ROLESTMT_ROLE,    /* 代表创建角色 */
ROLESTMT_USER,    /* 代表创建用户 */
ROLESTMT_GROUP,  /* 代表创建组用户 */ 
} RoleStmtType;

字段option用来存储角色的属性信息,具体的数据结构为:

typedef struct DefElem {
    NodeTag type;
    char* defnamespace;     /* 节点对应的命名空间  */
    char* defname;          /* 节点对应的角色属性名  */
    Node* arg;              /* 表示值或类型名  */
    DefElemAction defaction;  /* SET/ADD/DROP 等其他未指定的行为  */
} DefElem;

在上述的关键数据结构基础之上,完整的创建角色流程如图9-14所示。
在这里插入图片描述

图9-14 openGauss角色创建流程

创建角色时先判断所要创建的角色类型。如果是创建用户,则设置其canlogin属性为true,因为用户默认具有登录权限。而创建角色和创建组时,若角色属性参数没有声明的话,则canlogin属性默认为false。相关代码如下:

/* 默认值可能因原始语句类型而异 */
switch (stmt->stmt_type) {
case ROLESTMT_ROLE:
        break;
    case ROLESTMT_USER:
         canlogin = true;
         break;
     case ROLESTMT_GROUP:
         break;
     default:
         break;
}

检查完所要创建的角色类型以后,开始循环获取角色属性options中的内容,并将其转换成对应的角色属性值类型。相关代码如下:

/* 从node tree中获取option */
foreach (option, stmt->options) {
    DefElem* defel = (DefElem*)lfirst(option);

    if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 ||
        strcmp(defel->defname, "unencryptedPassword") == 0) {
        if (dpassword != NULL) {
            clean_role_password(dpassword);
            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
        }
        dpassword = defel;
        if (strcmp(defel->defname, "encryptedPassword") == 0)
            encrypt_password = true;
        else if (strcmp(defel->defname, "unencryptedPassword") == 0) {
            clean_role_password(dpassword);
            ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                    errmsg("Permission denied to create role with option UNENCRYPTED.")));
        }
    } else if (strcmp(defel->defname, "sysid") == 0) {
        ereport(NOTICE, (errmsg("SYSID can no longer be specified")));
    } else if (strcmp(defel->defname, "inherit") == 0) {
        if (dinherit != NULL) {
            clean_role_password(dpassword);
            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
        }
        dinherit = defel;
    } else if (strcmp(defel->defname, "createrole") == 0) {
        if (dcreaterole != NULL) {
            clean_role_password(dpassword);
            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
        }
        dcreaterole = defel;
    } else if (strcmp(defel->defname, "createdb") == 0) {
        if (dcreatedb != NULL) {
            clean_role_password(dpassword);
            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
        }
        dcreatedb = defel;
    } else if (strcmp(defel->defname, "useft") == 0) {
        if (duseft != NULL) {
            clean_role_password(dpassword);
            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
        }
        duseft = defel;
……

根据对应的参数信息转换需要的角色属性值类型,如提取issuper值和createrole值等。相关代码如下:

  if (dissuper != NULL)
        issuper = intVal(dissuper->arg) != 0;
    if (dinherit != NULL)
        inherit = intVal(dinherit->arg) != 0;
    if (dcreaterole != NULL)
        createrole = intVal(dcreaterole->arg) != 0;
    if (dcreatedb != NULL)
        createdb = intVal(dcreatedb->arg) != 0;
   ……

在完成了转换以后,将角色属性值以及角色的信息一起构建一个pg_authid的元组,再写回系统表并更新索引。作相关代码如下:

/* 检查pg_authid relation,确认该角色没有存在*/
Relation pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    TupleDesc pg_authid_dsc = RelationGetDescr(pg_authid_rel);

    if (OidIsValid(get_role_oid(stmt->role, true))) {
        str_reset(password);
        ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("role \"%s\" already exists", stmt->role)));
}
……
    /* 创建一个插入的tuple */
    errno_t errorno = memset_s(new_record, sizeof(new_record), 0, sizeof(new_record));
    securec_check(errorno, "\0", "\0");
    errorno = memset_s(new_record_nulls, sizeof(new_record_nulls), false, sizeof(new_record_nulls));
    securec_check(errorno, "\0", "\0");

    new_record[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->role));

    new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
    new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
    new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
    new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
    
    new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
    new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
    new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
    new_record[Anum_pg_authid_rolauditadmin - 1] = BoolGetDatum(isauditadmin);
    new_record[Anum_pg_authid_rolsystemadmin - 1] = BoolGetDatum(issystemadmin);
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
……
    HeapTuple tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);

    if (u_sess->proc_cxt.IsBinaryUpgrade && OidIsValid(u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid)) {
        HeapTupleSetOid(tuple, u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid);
        u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid = InvalidOid;
    }

    roleid = simple_heap_insert(pg_authid_rel, tuple);

    if (IsUnderPostmaster) {
        if (OidIsValid(rpoid) && (rpoid != DEFAULT_POOL_OID))
            recordDependencyOnRespool(AuthIdRelationId, roleid, rpoid);

        u_sess->wlm_cxt->wlmcatalog_update_user = true;
}
……

完成更新以后,将新创建的角色加入指定存在的父角色中。相关代码如下:

  /* 将新角色添加到指定的现有角色中 */
    foreach (item, addroleto) {
        char* oldrolename = strVal(lfirst(item));
        Oid oldroleid = get_role_oid(oldrolename, false);

        AddRoleMems(
            oldrolename, oldroleid, list_make1(makeString(stmt->role)), list_make1_oid(roleid), GetUserId(), false);
    }

    AddRoleMems(stmt->role, roleid, adminmembers, roleNamesToIds(adminmembers), GetUserId(), true);
    AddRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), GetUserId(), false);

至此就完成了整个角色创建的过程。

9.3.2 角色管理

1. 修改角色属性

修改一个数据库角色可以使用SQL命令ALTER ROLE。角色属性的修改是通过调用AlterRole函数来实现的,该函数只有一个类型为AlterRoleStmt结构的参数。相关代码如下:

typedef struct AlterRoleStmt {
    NodeTag  type;
    char*  role; /* 角色的名称 */
    List*  options; /* 需要修改的属性列表 */
    int  action;  /* +1增加成员关系, -1删除成员关系 */
    RoleLockType  lockstatus; /* 角色锁定状态 */
} AlterRoleStmt;

修改角色的流程如图9-15所示。
在这里插入图片描述

图9-15 openGauss角色管理流程图

调用函数AlterRole修改用户角色属性时,首先循环判断options,依次提取要修改的角色属性;然后查看系统表pg_authid判断是否已存在该角色,如果不存在则提示报错;再进行相应的权限判断,检查执行者是否有权限去更改该角色的属性;最后构建一个新的元组,将要更改的属性更新到新元组中,存入系统表pg_authid。同时AlterRole函数也可以用来调整角色的成员关系,结构体中的action字段值设置为1和-1分别表示增加和删除成员关系,该选项将在授予和回收角色章节具体描述。AlterRole函数的具体实现代码如下:

void AlterRole(AlterRoleStmt* stmt)
{
    . . .
    /* 循环提取角色的属性options */
    foreach (option, stmt->options) {
        DefElem* defel = (DefElem*)lfirst(option);

        if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 ||
            strcmp(defel->defname, "unencryptedPassword") == 0) {
            if (dpassword != NULL) {
                clean_role_password(dpassword);
                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
            }
            dpassword = defel;
            if (strcmp(defel->defname, "encryptedPassword") == 0)
                encrypt_password = true;
            else if (strcmp(defel->defname, "unencryptedPassword") == 0) {
                clean_role_password(dpassword);
                ereport(ERROR,
                    (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
                        errmsg("Permission denied to create role with option UNENCRYPTED.")));
            }
        } else if (strcmp(defel->defname, "createrole") == 0) {
            if (dcreaterole != NULL) {
                clean_role_password(dpassword);
                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
            }
            dcreaterole = defel;
        } else if (strcmp(defel->defname, "inherit") == 0) {
            if (dinherit != NULL) {
                clean_role_password(dpassword);
                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
            }
            dinherit = defel;
        }
. . .
        else {
            clean_role_password(dpassword);
            ereport(ERROR,
                (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("option \"%s\" not recognized", defel->defname)));
        }
    }
/* 将提取的属性赋值给对应的变量 */
    if (dpassword != NULL && dpassword->arg != NULL) {
        head = list_head((List*)dpassword->arg);
        if (head != NULL) {
            pwdargs = (A_Const*)linitial((List*)dpassword->arg);
            if (pwdargs != NULL) {
                password = strVal(&pwdargs->val);
            }
            if (lnext(head)) {
                pwdargs = (A_Const*)lsecond((List*)dpassword->arg);
                if (pwdargs != NULL) {
                    replPasswd = strVal(&pwdargs->val);
                }
            }
        }
    }
    if (dinherit != NULL)
        inherit = intVal(dinherit->arg);
    if (dcreaterole != NULL)
        createrole = intVal(dcreaterole->arg);
 . . .
    /* 查看要修改的角色是否存在,不存在则提示报错 */
    Relation pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);

    HeapTuple tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
    if (!HeapTupleIsValid(tuple)) {
        str_reset(password);
        str_reset(replPasswd);

        if (!have_createrole_privilege())
            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
        else
            ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role)));
    }
roleid = HeapTupleGetOid(tuple);
. . .
/* 检查是否有权限更改相应角色的属性,权限不足则提示报错 */
    if (roleid == BOOTSTRAP_SUPERUSERID) {
        if (!(issuper < 0 && inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && isreplication < 0 &&
                isauditadmin < 0 && issystemadmin < 0 && isvcadmin < 0 && useft < 0 && dconnlimit == NULL &&
                rolemembers == NULL && validBegin == NULL && validUntil == NULL && drespool == NULL &&
                dparent == NULL && dnode_group == NULL && dspacelimit == NULL && dtmpspacelimit == NULL &&
                dspillspacelimit == NULL)) {
            str_reset(password);
            str_reset(replPasswd);
            ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                    errmsg("Permission denied to change privilege of the initial account.")));
        }
    }
    if (dpassword != NULL && roleid == BOOTSTRAP_SUPERUSERID && GetUserId() != BOOTSTRAP_SUPERUSERID) {
        str_reset(password);
        str_reset(replPasswd);
        ereport(ERROR,
            (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                errmsg("Permission denied to change password of the initial account.")));
    }
    . . .
    } else if (!have_createrole_privilege()) {
        if (!(inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && isreplication < 0 && isauditadmin < 0 &&
                issystemadmin < 0 && isvcadmin < 0 && useft < 0 && dconnlimit == NULL && rolemembers == NULL &&
                validBegin == NULL && validUntil == NULL && !*respool && !OidIsValid(parentid) && dnode_group == NULL &&
                !spacelimit && !tmpspacelimit && !spillspacelimit &&
                /* if not superuser or have createrole privilege, permission of lock and unlock is denied */
                stmt->lockstatus == DO_NOTHING &&
                /* if alter password, it will be handled below */
                roleid == GetUserId()) ||
            (roleid != GetUserId() && dpassword == NULL)) {
            str_reset(password);
            str_reset(replPasswd);
            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
        }
}
...
    /* 将要更改的角色属性值分别更新到新元组中,再将新元组替代旧元组存入系统表pg_authid中 */
    if (issuper >= 0) {
        new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
        new_record_repl[Anum_pg_authid_rolsuper - 1] = true;

        new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
        new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
    }
    if (inherit >= 0) {
        new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
        new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
    }
  . . .
    HeapTuple new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record, new_record_nulls, new_record_repl);
    simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);

    CatalogUpdateIndexes(pg_authid_rel, new_tuple);
   . . .
/* 判断成员关系,增加或删除成员 */
    if (stmt->action == 1) 
        AddRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), GetUserId(), false);
    else if (stmt->action == -1) /* drop members FROM role */
        DelRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), false);

    . . .
    heap_close(pg_authid_rel, NoLock);
}

2. 删除角色

如果要删除一个角色,可以使用SQL命令DROP ROLE。角色的删除是通过调用DropRole函数来实现的,该函数只有一个类型为DropRoleStmt结构的参数。相关代码如下:

typedef struct DropRoleStmt {
    NodeTagtype;
    List*roles;               /*  要删除的角色列表  */
    boolmissing_ok;          /*  判断角色是否存在  */
    boolis_user;             /*  要删除的是角色还是用户  */
    boolinherit_from_parent;  /*  是否继承自父角色*/
    DropBehavior behavior;            /*  是否级联删除依赖对象  */
} DropRoleStmt;

删除角色的流程如图9-16所示。
在这里插入图片描述

图9-16 openGauss角色删除流程图

角色删除的执行流程为:首先判断当前操作者是否有权限执行该操作,若没有则报错退出;然后检查待删除的角色是否存在,若不存在,则根据missing_ok选择返回ERROR或NOTICE提示信息;再通过扫描系统表pg_authid和pg_auth_members,删除所有涉及待删除角色的元组执行;若behavior取值DROP_CASCADE,则级联删除该角色所拥有的所有数据库对象;最后删除该角色在系统表pg_auth_history和pg_user_status中对应的信息。具体的实现过程代码如下:

void DropRole(DropRoleStmt* stmt)
{
    . . .
/*  检查执行者是否有权限删除角色  */
    if (!have_createrole_privilege())
        ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied to drop role.")));
/*  循环处理要删除的角色  */
    foreach (item, stmt->roles) {
. . .
/*  检查要删除的角色是否存在,若不存在则提示报错  */
        HeapTuple tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
        if (!HeapTupleIsValid(tuple)) {
            if (!stmt->missing_ok) {
                ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", role)));
            } else {
                ereport(NOTICE, (errmsg("role \"%s\" does not exist, skipping", role)));
            }
            continue;
        }
        . . .
/*  当前用户不允许删除  */
        if (roleid == GetUserId())
            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("current user cannot be dropped")));
        if (roleid == GetOuterUserId())
            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("current user cannot be dropped")));
        if (roleid == GetSessionUserId())
            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("session user cannot be dropped")));
        /*  校验执行者和被删除角色的权限,如系统管理员才有权限删除其他系统管理员  */
        if((((Form_pg_authid)GETSTRUCT(tuple))->rolsuper|| ((Form_pg_authid)GETSTRUCT(tuple))->rolsystemadmin) &&
            !isRelSuperuser())
            ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
        if ((((Form_pg_authid)GETSTRUCT(tuple))->rolauditadmin) &&
            g_instance.attr.attr_security.enablePrivilegesSeparate && !isRelSuperuser())
            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
        . . .
    /*  针对CASCADE(级联)的情况,删除该角色拥有的对象  */
        if (stmt->behavior == DROP_CASCADE) {
            char* user = NULL;
            CancelQuery(role);
            user = (char*)palloc(sizeof(char) * strlen(role) + 1);
            errno_t errorno = strncpy_s(user, strlen(role) + 1, role, strlen(role));
            securec_check(errorno, "\0", "\0");
            drop_objectstmt.behavior = stmt->behavior;
            drop_objectstmt.type = T_DropOwnedStmt;
            drop_objectstmt.roles = list_make1(makeString(user));

            DropOwnedObjects(&drop_objectstmt);
            list_free_deep(drop_objectstmt.roles);
        }

        /*  检查是否有对象依赖于该角色,若还存在依赖,则提示报错  */
        if (checkSharedDependencies(AuthIdRelationId, roleid, &detail, &detail_log))
            ereport(ERROR,
                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
                    errmsg("role \"%s\" cannot be dropped because some objects depend on it", role),
                    errdetail_internal("%s", detail),
                    errdetail_log("%s", detail_log)));
        /*  从相关系统表中删除涉及待删除角色的元组  */
        simple_heap_delete(pg_authid_rel, &tuple->t_self);
. . .
        while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan))) {
            simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
        }

        systable_endscan(sscan);
        DropAuthHistory(roleid);
        DropUserStatus(roleid);
        DeleteSharedComments(roleid, AuthIdRelationId);
        DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
        DropSetting(InvalidOid, roleid);
. . .
    heap_close(pg_auth_members_rel, NoLock);
    heap_close(pg_authid_rel, NoLock);
}

3. 授予和回收角色

如果要授予或回收角色的成员关系,可以使用SQL命令“GRANT/REVOKE”。如果声明了“WITH ADMIN OPTION”选项,那么被加入的成员角色还可以将其他角色加入到父角色中。角色的授予或回收通过调用GrantRole函数来实现,该函数只有一个类型为GrantRoleStmt结构的参数。相关代码如下:

typedef struct GrantRoleStmt {
    NodeTag type;
    List* granted_roles;/*  被授予或回收的角色集合  */
    List* grantee_roles;/*  从granted_roles中增加或删除的角色集合  */
    Bool is_grant;/*  true代表授权,false代表回收  */
    Bool admin_opt;/*  是否带有with admin option选项  */
    char* grantor;/*  授权者  */
    Drop Behaviorbehavior;/*  是否级联回收角色  */
} GrantRoleStmt;

授予角色时,grantee_roles中的角色将被添加到granted_roles,通过调用函数AddRoleMems实现;回收角色时,将grantee_roles中的角色从granted_roles中删除,通过调用函数DelRoleMems实现。
函数AddRoleMems的实现流程如图9-17所示。
在这里插入图片描述

图9-17 openGauss增加用户成员流程图

函数AddRoleMems的具体实现代码如下,其中:
(1) rolename和roleid分别表示要被加入成员的角色的名称和OID。
(2) memberNames和memberIds分别是要添加的角色名称和OID的列表。
(3) grantorId表示授权者的OID。
(4) admin_opt表示是否带有with admin option选项。

static void AddRoleMems(
    const char* rolename, Oid roleid, const List* memberNames, List* memberIds, Oid grantorId, bool admin_opt)
{
. . .
    /*  校验执行者的权限  */
    if (superuser_arg(roleid)) {
        if (!isRelSuperuser())
            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
    . . .
    } 
. . .
    if (grantorId != GetUserId() && !superuser())
        ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to set grantor")));
/*  循环处理要添加的角色  */
    pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
    pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);

    forboth(nameitem, memberNames, iditem, memberIds)
    {
        /*  针对角色和成员信息创建pg_auth_members元组,再将新元组插入到系统表中  */
. . .
        new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
        new_record[Anum_pg_auth_members_member -1] = ObjectIdGetDatum(memberid);
        new_record[Anum_pg_auth_members_grantor -  1] = ObjectIdGetDatum(grantorId);
        new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);

        if (HeapTupleIsValid(authmem_tuple)) {
            new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
            new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
            tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, new_record, new_record_nulls, new_record_repl);
            simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
            CatalogUpdateIndexes(pg_authmem_rel, tuple);
            ReleaseSysCache(authmem_tuple);
        } else {
            tuple = heap_form_tuple(pg_authmem_dsc, new_record, new_record_nulls);
            (void)simple_heap_insert(pg_authmem_rel, tuple);
            CatalogUpdateIndexes(pg_authmem_rel, tuple);
        }
    }
. . .
    heap_close(pg_authmem_rel, NoLock);
}

函数DelRoleMems的实现过程类似。首先对执行者的相关权限进行校验,然后循环处理要删除的角色,删除系统表pg_auth_member中相关的元组。

感谢大家学习第9章 安全管理源码解析中“9.3 角色管理”的精彩内容,下一篇我们开启“9.4 对象权限管理”的相关内容的介绍。
敬请期待。

💜走过路过,看到这里了,还请各位小伙伴点赞、收藏、评论,千言万语,不胜感谢💜


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK