diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/user.c | 262 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 49 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/acl.c | 47 |
4 files changed, 267 insertions, 93 deletions
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 511ca8d8fd1..265a48af7eb 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -51,6 +51,9 @@ * RRG_REMOVE_ADMIN_OPTION indicates a grant that would need to have * admin_option set to false by the operation. * + * RRG_REMOVE_INHERIT_OPTION indicates a grant that would need to have + * inherit_option set to false by the operation. + * * RRG_DELETE_GRANT indicates a grant that would need to be removed entirely * by the operation. */ @@ -58,12 +61,22 @@ typedef enum { RRG_NOOP, RRG_REMOVE_ADMIN_OPTION, + RRG_REMOVE_INHERIT_OPTION, RRG_DELETE_GRANT } RevokeRoleGrantAction; /* Potentially set by pg_upgrade_support functions */ Oid binary_upgrade_next_pg_authid_oid = InvalidOid; +typedef struct +{ + unsigned specified; + bool admin; + bool inherit; +} GrantRoleOptions; + +#define GRANT_ROLE_SPECIFIED_ADMIN 0x0001 +#define GRANT_ROLE_SPECIFIED_INHERIT 0x0002 /* GUC parameter */ int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256; @@ -73,17 +86,18 @@ check_password_hook_type check_password_hook = NULL; static void AddRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, - Oid grantorId, bool admin_opt); + Oid grantorId, GrantRoleOptions *popt); static void DelRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, - Oid grantorId, bool admin_opt, DropBehavior behavior); + Oid grantorId, GrantRoleOptions *popt, + DropBehavior behavior); static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant); static RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist); static bool plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, Oid member, Oid grantor, - bool revoke_admin_option_only, + GrantRoleOptions *popt, DropBehavior behavior); static void plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, Oid member); @@ -92,6 +106,7 @@ static void plan_recursive_revoke(CatCList *memlist, int index, bool revoke_admin_option_only, DropBehavior behavior); +static void InitGrantRoleOptions(GrantRoleOptions *popt); /* Check if current user has createrole privileges */ @@ -144,6 +159,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) DefElem *dadminmembers = NULL; DefElem *dvalidUntil = NULL; DefElem *dbypassRLS = NULL; + GrantRoleOptions popt; /* The defaults can vary depending on the original statement type */ switch (stmt->stmt_type) @@ -462,6 +478,9 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) if (addroleto || adminmembers || rolemembers) CommandCounterIncrement(); + /* Default grant. */ + InitGrantRoleOptions(&popt); + /* * Add the new role to the specified existing roles. */ @@ -486,7 +505,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) AddRoleMems(oldrolename, oldroleid, thisrole_list, thisrole_oidlist, - InvalidOid, false); + InvalidOid, &popt); ReleaseSysCache(oldroletup); } @@ -497,11 +516,13 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) * option, rolemembers don't. */ AddRoleMems(stmt->role, roleid, - adminmembers, roleSpecsToIds(adminmembers), - InvalidOid, true); - AddRoleMems(stmt->role, roleid, rolemembers, roleSpecsToIds(rolemembers), - InvalidOid, false); + InvalidOid, &popt); + popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN; + popt.admin = true; + AddRoleMems(stmt->role, roleid, + adminmembers, roleSpecsToIds(adminmembers), + InvalidOid, &popt); /* Post creation hook for new role */ InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0); @@ -552,6 +573,7 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) DefElem *dvalidUntil = NULL; DefElem *dbypassRLS = NULL; Oid roleid; + GrantRoleOptions popt; check_rolespec_name(stmt->role, "Cannot alter reserved roles."); @@ -843,6 +865,8 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) ReleaseSysCache(tuple); heap_freetuple(new_tuple); + InitGrantRoleOptions(&popt); + /* * Advance command counter so we can see new record; else tests in * AddRoleMems may fail. @@ -856,11 +880,11 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) if (stmt->action == +1) /* add members to role */ AddRoleMems(rolename, roleid, rolemembers, roleSpecsToIds(rolemembers), - InvalidOid, false); + InvalidOid, &popt); else if (stmt->action == -1) /* drop members from role */ DelRoleMems(rolename, roleid, rolemembers, roleSpecsToIds(rolemembers), - InvalidOid, false, DROP_RESTRICT); + InvalidOid, &popt, DROP_RESTRICT); } /* @@ -1337,13 +1361,48 @@ RenameRole(const char *oldname, const char *newname) * Grant/Revoke roles to/from roles */ void -GrantRole(GrantRoleStmt *stmt) +GrantRole(ParseState *pstate, GrantRoleStmt *stmt) { Relation pg_authid_rel; Oid grantor; List *grantee_ids; ListCell *item; + GrantRoleOptions popt; + + /* Parse options list. */ + InitGrantRoleOptions(&popt); + foreach(item, stmt->opt) + { + DefElem *opt = (DefElem *) lfirst(item); + char *optval = defGetString(opt); + + if (strcmp(opt->defname, "admin") == 0) + { + popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN; + + if (parse_bool(optval, &popt.admin)) + continue; + } + else if (strcmp(opt->defname, "inherit") == 0) + { + popt.specified |= GRANT_ROLE_SPECIFIED_INHERIT; + if (parse_bool(optval, &popt.inherit)) + continue; + } + else + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized role option \"%s\"", opt->defname), + parser_errposition(pstate, opt->location)); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized value for role option \"%s\": \"%s\"", + opt->defname, optval), + parser_errposition(pstate, opt->location))); + } + /* Lookup OID of grantor, if specified. */ if (stmt->grantor) grantor = get_rolespec_oid(stmt->grantor, false); else @@ -1355,11 +1414,11 @@ GrantRole(GrantRoleStmt *stmt) pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock); /* - * 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 + * Step through all of the granted roles and add, update, or remove + * entries in pg_auth_members as appropriate. If stmt->is_grant is true, + * we are adding new grants or, if they already exist, updating options + * on those grants. If stmt->is_grant is false, we are revoking grants or + * removing options from them. */ foreach(item, stmt->granted_roles) { @@ -1377,11 +1436,11 @@ GrantRole(GrantRoleStmt *stmt) if (stmt->is_grant) AddRoleMems(rolename, roleid, stmt->grantee_roles, grantee_ids, - grantor, stmt->admin_opt); + grantor, &popt); else DelRoleMems(rolename, roleid, stmt->grantee_roles, grantee_ids, - grantor, stmt->admin_opt, stmt->behavior); + grantor, &popt, stmt->behavior); } /* @@ -1483,12 +1542,12 @@ roleSpecsToIds(List *memberNames) * memberSpecs: list of RoleSpec of roles to add (used only for error messages) * memberIds: OIDs of roles to add * grantorId: who is granting the membership (InvalidOid if not set explicitly) - * admin_opt: granting admin option? + * popt: information about grant options */ static void AddRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, - Oid grantorId, bool admin_opt) + Oid grantorId, GrantRoleOptions *popt) { Relation pg_authmem_rel; TupleDesc pg_authmem_dsc; @@ -1607,7 +1666,7 @@ AddRoleMems(const char *rolename, Oid roleid, * has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on * X back to A). */ - if (admin_opt && grantorId != BOOTSTRAP_SUPERUSERID) + if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID) { CatCList *memlist; RevokeRoleGrantAction *actions; @@ -1669,25 +1728,55 @@ AddRoleMems(const char *rolename, Oid roleid, Datum new_record[Natts_pg_auth_members] = {0}; bool new_record_nulls[Natts_pg_auth_members] = {0}; bool new_record_repl[Natts_pg_auth_members] = {0}; - Form_pg_auth_members authmem_form; - /* - * Check if entry for this role/member already exists; if so, give - * warning unless we are adding admin option. - */ + /* Common initialization for possible insert or update */ + 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); + + /* Find any existing tuple */ authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid), ObjectIdGetDatum(memberid), ObjectIdGetDatum(grantorId)); - if (!HeapTupleIsValid(authmem_tuple)) - { - authmem_form = NULL; - } - else + + /* + * If we found a tuple, update it with new option values, unless + * there are no changes, in which case issue a WARNING. + * + * If we didn't find a tuple, just insert one. + */ + if (HeapTupleIsValid(authmem_tuple)) { + Form_pg_auth_members authmem_form; + bool at_least_one_change = false; + authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple); - if (!admin_opt || authmem_form->admin_option) + if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0 + && authmem_form->admin_option != popt->admin) + { + new_record[Anum_pg_auth_members_admin_option - 1] = + BoolGetDatum(popt->admin); + new_record_repl[Anum_pg_auth_members_admin_option - 1] = + true; + at_least_one_change = true; + } + + if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0 + && authmem_form->inherit_option != popt->inherit) + { + new_record[Anum_pg_auth_members_inherit_option - 1] = + BoolGetDatum(popt->inherit); + new_record_repl[Anum_pg_auth_members_inherit_option - 1] = + true; + at_least_one_change = true; + } + + if (!at_least_one_change) { ereport(NOTICE, (errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"", @@ -1696,17 +1785,7 @@ AddRoleMems(const char *rolename, Oid roleid, ReleaseSysCache(authmem_tuple); continue; } - } - /* Build a tuple to insert or update */ - 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_admin_option - 1] = true; tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, new_record, new_record_nulls, new_record_repl); @@ -1719,6 +1798,33 @@ AddRoleMems(const char *rolename, Oid roleid, Oid objectId; Oid *newmembers = palloc(sizeof(Oid)); + /* Set admin option if user set it to true, otherwise not. */ + new_record[Anum_pg_auth_members_admin_option - 1] = + BoolGetDatum(popt->admin); + + /* + * If the user specified a value for the inherit option, use + * whatever was specified. Otherwise, set the default value based + * on the role-level property. + */ + if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0) + new_record[Anum_pg_auth_members_inherit_option - 1] = + popt->inherit; + else + { + HeapTuple mrtup; + Form_pg_authid mrform; + + mrtup = SearchSysCache1(AUTHOID, memberid); + if (!HeapTupleIsValid(mrtup)) + elog(ERROR, "cache lookup failed for role %u", memberid); + mrform = (Form_pg_authid) GETSTRUCT(mrtup); + new_record[Anum_pg_auth_members_inherit_option - 1] = + mrform->rolinherit; + ReleaseSysCache(mrtup); + } + + /* get an OID for the new row and insert it */ objectId = GetNewObjectId(); new_record[Anum_pg_auth_members_oid - 1] = objectId; tuple = heap_form_tuple(pg_authmem_dsc, @@ -1751,13 +1857,13 @@ AddRoleMems(const char *rolename, Oid roleid, * memberSpecs: list of RoleSpec of roles to del (used only for error messages) * memberIds: OIDs of roles to del * grantorId: who is revoking the membership - * admin_opt: remove admin option only? + * popt: information about grant options * behavior: RESTRICT or CASCADE behavior for recursive removal */ static void DelRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, - Oid grantorId, bool admin_opt, DropBehavior behavior) + Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior) { Relation pg_authmem_rel; TupleDesc pg_authmem_dsc; @@ -1824,7 +1930,7 @@ DelRoleMems(const char *rolename, Oid roleid, Oid memberid = lfirst_oid(iditem); if (!plan_single_revoke(memlist, actions, memberid, grantorId, - admin_opt, behavior)) + popt, behavior)) { ereport(WARNING, (errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"", @@ -1862,15 +1968,29 @@ DelRoleMems(const char *rolename, Oid roleid, } else { - /* Just turn off the admin option */ + /* Just turn off the specified option */ HeapTuple tuple; Datum new_record[Natts_pg_auth_members] = {0}; bool new_record_nulls[Natts_pg_auth_members] = {0}; bool new_record_repl[Natts_pg_auth_members] = {0}; /* Build a tuple to update with */ - new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false); - new_record_repl[Anum_pg_auth_members_admin_option - 1] = true; + if (actions[i] == RRG_REMOVE_ADMIN_OPTION) + { + new_record[Anum_pg_auth_members_admin_option - 1] = + BoolGetDatum(false); + new_record_repl[Anum_pg_auth_members_admin_option - 1] = + true; + } + else if (actions[i] == RRG_REMOVE_INHERIT_OPTION) + { + new_record[Anum_pg_auth_members_inherit_option - 1] = + BoolGetDatum(false); + new_record_repl[Anum_pg_auth_members_inherit_option - 1] = + true; + } + else + elog(ERROR, "unknown role revoke action"); tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, new_record, @@ -2028,11 +2148,21 @@ initialize_revoke_actions(CatCList *memlist) */ static bool plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, - Oid member, Oid grantor, bool revoke_admin_option_only, + Oid member, Oid grantor, GrantRoleOptions *popt, DropBehavior behavior) { int i; + /* + * If popt.specified == 0, we're revoking the grant entirely; otherwise, + * we expect just one bit to be set, and we're revoking the corresponding + * option. As of this writing, there's no syntax that would allow for + * an attempt to revoke multiple options at once, and the logic below + * wouldn't work properly if such syntax were added, so assert that our + * caller isn't trying to do that. + */ + Assert(pg_popcount32(popt->specified) <= 1); + for (i = 0; i < memlist->n_members; ++i) { HeapTuple authmem_tuple; @@ -2044,8 +2174,27 @@ plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, if (authmem_form->member == member && authmem_form->grantor == grantor) { - plan_recursive_revoke(memlist, actions, i, - revoke_admin_option_only, behavior); + if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0) + { + /* + * Revoking the INHERIT option doesn't change anything for + * dependent privileges, so we don't need to recurse. + */ + actions[i] = RRG_REMOVE_INHERIT_OPTION; + } + else + { + bool revoke_admin_option_only; + + /* + * Revoking the grant entirely, or ADMIN option on a grant, + * implicates dependent privileges, so we may need to recurse. + */ + revoke_admin_option_only = + (popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0; + plan_recursive_revoke(memlist, actions, i, + revoke_admin_option_only, behavior); + } return true; } } @@ -2172,3 +2321,14 @@ plan_recursive_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, } } } + +/* + * Initialize a GrantRoleOptions object with default values. + */ +static void +InitGrantRoleOptions(GrantRoleOptions *popt) +{ + popt->specified = 0; + popt->admin = false; + popt->inherit = false; +} diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c8bd66dd543..b5ab9d9c9a3 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -362,9 +362,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> utility_option_arg %type <defelt> drop_option %type <boolean> opt_or_replace opt_no - opt_grant_grant_option opt_grant_admin_option + opt_grant_grant_option opt_nowait opt_if_exists opt_with_data opt_transaction_chain +%type <list> grant_role_opt_list +%type <defelt> grant_role_opt +%type <node> grant_role_opt_value %type <ival> opt_nowait_or_skip %type <list> OptRoleList AlterOptRoleList @@ -7848,15 +7851,26 @@ opt_grant_grant_option: *****************************************************************************/ GrantRoleStmt: - GRANT privilege_list TO role_list opt_grant_admin_option opt_granted_by + GRANT privilege_list TO role_list opt_granted_by { GrantRoleStmt *n = makeNode(GrantRoleStmt); n->is_grant = true; n->granted_roles = $2; n->grantee_roles = $4; - n->admin_opt = $5; - n->grantor = $6; + n->opt = NIL; + n->grantor = $5; + $$ = (Node *) n; + } + | GRANT privilege_list TO role_list WITH grant_role_opt_list opt_granted_by + { + GrantRoleStmt *n = makeNode(GrantRoleStmt); + + n->is_grant = true; + n->granted_roles = $2; + n->grantee_roles = $4; + n->opt = $6; + n->grantor = $7; $$ = (Node *) n; } ; @@ -7867,19 +7881,22 @@ RevokeRoleStmt: GrantRoleStmt *n = makeNode(GrantRoleStmt); n->is_grant = false; - n->admin_opt = false; + n->opt = NIL; n->granted_roles = $2; n->grantee_roles = $4; n->grantor = $5; n->behavior = $6; $$ = (Node *) n; } - | REVOKE ADMIN OPTION FOR privilege_list FROM role_list opt_granted_by opt_drop_behavior + | REVOKE ColId OPTION FOR privilege_list FROM role_list opt_granted_by opt_drop_behavior { GrantRoleStmt *n = makeNode(GrantRoleStmt); + DefElem *opt; + opt = makeDefElem(pstrdup($2), + (Node *) makeBoolean(false), @2); n->is_grant = false; - n->admin_opt = true; + n->opt = list_make1(opt); n->granted_roles = $5; n->grantee_roles = $7; n->grantor = $8; @@ -7888,8 +7905,22 @@ RevokeRoleStmt: } ; -opt_grant_admin_option: WITH ADMIN OPTION { $$ = true; } - | /*EMPTY*/ { $$ = false; } +grant_role_opt_list: + grant_role_opt_list ',' grant_role_opt { $$ = lappend($1, $3); } + | grant_role_opt { $$ = list_make1($1); } + ; + +grant_role_opt: + ColLabel grant_role_opt_value + { + $$ = makeDefElem(pstrdup($1), $2, @1); + } + ; + +grant_role_opt_value: + OPTION { $$ = (Node *) makeBoolean(true); } + | TRUE_P { $$ = (Node *) makeBoolean(true); } + | FALSE_P { $$ = (Node *) makeBoolean(false); } ; opt_granted_by: GRANTED BY RoleSpec { $$ = $3; } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6b0a8652622..aa008157878 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -767,7 +767,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, case T_GrantRoleStmt: /* no event triggers for global objects */ - GrantRole((GrantRoleStmt *) parsetree); + GrantRole(pstate, (GrantRoleStmt *) parsetree); break; case T_CreatedbStmt: diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 3e045da31fc..ea28da26a89 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -66,7 +66,7 @@ typedef struct */ enum RoleRecurseType { - ROLERECURSE_PRIVS = 0, /* recurse if rolinherit */ + ROLERECURSE_PRIVS = 0, /* recurse through inheritable grants */ ROLERECURSE_MEMBERS = 1 /* recurse unconditionally */ }; static Oid cached_role[] = {InvalidOid, InvalidOid}; @@ -4735,8 +4735,8 @@ initialize_acl(void) /* * In normal mode, set a callback on any syscache invalidation of rows - * of pg_auth_members (for roles_is_member_of()), pg_authid (for - * has_rolinherit()), or pg_database (for roles_is_member_of()) + * of pg_auth_members (for roles_is_member_of()) pg_database (for + * roles_is_member_of()) */ CacheRegisterSyscacheCallback(AUTHMEMROLEMEM, RoleMembershipCacheCallback, @@ -4769,29 +4769,11 @@ RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue) cached_role[ROLERECURSE_MEMBERS] = InvalidOid; } - -/* Check if specified role has rolinherit set */ -static bool -has_rolinherit(Oid roleid) -{ - bool result = false; - HeapTuple utup; - - utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); - if (HeapTupleIsValid(utup)) - { - result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit; - ReleaseSysCache(utup); - } - return result; -} - - /* * Get a list of roles that the specified roleid is a member of * - * Type ROLERECURSE_PRIVS recurses only through roles that have rolinherit - * set, while ROLERECURSE_MEMBERS recurses through all roles. + * Type ROLERECURSE_PRIVS recurses only through inheritable grants, + * while ROLERECURSE_MEMBERS recurses through all grants. * * Since indirect membership testing is relatively expensive, we cache * a list of memberships. Hence, the result is only guaranteed good until @@ -4861,23 +4843,24 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type, CatCList *memlist; int i; - if (type == ROLERECURSE_PRIVS && !has_rolinherit(memberid)) - continue; /* ignore non-inheriting roles */ - /* Find roles that memberid is directly a member of */ memlist = SearchSysCacheList1(AUTHMEMMEMROLE, ObjectIdGetDatum(memberid)); for (i = 0; i < memlist->n_members; i++) { HeapTuple tup = &memlist->members[i]->tuple; - Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid; + Form_pg_auth_members form = (Form_pg_auth_members) GETSTRUCT(tup); + Oid otherid = form->roleid; + + /* If we're supposed to ignore non-heritable grants, do so. */ + if (type == ROLERECURSE_PRIVS && !form->inherit_option) + continue; /* * While otherid==InvalidOid shouldn't appear in the catalog, the * OidIsValid() avoids crashing if that arises. */ - if (otherid == admin_of && - ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option && + if (otherid == admin_of && form->admin_option && OidIsValid(admin_of) && !OidIsValid(*admin_role)) *admin_role = memberid; @@ -4920,8 +4903,8 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type, /* * Does member have the privileges of role (directly or indirectly)? * - * This is defined not to recurse through roles that don't have rolinherit - * set; for such roles, membership implies the ability to do SET ROLE, but + * This is defined not to recurse through grants that are not inherited; + * in such cases, membership implies the ability to do SET ROLE, but * the privileges are not available until you've done so. */ bool @@ -4948,7 +4931,7 @@ has_privs_of_role(Oid member, Oid role) /* * Is member a member of role (directly or indirectly)? * - * This is defined to recurse through roles regardless of rolinherit. + * This is defined to recurse through grants whether they are inherited or not. * * Do not use this for privilege checking, instead use has_privs_of_role() */ |