📄 user.c
字号:
/* * Now we can clean up; but keep locks until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_auth_members_rel, NoLock); heap_close(pg_authid_rel, NoLock); /* * Set flag to update flat auth file at commit. */ auth_file_update_needed();}/* * Rename role */voidRenameRole(const char *oldname, const char *newname){ HeapTuple oldtuple, newtuple; TupleDesc dsc; Relation rel; Datum datum; bool isnull; Datum repl_val[Natts_pg_authid]; char repl_null[Natts_pg_authid]; char repl_repl[Natts_pg_authid]; int i; Oid roleid; /* ExclusiveLock because we need to update the flat auth file */ rel = heap_open(AuthIdRelationId, ExclusiveLock); dsc = RelationGetDescr(rel); oldtuple = SearchSysCache(AUTHNAME, CStringGetDatum(oldname), 0, 0, 0); if (!HeapTupleIsValid(oldtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", oldname))); /* * XXX Client applications probably store the session user somewhere, so * renaming it could cause confusion. On the other hand, there may not be * an actual problem besides a little confusion, so think about this and * decide. Same for SET ROLE ... we don't restrict renaming the current * effective userid, though. */ roleid = HeapTupleGetOid(oldtuple); if (roleid == GetSessionUserId()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("session user may not be renamed"))); if (roleid == GetOuterUserId()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("current user may not be renamed"))); /* make sure the new name doesn't exist */ if (SearchSysCacheExists(AUTHNAME, CStringGetDatum(newname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("role \"%s\" already exists", newname))); if (strcmp(newname, "public") == 0 || strcmp(newname, "none") == 0) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("role name \"%s\" is reserved", newname))); /* * createrole is enough privilege unless you want to mess with a superuser */ if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper) { if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to rename superusers"))); } else { if (!have_createrole_privilege()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to rename role"))); } /* OK, construct the modified tuple */ for (i = 0; i < Natts_pg_authid; i++) repl_repl[i] = ' '; repl_repl[Anum_pg_authid_rolname - 1] = 'r'; repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, CStringGetDatum(newname)); repl_null[Anum_pg_authid_rolname - 1] = ' '; datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull); if (!isnull && isMD5(DatumGetCString(DirectFunctionCall1(textout, datum)))) { /* MD5 uses the username as salt, so just clear it on a rename */ repl_repl[Anum_pg_authid_rolpassword - 1] = 'r'; repl_null[Anum_pg_authid_rolpassword - 1] = 'n'; ereport(NOTICE, (errmsg("MD5 password cleared because of role rename"))); } newtuple = heap_modifytuple(oldtuple, dsc, repl_val, repl_null, repl_repl); simple_heap_update(rel, &oldtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); ReleaseSysCache(oldtuple); heap_close(rel, NoLock); /* * Set flag to update flat auth file at commit. */ auth_file_update_needed();}/* * GrantRoleStmt * * Grant/Revoke roles to/from roles */voidGrantRole(GrantRoleStmt *stmt){ Relation pg_authid_rel; Oid grantor; List *grantee_ids; ListCell *item; if (stmt->grantor) grantor = get_roleid_checked(stmt->grantor); else grantor = GetUserId(); grantee_ids = roleNamesToIds(stmt->grantee_roles); /* * Even though this operation doesn't change pg_authid, we must secure * exclusive lock on it to protect our update of the flat auth file. */ pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); /* * Step through all of the granted roles and add/remove entries for the * grantees, or, if admin_opt is set, then just add/remove the admin * option. * * Note: Permissions checking is done by AddRoleMems/DelRoleMems */ foreach(item, stmt->granted_roles) { char *rolename = strVal(lfirst(item)); Oid roleid = get_roleid_checked(rolename); if (stmt->is_grant) AddRoleMems(rolename, roleid, stmt->grantee_roles, grantee_ids, grantor, stmt->admin_opt); else DelRoleMems(rolename, roleid, stmt->grantee_roles, grantee_ids, stmt->admin_opt); } heap_close(pg_authid_rel, NoLock); /* * Set flag to update flat auth file at commit. */ auth_file_update_needed();}/* * roleNamesToIds * * Given a list of role names (as String nodes), generate a list of role OIDs * in the same order. */static List *roleNamesToIds(List *memberNames){ List *result = NIL; ListCell *l; foreach(l, memberNames) { char *rolename = strVal(lfirst(l)); Oid roleid = get_roleid_checked(rolename); result = lappend_oid(result, roleid); } return result;}/* * AddRoleMems -- Add given members to the specified role * * rolename: name of role to add to (used only for error messages) * roleid: OID of role to add to * memberNames: list of names of roles to add (used only for error messages) * memberIds: OIDs of roles to add * grantorId: who is granting the membership * admin_opt: granting admin option? * * Note: caller is responsible for holding ExclusiveLock on pg_authid, * and for calling auth_file_update_needed(). */static voidAddRoleMems(const char *rolename, Oid roleid, List *memberNames, List *memberIds, Oid grantorId, bool admin_opt){ Relation pg_authmem_rel; TupleDesc pg_authmem_dsc; ListCell *nameitem; ListCell *iditem; Assert(list_length(memberNames) == list_length(memberIds)); /* Skip permission check if nothing to do */ if (!memberIds) return; /* * Check permissions: must have createrole or admin option on the role to * be changed. To mess with a superuser role, you gotta be superuser. */ if (superuser_arg(roleid)) { if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to alter superusers"))); } else { if (!have_createrole_privilege() && !is_admin_of_role(grantorId, roleid)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must have admin option on role \"%s\"", rolename))); } /* XXX not sure about this check */ if (grantorId != GetUserId() && !superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to set grantor"))); /* We need only regular writer's lock on pg_auth_members */ pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); forboth(nameitem, memberNames, iditem, memberIds) { const char *membername = strVal(lfirst(nameitem)); Oid memberid = lfirst_oid(iditem); HeapTuple authmem_tuple; HeapTuple tuple; Datum new_record[Natts_pg_auth_members]; char new_record_nulls[Natts_pg_auth_members]; char new_record_repl[Natts_pg_auth_members]; /* * Refuse creation of membership loops, including the trivial case * where a role is made a member of itself. We do this by checking to * see if the target role is already a member of the proposed member * role. We have to ignore possible superuserness, however, else we * could never grant membership in a superuser-privileged role. */ if (is_member_of_role_nosuper(roleid, memberid)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), (errmsg("role \"%s\" is a member of role \"%s\"", rolename, membername)))); /* * Check if entry for this role/member already exists; if so, give * warning unless we are adding admin option. */ authmem_tuple = SearchSysCache(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid), ObjectIdGetDatum(memberid), 0, 0); if (HeapTupleIsValid(authmem_tuple) && (!admin_opt || ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option)) { ereport(NOTICE, (errmsg("role \"%s\" is already a member of role \"%s\"", membername, rolename))); ReleaseSysCache(authmem_tuple); continue; } /* Build a tuple to insert or update */ MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); 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] = 'r'; new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r'; tuple = heap_modifytuple(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_formtuple(pg_authmem_dsc, new_record, new_record_nulls); simple_heap_insert(pg_authmem_rel, tuple); CatalogUpdateIndexes(pg_authmem_rel, tuple); } /* CCI after each change, in case there are duplicates in list */ CommandCounterIncrement(); } /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_authmem_rel, NoLock);}/* * DelRoleMems -- Remove given members from the specified role * * rolename: name of role to del from (used only for error messages) * roleid: OID of role to del from * memberNames: list of names of roles to del (used only for error messages) * memberIds: OIDs of roles to del * admin_opt: remove admin option only? * * Note: caller is responsible for holding ExclusiveLock on pg_authid, * and for calling auth_file_update_needed(). */static voidDelRoleMems(const char *rolename, Oid roleid, List *memberNames, List *memberIds, bool admin_opt){ Relation pg_authmem_rel; TupleDesc pg_authmem_dsc; ListCell *nameitem; ListCell *iditem; Assert(list_length(memberNames) == list_length(memberIds)); /* Skip permission check if nothing to do */ if (!memberIds) return; /* * Check permissions: must have createrole or admin option on the role to * be changed. To mess with a superuser role, you gotta be superuser. */ if (superuser_arg(roleid)) { if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to alter superusers"))); } else { if (!have_createrole_privilege() && !is_admin_of_role(GetUserId(), roleid)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must have admin option on role \"%s\"", rolename))); } /* We need only regular writer's lock on pg_auth_members */ pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); forboth(nameitem, memberNames, iditem, memberIds) { const char *membername = strVal(lfirst(nameitem)); Oid memberid = lfirst_oid(iditem); HeapTuple authmem_tuple; /* * Find entry for this role/member */ authmem_tuple = SearchSysCache(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid), ObjectIdGetDatum(memberid), 0, 0); if (!HeapTupleIsValid(authmem_tuple)) { ereport(WARNING, (errmsg("role \"%s\" is not a member of role \"%s\"", membername, rolename))); continue; } if (!admin_opt) { /* Remove the entry altogether */ simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self); } else { /* Just turn off the admin option */ HeapTuple tuple; Datum new_record[Natts_pg_auth_members]; char new_record_nulls[Natts_pg_auth_members]; char new_record_repl[Natts_pg_auth_members]; /* Build a tuple to update with */ MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false); new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r'; tuple = heap_modifytuple(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); /* CCI after each change, in case there are duplicates in list */ CommandCounterIncrement(); } /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_authmem_rel, NoLock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -