diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/transam/xact.c | 68 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 26 | ||||
-rw-r--r-- | src/backend/commands/analyze.c | 31 | ||||
-rw-r--r-- | src/backend/commands/schemacmds.c | 13 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 15 | ||||
-rw-r--r-- | src/backend/commands/variable.c | 35 | ||||
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 20 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 43 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 77 | ||||
-rw-r--r-- | src/include/miscadmin.h | 7 |
10 files changed, 216 insertions, 119 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 4409f611e95..4cebea05c0f 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.255 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.256 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -123,7 +123,8 @@ typedef struct TransactionStateData MemoryContext curTransactionContext; /* my xact-lifetime context */ ResourceOwner curTransactionOwner; /* my query resources */ List *childXids; /* subcommitted child XIDs */ - Oid currentUser; /* subxact start current_user */ + Oid prevUser; /* previous CurrentUserId setting */ + bool prevSecDefCxt; /* previous SecurityDefinerContext setting */ bool prevXactReadOnly; /* entry-time xact r/o state */ struct TransactionStateData *parent; /* back link to parent */ } TransactionStateData; @@ -148,7 +149,8 @@ static TransactionStateData TopTransactionStateData = { NULL, /* cur transaction context */ NULL, /* cur transaction resource owner */ NIL, /* subcommitted child Xids */ - 0, /* entry-time current userid */ + InvalidOid, /* previous CurrentUserId setting */ + false, /* previous SecurityDefinerContext setting */ false, /* entry-time xact r/o state */ NULL /* link to parent state block */ }; @@ -1490,19 +1492,15 @@ StartTransaction(void) /* * initialize current transaction state fields + * + * note: prevXactReadOnly is not used at the outermost level */ s->nestingLevel = 1; s->gucNestLevel = 1; s->childXids = NIL; - - /* - * You might expect to see "s->currentUser = GetUserId();" here, but you - * won't because it doesn't work during startup; the userid isn't set yet - * during a backend's first transaction start. We only use the - * currentUser field in sub-transaction state structs. - * - * prevXactReadOnly is also valid only in sub-transactions. - */ + GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt); + /* SecurityDefinerContext should never be set outside a transaction */ + Assert(!s->prevSecDefCxt); /* * initialize other subsystems for new transaction @@ -1963,17 +1961,16 @@ AbortTransaction(void) s->state = TRANS_ABORT; /* - * Reset user id which might have been changed transiently. We cannot use - * s->currentUser, since it may not be set yet; instead rely on internal - * state of miscinit.c. + * Reset user ID which might have been changed transiently. We need this + * to clean up in case control escaped out of a SECURITY DEFINER function + * or other local change of CurrentUserId; therefore, the prior value + * of SecurityDefinerContext also needs to be restored. * - * (Note: it is not necessary to restore session authorization here - * because that can only be changed via GUC, and GUC will take care of - * rolling it back if need be. However, an error within a SECURITY - * DEFINER function could send control here with the wrong current - * userid.) + * (Note: it is not necessary to restore session authorization or role + * settings here because those can only be changed via GUC, and GUC will + * take care of rolling them back if need be.) */ - AtAbort_UserId(); + SetUserIdAndContext(s->prevUser, s->prevSecDefCxt); /* * do abort processing @@ -3807,6 +3804,12 @@ AbortSubTransaction(void) s->state = TRANS_ABORT; /* + * Reset user ID which might have been changed transiently. (See notes + * in AbortTransaction.) + */ + SetUserIdAndContext(s->prevUser, s->prevSecDefCxt); + + /* * We can skip all this stuff if the subxact failed before creating a * ResourceOwner... */ @@ -3859,20 +3862,6 @@ AbortSubTransaction(void) } /* - * Reset user id which might have been changed transiently. Here we want - * to restore to the userid that was current at subxact entry. (As in - * AbortTransaction, we need not worry about the session userid.) - * - * Must do this after AtEOXact_GUC to handle the case where we entered the - * subxact inside a SECURITY DEFINER function (hence current and session - * userids were different) and then session auth was changed inside the - * subxact. GUC will reset both current and session userids to the - * entry-time session userid. This is right in every other scenario so it - * seems simplest to let GUC do that and fix it here. - */ - SetUserId(s->currentUser); - - /* * Restore the upper transaction's read-only state, too. This should be * redundant with GUC's cleanup but we may as well do it for consistency * with the commit case. @@ -3926,13 +3915,6 @@ PushTransaction(void) { TransactionState p = CurrentTransactionState; TransactionState s; - Oid currentUser; - - /* - * At present, GetUserId cannot fail, but let's not assume that. Get the - * ID before entering the critical code sequence. - */ - currentUser = GetUserId(); /* * We keep subtransaction state nodes in TopTransactionContext. @@ -3966,7 +3948,7 @@ PushTransaction(void) s->savepointLevel = p->savepointLevel; s->state = TRANS_DEFAULT; s->blockState = TBLOCK_SUBBEGIN; - s->currentUser = currentUser; + GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt); s->prevXactReadOnly = XactReadOnly; CurrentTransactionState = s; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index e3e3b5f7cff..97904b703cf 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.289 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.290 2008/01/03 21:23:15 tgl Exp $ * * * INTERFACE ROUTINES @@ -1339,6 +1339,8 @@ index_build(Relation heapRelation, { RegProcedure procedure; IndexBuildResult *stats; + Oid save_userid; + bool save_secdefcxt; /* * sanity checks @@ -1350,6 +1352,13 @@ index_build(Relation heapRelation, Assert(RegProcedureIsValid(procedure)); /* + * Switch to the table owner's userid, so that any index functions are + * run as that user. + */ + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(heapRelation->rd_rel->relowner, true); + + /* * Call the access method's build procedure */ stats = (IndexBuildResult *) @@ -1359,6 +1368,9 @@ index_build(Relation heapRelation, PointerGetDatum(indexInfo))); Assert(PointerIsValid(stats)); + /* Restore userid */ + SetUserIdAndContext(save_userid, save_secdefcxt); + /* * If we found any potentially broken HOT chains, mark the index as not * being usable until the current transaction is below the event horizon. @@ -1857,6 +1869,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) IndexInfo *indexInfo; IndexVacuumInfo ivinfo; v_i_state state; + Oid save_userid; + bool save_secdefcxt; /* Open and lock the parent heap relation */ heapRelation = heap_open(heapId, ShareUpdateExclusiveLock); @@ -1874,6 +1888,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) indexInfo->ii_Concurrent = true; /* + * Switch to the table owner's userid, so that any index functions are + * run as that user. + */ + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(heapRelation->rd_rel->relowner, true); + + /* * Scan the index and gather up all the TIDs into a tuplesort object. */ ivinfo.index = indexRelation; @@ -1910,6 +1931,9 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples", state.htups, state.itups, state.tups_inserted); + /* Restore userid */ + SetUserIdAndContext(save_userid, save_secdefcxt); + /* Close rels, but keep locks */ index_close(indexRelation, NoLock); heap_close(heapRelation, NoLock); diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index f39a9575bbf..82bb020bc57 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.113 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.114 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -119,6 +119,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, HeapTuple *rows; PGRUsage ru0; TimestampTz starttime = 0; + Oid save_userid; + bool save_secdefcxt; if (vacstmt->verbose) elevel = INFO; @@ -202,6 +204,18 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, return; } + ereport(elevel, + (errmsg("analyzing \"%s.%s\"", + get_namespace_name(RelationGetNamespace(onerel)), + RelationGetRelationName(onerel)))); + + /* + * Switch to the table owner's userid, so that any index functions are + * run as that user. + */ + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(onerel->rd_rel->relowner, true); + /* let others know what I'm doing */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyProc->vacuumFlags |= PROC_IN_ANALYZE; @@ -215,11 +229,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, starttime = GetCurrentTimestamp(); } - ereport(elevel, - (errmsg("analyzing \"%s.%s\"", - get_namespace_name(RelationGetNamespace(onerel)), - RelationGetRelationName(onerel)))); - /* * Determine which columns to analyze * @@ -344,9 +353,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, onerel->rd_rel->relisshared, 0, 0); - vac_close_indexes(nindexes, Irel, AccessShareLock); - relation_close(onerel, ShareUpdateExclusiveLock); - return; + goto cleanup; } /* @@ -466,6 +473,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, totalrows, totaldeadrows); } + /* We skip to here if there were no analyzable columns */ +cleanup: + /* Done with indexes */ vac_close_indexes(nindexes, Irel, NoLock); @@ -498,6 +508,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyProc->vacuumFlags &= ~PROC_IN_ANALYZE; LWLockRelease(ProcArrayLock); + + /* Restore userid */ + SetUserIdAndContext(save_userid, save_secdefcxt); } /* diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 91a7ce9270d..d77294ccc22 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.48 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.49 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -48,9 +48,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) ListCell *parsetree_item; Oid owner_uid; Oid saved_uid; + bool saved_secdefcxt; AclResult aclresult; - saved_uid = GetUserId(); + GetUserIdAndContext(&saved_uid, &saved_secdefcxt); /* * Who is supposed to own the new schema? @@ -86,11 +87,11 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) * temporarily set the current user so that the object(s) will be created * with the correct ownership. * - * (The setting will revert to session user on error or at the end of this - * routine.) + * (The setting will be restored at the end of this routine, or in case + * of error, transaction abort will clean things up.) */ if (saved_uid != owner_uid) - SetUserId(owner_uid); + SetUserIdAndContext(owner_uid, true); /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid); @@ -142,7 +143,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) PopOverrideSearchPath(); /* Reset current user */ - SetUserId(saved_uid); + SetUserIdAndContext(saved_uid, saved_secdefcxt); } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 389141cd409..6b2b70dd1aa 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.362 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.363 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -971,6 +971,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) Relation onerel; LockRelId onerelid; Oid toast_relid; + Oid save_userid; + bool save_secdefcxt; /* Begin a transaction for vacuuming this relation */ StartTransactionCommand(); @@ -1101,6 +1103,14 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) toast_relid = onerel->rd_rel->reltoastrelid; /* + * Switch to the table owner's userid, so that any index functions are + * run as that user. (This is unnecessary, but harmless, for lazy + * VACUUM.) + */ + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(onerel->rd_rel->relowner, true); + + /* * Do the actual work --- either FULL or "lazy" vacuum */ if (vacstmt->full) @@ -1108,6 +1118,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) else lazy_vacuum_rel(onerel, vacstmt, vac_strategy); + /* Restore userid */ + SetUserIdAndContext(save_userid, save_secdefcxt); + /* all done with this class, but hold lock until commit */ relation_close(onerel, NoLock); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index d0f1168570e..2c234071d21 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.124 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.125 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -717,6 +717,21 @@ assign_session_authorization(const char *value, bool doit, GucSource source) /* not a saved ID, so look it up */ HeapTuple roleTup; + if (InSecurityDefinerContext()) + { + /* + * Disallow SET SESSION AUTHORIZATION inside a security definer + * context. We need to do this because when we exit the context, + * GUC won't be notified, leaving things out of sync. Note that + * this test is positioned so that restoring a previously saved + * setting isn't prevented. + */ + ereport(GUC_complaint_elevel(source), + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set session authorization within security-definer function"))); + return NULL; + } + if (!IsTransactionState()) { /* @@ -823,6 +838,24 @@ assign_role(const char *value, bool doit, GucSource source) } } + if (roleid == InvalidOid && InSecurityDefinerContext()) + { + /* + * Disallow SET ROLE inside a security definer context. We need to do + * this because when we exit the context, GUC won't be notified, + * leaving things out of sync. Note that this test is arranged so + * that restoring a previously saved setting isn't prevented. + * + * XXX it would be nice to allow this case in future, with the + * behavior being that the SET ROLE's effects end when the security + * definer context is exited. + */ + ereport(GUC_complaint_elevel(source), + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set role within security-definer function"))); + return NULL; + } + if (roleid == InvalidOid && strcmp(actual_rolename, "none") != 0) { diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index cd6e3968469..50f4b4cbc8f 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -15,7 +15,7 @@ * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.100 2008/01/01 19:45:52 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.101 2008/01/03 21:23:15 tgl Exp $ * * ---------- */ @@ -3173,7 +3173,8 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, { SPIPlanPtr qplan; Relation query_rel; - Oid save_uid; + Oid save_userid; + bool save_secdefcxt; /* * The query is always run against the FK table except when this is an @@ -3187,8 +3188,8 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, query_rel = fk_rel; /* Switch to proper UID to perform check as */ - save_uid = GetUserId(); - SetUserId(RelationGetForm(query_rel)->relowner); + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true); /* Create the plan */ qplan = SPI_prepare(querystr, nargs, argtypes); @@ -3197,7 +3198,7 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, elog(ERROR, "SPI_prepare returned %d for %s", SPI_result, querystr); /* Restore UID */ - SetUserId(save_uid); + SetUserIdAndContext(save_userid, save_secdefcxt); /* Save the plan if requested */ if (cache_plan) @@ -3226,7 +3227,8 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, Snapshot crosscheck_snapshot; int limit; int spi_result; - Oid save_uid; + Oid save_userid; + bool save_secdefcxt; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; @@ -3304,8 +3306,8 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0; /* Switch to proper UID to perform check as */ - save_uid = GetUserId(); - SetUserId(RelationGetForm(query_rel)->relowner); + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true); /* Finally we can run the query. */ spi_result = SPI_execute_snapshot(qplan, @@ -3314,7 +3316,7 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, false, false, limit); /* Restore UID */ - SetUserId(save_uid); + SetUserIdAndContext(save_userid, save_secdefcxt); /* Check result */ if (spi_result < 0) diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index b2254ba0077..19216b4381c 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.112 2008/01/01 19:45:53 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.113 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -864,6 +864,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) struct fmgr_security_definer_cache *volatile fcache; FmgrInfo *save_flinfo; Oid save_userid; + bool save_secdefcxt; volatile int save_nestlevel; if (!fcinfo->flinfo->fn_extra) @@ -908,46 +909,50 @@ fmgr_security_definer(PG_FUNCTION_ARGS) else fcache = fcinfo->flinfo->fn_extra; - save_flinfo = fcinfo->flinfo; - /* GetUserId is cheap enough that no harm in a wasted call */ - save_userid = GetUserId(); + /* GetUserIdAndContext is cheap enough that no harm in a wasted call */ + GetUserIdAndContext(&save_userid, &save_secdefcxt); if (fcache->proconfig) /* Need a new GUC nesting level */ save_nestlevel = NewGUCNestLevel(); else save_nestlevel = 0; /* keep compiler quiet */ - PG_TRY(); + if (OidIsValid(fcache->userid)) + SetUserIdAndContext(fcache->userid, true); + + if (fcache->proconfig) { - fcinfo->flinfo = &fcache->flinfo; + ProcessGUCArray(fcache->proconfig, + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, + GUC_ACTION_SAVE); + } - if (OidIsValid(fcache->userid)) - SetUserId(fcache->userid); + /* + * We don't need to restore GUC or userid settings on error, because the + * ensuing xact or subxact abort will do that. The PG_TRY block is only + * needed to clean up the flinfo link. + */ + save_flinfo = fcinfo->flinfo; - if (fcache->proconfig) - { - ProcessGUCArray(fcache->proconfig, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, - GUC_ACTION_SAVE); - } + PG_TRY(); + { + fcinfo->flinfo = &fcache->flinfo; result = FunctionCallInvoke(fcinfo); } PG_CATCH(); { fcinfo->flinfo = save_flinfo; - /* We don't need to restore GUC settings, outer xact abort will */ - if (OidIsValid(fcache->userid)) - SetUserId(save_userid); PG_RE_THROW(); } PG_END_TRY(); fcinfo->flinfo = save_flinfo; + if (fcache->proconfig) AtEOXact_GUC(true, save_nestlevel); if (OidIsValid(fcache->userid)) - SetUserId(save_userid); + SetUserIdAndContext(save_userid, save_secdefcxt); return result; } diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 888d5fae30a..5a42a8953a7 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.165 2008/01/01 19:45:53 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.166 2008/01/03 21:23:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -264,13 +264,15 @@ make_absolute_path(const char *path) * OuterUserId is the current user ID in effect at the "outer level" (outside * any transaction or function). This is initially the same as SessionUserId, * but can be changed by SET ROLE to any role that SessionUserId is a - * member of. We store this mainly so that AtAbort_UserId knows what to - * reset CurrentUserId to. + * member of. (XXX rename to something like CurrentRoleId?) * * CurrentUserId is the current effective user ID; this is the one to use * for all normal permissions-checking purposes. At outer level this will * be the same as OuterUserId, but it changes during calls to SECURITY * DEFINER functions, as well as locally in some specialized commands. + * + * SecurityDefinerContext is TRUE if we are within a SECURITY DEFINER function + * or another context that temporarily changes CurrentUserId. * ---------------------------------------------------------------- */ static Oid AuthenticatedUserId = InvalidOid; @@ -282,12 +284,16 @@ static Oid CurrentUserId = InvalidOid; static bool AuthenticatedUserIsSuperuser = false; static bool SessionUserIsSuperuser = false; +static bool SecurityDefinerContext = false; + /* We also remember if a SET ROLE is currently active */ static bool SetRoleIsActive = false; /* - * GetUserId/SetUserId - get/set the current effective user ID. + * GetUserId - get the current effective user ID. + * + * Note: there's no SetUserId() anymore; use SetUserIdAndContext(). */ Oid GetUserId(void) @@ -297,14 +303,6 @@ GetUserId(void) } -void -SetUserId(Oid userid) -{ - AssertArg(OidIsValid(userid)); - CurrentUserId = userid; -} - - /* * GetOuterUserId/SetOuterUserId - get/set the outer-level user ID. */ @@ -319,6 +317,7 @@ GetOuterUserId(void) static void SetOuterUserId(Oid userid) { + AssertState(!SecurityDefinerContext); AssertArg(OidIsValid(userid)); OuterUserId = userid; @@ -341,6 +340,7 @@ GetSessionUserId(void) static void SetSessionUserId(Oid userid, bool is_superuser) { + AssertState(!SecurityDefinerContext); AssertArg(OidIsValid(userid)); SessionUserId = userid; SessionUserIsSuperuser = is_superuser; @@ -353,6 +353,44 @@ SetSessionUserId(Oid userid, bool is_superuser) /* + * GetUserIdAndContext/SetUserIdAndContext - get/set the current user ID + * and the SecurityDefinerContext flag. + * + * Unlike GetUserId, GetUserIdAndContext does *not* Assert that the current + * value of CurrentUserId is valid; nor does SetUserIdAndContext require + * the new value to be valid. In fact, these routines had better not + * ever throw any kind of error. This is because they are used by + * StartTransaction and AbortTransaction to save/restore the settings, + * and during the first transaction within a backend, the value to be saved + * and perhaps restored is indeed invalid. We have to be able to get + * through AbortTransaction without asserting in case InitPostgres fails. + */ +void +GetUserIdAndContext(Oid *userid, bool *sec_def_context) +{ + *userid = CurrentUserId; + *sec_def_context = SecurityDefinerContext; +} + +void +SetUserIdAndContext(Oid userid, bool sec_def_context) +{ + CurrentUserId = userid; + SecurityDefinerContext = sec_def_context; +} + + +/* + * InSecurityDefinerContext - are we inside a SECURITY DEFINER context? + */ +bool +InSecurityDefinerContext(void) +{ + return SecurityDefinerContext; +} + + +/* * Initialize user identity during normal backend startup */ void @@ -480,21 +518,6 @@ InitializeSessionUserIdStandalone(void) /* - * Reset effective userid during AbortTransaction - * - * This is essentially SetUserId(GetOuterUserId()), but without the Asserts. - * The reason is that if a backend's InitPostgres transaction fails (eg, - * because an invalid user name was given), we have to be able to get through - * AbortTransaction without asserting. - */ -void -AtAbort_UserId(void) -{ - CurrentUserId = OuterUserId; -} - - -/* * Change session auth ID while running * * Only a superuser may set auth ID to something other than himself. Note diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f7260ec96f2..6ded4c9bc4c 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.198 2008/01/01 19:45:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.199 2008/01/03 21:23:15 tgl Exp $ * * NOTES * some of the information in this file should be moved to other files. @@ -234,12 +234,13 @@ extern void SetDatabasePath(const char *path); extern char *GetUserNameFromId(Oid roleid); extern Oid GetUserId(void); -extern void SetUserId(Oid userid); extern Oid GetOuterUserId(void); extern Oid GetSessionUserId(void); +extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context); +extern void SetUserIdAndContext(Oid userid, bool sec_def_context); +extern bool InSecurityDefinerContext(void); extern void InitializeSessionUserId(const char *rolename); extern void InitializeSessionUserIdStandalone(void); -extern void AtAbort_UserId(void); extern void SetSessionAuthorization(Oid userid, bool is_superuser); extern Oid GetCurrentRoleId(void); extern void SetCurrentRoleId(Oid roleid, bool is_superuser); |