summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c20
-rw-r--r--src/backend/catalog/index.c14
-rw-r--r--src/backend/commands/schemacmds.c9
-rw-r--r--src/backend/commands/vacuum.c15
-rw-r--r--src/backend/commands/variable.c16
-rw-r--r--src/backend/utils/adt/ri_triggers.c125
-rw-r--r--src/backend/utils/fmgr/fmgr.c11
-rw-r--r--src/backend/utils/init/miscinit.c69
-rw-r--r--src/include/miscadmin.h7
9 files changed, 197 insertions, 89 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 1c5ffb1192d..24a50e5eb8f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.135.2.4 2007/04/26 23:25:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.135.2.5 2008/01/03 21:25:58 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -215,6 +215,8 @@ static TransactionStateData CurrentTransactionStateData = {
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
+static Oid prevUser; /* CurrentUserId at transaction start */
+
/*
* User-tweakable parameters
*/
@@ -960,6 +962,7 @@ static void
CommitTransaction(void)
{
TransactionState s = CurrentTransactionState;
+ bool prevSecDefCxt;
/*
* check the current transaction state
@@ -983,6 +986,10 @@ CommitTransaction(void)
*/
s->state = TRANS_COMMIT;
+ GetUserIdAndContext(&prevUser, &prevSecDefCxt);
+ /* SecurityDefinerContext should never be set outside a transaction */
+ Assert(!prevSecDefCxt);
+
/*
* Do pre-commit processing (most of this stuff requires database
* access, and in fact could still cause an error...)
@@ -1118,9 +1125,16 @@ AbortTransaction(void)
AtAbort_Memory();
/*
- * Reset user id which might have been changed transiently
+ * 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
+ * setting here because that can only be changed via GUC, and GUC will
+ * take care of rolling it back if need be.)
*/
- SetUserId(GetSessionUserId());
+ SetUserIdAndContext(prevUser, false);
/*
* do abort processing
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index debc3945eec..506fd43dcae 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.202.2.1 2005/06/25 16:54:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.202.2.2 2008/01/03 21:25:58 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1439,6 +1439,8 @@ index_build(Relation heapRelation,
IndexInfo *indexInfo)
{
RegProcedure procedure;
+ Oid save_userid;
+ bool save_secdefcxt;
/*
* sanity checks
@@ -1450,12 +1452,22 @@ 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
*/
OidFunctionCall3(procedure,
PointerGetDatum(heapRelation),
PointerGetDatum(indexRelation),
PointerGetDatum(indexInfo));
+
+ /* Restore userid */
+ SetUserIdAndContext(save_userid, save_secdefcxt);
}
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 09165d47bd3..ba62a54223f 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.6 2002/09/04 20:31:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.6.2.1 2008/01/03 21:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,9 +43,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
const char *owner_name;
Oid owner_userid;
Oid saved_userid;
+ bool saved_secdefcxt;
AclResult aclresult;
- saved_userid = GetUserId();
+ GetUserIdAndContext(&saved_userid, &saved_secdefcxt);
/*
* Figure out user identities.
@@ -68,7 +69,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
* (This will revert to session user on error or at the end of
* this routine.)
*/
- SetUserId(owner_userid);
+ SetUserIdAndContext(owner_userid, true);
}
else
/* not superuser */
@@ -143,7 +144,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
PopSpecialNamespace(namespaceId);
/* Reset current user */
- SetUserId(saved_userid);
+ SetUserIdAndContext(saved_userid, saved_secdefcxt);
}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 31a4be47853..9befea59e0a 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.244.2.2 2007/03/14 18:49:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.244.2.3 2008/01/03 21:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -720,6 +720,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
LockRelId onerelid;
Oid toast_relid;
bool result;
+ Oid save_userid;
+ bool save_secdefcxt;
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand(true);
@@ -821,6 +823,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)
@@ -830,6 +840,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
result = true; /* did the vacuum */
+ /* 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 87f8953ee26..1a351b62876 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.71.2.4 2006/02/12 22:33:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.71.2.5 2008/01/03 21:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -561,6 +561,20 @@ assign_session_authorization(const char *value, bool doit, bool interactive)
/* not a saved ID, so look it up */
HeapTuple userTup;
+ 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.
+ */
+ if (interactive)
+ elog(ERROR, "cannot set session authorization within security-definer function");
+ return NULL;
+ }
+
if (! IsTransactionState())
{
/*
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 6f85e6fc4a5..acb17219da8 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -17,7 +17,7 @@
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.43.2.5 2004/10/13 22:22:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.43.2.6 2008/01/03 21:25:58 tgl Exp $
*
* ----------
*/
@@ -178,9 +178,10 @@ RI_FKey_check(PG_FUNCTION_ARGS)
bool isnull;
int i;
int match_type;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
- save_uid = GetUserId();
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
ReferentialIntegritySnapshotOverride = true;
@@ -297,12 +298,12 @@ RI_FKey_check(PG_FUNCTION_ARGS)
/*
* Execute the plan
*/
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed == 0)
elog(ERROR, "%s referential integrity violation - "
@@ -486,12 +487,12 @@ RI_FKey_check(PG_FUNCTION_ARGS)
* Now check that foreign key exists in PK table
*/
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed == 0)
elog(ERROR, "%s referential integrity violation - "
@@ -558,10 +559,11 @@ ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, Oid tgoid, int match_type,
Datum check_values[RI_MAX_NUMKEYS];
char check_nulls[RI_MAX_NUMKEYS + 1];
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
bool result;
- save_uid = GetUserId();
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
ri_BuildQueryKeyPkCheck(&qkey, tgoid,
RI_PLAN_CHECK_LOOKUPPK, pk_rel,
@@ -681,12 +683,12 @@ ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, Oid tgoid, int match_type,
* Now check that foreign key exists in PK table
*/
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in ri_Check_Pk_Match()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
result = (SPI_processed != 0);
@@ -721,9 +723,10 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
bool isnull;
int i;
int match_type;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
- save_uid = GetUserId();
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
ReferentialIntegritySnapshotOverride = true;
@@ -886,12 +889,12 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
/*
* Now check for existing references
*/
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_del()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed > 0)
elog(ERROR, "%s referential integrity violation - "
@@ -948,9 +951,10 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
bool isnull;
int i;
int match_type;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
- save_uid = GetUserId();
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
ReferentialIntegritySnapshotOverride = true;
@@ -1124,12 +1128,12 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
/*
* Now check for existing references
*/
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_upd()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed > 0)
elog(ERROR, "%s referential integrity violation - "
@@ -1182,7 +1186,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
char del_nulls[RI_MAX_NUMKEYS + 1];
bool isnull;
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -1333,13 +1338,13 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
/*
* Now delete constraint
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, del_values, del_nulls, 0) != SPI_OK_DELETE)
elog(ERROR, "SPI_execp() failed in RI_FKey_cascade_del()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_del()");
@@ -1387,7 +1392,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
bool isnull;
int i;
int j;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -1569,13 +1575,13 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
/*
* Now update the existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE)
elog(ERROR, "SPI_execp() failed in RI_FKey_cascade_upd()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_upd()");
@@ -1628,7 +1634,8 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
char del_nulls[RI_MAX_NUMKEYS + 1];
bool isnull;
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -1781,13 +1788,13 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
/*
* Now check for existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_del()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed > 0)
elog(ERROR, "%s referential integrity violation - "
@@ -1848,7 +1855,8 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
char upd_nulls[RI_MAX_NUMKEYS + 1];
bool isnull;
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -2012,15 +2020,13 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
/*
* Now check for existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
-
- SetUserId(RelationGetForm(pk_rel)->relowner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(RelationGetForm(pk_rel)->relowner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_upd()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_processed > 0)
elog(ERROR, "%s referential integrity violation - "
@@ -2073,7 +2079,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
char upd_nulls[RI_MAX_NUMKEYS + 1];
bool isnull;
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -2234,13 +2241,13 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
/*
* Now update the existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE)
elog(ERROR, "SPI_execp() failed in RI_FKey_setnull_del()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_del()");
@@ -2289,7 +2296,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
int i;
int match_type;
bool use_cached_query;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -2495,13 +2503,13 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
/*
* Now update the existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE)
elog(ERROR, "SPI_execp() failed in RI_FKey_setnull_upd()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_upd()");
@@ -2547,7 +2555,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
char upd_nulls[RI_MAX_NUMKEYS + 1];
bool isnull;
int i;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -2739,13 +2748,13 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
/*
* Now update the existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE)
elog(ERROR, "SPI_execp() failed in RI_FKey_setdefault_del()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_del()");
@@ -2803,7 +2812,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
bool isnull;
int i;
int match_type;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
Oid fk_owner;
ReferentialIntegritySnapshotOverride = true;
@@ -3018,13 +3028,13 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
/*
* Now update the existing references
*/
- save_uid = GetUserId();
- SetUserId(fk_owner);
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fk_owner, true);
if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE)
elog(ERROR, "SPI_execp() failed in RI_FKey_setdefault_upd()");
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_upd()");
@@ -3171,7 +3181,8 @@ ri_PlanCheck(char *querystr, int nargs, Oid *argtypes,
{
void *qplan;
Relation query_rel;
- Oid save_uid;
+ Oid save_userid;
+ bool save_secdefcxt;
/*
* The query is always run against the FK table except
@@ -3185,14 +3196,14 @@ ri_PlanCheck(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);
/* Restore UID */
- SetUserId(save_uid);
+ SetUserIdAndContext(save_userid, save_secdefcxt);
/* Save the plan if requested */
if (cache_plan)
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 470d4a11dd6..5cebe0595b5 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.63 2002/10/04 17:19:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.63.2.1 2008/01/03 21:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -651,6 +651,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
FmgrInfo *save_flinfo;
struct fmgr_security_definer_cache *fcache;
Oid save_userid;
+ bool save_secdefcxt;
HeapTuple tuple;
if (!fcinfo->flinfo->fn_extra)
@@ -673,16 +674,18 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
else
fcache = fcinfo->flinfo->fn_extra;
+ GetUserIdAndContext(&save_userid, &save_secdefcxt);
+ SetUserIdAndContext(fcache->userid, true);
+
save_flinfo = fcinfo->flinfo;
fcinfo->flinfo = &fcache->flinfo;
- save_userid = GetUserId();
- SetUserId(fcache->userid);
result = FunctionCallInvoke(fcinfo);
- SetUserId(save_userid);
fcinfo->flinfo = save_flinfo;
+ SetUserIdAndContext(save_userid, save_secdefcxt);
+
return result;
}
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f41706862fa..e772d6a8ec5 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.96 2002/09/04 20:31:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.96.2.1 2008/01/03 21:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -483,6 +483,9 @@ GetCharSetByHost(char *TableName, int host, const char *DataDir)
* are implemented. Conceptually there is a stack, whose bottom
* is the session user. You are yourself responsible to save and
* restore the current user id if you need to change it.
+ *
+ * SecurityDefinerContext is TRUE if we are within a SECURITY DEFINER function
+ * or another context that temporarily changes CurrentUserId.
* ----------------------------------------------------------------
*/
static Oid AuthenticatedUserId = InvalidOid;
@@ -491,8 +494,13 @@ static Oid CurrentUserId = InvalidOid;
static bool AuthenticatedUserIsSuperuser = false;
+static bool SecurityDefinerContext = false;
+
+
/*
- * This function is relevant for all privilege checks.
+ * GetUserId - get the current effective user ID.
+ *
+ * Note: there's no SetUserId() anymore; use SetUserIdAndContext().
*/
Oid
GetUserId(void)
@@ -502,14 +510,6 @@ GetUserId(void)
}
-void
-SetUserId(Oid newid)
-{
- AssertArg(OidIsValid(newid));
- CurrentUserId = newid;
-}
-
-
/*
* This value is only relevant for informational purposes.
*/
@@ -521,17 +521,57 @@ GetSessionUserId(void)
}
-void
+static void
SetSessionUserId(Oid newid)
{
+ AssertState(!SecurityDefinerContext);
AssertArg(OidIsValid(newid));
SessionUserId = newid;
- /* Current user defaults to session user. */
- if (!OidIsValid(CurrentUserId))
- CurrentUserId = newid;
+ CurrentUserId = newid;
}
+/*
+ * 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
InitializeSessionUserId(const char *username)
{
@@ -616,7 +656,6 @@ SetSessionAuthorization(Oid userid)
elog(ERROR, "permission denied");
SetSessionUserId(userid);
- SetUserId(userid);
}
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 1dbd737db3b..7f7894b597a 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: miscadmin.h,v 1.111 2002/10/03 17:07:53 momjian Exp $
+ * $Id: miscadmin.h,v 1.111.2.1 2008/01/03 21:25:58 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to
@@ -203,9 +203,10 @@ extern void SetDatabasePath(const char *path);
extern char *GetUserNameFromId(Oid userid);
extern Oid GetUserId(void);
-extern void SetUserId(Oid userid);
extern Oid GetSessionUserId(void);
-extern void SetSessionUserId(Oid userid);
+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 *username);
extern void InitializeSessionUserIdStandalone(void);
extern void SetSessionAuthorization(Oid userid);