PostgreSQL Source Code  git master
user.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_db_role_setting.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/seclabel.h"
#include "commands/user.h"
#include "libpq/crypt.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
Include dependency graph for user.c:

Go to the source code of this file.

Data Structures

struct  GrantRoleOptions
 

Macros

#define GRANT_ROLE_SPECIFIED_ADMIN   0x0001
 
#define GRANT_ROLE_SPECIFIED_INHERIT   0x0002
 
#define GRANT_ROLE_SPECIFIED_SET   0x0004
 

Enumerations

enum  RevokeRoleGrantAction {
  RRG_NOOP , RRG_REMOVE_ADMIN_OPTION , RRG_REMOVE_INHERIT_OPTION , RRG_REMOVE_SET_OPTION ,
  RRG_DELETE_GRANT
}
 

Functions

static void AddRoleMems (Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt)
 
static void DelRoleMems (Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
 
static void check_role_membership_authorization (Oid currentUserId, Oid roleid, bool is_grant)
 
static Oid check_role_grantor (Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
 
static RevokeRoleGrantActioninitialize_revoke_actions (CatCList *memlist)
 
static bool plan_single_revoke (CatCList *memlist, RevokeRoleGrantAction *actions, Oid member, Oid grantor, GrantRoleOptions *popt, DropBehavior behavior)
 
static void plan_member_revoke (CatCList *memlist, RevokeRoleGrantAction *actions, Oid member)
 
static void plan_recursive_revoke (CatCList *memlist, RevokeRoleGrantAction *actions, int index, bool revoke_admin_option_only, DropBehavior behavior)
 
static void InitGrantRoleOptions (GrantRoleOptions *popt)
 
static bool have_createrole_privilege (void)
 
Oid CreateRole (ParseState *pstate, CreateRoleStmt *stmt)
 
Oid AlterRole (ParseState *pstate, AlterRoleStmt *stmt)
 
Oid AlterRoleSet (AlterRoleSetStmt *stmt)
 
void DropRole (DropRoleStmt *stmt)
 
ObjectAddress RenameRole (const char *oldname, const char *newname)
 
void GrantRole (ParseState *pstate, GrantRoleStmt *stmt)
 
void DropOwnedObjects (DropOwnedStmt *stmt)
 
void ReassignOwnedObjects (ReassignOwnedStmt *stmt)
 
ListroleSpecsToIds (List *memberNames)
 
bool check_createrole_self_grant (char **newval, void **extra, GucSource source)
 
void assign_createrole_self_grant (const char *newval, void *extra)
 

Variables

Oid binary_upgrade_next_pg_authid_oid = InvalidOid
 
int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256
 
char * createrole_self_grant = ""
 
static bool createrole_self_grant_enabled = false
 
static GrantRoleOptions createrole_self_grant_options
 
check_password_hook_type check_password_hook = NULL
 

Macro Definition Documentation

◆ GRANT_ROLE_SPECIFIED_ADMIN

#define GRANT_ROLE_SPECIFIED_ADMIN   0x0001

Definition at line 80 of file user.c.

◆ GRANT_ROLE_SPECIFIED_INHERIT

#define GRANT_ROLE_SPECIFIED_INHERIT   0x0002

Definition at line 81 of file user.c.

◆ GRANT_ROLE_SPECIFIED_SET

#define GRANT_ROLE_SPECIFIED_SET   0x0004

Definition at line 82 of file user.c.

Enumeration Type Documentation

◆ RevokeRoleGrantAction

Enumerator
RRG_NOOP 
RRG_REMOVE_ADMIN_OPTION 
RRG_REMOVE_INHERIT_OPTION 
RRG_REMOVE_SET_OPTION 
RRG_DELETE_GRANT 

Definition at line 60 of file user.c.

61 {
62  RRG_NOOP,
RevokeRoleGrantAction
Definition: user.c:61
@ RRG_REMOVE_SET_OPTION
Definition: user.c:65
@ RRG_NOOP
Definition: user.c:62
@ RRG_DELETE_GRANT
Definition: user.c:66
@ RRG_REMOVE_INHERIT_OPTION
Definition: user.c:64
@ RRG_REMOVE_ADMIN_OPTION
Definition: user.c:63

Function Documentation

◆ AddRoleMems()

static void AddRoleMems ( Oid  currentUserId,
const char *  rolename,
Oid  roleid,
List memberSpecs,
List memberIds,
Oid  grantorId,
GrantRoleOptions popt 
)
static

Definition at line 1681 of file user.c.

1684 {
1685  Relation pg_authmem_rel;
1686  TupleDesc pg_authmem_dsc;
1687  ListCell *specitem;
1688  ListCell *iditem;
1689 
1690  Assert(list_length(memberSpecs) == list_length(memberIds));
1691 
1692  /* Validate grantor (and resolve implicit grantor if not specified). */
1693  grantorId = check_role_grantor(currentUserId, roleid, grantorId, true);
1694 
1695  pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1696  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  */
1703  LockSharedObject(AuthIdRelationId, roleid, 0,
1705 
1706  /* Preliminary sanity checks. */
1707  forboth(specitem, memberSpecs, iditem, memberIds)
1708  {
1709  RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1710  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  */
1731  if (memberid == ROLE_PG_DATABASE_OWNER)
1732  ereport(ERROR,
1733  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1734  errmsg("role \"%s\" cannot be a member of any role",
1735  get_rolespec_name(memberRole)));
1736 
1737  /*
1738  * Refuse creation of membership loops, including the trivial case
1739  * where a role is made a member of itself. We do this by checking to
1740  * see if the target role is already a member of the proposed member
1741  * role. We have to ignore possible superuserness, however, else we
1742  * could never grant membership in a superuser-privileged role.
1743  */
1744  if (is_member_of_role_nosuper(roleid, memberid))
1745  ereport(ERROR,
1746  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1747  errmsg("role \"%s\" is a member of role \"%s\"",
1748  rolename, get_rolespec_name(memberRole))));
1749  }
1750 
1751  /*
1752  * Disallow attempts to grant ADMIN OPTION back to a user who granted it
1753  * to you, similar to what check_circularity does for ACLs. We want the
1754  * chains of grants to remain acyclic, so that it's always possible to use
1755  * REVOKE .. CASCADE to clean up all grants that depend on the one being
1756  * revoked.
1757  *
1758  * NB: This check might look redundant with the check for membership loops
1759  * above, but it isn't. That's checking for role-member loop (e.g. A is a
1760  * member of B and B is a member of A) while this is checking for a
1761  * member-grantor loop (e.g. A gave ADMIN OPTION on X to B and now B, who
1762  * has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on
1763  * X back to A).
1764  */
1765  if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID)
1766  {
1767  CatCList *memlist;
1768  RevokeRoleGrantAction *actions;
1769  int i;
1770 
1771  /* Get the list of members for this role. */
1772  memlist = SearchSysCacheList1(AUTHMEMROLEMEM,
1773  ObjectIdGetDatum(roleid));
1774 
1775  /*
1776  * Figure out what would happen if we removed all existing grants to
1777  * every role to which we've been asked to make a new grant.
1778  */
1779  actions = initialize_revoke_actions(memlist);
1780  foreach(iditem, memberIds)
1781  {
1782  Oid memberid = lfirst_oid(iditem);
1783 
1784  if (memberid == BOOTSTRAP_SUPERUSERID)
1785  ereport(ERROR,
1786  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1787  errmsg("%s option cannot be granted back to your own grantor",
1788  "ADMIN")));
1789  plan_member_revoke(memlist, actions, memberid);
1790  }
1791 
1792  /*
1793  * If the result would be that the grantor role would no longer have
1794  * the ability to perform the grant, then the proposed grant would
1795  * create a circularity.
1796  */
1797  for (i = 0; i < memlist->n_members; ++i)
1798  {
1799  HeapTuple authmem_tuple;
1800  Form_pg_auth_members authmem_form;
1801 
1802  authmem_tuple = &memlist->members[i]->tuple;
1803  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1804 
1805  if (actions[i] == RRG_NOOP &&
1806  authmem_form->member == grantorId &&
1807  authmem_form->admin_option)
1808  break;
1809  }
1810  if (i >= memlist->n_members)
1811  ereport(ERROR,
1812  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1813  errmsg("%s option cannot be granted back to your own grantor",
1814  "ADMIN")));
1815 
1816  ReleaseSysCacheList(memlist);
1817  }
1818 
1819  /* Now perform the catalog updates. */
1820  forboth(specitem, memberSpecs, iditem, memberIds)
1821  {
1822  RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1823  Oid memberid = lfirst_oid(iditem);
1824  HeapTuple authmem_tuple;
1825  HeapTuple tuple;
1826  Datum new_record[Natts_pg_auth_members] = {0};
1827  bool new_record_nulls[Natts_pg_auth_members] = {0};
1828  bool new_record_repl[Natts_pg_auth_members] = {0};
1829 
1830  /* Common initialization for possible insert or update */
1831  new_record[Anum_pg_auth_members_roleid - 1] =
1832  ObjectIdGetDatum(roleid);
1833  new_record[Anum_pg_auth_members_member - 1] =
1834  ObjectIdGetDatum(memberid);
1835  new_record[Anum_pg_auth_members_grantor - 1] =
1836  ObjectIdGetDatum(grantorId);
1837 
1838  /* Find any existing tuple */
1839  authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM,
1840  ObjectIdGetDatum(roleid),
1841  ObjectIdGetDatum(memberid),
1842  ObjectIdGetDatum(grantorId));
1843 
1844  /*
1845  * If we found a tuple, update it with new option values, unless there
1846  * are no changes, in which case issue a WARNING.
1847  *
1848  * If we didn't find a tuple, just insert one.
1849  */
1850  if (HeapTupleIsValid(authmem_tuple))
1851  {
1852  Form_pg_auth_members authmem_form;
1853  bool at_least_one_change = false;
1854 
1855  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1856 
1857  if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0
1858  && authmem_form->admin_option != popt->admin)
1859  {
1860  new_record[Anum_pg_auth_members_admin_option - 1] =
1861  BoolGetDatum(popt->admin);
1862  new_record_repl[Anum_pg_auth_members_admin_option - 1] =
1863  true;
1864  at_least_one_change = true;
1865  }
1866 
1867  if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0
1868  && authmem_form->inherit_option != popt->inherit)
1869  {
1870  new_record[Anum_pg_auth_members_inherit_option - 1] =
1871  BoolGetDatum(popt->inherit);
1872  new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
1873  true;
1874  at_least_one_change = true;
1875  }
1876 
1877  if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
1878  && authmem_form->set_option != popt->set)
1879  {
1880  new_record[Anum_pg_auth_members_set_option - 1] =
1881  BoolGetDatum(popt->set);
1882  new_record_repl[Anum_pg_auth_members_set_option - 1] =
1883  true;
1884  at_least_one_change = true;
1885  }
1886 
1887  if (!at_least_one_change)
1888  {
1889  ereport(NOTICE,
1890  (errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
1891  get_rolespec_name(memberRole), rolename,
1892  GetUserNameFromId(grantorId, false))));
1893  ReleaseSysCache(authmem_tuple);
1894  continue;
1895  }
1896 
1897  tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1898  new_record,
1899  new_record_nulls, new_record_repl);
1900  CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1901 
1902  ReleaseSysCache(authmem_tuple);
1903  }
1904  else
1905  {
1906  Oid objectId;
1907  Oid *newmembers = palloc(sizeof(Oid));
1908 
1909  /*
1910  * The values for these options can be taken directly from 'popt'.
1911  * Either they were specified, or the defaults as set by
1912  * InitGrantRoleOptions are correct.
1913  */
1914  new_record[Anum_pg_auth_members_admin_option - 1] =
1915  BoolGetDatum(popt->admin);
1916  new_record[Anum_pg_auth_members_set_option - 1] =
1917  BoolGetDatum(popt->set);
1918 
1919  /*
1920  * If the user specified a value for the inherit option, use
1921  * whatever was specified. Otherwise, set the default value based
1922  * on the role-level property.
1923  */
1924  if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
1925  new_record[Anum_pg_auth_members_inherit_option - 1] =
1926  popt->inherit;
1927  else
1928  {
1929  HeapTuple mrtup;
1930  Form_pg_authid mrform;
1931 
1932  mrtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(memberid));
1933  if (!HeapTupleIsValid(mrtup))
1934  elog(ERROR, "cache lookup failed for role %u", memberid);
1935  mrform = (Form_pg_authid) GETSTRUCT(mrtup);
1936  new_record[Anum_pg_auth_members_inherit_option - 1] =
1937  mrform->rolinherit;
1938  ReleaseSysCache(mrtup);
1939  }
1940 
1941  /* get an OID for the new row and insert it */
1942  objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
1943  Anum_pg_auth_members_oid);
1944  new_record[Anum_pg_auth_members_oid - 1] = objectId;
1945  tuple = heap_form_tuple(pg_authmem_dsc,
1946  new_record, new_record_nulls);
1947  CatalogTupleInsert(pg_authmem_rel, tuple);
1948 
1949  /* updateAclDependencies wants to pfree array inputs */
1950  newmembers[0] = grantorId;
1951  updateAclDependencies(AuthMemRelationId, objectId,
1952  0, InvalidOid,
1953  0, NULL,
1954  1, newmembers);
1955  }
1956 
1957  /* CCI after each change, in case there are duplicates in list */
1959  }
1960 
1961  /*
1962  * Close pg_authmem, but keep lock till commit.
1963  */
1964  table_close(pg_authmem_rel, NoLock);
1965 }
char * get_rolespec_name(const RoleSpec *role)
Definition: acl.c:5539
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5242
#define GRANT_ROLE_SPECIFIED_ADMIN
Definition: user.c:80
static void plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, Oid member)
Definition: user.c:2391
#define GRANT_ROLE_SPECIFIED_SET
Definition: user.c:82
static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
Definition: user.c:2205
#define GRANT_ROLE_SPECIFIED_INHERIT
Definition: user.c:81
static RevokeRoleGrantAction * initialize_revoke_actions(CatCList *memlist)
Definition: user.c:2290
#define Assert(condition)
Definition: c.h:858
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:412
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:73
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1073
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define RowExclusiveLock
Definition: lockdefs.h:38
void * palloc(Size size)
Definition: mcxt.c:1317
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:980
FormData_pg_auth_members * Form_pg_auth_members
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define lfirst_oid(lc)
Definition: pg_list.h:174
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:491
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
unsigned specified
Definition: user.c:74
bool admin
Definition: user.c:75
bool set
Definition: user.c:77
bool inherit
Definition: user.c:76
ItemPointerData t_self
Definition: htup.h:65
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:240
#define ReleaseSysCacheList(x)
Definition: syscache.h:129
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:122
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void CommandCounterIncrement(void)
Definition: xact.c:1098

