openGauss源码解析(197)
openGauss源码解析:安全管理源码解析(8)
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);
}