/* 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.
Angebot
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.