/* Hook to check passwords in CreateRole() and AlterRole() */
check_password_hook_type check_password_hook = NULL;
staticvoid AddRoleMems(Oid currentUserId, constchar *rolename, Oid roleid,
List *memberSpecs, List *memberIds,
Oid grantorId, GrantRoleOptions *popt); staticvoid DelRoleMems(Oid currentUserId, constchar *rolename, Oid roleid,
List *memberSpecs, List *memberIds,
Oid grantorId, GrantRoleOptions *popt,
DropBehavior behavior); staticvoid 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 RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist); staticbool plan_single_revoke(CatCList *memlist,
RevokeRoleGrantAction *actions,
Oid member, Oid grantor,
GrantRoleOptions *popt,
DropBehavior behavior); staticvoid plan_member_revoke(CatCList *memlist,
RevokeRoleGrantAction *actions, Oid member); staticvoid plan_recursive_revoke(CatCList *memlist,
RevokeRoleGrantAction *actions, int index, bool revoke_admin_option_only,
DropBehavior behavior); staticvoid InitGrantRoleOptions(GrantRoleOptions *popt);
/* Check if current user has createrole privileges */ staticbool
have_createrole_privilege(void)
{ return has_createrole_privilege(GetUserId());
}
/* *CREATEROLE
*/
Oid
CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
{
Relation pg_authid_rel;
TupleDesc pg_authid_dsc;
HeapTuple tuple;
Datum new_record[Natts_pg_authid] = {0}; bool new_record_nulls[Natts_pg_authid] = {0};
Oid currentUserId = GetUserId();
Oid roleid;
ListCell *item;
ListCell *option; char *password = NULL; /* user password */ bool issuper = false; /* Make the user a superuser? */ bool inherit = true; /* Auto inherit privileges? */ bool createrole = false; /* Can this user create roles? */ bool createdb = false; /* Can the user create databases? */ bool canlogin = false; /* Can this user login? */ bool isreplication = false; /* Is this a replication role? */ bool bypassrls = false; /* Is this a row security enabled role? */ int connlimit = -1; /* maximum connections allowed */
List *addroleto = NIL; /* roles to make this a member of */
List *rolemembers = NIL; /* roles to be members of this role */
List *adminmembers = NIL; /* roles to be admins of this role */ char *validUntil = NULL; /* time the login is valid until */
Datum validUntil_datum; /* same, as timestamptz Datum */ bool validUntil_null;
DefElem *dpassword = NULL;
DefElem *dissuper = NULL;
DefElem *dinherit = NULL;
DefElem *dcreaterole = NULL;
DefElem *dcreatedb = NULL;
DefElem *dcanlogin = NULL;
DefElem *disreplication = NULL;
DefElem *dconnlimit = NULL;
DefElem *daddroleto = NULL;
DefElem *drolemembers = NULL;
DefElem *dadminmembers = NULL;
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
GrantRoleOptions popt;
/* The defaults can vary depending on the original statement type */ switch (stmt->stmt_type)
{ case ROLESTMT_ROLE: break; case ROLESTMT_USER:
canlogin = true; /* may eventually want inherit to default to false here */ break; case ROLESTMT_GROUP: break;
}
/* Extract options from the statement node tree */
foreach(option, stmt->options)
{
DefElem *defel = (DefElem *) lfirst(option);
if (dpassword && dpassword->arg)
password = strVal(dpassword->arg); if (dissuper)
issuper = boolVal(dissuper->arg); if (dinherit)
inherit = boolVal(dinherit->arg); if (dcreaterole)
createrole = boolVal(dcreaterole->arg); if (dcreatedb)
createdb = boolVal(dcreatedb->arg); if (dcanlogin)
canlogin = boolVal(dcanlogin->arg); if (disreplication)
isreplication = boolVal(disreplication->arg); if (dconnlimit)
{
connlimit = intVal(dconnlimit->arg); if (connlimit < -1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid connection limit: %d", connlimit)));
} if (daddroleto)
addroleto = (List *) daddroleto->arg; if (drolemembers)
rolemembers = (List *) drolemembers->arg; if (dadminmembers)
adminmembers = (List *) dadminmembers->arg; if (dvalidUntil)
validUntil = strVal(dvalidUntil->arg); if (dbypassRLS)
bypassrls = boolVal(dbypassRLS->arg);
/* Check some permissions first */ if (!superuser_arg(currentUserId))
{ if (!has_createrole_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role"),
errdetail("Only roles with the %s attribute may create roles.", "CREATEROLE"))); if (issuper)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role"),
errdetail("Only roles with the %s attribute may create roles with the %s attribute.", "SUPERUSER", "SUPERUSER"))); if (createdb && !have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role"),
errdetail("Only roles with the %s attribute may create roles with the %s attribute.", "CREATEDB", "CREATEDB"))); if (isreplication && !has_rolreplication(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role"),
errdetail("Only roles with the %s attribute may create roles with the %s attribute.", "REPLICATION", "REPLICATION"))); if (bypassrls && !has_bypassrls_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role"),
errdetail("Only roles with the %s attribute may create roles with the %s attribute.", "BYPASSRLS", "BYPASSRLS")));
}
/* *Checkthattheuserisnottryingtocreatearoleinthereserved *"pg_"namespace.
*/ if (IsReservedName(stmt->role))
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
errmsg("role name \"%s\" is reserved",
stmt->role),
errdetail("Role names starting with \"pg_\" are reserved.")));
/* *Ifbuiltwithappropriateswitch,whinewhenregression-testing *conventionsforrolenamesareviolated.
*/ #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS if (strncmp(stmt->role, "regress_", 8) != 0)
elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\""); #endif
/* *pg_largeobject_metadatacontainspg_authid.oid's,soweusethe *binary-upgradeoverride.
*/ if (IsBinaryUpgrade)
{ if (!OidIsValid(binary_upgrade_next_pg_authid_oid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("pg_authid OID value not set when in binary upgrade mode")));
/* can only add this role to roles for which you have rights */
check_role_membership_authorization(currentUserId, oldroleid, true);
AddRoleMems(currentUserId, oldrolename, oldroleid,
thisrole_list,
thisrole_oidlist,
InvalidOid, &popt);
ReleaseSysCache(oldroletup);
}
}
/* *Ifthecurrentuserisn'tasuperuser,makethemanadminofthenew *rolesothattheycanadministerthenewobjecttheyjustcreated. *Superuserswillbeabletodothatanyway. * *Thegrantorofrecordforthisimplicitgrantisthebootstrap *superuser,whichmeansthattheCREATEROLEusercannotrevokethe *grant.Theycanhowevergrantthecreatedrolebacktothemselveswith *differentoptions,sincetheyenjoyADMINOPTIONonit.
*/ if (!superuser())
{
RoleSpec *current_role = makeNode(RoleSpec);
GrantRoleOptions poptself;
List *memberSpecs;
List *memberIds = list_make1_oid(currentUserId);
/* To mess with a superuser in any way you gotta be superuser. */ if (!superuser() && authform->rolsuper)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may alter roles with the %s attribute.", "SUPERUSER", "SUPERUSER"))); if (!superuser() && dissuper)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may change the %s attribute.", "SUPERUSER", "SUPERUSER")));
/* *MostchangestoarolerequirethatyoubothhaveCREATEROLEprivileges *andalsoADMINOPTIONontherole.
*/ if (!have_createrole_privilege() ||
!is_admin_of_role(GetUserId(), roleid))
{ /* things an unprivileged user certainly can't do */ if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
dvalidUntil || disreplication || dbypassRLS)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.", "CREATEROLE", "ADMIN", rolename)));
/* an unprivileged user can change their own password */ if (dpassword && roleid != currentUserId)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("To change another role's password, the current user must have the %s attribute and the %s option on the role.", "CREATEROLE", "ADMIN")));
} elseif (!superuser())
{ /* *EvenifyouhavebothCREATEROLEandADMINOPTIONonarole,you *canonlychangetheCREATEDB,REPLICATION,orBYPASSRLSattributes *iftheyaresetforyourownrole(oryouarethesuperuser).
*/ if (dcreatedb && !have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may change the %s attribute.", "CREATEDB", "CREATEDB"))); if (disreplication && !has_rolreplication(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may change the %s attribute.", "REPLICATION", "REPLICATION"))); if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may change the %s attribute.", "BYPASSRLS", "BYPASSRLS")));
}
/* To add or drop members, you need ADMIN OPTION. */ if (drolemembers && !is_admin_of_role(currentUserId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s option on role \"%s\" may add or drop members.", "ADMIN", rolename)));
/* Convert validuntil to internal form */ if (dvalidUntil)
{
validUntil_datum = DirectFunctionCall3(timestamptz_in,
CStringGetDatum(validUntil),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
validUntil_null = false;
} else
{ /* fetch existing setting in case hook needs it */
validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
Anum_pg_authid_rolvaliduntil,
&validUntil_null);
}
/* *issuper/createrole/etc
*/ if (dissuper)
{ bool should_be_super = boolVal(dissuper->arg);
if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("permission denied to alter role"),
errdetail("The bootstrap superuser must have the %s attribute.", "SUPERUSER")));
/* *Advancecommandcountersowecanseenewrecord;elsetestsin *AddRoleMemsmayfail.
*/ if (drolemembers)
{
List *rolemembers = (List *) drolemembers->arg;
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
AddRoleMems(currentUserId, rolename, roleid,
rolemembers, roleSpecsToIds(rolemembers),
InvalidOid, &popt); elseif (stmt->action == -1) /* drop members from role */
DelRoleMems(currentUserId, rolename, roleid,
rolemembers, roleSpecsToIds(rolemembers),
InvalidOid, &popt, DROP_RESTRICT);
}
/* *Tomesswithasuperuseryougottabesuperuser;otherwiseyouneed *CREATEROLEplusadminoptiononthetargetrole;unlessyou'rejust *tryingtochangeyourownsettings
*/ if (roleform->rolsuper)
{ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute may alter roles with the %s attribute.", "SUPERUSER", "SUPERUSER")));
} else
{ if ((!have_createrole_privilege() ||
!is_admin_of_role(GetUserId(), roleid))
&& roleid != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter role"),
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.", "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
}
ReleaseSysCache(roletuple);
}
/* look up and lock the database, if specified */ if (stmt->database != NULL)
{
databaseid = get_database_oid(stmt->database, false);
shdepLockAndCheckObject(DatabaseRelationId, databaseid);
if (!stmt->role)
{ /* *Ifnoroleisspecified,thenthisiseffectivelythesameas *ALTERDATABASE...SET,sousethesamepermissioncheck.
*/ if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
stmt->database);
}
}
if (!stmt->role && !stmt->database)
{ /* Must be superuser to alter settings globally. */ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter setting"),
errdetail("Only roles with the %s attribute may alter settings globally.", "SUPERUSER")));
}
if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role"),
errdetail("Only roles with the %s attribute and the %s option on the target roles may drop roles.", "CREATEROLE", "ADMIN")));
if (rolspec->roletype != ROLESPEC_CSTRING)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot use special role specifier in DROP ROLE")));
role = rolspec->rolename;
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role)); if (!HeapTupleIsValid(tuple))
{ if (!stmt->missing_ok)
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", role)));
} else
{
ereport(NOTICE,
(errmsg("role \"%s\" does not exist, skipping",
role)));
}
if (roleid == GetUserId())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("current user cannot be dropped"))); if (roleid == GetOuterUserId())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("current user cannot be dropped"))); if (roleid == GetSessionUserId())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("session user cannot be dropped")));
/* *Forsafety'ssake,weallowcreateroleholderstodropordinary *rolesbutnotsuperuserroles,andonlyiftheyalsohaveADMIN *OPTION.
*/ if (roleform->rolsuper && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role"),
errdetail("Only roles with the %s attribute may drop roles with the %s attribute.", "SUPERUSER", "SUPERUSER"))); if (!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role"),
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.", "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
/* DROP hook for the role being removed */
InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
/* Don't leak the syscache tuple */
ReleaseSysCache(tuple);
oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname)); if (!HeapTupleIsValid(oldtuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", oldname)));
if (roleid == GetSessionUserId())
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("session user cannot be renamed"))); if (roleid == GetOuterUserId())
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("current user cannot be renamed")));
/* *Checkthattheuserisnottryingtorenameasystemroleandnot *tryingtorenamearoleintothereserved"pg_"namespace.
*/ if (IsReservedName(NameStr(authform->rolname)))
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
errmsg("role name \"%s\" is reserved",
NameStr(authform->rolname)),
errdetail("Role names starting with \"pg_\" are reserved.")));
if (IsReservedName(newname))
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
errmsg("role name \"%s\" is reserved",
newname),
errdetail("Role names starting with \"pg_\" are reserved.")));
/* *Ifbuiltwithappropriateswitch,whinewhenregression-testing *conventionsforrolenamesareviolated.
*/ #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS if (strncmp(newname, "regress_", 8) != 0)
elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\""); #endif
/* make sure the new name doesn't exist */ if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role \"%s\" already exists", newname)));
/* *Onlysuperuserscanmesswithsuperusers.Otherwise,auserwith *CREATEROLEcanrenamearoleforwhichtheyhaveADMINOPTION.
*/ if (authform->rolsuper)
{ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role"),
errdetail("Only roles with the %s attribute may rename roles with the %s attribute.", "SUPERUSER", "SUPERUSER")));
} else
{ if (!have_createrole_privilege() ||
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role"),
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.", "CREATEROLE", "ADMIN", NameStr(authform->rolname))));
}
/* OK, construct the modified tuple */ for (i = 0; i < Natts_pg_authid; i++)
repl_repl[i] = false;
datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
{ /* MD5 uses the username as salt, so just clear it on a rename */
repl_repl[Anum_pg_authid_rolpassword - 1] = true;
repl_null[Anum_pg_authid_rolpassword - 1] = true;
ereport(NOTICE,
(errmsg("MD5 password cleared because of role rename")));
}
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized value for role option \"%s\": \"%s\"",
opt->defname, optval),
parser_errposition(pstate, opt->location)));
}
/* Lookup OID of grantor, if specified. */ if (stmt->grantor)
grantor = get_rolespec_oid(stmt->grantor, false); else
grantor = InvalidOid;
/* Must reject priv(columns) and ALL PRIVILEGES(columns) */ if (rolename == NULL || priv->cols != NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
if (!has_privs_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop objects"),
errdetail("Only roles with privileges of role \"%s\" may drop objects owned by it.",
GetUserNameFromId(roleid, false))));
}
/* Ok, do it */
shdepDropOwned(role_ids, stmt->behavior);
}
/* *ReassignOwnedObjects * *Givetheobjectsownedbyagivenlistofrolesawaytoanotheruser.
*/ void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
if (!has_privs_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to reassign objects"),
errdetail("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
GetUserNameFromId(roleid, false))));
}
/* Must have privileges on the receiving side too */
newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to reassign objects"),
errdetail("Only roles with privileges of role \"%s\" may reassign objects to it.",
GetUserNameFromId(newrole, false))));
/* Ok, do it */
shdepReassignOwned(role_ids, newrole);
}
/* *roleSpecsToIds * *GivenalistofRoleSpecs,generatealistofroleOIDsinthesameorder. * *ROLESPEC_PUBLICisnotallowed.
*/
List *
roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
RoleSpec *rolespec = lfirst_node(RoleSpec, l);
Oid roleid;
/* *pg_database_ownerisneverarolemember.Liftingthisrestriction *wouldrequireapolicydecisionaboutmembershiploops.Onecould *preventloops,whichwouldincludemaking"ALTERDATABASExOWNER *TOproposed_datdba"failifis_member_of_role(pg_database_owner, *proposed_datdba).Hence,gainingamembershipcouldreducewhata *rolecoulddo.Alternately,onecouldallowthesemembershipsto *completeloops.ArolecouldthenhaveactualWITHADMINOPTIONon *itself,promptingadecisionaboutis_admin_of_role()treatmentof *thecase. * *Liftingthisrestrictionalsohaspolicyimplicationsforownership *ofsharedobjects(databasesandtablespaces).Weallowsuch *ownership,butwemightfindcausetobanitinthefuture. *Designingsuchabanwouldmoretroublesomeifthedesignhadto *addresspg_database_ownerbeingamemberofroleFOOthatownsa *sharedobject.(Theeffectofsuchownershipisthatanyownerof *anotherdatabasecanactastheownerofaffectedsharedobjects.)
*/ if (memberid == ROLE_PG_DATABASE_OWNER)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("role \"%s\" cannot be a member of any role",
get_rolespec_name(memberRole)));
/* *Refusecreationofmembershiploops,includingthetrivialcase *wherearoleismadeamemberofitself.Wedothisbycheckingto *seeifthetargetroleisalreadyamemberoftheproposedmember *role.Wehavetoignorepossiblesuperuserness,however,elsewe *couldnevergrantmembershipinasuperuser-privilegedrole.
*/ if (is_member_of_role_nosuper(roleid, memberid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("role \"%s\" is a member of role \"%s\"",
rolename, get_rolespec_name(memberRole))));
}
if (memberid == BOOTSTRAP_SUPERUSERID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("%s option cannot be granted back to your own grantor", "ADMIN")));
plan_member_revoke(memlist, actions, memberid);
}
/* *Iftheresultwouldbethatthegrantorrolewouldnolongerhave *theabilitytoperformthegrant,thentheproposedgrantwould *createacircularity.
*/ for (i = 0; i < memlist->n_members; ++i)
{
HeapTuple authmem_tuple;
Form_pg_auth_members authmem_form;
if (actions[i] == RRG_NOOP &&
authmem_form->member == grantorId &&
authmem_form->admin_option) break;
} if (i >= memlist->n_members)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("%s option cannot be granted back to your own grantor", "ADMIN")));
ReleaseSysCacheList(memlist);
}
/* Now perform the catalog updates. */
forboth(specitem, memberSpecs, iditem, memberIds)
{
RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
Oid memberid = lfirst_oid(iditem);
HeapTuple authmem_tuple;
HeapTuple tuple;
Datum new_record[Natts_pg_auth_members] = {0}; bool new_record_nulls[Natts_pg_auth_members] = {0}; bool new_record_repl[Natts_pg_auth_members] = {0};
/* Common initialization for possible insert or update */
new_record[Anum_pg_auth_members_roleid - 1] =
ObjectIdGetDatum(roleid);
new_record[Anum_pg_auth_members_member - 1] =
ObjectIdGetDatum(memberid);
new_record[Anum_pg_auth_members_grantor - 1] =
ObjectIdGetDatum(grantorId);
if (!at_least_one_change)
{
ereport(NOTICE,
(errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
get_rolespec_name(memberRole), rolename,
GetUserNameFromId(grantorId, false))));
ReleaseSysCache(authmem_tuple); continue;
}
mrtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(memberid)); if (!HeapTupleIsValid(mrtup))
elog(ERROR, "cache lookup failed for role %u", memberid);
mrform = (Form_pg_authid) GETSTRUCT(mrtup);
new_record[Anum_pg_auth_members_inherit_option - 1] =
mrform->rolinherit;
ReleaseSysCache(mrtup);
}
/* get an OID for the new row and insert it */
objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
Anum_pg_auth_members_oid);
new_record[Anum_pg_auth_members_oid - 1] = objectId;
tuple = heap_form_tuple(pg_authmem_dsc,
new_record, new_record_nulls);
CatalogTupleInsert(pg_authmem_rel, tuple);
if (!plan_single_revoke(memlist, actions, memberid, grantorId,
popt, behavior))
{
ereport(WARNING,
(errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"",
get_rolespec_name(memberRole), rolename,
GetUserNameFromId(grantorId, false)))); continue;
}
}
/* *Wenowknowwhattodowitheachcatalogtuple:itshouldeitherbe *leftalone,deleted,orjusthavetheadmin_optionflagcleared. *Performtheappropriateactionineachcase.
*/ for (i = 0; i < memlist->n_members; ++i)
{
HeapTuple authmem_tuple;
Form_pg_auth_members authmem_form;
/* To mess with a superuser role, you gotta be superuser. */ if (superuser_arg(roleid))
{ if (!superuser_arg(currentUserId))
{ if (is_grant)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to grant role \"%s\"",
GetUserNameFromId(roleid, false)),
errdetail("Only roles with the %s attribute may grant roles with the %s attribute.", "SUPERUSER", "SUPERUSER"))); else
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to revoke role \"%s\"",
GetUserNameFromId(roleid, false)),
errdetail("Only roles with the %s attribute may revoke roles with the %s attribute.", "SUPERUSER", "SUPERUSER")));
}
} else
{ /* *Otherwise,musthaveadminoptionontheroletobechanged.
*/ if (!is_admin_of_role(currentUserId, roleid))
{ if (is_grant)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to grant role \"%s\"",
GetUserNameFromId(roleid, false)),
errdetail("Only roles with the %s option on role \"%s\" may grant this role.", "ADMIN", GetUserNameFromId(roleid, false)))); else
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to revoke role \"%s\"",
GetUserNameFromId(roleid, false)),
errdetail("Only roles with the %s option on role \"%s\" may revoke this role.", "ADMIN", GetUserNameFromId(roleid, false))));
}
}
}
/* *Sanity-check,orinfer,thegrantorforaGRANTorREVOKEstatement *targetingarole. * *ThegrantormustalwaysbeeitherarolewithADMINOPTIONontherolein *whichmembershipisbeinggranted,orthebootstrapsuperuser.Thisis *similartotherestrictionenforcedbyselect_best_grantor,exceptthat *rolesdon'thaveowners,soweregardthebootstrapsuperuserasthe *implicitowner. * *Ifthegrantorwasnotexplicitlyspecifiedbytheuser,grantorIdshould *bepassedasInvalidOid,andthisfunctionwillinfertheusertobe *recordedasthegrantor.Inmanycases,thiswillbethecurrentuser,but *thingsgetmorecomplicatedwhenthecurrentuserdoesn'tpossessADMIN *OPTIONontherolebutratherreliesonhavingSUPERUSERprivileges,or *oninheritingtheprivilegesofarolewhichdoeshaveADMINOPTION.See *belowfordetails. * *Ifthegrantorwasspecifiedbytheuser,thenitmustbeauserthat *canlegallyberecordedasthegrantor,aspertherulestatedabove. *Thisisanintegrityconstraint,notapermissionscheck,andthuseven *superusersaresubjecttothisrestriction.However,thereisalsoa *permissionscheck:tospecifyaroleasthegrantor,thecurrentuser *mustpossesstheprivilegesofthatrole.Superuserswillalwayspass *thischeck,butfornon-superusersitmayleadtoanerror. * *ThereturnvalueistheOIDtoberegardedasthegrantorwhenexecuting *theoperation.
*/ static Oid
check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
{ /* If the grantor ID was not specified, pick one to use. */ if (!OidIsValid(grantorId))
{ /* *Grantswherethegrantorisrecordedasthebootstrapsuperuserdo *notdependonanyotherexistinggrants,soalwaysdefaulttothis *interpretationwhenpossible.
*/ if (superuser_arg(currentUserId)) return BOOTSTRAP_SUPERUSERID;
/* *Otherwise,thegrantormusteitherhaveADMINOPTIONontheroleor *inherittheprivilegesofarolewhichdoes.Intheformercase, *recordthegrantorasthecurrentuser;inthelatter,pickoneof *therolesthatis"mostdirectly"inheritedbythecurrentrole *(i.e.fewest"hops"). * *(Weshouldn'tfailtofindabestgrantor,becausewe'vealready *establishedthatthecurrentuserhaspermissiontoperformthe *operation.)
*/
grantorId = select_best_admin(currentUserId, roleid); if (!OidIsValid(grantorId))
elog(ERROR, "no possible grantors"); return grantorId;
}
/* *Ifanexplicitgrantorisspecified,itmustbearolewhoseprivileges *thecurrentuserpossesses. * *ItshouldalsobearolethathasADMINOPTIONonthetargetrole,but *wecheckthisconditiononlyincaseofGRANT.ForREVOKE,nomatching *grantshouldexistanyway,butifitsomehowdoes,lettheusergetrid *ofit.
*/ if (is_grant)
{ if (!has_privs_of_role(currentUserId, grantorId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to grant privileges as role \"%s\"",
GetUserNameFromId(grantorId, false)),
errdetail("Only roles with privileges of role \"%s\" may grant privileges as this role.",
GetUserNameFromId(grantorId, false))));
if (grantorId != BOOTSTRAP_SUPERUSERID &&
select_best_admin(grantorId, roleid) != grantorId)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to grant privileges as role \"%s\"",
GetUserNameFromId(grantorId, false)),
errdetail("The grantor must have the %s option on role \"%s\".", "ADMIN", GetUserNameFromId(roleid, false))));
} else
{ if (!has_privs_of_role(currentUserId, grantorId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to revoke privileges granted by role \"%s\"",
GetUserNameFromId(grantorId, false)),
errdetail("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
GetUserNameFromId(grantorId, false))));
}
/* If it's already been done, we can just return. */ if (actions[index] == RRG_DELETE_GRANT) return; if (actions[index] == RRG_REMOVE_ADMIN_OPTION &&
revoke_admin_option_only) return;
/* *Iftheexistingtupledoesnothaveadmin_optionset,thenwedonot *needtorecurse.Ifwe'rejustsupposedtoclearthatbitwedon'tneed *todoanythingatall;ifwe'resupposedtoremovethegrant,weneed *todosomething,butonlytothetuple,andnotanyothers.
*/ if (!revoke_admin_option_only)
{
actions[index] = RRG_DELETE_GRANT; if (!authmem_form->admin_option) return;
} else
{ if (!authmem_form->admin_option) return;
actions[index] = RRG_REMOVE_ADMIN_OPTION;
}
/* Determine whether the member would still have ADMIN OPTION. */ for (i = 0; i < memlist->n_members; ++i)
{
HeapTuple am_cascade_tuple;
Form_pg_auth_members am_cascade_form;
/* Need a modifiable copy of string */
rawstring = pstrdup(*newval);
if (!SplitIdentifierString(rawstring, ',', &elemlist))
{ /* syntax error in list */
GUC_check_errdetail("List syntax is invalid.");
pfree(rawstring);
list_free(elemlist); returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.