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- /* GUC parameter */
85+ /* GUC parameters */
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)
532536 if (!superuser ())
533537 {
534538 RoleSpec * current_role = makeNode (RoleSpec );
535- GrantRoleOptions poptself ;
539+ GrantRoleOptions poptself ;
540+ List * memberSpecs ;
541+ List * memberIds = list_make1_oid (currentUserId );
536542
537543 current_role -> roletype = ROLESPEC_CURRENT_ROLE ;
538544 current_role -> location = -1 ;
545+ memberSpecs = list_make1 (current_role );
539546
540547 poptself .specified = GRANT_ROLE_SPECIFIED_ADMIN
541548 | GRANT_ROLE_SPECIFIED_INHERIT
@@ -545,14 +552,28 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
545552 poptself .set = false;
546553
547554 AddRoleMems (BOOTSTRAP_SUPERUSERID , stmt -> role , roleid ,
548- list_make1 ( current_role ), list_make1_oid ( GetUserId ()) ,
555+ memberSpecs , memberIds ,
549556 BOOTSTRAP_SUPERUSERID , & poptself );
550557
551558 /*
552559 * We must make the implicit grant visible to the code below, else
553560 * the additional grants will fail.
554561 */
555562 CommandCounterIncrement ();
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)
24142435 popt -> inherit = false;
24152436 popt -> 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+ }
0 commit comments