References GrantRoleOptions::admin, Assert, BoolGetDatum(), CatalogTupleInsert(), CatalogTupleUpdate(), check_role_grantor(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, forboth, get_rolespec_name(), GetNewOidWithIndex(), GETSTRUCT, GetUserNameFromId(), GRANT_ROLE_SPECIFIED_ADMIN, GRANT_ROLE_SPECIFIED_INHERIT, GRANT_ROLE_SPECIFIED_SET, heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, GrantRoleOptions::inherit, initialize_revoke_actions(), InvalidOid, is_member_of_role_nosuper(), lfirst_node, lfirst_oid, list_length(), LockSharedObject(), catclist::members, catclist::n_members, NoLock, NOTICE, ObjectIdGetDatum(), palloc(), plan_member_revoke(), RelationGetDescr, ReleaseSysCache(), ReleaseSysCacheList, RowExclusiveLock, RRG_NOOP, SearchSysCache1(), SearchSysCache3(), SearchSysCacheList1, GrantRoleOptions::set, ShareUpdateExclusiveLock, GrantRoleOptions::specified, HeapTupleData::t_self, table_close(), table_open(), catctup::tuple, and updateAclDependencies().

Referenced by AlterRole(), CreateRole(), and GrantRole().

◆ AlterRole()

Oid AlterRole ( ParseState pstate,
AlterRoleStmt stmt 
)

Definition at line 619 of file user.c.

620 {
621  Datum new_record[Natts_pg_authid] = {0};
622  bool new_record_nulls[Natts_pg_authid] = {0};
623  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;
631  char *password = NULL; /* user password */
632  int connlimit = -1; /* maximum connections allowed */
633  char *validUntil = NULL; /* time the login is valid until */
634  Datum validUntil_datum; /* same, as timestamptz Datum */
635  bool validUntil_null;
636  DefElem *dpassword = NULL;
637  DefElem *dissuper = NULL;
638  DefElem *dinherit = NULL;
639  DefElem *dcreaterole = NULL;
640  DefElem *dcreatedb = NULL;
641  DefElem *dcanlogin = NULL;
642  DefElem *disreplication = NULL;
643  DefElem *dconnlimit = NULL;
644  DefElem *drolemembers = NULL;
645  DefElem *dvalidUntil = NULL;
646  DefElem *dbypassRLS = NULL;
647  Oid roleid;
648  Oid currentUserId = GetUserId();
649  GrantRoleOptions popt;
650 
652  _("Cannot alter reserved roles."));
653 
654  /* Extract options from the statement node tree */
655  foreach(option, stmt->options)
656  {
657  DefElem *defel = (DefElem *) lfirst(option);
658 
659  if (strcmp(defel->defname, "password") == 0)
660  {
661  if (dpassword)
662  errorConflictingDefElem(defel, pstate);
663  dpassword = defel;
664  }
665  else if (strcmp(defel->defname, "superuser") == 0)
666  {
667  if (dissuper)
668  errorConflictingDefElem(defel, pstate);
669  dissuper = defel;
670  }
671  else if (strcmp(defel->defname, "inherit") == 0)
672  {
673  if (dinherit)
674  errorConflictingDefElem(defel, pstate);
675  dinherit = defel;
676  }
677  else if (strcmp(defel->defname, "createrole") == 0)
678  {
679  if (dcreaterole)
680  errorConflictingDefElem(defel, pstate);
681  dcreaterole = defel;
682  }
683  else if (strcmp(defel->defname, "createdb") == 0)
684  {
685  if (dcreatedb)
686  errorConflictingDefElem(defel, pstate);
687  dcreatedb = defel;
688  }
689  else if (strcmp(defel->defname, "canlogin") == 0)
690  {
691  if (dcanlogin)
692  errorConflictingDefElem(defel, pstate);
693  dcanlogin = defel;
694  }
695  else if (strcmp(defel->defname, "isreplication") == 0)
696  {
697  if (disreplication)
698  errorConflictingDefElem(defel, pstate);
699  disreplication = defel;
700  }
701  else if (strcmp(defel->defname, "connectionlimit") == 0)
702  {
703  if (dconnlimit)
704  errorConflictingDefElem(defel, pstate);
705  dconnlimit = defel;
706  }
707  else if (strcmp(defel->defname, "rolemembers") == 0 &&
708  stmt->action != 0)
709  {
710  if (drolemembers)
711  errorConflictingDefElem(defel, pstate);
712  drolemembers = defel;
713  }
714  else if (strcmp(defel->defname, "validUntil") == 0)
715  {
716  if (dvalidUntil)
717  errorConflictingDefElem(defel, pstate);
718  dvalidUntil = defel;
719  }
720  else if (strcmp(defel->defname, "bypassrls") == 0)
721  {
722  if (dbypassRLS)
723  errorConflictingDefElem(defel, pstate);
724  dbypassRLS = defel;
725  }
726  else
727  elog(ERROR, "option \"%s\" not recognized",
728  defel->defname);
729  }
730 
731  if (dpassword && dpassword->arg)
732  password = strVal(dpassword->arg);
733  if (dconnlimit)
734  {
735  connlimit = intVal(dconnlimit->arg);
736  if (connlimit < -1)
737  ereport(ERROR,
738  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
739  errmsg("invalid connection limit: %d", connlimit)));
740  }
741  if (dvalidUntil)
742  validUntil = strVal(dvalidUntil->arg);
743 
744  /*
745  * Scan the pg_authid relation to be certain the user exists.
746  */
747  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
748  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
749 
750  tuple = get_rolespec_tuple(stmt->role);
751  authform = (Form_pg_authid) GETSTRUCT(tuple);
752  rolename = pstrdup(NameStr(authform->rolname));
753  roleid = authform->oid;
754 
755  /* To mess with a superuser in any way you gotta be superuser. */
756  if (!superuser() && authform->rolsuper)
757  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")));
762  if (!superuser() && dissuper)
763  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  */
773  if (!have_createrole_privilege() ||
774  !is_admin_of_role(GetUserId(), roleid))
775  {
776  /* things an unprivileged user certainly can't do */
777  if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
778  dvalidUntil || disreplication || dbypassRLS)
779  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 */
786  if (dpassword && roleid != currentUserId)
787  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  }
793  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  if (dcreatedb && !have_createdb_privilege())
801  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  if (disreplication && !has_rolreplication(currentUserId))
807  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  if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
813  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. */
821  if (drolemembers && !is_admin_of_role(currentUserId, roleid))
822  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 */
829  if (dvalidUntil)
830  {
831  validUntil_datum = DirectFunctionCall3(timestamptz_in,
832  CStringGetDatum(validUntil),
834  Int32GetDatum(-1));
835  validUntil_null = false;
836  }
837  else
838  {
839  /* fetch existing setting in case hook needs it */
840  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  */
849  (*check_password_hook) (rolename,
850  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  */
862  if (dissuper)
863  {
864  bool should_be_super = boolVal(dissuper->arg);
865 
866  if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
867  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 
873  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
874  new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
875  }
876 
877  if (dinherit)
878  {
879  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg));
880  new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
881  }
882 
883  if (dcreaterole)
884  {
885  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg));
886  new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
887  }
888 
889  if (dcreatedb)
890  {
891  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg));
892  new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
893  }
894 
895  if (dcanlogin)
896  {
897  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg));
898  new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
899  }
900 
901  if (disreplication)
902  {
903  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg));
904  new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
905  }
906 
907  if (dconnlimit)
908  {
909  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
910  new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
911  }
912 
913  /* password */
914  if (password)
915  {
916  char *shadow_pass;
917  const char *logdetail = NULL;
918 
919  /* Like in CREATE USER, don't allow an empty password. */
920  if (password[0] == '\0' ||
921  plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
922  {
923  ereport(NOTICE,
924  (errmsg("empty string is not a valid password, clearing password")));
925  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
926  }
927  else
928  {
929  /* Encrypt the password to the requested format. */
930  shadow_pass = encrypt_password(Password_encryption, rolename,
931  password);
932  new_record[Anum_pg_authid_rolpassword - 1] =
933  CStringGetTextDatum(shadow_pass);
934  }
935  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
936  }
937 
938  /* unset password */
939  if (dpassword && dpassword->arg == NULL)
940  {
941  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
942  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
943  }
944 
945  /* valid until */
946  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
947  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
948  new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
949 
950  if (dbypassRLS)
951  {
952  new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg));
953  new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
954  }
955 
956  new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
957  new_record_nulls, new_record_repl);
958  CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
959 
960  InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
961 
962  ReleaseSysCache(tuple);
963  heap_freetuple(new_tuple);
964 
965  InitGrantRoleOptions(&popt);
966 
967  /*
968  * Advance command counter so we can see new record; else tests in
969  * AddRoleMems may fail.
970  */
971  if (drolemembers)
972  {
973  List *rolemembers = (List *) drolemembers->arg;
974 
976 
977  if (stmt->action == +1) /* add members to role */
978  AddRoleMems(currentUserId, rolename, roleid,
979  rolemembers, roleSpecsToIds(rolemembers),
980  InvalidOid, &popt);
981  else if (stmt->action == -1) /* drop members from role */
982  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  */
990  table_close(pg_authid_rel, NoLock);
991 
992  return roleid;
993 }
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:5264
void check_rolespec_name(const RoleSpec *role, const char *detail_msg)
Definition: acl.c:5561
HeapTuple get_rolespec_tuple(const RoleSpec *role)
Definition: acl.c:5493
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4242
static bool have_createrole_privilege(void)
Definition: user.c:122
static void InitGrantRoleOptions(GrantRoleOptions *popt)
Definition: user.c:2505
static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt)
Definition: user.c:1681
int Password_encryption
Definition: user.c:85
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652
check_password_hook_type check_password_hook
Definition: user.c:91
static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
Definition: user.c:1979
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:417
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:746
#define STATUS_OK
Definition: c.h:1169
int plain_crypt_verify(const char *role, const char *shadow_pass, const char *client_pass, const char **logdetail)
Definition: crypt.c:222
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:88
char * encrypt_password(PasswordType target_type, const char *role, const char *password)
Definition: crypt.c:115
bool have_createdb_privilege(void)
Definition: dbcommands.c:2931
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:384
int errdetail(const char *fmt,...)
Definition: elog.c:1203
#define _(x)
Definition: elog.c:90
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define stmt
Definition: indent_codes.h:59
char * pstrdup(const char *in)
Definition: mcxt.c:1696
Oid GetUserId(void)
Definition: miscinit.c:514
bool has_rolreplication(Oid roleid)
Definition: miscinit.c:711
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
@ DROP_RESTRICT
Definition: parsenodes.h:2334
#define lfirst(lc)
Definition: pg_list.h:172
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static char * password
Definition: streamutil.c:54
char * defname
Definition: parsenodes.h:815
Node * arg
Definition: parsenodes.h:816
Definition: pg_list.h:54
bool superuser(void)
Definition: superuser.c:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
#define boolVal(v)
Definition: value.h:81
#define intVal(v)
Definition: value.h:79
#define strVal(v)
Definition: value.h:82

