Skip to content

Commit e768919

Browse files
committed
Add option to bgworkers to allow the bypass of role login check
This adds a new option called BGWORKER_BYPASS_ROLELOGINCHECK to the flags available to BackgroundWorkerInitializeConnection() and BackgroundWorkerInitializeConnectionByOid(). This gives the possibility to bgworkers to bypass the role login check, making possible the use of a role that has no login rights while not being a superuser. PostgresInit() gains a new flag called INIT_PG_OVERRIDE_ROLE_LOGIN, taking advantage of the refactoring done in 4800a5d. Regression tests are added to worker_spi to check the behavior of this new option with bgworkers. Author: Bertrand Drouvot Reviewed-by: Nathan Bossart, Michael Paquier, Bharath Rupireddy Discussion: https://postgr.es/m/bcc36259-7850-4882-97ef-d6b905d2fc51@gmail.com
1 parent b6a77c6 commit e768919

File tree

8 files changed

+54
-7
lines changed

8 files changed

+54
-7
lines changed

doc/src/sgml/bgworker.sgml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ typedef struct BackgroundWorker
201201
during <command>initdb</command>. If <literal>BGWORKER_BYPASS_ALLOWCONN</literal>
202202
is specified as <varname>flags</varname> it is possible to bypass the restriction
203203
to connect to databases not allowing user connections.
204+
If <literal>BGWORKER_BYPASS_ROLELOGINCHECK</literal> is specified as
205+
<varname>flags</varname> it is possible to bypass the login check for the
206+
role used to connect to databases.
204207
A background worker can only call one of these two functions, and only
205208
once. It is not possible to switch databases.
206209
</para>

