LCOV - differential code coverage report
Current view: top level - src/backend/commands - user.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 88.8 % 857 761 96 1 760 1
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 21 21 1 20
Baseline: 16@8cea358b128 Branches: 70.8 % 798 565 233 565
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (60,120] days: 100.0 % 4 4 4
(240..) days: 88.7 % 853 757 96 1 756
Function coverage date bins:
(240..) days: 100.0 % 21 21 1 20
Branch coverage date bins:
(60,120] days: 100.0 % 6 6 6
(240..) days: 70.6 % 792 559 233 559

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

Generated by: LCOV version 2.1-beta2-3-g6141622