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/timestamp.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 = ""
 
bool createrole_self_grant_enabled = false
 
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 81 of file user.c.

◆ GRANT_ROLE_SPECIFIED_INHERIT

#define GRANT_ROLE_SPECIFIED_INHERIT   0x0002

Definition at line 82 of file user.c.

◆ GRANT_ROLE_SPECIFIED_SET

#define GRANT_ROLE_SPECIFIED_SET   0x0004

Definition at line 83 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 61 of file user.c.

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

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 1688 of file user.c.

1691 {
1692  Relation pg_authmem_rel;
1693  TupleDesc pg_authmem_dsc;
1694  ListCell *specitem;
1695  ListCell *iditem;
1696 
1697  Assert(list_length(memberSpecs) == list_length(memberIds));
1698 
1699  /* Validate grantor (and resolve implicit grantor if not specified). */
1700  grantorId = check_role_grantor(currentUserId, roleid, grantorId, true);
1701 
1702  pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1703  pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1704 
1705  /*
1706  * Only allow changes to this role by one backend at a time, so that we
1707  * can check integrity constraints like the lack of circular ADMIN OPTION
1708  * grants without fear of race conditions.
1709  */
1710  LockSharedObject(AuthIdRelationId, roleid, 0,
1712 
1713  /* Preliminary sanity checks. */
1714  forboth(specitem, memberSpecs, iditem, memberIds)
1715  {
1716  RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1717  Oid memberid = lfirst_oid(iditem);
1718 
1719  /*
1720  * pg_database_owner is never a role member. Lifting this restriction
1721  * would require a policy decision about membership loops. One could
1722  * prevent loops, which would include making "ALTER DATABASE x OWNER
1723  * TO proposed_datdba" fail if is_member_of_role(pg_database_owner,
1724  * proposed_datdba). Hence, gaining a membership could reduce what a
1725  * role could do. Alternately, one could allow these memberships to
1726  * complete loops. A role could then have actual WITH ADMIN OPTION on
1727  * itself, prompting a decision about is_admin_of_role() treatment of
1728  * the case.
1729  *
1730  * Lifting this restriction also has policy implications for ownership
1731  * of shared objects (databases and tablespaces). We allow such
1732  * ownership, but we might find cause to ban it in the future.
1733  * Designing such a ban would more troublesome if the design had to
1734  * address pg_database_owner being a member of role FOO that owns a
1735  * shared object. (The effect of such ownership is that any owner of
1736  * another database can act as the owner of affected shared objects.)
1737  */
1738  if (memberid == ROLE_PG_DATABASE_OWNER)
1739  ereport(ERROR,
1740  errmsg("role \"%s\" cannot be a member of any role",
1741  get_rolespec_name(memberRole)));
1742 
1743  /*
1744  * Refuse creation of membership loops, including the trivial case
1745  * where a role is made a member of itself. We do this by checking to
1746  * see if the target role is already a member of the proposed member
1747  * role. We have to ignore possible superuserness, however, else we
1748  * could never grant membership in a superuser-privileged role.
1749  */
1750  if (is_member_of_role_nosuper(roleid, memberid))
1751  ereport(ERROR,
1752  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1753  errmsg("role \"%s\" is a member of role \"%s\"",
1754  rolename, get_rolespec_name(memberRole))));
1755  }
1756 
1757  /*
1758  * Disallow attempts to grant ADMIN OPTION back to a user who granted it
1759  * to you, similar to what check_circularity does for ACLs. We want the
1760  * chains of grants to remain acyclic, so that it's always possible to use
1761  * REVOKE .. CASCADE to clean up all grants that depend on the one being
1762  * revoked.
1763  *
1764  * NB: This check might look redundant with the check for membership loops
1765  * above, but it isn't. That's checking for role-member loop (e.g. A is a
1766  * member of B and B is a member of A) while this is checking for a
1767  * member-grantor loop (e.g. A gave ADMIN OPTION on X to B and now B, who
1768  * has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on
1769  * X back to A).
1770  */
1771  if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID)
1772  {
1773  CatCList *memlist;
1774  RevokeRoleGrantAction *actions;
1775  int i;
1776 
1777  /* Get the list of members for this role. */
1779  ObjectIdGetDatum(roleid));
1780 
1781  /*
1782  * Figure out what would happen if we removed all existing grants to
1783  * every role to which we've been asked to make a new grant.
1784  */
1785  actions = initialize_revoke_actions(memlist);
1786  foreach(iditem, memberIds)
1787  {
1788  Oid memberid = lfirst_oid(iditem);
1789 
1790  if (memberid == BOOTSTRAP_SUPERUSERID)
1791  ereport(ERROR,
1792  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1793  errmsg("%s option cannot be granted back to your own grantor",
1794  "ADMIN")));
1795  plan_member_revoke(memlist, actions, memberid);
1796  }
1797 
1798  /*
1799  * If the result would be that the grantor role would no longer have
1800  * the ability to perform the grant, then the proposed grant would
1801  * create a circularity.
1802  */
1803  for (i = 0; i < memlist->n_members; ++i)
1804  {
1805  HeapTuple authmem_tuple;
1806  Form_pg_auth_members authmem_form;
1807 
1808  authmem_tuple = &memlist->members[i]->tuple;
1809  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1810 
1811  if (actions[i] == RRG_NOOP &&
1812  authmem_form->member == grantorId &&
1813  authmem_form->admin_option)
1814  break;
1815  }
1816  if (i >= memlist->n_members)
1817  ereport(ERROR,
1818  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1819  errmsg("%s option cannot be granted back to your own grantor",
1820  "ADMIN")));
1821 
1822  ReleaseSysCacheList(memlist);
1823  }
1824 
1825  /* Now perform the catalog updates. */
1826  forboth(specitem, memberSpecs, iditem, memberIds)
1827  {
1828  RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1829  Oid memberid = lfirst_oid(iditem);
1830  HeapTuple authmem_tuple;
1831  HeapTuple tuple;
1832  Datum new_record[Natts_pg_auth_members] = {0};
1833  bool new_record_nulls[Natts_pg_auth_members] = {0};
1834  bool new_record_repl[Natts_pg_auth_members] = {0};
1835 
1836  /* Common initialization for possible insert or update */
1837  new_record[Anum_pg_auth_members_roleid - 1] =
1838  ObjectIdGetDatum(roleid);
1839  new_record[Anum_pg_auth_members_member - 1] =
1840  ObjectIdGetDatum(memberid);
1841  new_record[Anum_pg_auth_members_grantor - 1] =
1842  ObjectIdGetDatum(grantorId);
1843 
1844  /* Find any existing tuple */
1845  authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM,
1846  ObjectIdGetDatum(roleid),
1847  ObjectIdGetDatum(memberid),
1848  ObjectIdGetDatum(grantorId));
1849 
1850  /*
1851  * If we found a tuple, update it with new option values, unless there
1852  * are no changes, in which case issue a WARNING.
1853  *
1854  * If we didn't find a tuple, just insert one.
1855  */
1856  if (HeapTupleIsValid(authmem_tuple))
1857  {
1858  Form_pg_auth_members authmem_form;
1859  bool at_least_one_change = false;
1860 
1861  authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1862 
1863  if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0
1864  && authmem_form->admin_option != popt->admin)
1865  {
1866  new_record[Anum_pg_auth_members_admin_option - 1] =
1867  BoolGetDatum(popt->admin);
1868  new_record_repl[Anum_pg_auth_members_admin_option - 1] =
1869  true;
1870  at_least_one_change = true;
1871  }
1872 
1873  if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0
1874  && authmem_form->inherit_option != popt->inherit)
1875  {
1876  new_record[Anum_pg_auth_members_inherit_option - 1] =
1877  BoolGetDatum(popt->inherit);
1878  new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
1879  true;
1880  at_least_one_change = true;
1881  }
1882 
1883  if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
1884  && authmem_form->set_option != popt->set)
1885  {
1886  new_record[Anum_pg_auth_members_set_option - 1] =
1887  BoolGetDatum(popt->set);
1888  new_record_repl[Anum_pg_auth_members_set_option - 1] =
1889  true;
1890  at_least_one_change = true;
1891  }
1892 
1893  if (!at_least_one_change)
1894  {
1895  ereport(NOTICE,
1896  (errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
1897  get_rolespec_name(memberRole), rolename,
1898  GetUserNameFromId(grantorId, false))));
1899  ReleaseSysCache(authmem_tuple);
1900  continue;
1901  }
1902 
1903  tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1904  new_record,
1905  new_record_nulls, new_record_repl);
1906  CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1907 
1908  ReleaseSysCache(authmem_tuple);
1909  }
1910  else
1911  {
1912  Oid objectId;
1913  Oid *newmembers = palloc(sizeof(Oid));
1914 
1915  /*
1916  * The values for these options can be taken directly from 'popt'.
1917  * Either they were specified, or the defaults as set by
1918  * InitGrantRoleOptions are correct.
1919  */
1920  new_record[Anum_pg_auth_members_admin_option - 1] =
1921  BoolGetDatum(popt->admin);
1922  new_record[Anum_pg_auth_members_set_option - 1] =
1923  BoolGetDatum(popt->set);
1924 
1925  /*
1926  * If the user specified a value for the inherit option, use
1927  * whatever was specified. Otherwise, set the default value based
1928  * on the role-level property.
1929  */
1930  if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
1931  new_record[Anum_pg_auth_members_inherit_option - 1] =
1932  popt->inherit;
1933  else
1934  {
1935  HeapTuple mrtup;
1936  Form_pg_authid mrform;
1937 
1938  mrtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(memberid));
1939  if (!HeapTupleIsValid(mrtup))
1940  elog(ERROR, "cache lookup failed for role %u", memberid);
1941  mrform = (Form_pg_authid) GETSTRUCT(mrtup);
1942  new_record[Anum_pg_auth_members_inherit_option - 1] =
1943  mrform->rolinherit;
1944  ReleaseSysCache(mrtup);
1945  }
1946 
1947  /* get an OID for the new row and insert it */
1948  objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
1949  Anum_pg_auth_members_oid);
1950  new_record[Anum_pg_auth_members_oid - 1] = objectId;
1951  tuple = heap_form_tuple(pg_authmem_dsc,
1952  new_record, new_record_nulls);
1953  CatalogTupleInsert(pg_authmem_rel, tuple);
1954 
1955  /* updateAclDependencies wants to pfree array inputs */
1956  newmembers[0] = grantorId;
1957  updateAclDependencies(AuthMemRelationId, objectId,
1958  0, InvalidOid,
1959  0, NULL,
1960  1, newmembers);
1961  }
1962 
1963  /* CCI after each change, in case there are duplicates in list */
1965  }
1966 
1967  /*
1968  * Close pg_authmem, but keep lock till commit.
1969  */
1970  table_close(pg_authmem_rel, NoLock);
1971 }
char * get_rolespec_name(const RoleSpec *role)
Definition: acl.c:5465
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5168
#define GRANT_ROLE_SPECIFIED_ADMIN
Definition: user.c:81
static void plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions, Oid member)
Definition: user.c:2396
#define GRANT_ROLE_SPECIFIED_SET
Definition: user.c:83
static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
Definition: user.c:2210
#define GRANT_ROLE_SPECIFIED_INHERIT
Definition: user.c:82
static RevokeRoleGrantAction * initialize_revoke_actions(CatCList *memlist)
Definition: user.c:2295
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#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:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#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
Assert(fmt[strlen(fmt) - 1] !='\n')
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1046
#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:1226
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:973
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:467
#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:482
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:530
unsigned specified
Definition: user.c:75
bool admin
Definition: user.c:76
bool set
Definition: user.c:78
bool inherit
Definition: user.c:77
ItemPointerData t_self
Definition: htup.h:65
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
int n_members
Definition: catcache.h:176
HeapTupleData tuple
Definition: catcache.h:121
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:842
@ AUTHOID
Definition: syscache.h:45
@ AUTHMEMROLEMEM
Definition: syscache.h:43
#define ReleaseSysCacheList(x)
Definition: syscache.h:225
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:218
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:1078