src/backend/postmaster/postmaster.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5567,6 +5567,9 @@ BackgroundWorkerInitializeConnection(const char *dbname, const char *username, u
55675567
/* ignore datallowconn? */
55685568
if (flags & BGWORKER_BYPASS_ALLOWCONN)
55695569
init_flags |= INIT_PG_OVERRIDE_ALLOW_CONNS;
5570+
/* ignore rolcanlogin? */
5571+
if (flags & BGWORKER_BYPASS_ROLELOGINCHECK)
5572+
init_flags |= INIT_PG_OVERRIDE_ROLE_LOGIN;
55705573

55715574
/* XXX is this the right errcode? */
55725575
if (!(worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION))
@@ -5598,6 +5601,9 @@ BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
55985601
/* ignore datallowconn? */
55995602
if (flags & BGWORKER_BYPASS_ALLOWCONN)
56005603
init_flags |= INIT_PG_OVERRIDE_ALLOW_CONNS;
5604+
/* ignore rolcanlogin? */
5605+
if (flags & BGWORKER_BYPASS_ROLELOGINCHECK)
5606+
init_flags |= INIT_PG_OVERRIDE_ROLE_LOGIN;
56015607

56025608
/* XXX is this the right errcode? */
56035609
if (!(worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION))

src/backend/utils/init/miscinit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ has_rolreplication(Oid roleid)
725725
* Initialize user identity during normal backend startup
726726
*/
727727
void
728-
InitializeSessionUserId(const char *rolename, Oid roleid)
728+
InitializeSessionUserId(const char *rolename, Oid roleid, bool bypass_login_check)
729729
{
730730
HeapTuple roleTup;
731731
Form_pg_authid rform;
@@ -789,7 +789,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid)
789789
/*
790790
* Is role allowed to login at all?
791791
*/
792-
if (!rform->rolcanlogin)
792+
if (!bypass_login_check && !rform->rolcanlogin)
793793
ereport(FATAL,
794794
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
795795
errmsg("role \"%s\" is not permitted to log in",

src/backend/utils/init/postinit.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ BaseInit(void)
684684
* flags:
685685
* - INIT_PG_LOAD_SESSION_LIBS to honor [session|local]_preload_libraries.
686686
* - INIT_PG_OVERRIDE_ALLOW_CONNS to connect despite !datallowconn.
687+
* - INIT_PG_OVERRIDE_ROLE_LOGIN to connect despite !rolcanlogin.
687688
* out_dbname: optional output parameter, see below; pass NULL if not used
688689
*
689690
* The database can be specified by name, using the in_dbname parameter, or by
@@ -901,7 +902,8 @@ InitPostgres(const char *in_dbname, Oid dboid,
901902
}
902903
else
903904
{
904-
InitializeSessionUserId(username, useroid);
905+
InitializeSessionUserId(username, useroid,
906+
(flags & INIT_PG_OVERRIDE_ROLE_LOGIN) != 0);
905907
am_superuser = superuser();
906908
}
907909
}
@@ -910,7 +912,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
910912
/* normal multiuser case */
911913
Assert(MyProcPort != NULL);
912914
PerformAuthentication(MyProcPort);
913-
InitializeSessionUserId(username, useroid);
915+
InitializeSessionUserId(username, useroid, false);
914916
/* ensure that auth_method is actually valid, aka authn_id is not NULL */
915917
if (MyClientConnectionInfo.authn_id)
916918
InitializeSystemUser(MyClientConnectionInfo.authn_id,

src/include/miscadmin.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ extern bool InSecurityRestrictedOperation(void);
364364
extern bool InNoForceRLSOperation(void);
365365
extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context);
366366
extern void SetUserIdAndContext(Oid userid, bool sec_def_context);
367-
extern void InitializeSessionUserId(const char *rolename, Oid roleid);
367+
extern void InitializeSessionUserId(const char *rolename, Oid roleid,
368+
bool bypass_login_check);
368369
extern void InitializeSessionUserIdStandalone(void);
369370
extern void SetSessionAuthorization(Oid userid, bool is_superuser);
370371
extern Oid GetCurrentRoleId(void);
@@ -466,6 +467,7 @@ extern PGDLLIMPORT AuxProcType MyAuxProcType;
466467
/* flags for InitPostgres() */
467468
#define INIT_PG_LOAD_SESSION_LIBS 0x0001
468469
#define INIT_PG_OVERRIDE_ALLOW_CONNS 0x0002
470+
#define INIT_PG_OVERRIDE_ROLE_LOGIN 0x0004
469471
extern void pg_split_opts(char **argv, int *argcp, const char *optstr);
470472
extern void InitializeMaxBackends(void);
471473
extern void InitPostgres(const char *in_dbname, Oid dboid,

src/include/postmaster/bgworker.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,11 @@ extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, ui
150150
* Flags to BackgroundWorkerInitializeConnection et al
151151
*
152152
*
153-
* Allow bypassing datallowconn restrictions when connecting to database
153+
* Allow bypassing datallowconn restrictions and login check when connecting
154+
* to database
154155
*/
155-
#define BGWORKER_BYPASS_ALLOWCONN 1
156+
#define BGWORKER_BYPASS_ALLOWCONN 0x0001
157+
#define BGWORKER_BYPASS_ROLELOGINCHECK 0x0002
156158

157159

158160
/* Block/unblock signals in a background worker process */

src/test/modules/worker_spi/t/001_worker_spi.pl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,34 @@
131131
qq[noconndb|myrole|WorkerSpiMain]),
132132
'dynamic bgworker with BYPASS_ALLOWCONN started');
133133

134+
# Check BGWORKER_BYPASS_ROLELOGINCHECK.
135+
# First create a role without login access.
136+
$node->safe_psql(
137+
'postgres', qq[
138+
CREATE ROLE nologrole WITH NOLOGIN;
139+
GRANT CREATE ON DATABASE mydb TO nologrole;
140+
]);
141+
my $nologrole_id = $node->safe_psql('mydb',
142+
"SELECT oid FROM pg_roles where rolname = 'nologrole';");
143+
$log_offset = -s $node->logfile;
144+
145+
# bgworker cannot be launched with login restriction.
146+
$node->psql('postgres',
147+
qq[SELECT worker_spi_launch(13, $mydb_id, $nologrole_id);]);
148+
$node->wait_for_log(qr/role "nologrole" is not permitted to log in/,
149+
$log_offset);
150+
151+
# bgworker bypasses the login restriction, and can be launched.
152+
$log_offset = -s $node->logfile;
153+
my $worker5_pid = $node->safe_psql('mydb',
154+
qq[SELECT worker_spi_launch(13, $mydb_id, $nologrole_id, '{"ROLELOGINCHECK"}');]
155+
);
156+
ok( $node->poll_query_until(
157+
'mydb',
158+
qq[SELECT datname, usename, wait_event FROM pg_stat_activity
159+
WHERE backend_type = 'worker_spi dynamic' AND
160+
pid = $worker5_pid;],
161+
'mydb|nologrole|WorkerSpiMain'),
162+
'dynamic bgworker with BYPASS_ROLELOGINCHECK launched');
163+
134164
done_testing();

src/test/modules/worker_spi/worker_spi.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ worker_spi_launch(PG_FUNCTION_ARGS)
452452

453453
if (strcmp(optname, "ALLOWCONN") == 0)
454454
flags |= BGWORKER_BYPASS_ALLOWCONN;
455+
else if (strcmp(optname, "ROLELOGINCHECK") == 0)
456+
flags |= BGWORKER_BYPASS_ROLELOGINCHECK;
455457
else
456458
ereport(ERROR,
457459
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy