diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index aed01cf4cae..2f0e6c09b0f 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -69,14 +69,6 @@ typedef enum /* Potentially set by pg_upgrade_support functions */ Oid binary_upgrade_next_pg_authid_oid = InvalidOid; -typedef struct -{ - unsigned specified; - bool admin; - bool inherit; - bool set; -} GrantRoleOptions; - #define GRANT_ROLE_SPECIFIED_ADMIN 0x0001 #define GRANT_ROLE_SPECIFIED_INHERIT 0x0002 #define GRANT_ROLE_SPECIFIED_SET 0x0004 @@ -89,7 +81,7 @@ GrantRoleOptions createrole_self_grant_options; /* Hook to check passwords in CreateRole() and AlterRole() */ check_password_hook_type check_password_hook = NULL; - +CheckRoleMembershipAuthorization_hook_type CheckRoleMembershipAuthorization_hook = NULL; static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt); @@ -98,7 +90,7 @@ static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior); static void check_role_membership_authorization(Oid currentUserId, Oid roleid, - bool is_grant); + bool is_grant, List* memberIds, GrantRoleOptions * popt); static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant); static RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist); @@ -517,7 +509,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) char *oldrolename = NameStr(oldroleform->rolname); /* can only add this role to roles for which you have rights */ - check_role_membership_authorization(currentUserId, oldroleid, true); + check_role_membership_authorization(currentUserId, oldroleid, true, thisrole_oidlist, &popt); AddRoleMems(currentUserId, oldrolename, oldroleid, thisrole_list, thisrole_oidlist, @@ -1557,7 +1549,7 @@ GrantRole(ParseState *pstate, GrantRoleStmt *stmt) roleid = get_role_oid(rolename, false); check_role_membership_authorization(currentUserId, - roleid, stmt->is_grant); + roleid, stmt->is_grant, grantee_ids, &popt); if (stmt->is_grant) AddRoleMems(currentUserId, rolename, roleid, stmt->grantee_roles, grantee_ids, @@ -2108,7 +2100,7 @@ DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, */ static void check_role_membership_authorization(Oid currentUserId, Oid roleid, - bool is_grant) + bool is_grant, List *memberIds, GrantRoleOptions * popt) { /* * The charter of pg_database_owner is to have exactly one, implicit, @@ -2147,6 +2139,10 @@ check_role_membership_authorization(Oid currentUserId, Oid roleid, } else { + if (CheckRoleMembershipAuthorization_hook && CheckRoleMembershipAuthorization_hook(currentUserId, roleid, is_grant, memberIds, popt)) + { + return; + } /* * Otherwise, must have admin option on the role to be changed. */ diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 5e648e6a17c..d488fff2830 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -134,6 +134,7 @@ static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue * Generally neon_superuser on neon.com */ char *privileged_role_name = NULL; +SelectBestAdmin_hook_type SelectBestAdmin_hook = NULL; bool is_privileged_role(void) @@ -5336,6 +5337,11 @@ select_best_admin(Oid member, Oid role) return InvalidOid; (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role); + + if (SelectBestAdmin_hook) + { + SelectBestAdmin_hook(&admin_role, member, role); + } return admin_role; } diff --git a/src/include/commands/user.h b/src/include/commands/user.h index 97dcb93791b..9a79402b8d4 100644 --- a/src/include/commands/user.h +++ b/src/include/commands/user.h @@ -17,6 +17,14 @@ #include "parser/parse_node.h" #include "utils/guc.h" +typedef struct +{ + unsigned specified; + bool admin; + bool inherit; + bool set; +} GrantRoleOptions; + /* GUCs */ extern PGDLLIMPORT int Password_encryption; /* values from enum PasswordType */ extern PGDLLIMPORT char *createrole_self_grant; @@ -26,6 +34,9 @@ typedef void (*check_password_hook_type) (const char *username, const char *shad extern PGDLLIMPORT check_password_hook_type check_password_hook; +typedef bool (*CheckRoleMembershipAuthorization_hook_type) (Oid currentUserId, Oid roleid, bool is_grant, List *memberIds, GrantRoleOptions * popt); +extern PGDLLIMPORT CheckRoleMembershipAuthorization_hook_type CheckRoleMembershipAuthorization_hook; + extern Oid CreateRole(ParseState *pstate, CreateRoleStmt *stmt); extern Oid AlterRole(ParseState *pstate, AlterRoleStmt *stmt); extern Oid AlterRoleSet(AlterRoleSetStmt *stmt); diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 731d84b2a93..7861a947e1f 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -287,4 +287,7 @@ extern bool object_ownercheck(Oid classid, Oid objectid, Oid roleid); extern bool has_createrole_privilege(Oid roleid); extern bool has_bypassrls_privilege(Oid roleid); +typedef void (*SelectBestAdmin_hook_type) (Oid* admin_role, Oid member, Oid role); +extern PGDLLIMPORT SelectBestAdmin_hook_type SelectBestAdmin_hook; + #endif /* ACL_H */