References _, AddRoleMems(), DefElem::arg, BoolGetDatum(), boolVal, CatalogTupleUpdate(), check_password_hook, check_rolespec_name(), CommandCounterIncrement(), CStringGetDatum(), CStringGetTextDatum, DefElem::defname, DelRoleMems(), DirectFunctionCall3, DROP_RESTRICT, elog, encrypt_password(), ereport, errcode(), errdetail(), errmsg(), ERROR, errorConflictingDefElem(), get_password_type(), get_rolespec_tuple(), GETSTRUCT, GetUserId(), has_bypassrls_privilege(), has_rolreplication(), have_createdb_privilege(), have_createrole_privilege(), heap_freetuple(), heap_modify_tuple(), InitGrantRoleOptions(), Int32GetDatum(), intVal, InvalidOid, InvokeObjectPostAlterHook, is_admin_of_role(), lfirst, NameStr, NoLock, NOTICE, ObjectIdGetDatum(), password, Password_encryption, plain_crypt_verify(), pstrdup(), RelationGetDescr, ReleaseSysCache(), roleSpecsToIds(), RowExclusiveLock, STATUS_OK, stmt, strVal, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and timestamptz_in().

Referenced by standard_ProcessUtility().

◆ AlterRoleSet()

Oid AlterRoleSet ( AlterRoleSetStmt stmt)

Definition at line 1000 of file user.c.

1001 {
1002  HeapTuple roletuple;
1003  Form_pg_authid roleform;
1004  Oid databaseid = InvalidOid;
1005  Oid roleid = InvalidOid;
1006 
1007  if (stmt->role)
1008  {
1009  check_rolespec_name(stmt->role,
1010  _("Cannot alter reserved roles."));
1011 
1012  roletuple = get_rolespec_tuple(stmt->role);
1013  roleform = (Form_pg_authid) GETSTRUCT(roletuple);
1014  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  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  if (roleform->rolsuper)
1028  {
1029  if (!superuser())
1030  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  {
1038  if ((!have_createrole_privilege() ||
1039  !is_admin_of_role(GetUserId(), roleid))
1040  && roleid != GetUserId())
1041  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 
1048  ReleaseSysCache(roletuple);
1049  }
1050 
1051  /* look up and lock the database, if specified */
1052  if (stmt->database != NULL)
1053  {
1054  databaseid = get_database_oid(stmt->database, false);
1055  shdepLockAndCheckObject(DatabaseRelationId, databaseid);
1056 
1057  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  */
1063  if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
1065  stmt->database);
1066  }
1067  }
1068 
1069  if (!stmt->role && !stmt->database)
1070  {
1071  /* Must be superuser to alter settings globally. */
1072  if (!superuser())
1073  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 
1080  AlterSetting(databaseid, roleid, stmt->setstmt);
1081 
1082  return roleid;
1083 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2700
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4142
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3119
@ OBJECT_DATABASE
Definition: parsenodes.h:2270
void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1211

References _, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterSetting(), check_rolespec_name(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_database_oid(), get_rolespec_tuple(), GETSTRUCT, GetUserId(), have_createrole_privilege(), InvalidOid, is_admin_of_role(), NameStr, OBJECT_DATABASE, object_ownercheck(), ReleaseSysCache(), shdepLockAndCheckObject(), stmt, and superuser().

Referenced by standard_ProcessUtility().

◆ assign_createrole_self_grant()

void assign_createrole_self_grant ( const char *  newval,
void *  extra 
)

◆ check_createrole_self_grant()

bool check_createrole_self_grant ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 2517 of file user.c.

2518 {
2519  char *rawstring;
2520  List *elemlist;
2521  ListCell *l;
2522  unsigned options = 0;
2523  unsigned *result;
2524 
2525  /* Need a modifiable copy of string */
2526  rawstring = pstrdup(*newval);
2527 
2528  if (!SplitIdentifierString(rawstring, ',', &elemlist))
2529  {
2530  /* syntax error in list */
2531  GUC_check_errdetail("List syntax is invalid.");
2532  pfree(rawstring);
2533  list_free(elemlist);
2534  return false;
2535  }
2536 
2537  foreach(l, elemlist)
2538  {
2539  char *tok = (char *) lfirst(l);
2540 
2541  if (pg_strcasecmp(tok, "SET") == 0)
2543  else if (pg_strcasecmp(tok, "INHERIT") == 0)
2545  else
2546  {
2547  GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
2548  pfree(rawstring);
2549  list_free(elemlist);
2550  return false;
2551  }
2552  }
2553 
2554  pfree(rawstring);
2555  list_free(elemlist);
2556 
2557  result = (unsigned *) guc_malloc(LOG, sizeof(unsigned));
2558  *result = options;
2559  *extra = result;
2560 
2561  return true;
2562 }
#define LOG
Definition: elog.h:31
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:637
#define newval
#define GUC_check_errdetail
Definition: guc.h:472
void list_free(List *list)
Definition: list.c:1546
void pfree(void *pointer)
Definition: mcxt.c:1521
static char ** options
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3457

References GRANT_ROLE_SPECIFIED_INHERIT, GRANT_ROLE_SPECIFIED_SET, GUC_check_errdetail, guc_malloc(), lfirst, list_free(), LOG, newval, options, pfree(), pg_strcasecmp(), pstrdup(), and SplitIdentifierString().

◆ check_role_grantor()

static Oid check_role_grantor ( Oid  currentUserId,
Oid  roleid,
Oid  grantorId,
bool  is_grant 
)
static

Definition at line 2205 of file user.c.

2206 {
2207  /* If the grantor ID was not specified, pick one to use. */
2208  if (!OidIsValid(grantorId))
2209  {
2210  /*
2211  * Grants where the grantor is recorded as the bootstrap superuser do
2212  * not depend on any other existing grants, so always default to this
2213  * interpretation when possible.
2214  */
2215  if (superuser_arg(currentUserId))
2216  return BOOTSTRAP_SUPERUSERID;
2217 
2218  /*
2219  * Otherwise, the grantor must either have ADMIN OPTION on the role or
2220  * inherit the privileges of a role which does. In the former case,
2221  * record the grantor as the current user; in the latter, pick one of
2222  * the roles that is "most directly" inherited by the current role
2223  * (i.e. fewest "hops").
2224  *
2225  * (We shouldn't fail to find a best grantor, because we've already
2226  * established that the current user has permission to perform the
2227  * operation.)
2228  */
2229  grantorId = select_best_admin(currentUserId, roleid);
2230  if (!OidIsValid(grantorId))
2231  elog(ERROR, "no possible grantors");
2232  return grantorId;
2233  }
2234 
2235  /*
2236  * If an explicit grantor is specified, it must be a role whose privileges
2237  * the current user possesses.
2238  *
2239  * It should also be a role that has ADMIN OPTION on the target role, but
2240  * we check this condition only in case of GRANT. For REVOKE, no matching
2241  * grant should exist anyway, but if it somehow does, let the user get rid
2242  * of it.
2243  */
2244  if (is_grant)
2245  {
2246  if (!has_privs_of_role(currentUserId, grantorId))
2247  ereport(ERROR,
2248  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2249  errmsg("permission denied to grant privileges as role \"%s\"",
2250  GetUserNameFromId(grantorId, false)),
2251  errdetail("Only roles with privileges of role \"%s\" may grant privileges as this role.",
2252  GetUserNameFromId(grantorId, false))));
2253 
2254  if (grantorId != BOOTSTRAP_SUPERUSERID &&
2255  select_best_admin(grantorId, roleid) != grantorId)
2256  ereport(ERROR,
2257  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2258  errmsg("permission denied to grant privileges as role \"%s\"",
2259  GetUserNameFromId(grantorId, false)),
2260  errdetail("The grantor must have the %s option on role \"%s\".",
2261  "ADMIN", GetUserNameFromId(roleid, false))));
2262  }
2263  else
2264  {
2265  if (!has_privs_of_role(currentUserId, grantorId))
2266  ereport(ERROR,
2267  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2268  errmsg("permission denied to revoke privileges granted by role \"%s\"",
2269  GetUserNameFromId(grantorId, false)),
2270  errdetail("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
2271  GetUserNameFromId(grantorId, false))));
2272  }
2273 
2274  /*
2275  * If a grantor was specified explicitly, always attribute the grant to
2276  * that role (unless we error out above).
2277  */
2278  return grantorId;
2279 }
Oid select_best_admin(Oid member, Oid role)
Definition: acl.c:5289
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5134
#define OidIsValid(objectId)
Definition: c.h:775
bool superuser_arg(Oid roleid)
Definition: superuser.c:56

References elog, ereport, errcode(), errdetail(), errmsg(), ERROR, GetUserNameFromId(), has_privs_of_role(), OidIsValid, select_best_admin(), and superuser_arg().

Referenced by AddRoleMems(), and DelRoleMems().

◆ check_role_membership_authorization()

static void check_role_membership_authorization ( Oid  currentUserId,
Oid  roleid,
bool  is_grant 
)
static

Definition at line 2111 of file user.c.

2113 {
2114  /*
2115  * The charter of pg_database_owner is to have exactly one, implicit,
2116  * situation-dependent member. There's no technical need for this
2117  * restriction. (One could lift it and take the further step of making
2118  * object_ownercheck(DatabaseRelationId, ...) equivalent to
2119  * has_privs_of_role(roleid, ROLE_PG_DATABASE_OWNER), in which case
2120  * explicit, situation-independent members could act as the owner of any
2121  * database.)
2122  */
2123  if (is_grant && roleid == ROLE_PG_DATABASE_OWNER)
2124  ereport(ERROR,
2125  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2126  errmsg("role \"%s\" cannot have explicit members",
2127  GetUserNameFromId(roleid, false)));
2128 
2129  /* To mess with a superuser role, you gotta be superuser. */
2130  if (superuser_arg(roleid))
2131  {
2132  if (!superuser_arg(currentUserId))
2133  {
2134  if (is_grant)
2135  ereport(ERROR,
2136  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2137  errmsg("permission denied to grant role \"%s\"",
2138  GetUserNameFromId(roleid, false)),
2139  errdetail("Only roles with the %s attribute may grant roles with the %s attribute.",
2140  "SUPERUSER", "SUPERUSER")));
2141  else
2142  ereport(ERROR,
2143  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2144  errmsg("permission denied to revoke role \"%s\"",
2145  GetUserNameFromId(roleid, false)),
2146  errdetail("Only roles with the %s attribute may revoke roles with the %s attribute.",
2147  "SUPERUSER", "SUPERUSER")));
2148  }
2149  }
2150  else
2151  {
2152  /*
2153  * Otherwise, must have admin option on the role to be changed.
2154  */
2155  if (!is_admin_of_role(currentUserId, roleid))
2156  {
2157  if (is_grant)
2158  ereport(ERROR,
2159  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2160  errmsg("permission denied to grant role \"%s\"",
2161  GetUserNameFromId(roleid, false)),
2162  errdetail("Only roles with the %s option on role \"%s\" may grant this role.",
2163  "ADMIN", GetUserNameFromId(roleid, false))));
2164  else
2165  ereport(ERROR,
2166  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2167  errmsg("permission denied to revoke role \"%s\"",
2168  GetUserNameFromId(roleid, false)),
2169  errdetail("Only roles with the %s option on role \"%s\" may revoke this role.",
2170  "ADMIN", GetUserNameFromId(roleid, false))));
2171  }
2172  }
2173 }

References ereport, errcode(), errdetail(), errmsg(), ERROR, GetUserNameFromId(), is_admin_of_role(), and superuser_arg().

Referenced by CreateRole(), and GrantRole().

◆ CreateRole()

Oid CreateRole ( ParseState pstate,
CreateRoleStmt stmt 
)

Definition at line 132 of file user.c.