References GrantRoleOptions::admin, Assert(), AUTHMEMROLEMEM, AUTHOID, 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 620 of file user.c.

621 {
622  Datum new_record[Natts_pg_authid] = {0};
623  bool new_record_nulls[Natts_pg_authid] = {0};
624  bool new_record_repl[Natts_pg_authid] = {0};
625  Relation pg_authid_rel;
626  TupleDesc pg_authid_dsc;
627  HeapTuple tuple,
628  new_tuple;
629  Form_pg_authid authform;
630  ListCell *option;
631  char *rolename;
632  char *password = NULL; /* user password */
633  int connlimit = -1; /* maximum connections allowed */
634  char *validUntil = NULL; /* time the login is valid until */
635  Datum validUntil_datum; /* same, as timestamptz Datum */
636  bool validUntil_null;
637  DefElem *dpassword = NULL;
638  DefElem *dissuper = NULL;
639  DefElem *dinherit = NULL;
640  DefElem *dcreaterole = NULL;
641  DefElem *dcreatedb = NULL;
642  DefElem *dcanlogin = NULL;
643  DefElem *disreplication = NULL;
644  DefElem *dconnlimit = NULL;
645  DefElem *drolemembers = NULL;
646  DefElem *dvalidUntil = NULL;
647  DefElem *dbypassRLS = NULL;
648  Oid roleid;
649  Oid currentUserId = GetUserId();
650  GrantRoleOptions popt;
651 
653  _("Cannot alter reserved roles."));
654 
655  /* Extract options from the statement node tree */
656  foreach(option, stmt->options)
657  {
658  DefElem *defel = (DefElem *) lfirst(option);
659 
660  if (strcmp(defel->defname, "password") == 0)
661  {
662  if (dpassword)
663  errorConflictingDefElem(defel, pstate);
664  dpassword = defel;
665  }
666  else if (strcmp(defel->defname, "superuser") == 0)
667  {
668  if (dissuper)
669  errorConflictingDefElem(defel, pstate);
670  dissuper = defel;
671  }
672  else if (strcmp(defel->defname, "inherit") == 0)
673  {
674  if (dinherit)
675  errorConflictingDefElem(defel, pstate);
676  dinherit = defel;
677  }
678  else if (strcmp(defel->defname, "createrole") == 0)
679  {
680  if (dcreaterole)
681  errorConflictingDefElem(defel, pstate);
682  dcreaterole = defel;
683  }
684  else if (strcmp(defel->defname, "createdb") == 0)
685  {
686  if (dcreatedb)
687  errorConflictingDefElem(defel, pstate);
688  dcreatedb = defel;
689  }
690  else if (strcmp(defel->defname, "canlogin") == 0)
691  {
692  if (dcanlogin)
693  errorConflictingDefElem(defel, pstate);
694  dcanlogin = defel;
695  }
696  else if (strcmp(defel->defname, "isreplication") == 0)
697  {
698  if (disreplication)
699  errorConflictingDefElem(defel, pstate);
700  disreplication = defel;
701  }
702  else if (strcmp(defel->defname, "connectionlimit") == 0)
703  {
704  if (dconnlimit)
705  errorConflictingDefElem(defel, pstate);
706  dconnlimit = defel;
707  }
708  else if (strcmp(defel->defname, "rolemembers") == 0 &&
709  stmt->action != 0)
710  {
711  if (drolemembers)
712  errorConflictingDefElem(defel, pstate);
713  drolemembers = defel;
714  }
715  else if (strcmp(defel->defname, "validUntil") == 0)
716  {
717  if (dvalidUntil)
718  errorConflictingDefElem(defel, pstate);
719  dvalidUntil = defel;
720  }
721  else if (strcmp(defel->defname, "bypassrls") == 0)
722  {
723  if (dbypassRLS)
724  errorConflictingDefElem(defel, pstate);
725  dbypassRLS = defel;
726  }
727  else
728  elog(ERROR, "option \"%s\" not recognized",
729  defel->defname);
730  }
731 
732  if (dpassword && dpassword->arg)
733  password = strVal(dpassword->arg);
734  if (dconnlimit)
735  {
736  connlimit = intVal(dconnlimit->arg);
737  if (connlimit < -1)
738  ereport(ERROR,
739  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
740  errmsg("invalid connection limit: %d", connlimit)));
741  }
742  if (dvalidUntil)
743  validUntil = strVal(dvalidUntil->arg);
744 
745  /*
746  * Scan the pg_authid relation to be certain the user exists.
747  */
748  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
749  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
750 
751  tuple = get_rolespec_tuple(stmt->role);
752  authform = (Form_pg_authid) GETSTRUCT(tuple);
753  rolename = pstrdup(NameStr(authform->rolname));
754  roleid = authform->oid;
755 
756  /* To mess with a superuser in any way you gotta be superuser. */
757  if (!superuser() && authform->rolsuper)
758  ereport(ERROR,
759  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
760  errmsg("permission denied to alter role"),
761  errdetail("Only roles with the %s attribute may alter roles with the %s attribute.",
762  "SUPERUSER", "SUPERUSER")));
763  if (!superuser() && dissuper)
764  ereport(ERROR,
765  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
766  errmsg("permission denied to alter role"),
767  errdetail("Only roles with the %s attribute may change the %s attribute.",
768  "SUPERUSER", "SUPERUSER")));
769 
770  /*
771  * Most changes to a role require that you both have CREATEROLE privileges
772  * and also ADMIN OPTION on the role.
773  */
774  if (!have_createrole_privilege() ||
775  !is_admin_of_role(GetUserId(), roleid))
776  {
777  /* things an unprivileged user certainly can't do */
778  if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
779  dvalidUntil || disreplication || dbypassRLS)
780  ereport(ERROR,
781  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
782  errmsg("permission denied to alter role"),
783  errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
784  "CREATEROLE", "ADMIN", rolename)));
785 
786  /* an unprivileged user can change their own password */
787  if (dpassword && roleid != currentUserId)
788  ereport(ERROR,
789  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
790  errmsg("permission denied to alter role"),
791  errdetail("To change another role's password, the current user must have the %s attribute and the %s option on the role.",
792  "CREATEROLE", "ADMIN")));
793  }
794  else if (!superuser())
795  {
796  /*
797  * Even if you have both CREATEROLE and ADMIN OPTION on a role, you
798  * can only change the CREATEDB, REPLICATION, or BYPASSRLS attributes
799  * if they are set for your own role (or you are the superuser).
800  */
801  if (dcreatedb && !have_createdb_privilege())
802  ereport(ERROR,
803  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
804  errmsg("permission denied to alter role"),
805  errdetail("Only roles with the %s attribute may change the %s attribute.",
806  "CREATEDB", "CREATEDB")));
807  if (disreplication && !has_rolreplication(currentUserId))
808  ereport(ERROR,
809  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
810  errmsg("permission denied to alter role"),
811  errdetail("Only roles with the %s attribute may change the %s attribute.",
812  "REPLICATION", "REPLICATION")));
813  if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
814  ereport(ERROR,
815  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
816  errmsg("permission denied to alter role"),
817  errdetail("Only roles with the %s attribute may change the %s attribute.",
818  "BYPASSRLS", "BYPASSRLS")));
819  }
820 
821  /* To add members to a role, you need ADMIN OPTION. */
822  if (drolemembers && !is_admin_of_role(currentUserId, roleid))
823  ereport(ERROR,
824  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
825  errmsg("permission denied to alter role"),
826  errdetail("Only roles with the %s option on role \"%s\" may add members.",
827  "ADMIN", rolename)));
828 
829  /* Convert validuntil to internal form */
830  if (dvalidUntil)
831  {
832  validUntil_datum = DirectFunctionCall3(timestamptz_in,
833  CStringGetDatum(validUntil),
835  Int32GetDatum(-1));
836  validUntil_null = false;
837  }
838  else
839  {
840  /* fetch existing setting in case hook needs it */
841  validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
842  Anum_pg_authid_rolvaliduntil,
843  &validUntil_null);
844  }
845 
846  /*
847  * Call the password checking hook if there is one defined
848  */
850  (*check_password_hook) (rolename,
851  password,
853  validUntil_datum,
854  validUntil_null);
855 
856  /*
857  * Build an updated tuple, perusing the information just obtained
858  */
859 
860  /*
861  * issuper/createrole/etc
862  */
863  if (dissuper)
864  {
865  bool should_be_super = boolVal(dissuper->arg);
866 
867  if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
868  ereport(ERROR,
869  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
870  errmsg("permission denied to alter role"),
871  errdetail("The bootstrap user must have the %s attribute.",
872  "SUPERUSER")));
873 
874  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
875  new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
876  }
877 
878  if (dinherit)
879  {
880  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg));
881  new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
882  }
883 
884  if (dcreaterole)
885  {
886  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg));
887  new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
888  }
889 
890  if (dcreatedb)
891  {
892  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg));
893  new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
894  }
895 
896  if (dcanlogin)
897  {
898  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg));
899  new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
900  }
901 
902  if (disreplication)
903  {
904  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg));
905  new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
906  }
907 
908  if (dconnlimit)
909  {
910  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
911  new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
912  }
913 
914  /* password */
915  if (password)
916  {
917  char *shadow_pass;
918  const char *logdetail = NULL;
919 
920  /* Like in CREATE USER, don't allow an empty password. */
921  if (password[0] == '\0' ||
922  plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
923  {
924  ereport(NOTICE,
925  (errmsg("empty string is not a valid password, clearing password")));
926  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
927  }
928  else
929  {
930  /* Encrypt the password to the requested format. */
931  shadow_pass = encrypt_password(Password_encryption, rolename,
932  password);
933  new_record[Anum_pg_authid_rolpassword - 1] =
934  CStringGetTextDatum(shadow_pass);
935  }
936  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
937  }
938 
939  /* unset password */
940  if (dpassword && dpassword->arg == NULL)
941  {
942  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
943  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
944  }
945 
946  /* valid until */
947  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
948  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
949  new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
950 
951  if (dbypassRLS)
952  {
953  new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg));
954  new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
955  }
956 
957  new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
958  new_record_nulls, new_record_repl);
959  CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
960 
961  InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
962 
963  ReleaseSysCache(tuple);
964  heap_freetuple(new_tuple);
965 
966  InitGrantRoleOptions(&popt);
967 
968  /*
969  * Advance command counter so we can see new record; else tests in
970  * AddRoleMems may fail.
971  */
972  if (drolemembers)
973  {
974  List *rolemembers = (List *) drolemembers->arg;
975 
977 
978  if (stmt->action == +1) /* add members to role */
979  AddRoleMems(currentUserId, rolename, roleid,
980  rolemembers, roleSpecsToIds(rolemembers),
981  InvalidOid, &popt);
982  else if (stmt->action == -1) /* drop members from role */
983  DelRoleMems(currentUserId, rolename, roleid,
984  rolemembers, roleSpecsToIds(rolemembers),
985  InvalidOid, &popt, DROP_RESTRICT);
986  }
987 
988  /*
989  * Close pg_authid, but keep lock till commit.
990  */
991  table_close(pg_authid_rel, NoLock);
992 
993  return roleid;
994 }
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:5190
void check_rolespec_name(const RoleSpec *role, const char *detail_msg)
Definition: acl.c:5487
HeapTuple get_rolespec_tuple(const RoleSpec *role)
Definition: acl.c:5419
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4193
static bool have_createrole_privilege(void)
Definition: user.c:123
static void InitGrantRoleOptions(GrantRoleOptions *popt)
Definition: user.c:2510
static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt)
Definition: user.c:1688
int Password_encryption
Definition: user.c:86
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1659
check_password_hook_type check_password_hook
Definition: user.c:92
static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
Definition: user.c:1985
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:417
#define CStringGetTextDatum(s)
Definition: builtins.h:94
#define NameStr(name)
Definition: c.h:735
#define STATUS_OK
Definition: c.h:1182
int plain_crypt_verify(const char *role, const char *shadow_pass, const char *client_pass, const char **logdetail)
Definition: crypt.c:223
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
char * encrypt_password(PasswordType target_type, const char *role, const char *password)
Definition: crypt.c:116
bool have_createdb_privilege(void)
Definition: dbcommands.c:2854
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
int errdetail(const char *fmt,...)
Definition: elog.c:1202
#define _(x)
Definition: elog.c:91
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define stmt
Definition: indent_codes.h:59
char * pstrdup(const char *in)
Definition: mcxt.c:1644
Oid GetUserId(void)
Definition: miscinit.c:508
bool has_rolreplication(Oid roleid)
Definition: miscinit.c:705
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
@ DROP_RESTRICT
Definition: parsenodes.h:2169
#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:53
char * defname
Definition: parsenodes.h:802
Node * arg
Definition: parsenodes.h:803
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:1081
@ AUTHNAME
Definition: syscache.h:44
#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, AUTHNAME, 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 1001 of file user.c.

1002 {
1003  HeapTuple roletuple;
1004  Form_pg_authid roleform;
1005  Oid databaseid = InvalidOid;
1006  Oid roleid = InvalidOid;
1007 
1008  if (stmt->role)
1009  {
1010  check_rolespec_name(stmt->role,
1011  _("Cannot alter reserved roles."));
1012 
1013  roletuple = get_rolespec_tuple(stmt->role);
1014  roleform = (Form_pg_authid) GETSTRUCT(roletuple);
1015  roleid = roleform->oid;
1016 
1017  /*
1018  * Obtain a lock on the role and make sure it didn't go away in the
1019  * meantime.
1020  */
1021  shdepLockAndCheckObject(AuthIdRelationId, roleid);
1022 
1023  /*
1024  * To mess with a superuser you gotta be superuser; otherwise you need
1025  * CREATEROLE plus admin option on the target role; unless you're just
1026  * trying to change your own settings
1027  */
1028  if (roleform->rolsuper)
1029  {
1030  if (!superuser())
1031  ereport(ERROR,
1032  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1033  errmsg("permission denied to alter role"),
1034  errdetail("Only roles with the %s attribute may alter roles with the %s attribute.",
1035  "SUPERUSER", "SUPERUSER")));
1036  }
1037  else
1038  {
1039  if ((!have_createrole_privilege() ||
1040  !is_admin_of_role(GetUserId(), roleid))
1041  && roleid != GetUserId())
1042  ereport(ERROR,
1043  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1044  errmsg("permission denied to alter role"),
1045  errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
1046  "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
1047  }
1048 
1049  ReleaseSysCache(roletuple);
1050  }
1051 
1052  /* look up and lock the database, if specified */
1053  if (stmt->database != NULL)
1054  {
1055  databaseid = get_database_oid(stmt->database, false);
1056  shdepLockAndCheckObject(DatabaseRelationId, databaseid);
1057 
1058  if (!stmt->role)
1059  {
1060  /*
1061  * If no role is specified, then this is effectively the same as
1062  * ALTER DATABASE ... SET, so use the same permission check.
1063  */
1064  if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
1066  stmt->database);
1067  }
1068  }
1069 
1070  if (!stmt->role && !stmt->database)
1071  {
1072  /* Must be superuser to alter settings globally. */
1073  if (!superuser())
1074  ereport(ERROR,
1075  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1076  errmsg("permission denied to alter setting"),
1077  errdetail("Only roles with the %s attribute may alter settings globally.",
1078  "SUPERUSER")));
1079  }
1080 
1081  AlterSetting(databaseid, roleid, stmt->setstmt);
1082 
1083  return roleid;
1084 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2695
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4097
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3042
@ OBJECT_DATABASE
Definition: parsenodes.h:2105
void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1166

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 2522 of file user.c.

