diff options
Diffstat (limited to 'src/backend/utils/init/miscinit.c')
-rw-r--r-- | src/backend/utils/init/miscinit.c | 95 |
1 files changed, 77 insertions, 18 deletions
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 7a81fabb8fb..34dfe670e43 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.150.2.2 2008/01/03 21:24:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.150.2.3 2009/12/09 21:58:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -293,8 +293,10 @@ make_absolute_path(const char *path) * 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. + * SecurityRestrictionContext holds flags indicating reason(s) for changing + * CurrentUserId. In some cases we need to lock down operations that are + * not directly controlled by privilege settings, and this provides a + * convenient way to do it. * ---------------------------------------------------------------- */ static Oid AuthenticatedUserId = InvalidOid; @@ -306,7 +308,7 @@ static Oid CurrentUserId = InvalidOid; static bool AuthenticatedUserIsSuperuser = false; static bool SessionUserIsSuperuser = false; -static bool SecurityDefinerContext = false; +static int SecurityRestrictionContext = 0; /* We also remember if a SET ROLE is currently active */ static bool SetRoleIsActive = false; @@ -315,7 +317,7 @@ static bool SetRoleIsActive = false; /* * GetUserId - get the current effective user ID. * - * Note: there's no SetUserId() anymore; use SetUserIdAndContext(). + * Note: there's no SetUserId() anymore; use SetUserIdAndSecContext(). */ Oid GetUserId(void) @@ -339,7 +341,7 @@ GetOuterUserId(void) static void SetOuterUserId(Oid userid) { - AssertState(!SecurityDefinerContext); + AssertState(SecurityRestrictionContext == 0); AssertArg(OidIsValid(userid)); OuterUserId = userid; @@ -362,7 +364,7 @@ GetSessionUserId(void) static void SetSessionUserId(Oid userid, bool is_superuser) { - AssertState(!SecurityDefinerContext); + AssertState(SecurityRestrictionContext == 0); AssertArg(OidIsValid(userid)); SessionUserId = userid; SessionUserIsSuperuser = is_superuser; @@ -375,11 +377,29 @@ SetSessionUserId(Oid userid, bool is_superuser) /* - * GetUserIdAndContext/SetUserIdAndContext - get/set the current user ID - * and the SecurityDefinerContext flag. + * GetUserIdAndSecContext/SetUserIdAndSecContext - get/set the current user ID + * and the SecurityRestrictionContext flags. * - * Unlike GetUserId, GetUserIdAndContext does *not* Assert that the current - * value of CurrentUserId is valid; nor does SetUserIdAndContext require + * Currently there are two valid bits in SecurityRestrictionContext: + * + * SECURITY_LOCAL_USERID_CHANGE indicates that we are inside an operation + * that is temporarily changing CurrentUserId via these functions. This is + * needed to indicate that the actual value of CurrentUserId is not in sync + * with guc.c's internal state, so SET ROLE has to be disallowed. + * + * SECURITY_RESTRICTED_OPERATION indicates that we are inside an operation + * that does not wish to trust called user-defined functions at all. This + * bit prevents not only SET ROLE, but various other changes of session state + * that normally is unprotected but might possibly be used to subvert the + * calling session later. An example is replacing an existing prepared + * statement with new code, which will then be executed with the outer + * session's permissions when the prepared statement is next used. Since + * these restrictions are fairly draconian, we apply them only in contexts + * where the called functions are really supposed to be side-effect-free + * anyway, such as VACUUM/ANALYZE/REINDEX. + * + * Unlike GetUserId, GetUserIdAndSecContext does *not* Assert that the current + * value of CurrentUserId is valid; nor does SetUserIdAndSecContext 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, @@ -388,27 +408,66 @@ SetSessionUserId(Oid userid, bool is_superuser) * through AbortTransaction without asserting in case InitPostgres fails. */ void -GetUserIdAndContext(Oid *userid, bool *sec_def_context) +GetUserIdAndSecContext(Oid *userid, int *sec_context) { *userid = CurrentUserId; - *sec_def_context = SecurityDefinerContext; + *sec_context = SecurityRestrictionContext; } void -SetUserIdAndContext(Oid userid, bool sec_def_context) +SetUserIdAndSecContext(Oid userid, int sec_context) { CurrentUserId = userid; - SecurityDefinerContext = sec_def_context; + SecurityRestrictionContext = sec_context; } /* - * InSecurityDefinerContext - are we inside a SECURITY DEFINER context? + * InLocalUserIdChange - are we inside a local change of CurrentUserId? */ bool -InSecurityDefinerContext(void) +InLocalUserIdChange(void) { - return SecurityDefinerContext; + return (SecurityRestrictionContext & SECURITY_LOCAL_USERID_CHANGE) != 0; +} + +/* + * InSecurityRestrictedOperation - are we inside a security-restricted command? + */ +bool +InSecurityRestrictedOperation(void) +{ + return (SecurityRestrictionContext & SECURITY_RESTRICTED_OPERATION) != 0; +} + + +/* + * These are obsolete versions of Get/SetUserIdAndSecContext that are + * only provided for bug-compatibility with some rather dubious code in + * pljava. We allow the userid to be set, but only when not inside a + * security restriction context. + */ +void +GetUserIdAndContext(Oid *userid, bool *sec_def_context) +{ + *userid = CurrentUserId; + *sec_def_context = InLocalUserIdChange(); +} + +void +SetUserIdAndContext(Oid userid, bool sec_def_context) +{ + /* We throw the same error SET ROLE would. */ + if (InSecurityRestrictedOperation()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("cannot set parameter \"%s\" within security-restricted operation", + "role"))); + CurrentUserId = userid; + if (sec_def_context) + SecurityRestrictionContext |= SECURITY_LOCAL_USERID_CHANGE; + else + SecurityRestrictionContext &= ~SECURITY_LOCAL_USERID_CHANGE; } |