133 {
134  Relation pg_authid_rel;
135  TupleDesc pg_authid_dsc;
136  HeapTuple tuple;
137  Datum new_record[Natts_pg_authid] = {0};
138  bool new_record_nulls[Natts_pg_authid] = {0};
139  Oid currentUserId = GetUserId();
140  Oid roleid;
141  ListCell *item;
142  ListCell *option;
143  char *password = NULL; /* user password */
144  bool issuper = false; /* Make the user a superuser? */
145  bool inherit = true; /* Auto inherit privileges? */
146  bool createrole = false; /* Can this user create roles? */
147  bool createdb = false; /* Can the user create databases? */
148  bool canlogin = false; /* Can this user login? */
149  bool isreplication = false; /* Is this a replication role? */
150  bool bypassrls = false; /* Is this a row security enabled role? */
151  int connlimit = -1; /* maximum connections allowed */
152  List *addroleto = NIL; /* roles to make this a member of */
153  List *rolemembers = NIL; /* roles to be members of this role */
154  List *adminmembers = NIL; /* roles to be admins of this role */
155  char *validUntil = NULL; /* time the login is valid until */
156  Datum validUntil_datum; /* same, as timestamptz Datum */
157  bool validUntil_null;
158  DefElem *dpassword = NULL;
159  DefElem *dissuper = NULL;
160  DefElem *dinherit = NULL;
161  DefElem *dcreaterole = NULL;
162  DefElem *dcreatedb = NULL;
163  DefElem *dcanlogin = NULL;
164  DefElem *disreplication = NULL;
165  DefElem *dconnlimit = NULL;
166  DefElem *daddroleto = NULL;
167  DefElem *drolemembers = NULL;
168  DefElem *dadminmembers = NULL;
169  DefElem *dvalidUntil = NULL;
170  DefElem *dbypassRLS = NULL;
171  GrantRoleOptions popt;
172 
173  /* The defaults can vary depending on the original statement type */
174  switch (stmt->stmt_type)
175  {
176  case ROLESTMT_ROLE:
177  break;
178  case ROLESTMT_USER:
179  canlogin = true;
180  /* may eventually want inherit to default to false here */
181  break;
182  case ROLESTMT_GROUP:
183  break;
184  }
185 
186  /* Extract options from the statement node tree */
187  foreach(option, stmt->options)
188  {
189  DefElem *defel = (DefElem *) lfirst(option);
190 
191  if (strcmp(defel->defname, "password") == 0)
192  {
193  if (dpassword)
194  errorConflictingDefElem(defel, pstate);
195  dpassword = defel;
196  }
197  else if (strcmp(defel->defname, "sysid") == 0)
198  {
199  ereport(NOTICE,
200  (errmsg("SYSID can no longer be specified")));
201  }
202  else if (strcmp(defel->defname, "superuser") == 0)
203  {
204  if (dissuper)
205  errorConflictingDefElem(defel, pstate);
206  dissuper = defel;
207  }
208  else if (strcmp(defel->defname, "inherit") == 0)
209  {
210  if (dinherit)
211  errorConflictingDefElem(defel, pstate);
212  dinherit = defel;
213  }
214  else if (strcmp(defel->defname, "createrole") == 0)
215  {
216  if (dcreaterole)
217  errorConflictingDefElem(defel, pstate);
218  dcreaterole = defel;
219  }
220  else if (strcmp(defel->defname, "createdb") == 0)
221  {
222  if (dcreatedb)
223  errorConflictingDefElem(defel, pstate);
224  dcreatedb = defel;
225  }
226  else if (strcmp(defel->defname, "canlogin") == 0)
227  {
228  if (dcanlogin)
229  errorConflictingDefElem(defel, pstate);
230  dcanlogin = defel;
231  }
232  else if (strcmp(defel->defname, "isreplication") == 0)
233  {
234  if (disreplication)
235  errorConflictingDefElem(defel, pstate);
236  disreplication = defel;
237  }
238  else if (strcmp(defel->defname, "connectionlimit") == 0)
239  {
240  if (dconnlimit)
241  errorConflictingDefElem(defel, pstate);
242  dconnlimit = defel;
243  }
244  else if (strcmp(defel->defname, "addroleto") == 0)
245  {
246  if (daddroleto)
247  errorConflictingDefElem(defel, pstate);
248  daddroleto = defel;
249  }
250  else if (strcmp(defel->defname, "rolemembers") == 0)
251  {
252  if (drolemembers)
253  errorConflictingDefElem(defel, pstate);
254  drolemembers = defel;
255  }
256  else if (strcmp(defel->defname, "adminmembers") == 0)
257  {
258  if (dadminmembers)
259  errorConflictingDefElem(defel, pstate);
260  dadminmembers = defel;
261  }
262  else if (strcmp(defel->defname, "validUntil") == 0)
263  {
264  if (dvalidUntil)
265  errorConflictingDefElem(defel, pstate);
266  dvalidUntil = defel;
267  }
268  else if (strcmp(defel->defname, "bypassrls") == 0)
269  {
270  if (dbypassRLS)
271  errorConflictingDefElem(defel, pstate);
272  dbypassRLS = defel;
273  }
274  else
275  elog(ERROR, "option \"%s\" not recognized",
276  defel->defname);
277  }
278 
279  if (dpassword && dpassword->arg)
280  password = strVal(dpassword->arg);
281  if (dissuper)
282  issuper = boolVal(dissuper->arg);
283  if (dinherit)
284  inherit = boolVal(dinherit->arg);
285  if (dcreaterole)
286  createrole = boolVal(dcreaterole->arg);
287  if (dcreatedb)
288  createdb = boolVal(dcreatedb->arg);
289  if (dcanlogin)
290  canlogin = boolVal(dcanlogin->arg);
291  if (disreplication)
292  isreplication = boolVal(disreplication->arg);
293  if (dconnlimit)
294  {
295  connlimit = intVal(dconnlimit->arg);
296  if (connlimit < -1)
297  ereport(ERROR,
298  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
299  errmsg("invalid connection limit: %d", connlimit)));
300  }
301  if (daddroleto)
302  addroleto = (List *) daddroleto->arg;
303  if (drolemembers)
304  rolemembers = (List *) drolemembers->arg;
305  if (dadminmembers)
306  adminmembers = (List *) dadminmembers->arg;
307  if (dvalidUntil)
308  validUntil = strVal(dvalidUntil->arg);
309  if (dbypassRLS)
310  bypassrls = boolVal(dbypassRLS->arg);
311 
312  /* Check some permissions first */
313  if (!superuser_arg(currentUserId))
314  {
315  if (!has_createrole_privilege(currentUserId))
316  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")));
321  if (issuper)
322  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")));
328  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")));
333  if (isreplication && !has_rolreplication(currentUserId))
334  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")));
339  if (bypassrls && !has_bypassrls_privilege(currentUserId))
340  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  */
351  if (IsReservedName(stmt->role))
352  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  */
371  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
372  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
373 
374  if (OidIsValid(get_role_oid(stmt->role, true)))
375  ereport(ERROR,
377  errmsg("role \"%s\" already exists",
378  stmt->role)));
379 
380  /* Convert validuntil to internal form */
381  if (validUntil)
382  {
383  validUntil_datum = DirectFunctionCall3(timestamptz_in,
384  CStringGetDatum(validUntil),
386  Int32GetDatum(-1));
387  validUntil_null = false;
388  }
389  else
390  {
391  validUntil_datum = (Datum) 0;
392  validUntil_null = true;
393  }
394 
395  /*
396  * Call the password checking hook if there is one defined
397  */
399  (*check_password_hook) (stmt->role,
400  password,
402  validUntil_datum,
403  validUntil_null);
404 
405  /*
406  * Build a tuple to insert
407  */
408  new_record[Anum_pg_authid_rolname - 1] =
410  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
411  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
412  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
413  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
414  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
415  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
416  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
417 
418  if (password)
419  {
420  char *shadow_pass;
421  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  */
435  if (password[0] == '\0' ||
436  plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
437  {
438  ereport(NOTICE,
439  (errmsg("empty string is not a valid password, clearing password")));
440  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
441  }
442  else
443  {
444  /* Encrypt the password to the requested format. */
445  shadow_pass = encrypt_password(Password_encryption, stmt->role,
446  password);
447  new_record[Anum_pg_authid_rolpassword - 1] =
448  CStringGetTextDatum(shadow_pass);
449  }
450  }
451  else
452  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
453 
454  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
455  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
456 
457  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  */
463  if (IsBinaryUpgrade)
464  {
466  ereport(ERROR,
467  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
468  errmsg("pg_authid OID value not set when in binary upgrade mode")));
469 
472  }
473  else
474  {
475  roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
476  Anum_pg_authid_oid);
477  }
478 
479  new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
480 
481  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  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  */
492  if (addroleto || adminmembers || rolemembers)
494 
495  /* Default grant. */
496  InitGrantRoleOptions(&popt);
497 
498  /*
499  * Add the new role to the specified existing roles.
500  */
501  if (addroleto)
502  {
503  RoleSpec *thisrole = makeNode(RoleSpec);
504  List *thisrole_list = list_make1(thisrole);
505  List *thisrole_oidlist = list_make1_oid(roleid);
506 
507  thisrole->roletype = ROLESPEC_CSTRING;
508  thisrole->rolename = stmt->role;
509  thisrole->location = -1;
510 
511  foreach(item, addroleto)
512  {
513  RoleSpec *oldrole = lfirst(item);
514  HeapTuple oldroletup = get_rolespec_tuple(oldrole);
515  Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
516  Oid oldroleid = oldroleform->oid;
517  char *oldrolename = NameStr(oldroleform->rolname);
518 
519  /* can only add this role to roles for which you have rights */
520  check_role_membership_authorization(currentUserId, oldroleid, true);
521  AddRoleMems(currentUserId, oldrolename, oldroleid,
522  thisrole_list,
523  thisrole_oidlist,
524  InvalidOid, &popt);
525 
526  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  */
540  if (!superuser())
541  {
542  RoleSpec *current_role = makeNode(RoleSpec);
543  GrantRoleOptions poptself;
544  List *memberSpecs;
545  List *memberIds = list_make1_oid(currentUserId);
546 
547  current_role->roletype = ROLESPEC_CURRENT_ROLE;
548  current_role->location = -1;
549  memberSpecs = list_make1(current_role);
550 
554  poptself.admin = true;
555  poptself.inherit = false;
556  poptself.set = false;
557 
558  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  */
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  */
578  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  */
590  AddRoleMems(currentUserId, stmt->role, roleid,
591  rolemembers, roleSpecsToIds(rolemembers),
592  InvalidOid, &popt);
594  popt.admin = true;
595  AddRoleMems(currentUserId, stmt->role, roleid,
596  adminmembers, roleSpecsToIds(adminmembers),
597  InvalidOid, &popt);
598 
599  /* Post creation hook for new role */
600  InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
601 
602  /*
603  * Close pg_authid, but keep lock till commit.
604  */
605  table_close(pg_authid_rel, NoLock);
606 
607  return roleid;
608 }
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5420
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:4223
static void check_role_membership_authorization(Oid currentUserId, Oid roleid, bool is_grant)
Definition: user.c:2111
Oid binary_upgrade_next_pg_authid_oid
Definition: user.c:70
bool IsReservedName(const char *name)
Definition: catalog.c:238
Oid createdb(ParseState *pstate, const CreatedbStmt *stmt)
Definition: dbcommands.c:682
#define WARNING
Definition: elog.h:36
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
bool IsBinaryUpgrade
Definition: globals.c:119
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define makeNode(_type_)
Definition: nodes.h:155
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
@ ROLESPEC_CSTRING
Definition: parsenodes.h:394
@ ROLESPEC_CURRENT_ROLE
Definition: parsenodes.h:395
@ ROLESTMT_ROLE
Definition: parsenodes.h:3081
@ ROLESTMT_USER
Definition: parsenodes.h:3082
@ ROLESTMT_GROUP
Definition: parsenodes.h:3083
#define NIL
Definition: pg_list.h:68
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define list_make1(x1)
Definition: pg_list.h:212
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ParseLoc location
Definition: parsenodes.h:406
RoleSpecType roletype
Definition: parsenodes.h:404
char * rolename
Definition: parsenodes.h:405

References AddRoleMems(), GrantRoleOptions::admin, DefElem::arg, binary_upgrade_next_pg_authid_oid, BoolGetDatum(), boolVal, CatalogTupleInsert(), check_password_hook, check_role_membership_authorization(), CommandCounterIncrement(), createdb(), createrole_self_grant_enabled, createrole_self_grant_options, CStringGetDatum(), CStringGetTextDatum, DefElem::defname, DirectFunctionCall1, DirectFunctionCall3, elog, encrypt_password(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, errorConflictingDefElem(), get_password_type(), get_role_oid(), get_rolespec_tuple(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), GRANT_ROLE_SPECIFIED_ADMIN, GRANT_ROLE_SPECIFIED_INHERIT, GRANT_ROLE_SPECIFIED_SET, has_bypassrls_privilege(), has_createrole_privilege(), has_rolreplication(), have_createdb_privilege(), heap_form_tuple(), if(), GrantRoleOptions::inherit, InitGrantRoleOptions(), Int32GetDatum(), intVal, InvalidOid, InvokeObjectPostCreateHook, IsBinaryUpgrade, IsReservedName(), lfirst, list_make1, list_make1_oid, RoleSpec::location, makeNode, namein(), NameStr, NIL, NoLock, NOTICE, ObjectIdGetDatum(), OidIsValid, password, Password_encryption, plain_crypt_verify(), RelationGetDescr, ReleaseSysCache(), RoleSpec::rolename, ROLESPEC_CSTRING, ROLESPEC_CURRENT_ROLE, roleSpecsToIds(), ROLESTMT_GROUP, ROLESTMT_ROLE, ROLESTMT_USER, RoleSpec::roletype, RowExclusiveLock, GrantRoleOptions::set, GrantRoleOptions::specified, STATUS_OK, stmt, strVal, superuser(), superuser_arg(), table_close(), table_open(), timestamptz_in(), and WARNING.

Referenced by standard_ProcessUtility().

◆ DelRoleMems()

static void DelRoleMems ( Oid  currentUserId,
const char *  rolename,
Oid  roleid,
List memberSpecs,
List memberIds,
Oid  grantorId,
GrantRoleOptions popt,
DropBehavior  behavior 
)
static

Definition at line 1979 of file user.c.

1982 {
1983  Relation pg_authmem_rel;
1984  TupleDesc pg_authmem_dsc;
1985  ListCell *specitem;
1986  ListCell *iditem;
1987  CatCList *memlist;
1988  RevokeRoleGrantAction *actions;
1989  int i;
1990 
1991  Assert(list_length(memberSpecs) == list_length(memberIds));
1992 
1993  /* Validate grantor (and resolve implicit grantor if not specified). */
1994  grantorId = check_role_grantor(currentUserId, roleid, grantorId, false);
1995 
1996  pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1997  pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1998 
1999  /*
2000  * Only allow changes to this role by one backend at a time, so that we
2001  * can check for things like dependent privileges without fear of race
2002  * conditions.
2003  */
2004  LockSharedObject(AuthIdRelationId, roleid, 0,
2006 
2007  memlist = SearchSysCacheList1(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid));
2008  actions = initialize_revoke_actions(memlist);
2009 
2010  /*
2011  * We may need to recurse to dependent privileges if DROP_CASCADE was
2012  * specified, or refuse to perform the operation if dependent privileges
2013  * exist and DROP_RESTRICT was specified. plan_single_revoke() will figure
2014  * out what to do with each catalog tuple.
2015  */
2016  forboth(specitem, memberSpecs, iditem, memberIds)
2017  {
2018  RoleSpec *memberRole = lfirst(specitem);
2019  Oid memberid = lfirst_oid(iditem);
2020 
2021  if (!plan_single_revoke(memlist, actions, memberid, grantorId,
2022  popt, behavior))
2023  {
2024  ereport(WARNING,
2025  (errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"",
2026  get_rolespec_name(memberRole), rolename,
2027  GetUserNameFromId(grantorId, false))));
2028  continue;
2029  }
2030  }
2031 
2032  /*
2033  * We now know what to do with each catalog tuple: it should either be
2034  * left alone, deleted, or just have the admin_option flag cleared.
2035  * Perform the appropriate action in each case.
2036  */
2037  for (i = 0; i < memlist->n_members; ++i)
2038  {
2039  HeapTuple authmem_tuple;
2040  Form_pg_auth_members authmem_form;
2041 
2042  if (actions[i] == RRG_NOOP)
2043  continue;
2044 
2045  authmem_tuple = &memlist->members[i]->tuple;
2046  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2047 
2048  if (actions[i] == RRG_DELETE_GRANT)
2049  {
2050  /*
2051  * Remove the entry altogether, after first removing its
2052  * dependencies
2053  */
2054  deleteSharedDependencyRecordsFor(AuthMemRelationId,
2055  authmem_form->oid, 0);
2056  CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
2057  }
2058  else
2059  {
2060  /* Just turn off the specified option */
2061  HeapTuple tuple;
2062  Datum new_record[Natts_pg_auth_members] = {0};
2063  bool new_record_nulls[Natts_pg_auth_members] = {0};
2064  bool new_record_repl[Natts_pg_auth_members] = {0};
2065 
2066  /* Build a tuple to update with */
2067  if (actions[i] == RRG_REMOVE_ADMIN_OPTION)
2068  {
2069  new_record[Anum_pg_auth_members_admin_option - 1] =
2070  BoolGetDatum(false);
2071  new_record_repl[Anum_pg_auth_members_admin_option - 1] =
2072  true;
2073  }
2074  else if (actions[i] == RRG_REMOVE_INHERIT_OPTION)
2075  {
2076  new_record[Anum_pg_auth_members_inherit_option - 1] =
2077  BoolGetDatum(false);
2078  new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
2079  true;
2080  }
2081  else if (actions[i] == RRG_REMOVE_SET_OPTION)
2082  {
2083  new_record[Anum_pg_auth_members_set_option - 1] =
2084  BoolGetDatum(false);
2085  new_record_repl[Anum_pg_auth_members_set_option - 1] =
2086  true;
2087  }
2088  else
2089  elog(ERROR, "unknown role revoke action");
2090 
2091  tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
2092  new_record,
2093  new_record_nulls, new_record_repl);
2094  CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
2095  }
2096  }
2097 
2098  ReleaseSysCacheList(memlist);
2099 
2100  /*
2101  * Close pg_authmem, but keep lock till commit.
2102  */
2103  table_close(pg_authmem_rel, NoLock);
2104 }
static bool plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, Oid member, Oid grantor, GrantRoleOptions *popt, DropBehavior behavior)
Definition: user.c:2321
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1047