2523 {
2524  char *rawstring;
2525  List *elemlist;
2526  ListCell *l;
2527  unsigned options = 0;
2528  unsigned *result;
2529 
2530  /* Need a modifiable copy of string */
2531  rawstring = pstrdup(*newval);
2532 
2533  if (!SplitIdentifierString(rawstring, ',', &elemlist))
2534  {
2535  /* syntax error in list */
2536  GUC_check_errdetail("List syntax is invalid.");
2537  pfree(rawstring);
2538  list_free(elemlist);
2539  return false;
2540  }
2541 
2542  foreach(l, elemlist)
2543  {
2544  char *tok = (char *) lfirst(l);
2545 
2546  if (pg_strcasecmp(tok, "SET") == 0)
2548  else if (pg_strcasecmp(tok, "INHERIT") == 0)
2550  else
2551  {
2552  GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
2553  pfree(rawstring);
2554  list_free(elemlist);
2555  return false;
2556  }
2557  }
2558 
2559  pfree(rawstring);
2560  list_free(elemlist);
2561 
2562  result = (unsigned *) guc_malloc(LOG, sizeof(unsigned));
2563  *result = options;
2564  *extra = result;
2565 
2566  return true;
2567 }
#define LOG
Definition: elog.h:31
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:633
#define newval
#define GUC_check_errdetail
Definition: guc.h:436
void list_free(List *list)
Definition: list.c:1545
void pfree(void *pointer)
Definition: mcxt.c:1456
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:3456

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 2210 of file user.c.

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

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

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 133 of file user.c.

134 {
135  Relation pg_authid_rel;
136  TupleDesc pg_authid_dsc;
137  HeapTuple tuple;
138  Datum new_record[Natts_pg_authid] = {0};
139  bool new_record_nulls[Natts_pg_authid] = {0};
140  Oid currentUserId = GetUserId();
141  Oid roleid;
142  ListCell *item;
143  ListCell *option;
144  char *password = NULL; /* user password */
145  bool issuper = false; /* Make the user a superuser? */
146  bool inherit = true; /* Auto inherit privileges? */
147  bool createrole = false; /* Can this user create roles? */
148  bool createdb = false; /* Can the user create databases? */
149  bool canlogin = false; /* Can this user login? */
150  bool isreplication = false; /* Is this a replication role? */
151  bool bypassrls = false; /* Is this a row security enabled role? */
152  int connlimit = -1; /* maximum connections allowed */
153  List *addroleto = NIL; /* roles to make this a member of */
154  List *rolemembers = NIL; /* roles to be members of this role */
155  List *adminmembers = NIL; /* roles to be admins of this role */
156  char *validUntil = NULL; /* time the login is valid until */
157  Datum validUntil_datum; /* same, as timestamptz Datum */
158  bool validUntil_null;
159  DefElem *dpassword = NULL;
160  DefElem *dissuper = NULL;
161  DefElem *dinherit = NULL;
162  DefElem *dcreaterole = NULL;
163  DefElem *dcreatedb = NULL;
164  DefElem *dcanlogin = NULL;
165  DefElem *disreplication = NULL;
166  DefElem *dconnlimit = NULL;
167  DefElem *daddroleto = NULL;
168  DefElem *drolemembers = NULL;
169  DefElem *dadminmembers = NULL;
170  DefElem *dvalidUntil = NULL;
171  DefElem *dbypassRLS = NULL;
172  GrantRoleOptions popt;
173 
174  /* The defaults can vary depending on the original statement type */
175  switch (stmt->stmt_type)
176  {
177  case ROLESTMT_ROLE:
178  break;
179  case ROLESTMT_USER:
180  canlogin = true;
181  /* may eventually want inherit to default to false here */
182  break;
183  case ROLESTMT_GROUP:
184  break;
185  }
186 
187  /* Extract options from the statement node tree */
188  foreach(option, stmt->options)
189  {
190  DefElem *defel = (DefElem *) lfirst(option);
191 
192  if (strcmp(defel->defname, "password") == 0)
193  {
194  if (dpassword)
195  errorConflictingDefElem(defel, pstate);
196  dpassword = defel;
197  }
198  else if (strcmp(defel->defname, "sysid") == 0)
199  {
200  ereport(NOTICE,
201  (errmsg("SYSID can no longer be specified")));
202  }
203  else if (strcmp(defel->defname, "superuser") == 0)
204  {
205  if (dissuper)
206  errorConflictingDefElem(defel, pstate);
207  dissuper = defel;
208  }
209  else if (strcmp(defel->defname, "inherit") == 0)
210  {
211  if (dinherit)
212  errorConflictingDefElem(defel, pstate);
213  dinherit = defel;
214  }
215  else if (strcmp(defel->defname, "createrole") == 0)
216  {
217  if (dcreaterole)
218  errorConflictingDefElem(defel, pstate);
219  dcreaterole = defel;
220  }
221  else if (strcmp(defel->defname, "createdb") == 0)
222  {
223  if (dcreatedb)
224  errorConflictingDefElem(defel, pstate);
225  dcreatedb = defel;
226  }
227  else if (strcmp(defel->defname, "canlogin") == 0)
228  {
229  if (dcanlogin)
230  errorConflictingDefElem(defel, pstate);
231  dcanlogin = defel;
232  }
233  else if (strcmp(defel->defname, "isreplication") == 0)
234  {
235  if (disreplication)
236  errorConflictingDefElem(defel, pstate);
237  disreplication = defel;
238  }
239  else if (strcmp(defel->defname, "connectionlimit") == 0)
240  {
241  if (dconnlimit)
242  errorConflictingDefElem(defel, pstate);
243  dconnlimit = defel;
244  }
245  else if (strcmp(defel->defname, "addroleto") == 0)
246  {
247  if (daddroleto)
248  errorConflictingDefElem(defel, pstate);
249  daddroleto = defel;
250  }
251  else if (strcmp(defel->defname, "rolemembers") == 0)
252  {
253  if (drolemembers)
254  errorConflictingDefElem(defel, pstate);
255  drolemembers = defel;
256  }
257  else if (strcmp(defel->defname, "adminmembers") == 0)
258  {
259  if (dadminmembers)
260  errorConflictingDefElem(defel, pstate);
261  dadminmembers = defel;
262  }
263  else if (strcmp(defel->defname, "validUntil") == 0)
264  {
265  if (dvalidUntil)
266  errorConflictingDefElem(defel, pstate);
267  dvalidUntil = defel;
268  }
269  else if (strcmp(defel->defname, "bypassrls") == 0)
270  {
271  if (dbypassRLS)
272  errorConflictingDefElem(defel, pstate);
273  dbypassRLS = defel;
274  }
275  else
276  elog(ERROR, "option \"%s\" not recognized",
277  defel->defname);
278  }
279 
280  if (dpassword && dpassword->arg)
281  password = strVal(dpassword->arg);
282  if (dissuper)
283  issuper = boolVal(dissuper->arg);
284  if (dinherit)
285  inherit = boolVal(dinherit->arg);
286  if (dcreaterole)
287  createrole = boolVal(dcreaterole->arg);
288  if (dcreatedb)
289  createdb = boolVal(dcreatedb->arg);
290  if (dcanlogin)
291  canlogin = boolVal(dcanlogin->arg);
292  if (disreplication)
293  isreplication = boolVal(disreplication->arg);
294  if (dconnlimit)
295  {
296  connlimit = intVal(dconnlimit->arg);
297  if (connlimit < -1)
298  ereport(ERROR,
299  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
300  errmsg("invalid connection limit: %d", connlimit)));
301  }
302  if (daddroleto)
303  addroleto = (List *) daddroleto->arg;
304  if (drolemembers)
305  rolemembers = (List *) drolemembers->arg;
306  if (dadminmembers)
307  adminmembers = (List *) dadminmembers->arg;
308  if (dvalidUntil)
309  validUntil = strVal(dvalidUntil->arg);
310  if (dbypassRLS)
311  bypassrls = boolVal(dbypassRLS->arg);
312 
313  /* Check some permissions first */
314  if (!superuser_arg(currentUserId))
315  {
316  if (!has_createrole_privilege(currentUserId))
317  ereport(ERROR,
318  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
319  errmsg("permission denied to create role"),
320  errdetail("Only roles with the %s attribute may create roles.",
321  "CREATEROLE")));
322  if (issuper)
323  ereport(ERROR,
324  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
325  errmsg("permission denied to create role"),
326  errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
327  "SUPERUSER", "SUPERUSER")));
329  ereport(ERROR,
330  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
331  errmsg("permission denied to create role"),
332  errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
333  "CREATEDB", "CREATEDB")));
334  if (isreplication && !has_rolreplication(currentUserId))
335  ereport(ERROR,
336  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
337  errmsg("permission denied to create role"),
338  errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
339  "REPLICATION", "REPLICATION")));
340  if (bypassrls && !has_bypassrls_privilege(currentUserId))
341  ereport(ERROR,
342  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
343  errmsg("permission denied to create role"),
344  errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
345  "BYPASSRLS", "BYPASSRLS")));
346  }
347 
348  /*
349  * Check that the user is not trying to create a role in the reserved
350  * "pg_" namespace.
351  */
352  if (IsReservedName(stmt->role))
353  ereport(ERROR,
354  (errcode(ERRCODE_RESERVED_NAME),
355  errmsg("role name \"%s\" is reserved",
356  stmt->role),
357  errdetail("Role names starting with \"pg_\" are reserved.")));
358 
359  /*
360  * If built with appropriate switch, whine when regression-testing
361  * conventions for role names are violated.
362  */
363 #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
364  if (strncmp(stmt->role, "regress_", 8) != 0)
365  elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
366 #endif
367 
368  /*
369  * Check the pg_authid relation to be certain the role doesn't already
370  * exist.
371  */
372  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
373  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
374 
375  if (OidIsValid(get_role_oid(stmt->role, true)))
376  ereport(ERROR,
378  errmsg("role \"%s\" already exists",
379  stmt->role)));
380 
381  /* Convert validuntil to internal form */
382  if (validUntil)
383  {
384  validUntil_datum = DirectFunctionCall3(timestamptz_in,
385  CStringGetDatum(validUntil),
387  Int32GetDatum(-1));
388  validUntil_null = false;
389  }
390  else
391  {
392  validUntil_datum = (Datum) 0;
393  validUntil_null = true;
394  }
395 
396  /*
397  * Call the password checking hook if there is one defined
398  */
400  (*check_password_hook) (stmt->role,
401  password,
403  validUntil_datum,
404  validUntil_null);
405 
406  /*
407  * Build a tuple to insert
408  */
409  new_record[Anum_pg_authid_rolname - 1] =
411  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
412  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
413  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
414  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
415  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
416  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
417  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
418 
419  if (password)
420  {
421  char *shadow_pass;
422  const char *logdetail = NULL;
423 
424  /*
425  * Don't allow an empty password. Libpq treats an empty password the
426  * same as no password at all, and won't even try to authenticate. But
427  * other clients might, so allowing it would be confusing. By clearing
428  * the password when an empty string is specified, the account is
429  * consistently locked for all clients.
430  *
431  * Note that this only covers passwords stored in the database itself.
432  * There are also checks in the authentication code, to forbid an
433  * empty password from being used with authentication methods that
434  * fetch the password from an external system, like LDAP or PAM.
435  */
436  if (password[0] == '\0' ||
437  plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
438  {
439  ereport(NOTICE,
440  (errmsg("empty string is not a valid password, clearing password")));
441  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
442  }
443  else
444  {
445  /* Encrypt the password to the requested format. */
446  shadow_pass = encrypt_password(Password_encryption, stmt->role,
447  password);
448  new_record[Anum_pg_authid_rolpassword - 1] =
449  CStringGetTextDatum(shadow_pass);
450  }
451  }
452  else
453  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
454 
455  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
456  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
457 
458  new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
459 
460  /*
461  * pg_largeobject_metadata contains pg_authid.oid's, so we use the
462  * binary-upgrade override.
463  */
464  if (IsBinaryUpgrade)
465  {
467  ereport(ERROR,
468  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
469  errmsg("pg_authid OID value not set when in binary upgrade mode")));
470 
473  }
474  else
475  {
476  roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
477  Anum_pg_authid_oid);
478  }
479 
480  new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
481 
482  tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
483 
484  /*
485  * Insert new record in the pg_authid table
486  */
487  CatalogTupleInsert(pg_authid_rel, tuple);
488 
489  /*
490  * Advance command counter so we can see new record; else tests in
491  * AddRoleMems may fail.
492  */
493  if (addroleto || adminmembers || rolemembers)
495 
496  /* Default grant. */
497  InitGrantRoleOptions(&popt);
498 
499  /*
500  * Add the new role to the specified existing roles.
501  */
502  if (addroleto)
503  {
504  RoleSpec *thisrole = makeNode(RoleSpec);
505  List *thisrole_list = list_make1(thisrole);
506  List *thisrole_oidlist = list_make1_oid(roleid);
507 
508  thisrole->roletype = ROLESPEC_CSTRING;
509  thisrole->rolename = stmt->role;
510  thisrole->location = -1;
511 
512  foreach(item, addroleto)
513  {
514  RoleSpec *oldrole = lfirst(item);
515  HeapTuple oldroletup = get_rolespec_tuple(oldrole);
516  Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
517  Oid oldroleid = oldroleform->oid;
518  char *oldrolename = NameStr(oldroleform->rolname);
519 
520  /* can only add this role to roles for which you have rights */
521  check_role_membership_authorization(currentUserId, oldroleid, true);
522  AddRoleMems(currentUserId, oldrolename, oldroleid,
523  thisrole_list,
524  thisrole_oidlist,
525  InvalidOid, &popt);
526 
527  ReleaseSysCache(oldroletup);
528  }
529  }
530 
531  /*
532  * If the current user isn't a superuser, make them an admin of the new
533  * role so that they can administer the new object they just created.
534  * Superusers will be able to do that anyway.
535  *
536  * The grantor of record for this implicit grant is the bootstrap
537  * superuser, which means that the CREATEROLE user cannot revoke the
538  * grant. They can however grant the created role back to themselves with
539  * different options, since they enjoy ADMIN OPTION on it.
540  */
541  if (!superuser())
542  {
543  RoleSpec *current_role = makeNode(RoleSpec);
544  GrantRoleOptions poptself;
545  List *memberSpecs;
546  List *memberIds = list_make1_oid(currentUserId);
547 
548  current_role->roletype = ROLESPEC_CURRENT_ROLE;
549  current_role->location = -1;
550  memberSpecs = list_make1(current_role);
551 
555  poptself.admin = true;
556  poptself.inherit = false;
557  poptself.set = false;
558 
559  AddRoleMems(BOOTSTRAP_SUPERUSERID, stmt->role, roleid,
560  memberSpecs, memberIds,
561  BOOTSTRAP_SUPERUSERID, &poptself);
562 
563  /*
564  * We must make the implicit grant visible to the code below, else the
565  * additional grants will fail.
566  */
568 
569  /*
570  * Because of the implicit grant above, a CREATEROLE user who creates
571  * a role has the ability to grant that role back to themselves with
572  * the INHERIT or SET options, if they wish to inherit the role's
573  * privileges or be able to SET ROLE to it. The createrole_self_grant
574  * GUC can be used to make this happen automatically. This has no
575  * security implications since the same user is able to make the same
576  * grant using an explicit GRANT statement; it's just convenient.
577  */
579  AddRoleMems(currentUserId, stmt->role, roleid,
580  memberSpecs, memberIds,
581  currentUserId, &createrole_self_grant_options);
582  }
583 
584  /*
585  * Add the specified members to this new role. adminmembers get the admin
586  * option, rolemembers don't.
587  *
588  * NB: No permissions check is required here. If you have enough rights to
589  * create a role, you can add any members you like.
590  */
591  AddRoleMems(currentUserId, stmt->role, roleid,
592  rolemembers, roleSpecsToIds(rolemembers),
593  InvalidOid, &popt);
595  popt.admin = true;
596  AddRoleMems(currentUserId, stmt->role, roleid,
597  adminmembers, roleSpecsToIds(adminmembers),
598  InvalidOid, &popt);
599 
600  /* Post creation hook for new role */
601  InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
602 
603  /*
604  * Close pg_authid, but keep lock till commit.
605  */
606  table_close(pg_authid_rel, NoLock);
607 
608  return roleid;
609 }
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5346
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:4174
static void check_role_membership_authorization(Oid currentUserId, Oid roleid, bool is_grant)
Definition: user.c:2117
Oid binary_upgrade_next_pg_authid_oid
Definition: user.c:71
bool IsReservedName(const char *name)
Definition: catalog.c:219
Oid createdb(ParseState *pstate, const CreatedbStmt *stmt)
Definition: dbcommands.c:671
#define WARNING
Definition: elog.h:36
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
bool IsBinaryUpgrade
Definition: globals.c:116
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:176
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
@ ROLESPEC_CSTRING
Definition: parsenodes.h:384
@ ROLESPEC_CURRENT_ROLE
Definition: parsenodes.h:385
@ ROLESTMT_ROLE
Definition: parsenodes.h:2926
@ ROLESTMT_USER
Definition: parsenodes.h:2927
@ ROLESTMT_GROUP
Definition: parsenodes.h:2928
#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
RoleSpecType roletype
Definition: parsenodes.h:394
int location
Definition: parsenodes.h:396
char * rolename
Definition: parsenodes.h:395

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 1985 of file user.c.

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

