diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 9a1da59..28ab39f 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -981,8 +981,22 @@ fmgr_security_definer(PG_FUNCTION_ARGS) if (fcache->proconfig) AtEOXact_GUC(true, save_nestlevel); + if (OidIsValid(fcache->userid)) - SetUserIdAndSecContext(save_userid, save_sec_context); + { + Oid current_userid; + int current_sec_context; + /* + * If the called function stack used SET ROLE to change CurrentUserId + * then do not revert the setting back to the saved user. + */ + GetUserIdAndSecContext(¤t_userid, ¤t_sec_context); + + if(fcache->userid == current_userid) + SetUserIdAndSecContext(save_userid, save_sec_context); + else + SetUserIdAndSecContext(current_userid, save_sec_context); + } return result; } diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 359edee..a565836 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -313,7 +313,7 @@ GetOuterUserId(void) static void SetOuterUserId(Oid userid) { - AssertState(SecurityRestrictionContext == 0); + AssertState(!InSecurityRestrictedOperation()); AssertArg(OidIsValid(userid)); OuterUserId = userid; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index b530720..4a54df3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2381,7 +2381,8 @@ static struct config_string ConfigureNamesString[] = {"session_authorization", PGC_USERSET, UNGROUPED, gettext_noop("Sets the session user name."), NULL, - GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST + GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + | GUC_NOT_WHILE_SEC_REST | GUC_NOT_WHILE_USER_CHANGE }, &session_authorization_string, NULL, assign_session_authorization, show_session_authorization @@ -4747,20 +4748,20 @@ set_config_option(const char *name, const char *value, * we prohibit changing these in a security-restricted operation because * otherwise RESET could be used to regain the session user's privileges. */ - if (record->flags & GUC_NOT_WHILE_SEC_REST) + if (record->flags & GUC_NOT_WHILE_USER_CHANGE) { if (InLocalUserIdChange()) { - /* - * Phrasing of this error message is historical, but it's the - * most common case. - */ ereport(elevel, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("cannot set parameter \"%s\" within security-definer function", + errmsg("cannot set parameter \"%s\" while user-id changed temporarily", name))); return false; } + } + + if (record->flags & GUC_NOT_WHILE_SEC_REST) + { if (InSecurityRestrictedOperation()) { ereport(elevel, diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 9c95b60..469c787 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -149,7 +149,9 @@ typedef enum #define GUC_UNIT_MIN 0x4000 /* value is in minutes */ #define GUC_UNIT_TIME 0x7000 /* mask for MS, S, MIN */ -#define GUC_NOT_WHILE_SEC_REST 0x8000 /* can't set if security restricted */ +#define GUC_NOT_WHILE_SEC_REST 0x08000 /* can't set if security restricted */ +#define GUC_NOT_WHILE_USER_CHANGE 0x10000 /* can't set if current-user-id temporarily changed */ + /* GUC vars that are actually declared in guc.c, rather than elsewhere */ extern bool log_duration;