References Assert, BoolGetDatum(), CatalogTupleDelete(), CatalogTupleUpdate(), check_role_grantor(), deleteSharedDependencyRecordsFor(), elog, ereport, errmsg(), ERROR, forboth, get_rolespec_name(), GETSTRUCT, GetUserNameFromId(), heap_modify_tuple(), i, initialize_revoke_actions(), lfirst, lfirst_oid, list_length(), LockSharedObject(), catclist::members, catclist::n_members, NoLock, ObjectIdGetDatum(), plan_single_revoke(), RelationGetDescr, ReleaseSysCacheList, RowExclusiveLock, RRG_DELETE_GRANT, RRG_NOOP, RRG_REMOVE_ADMIN_OPTION, RRG_REMOVE_INHERIT_OPTION, RRG_REMOVE_SET_OPTION, SearchSysCacheList1, ShareUpdateExclusiveLock, HeapTupleData::t_self, table_close(), table_open(), catctup::tuple, and WARNING.

Referenced by AlterRole(), and GrantRole().

◆ DropOwnedObjects()

void DropOwnedObjects ( DropOwnedStmt stmt)

Definition at line 1583 of file user.c.

1584 {
1585  List *role_ids = roleSpecsToIds(stmt->roles);
1586  ListCell *cell;
1587 
1588  /* Check privileges */
1589  foreach(cell, role_ids)
1590  {
1591  Oid roleid = lfirst_oid(cell);
1592 
1593  if (!has_privs_of_role(GetUserId(), roleid))
1594  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  shdepDropOwned(role_ids, stmt->behavior);
1603 }
void shdepDropOwned(List *roleids, DropBehavior behavior)
Definition: pg_shdepend.c:1342

References ereport, errcode(), errdetail(), errmsg(), ERROR, GetUserId(), GetUserNameFromId(), has_privs_of_role(), lfirst_oid, roleSpecsToIds(), shdepDropOwned(), and stmt.

Referenced by ProcessUtilitySlow().

◆ DropRole()

void DropRole ( DropRoleStmt stmt)

Definition at line 1090 of file user.c.

1091 {
1092  Relation pg_authid_rel,
1093  pg_auth_members_rel;
1094  ListCell *item;
1095  List *role_oids = NIL;
1096 
1098  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  */
1108  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
1109  pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1110 
1111  foreach(item, stmt->roles)
1112  {
1113  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  if (rolspec->roletype != ROLESPEC_CSTRING)
1123  ereport(ERROR,
1124  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1125  errmsg("cannot use special role specifier in DROP ROLE")));
1126  role = rolspec->rolename;
1127 
1128  tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
1129  if (!HeapTupleIsValid(tuple))
1130  {
1131  if (!stmt->missing_ok)
1132  {
1133  ereport(ERROR,
1134  (errcode(ERRCODE_UNDEFINED_OBJECT),
1135  errmsg("role \"%s\" does not exist", role)));
1136  }
1137  else
1138  {
1139  ereport(NOTICE,
1140  (errmsg("role \"%s\" does not exist, skipping",
1141  role)));
1142  }
1143 
1144  continue;
1145  }
1146 
1147  roleform = (Form_pg_authid) GETSTRUCT(tuple);
1148  roleid = roleform->oid;
1149 
1150  if (roleid == GetUserId())
1151  ereport(ERROR,
1152  (errcode(ERRCODE_OBJECT_IN_USE),
1153  errmsg("current user cannot be dropped")));
1154  if (roleid == GetOuterUserId())
1155  ereport(ERROR,
1156  (errcode(ERRCODE_OBJECT_IN_USE),
1157  errmsg("current user cannot be dropped")));
1158  if (roleid == GetSessionUserId())
1159  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  */
1168  if (roleform->rolsuper && !superuser())
1169  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")));
1174  if (!is_admin_of_role(GetUserId(), roleid))
1175  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 */
1182  InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
1183 
1184  /* Don't leak the syscache tuple */
1185  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  */
1191  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  */
1210  ScanKeyInit(&scankey,
1211  Anum_pg_auth_members_roleid,
1212  BTEqualStrategyNumber, F_OIDEQ,
1213  ObjectIdGetDatum(roleid));
1214 
1215  sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
1216  true, NULL, 1, &scankey);
1217 
1218  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1219  {
1220  Form_pg_auth_members authmem_form;
1221 
1222  authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1223  deleteSharedDependencyRecordsFor(AuthMemRelationId,
1224  authmem_form->oid, 0);
1225  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1226  }
1227 
1228  systable_endscan(sscan);
1229 
1230  ScanKeyInit(&scankey,
1231  Anum_pg_auth_members_member,
1232  BTEqualStrategyNumber, F_OIDEQ,
1233  ObjectIdGetDatum(roleid));
1234 
1235  sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
1236  true, NULL, 1, &scankey);
1237 
1238  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1239  {
1240  Form_pg_auth_members authmem_form;
1241 
1242  authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1243  deleteSharedDependencyRecordsFor(AuthMemRelationId,
1244  authmem_form->oid, 0);
1245  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1246  }
1247 
1248  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  */
1260 
1261  /* Looks tentatively OK, add it to the list if not there yet. */
1262  role_oids = list_append_unique_oid(role_oids, roleid);
1263  }
1264 
1265  /*
1266  * Second pass over the roles to be removed.
1267  */
1268  foreach(item, role_oids)
1269  {
1270  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  */
1283  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
1284  if (!HeapTupleIsValid(tuple))
1285  elog(ERROR, "could not find tuple for role %u", roleid);
1286  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  if (checkSharedDependencies(AuthIdRelationId, roleid,
1296  &detail, &detail_log))
1297  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  CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
1308 
1309  ReleaseSysCache(tuple);
1310 
1311  /*
1312  * Remove any comments or security labels on this role.
1313  */
1314  DeleteSharedComments(roleid, AuthIdRelationId);
1315  DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
1316 
1317  /*
1318  * Remove settings for this role.
1319  */
1320  DropSetting(InvalidOid, roleid);
1321  }
1322 
1323  /*
1324  * Now we can clean up; but keep locks until commit.
1325  */
1326  table_close(pg_auth_members_rel, NoLock);
1327  table_close(pg_authid_rel, NoLock);
1328 }
void DeleteSharedComments(Oid oid, Oid classoid)
Definition: comment.c:374
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errdetail_log(const char *fmt,...)
Definition: elog.c:1251
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
#define AccessExclusiveLock
Definition: lockdefs.h:43
Oid GetOuterUserId(void)
Definition: miscinit.c:525
Oid GetSessionUserId(void)
Definition: miscinit.c:548
#define InvokeObjectDropHook(classId, objectId, subId)
Definition: objectaccess.h:182
void DropSetting(Oid databaseid, Oid roleid)
bool checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
Definition: pg_shdepend.c:676
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void DeleteSharedSecurityLabel(Oid objectId, Oid classId)
Definition: seclabel.c:491
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References AccessExclusiveLock, BTEqualStrategyNumber, CatalogTupleDelete(), checkSharedDependencies(), CommandCounterIncrement(), DeleteSharedComments(), deleteSharedDependencyRecordsFor(), DeleteSharedSecurityLabel(), DropSetting(), elog, ereport, errcode(), errdetail(), errdetail_internal(), errdetail_log(), errmsg(), ERROR, GetOuterUserId(), GetSessionUserId(), GETSTRUCT, GetUserId(), have_createrole_privilege(), HeapTupleIsValid, InvalidOid, InvokeObjectDropHook, is_admin_of_role(), lfirst, lfirst_oid, list_append_unique_oid(), LockSharedObject(), NameStr, NIL, NoLock, NOTICE, ObjectIdGetDatum(), PointerGetDatum(), ReleaseSysCache(), RoleSpec::rolename, ROLESPEC_CSTRING, RoleSpec::roletype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), stmt, superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by standard_ProcessUtility().

