Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+3
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

+6
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

+2-2
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

+4-2
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

+3-1
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

+4-2
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

+30
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

+2
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)