LCOV - differential code coverage report
Current view: top level - src/backend/commands - user.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 88.9 % 862 766 315 18 41 2 13 280 323 150 38 255 15 91
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 21 21 9 12 19 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * user.c
       4                 :  *    Commands for manipulating roles (formerly called users).
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  * src/backend/commands/user.c
      10                 :  *
      11                 :  *-------------------------------------------------------------------------
      12                 :  */
      13                 : #include "postgres.h"
      14                 : 
      15                 : #include "access/genam.h"
      16                 : #include "access/htup_details.h"
      17                 : #include "access/table.h"
      18                 : #include "access/xact.h"
      19                 : #include "catalog/binary_upgrade.h"
      20                 : #include "catalog/catalog.h"
      21                 : #include "catalog/dependency.h"
      22                 : #include "catalog/indexing.h"
      23                 : #include "catalog/objectaccess.h"
      24                 : #include "catalog/pg_auth_members.h"
      25                 : #include "catalog/pg_authid.h"
      26                 : #include "catalog/pg_database.h"
      27                 : #include "catalog/pg_db_role_setting.h"
      28                 : #include "commands/comment.h"
      29                 : #include "commands/dbcommands.h"
      30                 : #include "commands/defrem.h"
      31                 : #include "commands/seclabel.h"
      32                 : #include "commands/user.h"
      33                 : #include "libpq/crypt.h"
      34                 : #include "miscadmin.h"
      35                 : #include "storage/lmgr.h"
      36                 : #include "utils/acl.h"
      37                 : #include "utils/builtins.h"
      38                 : #include "utils/catcache.h"
      39                 : #include "utils/fmgroids.h"
      40                 : #include "utils/syscache.h"
      41                 : #include "utils/timestamp.h"
      42                 : #include "utils/varlena.h"
      43                 : 
      44                 : /*
      45                 :  * Removing a role grant - or the admin option on it - might recurse to
      46                 :  * dependent grants. We use these values to reason about what would need to
      47                 :  * be done in such cases.
      48                 :  *
      49                 :  * RRG_NOOP indicates a grant that would not need to be altered by the
      50                 :  * operation.
      51                 :  *
      52                 :  * RRG_REMOVE_ADMIN_OPTION indicates a grant that would need to have
      53                 :  * admin_option set to false by the operation.
      54                 :  *
      55                 :  * Similarly, RRG_REMOVE_INHERIT_OPTION and RRG_REMOVE_SET_OPTION indicate
      56                 :  * grants that would need to have the corresponding options set to false.
      57                 :  *
      58                 :  * RRG_DELETE_GRANT indicates a grant that would need to be removed entirely
      59                 :  * by the operation.
      60                 :  */
      61                 : typedef enum
      62                 : {
      63                 :     RRG_NOOP,
      64                 :     RRG_REMOVE_ADMIN_OPTION,
      65                 :     RRG_REMOVE_INHERIT_OPTION,
      66                 :     RRG_REMOVE_SET_OPTION,
      67                 :     RRG_DELETE_GRANT
      68                 : } RevokeRoleGrantAction;
      69                 : 
      70                 : /* Potentially set by pg_upgrade_support functions */
      71                 : Oid         binary_upgrade_next_pg_authid_oid = InvalidOid;
      72                 : 
      73                 : typedef struct
      74                 : {
      75                 :     unsigned    specified;
      76                 :     bool        admin;
      77                 :     bool        inherit;
      78                 :     bool        set;
      79                 : } GrantRoleOptions;
      80                 : 
      81                 : #define GRANT_ROLE_SPECIFIED_ADMIN          0x0001
      82                 : #define GRANT_ROLE_SPECIFIED_INHERIT        0x0002
      83                 : #define GRANT_ROLE_SPECIFIED_SET            0x0004
      84                 : 
      85                 : /* GUC parameters */
      86                 : int         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;
      90                 : 
      91                 : /* Hook to check passwords in CreateRole() and AlterRole() */
      92                 : check_password_hook_type check_password_hook = NULL;
      93                 : 
      94                 : static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
      95                 :                         List *memberSpecs, List *memberIds,
      96                 :                         Oid grantorId, GrantRoleOptions *popt);
      97                 : static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
      98                 :                         List *memberSpecs, List *memberIds,
      99                 :                         Oid grantorId, GrantRoleOptions *popt,
     100                 :                         DropBehavior behavior);
     101                 : static void check_role_membership_authorization(Oid currentUserId, Oid roleid,
     102                 :                                                 bool is_grant);
     103                 : static Oid  check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId,
     104                 :                                bool is_grant);
     105                 : static RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist);
     106                 : static bool plan_single_revoke(CatCList *memlist,
     107                 :                                RevokeRoleGrantAction *actions,
     108                 :                                Oid member, Oid grantor,
     109                 :                                GrantRoleOptions *popt,
     110                 :                                DropBehavior behavior);
     111                 : static void plan_member_revoke(CatCList *memlist,
     112                 :                                RevokeRoleGrantAction *actions, Oid member);
     113                 : static void plan_recursive_revoke(CatCList *memlist,
     114                 :                                   RevokeRoleGrantAction *actions,
     115                 :                                   int index,
     116                 :                                   bool revoke_admin_option_only,
     117                 :                                   DropBehavior behavior);
     118                 : static void InitGrantRoleOptions(GrantRoleOptions *popt);
     119                 : 
     120                 : 
     121                 : /* Check if current user has createrole privileges */
     122                 : static bool
     123 GIC        1014 : have_createrole_privilege(void)
     124                 : {
     125            1014 :     return has_createrole_privilege(GetUserId());
     126                 : }
     127                 : 
     128                 : 
     129                 : /*
     130                 :  * CREATE ROLE
     131                 :  */
     132                 : Oid
     133             799 : CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
     134                 : {
     135                 :     Relation    pg_authid_rel;
     136                 :     TupleDesc   pg_authid_dsc;
     137                 :     HeapTuple   tuple;
     138 GNC         799 :     Datum       new_record[Natts_pg_authid] = {0};
     139             799 :     bool        new_record_nulls[Natts_pg_authid] = {0};
     140             799 :     Oid         currentUserId = GetUserId();
     141                 :     Oid         roleid;
     142                 :     ListCell   *item;
     143                 :     ListCell   *option;
     144 GIC         799 :     char       *password = NULL;    /* user password */
     145             799 :     bool        issuper = false;    /* Make the user a superuser? */
     146             799 :     bool        inherit = true; /* Auto inherit privileges? */
     147             799 :     bool        createrole = false; /* Can this user create roles? */
     148             799 :     bool        createdb = false;   /* Can the user create databases? */
     149             799 :     bool        canlogin = false;   /* Can this user login? */
     150             799 :     bool        isreplication = false;  /* Is this a replication role? */
     151             799 :     bool        bypassrls = false;  /* Is this a row security enabled role? */
     152             799 :     int         connlimit = -1; /* maximum connections allowed */
     153             799 :     List       *addroleto = NIL;    /* roles to make this a member of */
     154             799 :     List       *rolemembers = NIL;  /* roles to be members of this role */
     155             799 :     List       *adminmembers = NIL; /* roles to be admins of this role */
     156             799 :     char       *validUntil = NULL;  /* time the login is valid until */
     157                 :     Datum       validUntil_datum;   /* same, as timestamptz Datum */
     158                 :     bool        validUntil_null;
     159             799 :     DefElem    *dpassword = NULL;
     160             799 :     DefElem    *dissuper = NULL;
     161             799 :     DefElem    *dinherit = NULL;
     162             799 :     DefElem    *dcreaterole = NULL;
     163             799 :     DefElem    *dcreatedb = NULL;
     164             799 :     DefElem    *dcanlogin = NULL;
     165             799 :     DefElem    *disreplication = NULL;
     166             799 :     DefElem    *dconnlimit = NULL;
     167             799 :     DefElem    *daddroleto = NULL;
     168             799 :     DefElem    *drolemembers = NULL;
     169             799 :     DefElem    *dadminmembers = NULL;
     170             799 :     DefElem    *dvalidUntil = NULL;
     171             799 :     DefElem    *dbypassRLS = NULL;
     172                 :     GrantRoleOptions    popt;
     173                 : 
     174                 :     /* The defaults can vary depending on the original statement type */
     175             799 :     switch (stmt->stmt_type)
     176                 :     {
     177             574 :         case ROLESTMT_ROLE:
     178             574 :             break;
     179             213 :         case ROLESTMT_USER:
     180             213 :             canlogin = true;
     181                 :             /* may eventually want inherit to default to false here */
     182             213 :             break;
     183              12 :         case ROLESTMT_GROUP:
     184              12 :             break;
     185                 :     }
     186 ECB             : 
     187                 :     /* Extract options from the statement node tree */
     188 CBC        1317 :     foreach(option, stmt->options)
     189                 :     {
     190 GIC         518 :         DefElem    *defel = (DefElem *) lfirst(option);
     191                 : 
     192             518 :         if (strcmp(defel->defname, "password") == 0)
     193                 :         {
     194              57 :             if (dpassword)
     195 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     196 CBC          57 :             dpassword = defel;
     197                 :         }
     198 GIC         461 :         else if (strcmp(defel->defname, "sysid") == 0)
     199                 :         {
     200               3 :             ereport(NOTICE,
     201 ECB             :                     (errmsg("SYSID can no longer be specified")));
     202                 :         }
     203 CBC         458 :         else if (strcmp(defel->defname, "superuser") == 0)
     204                 :         {
     205 GIC          84 :             if (dissuper)
     206 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     207 CBC          84 :             dissuper = defel;
     208 ECB             :         }
     209 CBC         374 :         else if (strcmp(defel->defname, "inherit") == 0)
     210 ECB             :         {
     211 CBC          28 :             if (dinherit)
     212 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     213 CBC          28 :             dinherit = defel;
     214 ECB             :         }
     215 CBC         346 :         else if (strcmp(defel->defname, "createrole") == 0)
     216 ECB             :         {
     217 CBC          41 :             if (dcreaterole)
     218 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     219 CBC          41 :             dcreaterole = defel;
     220                 :         }
     221 GIC         305 :         else if (strcmp(defel->defname, "createdb") == 0)
     222 ECB             :         {
     223 CBC          31 :             if (dcreatedb)
     224 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     225 CBC          31 :             dcreatedb = defel;
     226 ECB             :         }
     227 CBC         274 :         else if (strcmp(defel->defname, "canlogin") == 0)
     228 ECB             :         {
     229 CBC         124 :             if (dcanlogin)
     230 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     231 CBC         124 :             dcanlogin = defel;
     232 ECB             :         }
     233 CBC         150 :         else if (strcmp(defel->defname, "isreplication") == 0)
     234 ECB             :         {
     235 GIC          38 :             if (disreplication)
     236 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     237 GIC          38 :             disreplication = defel;
     238 ECB             :         }
     239 GIC         112 :         else if (strcmp(defel->defname, "connectionlimit") == 0)
     240 ECB             :         {
     241 CBC           6 :             if (dconnlimit)
     242 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     243 CBC           6 :             dconnlimit = defel;
     244                 :         }
     245             106 :         else if (strcmp(defel->defname, "addroleto") == 0)
     246 ECB             :         {
     247 CBC          48 :             if (daddroleto)
     248 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     249 GIC          48 :             daddroleto = defel;
     250                 :         }
     251 CBC          58 :         else if (strcmp(defel->defname, "rolemembers") == 0)
     252                 :         {
     253              10 :             if (drolemembers)
     254 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     255 CBC          10 :             drolemembers = defel;
     256                 :         }
     257              48 :         else if (strcmp(defel->defname, "adminmembers") == 0)
     258 EUB             :         {
     259 CBC          10 :             if (dadminmembers)
     260 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     261 CBC          10 :             dadminmembers = defel;
     262                 :         }
     263              38 :         else if (strcmp(defel->defname, "validUntil") == 0)
     264                 :         {
     265 GIC           1 :             if (dvalidUntil)
     266 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     267 GIC           1 :             dvalidUntil = defel;
     268 ECB             :         }
     269 GBC          37 :         else if (strcmp(defel->defname, "bypassrls") == 0)
     270 ECB             :         {
     271 GIC          37 :             if (dbypassRLS)
     272 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     273 GIC          37 :             dbypassRLS = defel;
     274 ECB             :         }
     275 EUB             :         else
     276 LBC           0 :             elog(ERROR, "option \"%s\" not recognized",
     277                 :                  defel->defname);
     278 ECB             :     }
     279                 : 
     280 CBC         799 :     if (dpassword && dpassword->arg)
     281 GBC          51 :         password = strVal(dpassword->arg);
     282 CBC         799 :     if (dissuper)
     283 GIC          84 :         issuper = boolVal(dissuper->arg);
     284 CBC         799 :     if (dinherit)
     285 GIC          28 :         inherit = boolVal(dinherit->arg);
     286 CBC         799 :     if (dcreaterole)
     287 GBC          41 :         createrole = boolVal(dcreaterole->arg);
     288 CBC         799 :     if (dcreatedb)
     289 GIC          31 :         createdb = boolVal(dcreatedb->arg);
     290 CBC         799 :     if (dcanlogin)
     291 GIC         124 :         canlogin = boolVal(dcanlogin->arg);
     292 CBC         799 :     if (disreplication)
     293 GBC          38 :         isreplication = boolVal(disreplication->arg);
     294 CBC         799 :     if (dconnlimit)
     295                 :     {
     296               6 :         connlimit = intVal(dconnlimit->arg);
     297 GIC           6 :         if (connlimit < -1)
     298 LBC           0 :             ereport(ERROR,
     299 EUB             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     300 ECB             :                      errmsg("invalid connection limit: %d", connlimit)));
     301                 :     }
     302 CBC         799 :     if (daddroleto)
     303 GIC          48 :         addroleto = (List *) daddroleto->arg;
     304 CBC         799 :     if (drolemembers)
     305 GBC          10 :         rolemembers = (List *) drolemembers->arg;
     306 CBC         799 :     if (dadminmembers)
     307 GIC          10 :         adminmembers = (List *) dadminmembers->arg;
     308 CBC         799 :     if (dvalidUntil)
     309 GIC           1 :         validUntil = strVal(dvalidUntil->arg);
     310 CBC         799 :     if (dbypassRLS)
     311 GBC          37 :         bypassrls = boolVal(dbypassRLS->arg);
     312 ECB             : 
     313                 :     /* Check some permissions first */
     314 GNC         799 :     if (!superuser_arg(currentUserId))
     315                 :     {
     316             111 :         if (!has_createrole_privilege(currentUserId))
     317 UBC           0 :             ereport(ERROR,
     318 ECB             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     319                 :                      errmsg("permission denied to create role"),
     320                 :                      errdetail("Only roles with the %s attribute may create roles.",
     321                 :                                "CREATEROLE")));
     322 GNC         111 :         if (issuper)
     323 CBC           3 :             ereport(ERROR,
     324                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     325                 :                      errmsg("permission denied to create role"),
     326                 :                      errdetail("Only roles with the %s attribute may create roles with %s.",
     327                 :                                "SUPERUSER", "SUPERUSER")));
     328 GNC         108 :         if (createdb && !have_createdb_privilege())
     329 GIC           3 :             ereport(ERROR,
     330 ECB             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     331                 :                      errmsg("permission denied to create role"),
     332                 :                      errdetail("Only roles with the %s attribute may create roles with %s.",
     333                 :                                "CREATEDB", "CREATEDB")));
     334 GNC         105 :         if (isreplication && !has_rolreplication(currentUserId))
     335 GIC           6 :             ereport(ERROR,
     336 EUB             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     337                 :                      errmsg("permission denied to create role"),
     338                 :                      errdetail("Only roles with the %s attribute may create roles with %s.",
     339                 :                                "REPLICATION", "REPLICATION")));
     340 GNC          99 :         if (bypassrls && !has_bypassrls_privilege(currentUserId))
     341               3 :             ereport(ERROR,
     342                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     343                 :                      errmsg("permission denied to create role"),
     344                 :                      errdetail("Only roles with the %s attribute may create roles with %s.",
     345                 :                                "BYPASSRLS", "BYPASSRLS")));
     346                 :     }
     347                 : 
     348 ECB             :     /*
     349                 :      * Check that the user is not trying to create a role in the reserved
     350                 :      * "pg_" namespace.
     351                 :      */
     352 CBC         784 :     if (IsReservedName(stmt->role))
     353               4 :         ereport(ERROR,
     354 ECB             :                 (errcode(ERRCODE_RESERVED_NAME),
     355                 :                  errmsg("role name \"%s\" is reserved",
     356                 :                         stmt->role),
     357                 :                  errdetail("Role names starting with \"pg_\" are reserved.")));
     358                 : 
     359                 :     /*
     360                 :      * If built with appropriate switch, whine when regression-testing
     361                 :      * conventions for role names are violated.
     362                 :      */
     363                 : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
     364                 :     if (strncmp(stmt->role, "regress_", 8) != 0)
     365                 :         elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
     366 EUB             : #endif
     367                 : 
     368                 :     /*
     369                 :      * Check the pg_authid relation to be certain the role doesn't already
     370 ECB             :      * exist.
     371                 :      */
     372 CBC         780 :     pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
     373             780 :     pg_authid_dsc = RelationGetDescr(pg_authid_rel);
     374 ECB             : 
     375 CBC         780 :     if (OidIsValid(get_role_oid(stmt->role, true)))
     376               3 :         ereport(ERROR,
     377 ECB             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     378                 :                  errmsg("role \"%s\" already exists",
     379                 :                         stmt->role)));
     380                 : 
     381                 :     /* Convert validuntil to internal form */
     382 CBC         777 :     if (validUntil)
     383                 :     {
     384               1 :         validUntil_datum = DirectFunctionCall3(timestamptz_in,
     385 EUB             :                                                CStringGetDatum(validUntil),
     386                 :                                                ObjectIdGetDatum(InvalidOid),
     387                 :                                                Int32GetDatum(-1));
     388 GIC           1 :         validUntil_null = false;
     389                 :     }
     390 ECB             :     else
     391                 :     {
     392 GIC         776 :         validUntil_datum = (Datum) 0;
     393             776 :         validUntil_null = true;
     394                 :     }
     395                 : 
     396 ECB             :     /*
     397                 :      * Call the password checking hook if there is one defined
     398                 :      */
     399 GIC         777 :     if (check_password_hook && password)
     400 UIC           0 :         (*check_password_hook) (stmt->role,
     401                 :                                 password,
     402 ECB             :                                 get_password_type(password),
     403                 :                                 validUntil_datum,
     404                 :                                 validUntil_null);
     405                 : 
     406                 :     /*
     407                 :      * Build a tuple to insert
     408                 :      */
     409 GIC         777 :     new_record[Anum_pg_authid_rolname - 1] =
     410             777 :         DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
     411             777 :     new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
     412             777 :     new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
     413             777 :     new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
     414             777 :     new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
     415             777 :     new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
     416 CBC         777 :     new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
     417             777 :     new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
     418                 : 
     419 GIC         777 :     if (password)
     420                 :     {
     421                 :         char       *shadow_pass;
     422              51 :         const char *logdetail = NULL;
     423                 : 
     424                 :         /*
     425                 :          * Don't allow an empty password. Libpq treats an empty password the
     426                 :          * same as no password at all, and won't even try to authenticate. But
     427                 :          * other clients might, so allowing it would be confusing. By clearing
     428                 :          * the password when an empty string is specified, the account is
     429                 :          * consistently locked for all clients.
     430                 :          *
     431                 :          * Note that this only covers passwords stored in the database itself.
     432                 :          * There are also checks in the authentication code, to forbid an
     433                 :          * empty password from being used with authentication methods that
     434                 :          * fetch the password from an external system, like LDAP or PAM.
     435                 :          */
     436 CBC          99 :         if (password[0] == '\0' ||
     437              48 :             plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
     438                 :         {
     439               3 :             ereport(NOTICE,
     440 ECB             :                     (errmsg("empty string is not a valid password, clearing password")));
     441 GIC           3 :             new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
     442                 :         }
     443                 :         else
     444                 :         {
     445                 :             /* Encrypt the password to the requested format. */
     446 CBC          48 :             shadow_pass = encrypt_password(Password_encryption, stmt->role,
     447                 :                                            password);
     448              48 :             new_record[Anum_pg_authid_rolpassword - 1] =
     449 GIC          48 :                 CStringGetTextDatum(shadow_pass);
     450                 :         }
     451                 :     }
     452 ECB             :     else
     453 GIC         726 :         new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
     454                 : 
     455             777 :     new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
     456 CBC         777 :     new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
     457 ECB             : 
     458 GIC         777 :     new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
     459                 : 
     460                 :     /*
     461                 :      * pg_largeobject_metadata contains pg_authid.oid's, so we use the
     462                 :      * binary-upgrade override.
     463 ECB             :      */
     464 GBC         777 :     if (IsBinaryUpgrade)
     465                 :     {
     466 UIC           0 :         if (!OidIsValid(binary_upgrade_next_pg_authid_oid))
     467               0 :             ereport(ERROR,
     468                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     469                 :                      errmsg("pg_authid OID value not set when in binary upgrade mode")));
     470                 : 
     471               0 :         roleid = binary_upgrade_next_pg_authid_oid;
     472               0 :         binary_upgrade_next_pg_authid_oid = InvalidOid;
     473 ECB             :     }
     474                 :     else
     475                 :     {
     476 CBC         777 :         roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
     477 ECB             :                                     Anum_pg_authid_oid);
     478                 :     }
     479                 : 
     480 CBC         777 :     new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
     481 ECB             : 
     482 GIC         777 :     tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
     483 ECB             : 
     484                 :     /*
     485                 :      * Insert new record in the pg_authid table
     486                 :      */
     487 GIC         777 :     CatalogTupleInsert(pg_authid_rel, tuple);
     488                 : 
     489                 :     /*
     490                 :      * Advance command counter so we can see new record; else tests in
     491                 :      * AddRoleMems may fail.
     492                 :      */
     493             777 :     if (addroleto || adminmembers || rolemembers)
     494              65 :         CommandCounterIncrement();
     495                 : 
     496                 :     /* Default grant. */
     497 GNC         777 :     InitGrantRoleOptions(&popt);
     498                 : 
     499                 :     /*
     500                 :      * Add the new role to the specified existing roles.
     501                 :      */
     502 GIC         777 :     if (addroleto)
     503 ECB             :     {
     504 CBC          48 :         RoleSpec   *thisrole = makeNode(RoleSpec);
     505 GIC          48 :         List       *thisrole_list = list_make1(thisrole);
     506 CBC          48 :         List       *thisrole_oidlist = list_make1_oid(roleid);
     507                 : 
     508              48 :         thisrole->roletype = ROLESPEC_CSTRING;
     509 GIC          48 :         thisrole->rolename = stmt->role;
     510              48 :         thisrole->location = -1;
     511                 : 
     512              60 :         foreach(item, addroleto)
     513 ECB             :         {
     514 GIC          48 :             RoleSpec   *oldrole = lfirst(item);
     515 CBC          48 :             HeapTuple   oldroletup = get_rolespec_tuple(oldrole);
     516              48 :             Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
     517 GIC          48 :             Oid         oldroleid = oldroleform->oid;
     518              48 :             char       *oldrolename = NameStr(oldroleform->rolname);
     519                 : 
     520                 :             /* can only add this role to roles for which you have rights */
     521 GNC          48 :             check_role_membership_authorization(currentUserId, oldroleid, true);
     522              12 :             AddRoleMems(currentUserId, oldrolename, oldroleid,
     523                 :                         thisrole_list,
     524 ECB             :                         thisrole_oidlist,
     525                 :                         InvalidOid, &popt);
     526                 : 
     527 CBC          12 :             ReleaseSysCache(oldroletup);
     528                 :         }
     529                 :     }
     530                 : 
     531                 :     /*
     532                 :      * If the current user isn't a superuser, make them an admin of the new
     533                 :      * role so that they can administer the new object they just created.
     534                 :      * Superusers will be able to do that anyway.
     535                 :      *
     536                 :      * The grantor of record for this implicit grant is the bootstrap
     537                 :      * superuser, which means that the CREATEROLE user cannot revoke the
     538                 :      * grant. They can however grant the created role back to themselves
     539                 :      * with different options, since they enjoy ADMIN OPTION on it.
     540                 :      */
     541 GNC         741 :     if (!superuser())
     542                 :     {
     543              60 :         RoleSpec   *current_role = makeNode(RoleSpec);
     544                 :         GrantRoleOptions poptself;
     545                 :         List       *memberSpecs;
     546              60 :         List       *memberIds = list_make1_oid(currentUserId);
     547                 : 
     548              60 :         current_role->roletype = ROLESPEC_CURRENT_ROLE;
     549              60 :         current_role->location = -1;
     550              60 :         memberSpecs = list_make1(current_role);
     551                 : 
     552              60 :         poptself.specified = GRANT_ROLE_SPECIFIED_ADMIN
     553                 :             | GRANT_ROLE_SPECIFIED_INHERIT
     554                 :             | GRANT_ROLE_SPECIFIED_SET;
     555              60 :         poptself.admin = true;
     556              60 :         poptself.inherit = false;
     557              60 :         poptself.set = false;
     558                 : 
     559              60 :         AddRoleMems(BOOTSTRAP_SUPERUSERID, stmt->role, roleid,
     560                 :                     memberSpecs, memberIds,
     561                 :                     BOOTSTRAP_SUPERUSERID, &poptself);
     562                 : 
     563                 :         /*
     564                 :          * We must make the implicit grant visible to the code below, else
     565                 :          * the additional grants will fail.
     566                 :          */
     567              60 :         CommandCounterIncrement();
     568                 : 
     569                 :         /*
     570                 :          * Because of the implicit grant above, a CREATEROLE user who creates
     571                 :          * a role has the ability to grant that role back to themselves with
     572                 :          * the INHERIT or SET options, if they wish to inherit the role's
     573                 :          * privileges or be able to SET ROLE to it. The createrole_self_grant
     574                 :          * GUC can be used to make this happen automatically. This has no
     575                 :          * security implications since the same user is able to make the same
     576                 :          * grant using an explicit GRANT statement; it's just convenient.
     577                 :          */
     578              60 :         if (createrole_self_grant_enabled)
     579               3 :             AddRoleMems(currentUserId, stmt->role, roleid,
     580                 :                         memberSpecs, memberIds,
     581                 :                         currentUserId, &createrole_self_grant_options);
     582                 :     }
     583                 : 
     584                 :     /*
     585                 :      * Add the specified members to this new role. adminmembers get the admin
     586 ECB             :      * option, rolemembers don't.
     587                 :      *
     588                 :      * NB: No permissions check is required here. If you have enough rights
     589                 :      * to create a role, you can add any members you like.
     590                 :      */
     591 GNC         741 :     AddRoleMems(currentUserId, stmt->role, roleid,
     592                 :                 rolemembers, roleSpecsToIds(rolemembers),
     593                 :                 InvalidOid, &popt);
     594             738 :     popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
     595             738 :     popt.admin = true;
     596             738 :     AddRoleMems(currentUserId, stmt->role, roleid,
     597                 :                 adminmembers, roleSpecsToIds(adminmembers),
     598                 :                 InvalidOid, &popt);
     599 EUB             : 
     600                 :     /* Post creation hook for new role */
     601 GIC         735 :     InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
     602                 : 
     603 ECB             :     /*
     604                 :      * Close pg_authid, but keep lock till commit.
     605                 :      */
     606 GIC         735 :     table_close(pg_authid_rel, NoLock);
     607 ECB             : 
     608 GIC         735 :     return roleid;
     609 ECB             : }
     610                 : 
     611                 : 
     612                 : /*
     613                 :  * ALTER ROLE
     614                 :  *
     615                 :  * Note: the rolemembers option accepted here is intended to support the
     616                 :  * backwards-compatible ALTER GROUP syntax.  Although it will work to say
     617                 :  * "ALTER ROLE role ROLE rolenames", we don't document it.
     618                 :  */
     619                 : Oid
     620 CBC         197 : AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
     621 ECB             : {
     622 GNC         197 :     Datum       new_record[Natts_pg_authid] = {0};
     623             197 :     bool        new_record_nulls[Natts_pg_authid] = {0};
     624             197 :     bool        new_record_repl[Natts_pg_authid] = {0};
     625                 :     Relation    pg_authid_rel;
     626                 :     TupleDesc   pg_authid_dsc;
     627                 :     HeapTuple   tuple,
     628                 :                 new_tuple;
     629 ECB             :     Form_pg_authid authform;
     630                 :     ListCell   *option;
     631                 :     char       *rolename;
     632 CBC         197 :     char       *password = NULL;    /* user password */
     633             197 :     int         connlimit = -1; /* maximum connections allowed */
     634 GIC         197 :     char       *validUntil = NULL;  /* time the login is valid until */
     635 ECB             :     Datum       validUntil_datum;   /* same, as timestamptz Datum */
     636                 :     bool        validUntil_null;
     637 CBC         197 :     DefElem    *dpassword = NULL;
     638 GIC         197 :     DefElem    *dissuper = NULL;
     639 CBC         197 :     DefElem    *dinherit = NULL;
     640 GIC         197 :     DefElem    *dcreaterole = NULL;
     641 CBC         197 :     DefElem    *dcreatedb = NULL;
     642             197 :     DefElem    *dcanlogin = NULL;
     643             197 :     DefElem    *disreplication = NULL;
     644             197 :     DefElem    *dconnlimit = NULL;
     645             197 :     DefElem    *drolemembers = NULL;
     646 GIC         197 :     DefElem    *dvalidUntil = NULL;
     647             197 :     DefElem    *dbypassRLS = NULL;
     648 ECB             :     Oid         roleid;
     649 GNC         197 :     Oid         currentUserId = GetUserId();
     650                 :     GrantRoleOptions    popt;
     651 ECB             : 
     652 GIC         197 :     check_rolespec_name(stmt->role,
     653             197 :                         _("Cannot alter reserved roles."));
     654                 : 
     655                 :     /* Extract options from the statement node tree */
     656 CBC         472 :     foreach(option, stmt->options)
     657                 :     {
     658 GIC         275 :         DefElem    *defel = (DefElem *) lfirst(option);
     659                 : 
     660             275 :         if (strcmp(defel->defname, "password") == 0)
     661                 :         {
     662              33 :             if (dpassword)
     663 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     664 GIC          33 :             dpassword = defel;
     665                 :         }
     666             242 :         else if (strcmp(defel->defname, "superuser") == 0)
     667                 :         {
     668              37 :             if (dissuper)
     669 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     670 CBC          37 :             dissuper = defel;
     671                 :         }
     672             205 :         else if (strcmp(defel->defname, "inherit") == 0)
     673                 :         {
     674 GIC          26 :             if (dinherit)
     675 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     676 GIC          26 :             dinherit = defel;
     677 ECB             :         }
     678 CBC         179 :         else if (strcmp(defel->defname, "createrole") == 0)
     679 ECB             :         {
     680 GIC          17 :             if (dcreaterole)
     681 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     682 GIC          17 :             dcreaterole = defel;
     683                 :         }
     684 CBC         162 :         else if (strcmp(defel->defname, "createdb") == 0)
     685 ECB             :         {
     686 CBC          26 :             if (dcreatedb)
     687 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     688 CBC          26 :             dcreatedb = defel;
     689                 :         }
     690 GIC         136 :         else if (strcmp(defel->defname, "canlogin") == 0)
     691                 :         {
     692              29 :             if (dcanlogin)
     693 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     694 GIC          29 :             dcanlogin = defel;
     695                 :         }
     696 CBC         107 :         else if (strcmp(defel->defname, "isreplication") == 0)
     697                 :         {
     698 GIC          60 :             if (disreplication)
     699 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     700 GIC          60 :             disreplication = defel;
     701                 :         }
     702              47 :         else if (strcmp(defel->defname, "connectionlimit") == 0)
     703                 :         {
     704               6 :             if (dconnlimit)
     705 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     706 GIC           6 :             dconnlimit = defel;
     707 ECB             :         }
     708 CBC          41 :         else if (strcmp(defel->defname, "rolemembers") == 0 &&
     709 GIC          15 :                  stmt->action != 0)
     710                 :         {
     711              15 :             if (drolemembers)
     712 UIC           0 :                 errorConflictingDefElem(defel, pstate);
     713 GIC          15 :             drolemembers = defel;
     714                 :         }
     715              26 :         else if (strcmp(defel->defname, "validUntil") == 0)
     716                 :         {
     717 UIC           0 :             if (dvalidUntil)
     718               0 :                 errorConflictingDefElem(defel, pstate);
     719               0 :             dvalidUntil = defel;
     720 ECB             :         }
     721 GIC          26 :         else if (strcmp(defel->defname, "bypassrls") == 0)
     722                 :         {
     723 CBC          26 :             if (dbypassRLS)
     724 LBC           0 :                 errorConflictingDefElem(defel, pstate);
     725 CBC          26 :             dbypassRLS = defel;
     726                 :         }
     727                 :         else
     728 UIC           0 :             elog(ERROR, "option \"%s\" not recognized",
     729                 :                  defel->defname);
     730 ECB             :     }
     731                 : 
     732 GIC         197 :     if (dpassword && dpassword->arg)
     733              33 :         password = strVal(dpassword->arg);
     734             197 :     if (dconnlimit)
     735 ECB             :     {
     736 GIC           6 :         connlimit = intVal(dconnlimit->arg);
     737 CBC           6 :         if (connlimit < -1)
     738 UIC           0 :             ereport(ERROR,
     739                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     740                 :                      errmsg("invalid connection limit: %d", connlimit)));
     741                 :     }
     742 GIC         197 :     if (dvalidUntil)
     743 UIC           0 :         validUntil = strVal(dvalidUntil->arg);
     744                 : 
     745                 :     /*
     746                 :      * Scan the pg_authid relation to be certain the user exists.
     747                 :      */
     748 GIC         197 :     pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
     749 CBC         197 :     pg_authid_dsc = RelationGetDescr(pg_authid_rel);
     750                 : 
     751             197 :     tuple = get_rolespec_tuple(stmt->role);
     752             189 :     authform = (Form_pg_authid) GETSTRUCT(tuple);
     753             189 :     rolename = pstrdup(NameStr(authform->rolname));
     754 GIC         189 :     roleid = authform->oid;
     755                 : 
     756                 :     /* To mess with a superuser in any way you gotta be superuser. */
     757 GNC         189 :     if (!superuser() && authform->rolsuper)
     758 UNC           0 :         ereport(ERROR,
     759                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     760                 :                  errmsg("permission denied to alter role"),
     761                 :                  errdetail("Only roles with the %s attribute may alter roles with %s.",
     762                 :                            "SUPERUSER", "SUPERUSER")));
     763 GNC         189 :     if (!superuser() && dissuper)
     764               9 :         ereport(ERROR,
     765                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     766                 :                  errmsg("permission denied to alter role"),
     767                 :                  errdetail("Only roles with the %s attribute may change the %s attribute.",
     768                 :                            "SUPERUSER", "SUPERUSER")));
     769                 : 
     770                 :     /*
     771                 :      * Most changes to a role require that you both have CREATEROLE privileges
     772                 :      * and also ADMIN OPTION on the role.
     773 ECB             :      */
     774 GNC         180 :     if (!have_createrole_privilege() ||
     775             168 :         !is_admin_of_role(GetUserId(), roleid))
     776 ECB             :     {
     777                 :         /* things an unprivileged user certainly can't do */
     778 GIC          15 :         if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
     779 GNC          12 :             dvalidUntil || disreplication || dbypassRLS)
     780 GIC           3 :             ereport(ERROR,
     781 ECB             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     782                 :                      errmsg("permission denied to alter role"),
     783                 :                      errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
     784                 :                                "CREATEROLE", "ADMIN", rolename)));
     785                 : 
     786                 :         /* an unprivileged user can change their own password */
     787 GNC          12 :         if (dpassword && roleid != currentUserId)
     788               3 :             ereport(ERROR,
     789                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     790                 :                      errmsg("permission denied to alter role"),
     791                 :                      errdetail("To change another role's password, the current user must have the %s attribute and the %s option on the role.",
     792                 :                                "CREATEROLE", "ADMIN")));
     793 ECB             :     }
     794 GNC         165 :     else if (!superuser())
     795                 :     {
     796                 :         /*
     797                 :          * Even if you have both CREATEROLE and ADMIN OPTION on a role, you
     798                 :          * can only change the CREATEDB, REPLICATION, or BYPASSRLS attributes
     799                 :          * if they are set for your own role (or you are the superuser).
     800                 :          */
     801              30 :         if (dcreatedb && !have_createdb_privilege())
     802               3 :             ereport(ERROR,
     803                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     804                 :                      errmsg("permission denied to alter role"),
     805                 :                      errdetail("Only roles with the %s attribute may change the %s attribute.",
     806                 :                                "CREATEDB", "CREATEDB")));
     807              27 :         if (disreplication && !has_rolreplication(currentUserId))
     808               3 :             ereport(ERROR,
     809                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     810                 :                      errmsg("permission denied to alter role"),
     811                 :                      errdetail("Only roles with the %s attribute may change the %s attribute.",
     812                 :                                "REPLICATION", "REPLICATION")));
     813              24 :         if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
     814               3 :             ereport(ERROR,
     815                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     816                 :                      errmsg("permission denied to alter role"),
     817                 :                      errdetail("Only roles with the %s attribute may change the %s attribute.",
     818                 :                                "BYPASSRLS", "BYPASSRLS")));
     819                 :     }
     820                 : 
     821                 :     /* To add members to a role, you need ADMIN OPTION. */
     822             165 :     if (drolemembers && !is_admin_of_role(currentUserId, roleid))
     823 UNC           0 :         ereport(ERROR,
     824                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     825                 :                  errmsg("permission denied to alter role"),
     826                 :                  errdetail("Only roles with the %s option on role \"%s\" may add members.",
     827                 :                            "ADMIN", rolename)));
     828 EUB             : 
     829 ECB             :     /* Convert validuntil to internal form */
     830 GIC         165 :     if (dvalidUntil)
     831 ECB             :     {
     832 UIC           0 :         validUntil_datum = DirectFunctionCall3(timestamptz_in,
     833 ECB             :                                                CStringGetDatum(validUntil),
     834 EUB             :                                                ObjectIdGetDatum(InvalidOid),
     835 ECB             :                                                Int32GetDatum(-1));
     836 UIC           0 :         validUntil_null = false;
     837 ECB             :     }
     838                 :     else
     839                 :     {
     840 EUB             :         /* fetch existing setting in case hook needs it */
     841 CBC         165 :         validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
     842                 :                                            Anum_pg_authid_rolvaliduntil,
     843 ECB             :                                            &validUntil_null);
     844                 :     }
     845                 : 
     846 EUB             :     /*
     847 ECB             :      * Call the password checking hook if there is one defined
     848                 :      */
     849 CBC         165 :     if (check_password_hook && password)
     850 GIC           6 :         (*check_password_hook) (rolename,
     851 ECB             :                                 password,
     852 EUB             :                                 get_password_type(password),
     853 ECB             :                                 validUntil_datum,
     854                 :                                 validUntil_null);
     855                 : 
     856                 :     /*
     857                 :      * Build an updated tuple, perusing the information just obtained
     858 EUB             :      */
     859                 : 
     860 ECB             :     /*
     861 EUB             :      * issuper/createrole/etc
     862 ECB             :      */
     863 GIC         161 :     if (dissuper)
     864 ECB             :     {
     865 GNC          28 :         bool    should_be_super = boolVal(dissuper->arg);
     866                 : 
     867              28 :         if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
     868 UNC           0 :             ereport(ERROR,
     869                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     870                 :                      errmsg("permission denied to alter role"),
     871                 :                      errdetail("The bootstrap user must have the %s attribute.",
     872                 :                                "SUPERUSER")));
     873                 : 
     874 GNC          28 :         new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
     875 CBC          28 :         new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
     876 EUB             :     }
     877 ECB             : 
     878 GIC         161 :     if (dinherit)
     879 ECB             :     {
     880 CBC          23 :         new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg));
     881 GIC          23 :         new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
     882 ECB             :     }
     883 EUB             : 
     884 CBC         161 :     if (dcreaterole)
     885                 :     {
     886              17 :         new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg));
     887 GIC          17 :         new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
     888 EUB             :     }
     889                 : 
     890 GBC         161 :     if (dcreatedb)
     891                 :     {
     892 CBC          23 :         new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg));
     893 GIC          23 :         new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
     894 ECB             :     }
     895 EUB             : 
     896 CBC         161 :     if (dcanlogin)
     897                 :     {
     898 GIC          26 :         new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg));
     899 GBC          26 :         new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
     900                 :     }
     901                 : 
     902 GIC         161 :     if (disreplication)
     903 ECB             :     {
     904 CBC          49 :         new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg));
     905              49 :         new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
     906                 :     }
     907 ECB             : 
     908 CBC         161 :     if (dconnlimit)
     909 EUB             :     {
     910 GIC           3 :         new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
     911               3 :         new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
     912                 :     }
     913 ECB             : 
     914 EUB             :     /* password */
     915 GIC         161 :     if (password)
     916                 :     {
     917                 :         char       *shadow_pass;
     918              26 :         const char *logdetail = NULL;
     919 ECB             : 
     920                 :         /* Like in CREATE USER, don't allow an empty password. */
     921 GIC          52 :         if (password[0] == '\0' ||
     922 CBC          26 :             plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
     923 ECB             :         {
     924 CBC           6 :             ereport(NOTICE,
     925 ECB             :                     (errmsg("empty string is not a valid password, clearing password")));
     926 GIC           6 :             new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
     927                 :         }
     928 ECB             :         else
     929 EUB             :         {
     930                 :             /* Encrypt the password to the requested format. */
     931 GIC          20 :             shadow_pass = encrypt_password(Password_encryption, rolename,
     932                 :                                            password);
     933              20 :             new_record[Anum_pg_authid_rolpassword - 1] =
     934 CBC          20 :                 CStringGetTextDatum(shadow_pass);
     935 ECB             :         }
     936 GIC          26 :         new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
     937                 :     }
     938                 : 
     939                 :     /* unset password */
     940             161 :     if (dpassword && dpassword->arg == NULL)
     941                 :     {
     942 UIC           0 :         new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
     943               0 :         new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
     944                 :     }
     945 ECB             : 
     946                 :     /* valid until */
     947 GIC         161 :     new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
     948             161 :     new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
     949 CBC         161 :     new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
     950 ECB             : 
     951 CBC         161 :     if (dbypassRLS)
     952                 :     {
     953 GIC          23 :         new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg));
     954              23 :         new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
     955                 :     }
     956                 : 
     957             161 :     new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
     958 ECB             :                                   new_record_nulls, new_record_repl);
     959 CBC         161 :     CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
     960                 : 
     961 GIC         161 :     InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
     962                 : 
     963             161 :     ReleaseSysCache(tuple);
     964             161 :     heap_freetuple(new_tuple);
     965 ECB             : 
     966 GNC         161 :     InitGrantRoleOptions(&popt);
     967                 : 
     968                 :     /*
     969                 :      * Advance command counter so we can see new record; else tests in
     970                 :      * AddRoleMems may fail.
     971                 :      */
     972 GIC         161 :     if (drolemembers)
     973                 :     {
     974 CBC          15 :         List       *rolemembers = (List *) drolemembers->arg;
     975 ECB             : 
     976 GIC          15 :         CommandCounterIncrement();
     977                 : 
     978              15 :         if (stmt->action == +1) /* add members to role */
     979 GNC           9 :             AddRoleMems(currentUserId, rolename, roleid,
     980 ECB             :                         rolemembers, roleSpecsToIds(rolemembers),
     981                 :                         InvalidOid, &popt);
     982 GIC           6 :         else if (stmt->action == -1) /* drop members from role */
     983 GNC           6 :             DelRoleMems(currentUserId, rolename, roleid,
     984                 :                         rolemembers, roleSpecsToIds(rolemembers),
     985                 :                         InvalidOid, &popt, DROP_RESTRICT);
     986 ECB             :     }
     987                 : 
     988                 :     /*
     989                 :      * Close pg_authid, but keep lock till commit.
     990                 :      */
     991 GIC         161 :     table_close(pg_authid_rel, NoLock);
     992                 : 
     993             161 :     return roleid;
     994                 : }
     995 ECB             : 
     996 EUB             : 
     997                 : /*
     998                 :  * ALTER ROLE ... SET
     999                 :  */
    1000                 : Oid
    1001 GIC          46 : AlterRoleSet(AlterRoleSetStmt *stmt)
    1002                 : {
    1003 ECB             :     HeapTuple   roletuple;
    1004                 :     Form_pg_authid roleform;
    1005 GBC          46 :     Oid         databaseid = InvalidOid;
    1006 GIC          46 :     Oid         roleid = InvalidOid;
    1007                 : 
    1008              46 :     if (stmt->role)
    1009 EUB             :     {
    1010 GIC          42 :         check_rolespec_name(stmt->role,
    1011              42 :                             _("Cannot alter reserved roles."));
    1012                 : 
    1013              42 :         roletuple = get_rolespec_tuple(stmt->role);
    1014 CBC          38 :         roleform = (Form_pg_authid) GETSTRUCT(roletuple);
    1015 GIC          38 :         roleid = roleform->oid;
    1016                 : 
    1017                 :         /*
    1018                 :          * Obtain a lock on the role and make sure it didn't go away in the
    1019                 :          * meantime.
    1020                 :          */
    1021              38 :         shdepLockAndCheckObject(AuthIdRelationId, roleid);
    1022 ECB             : 
    1023                 :         /*
    1024                 :          * To mess with a superuser you gotta be superuser; otherwise you
    1025                 :          * need CREATEROLE plus admin option on the target role; unless you're
    1026                 :          * just trying to change your own settings
    1027                 :          */
    1028 GIC          38 :         if (roleform->rolsuper)
    1029                 :         {
    1030              14 :             if (!superuser())
    1031 UIC           0 :                 ereport(ERROR,
    1032                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1033                 :                          errmsg("permission denied to alter role"),
    1034                 :                          errdetail("Only roles with the %s attribute may alter roles with %s.",
    1035                 :                                    "SUPERUSER", "SUPERUSER")));
    1036                 :         }
    1037                 :         else
    1038                 :         {
    1039 GNC          24 :             if ((!have_createrole_privilege() ||
    1040              13 :                 !is_admin_of_role(GetUserId(), roleid))
    1041              11 :                 && roleid != GetUserId())
    1042 UIC           0 :                 ereport(ERROR,
    1043 ECB             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1044                 :                          errmsg("permission denied to alter role"),
    1045                 :                          errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
    1046                 :                                    "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
    1047                 :         }
    1048 EUB             : 
    1049 GIC          38 :         ReleaseSysCache(roletuple);
    1050                 :     }
    1051                 : 
    1052                 :     /* look up and lock the database, if specified */
    1053              42 :     if (stmt->database != NULL)
    1054 ECB             :     {
    1055 LBC           0 :         databaseid = get_database_oid(stmt->database, false);
    1056 UIC           0 :         shdepLockAndCheckObject(DatabaseRelationId, databaseid);
    1057                 : 
    1058 LBC           0 :         if (!stmt->role)
    1059                 :         {
    1060 ECB             :             /*
    1061                 :              * If no role is specified, then this is effectively the same as
    1062                 :              * ALTER DATABASE ... SET, so use the same permission check.
    1063                 :              */
    1064 UNC           0 :             if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
    1065 UIC           0 :                 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
    1066 LBC           0 :                                stmt->database);
    1067 ECB             :         }
    1068                 :     }
    1069                 : 
    1070 CBC          42 :     if (!stmt->role && !stmt->database)
    1071                 :     {
    1072 ECB             :         /* Must be superuser to alter settings globally. */
    1073 CBC           4 :         if (!superuser())
    1074 UIC           0 :             ereport(ERROR,
    1075                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1076                 :                      errmsg("permission denied to alter setting"),
    1077                 :                      errdetail("Only roles with the %s attribute may alter settings globally.",
    1078                 :                                "SUPERUSER")));
    1079                 :     }
    1080 ECB             : 
    1081 CBC          42 :     AlterSetting(databaseid, roleid, stmt->setstmt);
    1082                 : 
    1083 GIC          38 :     return roleid;
    1084 ECB             : }
    1085                 : 
    1086                 : 
    1087                 : /*
    1088                 :  * DROP ROLE
    1089                 :  */
    1090                 : void
    1091 GIC         798 : DropRole(DropRoleStmt *stmt)
    1092 ECB             : {
    1093                 :     Relation    pg_authid_rel,
    1094                 :                 pg_auth_members_rel;
    1095                 :     ListCell   *item;
    1096 GNC         798 :     List       *role_addresses = NIL;
    1097                 : 
    1098 CBC         798 :     if (!have_createrole_privilege())
    1099 UIC           0 :         ereport(ERROR,
    1100                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1101                 :                  errmsg("permission denied to drop role"),
    1102                 :                  errdetail("Only roles with the %s attribute and the %s option on the target roles may drop roles.",
    1103                 :                            "CREATEROLE", "ADMIN")));
    1104                 : 
    1105                 :     /*
    1106 ECB             :      * Scan the pg_authid relation to find the Oid of the role(s) to be
    1107                 :      * deleted and perform preliminary permissions and sanity checks.
    1108                 :      */
    1109 CBC         798 :     pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
    1110 GIC         798 :     pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
    1111 ECB             : 
    1112 GIC        1584 :     foreach(item, stmt->roles)
    1113                 :     {
    1114             841 :         RoleSpec   *rolspec = lfirst(item);
    1115                 :         char       *role;
    1116 ECB             :         HeapTuple   tuple,
    1117                 :                     tmp_tuple;
    1118                 :         Form_pg_authid roleform;
    1119                 :         ScanKeyData scankey;
    1120                 :         SysScanDesc sscan;
    1121                 :         Oid         roleid;
    1122                 :         ObjectAddress *role_address;
    1123                 : 
    1124 CBC         841 :         if (rolspec->roletype != ROLESPEC_CSTRING)
    1125 UIC           0 :             ereport(ERROR,
    1126 EUB             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1127                 :                      errmsg("cannot use special role specifier in DROP ROLE")));
    1128 GIC         841 :         role = rolspec->rolename;
    1129                 : 
    1130             841 :         tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
    1131 CBC         841 :         if (!HeapTupleIsValid(tuple))
    1132 ECB             :         {
    1133 CBC         151 :             if (!stmt->missing_ok)
    1134                 :             {
    1135              46 :                 ereport(ERROR,
    1136                 :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    1137 ECB             :                          errmsg("role \"%s\" does not exist", role)));
    1138                 :             }
    1139                 :             else
    1140                 :             {
    1141 CBC         105 :                 ereport(NOTICE,
    1142                 :                         (errmsg("role \"%s\" does not exist, skipping",
    1143 ECB             :                                 role)));
    1144                 :             }
    1145                 : 
    1146 GIC         105 :             continue;
    1147 ECB             :         }
    1148                 : 
    1149 GIC         690 :         roleform = (Form_pg_authid) GETSTRUCT(tuple);
    1150 CBC         690 :         roleid = roleform->oid;
    1151                 : 
    1152 GIC         690 :         if (roleid == GetUserId())
    1153               3 :             ereport(ERROR,
    1154                 :                     (errcode(ERRCODE_OBJECT_IN_USE),
    1155                 :                      errmsg("current user cannot be dropped")));
    1156 CBC         687 :         if (roleid == GetOuterUserId())
    1157 UIC           0 :             ereport(ERROR,
    1158 ECB             :                     (errcode(ERRCODE_OBJECT_IN_USE),
    1159                 :                      errmsg("current user cannot be dropped")));
    1160 CBC         687 :         if (roleid == GetSessionUserId())
    1161 UIC           0 :             ereport(ERROR,
    1162 ECB             :                     (errcode(ERRCODE_OBJECT_IN_USE),
    1163                 :                      errmsg("session user cannot be dropped")));
    1164                 : 
    1165                 :         /*
    1166                 :          * For safety's sake, we allow createrole holders to drop ordinary
    1167                 :          * roles but not superuser roles, and only if they also have ADMIN
    1168                 :          * OPTION.
    1169                 :          */
    1170 GIC         687 :         if (roleform->rolsuper && !superuser())
    1171               3 :             ereport(ERROR,
    1172                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1173                 :                      errmsg("permission denied to drop role"),
    1174                 :                      errdetail("Only roles with the %s attribute may drop roles with %s.",
    1175                 :                                "SUPERUSER", "SUPERUSER")));
    1176 GNC         684 :         if (!is_admin_of_role(GetUserId(), roleid))
    1177               3 :             ereport(ERROR,
    1178                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1179                 :                      errmsg("permission denied to drop role"),
    1180                 :                      errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.",
    1181                 :                                "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
    1182                 : 
    1183 ECB             :         /* DROP hook for the role being removed */
    1184 GIC         681 :         InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
    1185 ECB             : 
    1186                 :         /* Don't leak the syscache tuple */
    1187 GNC         681 :         ReleaseSysCache(tuple);
    1188                 : 
    1189                 :         /*
    1190                 :          * Lock the role, so nobody can add dependencies to her while we drop
    1191                 :          * her.  We keep the lock until the end of transaction.
    1192                 :          */
    1193 GIC         681 :         LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
    1194                 : 
    1195 ECB             :         /*
    1196                 :          * If there is a pg_auth_members entry that has one of the roles to be
    1197                 :          * dropped as the roleid or member, it should be silently removed, but
    1198                 :          * if there is a pg_auth_members entry that has one of the roles to be
    1199                 :          * dropped as the grantor, the operation should fail.
    1200                 :          *
    1201                 :          * It's possible, however, that a single pg_auth_members entry could
    1202                 :          * fall into multiple categories - e.g. the user could do "GRANT foo
    1203                 :          * TO bar GRANTED BY baz" and then "DROP ROLE baz, bar". We want such
    1204                 :          * an operation to succeed regardless of the order in which the
    1205                 :          * to-be-dropped roles are passed to DROP ROLE.
    1206                 :          *
    1207                 :          * To make that work, we remove all pg_auth_members entries that can
    1208                 :          * be silently removed in this loop, and then below we'll make a
    1209                 :          * second pass over the list of roles to be removed and check for any
    1210                 :          * remaining dependencies.
    1211                 :          */
    1212 GIC         681 :         ScanKeyInit(&scankey,
    1213                 :                     Anum_pg_auth_members_roleid,
    1214                 :                     BTEqualStrategyNumber, F_OIDEQ,
    1215                 :                     ObjectIdGetDatum(roleid));
    1216                 : 
    1217 CBC         681 :         sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
    1218                 :                                    true, NULL, 1, &scankey);
    1219 ECB             : 
    1220 GBC         766 :         while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
    1221                 :         {
    1222                 :             Form_pg_auth_members authmem_form;
    1223                 : 
    1224 GNC          85 :             authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
    1225              85 :             deleteSharedDependencyRecordsFor(AuthMemRelationId,
    1226                 :                                              authmem_form->oid, 0);
    1227 GIC          85 :             CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
    1228                 :         }
    1229                 : 
    1230             681 :         systable_endscan(sscan);
    1231                 : 
    1232             681 :         ScanKeyInit(&scankey,
    1233 ECB             :                     Anum_pg_auth_members_member,
    1234                 :                     BTEqualStrategyNumber, F_OIDEQ,
    1235                 :                     ObjectIdGetDatum(roleid));
    1236 EUB             : 
    1237 GIC         681 :         sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
    1238                 :                                    true, NULL, 1, &scankey);
    1239                 : 
    1240             804 :         while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
    1241                 :         {
    1242                 :             Form_pg_auth_members authmem_form;
    1243                 : 
    1244 GNC         123 :             authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
    1245             123 :             deleteSharedDependencyRecordsFor(AuthMemRelationId,
    1246                 :                                              authmem_form->oid, 0);
    1247 GIC         123 :             CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
    1248 ECB             :         }
    1249                 : 
    1250 GIC         681 :         systable_endscan(sscan);
    1251                 : 
    1252 EUB             :         /*
    1253                 :          * Advance command counter so that later iterations of this loop will
    1254                 :          * see the changes already made.  This is essential if, for example,
    1255                 :          * we are trying to drop both a role and one of its direct members ---
    1256                 :          * we'll get an error if we try to delete the linking pg_auth_members
    1257                 :          * tuple twice.  (We do not need a CCI between the two delete loops
    1258 ECB             :          * above, because it's not allowed for a role to directly contain
    1259                 :          * itself.)
    1260                 :          */
    1261 CBC         681 :         CommandCounterIncrement();
    1262                 : 
    1263                 :         /* Looks tentatively OK, add it to the list. */
    1264 GNC         681 :         role_address = palloc(sizeof(ObjectAddress));
    1265             681 :         role_address->classId = AuthIdRelationId;
    1266             681 :         role_address->objectId = roleid;
    1267             681 :         role_address->objectSubId = 0;
    1268             681 :         role_addresses = lappend(role_addresses, role_address);
    1269                 :     }
    1270                 : 
    1271                 :     /*
    1272                 :      * Second pass over the roles to be removed.
    1273                 :      */
    1274            1362 :     foreach(item, role_addresses)
    1275                 :     {
    1276             681 :         ObjectAddress *role_address = lfirst(item);
    1277             681 :         Oid         roleid = role_address->objectId;
    1278                 :         HeapTuple   tuple;
    1279                 :         Form_pg_authid roleform;
    1280                 :         char       *detail;
    1281                 :         char       *detail_log;
    1282                 : 
    1283                 :         /*
    1284                 :          * Re-find the pg_authid tuple.
    1285                 :          *
    1286                 :          * Since we've taken a lock on the role OID, it shouldn't be possible
    1287                 :          * for the tuple to have been deleted -- or for that matter updated --
    1288                 :          * unless the user is manually modifying the system catalogs.
    1289                 :          */
    1290             681 :         tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    1291             681 :         if (!HeapTupleIsValid(tuple))
    1292 UNC           0 :             elog(ERROR, "could not find tuple for role %u", roleid);
    1293 GNC         681 :         roleform = (Form_pg_authid) GETSTRUCT(tuple);
    1294                 : 
    1295                 :         /*
    1296                 :          * Check for pg_shdepend entries depending on this role.
    1297                 :          *
    1298                 :          * This needs to happen after we've completed removing any
    1299                 :          * pg_auth_members entries that can be removed silently, in order to
    1300                 :          * avoid spurious failures. See notes above for more details.
    1301                 :          */
    1302             681 :         if (checkSharedDependencies(AuthIdRelationId, roleid,
    1303                 :                                     &detail, &detail_log))
    1304              62 :             ereport(ERROR,
    1305                 :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    1306                 :                      errmsg("role \"%s\" cannot be dropped because some objects depend on it",
    1307                 :                             NameStr(roleform->rolname)),
    1308                 :                      errdetail_internal("%s", detail),
    1309                 :                      errdetail_log("%s", detail_log)));
    1310                 : 
    1311                 :         /*
    1312                 :          * Remove the role from the pg_authid table
    1313                 :          */
    1314             619 :         CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
    1315                 : 
    1316             619 :         ReleaseSysCache(tuple);
    1317                 : 
    1318                 :         /*
    1319                 :          * Remove any comments or security labels on this role.
    1320                 :          */
    1321             619 :         DeleteSharedComments(roleid, AuthIdRelationId);
    1322             619 :         DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
    1323                 : 
    1324                 :         /*
    1325                 :          * Remove settings for this role.
    1326                 :          */
    1327             619 :         DropSetting(InvalidOid, roleid);
    1328 EUB             :     }
    1329                 : 
    1330                 :     /*
    1331                 :      * Now we can clean up; but keep locks until commit.
    1332                 :      */
    1333 GIC         681 :     table_close(pg_auth_members_rel, NoLock);
    1334             681 :     table_close(pg_authid_rel, NoLock);
    1335 CBC         681 : }
    1336                 : 
    1337 ECB             : /*
    1338                 :  * Rename role
    1339                 :  */
    1340                 : ObjectAddress
    1341 GIC          15 : RenameRole(const char *oldname, const char *newname)
    1342                 : {
    1343                 :     HeapTuple   oldtuple,
    1344                 :                 newtuple;
    1345 ECB             :     TupleDesc   dsc;
    1346                 :     Relation    rel;
    1347                 :     Datum       datum;
    1348                 :     bool        isnull;
    1349                 :     Datum       repl_val[Natts_pg_authid];
    1350                 :     bool        repl_null[Natts_pg_authid];
    1351                 :     bool        repl_repl[Natts_pg_authid];
    1352                 :     int         i;
    1353 EUB             :     Oid         roleid;
    1354                 :     ObjectAddress address;
    1355                 :     Form_pg_authid authform;
    1356                 : 
    1357 GIC          15 :     rel = table_open(AuthIdRelationId, RowExclusiveLock);
    1358              15 :     dsc = RelationGetDescr(rel);
    1359                 : 
    1360              15 :     oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
    1361              15 :     if (!HeapTupleIsValid(oldtuple))
    1362 UIC           0 :         ereport(ERROR,
    1363 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1364                 :                  errmsg("role \"%s\" does not exist", oldname)));
    1365                 : 
    1366                 :     /*
    1367                 :      * XXX Client applications probably store the session user somewhere, so
    1368                 :      * renaming it could cause confusion.  On the other hand, there may not be
    1369                 :      * an actual problem besides a little confusion, so think about this and
    1370                 :      * decide.  Same for SET ROLE ... we don't restrict renaming the current
    1371                 :      * effective userid, though.
    1372                 :      */
    1373                 : 
    1374 GIC          15 :     authform = (Form_pg_authid) GETSTRUCT(oldtuple);
    1375              15 :     roleid = authform->oid;
    1376                 : 
    1377              15 :     if (roleid == GetSessionUserId())
    1378 LBC           0 :         ereport(ERROR,
    1379 EUB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1380                 :                  errmsg("session user cannot be renamed")));
    1381 GIC          15 :     if (roleid == GetOuterUserId())
    1382 LBC           0 :         ereport(ERROR,
    1383                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1384 ECB             :                  errmsg("current user cannot be renamed")));
    1385                 : 
    1386                 :     /*
    1387                 :      * Check that the user is not trying to rename a system role and not
    1388                 :      * trying to rename a role into the reserved "pg_" namespace.
    1389                 :      */
    1390 GIC          15 :     if (IsReservedName(NameStr(authform->rolname)))
    1391 UIC           0 :         ereport(ERROR,
    1392                 :                 (errcode(ERRCODE_RESERVED_NAME),
    1393                 :                  errmsg("role name \"%s\" is reserved",
    1394                 :                         NameStr(authform->rolname)),
    1395 ECB             :                  errdetail("Role names starting with \"pg_\" are reserved.")));
    1396                 : 
    1397 GIC          15 :     if (IsReservedName(newname))
    1398 UIC           0 :         ereport(ERROR,
    1399                 :                 (errcode(ERRCODE_RESERVED_NAME),
    1400 ECB             :                  errmsg("role name \"%s\" is reserved",
    1401                 :                         newname),
    1402                 :                  errdetail("Role names starting with \"pg_\" are reserved.")));
    1403                 : 
    1404                 :     /*
    1405                 :      * If built with appropriate switch, whine when regression-testing
    1406                 :      * conventions for role names are violated.
    1407                 :      */
    1408                 : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
    1409                 :     if (strncmp(newname, "regress_", 8) != 0)
    1410                 :         elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
    1411 EUB             : #endif
    1412                 : 
    1413                 :     /* make sure the new name doesn't exist */
    1414 CBC          15 :     if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
    1415 UBC           0 :         ereport(ERROR,
    1416                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    1417                 :                  errmsg("role \"%s\" already exists", newname)));
    1418                 : 
    1419                 :     /*
    1420                 :      * Only superusers can mess with superusers. Otherwise, a user with
    1421                 :      * CREATEROLE can rename a role for which they have ADMIN OPTION.
    1422                 :      */
    1423 GNC          15 :     if (authform->rolsuper)
    1424                 :     {
    1425 CBC           3 :         if (!superuser())
    1426 LBC           0 :             ereport(ERROR,
    1427                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1428                 :                      errmsg("permission denied to rename role"),
    1429                 :                      errdetail("Only roles with the %s attribute may rename roles with %s.",
    1430                 :                                "SUPERUSER", "SUPERUSER")));
    1431                 :     }
    1432                 :     else
    1433 ECB             :     {
    1434 GNC          12 :         if (!have_createrole_privilege() ||
    1435              12 :             !is_admin_of_role(GetUserId(), roleid))
    1436 GIC           3 :             ereport(ERROR,
    1437                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1438                 :                      errmsg("permission denied to rename role"),
    1439                 :                      errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.",
    1440                 :                                "CREATEROLE", "ADMIN", NameStr(authform->rolname))));
    1441                 :     }
    1442                 : 
    1443                 :     /* OK, construct the modified tuple */
    1444 CBC         156 :     for (i = 0; i < Natts_pg_authid; i++)
    1445 GIC         144 :         repl_repl[i] = false;
    1446                 : 
    1447 CBC          12 :     repl_repl[Anum_pg_authid_rolname - 1] = true;
    1448 GIC          12 :     repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
    1449                 :                                                                CStringGetDatum(newname));
    1450              12 :     repl_null[Anum_pg_authid_rolname - 1] = false;
    1451                 : 
    1452              12 :     datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
    1453 ECB             : 
    1454 GIC          12 :     if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
    1455                 :     {
    1456                 :         /* MD5 uses the username as salt, so just clear it on a rename */
    1457               3 :         repl_repl[Anum_pg_authid_rolpassword - 1] = true;
    1458               3 :         repl_null[Anum_pg_authid_rolpassword - 1] = true;
    1459                 : 
    1460               3 :         ereport(NOTICE,
    1461                 :                 (errmsg("MD5 password cleared because of role rename")));
    1462                 :     }
    1463                 : 
    1464              12 :     newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
    1465              12 :     CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
    1466                 : 
    1467              12 :     InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
    1468                 : 
    1469              12 :     ObjectAddressSet(address, AuthIdRelationId, roleid);
    1470                 : 
    1471              12 :     ReleaseSysCache(oldtuple);
    1472 ECB             : 
    1473                 :     /*
    1474                 :      * Close pg_authid, but keep lock till commit.
    1475                 :      */
    1476 GIC          12 :     table_close(rel, NoLock);
    1477 ECB             : 
    1478 GIC          12 :     return address;
    1479                 : }
    1480 ECB             : 
    1481                 : /*
    1482                 :  * GrantRoleStmt
    1483                 :  *
    1484                 :  * Grant/Revoke roles to/from roles
    1485                 :  */
    1486                 : void
    1487 GNC        1175 : GrantRole(ParseState *pstate, GrantRoleStmt *stmt)
    1488                 : {
    1489                 :     Relation    pg_authid_rel;
    1490 ECB             :     Oid         grantor;
    1491                 :     List       *grantee_ids;
    1492                 :     ListCell   *item;
    1493                 :     GrantRoleOptions    popt;
    1494 GNC        1175 :     Oid         currentUserId = GetUserId();
    1495                 : 
    1496                 :     /* Parse options list. */
    1497            1175 :     InitGrantRoleOptions(&popt);
    1498            1281 :     foreach(item, stmt->opt)
    1499                 :     {
    1500             106 :         DefElem    *opt = (DefElem *) lfirst(item);
    1501             106 :         char       *optval = defGetString(opt);
    1502                 : 
    1503             106 :         if (strcmp(opt->defname, "admin") == 0)
    1504                 :         {
    1505              64 :             popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
    1506                 : 
    1507              64 :             if (parse_bool(optval, &popt.admin))
    1508              64 :                 continue;
    1509                 :         }
    1510              42 :         else if (strcmp(opt->defname, "inherit") == 0)
    1511                 :         {
    1512              24 :             popt.specified |= GRANT_ROLE_SPECIFIED_INHERIT;
    1513              24 :             if (parse_bool(optval, &popt.inherit))
    1514              24 :                 continue;
    1515                 :         }
    1516              18 :         else if (strcmp(opt->defname, "set") == 0)
    1517                 :         {
    1518              18 :             popt.specified |= GRANT_ROLE_SPECIFIED_SET;
    1519              18 :             if (parse_bool(optval, &popt.set))
    1520              18 :                 continue;
    1521                 :         }
    1522                 :         else
    1523 UNC           0 :             ereport(ERROR,
    1524                 :                     errcode(ERRCODE_SYNTAX_ERROR),
    1525                 :                     errmsg("unrecognized role option \"%s\"", opt->defname),
    1526                 :                     parser_errposition(pstate, opt->location));
    1527                 : 
    1528               0 :         ereport(ERROR,
    1529                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1530                 :                  errmsg("unrecognized value for role option \"%s\": \"%s\"",
    1531                 :                         opt->defname, optval),
    1532                 :                  parser_errposition(pstate, opt->location)));
    1533                 :     }
    1534                 : 
    1535                 :     /* Lookup OID of grantor, if specified. */
    1536 GIC        1175 :     if (stmt->grantor)
    1537              39 :         grantor = get_rolespec_oid(stmt->grantor, false);
    1538                 :     else
    1539 GNC        1136 :         grantor = InvalidOid;
    1540                 : 
    1541 GIC        1172 :     grantee_ids = roleSpecsToIds(stmt->grantee_roles);
    1542 ECB             : 
    1543                 :     /* AccessShareLock is enough since we aren't modifying pg_authid */
    1544 GIC        1172 :     pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock);
    1545                 : 
    1546 ECB             :     /*
    1547                 :      * Step through all of the granted roles and add, update, or remove
    1548                 :      * entries in pg_auth_members as appropriate. If stmt->is_grant is true,
    1549                 :      * we are adding new grants or, if they already exist, updating options
    1550                 :      * on those grants. If stmt->is_grant is false, we are revoking grants or
    1551                 :      * removing options from them.
    1552                 :      */
    1553 GIC        2285 :     foreach(item, stmt->granted_roles)
    1554                 :     {
    1555            1173 :         AccessPriv *priv = (AccessPriv *) lfirst(item);
    1556            1173 :         char       *rolename = priv->priv_name;
    1557                 :         Oid         roleid;
    1558                 : 
    1559                 :         /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
    1560            1173 :         if (rolename == NULL || priv->cols != NIL)
    1561 UIC           0 :             ereport(ERROR,
    1562                 :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1563 ECB             :                      errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
    1564                 : 
    1565 GIC        1173 :         roleid = get_role_oid(rolename, false);
    1566 GNC        1173 :         check_role_membership_authorization(currentUserId,
    1567            1173 :                                             roleid, stmt->is_grant);
    1568 CBC        1128 :         if (stmt->is_grant)
    1569 GNC        1052 :             AddRoleMems(currentUserId, rolename, roleid,
    1570 ECB             :                         stmt->grantee_roles, grantee_ids,
    1571                 :                         grantor, &popt);
    1572                 :         else
    1573 GNC          76 :             DelRoleMems(currentUserId, rolename, roleid,
    1574                 :                         stmt->grantee_roles, grantee_ids,
    1575                 :                         grantor, &popt, stmt->behavior);
    1576                 :     }
    1577                 : 
    1578 ECB             :     /*
    1579                 :      * Close pg_authid, but keep lock till commit.
    1580                 :      */
    1581 CBC        1112 :     table_close(pg_authid_rel, NoLock);
    1582 GIC        1112 : }
    1583                 : 
    1584                 : /*
    1585                 :  * DropOwnedObjects
    1586                 :  *
    1587                 :  * Drop the objects owned by a given list of roles.
    1588                 :  */
    1589                 : void
    1590              69 : DropOwnedObjects(DropOwnedStmt *stmt)
    1591                 : {
    1592              69 :     List       *role_ids = roleSpecsToIds(stmt->roles);
    1593                 :     ListCell   *cell;
    1594 ECB             : 
    1595                 :     /* Check privileges */
    1596 GBC         147 :     foreach(cell, role_ids)
    1597 ECB             :     {
    1598 GIC          84 :         Oid         roleid = lfirst_oid(cell);
    1599                 : 
    1600              84 :         if (!has_privs_of_role(GetUserId(), roleid))
    1601               6 :             ereport(ERROR,
    1602                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1603                 :                      errmsg("permission denied to drop objects"),
    1604                 :                      errdetail("Only roles with privileges of role \"%s\" may drop objects owned by it.",
    1605                 :                                GetUserNameFromId(roleid, false))));
    1606                 :     }
    1607                 : 
    1608 ECB             :     /* Ok, do it */
    1609 GIC          63 :     shdepDropOwned(role_ids, stmt->behavior);
    1610 CBC          60 : }
    1611                 : 
    1612                 : /*
    1613                 :  * ReassignOwnedObjects
    1614                 :  *
    1615                 :  * Give the objects owned by a given list of roles away to another user.
    1616                 :  */
    1617                 : void
    1618 GIC          19 : ReassignOwnedObjects(ReassignOwnedStmt *stmt)
    1619                 : {
    1620 CBC          19 :     List       *role_ids = roleSpecsToIds(stmt->roles);
    1621                 :     ListCell   *cell;
    1622 ECB             :     Oid         newrole;
    1623                 : 
    1624                 :     /* Check privileges */
    1625 GIC          32 :     foreach(cell, role_ids)
    1626                 :     {
    1627 CBC          19 :         Oid         roleid = lfirst_oid(cell);
    1628 ECB             : 
    1629 GIC          19 :         if (!has_privs_of_role(GetUserId(), roleid))
    1630               6 :             ereport(ERROR,
    1631                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1632                 :                      errmsg("permission denied to reassign objects"),
    1633                 :                      errdetail("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
    1634                 :                                GetUserNameFromId(roleid, false))));
    1635 ECB             :     }
    1636                 : 
    1637                 :     /* Must have privileges on the receiving side too */
    1638 GIC          13 :     newrole = get_rolespec_oid(stmt->newrole, false);
    1639                 : 
    1640              13 :     if (!has_privs_of_role(GetUserId(), newrole))
    1641 CBC           3 :         ereport(ERROR,
    1642 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1643                 :                  errmsg("permission denied to reassign objects"),
    1644                 :                  errdetail("Only roles with privileges of role \"%s\" may reassign objects to it.",
    1645                 :                            GetUserNameFromId(newrole, false))));
    1646                 : 
    1647                 :     /* Ok, do it */
    1648 GIC          10 :     shdepReassignOwned(role_ids, newrole);
    1649              10 : }
    1650                 : 
    1651 ECB             : /*
    1652                 :  * roleSpecsToIds
    1653                 :  *
    1654                 :  * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
    1655                 :  *
    1656                 :  * ROLESPEC_PUBLIC is not allowed.
    1657                 :  */
    1658                 : List *
    1659 GIC        2769 : roleSpecsToIds(List *memberNames)
    1660                 : {
    1661            2769 :     List       *result = NIL;
    1662                 :     ListCell   *l;
    1663                 : 
    1664            4123 :     foreach(l, memberNames)
    1665                 :     {
    1666            1354 :         RoleSpec   *rolespec = lfirst_node(RoleSpec, l);
    1667 ECB             :         Oid         roleid;
    1668                 : 
    1669 GIC        1354 :         roleid = get_rolespec_oid(rolespec, false);
    1670 CBC        1354 :         result = lappend_oid(result, roleid);
    1671 ECB             :     }
    1672 GBC        2769 :     return result;
    1673                 : }
    1674                 : 
    1675                 : /*
    1676                 :  * AddRoleMems -- Add given members to the specified role
    1677                 :  *
    1678                 :  * currentUserId: OID of role performing the operation
    1679                 :  * rolename: name of role to add to (used only for error messages)
    1680                 :  * roleid: OID of role to add to
    1681                 :  * memberSpecs: list of RoleSpec of roles to add (used only for error messages)
    1682                 :  * memberIds: OIDs of roles to add
    1683                 :  * grantorId: OID that should be recorded as having granted the membership
    1684                 :  * (InvalidOid if not set explicitly)
    1685                 :  * popt: information about grant options
    1686 ECB             :  */
    1687                 : static void
    1688 GNC        2615 : AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
    1689 ECB             :             List *memberSpecs, List *memberIds,
    1690                 :             Oid grantorId, GrantRoleOptions *popt)
    1691                 : {
    1692                 :     Relation    pg_authmem_rel;
    1693                 :     TupleDesc   pg_authmem_dsc;
    1694 EUB             :     ListCell   *specitem;
    1695                 :     ListCell   *iditem;
    1696                 : 
    1697 GIC        2615 :     Assert(list_length(memberSpecs) == list_length(memberIds));
    1698                 : 
    1699                 :     /* Validate grantor (and resolve implicit grantor if not specified). */
    1700 GNC        2615 :     grantorId = check_role_grantor(currentUserId, roleid, grantorId, true);
    1701                 : 
    1702 CBC        2612 :     pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
    1703            2612 :     pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
    1704 ECB             : 
    1705                 :     /*
    1706                 :      * Only allow changes to this role by one backend at a time, so that we
    1707                 :      * can check integrity constraints like the lack of circular ADMIN OPTION
    1708                 :      * grants without fear of race conditions.
    1709                 :      */
    1710 GNC        2612 :     LockSharedObject(AuthIdRelationId, roleid, 0,
    1711                 :                      ShareUpdateExclusiveLock);
    1712                 : 
    1713                 :     /* Preliminary sanity checks. */
    1714 GIC        3800 :     forboth(specitem, memberSpecs, iditem, memberIds)
    1715                 :     {
    1716            1197 :         RoleSpec   *memberRole = lfirst_node(RoleSpec, specitem);
    1717            1197 :         Oid         memberid = lfirst_oid(iditem);
    1718                 : 
    1719 ECB             :         /*
    1720                 :          * pg_database_owner is never a role member.  Lifting this restriction
    1721                 :          * would require a policy decision about membership loops.  One could
    1722                 :          * prevent loops, which would include making "ALTER DATABASE x OWNER
    1723                 :          * TO proposed_datdba" fail if is_member_of_role(pg_database_owner,
    1724                 :          * proposed_datdba).  Hence, gaining a membership could reduce what a
    1725                 :          * role could do.  Alternately, one could allow these memberships to
    1726                 :          * complete loops.  A role could then have actual WITH ADMIN OPTION on
    1727                 :          * itself, prompting a decision about is_admin_of_role() treatment of
    1728                 :          * the case.
    1729                 :          *
    1730                 :          * Lifting this restriction also has policy implications for ownership
    1731                 :          * of shared objects (databases and tablespaces).  We allow such
    1732                 :          * ownership, but we might find cause to ban it in the future.
    1733                 :          * Designing such a ban would more troublesome if the design had to
    1734                 :          * address pg_database_owner being a member of role FOO that owns a
    1735                 :          * shared object.  (The effect of such ownership is that any owner of
    1736                 :          * another database can act as the owner of affected shared objects.)
    1737                 :          */
    1738 GIC        1197 :         if (memberid == ROLE_PG_DATABASE_OWNER)
    1739 CBC           3 :             ereport(ERROR,
    1740                 :                     errmsg("role \"%s\" cannot be a member of any role",
    1741 ECB             :                            get_rolespec_name(memberRole)));
    1742                 : 
    1743                 :         /*
    1744                 :          * Refuse creation of membership loops, including the trivial case
    1745                 :          * where a role is made a member of itself.  We do this by checking to
    1746                 :          * see if the target role is already a member of the proposed member
    1747                 :          * role.  We have to ignore possible superuserness, however, else we
    1748                 :          * could never grant membership in a superuser-privileged role.
    1749                 :          */
    1750 CBC        1194 :         if (is_member_of_role_nosuper(roleid, memberid))
    1751 GIC           6 :             ereport(ERROR,
    1752                 :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1753                 :                      errmsg("role \"%s\" is a member of role \"%s\"",
    1754                 :                             rolename, get_rolespec_name(memberRole))));
    1755                 :     }
    1756                 : 
    1757                 :     /*
    1758                 :      * Disallow attempts to grant ADMIN OPTION back to a user who granted it
    1759                 :      * to you, similar to what check_circularity does for ACLs. We want the
    1760                 :      * chains of grants to remain acyclic, so that it's always possible to use
    1761                 :      * REVOKE .. CASCADE to clean up all grants that depend on the one being
    1762                 :      * revoked.
    1763                 :      *
    1764                 :      * NB: This check might look redundant with the check for membership loops
    1765                 :      * above, but it isn't. That's checking for role-member loop (e.g. A is a
    1766                 :      * member of B and B is a member of A) while this is checking for a
    1767                 :      * member-grantor loop (e.g. A gave ADMIN OPTION on X to B and now B, who
    1768                 :      * has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on
    1769                 :      * X back to A).
    1770                 :      */
    1771 GNC        2603 :     if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID)
    1772                 :     {
    1773                 :         CatCList   *memlist;
    1774                 :         RevokeRoleGrantAction *actions;
    1775                 :         int         i;
    1776                 : 
    1777                 :         /* Get the list of members for this role. */
    1778              63 :         memlist = SearchSysCacheList1(AUTHMEMROLEMEM,
    1779                 :                                       ObjectIdGetDatum(roleid));
    1780                 : 
    1781                 :         /*
    1782                 :          * Figure out what would happen if we removed all existing grants to
    1783                 :          * every role to which we've been asked to make a new grant.
    1784 ECB             :          */
    1785 GNC          63 :         actions = initialize_revoke_actions(memlist);
    1786              96 :         foreach(iditem, memberIds)
    1787 ECB             :         {
    1788 GNC          33 :             Oid         memberid = lfirst_oid(iditem);
    1789                 : 
    1790              33 :             if (memberid == BOOTSTRAP_SUPERUSERID)
    1791 UNC           0 :                 ereport(ERROR,
    1792                 :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1793                 :                          errmsg("%s option cannot be granted back to your own grantor",
    1794                 :                                 "ADMIN")));
    1795 GNC          33 :             plan_member_revoke(memlist, actions, memberid);
    1796 ECB             :         }
    1797                 : 
    1798                 :         /*
    1799                 :          * If the result would be that the grantor role would no longer have
    1800                 :          * the ability to perform the grant, then the proposed grant would
    1801                 :          * create a circularity.
    1802                 :          */
    1803 GNC          75 :         for (i = 0; i < memlist->n_members; ++i)
    1804                 :         {
    1805                 :             HeapTuple   authmem_tuple;
    1806                 :             Form_pg_auth_members authmem_form;
    1807                 : 
    1808              72 :             authmem_tuple = &memlist->members[i]->tuple;
    1809              72 :             authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    1810                 : 
    1811              72 :             if (actions[i] == RRG_NOOP &&
    1812              66 :                 authmem_form->member == grantorId &&
    1813              60 :                 authmem_form->admin_option)
    1814              60 :                 break;
    1815                 :         }
    1816              63 :         if (i >= memlist->n_members)
    1817               3 :             ereport(ERROR,
    1818                 :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1819                 :                      errmsg("%s option cannot be granted back to your own grantor",
    1820                 :                             "ADMIN")));
    1821                 : 
    1822              60 :         ReleaseSysCacheList(memlist);
    1823                 :     }
    1824                 : 
    1825                 :     /* Now perform the catalog updates. */
    1826            3785 :     forboth(specitem, memberSpecs, iditem, memberIds)
    1827                 :     {
    1828            1185 :         RoleSpec   *memberRole = lfirst_node(RoleSpec, specitem);
    1829            1185 :         Oid         memberid = lfirst_oid(iditem);
    1830                 :         HeapTuple   authmem_tuple;
    1831                 :         HeapTuple   tuple;
    1832            1185 :         Datum       new_record[Natts_pg_auth_members] = {0};
    1833            1185 :         bool        new_record_nulls[Natts_pg_auth_members] = {0};
    1834            1185 :         bool        new_record_repl[Natts_pg_auth_members] = {0};
    1835                 : 
    1836                 :         /* Common initialization for possible insert or update */
    1837            1185 :         new_record[Anum_pg_auth_members_roleid - 1] =
    1838            1185 :             ObjectIdGetDatum(roleid);
    1839            1185 :         new_record[Anum_pg_auth_members_member - 1] =
    1840            1185 :             ObjectIdGetDatum(memberid);
    1841            1185 :         new_record[Anum_pg_auth_members_grantor - 1] =
    1842            1185 :             ObjectIdGetDatum(grantorId);
    1843                 : 
    1844                 :         /* Find any existing tuple */
    1845            1185 :         authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM,
    1846                 :                                         ObjectIdGetDatum(roleid),
    1847                 :                                         ObjectIdGetDatum(memberid),
    1848                 :                                         ObjectIdGetDatum(grantorId));
    1849                 : 
    1850                 :         /*
    1851                 :          * If we found a tuple, update it with new option values, unless
    1852                 :          * there are no changes, in which case issue a WARNING.
    1853                 :          *
    1854                 :          * If we didn't find a tuple, just insert one.
    1855                 :          */
    1856 CBC        1185 :         if (HeapTupleIsValid(authmem_tuple))
    1857 ECB             :         {
    1858                 :             Form_pg_auth_members authmem_form;
    1859 GNC          16 :             bool        at_least_one_change = false;
    1860                 : 
    1861              16 :             authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    1862                 : 
    1863              16 :             if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0
    1864 UNC           0 :                 && authmem_form->admin_option != popt->admin)
    1865                 :             {
    1866               0 :                 new_record[Anum_pg_auth_members_admin_option - 1] =
    1867               0 :                     BoolGetDatum(popt->admin);
    1868               0 :                 new_record_repl[Anum_pg_auth_members_admin_option - 1] =
    1869                 :                     true;
    1870               0 :                 at_least_one_change = true;
    1871                 :             }
    1872                 : 
    1873 GNC          16 :             if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0
    1874               7 :                 && authmem_form->inherit_option != popt->inherit)
    1875                 :             {
    1876               7 :                 new_record[Anum_pg_auth_members_inherit_option - 1] =
    1877               7 :                     BoolGetDatum(popt->inherit);
    1878               7 :                 new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
    1879                 :                     true;
    1880               7 :                 at_least_one_change = true;
    1881                 :             }
    1882                 : 
    1883              16 :             if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
    1884               4 :                 && authmem_form->set_option != popt->set)
    1885                 :             {
    1886               4 :                 new_record[Anum_pg_auth_members_set_option - 1] =
    1887               4 :                     BoolGetDatum(popt->set);
    1888               4 :                 new_record_repl[Anum_pg_auth_members_set_option - 1] =
    1889                 :                     true;
    1890               4 :                 at_least_one_change = true;
    1891                 :             }
    1892                 : 
    1893              16 :             if (!at_least_one_change)
    1894                 :             {
    1895               9 :                 ereport(NOTICE,
    1896                 :                         (errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
    1897                 :                                 get_rolespec_name(memberRole), rolename,
    1898                 :                                 GetUserNameFromId(grantorId, false))));
    1899               9 :                 ReleaseSysCache(authmem_tuple);
    1900               9 :                 continue;
    1901                 :             }
    1902                 : 
    1903 CBC           7 :             tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
    1904                 :                                       new_record,
    1905 ECB             :                                       new_record_nulls, new_record_repl);
    1906 CBC           7 :             CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
    1907                 : 
    1908               7 :             ReleaseSysCache(authmem_tuple);
    1909                 :         }
    1910                 :         else
    1911 EUB             :         {
    1912                 :             Oid         objectId;
    1913 GNC        1169 :             Oid        *newmembers = palloc(sizeof(Oid));
    1914                 : 
    1915                 :             /*
    1916                 :              * The values for these options can be taken directly from 'popt'.
    1917                 :              * Either they were specified, or the defaults as set by
    1918                 :              * InitGrantRoleOptions are correct.
    1919                 :              */
    1920            1169 :             new_record[Anum_pg_auth_members_admin_option - 1] =
    1921            1169 :                 BoolGetDatum(popt->admin);
    1922            1169 :             new_record[Anum_pg_auth_members_set_option - 1] =
    1923            1169 :                 BoolGetDatum(popt->set);
    1924                 : 
    1925                 :             /*
    1926                 :              * If the user specified a value for the inherit option, use
    1927                 :              * whatever was specified. Otherwise, set the default value based
    1928                 :              * on the role-level property.
    1929                 :              */
    1930            1169 :             if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
    1931              75 :                 new_record[Anum_pg_auth_members_inherit_option - 1] =
    1932              75 :                     popt->inherit;
    1933                 :             else
    1934                 :             {
    1935                 :                 HeapTuple       mrtup;
    1936                 :                 Form_pg_authid  mrform;
    1937                 : 
    1938            1094 :                 mrtup = SearchSysCache1(AUTHOID, memberid);
    1939            1094 :                 if (!HeapTupleIsValid(mrtup))
    1940 UNC           0 :                     elog(ERROR, "cache lookup failed for role %u", memberid);
    1941 GNC        1094 :                 mrform = (Form_pg_authid) GETSTRUCT(mrtup);
    1942            1094 :                 new_record[Anum_pg_auth_members_inherit_option - 1] =
    1943            1094 :                     mrform->rolinherit;
    1944            1094 :                 ReleaseSysCache(mrtup);
    1945                 :             }
    1946                 : 
    1947                 :             /* get an OID for the new row and insert it */
    1948            1169 :             objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
    1949                 :                                           Anum_pg_auth_members_oid);
    1950            1169 :             new_record[Anum_pg_auth_members_oid - 1] = objectId;
    1951 GIC        1169 :             tuple = heap_form_tuple(pg_authmem_dsc,
    1952                 :                                     new_record, new_record_nulls);
    1953            1169 :             CatalogTupleInsert(pg_authmem_rel, tuple);
    1954                 : 
    1955                 :             /* updateAclDependencies wants to pfree array inputs */
    1956 GNC        1169 :             newmembers[0] = grantorId;
    1957            1169 :             updateAclDependencies(AuthMemRelationId, objectId,
    1958                 :                                   0, InvalidOid,
    1959                 :                                   0, NULL,
    1960                 :                                   1, newmembers);
    1961                 :         }
    1962 EUB             : 
    1963                 :         /* CCI after each change, in case there are duplicates in list */
    1964 GIC        1176 :         CommandCounterIncrement();
    1965                 :     }
    1966                 : 
    1967                 :     /*
    1968                 :      * Close pg_authmem, but keep lock till commit.
    1969                 :      */
    1970 CBC        2600 :     table_close(pg_authmem_rel, NoLock);
    1971            2600 : }
    1972                 : 
    1973 ECB             : /*
    1974                 :  * DelRoleMems -- Remove given members from the specified role
    1975                 :  *
    1976                 :  * rolename: name of role to del from (used only for error messages)
    1977                 :  * roleid: OID of role to del from
    1978                 :  * memberSpecs: list of RoleSpec of roles to del (used only for error messages)
    1979                 :  * memberIds: OIDs of roles to del
    1980                 :  * grantorId: who is revoking the membership
    1981                 :  * popt: information about grant options
    1982                 :  * behavior: RESTRICT or CASCADE behavior for recursive removal
    1983                 :  */
    1984                 : static void
    1985 GNC          82 : DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
    1986                 :             List *memberSpecs, List *memberIds,
    1987                 :             Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
    1988                 : {
    1989 ECB             :     Relation    pg_authmem_rel;
    1990                 :     TupleDesc   pg_authmem_dsc;
    1991                 :     ListCell   *specitem;
    1992                 :     ListCell   *iditem;
    1993                 :     CatCList   *memlist;
    1994                 :     RevokeRoleGrantAction *actions;
    1995                 :     int         i;
    1996                 : 
    1997 GIC          82 :     Assert(list_length(memberSpecs) == list_length(memberIds));
    1998                 : 
    1999                 :     /* Validate grantor (and resolve implicit grantor if not specified). */
    2000 GNC          82 :     grantorId = check_role_grantor(currentUserId, roleid, grantorId, false);
    2001                 : 
    2002 GIC          82 :     pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
    2003              82 :     pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
    2004                 : 
    2005                 :     /*
    2006                 :      * Only allow changes to this role by one backend at a time, so that we
    2007                 :      * can check for things like dependent privileges without fear of race
    2008                 :      * conditions.
    2009                 :      */
    2010 GNC          82 :     LockSharedObject(AuthIdRelationId, roleid, 0,
    2011                 :                      ShareUpdateExclusiveLock);
    2012                 : 
    2013              82 :     memlist = SearchSysCacheList1(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid));
    2014              82 :     actions = initialize_revoke_actions(memlist);
    2015                 : 
    2016                 :     /*
    2017                 :      * We may need to recurse to dependent privileges if DROP_CASCADE was
    2018                 :      * specified, or refuse to perform the operation if dependent privileges
    2019                 :      * exist and DROP_RESTRICT was specified. plan_single_revoke() will figure
    2020                 :      * out what to do with each catalog tuple.
    2021                 :      */
    2022 GIC         158 :     forboth(specitem, memberSpecs, iditem, memberIds)
    2023                 :     {
    2024 CBC          82 :         RoleSpec   *memberRole = lfirst(specitem);
    2025 GIC          82 :         Oid         memberid = lfirst_oid(iditem);
    2026                 : 
    2027 GNC          82 :         if (!plan_single_revoke(memlist, actions, memberid, grantorId,
    2028                 :                                 popt, behavior))
    2029 ECB             :         {
    2030 GIC           3 :             ereport(WARNING,
    2031                 :                     (errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"",
    2032                 :                             get_rolespec_name(memberRole), rolename,
    2033                 :                             GetUserNameFromId(grantorId, false))));
    2034               3 :             continue;
    2035                 :         }
    2036                 :     }
    2037                 : 
    2038                 :     /*
    2039                 :      * We now know what to do with each catalog tuple: it should either be
    2040                 :      * left alone, deleted, or just have the admin_option flag cleared.
    2041                 :      * Perform the appropriate action in each case.
    2042                 :      */
    2043 GNC         221 :     for (i = 0; i < memlist->n_members; ++i)
    2044                 :     {
    2045                 :         HeapTuple   authmem_tuple;
    2046                 :         Form_pg_auth_members authmem_form;
    2047                 : 
    2048             145 :         if (actions[i] == RRG_NOOP)
    2049              63 :             continue;
    2050                 : 
    2051              82 :         authmem_tuple = &memlist->members[i]->tuple;
    2052              82 :         authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    2053                 : 
    2054              82 :         if (actions[i] == RRG_DELETE_GRANT)
    2055 ECB             :         {
    2056                 :             /*
    2057                 :              * Remove the entry altogether, after first removing its
    2058                 :              * dependencies
    2059                 :              */
    2060 GNC          58 :             deleteSharedDependencyRecordsFor(AuthMemRelationId,
    2061                 :                                              authmem_form->oid, 0);
    2062 GIC          58 :             CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
    2063                 :         }
    2064                 :         else
    2065                 :         {
    2066                 :             /* Just turn off the specified option */
    2067                 :             HeapTuple   tuple;
    2068 GNC          24 :             Datum       new_record[Natts_pg_auth_members] = {0};
    2069              24 :             bool        new_record_nulls[Natts_pg_auth_members] = {0};
    2070              24 :             bool        new_record_repl[Natts_pg_auth_members] = {0};
    2071 ECB             : 
    2072                 :             /* Build a tuple to update with */
    2073 GNC          24 :             if (actions[i] == RRG_REMOVE_ADMIN_OPTION)
    2074                 :             {
    2075              15 :                 new_record[Anum_pg_auth_members_admin_option - 1] =
    2076              15 :                     BoolGetDatum(false);
    2077              15 :                 new_record_repl[Anum_pg_auth_members_admin_option - 1] =
    2078                 :                     true;
    2079                 :             }
    2080               9 :             else if (actions[i] == RRG_REMOVE_INHERIT_OPTION)
    2081                 :             {
    2082               6 :                 new_record[Anum_pg_auth_members_inherit_option - 1] =
    2083               6 :                     BoolGetDatum(false);
    2084               6 :                 new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
    2085                 :                     true;
    2086                 :             }
    2087               3 :             else if (actions[i] == RRG_REMOVE_SET_OPTION)
    2088                 :             {
    2089               3 :                 new_record[Anum_pg_auth_members_set_option - 1] =
    2090               3 :                     BoolGetDatum(false);
    2091               3 :                 new_record_repl[Anum_pg_auth_members_set_option - 1] =
    2092                 :                     true;
    2093                 :             }
    2094                 :             else
    2095 UNC           0 :                 elog(ERROR, "unknown role revoke action");
    2096                 : 
    2097 CBC          24 :             tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
    2098 ECB             :                                       new_record,
    2099                 :                                       new_record_nulls, new_record_repl);
    2100 GIC          24 :             CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
    2101                 :         }
    2102                 :     }
    2103 ECB             : 
    2104 GNC          76 :     ReleaseSysCacheList(memlist);
    2105                 : 
    2106 ECB             :     /*
    2107                 :      * Close pg_authmem, but keep lock till commit.
    2108                 :      */
    2109 GIC          76 :     table_close(pg_authmem_rel, NoLock);
    2110              76 : }
    2111                 : 
    2112                 : /*
    2113                 :  * Check that currentUserId has permission to modify the membership list for
    2114                 :  * roleid. Throw an error if not.
    2115                 :  */
    2116                 : static void
    2117 GNC        1221 : check_role_membership_authorization(Oid currentUserId, Oid roleid,
    2118                 :                                     bool is_grant)
    2119                 : {
    2120                 :     /*
    2121                 :      * The charter of pg_database_owner is to have exactly one, implicit,
    2122                 :      * situation-dependent member.  There's no technical need for this
    2123                 :      * restriction.  (One could lift it and take the further step of making
    2124                 :      * object_ownercheck(DatabaseRelationId, ...) equivalent to
    2125                 :      * has_privs_of_role(roleid, ROLE_PG_DATABASE_OWNER), in which case
    2126                 :      * explicit, situation-independent members could act as the owner of any
    2127                 :      * database.)
    2128                 :      */
    2129            1221 :     if (is_grant && roleid == ROLE_PG_DATABASE_OWNER)
    2130               6 :         ereport(ERROR,
    2131                 :                 errmsg("role \"%s\" cannot have explicit members",
    2132                 :                        GetUserNameFromId(roleid, false)));
    2133                 : 
    2134                 :     /* To mess with a superuser role, you gotta be superuser. */
    2135            1215 :     if (superuser_arg(roleid))
    2136                 :     {
    2137               8 :         if (!superuser_arg(currentUserId))
    2138                 :         {
    2139               3 :             if (is_grant)
    2140               3 :                 ereport(ERROR,
    2141                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2142                 :                          errmsg("permission denied to grant role \"%s\"",
    2143                 :                                 GetUserNameFromId(roleid, false)),
    2144                 :                          errdetail("Only roles with the %s attribute may grant roles with %s.",
    2145                 :                                    "SUPERUSER", "SUPERUSER")));
    2146                 :             else
    2147 UNC           0 :                 ereport(ERROR,
    2148                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2149                 :                          errmsg("permission denied to revoke role \"%s\"",
    2150                 :                                 GetUserNameFromId(roleid, false)),
    2151                 :                          errdetail("Only roles with the %s attribute may revoke roles with %s.",
    2152                 :                                    "SUPERUSER", "SUPERUSER")));
    2153                 :         }
    2154                 :     }
    2155                 :     else
    2156                 :     {
    2157                 :         /*
    2158                 :          * Otherwise, must have admin option on the role to be changed.
    2159                 :          */
    2160 GNC        1207 :         if (!is_admin_of_role(currentUserId, roleid))
    2161                 :         {
    2162              72 :             if (is_grant)
    2163              72 :                 ereport(ERROR,
    2164                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2165                 :                          errmsg("permission denied to grant role \"%s\"",
    2166                 :                                 GetUserNameFromId(roleid, false)),
    2167                 :                          errdetail("Only roles with the %s option on role \"%s\" may grant this role.",
    2168                 :                                    "ADMIN", GetUserNameFromId(roleid, false))));
    2169                 :             else
    2170 UNC           0 :                 ereport(ERROR,
    2171                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2172                 :                          errmsg("permission denied to revoke role \"%s\"",
    2173                 :                                 GetUserNameFromId(roleid, false)),
    2174                 :                          errdetail("Only roles with the %s option on role \"%s\" may revoke this role.",
    2175                 :                                    "ADMIN", GetUserNameFromId(roleid, false))));
    2176                 :         }
    2177                 :     }
    2178 GNC        1140 : }
    2179                 : 
    2180                 : /*
    2181                 :  * Sanity-check, or infer, the grantor for a GRANT or REVOKE statement
    2182                 :  * targeting a role.
    2183                 :  *
    2184                 :  * The grantor must always be either a role with ADMIN OPTION on the role in
    2185                 :  * which membership is being granted, or the bootstrap superuser. This is
    2186                 :  * similar to the restriction enforced by select_best_grantor, except that
    2187                 :  * roles don't have owners, so we regard the bootstrap superuser as the
    2188                 :  * implicit owner.
    2189                 :  *
    2190                 :  * If the grantor was not explicitly specified by the user, grantorId should
    2191                 :  * be passed as InvalidOid, and this function will infer the user to be
    2192                 :  * recorded as the grantor. In many cases, this will be the current user, but
    2193                 :  * things get more complicated when the current user doesn't possess ADMIN
    2194                 :  * OPTION on the role but rather relies on having SUPERUSER privileges, or
    2195                 :  * on inheriting the privileges of a role which does have ADMIN OPTION. See
    2196                 :  * below for details.
    2197                 :  *
    2198                 :  * If the grantor was specified by the user, then it must be a user that
    2199                 :  * can legally be recorded as the grantor, as per the rule stated above.
    2200                 :  * This is an integrity constraint, not a permissions check, and thus even
    2201                 :  * superusers are subject to this restriction. However, there is also a
    2202                 :  * permissions check: to specify a role as the grantor, the current user
    2203                 :  * must possess the privileges of that role. Superusers will always pass
    2204                 :  * this check, but for non-superusers it may lead to an error.
    2205                 :  *
    2206                 :  * The return value is the OID to be regarded as the grantor when executing
    2207                 :  * the operation.
    2208                 :  */
    2209                 : static Oid
    2210            2697 : check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
    2211                 : {
    2212                 :     /* If the grantor ID was not specified, pick one to use. */
    2213            2697 :     if (!OidIsValid(grantorId))
    2214                 :     {
    2215                 :         /*
    2216                 :          * Grants where the grantor is recorded as the bootstrap superuser do
    2217                 :          * not depend on any other existing grants, so always default to this
    2218                 :          * interpretation when possible.
    2219                 :          */
    2220            2598 :         if (superuser_arg(currentUserId))
    2221            2430 :             return BOOTSTRAP_SUPERUSERID;
    2222                 : 
    2223                 :         /*
    2224                 :          * Otherwise, the grantor must either have ADMIN OPTION on the role or
    2225                 :          * inherit the privileges of a role which does. In the former case,
    2226                 :          * record the grantor as the current user; in the latter, pick one of
    2227                 :          * the roles that is "most directly" inherited by the current role
    2228                 :          * (i.e. fewest "hops").
    2229                 :          *
    2230                 :          * (We shouldn't fail to find a best grantor, because we've already
    2231                 :          * established that the current user has permission to perform the
    2232                 :          * operation.)
    2233                 :          */
    2234             168 :         grantorId = select_best_admin(currentUserId, roleid);
    2235             168 :         if (!OidIsValid(grantorId))
    2236 UNC           0 :             elog(ERROR, "no possible grantors");
    2237 GNC         168 :         return grantorId;
    2238                 :     }
    2239                 : 
    2240                 :     /*
    2241                 :      * If an explicit grantor is specified, it must be a role whose privileges
    2242                 :      * the current user possesses.
    2243                 :      *
    2244                 :      * It should also be a role that has ADMIN OPTION on the target role, but
    2245                 :      * we check this condition only in case of GRANT. For REVOKE, no matching
    2246                 :      * grant should exist anyway, but if it somehow does, let the user get rid
    2247                 :      * of it.
    2248                 :      */
    2249              99 :     if (is_grant)
    2250                 :     {
    2251              87 :         if (!has_privs_of_role(currentUserId, grantorId))
    2252 UNC           0 :             ereport(ERROR,
    2253                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2254                 :                      errmsg("permission denied to grant privileges as role \"%s\"",
    2255                 :                             GetUserNameFromId(grantorId, false)),
    2256                 :                      errdetail("Only roles with privileges of role \"%s\" may grant privileges as this role.",
    2257                 :                                GetUserNameFromId(grantorId, false))));
    2258                 : 
    2259 GNC         111 :         if (grantorId != BOOTSTRAP_SUPERUSERID &&
    2260              24 :             select_best_admin(grantorId, roleid) != grantorId)
    2261               3 :             ereport(ERROR,
    2262                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2263                 :                      errmsg("permission denied to grant privileges as role \"%s\"",
    2264                 :                             GetUserNameFromId(grantorId, false)),
    2265                 :                      errdetail("The grantor must have the %s option on role \"%s\".",
    2266                 :                                "ADMIN", GetUserNameFromId(roleid, false))));
    2267                 :     }
    2268                 :     else
    2269                 :     {
    2270              12 :         if (!has_privs_of_role(currentUserId, grantorId))
    2271 UNC           0 :             ereport(ERROR,
    2272                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2273                 :                      errmsg("permission denied to revoke privileges granted by role \"%s\"",
    2274                 :                             GetUserNameFromId(grantorId, false)),
    2275                 :                      errdetail("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
    2276                 :                                GetUserNameFromId(grantorId, false))));
    2277                 :     }
    2278                 : 
    2279                 :     /*
    2280                 :      * If a grantor was specified explicitly, always attribute the grant to
    2281                 :      * that role (unless we error out above).
    2282                 :      */
    2283 GNC          96 :     return grantorId;
    2284                 : }
    2285                 : 
    2286                 : /*
    2287                 :  * Initialize an array of RevokeRoleGrantAction objects.
    2288                 :  *
    2289                 :  * 'memlist' should be a list of all grants for the target role.
    2290                 :  *
    2291                 :  * This constructs an array indicating that no actions are to be performed;
    2292                 :  * that is, every element is initially RRG_NOOP.
    2293                 :  */
    2294                 : static RevokeRoleGrantAction *
    2295             145 : initialize_revoke_actions(CatCList *memlist)
    2296                 : {
    2297                 :     RevokeRoleGrantAction *result;
    2298                 :     int         i;
    2299                 : 
    2300             145 :     if (memlist->n_members == 0)
    2301 UNC           0 :         return NULL;
    2302                 : 
    2303 GNC         145 :     result = palloc(sizeof(RevokeRoleGrantAction) * memlist->n_members);
    2304             398 :     for (i = 0; i < memlist->n_members; i++)
    2305             253 :         result[i] = RRG_NOOP;
    2306             145 :     return result;
    2307                 : }
    2308                 : 
    2309                 : /*
    2310                 :  * Figure out what we would need to do in order to revoke a grant, or just the
    2311                 :  * admin option on a grant, given that there might be dependent privileges.
    2312                 :  *
    2313                 :  * 'memlist' should be a list of all grants for the target role.
    2314                 :  *
    2315                 :  * Whatever actions prove to be necessary will be signalled by updating
    2316                 :  * 'actions'.
    2317                 :  *
    2318                 :  * If behavior is DROP_RESTRICT, an error will occur if there are dependent
    2319                 :  * role membership grants; if DROP_CASCADE, those grants will be scheduled
    2320                 :  * for deletion.
    2321                 :  *
    2322                 :  * The return value is true if the matching grant was found in the list,
    2323                 :  * and false if not.
    2324                 :  */
    2325                 : static bool
    2326              82 : plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
    2327                 :                    Oid member, Oid grantor, GrantRoleOptions *popt,
    2328                 :                    DropBehavior behavior)
    2329                 : {
    2330                 :     int         i;
    2331                 : 
    2332                 :     /*
    2333                 :      * If popt.specified == 0, we're revoking the grant entirely; otherwise,
    2334                 :      * we expect just one bit to be set, and we're revoking the corresponding
    2335                 :      * option. As of this writing, there's no syntax that would allow for
    2336                 :      * an attempt to revoke multiple options at once, and the logic below
    2337                 :      * wouldn't work properly if such syntax were added, so assert that our
    2338                 :      * caller isn't trying to do that.
    2339                 :      */
    2340              82 :     Assert(pg_popcount32(popt->specified) <= 1);
    2341                 : 
    2342             142 :     for (i = 0; i < memlist->n_members; ++i)
    2343                 :     {
    2344                 :         HeapTuple   authmem_tuple;
    2345                 :         Form_pg_auth_members authmem_form;
    2346                 : 
    2347             139 :         authmem_tuple = &memlist->members[i]->tuple;
    2348             139 :         authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    2349                 : 
    2350             139 :         if (authmem_form->member == member &&
    2351              88 :             authmem_form->grantor == grantor)
    2352                 :         {
    2353              79 :             if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
    2354                 :             {
    2355                 :                 /*
    2356                 :                  * Revoking the INHERIT option doesn't change anything for
    2357                 :                  * dependent privileges, so we don't need to recurse.
    2358                 :                  */
    2359               6 :                 actions[i] = RRG_REMOVE_INHERIT_OPTION;
    2360                 :             }
    2361              73 :             else if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0)
    2362                 :             {
    2363                 :                 /* Here too, no need to recurse. */
    2364               3 :                 actions[i] = RRG_REMOVE_SET_OPTION;
    2365                 :             }
    2366                 :             else
    2367                 :             {
    2368                 :                 bool    revoke_admin_option_only;
    2369                 : 
    2370                 :                 /*
    2371                 :                  * Revoking the grant entirely, or ADMIN option on a grant,
    2372                 :                  * implicates dependent privileges, so we may need to recurse.
    2373                 :                  */
    2374              70 :                 revoke_admin_option_only =
    2375              70 :                     (popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0;
    2376              70 :                 plan_recursive_revoke(memlist, actions, i,
    2377                 :                                       revoke_admin_option_only, behavior);
    2378                 :             }
    2379              73 :             return true;
    2380                 :         }
    2381                 :     }
    2382                 : 
    2383               3 :     return false;
    2384                 : }
    2385                 : 
    2386                 : /*
    2387                 :  * Figure out what we would need to do in order to revoke all grants to
    2388                 :  * a given member, given that there might be dependent privileges.
    2389                 :  *
    2390                 :  * 'memlist' should be a list of all grants for the target role.
    2391                 :  *
    2392                 :  * Whatever actions prove to be necessary will be signalled by updating
    2393                 :  * 'actions'.
    2394                 :  */
    2395                 : static void
    2396              33 : plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
    2397                 :                    Oid member)
    2398                 : {
    2399                 :     int         i;
    2400                 : 
    2401              72 :     for (i = 0; i < memlist->n_members; ++i)
    2402                 :     {
    2403                 :         HeapTuple   authmem_tuple;
    2404                 :         Form_pg_auth_members authmem_form;
    2405                 : 
    2406              39 :         authmem_tuple = &memlist->members[i]->tuple;
    2407              39 :         authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    2408                 : 
    2409              39 :         if (authmem_form->member == member)
    2410               3 :             plan_recursive_revoke(memlist, actions, i, false, DROP_CASCADE);
    2411                 :     }
    2412              33 : }
    2413                 : 
    2414                 : /*
    2415                 :  * Workhorse for figuring out recursive revocation of role grants.
    2416                 :  *
    2417                 :  * This is similar to what recursive_revoke() does for ACLs.
    2418                 :  */
    2419                 : static void
    2420              85 : plan_recursive_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
    2421                 :                       int index,
    2422                 :                       bool revoke_admin_option_only, DropBehavior behavior)
    2423                 : {
    2424              85 :     bool        would_still_have_admin_option = false;
    2425                 :     HeapTuple   authmem_tuple;
    2426                 :     Form_pg_auth_members authmem_form;
    2427                 :     int         i;
    2428                 : 
    2429                 :     /* If it's already been done, we can just return. */
    2430              85 :     if (actions[index] == RRG_DELETE_GRANT)
    2431 UNC           0 :         return;
    2432 GNC          85 :     if (actions[index] == RRG_REMOVE_ADMIN_OPTION &&
    2433                 :         revoke_admin_option_only)
    2434 UNC           0 :         return;
    2435                 : 
    2436                 :     /* Locate tuple data. */
    2437 GNC          85 :     authmem_tuple = &memlist->members[index]->tuple;
    2438              85 :     authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
    2439                 : 
    2440                 :     /*
    2441                 :      * If the existing tuple does not have admin_option set, then we do not
    2442                 :      * need to recurse. If we're just supposed to clear that bit we don't need
    2443                 :      * to do anything at all; if we're supposed to remove the grant, we need
    2444                 :      * to do something, but only to the tuple, and not any others.
    2445                 :      */
    2446              85 :     if (!revoke_admin_option_only)
    2447                 :     {
    2448              67 :         actions[index] = RRG_DELETE_GRANT;
    2449              67 :         if (!authmem_form->admin_option)
    2450              46 :             return;
    2451                 :     }
    2452                 :     else
    2453                 :     {
    2454              18 :         if (!authmem_form->admin_option)
    2455 UNC           0 :             return;
    2456 GNC          18 :         actions[index] = RRG_REMOVE_ADMIN_OPTION;
    2457                 :     }
    2458                 : 
    2459                 :     /* Determine whether the member would still have ADMIN OPTION. */
    2460             114 :     for (i = 0; i < memlist->n_members; ++i)
    2461                 :     {
    2462                 :         HeapTuple   am_cascade_tuple;
    2463                 :         Form_pg_auth_members am_cascade_form;
    2464                 : 
    2465              75 :         am_cascade_tuple = &memlist->members[i]->tuple;
    2466              75 :         am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
    2467                 : 
    2468              75 :         if (am_cascade_form->member == authmem_form->member &&
    2469              39 :             am_cascade_form->admin_option && actions[i] == RRG_NOOP)
    2470                 :         {
    2471 UNC           0 :             would_still_have_admin_option = true;
    2472               0 :             break;
    2473                 :         }
    2474                 :     }
    2475                 : 
    2476                 :     /* If the member would still have ADMIN OPTION, we need not recurse. */
    2477 GNC          39 :     if (would_still_have_admin_option)
    2478 UNC           0 :         return;
    2479                 : 
    2480                 :     /*
    2481                 :      * Recurse to grants that are not yet slated for deletion which have this
    2482                 :      * member as the grantor.
    2483                 :      */
    2484 GNC         108 :     for (i = 0; i < memlist->n_members; ++i)
    2485                 :     {
    2486                 :         HeapTuple   am_cascade_tuple;
    2487                 :         Form_pg_auth_members am_cascade_form;
    2488                 : 
    2489              75 :         am_cascade_tuple = &memlist->members[i]->tuple;
    2490              75 :         am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
    2491                 : 
    2492              75 :         if (am_cascade_form->grantor == authmem_form->member &&
    2493              18 :             actions[i] != RRG_DELETE_GRANT)
    2494                 :         {
    2495              18 :             if (behavior == DROP_RESTRICT)
    2496               6 :                 ereport(ERROR,
    2497                 :                         (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    2498                 :                          errmsg("dependent privileges exist"),
    2499                 :                          errhint("Use CASCADE to revoke them too.")));
    2500                 : 
    2501              12 :             plan_recursive_revoke(memlist, actions, i, false, behavior);
    2502                 :         }
    2503                 :     }
    2504                 : }
    2505                 : 
    2506                 : /*
    2507                 :  * Initialize a GrantRoleOptions object with default values.
    2508                 :  */
    2509                 : static void
    2510            2113 : InitGrantRoleOptions(GrantRoleOptions *popt)
    2511                 : {
    2512            2113 :     popt->specified = 0;
    2513            2113 :     popt->admin = false;
    2514            2113 :     popt->inherit = false;
    2515            2113 :     popt->set = true;
    2516            2113 : }
    2517                 : 
    2518                 : /*
    2519                 :  * GUC check_hook for createrole_self_grant
    2520                 :  */
    2521                 : bool
    2522            1860 : check_createrole_self_grant(char **newval, void **extra, GucSource source)
    2523                 : {
    2524                 :     char       *rawstring;
    2525                 :     List       *elemlist;
    2526                 :     ListCell   *l;
    2527            1860 :     unsigned    options = 0;
    2528                 :     unsigned   *result;
    2529                 : 
    2530                 :     /* Need a modifiable copy of string */
    2531            1860 :     rawstring = pstrdup(*newval);
    2532                 : 
    2533            1860 :     if (!SplitIdentifierString(rawstring, ',', &elemlist))
    2534                 :     {
    2535                 :         /* syntax error in list */
    2536 UNC           0 :         GUC_check_errdetail("List syntax is invalid.");
    2537               0 :         pfree(rawstring);
    2538               0 :         list_free(elemlist);
    2539               0 :         return false;
    2540                 :     }
    2541                 : 
    2542 GNC        1866 :     foreach(l, elemlist)
    2543                 :     {
    2544               6 :         char       *tok = (char *) lfirst(l);
    2545                 : 
    2546               6 :         if (pg_strcasecmp(tok, "SET") == 0)
    2547               3 :             options |= GRANT_ROLE_SPECIFIED_SET;
    2548               3 :         else if (pg_strcasecmp(tok, "INHERIT") == 0)
    2549               3 :             options |= GRANT_ROLE_SPECIFIED_INHERIT;
    2550                 :         else
    2551                 :         {
    2552 UNC           0 :             GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
    2553               0 :             pfree(rawstring);
    2554               0 :             list_free(elemlist);
    2555               0 :             return false;
    2556                 :         }
    2557                 :     }
    2558                 : 
    2559 GNC        1860 :     pfree(rawstring);
    2560            1860 :     list_free(elemlist);
    2561                 : 
    2562            1860 :     result = (unsigned *) guc_malloc(LOG, sizeof(unsigned));
    2563            1860 :     *result = options;
    2564            1860 :     *extra = result;
    2565                 : 
    2566            1860 :     return true;
    2567                 : }
    2568                 : 
    2569                 : /*
    2570                 :  * GUC assign_hook for createrole_self_grant
    2571                 :  */
    2572                 : void
    2573            1860 : assign_createrole_self_grant(const char *newval, void *extra)
    2574                 : {
    2575            1860 :     unsigned    options = * (unsigned *) extra;
    2576                 : 
    2577            1860 :     createrole_self_grant_enabled = (options != 0);
    2578            1860 :     createrole_self_grant_options.specified = GRANT_ROLE_SPECIFIED_ADMIN
    2579                 :         | GRANT_ROLE_SPECIFIED_INHERIT
    2580                 :         | GRANT_ROLE_SPECIFIED_SET;
    2581            1860 :     createrole_self_grant_options.admin = false;
    2582            1860 :     createrole_self_grant_options.inherit =
    2583            1860 :         (options & GRANT_ROLE_SPECIFIED_INHERIT) != 0;
    2584            1860 :     createrole_self_grant_options.set =
    2585            1860 :         (options & GRANT_ROLE_SPECIFIED_SET) != 0;
    2586            1860 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a