◆ GrantRole()

void GrantRole ( ParseState pstate,
GrantRoleStmt stmt 
)

Definition at line 1480 of file user.c.

1481 {
1482  Relation pg_authid_rel;
1483  Oid grantor;
1484  List *grantee_ids;
1485  ListCell *item;
1486  GrantRoleOptions popt;
1487  Oid currentUserId = GetUserId();
1488 
1489  /* Parse options list. */
1490  InitGrantRoleOptions(&popt);
1491  foreach(item, stmt->opt)
1492  {
1493  DefElem *opt = (DefElem *) lfirst(item);
1494  char *optval = defGetString(opt);
1495 
1496  if (strcmp(opt->defname, "admin") == 0)
1497  {
1499 
1500  if (parse_bool(optval, &popt.admin))
1501  continue;
1502  }
1503  else if (strcmp(opt->defname, "inherit") == 0)
1504  {
1506  if (parse_bool(optval, &popt.inherit))
1507  continue;
1508  }
1509  else if (strcmp(opt->defname, "set") == 0)
1510  {
1512  if (parse_bool(optval, &popt.set))
1513  continue;
1514  }
1515  else
1516  ereport(ERROR,
1517  errcode(ERRCODE_SYNTAX_ERROR),
1518  errmsg("unrecognized role option \"%s\"", opt->defname),
1519  parser_errposition(pstate, opt->location));
1520 
1521  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. */
1529  if (stmt->grantor)
1530  grantor = get_rolespec_oid(stmt->grantor, false);
1531  else
1532  grantor = InvalidOid;
1533 
1534  grantee_ids = roleSpecsToIds(stmt->grantee_roles);
1535 
1536  /* AccessShareLock is enough since we aren't modifying pg_authid */
1537  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  */
1546  foreach(item, stmt->granted_roles)
1547  {
1548  AccessPriv *priv = (AccessPriv *) lfirst(item);
1549  char *rolename = priv->priv_name;
1550  Oid roleid;
1551 
1552  /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1553  if (rolename == NULL || priv->cols != NIL)
1554  ereport(ERROR,
1555  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1556  errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1557 
1558  roleid = get_role_oid(rolename, false);
1560  roleid, stmt->is_grant);
1561  if (stmt->is_grant)
1562  AddRoleMems(currentUserId, rolename, roleid,
1563  stmt->grantee_roles, grantee_ids,
1564  grantor, &popt);
1565  else
1566  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  */
1574  table_close(pg_authid_rel, NoLock);
1575 }
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5454
bool parse_bool(const char *value, bool *result)
Definition: bool.c:30
char * defGetString(DefElem *def)
Definition: define.c:48
#define AccessShareLock
Definition: lockdefs.h:36
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
char * priv_name
Definition: parsenodes.h:2548
List * cols
Definition: parsenodes.h:2549
ParseLoc location
Definition: parsenodes.h:819

References AccessShareLock, AddRoleMems(), GrantRoleOptions::admin, check_role_membership_authorization(), AccessPriv::cols, defGetString(), DefElem::defname, DelRoleMems(), ereport, errcode(), errmsg(), ERROR, get_role_oid(), get_rolespec_oid(), GetUserId(), GRANT_ROLE_SPECIFIED_ADMIN, GRANT_ROLE_SPECIFIED_INHERIT, GRANT_ROLE_SPECIFIED_SET, GrantRoleOptions::inherit, InitGrantRoleOptions(), InvalidOid, lfirst, DefElem::location, NIL, NoLock, parse_bool(), parser_errposition(), AccessPriv::priv_name, roleSpecsToIds(), GrantRoleOptions::set, GrantRoleOptions::specified, stmt, table_close(), and table_open().

Referenced by standard_ProcessUtility().

◆ have_createrole_privilege()

static bool have_createrole_privilege ( void  )
static

Definition at line 122 of file user.c.

123 {
125 }

References GetUserId(), and has_createrole_privilege().

Referenced by AlterRole(), AlterRoleSet(), DropRole(), and RenameRole().

◆ InitGrantRoleOptions()

static void InitGrantRoleOptions ( GrantRoleOptions popt)
static

Definition at line 2505 of file user.c.

2506 {
2507  popt->specified = 0;
2508  popt->admin = false;
2509  popt->inherit = false;
2510  popt->set = true;
2511 }

References GrantRoleOptions::admin, GrantRoleOptions::inherit, GrantRoleOptions::set, and GrantRoleOptions::specified.

Referenced by AlterRole(), CreateRole(), and GrantRole().

◆ initialize_revoke_actions()

static RevokeRoleGrantAction * initialize_revoke_actions ( CatCList memlist)
static

Definition at line 2290 of file user.c.

2291 {
2292  RevokeRoleGrantAction *result;
2293  int i;
2294 
2295  if (memlist->n_members == 0)
2296  return NULL;
2297 
2298  result = palloc(sizeof(RevokeRoleGrantAction) * memlist->n_members);
2299  for (i = 0; i < memlist->n_members; i++)
2300  result[i] = RRG_NOOP;
2301  return result;
2302 }

References i, catclist::n_members, palloc(), and RRG_NOOP.

Referenced by AddRoleMems(), and DelRoleMems().

◆ plan_member_revoke()

static void plan_member_revoke ( CatCList memlist,
RevokeRoleGrantAction actions,
Oid  member 
)
static

Definition at line 2391 of file user.c.

2393 {
2394  int i;
2395 
2396  for (i = 0; i < memlist->n_members; ++i)
2397  {
2398  HeapTuple authmem_tuple;
2399  Form_pg_auth_members authmem_form;
2400 
2401  authmem_tuple = &memlist->members[i]->tuple;
2402  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2403 
2404  if (authmem_form->member == member)
2405  plan_recursive_revoke(memlist, actions, i, false, DROP_CASCADE);
2406  }
2407 }
static void plan_recursive_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, int index, bool revoke_admin_option_only, DropBehavior behavior)
Definition: user.c:2415
@ DROP_CASCADE
Definition: parsenodes.h:2335

References DROP_CASCADE, GETSTRUCT, i, catclist::members, catclist::n_members, plan_recursive_revoke(), and catctup::tuple.

Referenced by AddRoleMems().

◆ plan_recursive_revoke()

static void plan_recursive_revoke ( CatCList memlist,
RevokeRoleGrantAction actions,
int  index,
bool  revoke_admin_option_only,
DropBehavior  behavior 
)
static

Definition at line 2415 of file user.c.

2418 {
2419  bool would_still_have_admin_option = false;
2420  HeapTuple authmem_tuple;
2421  Form_pg_auth_members authmem_form;
2422  int i;
2423 
2424  /* If it's already been done, we can just return. */
2425  if (actions[index] == RRG_DELETE_GRANT)
2426  return;
2427  if (actions[index] == RRG_REMOVE_ADMIN_OPTION &&
2428  revoke_admin_option_only)
2429  return;
2430 
2431  /* Locate tuple data. */
2432  authmem_tuple = &memlist->members[index]->tuple;
2433  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2434 
2435  /*
2436  * If the existing tuple does not have admin_option set, then we do not
2437  * need to recurse. If we're just supposed to clear that bit we don't need
2438  * to do anything at all; if we're supposed to remove the grant, we need
2439  * to do something, but only to the tuple, and not any others.
2440  */
2441  if (!revoke_admin_option_only)
2442  {
2443  actions[index] = RRG_DELETE_GRANT;
2444  if (!authmem_form->admin_option)
2445  return;
2446  }
2447  else
2448  {
2449  if (!authmem_form->admin_option)
2450  return;
2451  actions[index] = RRG_REMOVE_ADMIN_OPTION;
2452  }
2453 
2454  /* Determine whether the member would still have ADMIN OPTION. */
2455  for (i = 0; i < memlist->n_members; ++i)
2456  {
2457  HeapTuple am_cascade_tuple;
2458  Form_pg_auth_members am_cascade_form;
2459 
2460  am_cascade_tuple = &memlist->members[i]->tuple;
2461  am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
2462 
2463  if (am_cascade_form->member == authmem_form->member &&
2464  am_cascade_form->admin_option && actions[i] == RRG_NOOP)
2465  {
2466  would_still_have_admin_option = true;
2467  break;
2468  }
2469  }
2470 
2471  /* If the member would still have ADMIN OPTION, we need not recurse. */
2472  if (would_still_have_admin_option)
2473  return;
2474 
2475  /*
2476  * Recurse to grants that are not yet slated for deletion which have this
2477  * member as the grantor.
2478  */
2479  for (i = 0; i < memlist->n_members; ++i)
2480  {
2481  HeapTuple am_cascade_tuple;
2482  Form_pg_auth_members am_cascade_form;
2483 
2484  am_cascade_tuple = &memlist->members[i]->tuple;
2485  am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
2486 
2487  if (am_cascade_form->grantor == authmem_form->member &&
2488  actions[i] != RRG_DELETE_GRANT)
2489  {
2490  if (behavior == DROP_RESTRICT)
2491  ereport(ERROR,
2492  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
2493  errmsg("dependent privileges exist"),
2494  errhint("Use CASCADE to revoke them too.")));
2495 
2496  plan_recursive_revoke(memlist, actions, i, false, behavior);
2497  }
2498  }
2499 }
int errhint(const char *fmt,...)
Definition: elog.c:1317
Definition: type.h:95