References Assert(), AUTHMEMROLEMEM, 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 1590 of file user.c.

1591 {
1592  List *role_ids = roleSpecsToIds(stmt->roles);
1593  ListCell *cell;
1594 
1595  /* Check privileges */
1596  foreach(cell, role_ids)
1597  {
1598  Oid roleid = lfirst_oid(cell);
1599 
1600  if (!has_privs_of_role(GetUserId(), roleid))
1601  ereport(ERROR,
1602  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1603  errmsg("permission denied to drop objects"),
1604  errdetail("Only roles with privileges of role \"%s\" may drop objects owned by it.",
1605  GetUserNameFromId(roleid, false))));
1606  }
1607 
1608  /* Ok, do it */
1609  shdepDropOwned(role_ids, stmt->behavior);
1610 }
void shdepDropOwned(List *roleids, DropBehavior behavior)
Definition: pg_shdepend.c:1295

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 1091 of file user.c.

1092 {
1093  Relation pg_authid_rel,
1094  pg_auth_members_rel;
1095  ListCell *item;
1096  List *role_addresses = NIL;
1097 
1099  ereport(ERROR,
1100  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1101  errmsg("permission denied to drop role"),
1102  errdetail("Only roles with the %s attribute and the %s option on the target roles may drop roles.",
1103  "CREATEROLE", "ADMIN")));
1104 
1105  /*
1106  * Scan the pg_authid relation to find the Oid of the role(s) to be
1107  * deleted and perform preliminary permissions and sanity checks.
1108  */
1109  pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
1110  pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1111 
1112  foreach(item, stmt->roles)
1113  {
1114  RoleSpec *rolspec = lfirst(item);
1115  char *role;
1116  HeapTuple tuple,
1117  tmp_tuple;
1118  Form_pg_authid roleform;
1119  ScanKeyData scankey;
1120  SysScanDesc sscan;
1121  Oid roleid;
1122  ObjectAddress *role_address;
1123 
1124  if (rolspec->roletype != ROLESPEC_CSTRING)
1125  ereport(ERROR,
1126  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1127  errmsg("cannot use special role specifier in DROP ROLE")));
1128  role = rolspec->rolename;
1129 
1130  tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
1131  if (!HeapTupleIsValid(tuple))
1132  {
1133  if (!stmt->missing_ok)
1134  {
1135  ereport(ERROR,
1136  (errcode(ERRCODE_UNDEFINED_OBJECT),
1137  errmsg("role \"%s\" does not exist", role)));
1138  }
1139  else
1140  {
1141  ereport(NOTICE,
1142  (errmsg("role \"%s\" does not exist, skipping",
1143  role)));
1144  }
1145 
1146  continue;
1147  }
1148 
1149  roleform = (Form_pg_authid) GETSTRUCT(tuple);
1150  roleid = roleform->oid;
1151 
1152  if (roleid == GetUserId())
1153  ereport(ERROR,
1154  (errcode(ERRCODE_OBJECT_IN_USE),
1155  errmsg("current user cannot be dropped")));
1156  if (roleid == GetOuterUserId())
1157  ereport(ERROR,
1158  (errcode(ERRCODE_OBJECT_IN_USE),
1159  errmsg("current user cannot be dropped")));
1160  if (roleid == GetSessionUserId())
1161  ereport(ERROR,
1162  (errcode(ERRCODE_OBJECT_IN_USE),
1163  errmsg("session user cannot be dropped")));
1164 
1165  /*
1166  * For safety's sake, we allow createrole holders to drop ordinary
1167  * roles but not superuser roles, and only if they also have ADMIN
1168  * OPTION.
1169  */
1170  if (roleform->rolsuper && !superuser())
1171  ereport(ERROR,
1172  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1173  errmsg("permission denied to drop role"),
1174  errdetail("Only roles with the %s attribute may drop roles with the %s attribute.",
1175  "SUPERUSER", "SUPERUSER")));
1176  if (!is_admin_of_role(GetUserId(), roleid))
1177  ereport(ERROR,
1178  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1179  errmsg("permission denied to drop role"),
1180  errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.",
1181  "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
1182 
1183  /* DROP hook for the role being removed */
1184  InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
1185 
1186  /* Don't leak the syscache tuple */
1187  ReleaseSysCache(tuple);
1188 
1189  /*
1190  * Lock the role, so nobody can add dependencies to her while we drop
1191  * her. We keep the lock until the end of transaction.
1192  */
1193  LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
1194 
1195  /*
1196  * If there is a pg_auth_members entry that has one of the roles to be
1197  * dropped as the roleid or member, it should be silently removed, but
1198  * if there is a pg_auth_members entry that has one of the roles to be
1199  * dropped as the grantor, the operation should fail.
1200  *
1201  * It's possible, however, that a single pg_auth_members entry could
1202  * fall into multiple categories - e.g. the user could do "GRANT foo
1203  * TO bar GRANTED BY baz" and then "DROP ROLE baz, bar". We want such
1204  * an operation to succeed regardless of the order in which the
1205  * to-be-dropped roles are passed to DROP ROLE.
1206  *
1207  * To make that work, we remove all pg_auth_members entries that can
1208  * be silently removed in this loop, and then below we'll make a
1209  * second pass over the list of roles to be removed and check for any
1210  * remaining dependencies.
1211  */
1212  ScanKeyInit(&scankey,
1213  Anum_pg_auth_members_roleid,
1214  BTEqualStrategyNumber, F_OIDEQ,
1215  ObjectIdGetDatum(roleid));
1216 
1217  sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
1218  true, NULL, 1, &scankey);
1219 
1220  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1221  {
1222  Form_pg_auth_members authmem_form;
1223 
1224  authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1225  deleteSharedDependencyRecordsFor(AuthMemRelationId,
1226  authmem_form->oid, 0);
1227  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1228  }
1229 
1230  systable_endscan(sscan);
1231 
1232  ScanKeyInit(&scankey,
1233  Anum_pg_auth_members_member,
1234  BTEqualStrategyNumber, F_OIDEQ,
1235  ObjectIdGetDatum(roleid));
1236 
1237  sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
1238  true, NULL, 1, &scankey);
1239 
1240  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1241  {
1242  Form_pg_auth_members authmem_form;
1243 
1244  authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1245  deleteSharedDependencyRecordsFor(AuthMemRelationId,
1246  authmem_form->oid, 0);
1247  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1248  }
1249 
1250  systable_endscan(sscan);
1251 
1252  /*
1253  * Advance command counter so that later iterations of this loop will
1254  * see the changes already made. This is essential if, for example,
1255  * we are trying to drop both a role and one of its direct members ---
1256  * we'll get an error if we try to delete the linking pg_auth_members
1257  * tuple twice. (We do not need a CCI between the two delete loops
1258  * above, because it's not allowed for a role to directly contain
1259  * itself.)
1260  */
1262 
1263  /* Looks tentatively OK, add it to the list. */
1264  role_address = palloc(sizeof(ObjectAddress));
1265  role_address->classId = AuthIdRelationId;
1266  role_address->objectId = roleid;
1267  role_address->objectSubId = 0;
1268  role_addresses = lappend(role_addresses, role_address);
1269  }
1270 
1271  /*
1272  * Second pass over the roles to be removed.
1273  */
1274  foreach(item, role_addresses)
1275  {
1276  ObjectAddress *role_address = lfirst(item);
1277  Oid roleid = role_address->objectId;
1278  HeapTuple tuple;
1279  Form_pg_authid roleform;
1280  char *detail;
1281  char *detail_log;
1282 
1283  /*
1284  * Re-find the pg_authid tuple.
1285  *
1286  * Since we've taken a lock on the role OID, it shouldn't be possible
1287  * for the tuple to have been deleted -- or for that matter updated --
1288  * unless the user is manually modifying the system catalogs.
1289  */
1290  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
1291  if (!HeapTupleIsValid(tuple))
1292  elog(ERROR, "could not find tuple for role %u", roleid);
1293  roleform = (Form_pg_authid) GETSTRUCT(tuple);
1294 
1295  /*
1296  * Check for pg_shdepend entries depending on this role.
1297  *
1298  * This needs to happen after we've completed removing any
1299  * pg_auth_members entries that can be removed silently, in order to
1300  * avoid spurious failures. See notes above for more details.
1301  */
1302  if (checkSharedDependencies(AuthIdRelationId, roleid,
1303  &detail, &detail_log))
1304  ereport(ERROR,
1305  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1306  errmsg("role \"%s\" cannot be dropped because some objects depend on it",
1307  NameStr(roleform->rolname)),
1308  errdetail_internal("%s", detail),
1309  errdetail_log("%s", detail_log)));
1310 
1311  /*
1312  * Remove the role from the pg_authid table
1313  */
1314  CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
1315 
1316  ReleaseSysCache(tuple);
1317 
1318  /*
1319  * Remove any comments or security labels on this role.
1320  */
1321  DeleteSharedComments(roleid, AuthIdRelationId);
1322  DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
1323 
1324  /*
1325  * Remove settings for this role.
1326  */
1327  DropSetting(InvalidOid, roleid);
1328  }
1329 
1330  /*
1331  * Now we can clean up; but keep locks until commit.
1332  */
1333  table_close(pg_auth_members_rel, NoLock);
1334  table_close(pg_authid_rel, NoLock);
1335 }
void DeleteSharedComments(Oid oid, Oid classoid)
Definition: comment.c:374
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1229
int errdetail_log(const char *fmt,...)
Definition: elog.c:1250
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
List * lappend(List *list, void *datum)
Definition: list.c:338
#define AccessExclusiveLock
Definition: lockdefs.h:43
Oid GetOuterUserId(void)
Definition: miscinit.c:519
Oid GetSessionUserId(void)
Definition: miscinit.c:542
#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:631
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, AUTHNAME, AUTHOID, BTEqualStrategyNumber, CatalogTupleDelete(), checkSharedDependencies(), ObjectAddress::classId, 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(), lappend(), lfirst, LockSharedObject(), NameStr, NIL, NoLock, NOTICE, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, palloc(), 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 1487 of file user.c.

