diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 20 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 17 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 77 |
3 files changed, 73 insertions, 41 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index af2955183cd..8dae05d4046 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-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.89.2.1 2007/08/15 19:15:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.89.2.2 2008/01/03 21:23:45 tgl Exp $ * * ---------- */ @@ -3008,7 +3008,8 @@ ri_PlanCheck(const 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 when this is an @@ -3022,8 +3023,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); @@ -3032,7 +3033,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) @@ -3061,7 +3062,8 @@ ri_PerformCheck(RI_QueryKey *qkey, void *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]; @@ -3139,8 +3141,8 @@ ri_PerformCheck(RI_QueryKey *qkey, void *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, @@ -3149,7 +3151,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *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 e493aba7877..a7d6765862f 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.102.2.1 2007/07/31 15:49:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.102.2.2 2008/01/03 21:23:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -784,6 +784,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) FmgrInfo *save_flinfo; struct fmgr_security_definer_cache *volatile fcache; Oid save_userid; + bool save_secdefcxt; HeapTuple tuple; if (!fcinfo->flinfo->fn_extra) @@ -809,26 +810,32 @@ fmgr_security_definer(PG_FUNCTION_ARGS) else fcache = fcinfo->flinfo->fn_extra; + GetUserIdAndContext(&save_userid, &save_secdefcxt); + SetUserIdAndContext(fcache->userid, true); + + /* + * We don't need to restore the 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; - save_userid = GetUserId(); PG_TRY(); { fcinfo->flinfo = &fcache->flinfo; - SetUserId(fcache->userid); result = FunctionCallInvoke(fcinfo); } PG_CATCH(); { fcinfo->flinfo = save_flinfo; - SetUserId(save_userid); PG_RE_THROW(); } PG_END_TRY(); fcinfo->flinfo = save_flinfo; - 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 5ddb0b2e44c..fbd31df49d1 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.159 2006/10/04 00:30:02 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.159.2.1 2008/01/03 21:23:45 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 @@ -475,21 +513,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 |