Skip to content

Commit

Permalink
Move privilege check for SET SESSION AUTHORIZATION.
Browse files Browse the repository at this point in the history
Presently, the privilege check for SET SESSION AUTHORIZATION is
performed in session_authorization's assign_hook.  A relevant
comment states, "It's OK because the check does not require catalog
access and can't fail during an end-of-transaction GUC
reversion..."  However, we plan to add a catalog lookup to this
privilege check in a follow-up commit.

This commit moves this privilege check to the check_hook for
session_authorization.  Like check_role(), we do not throw a hard
error for insufficient privileges when the source is PGC_S_TEST.

Author: Joseph Koshakow
Discussion: https://postgr.es/m/CAAvxfHc-HHzONQ2oXdvhFF9ayRnidPwK%2BfVBhRzaBWYYLVQL-g%40mail.gmail.com
  • Loading branch information
nathan-bossart committed Jul 14, 2023
1 parent edca342 commit 9987a7b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 22 deletions.
32 changes: 28 additions & 4 deletions src/backend/commands/variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,14 +821,16 @@ check_session_authorization(char **newval, void **extra, GucSource source)
return false;
}

/*
* When source == PGC_S_TEST, we don't throw a hard error for a
* nonexistent user name or insufficient privileges, only a NOTICE. See
* comments in guc.h.
*/

/* Look up the username */
roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
if (!HeapTupleIsValid(roleTup))
{
/*
* When source == PGC_S_TEST, we don't throw a hard error for a
* nonexistent user name, only a NOTICE. See comments in guc.h.
*/
if (source == PGC_S_TEST)
{
ereport(NOTICE,
Expand All @@ -846,6 +848,28 @@ check_session_authorization(char **newval, void **extra, GucSource source)

ReleaseSysCache(roleTup);

/*
* Only superusers may SET SESSION AUTHORIZATION a role other than itself.
* Note that in case of multiple SETs in a single session, the original
* authenticated user's superuserness is what matters.
*/
if (roleid != GetAuthenticatedUserId() &&
!GetAuthenticatedUserIsSuperuser())
{
if (source == PGC_S_TEST)
{
ereport(NOTICE,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission will be denied to set session authorization \"%s\"",
*newval)));
return true;
}
GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
GUC_check_errmsg("permission denied to set session authorization \"%s\"",
*newval);
return false;
}

/* Set up "extra" struct for assign_session_authorization to use */
myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
if (!myextra)
Expand Down
30 changes: 12 additions & 18 deletions src/backend/utils/init/miscinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,16 @@ GetAuthenticatedUserId(void)
return AuthenticatedUserId;
}

/*
* Return whether the authenticated user was superuser at connection start.
*/
bool
GetAuthenticatedUserIsSuperuser(void)
{
Assert(OidIsValid(AuthenticatedUserId));
return AuthenticatedUserIsSuperuser;
}


/*
* GetUserIdAndSecContext/SetUserIdAndSecContext - get/set the current user ID
Expand Down Expand Up @@ -889,28 +899,12 @@ system_user(PG_FUNCTION_ARGS)
/*
* Change session auth ID while running
*
* Only a superuser may set auth ID to something other than himself. Note
* that in case of multiple SETs in a single session, the original userid's
* superuserness is what matters. But we set the GUC variable is_superuser
* to indicate whether the *current* session userid is a superuser.
*
* Note: this is not an especially clean place to do the permission check.
* It's OK because the check does not require catalog access and can't
* fail during an end-of-transaction GUC reversion, but we may someday
* have to push it up into assign_session_authorization.
* Note that we set the GUC variable is_superuser to indicate whether the
* current role is a superuser.
*/
void
SetSessionAuthorization(Oid userid, bool is_superuser)
{
/* Must have authenticated already, else can't make permission check */
Assert(OidIsValid(AuthenticatedUserId));

if (userid != AuthenticatedUserId &&
!AuthenticatedUserIsSuperuser)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set session authorization")));

SetSessionUserId(userid, is_superuser);

SetConfigOption("is_superuser",
Expand Down
1 change: 1 addition & 0 deletions src/include/miscadmin.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ extern Oid GetUserId(void);
extern Oid GetOuterUserId(void);
extern Oid GetSessionUserId(void);
extern Oid GetAuthenticatedUserId(void);
extern bool GetAuthenticatedUserIsSuperuser(void);
extern void GetUserIdAndSecContext(Oid *userid, int *sec_context);
extern void SetUserIdAndSecContext(Oid userid, int sec_context);
extern bool InLocalUserIdChange(void);
Expand Down

0 comments on commit 9987a7b

Please sign in to comment.