aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c68
-rw-r--r--src/backend/catalog/index.c26
-rw-r--r--src/backend/commands/analyze.c31
-rw-r--r--src/backend/commands/schemacmds.c13
-rw-r--r--src/backend/commands/vacuum.c15
-rw-r--r--src/backend/commands/variable.c35
-rw-r--r--src/backend/utils/adt/ri_triggers.c20
-rw-r--r--src/backend/utils/fmgr/fmgr.c43
-rw-r--r--src/backend/utils/init/miscinit.c77
-rw-r--r--src/include/miscadmin.h7
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);