aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/init/miscinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/init/miscinit.c')
-rw-r--r--src/backend/utils/init/miscinit.c124
1 files changed, 79 insertions, 45 deletions
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index ef60f41b8ce..f3597dc8b9e 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -29,6 +29,7 @@
#include <utime.h>
#include "access/htup_details.h"
+#include "access/parallel.h"
#include "catalog/pg_authid.h"
#include "common/file_perm.h"
#include "libpq/libpq.h"
@@ -530,7 +531,7 @@ GetOuterUserId(void)
static void
-SetOuterUserId(Oid userid)
+SetOuterUserId(Oid userid, bool is_superuser)
{
Assert(SecurityRestrictionContext == 0);
Assert(OidIsValid(userid));
@@ -538,6 +539,11 @@ SetOuterUserId(Oid userid)
/* We force the effective user ID to match, too */
CurrentUserId = userid;
+
+ /* Also update the is_superuser GUC to match OuterUserId's property */
+ SetConfigOption("is_superuser",
+ is_superuser ? "on" : "off",
+ PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
}
@@ -551,6 +557,12 @@ GetSessionUserId(void)
return SessionUserId;
}
+bool
+GetSessionUserIsSuperuser(void)
+{
+ Assert(OidIsValid(SessionUserId));
+ return SessionUserIsSuperuser;
+}
static void
SetSessionUserId(Oid userid, bool is_superuser)
@@ -559,11 +571,6 @@ SetSessionUserId(Oid userid, bool is_superuser)
Assert(OidIsValid(userid));
SessionUserId = userid;
SessionUserIsSuperuser = is_superuser;
- SetRoleIsActive = false;
-
- /* We force the effective user IDs to match, too */
- OuterUserId = userid;
- CurrentUserId = userid;
}
/*
@@ -577,7 +584,8 @@ GetSystemUser(void)
}
/*
- * GetAuthenticatedUserId - get the authenticated user ID
+ * GetAuthenticatedUserId/SetAuthenticatedUserId - get/set the authenticated
+ * user ID
*/
Oid
GetAuthenticatedUserId(void)
@@ -586,6 +594,21 @@ GetAuthenticatedUserId(void)
return AuthenticatedUserId;
}
+void
+SetAuthenticatedUserId(Oid userid)
+{
+ Assert(OidIsValid(userid));
+
+ /* call only once */
+ Assert(!OidIsValid(AuthenticatedUserId));
+
+ AuthenticatedUserId = userid;
+
+ /* Also mark our PGPROC entry with the authenticated user id */
+ /* (We assume this is an atomic store so no lock is needed) */
+ MyProc->roleId = userid;
+}
+
/*
* GetUserIdAndSecContext/SetUserIdAndSecContext - get/set the current user ID
@@ -743,9 +766,6 @@ InitializeSessionUserId(const char *rolename, Oid roleid, bool bypass_login_chec
*/
Assert(!IsBootstrapProcessingMode());
- /* call only once */
- Assert(!OidIsValid(AuthenticatedUserId));
-
/*
* Make sure syscache entries are flushed for recent catalog changes. This
* allows us to find roles that were created on-the-fly during
@@ -753,36 +773,52 @@ InitializeSessionUserId(const char *rolename, Oid roleid, bool bypass_login_chec
*/
AcceptInvalidationMessages();
+ /*
+ * Look up the role, either by name if that's given or by OID if not.
+ * Normally we have to fail if we don't find it, but in parallel workers
+ * just return without doing anything: all the critical work has been done
+ * already. The upshot of that is that if the role has been deleted, we
+ * will not enforce its rolconnlimit against parallel workers anymore.
+ */
if (rolename != NULL)
{
roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(rolename));
if (!HeapTupleIsValid(roleTup))
+ {
+ if (InitializingParallelWorker)
+ return;
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("role \"%s\" does not exist", rolename)));
+ }
}
else
{
roleTup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roleTup))
+ {
+ if (InitializingParallelWorker)
+ return;
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("role with OID %u does not exist", roleid)));
+ }
}
rform = (Form_pg_authid) GETSTRUCT(roleTup);
roleid = rform->oid;
rname = NameStr(rform->rolname);
-
- AuthenticatedUserId = roleid;
is_superuser = rform->rolsuper;
- /* This sets OuterUserId/CurrentUserId too */
- SetSessionUserId(roleid, is_superuser);
+ /* In a parallel worker, ParallelWorkerMain already set these variables */
+ if (!InitializingParallelWorker)
+ {
+ SetAuthenticatedUserId(roleid);
- /* Also mark our PGPROC entry with the authenticated user id */
- /* (We assume this is an atomic store so no lock is needed) */
- MyProc->roleId = roleid;
+ /* Set SessionUserId and related variables via the GUC mechanisms */
+ SetConfigOption("session_authorization", rname,
+ PGC_BACKEND, PGC_S_OVERRIDE);
+ }
/*
* These next checks are not enforced when in standalone mode, so that
@@ -819,13 +855,6 @@ InitializeSessionUserId(const char *rolename, Oid roleid, bool bypass_login_chec
rname)));
}
- /* Record username and superuser status as GUC settings too */
- SetConfigOption("session_authorization", rname,
- PGC_BACKEND, PGC_S_OVERRIDE);
- SetConfigOption("is_superuser",
- is_superuser ? "on" : "off",
- PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
-
ReleaseSysCache(roleTup);
}
@@ -847,15 +876,19 @@ InitializeSessionUserIdStandalone(void)
Assert(!OidIsValid(AuthenticatedUserId));
AuthenticatedUserId = BOOTSTRAP_SUPERUSERID;
- SetSessionUserId(BOOTSTRAP_SUPERUSERID, true);
/*
- * XXX This should set SetConfigOption("session_authorization"), too.
- * Since we don't, C code will get NULL, and current_setting() will get an
- * empty string.
+ * XXX Ideally we'd do this via SetConfigOption("session_authorization"),
+ * but we lack the role name needed to do that, and we can't fetch it
+ * because one reason for this special case is to be able to start up even
+ * if something's happened to the BOOTSTRAP_SUPERUSERID's pg_authid row.
+ * Since we don't set the GUC itself, C code will see the value as NULL,
+ * and current_setting() will report an empty string within this session.
*/
- SetConfigOption("is_superuser", "on",
- PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+ SetSessionAuthorization(BOOTSTRAP_SUPERUSERID, true);
+
+ /* We could do SetConfigOption("role"), but let's be consistent */
+ SetCurrentRoleId(InvalidOid, false);
}
/*
@@ -901,17 +934,21 @@ system_user(PG_FUNCTION_ARGS)
/*
* Change session auth ID while running
*
- * Note that we set the GUC variable is_superuser to indicate whether the
- * current role is a superuser.
+ * The SQL standard says that SET SESSION AUTHORIZATION implies SET ROLE NONE.
+ * We mechanize that at higher levels not here, because this is the GUC
+ * assign hook for "session_authorization", and it must be commutative with
+ * SetCurrentRoleId (the hook for "role") because guc.c provides no guarantees
+ * which will run first during cases such as transaction rollback. Therefore,
+ * we update derived state (OuterUserId/CurrentUserId/is_superuser) only if
+ * !SetRoleIsActive.
*/
void
SetSessionAuthorization(Oid userid, bool is_superuser)
{
SetSessionUserId(userid, is_superuser);
- SetConfigOption("is_superuser",
- is_superuser ? "on" : "off",
- PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+ if (!SetRoleIsActive)
+ SetOuterUserId(userid, is_superuser);
}
/*
@@ -947,28 +984,25 @@ SetCurrentRoleId(Oid roleid, bool is_superuser)
/*
* Get correct info if it's SET ROLE NONE
*
- * If SessionUserId hasn't been set yet, just do nothing --- the eventual
- * SetSessionUserId call will fix everything. This is needed since we
- * will get called during GUC initialization.
+ * If SessionUserId hasn't been set yet, do nothing beyond updating
+ * SetRoleIsActive --- the eventual SetSessionAuthorization call will
+ * update the derived state. This is needed since we will get called
+ * during GUC initialization.
*/
if (!OidIsValid(roleid))
{
+ SetRoleIsActive = false;
+
if (!OidIsValid(SessionUserId))
return;
roleid = SessionUserId;
is_superuser = SessionUserIsSuperuser;
-
- SetRoleIsActive = false;
}
else
SetRoleIsActive = true;
- SetOuterUserId(roleid);
-
- SetConfigOption("is_superuser",
- is_superuser ? "on" : "off",
- PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+ SetOuterUserId(roleid, is_superuser);
}