References DROP_RESTRICT, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, i, catclist::members, catclist::n_members, RRG_DELETE_GRANT, RRG_NOOP, RRG_REMOVE_ADMIN_OPTION, and catctup::tuple.

Referenced by plan_member_revoke(), and plan_single_revoke().

◆ plan_single_revoke()

static bool plan_single_revoke ( CatCList memlist,
RevokeRoleGrantAction actions,
Oid  member,
Oid  grantor,
GrantRoleOptions popt,
DropBehavior  behavior 
)
static

Definition at line 2321 of file user.c.

2324 {
2325  int i;
2326 
2327  /*
2328  * If popt.specified == 0, we're revoking the grant entirely; otherwise,
2329  * we expect just one bit to be set, and we're revoking the corresponding
2330  * option. As of this writing, there's no syntax that would allow for an
2331  * attempt to revoke multiple options at once, and the logic below
2332  * wouldn't work properly if such syntax were added, so assert that our
2333  * caller isn't trying to do that.
2334  */
2335  Assert(pg_popcount32(popt->specified) <= 1);
2336 
2337  for (i = 0; i < memlist->n_members; ++i)
2338  {
2339  HeapTuple authmem_tuple;
2340  Form_pg_auth_members authmem_form;
2341 
2342  authmem_tuple = &memlist->members[i]->tuple;
2343  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2344 
2345  if (authmem_form->member == member &&
2346  authmem_form->grantor == grantor)
2347  {
2348  if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
2349  {
2350  /*
2351  * Revoking the INHERIT option doesn't change anything for
2352  * dependent privileges, so we don't need to recurse.
2353  */
2354  actions[i] = RRG_REMOVE_INHERIT_OPTION;
2355  }
2356  else if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0)
2357  {
2358  /* Here too, no need to recurse. */
2359  actions[i] = RRG_REMOVE_SET_OPTION;
2360  }
2361  else
2362  {
2363  bool revoke_admin_option_only;
2364 
2365  /*
2366  * Revoking the grant entirely, or ADMIN option on a grant,
2367  * implicates dependent privileges, so we may need to recurse.
2368  */
2369  revoke_admin_option_only =
2370  (popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0;
2371  plan_recursive_revoke(memlist, actions, i,
2372  revoke_admin_option_only, behavior);
2373  }
2374  return true;
2375  }
2376  }
2377 
2378  return false;
2379 }
int pg_popcount32(uint32 word)
Definition: pg_bitutils.c:499

References Assert, GETSTRUCT, GRANT_ROLE_SPECIFIED_ADMIN, GRANT_ROLE_SPECIFIED_INHERIT, GRANT_ROLE_SPECIFIED_SET, i, catclist::members, catclist::n_members, pg_popcount32(), plan_recursive_revoke(), RRG_REMOVE_INHERIT_OPTION, RRG_REMOVE_SET_OPTION, GrantRoleOptions::specified, and catctup::tuple.

Referenced by DelRoleMems().

◆ ReassignOwnedObjects()

void ReassignOwnedObjects ( ReassignOwnedStmt stmt)

Definition at line 1611 of file user.c.

1612 {
1613  List *role_ids = roleSpecsToIds(stmt->roles);
1614  ListCell *cell;
1615  Oid newrole;
1616 
1617  /* Check privileges */
1618  foreach(cell, role_ids)
1619  {
1620  Oid roleid = lfirst_oid(cell);
1621 
1622  if (!has_privs_of_role(GetUserId(), roleid))
1623  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 */
1631  newrole = get_rolespec_oid(stmt->newrole, false);
1632 
1633  if (!has_privs_of_role(GetUserId(), newrole))
1634  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 */
1641  shdepReassignOwned(role_ids, newrole);
1642 }
void shdepReassignOwned(List *roleids, Oid newrole)
Definition: pg_shdepend.c:1530

References ereport, errcode(), errdetail(), errmsg(), ERROR, get_rolespec_oid(), GetUserId(), GetUserNameFromId(), has_privs_of_role(), lfirst_oid, roleSpecsToIds(), shdepReassignOwned(), and stmt.

Referenced by standard_ProcessUtility().

◆ RenameRole()

ObjectAddress RenameRole ( const char *  oldname,
const char *  newname 
)

Definition at line 1334 of file user.c.

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 
1350  rel = table_open(AuthIdRelationId, RowExclusiveLock);
1351  dsc = RelationGetDescr(rel);
1352 
1353  oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1354  if (!HeapTupleIsValid(oldtuple))
1355  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 
1367  authform = (Form_pg_authid) GETSTRUCT(oldtuple);
1368  roleid = authform->oid;
1369 
1370  if (roleid == GetSessionUserId())
1371  ereport(ERROR,
1372  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1373  errmsg("session user cannot be renamed")));
1374  if (roleid == GetOuterUserId())
1375  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  */
1383  if (IsReservedName(NameStr(authform->rolname)))
1384  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 
1390  if (IsReservedName(newname))
1391  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 */
1407  if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
1408  ereport(ERROR,
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  */
1416  if (authform->rolsuper)
1417  {
1418  if (!superuser())
1419  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  {
1427  if (!have_createrole_privilege() ||
1428  !is_admin_of_role(GetUserId(), roleid))
1429  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 */
1437  for (i = 0; i < Natts_pg_authid; i++)
1438  repl_repl[i] = false;
1439 
1440  repl_repl[Anum_pg_authid_rolname - 1] = true;
1441  repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1442  CStringGetDatum(newname));
1443  repl_null[Anum_pg_authid_rolname - 1] = false;
1444 
1445  datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1446 
1447  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 */
1450  repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1451  repl_null[Anum_pg_authid_rolpassword - 1] = true;
1452 
1453  ereport(NOTICE,
1454  (errmsg("MD5 password cleared because of role rename")));
1455  }
1456 
1457  newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1458  CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
1459 
1460  InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
1461 
1462  ObjectAddressSet(address, AuthIdRelationId, roleid);
1463 
1464  ReleaseSysCache(oldtuple);
1465 
1466  /*
1467  * Close pg_authid, but keep lock till commit.
1468  */
1469  table_close(rel, NoLock);
1470 
1471  return address;
1472 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
@ PASSWORD_TYPE_MD5
Definition: crypt.h:30
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95

References CatalogTupleUpdate(), CStringGetDatum(), DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, get_password_type(), GetOuterUserId(), GetSessionUserId(), GETSTRUCT, GetUserId(), have_createrole_privilege(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, is_admin_of_role(), IsReservedName(), namein(), NameStr, NoLock, NOTICE, ObjectAddressSet, PASSWORD_TYPE_MD5, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCacheExists1, superuser(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, and WARNING.

Referenced by ExecRenameStmt().

◆ roleSpecsToIds()

List* roleSpecsToIds ( List memberNames)

Definition at line 1652 of file user.c.

1653 {
1654  List *result = NIL;
1655  ListCell *l;
1656 
1657  foreach(l, memberNames)
1658  {
1659  RoleSpec *rolespec = lfirst_node(RoleSpec, l);
1660  Oid roleid;
1661 
1662  roleid = get_rolespec_oid(rolespec, false);
1663  result = lappend_oid(result, roleid);
1664  }
1665  return result;
1666 }
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375

References get_rolespec_oid(), lappend_oid(), lfirst_node, and NIL.

Referenced by AlterRole(), AlterTableMoveAll(), CreateRole(), DropOwnedObjects(), GrantRole(), and ReassignOwnedObjects().

Variable Documentation

◆ binary_upgrade_next_pg_authid_oid

Oid binary_upgrade_next_pg_authid_oid = InvalidOid

Definition at line 70 of file user.c.

Referenced by binary_upgrade_set_next_pg_authid_oid(), and CreateRole().

◆ check_password_hook

check_password_hook_type check_password_hook = NULL

Definition at line 91 of file user.c.

Referenced by _PG_init(), AlterRole(), and CreateRole().

◆ createrole_self_grant

char* createrole_self_grant = ""

Definition at line 86 of file user.c.

◆ createrole_self_grant_enabled

bool createrole_self_grant_enabled = false
static

Definition at line 87 of file user.c.

Referenced by assign_createrole_self_grant(), and CreateRole().

◆ createrole_self_grant_options

GrantRoleOptions createrole_self_grant_options
static

Definition at line 88 of file user.c.

Referenced by assign_createrole_self_grant(), and CreateRole().

◆ Password_encryption

int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256

Definition at line 85 of file user.c.

Referenced by AlterRole(), CheckPWChallengeAuth(), and CreateRole().