1488 {
1489  Relation pg_authid_rel;
1490  Oid grantor;
1491  List *grantee_ids;
1492  ListCell *item;
1493  GrantRoleOptions popt;
1494  Oid currentUserId = GetUserId();
1495 
1496  /* Parse options list. */
1497  InitGrantRoleOptions(&popt);
1498  foreach(item, stmt->opt)
1499  {
1500  DefElem *opt = (DefElem *) lfirst(item);
1501  char *optval = defGetString(opt);
1502 
1503  if (strcmp(opt->defname, "admin") == 0)
1504  {
1506 
1507  if (parse_bool(optval, &popt.admin))
1508  continue;
1509  }
1510  else if (strcmp(opt->defname, "inherit") == 0)
1511  {
1513  if (parse_bool(optval, &popt.inherit))
1514  continue;
1515  }
1516  else if (strcmp(opt->defname, "set") == 0)
1517  {
1519  if (parse_bool(optval, &popt.set))
1520  continue;
1521  }
1522  else
1523  ereport(ERROR,
1524  errcode(ERRCODE_SYNTAX_ERROR),
1525  errmsg("unrecognized role option \"%s\"", opt->defname),
1526  parser_errposition(pstate, opt->location));
1527 
1528  ereport(ERROR,
1529  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1530  errmsg("unrecognized value for role option \"%s\": \"%s\"",
1531  opt->defname, optval),
1532  parser_errposition(pstate, opt->location)));
1533  }
1534 
1535  /* Lookup OID of grantor, if specified. */
1536  if (stmt->grantor)
1537  grantor = get_rolespec_oid(stmt->grantor, false);
1538  else
1539  grantor = InvalidOid;
1540 
1541  grantee_ids = roleSpecsToIds(stmt->grantee_roles);
1542 
1543  /* AccessShareLock is enough since we aren't modifying pg_authid */
1544  pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock);
1545 
1546  /*
1547  * Step through all of the granted roles and add, update, or remove
1548  * entries in pg_auth_members as appropriate. If stmt->is_grant is true,
1549  * we are adding new grants or, if they already exist, updating options on
1550  * those grants. If stmt->is_grant is false, we are revoking grants or
1551  * removing options from them.
1552  */
1553  foreach(item, stmt->granted_roles)
1554  {
1555  AccessPriv *priv = (AccessPriv *) lfirst(item);
1556  char *rolename = priv->priv_name;
1557  Oid roleid;
1558 
1559  /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1560  if (rolename == NULL || priv->cols != NIL)
1561  ereport(ERROR,
1562  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1563  errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1564 
1565  roleid = get_role_oid(rolename, false);
1567  roleid, stmt->is_grant);
1568  if (stmt->is_grant)
1569  AddRoleMems(currentUserId, rolename, roleid,
1570  stmt->grantee_roles, grantee_ids,
1571  grantor, &popt);
1572  else
1573  DelRoleMems(currentUserId, rolename, roleid,
1574  stmt->grantee_roles, grantee_ids,
1575  grantor, &popt, stmt->behavior);
1576  }
1577 
1578  /*
1579  * Close pg_authid, but keep lock till commit.
1580  */
1581  table_close(pg_authid_rel, NoLock);
1582 }
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5380
bool parse_bool(const char *value, bool *result)
Definition: bool.c:30
char * defGetString(DefElem *def)
Definition: define.c:49
#define AccessShareLock
Definition: lockdefs.h:36
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
char * priv_name
Definition: parsenodes.h:2380
List * cols
Definition: parsenodes.h:2381
int location
Definition: parsenodes.h:806

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 123 of file user.c.

