3939#include "utils/fmgroids.h"
4040#include "utils/syscache.h"
4141#include "utils/timestamp.h"
42+ #include "utils/varlena.h"
4243
4344/*
4445 * Removing a role grant - or the admin option on it - might recurse to
@@ -81,8 +82,11 @@ typedef struct
8182#define GRANT_ROLE_SPECIFIED_INHERIT 0x0002
8283#define GRANT_ROLE_SPECIFIED_SET 0x0004
8384
84- /* GUCparameter */
85+ /* GUCparameters */
8586int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256 ;
87+ char * createrole_self_grant = "" ;
88+ bool createrole_self_grant_enabled = false;
89+ GrantRoleOptions createrole_self_grant_options ;
8690
8791/* Hook to check passwords in CreateRole() and AlterRole() */
8892check_password_hook_type check_password_hook = NULL ;
@@ -532,10 +536,13 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
532536if (!superuser ())
533537{
534538RoleSpec * current_role = makeNode (RoleSpec );
535- GrantRoleOptions poptself ;
539+ GrantRoleOptions poptself ;
540+ List * memberSpecs ;
541+ List * memberIds = list_make1_oid (currentUserId );
536542
537543current_role -> roletype = ROLESPEC_CURRENT_ROLE ;
538544current_role -> location = -1 ;
545+ memberSpecs = list_make1 (current_role );
539546
540547poptself .specified = GRANT_ROLE_SPECIFIED_ADMIN
541548|GRANT_ROLE_SPECIFIED_INHERIT
@@ -545,14 +552,28 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
545552poptself .set = false;
546553
547554AddRoleMems (BOOTSTRAP_SUPERUSERID ,stmt -> role ,roleid ,
548- list_make1 ( current_role ), list_make1_oid ( GetUserId ()) ,
555+ memberSpecs , memberIds ,
549556BOOTSTRAP_SUPERUSERID ,& poptself );
550557
551558/*
552559 * We must make the implicit grant visible to the code below, else
553560 * the additional grants will fail.
554561 */
555562CommandCounterIncrement ();
563+
564+ /*
565+ * Because of the implicit grant above, a CREATEROLE user who creates
566+ * a role has the ability to grant that role back to themselves with
567+ * the INHERIT or SET options, if they wish to inherit the role's
568+ * privileges or be able to SET ROLE to it. The createrole_self_grant
569+ * GUC can be used to make this happen automatically. This has no
570+ * security implications since the same user is able to make the same
571+ * grant using an explicit GRANT statement; it's just convenient.
572+ */
573+ if (createrole_self_grant_enabled )
574+ AddRoleMems (currentUserId ,stmt -> role ,roleid ,
575+ memberSpecs ,memberIds ,
576+ currentUserId ,& createrole_self_grant_options );
556577}
557578
558579/*
@@ -2414,3 +2435,73 @@ InitGrantRoleOptions(GrantRoleOptions *popt)
24142435popt -> inherit = false;
24152436popt -> set = true;
24162437}
2438+
2439+ /*
2440+ * GUC check_hook for createrole_self_grant
2441+ */
2442+ bool
2443+ check_createrole_self_grant (char * * newval ,void * * extra ,GucSource source )
2444+ {
2445+ char * rawstring ;
2446+ List * elemlist ;
2447+ ListCell * l ;
2448+ unsigned options = 0 ;
2449+ unsigned * result ;
2450+
2451+ /* Need a modifiable copy of string */
2452+ rawstring = pstrdup (* newval );
2453+
2454+ if (!SplitIdentifierString (rawstring ,',' ,& elemlist ))
2455+ {
2456+ /* syntax error in list */
2457+ GUC_check_errdetail ("List syntax is invalid." );
2458+ pfree (rawstring );
2459+ list_free (elemlist );
2460+ return false;
2461+ }
2462+
2463+ foreach (l ,elemlist )
2464+ {
2465+ char * tok = (char * )lfirst (l );
2466+
2467+ if (pg_strcasecmp (tok ,"SET" )== 0 )
2468+ options |=GRANT_ROLE_SPECIFIED_SET ;
2469+ else if (pg_strcasecmp (tok ,"INHERIT" )== 0 )
2470+ options |=GRANT_ROLE_SPECIFIED_INHERIT ;
2471+ else
2472+ {
2473+ GUC_check_errdetail ("Unrecognized key word: \"%s\"." ,tok );
2474+ pfree (rawstring );
2475+ list_free (elemlist );
2476+ return false;
2477+ }
2478+ }
2479+
2480+ pfree (rawstring );
2481+ list_free (elemlist );
2482+
2483+ result = (unsigned * )guc_malloc (LOG ,sizeof (unsigned ));
2484+ * result = options ;
2485+ * extra = result ;
2486+
2487+ return true;
2488+ }
2489+
2490+ /*
2491+ * GUC assign_hook for createrole_self_grant
2492+ */
2493+ void
2494+ assign_createrole_self_grant (const char * newval ,void * extra )
2495+ {
2496+ unsigned options = * (unsigned * )extra ;
2497+
2498+ createrole_self_grant_enabled = (options != 0 );
2499+ createrole_self_grant_options .specified = GRANT_ROLE_SPECIFIED_ADMIN
2500+ |GRANT_ROLE_SPECIFIED_INHERIT
2501+ |GRANT_ROLE_SPECIFIED_SET ;
2502+ createrole_self_grant_options .admin = false;
2503+ createrole_self_grant_options .inherit =
2504+ (options & GRANT_ROLE_SPECIFIED_INHERIT )!= 0 ;
2505+ createrole_self_grant_options .set =
2506+ (options & GRANT_ROLE_SPECIFIED_SET )!= 0 ;
2507+ }