124 {
126 }

References GetUserId(), and has_createrole_privilege().

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

◆ InitGrantRoleOptions()

static void InitGrantRoleOptions ( GrantRoleOptions popt)
static

Definition at line 2510 of file user.c.

2511 {
2512  popt->specified = 0;
2513  popt->admin = false;
2514  popt->inherit = false;
2515  popt->set = true;
2516 }

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 2295 of file user.c.

2296 {
2297  RevokeRoleGrantAction *result;
2298  int i;
2299 
2300  if (memlist->n_members == 0)
2301  return NULL;
2302 
2303  result = palloc(sizeof(RevokeRoleGrantAction) * memlist->n_members);
2304  for (i = 0; i < memlist->n_members; i++)
2305  result[i] = RRG_NOOP;
2306  return result;
2307 }

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 2396 of file user.c.

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

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 2420 of file user.c.

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

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

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 1618 of file user.c.

1619 {
1620  List *role_ids = roleSpecsToIds(stmt->roles);
1621  ListCell *cell;
1622  Oid newrole;
1623 
1624  /* Check privileges */
1625  foreach(cell, role_ids)
1626  {
1627  Oid roleid = lfirst_oid(cell);
1628 
1629  if (!has_privs_of_role(GetUserId(), roleid))
1630  ereport(ERROR,
1631  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1632  errmsg("permission denied to reassign objects"),
1633  errdetail("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
1634  GetUserNameFromId(roleid, false))));
1635  }
1636 
1637  /* Must have privileges on the receiving side too */
1638  newrole = get_rolespec_oid(stmt->newrole, false);
1639 
1640  if (!has_privs_of_role(GetUserId(), newrole))
1641  ereport(ERROR,
1642  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1643  errmsg("permission denied to reassign objects"),
1644  errdetail("Only roles with privileges of role \"%s\" may reassign objects to it.",
1645  GetUserNameFromId(newrole, false))));
1646 
1647  /* Ok, do it */
1648  shdepReassignOwned(role_ids, newrole);
1649 }
void shdepReassignOwned(List *roleids, Oid newrole)
Definition: pg_shdepend.c:1468

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 1341 of file user.c.

1342 {
1343  HeapTuple oldtuple,
1344  newtuple;
1345  TupleDesc dsc;
1346  Relation rel;
1347  Datum datum;
1348  bool isnull;
1349  Datum repl_val[Natts_pg_authid];
1350  bool repl_null[Natts_pg_authid];
1351  bool repl_repl[Natts_pg_authid];
1352  int i;
1353  Oid roleid;
1354  ObjectAddress address;
1355  Form_pg_authid authform;
1356 
1357  rel = table_open(AuthIdRelationId, RowExclusiveLock);
1358  dsc = RelationGetDescr(rel);
1359 
1360  oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1361  if (!HeapTupleIsValid(oldtuple))
1362  ereport(ERROR,
1363  (errcode(ERRCODE_UNDEFINED_OBJECT),
1364  errmsg("role \"%s\" does not exist", oldname)));
1365 
1366  /*
1367  * XXX Client applications probably store the session user somewhere, so
1368  * renaming it could cause confusion. On the other hand, there may not be
1369  * an actual problem besides a little confusion, so think about this and
1370  * decide. Same for SET ROLE ... we don't restrict renaming the current
1371  * effective userid, though.
1372  */
1373 
1374  authform = (Form_pg_authid) GETSTRUCT(oldtuple);
1375  roleid = authform->oid;
1376 
1377  if (roleid == GetSessionUserId())
1378  ereport(ERROR,
1379  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1380  errmsg("session user cannot be renamed")));
1381  if (roleid == GetOuterUserId())
1382  ereport(ERROR,
1383  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1384  errmsg("current user cannot be renamed")));
1385 
1386  /*
1387  * Check that the user is not trying to rename a system role and not
1388  * trying to rename a role into the reserved "pg_" namespace.
1389  */
1390  if (IsReservedName(NameStr(authform->rolname)))
1391  ereport(ERROR,
1392  (errcode(ERRCODE_RESERVED_NAME),
1393  errmsg("role name \"%s\" is reserved",
1394  NameStr(authform->rolname)),
1395  errdetail("Role names starting with \"pg_\" are reserved.")));
1396 
1397  if (IsReservedName(newname))
1398  ereport(ERROR,
1399  (errcode(ERRCODE_RESERVED_NAME),
1400  errmsg("role name \"%s\" is reserved",
1401  newname),
1402  errdetail("Role names starting with \"pg_\" are reserved.")));
1403 
1404  /*
1405  * If built with appropriate switch, whine when regression-testing
1406  * conventions for role names are violated.
1407  */
1408 #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
1409  if (strncmp(newname, "regress_", 8) != 0)
1410  elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
1411 #endif
1412 
1413  /* make sure the new name doesn't exist */
1415  ereport(ERROR,
1417  errmsg("role \"%s\" already exists", newname)));
1418 
1419  /*
1420  * Only superusers can mess with superusers. Otherwise, a user with
1421  * CREATEROLE can rename a role for which they have ADMIN OPTION.
1422  */
1423  if (authform->rolsuper)
1424  {
1425  if (!superuser())
1426  ereport(ERROR,
1427  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1428  errmsg("permission denied to rename role"),
1429  errdetail("Only roles with the %s attribute may rename roles with the %s attribute.",
1430  "SUPERUSER", "SUPERUSER")));
1431  }
1432  else
1433  {
1434  if (!have_createrole_privilege() ||
1435  !is_admin_of_role(GetUserId(), roleid))
1436  ereport(ERROR,
1437  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1438  errmsg("permission denied to rename role"),
1439  errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.",
1440  "CREATEROLE", "ADMIN", NameStr(authform->rolname))));
1441  }
1442 
1443  /* OK, construct the modified tuple */
1444  for (i = 0; i < Natts_pg_authid; i++)
1445  repl_repl[i] = false;
1446 
1447  repl_repl[Anum_pg_authid_rolname - 1] = true;
1448  repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1449  CStringGetDatum(newname));
1450  repl_null[Anum_pg_authid_rolname - 1] = false;
1451 
1452  datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1453 
1454  if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
1455  {
1456  /* MD5 uses the username as salt, so just clear it on a rename */
1457  repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1458  repl_null[Anum_pg_authid_rolpassword - 1] = true;
1459 
1460  ereport(NOTICE,
1461  (errmsg("MD5 password cleared because of role rename")));
1462  }
1463 
1464  newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1465  CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
1466 
1467  InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
1468 
1469  ObjectAddressSet(address, AuthIdRelationId, roleid);
1470 
1471  ReleaseSysCache(oldtuple);
1472 
1473  /*
1474  * Close pg_authid, but keep lock till commit.
1475  */
1476  table_close(rel, NoLock);
1477 
1478  return address;
1479 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
@ 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:191

References AUTHNAME, 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 1659 of file user.c.

1660 {
1661  List *result = NIL;
1662  ListCell *l;
1663 
1664  foreach(l, memberNames)
1665  {
1666  RoleSpec *rolespec = lfirst_node(RoleSpec, l);
1667  Oid roleid;
1668 
1669  roleid = get_rolespec_oid(rolespec, false);
1670  result = lappend_oid(result, roleid);
1671  }
1672  return result;
1673 }
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374

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 71 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 92 of file user.c.

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

◆ createrole_self_grant

char* createrole_self_grant = ""

Definition at line 87 of file user.c.

◆ createrole_self_grant_enabled

bool createrole_self_grant_enabled = false

Definition at line 88 of file user.c.

Referenced by assign_createrole_self_grant(), and CreateRole().

◆ createrole_self_grant_options

GrantRoleOptions createrole_self_grant_options

Definition at line 89 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 86 of file user.c.

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